Linux红外驱动重点解析

时间:2021-09-23 20:20:52

 Linux红外驱动重点解析

红外遥控是我们经常见到的一种无线收发设备,比如电视遥控,空调遥控,现在电视遥控有些慢慢变成了蓝牙装置。昨天是在知识星球里面看到有人提问,今天来解析一份网友写的驱动程序。

调试红外需要注意几个细节

1、我们发射的遥控器用肉眼是看不到的,需要拿相机来观察。

2、红外接收管和普通的二极管不同,如果用错物料也是不行的。

Linux红外驱动重点解析

1.NEC协议无线传输数据原理

 

NEC协议的特征: 

1、8位地址和8位指令长度;

2、地址和命令两次传输;(确保可靠性)

3、PWM脉冲宽度调制,以发射红外载波的占空比代表“0”和“1”;

4、载波频率为38KHz

5、位时间为1.125ms和2.25ms

NEC码位的定义:一个脉冲对应560us的连续载波,一个逻辑1传输需要2.25ms(560us脉冲+1680us低电平),一个逻辑0的 传输需要1.125ms(560us脉冲+560us低电平)。

而遥控接收头在收到脉冲时为低电平,在没有收到脉冲时为高电平,因此, 我们在接收头端收到的信号为:逻辑1应该是560us低+1680us高,逻辑0应该是560us低+560us高。

如下图:

Linux红外驱动重点解析

硬件

Linux红外驱动重点解析

2. Linux下的驱动接收程序

 

参考原文:

https://blog.csdn.net/wllw7176/article/details/110506677

两个驱动文件

  1. gpio-ir-recv.c  
  2. /* Copyright (c) 2012, Code Aurora Forum. All rights reserved.  
  3.  *  
  4.  * This program is free software; you can redistribute it and/or modify  
  5.  * it under the terms of the GNU General Public License version 2 and  
  6.  * only version 2 as published by the Free Software Foundation.  
  7.  *  
  8.  * This program is distributed in the hope that it will be useful,  
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of  
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  11.  * GNU General Public License for more details.  
  12.  */ 
  13. #include <linux/kernel.h>  
  14. #include <linux/init.h>  
  15. #include <linux/module.h>  
  16. #include <linux/interrupt.h>  
  17. #include <linux/gpio.h>  
  18. #include <linux/slab.h>  
  19. #include <linux/of.h>  
  20. #include <linux/of_gpio.h>  
  21. #include <linux/platform_device.h>  
  22. #include <linux/irq.h>  
  23. #include <media/rc-core.h>  
  24. #include <media/gpio-ir-recv.h>  
  25. #define GPIO_IR_DRIVER_NAME "gpio-rc-recv"  
  26. #define GPIO_IR_DEVICE_NAME "gpio_ir_recv"  
  27. struct gpio_rc_dev {  
  28.  struct rc_dev *rcdev;  
  29.  int gpio_nr;  
  30.  bool active_low;  
  31. };  
  32. #ifdef CONFIG_OF  
  33. /*  
  34.  * Translate OpenFirmware node properties into platform_data  
  35.  */  
  36. static int gpio_ir_recv_get_devtree_pdata(struct device *dev,  
  37.       struct gpio_ir_recv_platform_data *pdata)  
  38.  
  39.  struct device_node *np = dev->of_node;  
  40.  enum of_gpio_flags flags;  
  41.  int gpio;  
  42.  gpio = of_get_gpio_flags(np, 0, &flags);  
  43.  if (gpio < 0) {  
  44.   if (gpio != -EPROBE_DEFER)  
  45.    dev_err(dev, "Failed to get gpio flags (%d)\n", gpio);  
  46.   return gpio;  
  47.  }  
  48.  pdata->gpiogpio_nr = gpio;  
  49.  pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW);  
  50.  /* probe() takes care of map_name == NULL or allowed_protos == 0 */  
  51.  pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL);  
  52.  pdata->allowed_protos = 0 
  53.  return 0;  
  54.  
  55. static const struct of_device_id gpio_ir_recv_of_match[] = {  
  56.  { .compatible = "gpio-ir-receiver", },  
  57.  { },  
  58. };  
  59. MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); 
  60. #else /* !CONFIG_OF */  
  61. #define gpio_ir_recv_get_devtree_pdata(dev, pdata) (-ENOSYS)  
  62. #endif  
  63. static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) 
  64.  
  65.  struct gpio_rc_dev *gpio_dev = dev_id 
  66.  int gval;  
  67.  int rc = 0 
  68.  enum raw_event_type type = IR_SPACE 
  69.  gval = gpio_get_value(gpio_dev->gpio_nr);  
  70.  if (gval < 0 
  71.   goto err_get_value;  
  72.  if (gpio_dev->active_low)  
  73.   gval = !gval;  
  74.  if (gval == 1)  
  75.   type = IR_PULSE 
  76.  rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);  
  77.  if (rc < 0 
  78.   goto err_get_value;  
  79.  ir_raw_event_handle(gpio_dev->rcdev);  
  80. err_get_value:  
  81.  return IRQ_HANDLED;  
  82.  
  83. static int gpio_ir_recv_probe(struct platform_device *pdev)  
  84.  
  85.  struct gpio_rc_dev *gpio_dev;  
  86.  struct rc_dev *rcdev;  
  87.  const struct gpio_ir_recv_platform_data *pdata =  
  88.      pdev->dev.platform_data;  
  89.  int rc;  
  90.  if (pdev->dev.of_node) {  
  91.   struct gpio_ir_recv_platform_data *dtpdata =  
  92.    devm_kzalloc(&pdev->dev, sizeof(*dtpdata), GFP_KERNEL);  
  93.   if (!dtpdata)  
  94.    return -ENOMEM;  
  95.   rc = gpio_ir_recv_get_devtree_pdata(&pdev->dev, dtpdata);  
  96.   if (rc)  
  97.    return rc;  
  98.   pdata = dtpdata 
  99.  }  
  100.  if (!pdata)  
  101.   return -EINVAL;  
  102.  if (pdata->gpio_nr < 0 
  103.   return -EINVAL;  
  104.  gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);  
  105.  if (!gpio_dev)  
  106.   return -ENOMEM;  
  107.  rcdev = rc_allocate_device();  
  108.  if (!rcdev) {  
  109.   rc = -ENOMEM;  
  110.   goto err_allocate_device;  
  111.  }  
  112.  rcdev->priv = gpio_dev 
  113.  rcdev->driver_type = RC_DRIVER_IR_RAW 
  114.  rcdev->input_name = GPIO_IR_DEVICE_NAME 
  115.  rcdev->input_phys = GPIO_IR_DEVICE_NAME "/input0";  
  116.  rcdev->input_id.bustype = BUS_HOST 
  117.  rcdev->input_id.vendor = 0x0001 
  118.  rcdev->input_id.product = 0x0001 
  119.  rcdev->input_id.version = 0x0100 
  120.  rcdev->dev.parent = &pdev->dev;  
  121.  rcdev->driver_name = GPIO_IR_DRIVER_NAME 
  122.  if (pdata->allowed_protos)  
  123.   rcdev->allowed_protocols = pdata->allowed_protos;  
  124.  else  
  125.   rcdev->allowed_protocols = RC_BIT_ALL 
  126.  rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;   
  127.  gpio_dev->rcdevrcdev = rcdev;  
  128.  gpio_dev->gpio_nr = pdata->gpio_nr;  
  129.  gpio_dev->active_low = pdata->active_low;  
  130.  rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");  
  131.  if (rc < 0 
  132.   goto err_gpio_request;  
  133.  rc  = gpio_direction_input(pdata->gpio_nr);  
  134.  if (rc < 0 
  135.   goto err_gpio_direction_input;  
  136.  rc = rc_register_device(rcdev);  
  137.  if (rc < 0) {  
  138.   dev_err(&pdev->dev, "failed to register rc device\n");  
  139.   goto err_register_rc_device;  
  140.  }  
  141.  platform_set_drvdata(pdev, gpio_dev);  
  142.  rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr),  
  143.     gpio_ir_recv_irq,  
  144.    IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  
  145.      "gpio-ir-recv-irq", gpio_dev);  
  146.  if (rc < 0 
  147.   goto err_request_irq;  
  148.  return 0;  
  149. err_request_irq:  
  150.  rc_unregister_device(rcdev);  
  151.  rcdev = NULL 
  152. err_register_rc_device:  
  153. err_gpio_direction_input:  
  154.  gpio_free(pdata->gpio_nr);  
  155. err_gpio_request:  
  156.  rc_free_device(rcdev);  
  157. err_allocate_device:  
  158.  kfree(gpio_dev);  
  159.  return rc;  
  160.  
  161. static int gpio_ir_recv_remove(struct platform_device *pdev) 
  162.  
  163.  struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);  
  164.  free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);  
  165.  rc_unregister_device(gpio_dev->rcdev);  
  166.  gpio_free(gpio_dev->gpio_nr);  
  167.  kfree(gpio_dev);  
  168.  return 0; 
  169.  
  170. #ifdef CONFIG_PM  
  171. static int gpio_ir_recv_suspend(struct device *dev)  
  172.  
  173.  struct platform_device *pdev = to_platform_device(dev);  
  174.  struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);  
  175.  if (device_may_wakeup(dev))  
  176.   enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));  
  177.  else  
  178.   disable_irq(gpio_to_irq(gpio_dev->gpio_nr));  
  179.  return 0;  
  180.  
  181. static int gpio_ir_recv_resume(struct device *dev)  
  182.  
  183.  struct platform_device *pdev = to_platform_device(dev);  
  184.  struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);  
  185.  if (device_may_wakeup(dev))  
  186.   disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr));  
  187.  else  
  188.   enable_irq(gpio_to_irq(gpio_dev->gpio_nr));  
  189.  return 0;  
  190.  
  191. static const struct dev_pm_ops gpio_ir_recv_pm_ops = {  
  192.  .suspend        = gpio_ir_recv_suspend 
  193.  .resume         = gpio_ir_recv_resume 
  194. }; 
  195. #endif  
  196. static struct platform_driver gpio_ir_recv_driver = {  
  197.  .probe  = gpio_ir_recv_probe 
  198.  .remove = gpio_ir_recv_remove 
  199.  .driver = {  
  200.   .name   = GPIO_IR_DRIVER_NAME 
  201.   .of_match_table = of_match_ptr(gpio_ir_recv_of_match),  
  202. #ifdef CONFIG_PM  
  203.   .pm = &gpio_ir_recv_pm_ops,  
  204. #endif 
  205.  },  
  206. };  
  207. module_platform_driver(gpio_ir_recv_driver);  
  208. MODULE_DESCRIPTION("GPIO IR Receiver driver");  
  209. MODULE_LICENSE("GPL v2"); 

ir-nec-decoder.c

  1. /* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol  
  2.  *  
  3.  * Copyright (C) 2010 by Mauro Carvalho Chehab  
  4.  *  
  5.  * This program is free software; you can redistribute it and/or modify  
  6.  *  it under the terms of the GNU General Public License as published by  
  7.  *  the Free Software Foundation version 2 of the License.  
  8.  *  
  9.  *  This program is distributed in the hope that it will be useful,  
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
  12.  *  GNU General Public License for more details.  
  13.  */  
  14. #include <linux/bitrev.h>  
  15. #include <linux/module.h>  
  16. #include "rc-core-priv.h"  
  17. #define NEC_NBITS  32  
  18. #define NEC_UNIT  562500  /* ns */  
  19. #define NEC_HEADER_PULSE (16 * NEC_UNIT)  
  20. #define NECX_HEADER_PULSE (8  * NEC_UNIT) /* Less common NEC variant */  
  21. #define NEC_HEADER_SPACE (8  * NEC_UNIT)  
  22. #define NEC_REPEAT_SPACE (4  * NEC_UNIT)  
  23. #define NEC_BIT_PULSE  (1  * NEC_UNIT)  
  24. #define NEC_BIT_0_SPACE  (1  * NEC_UNIT)  
  25. #define NEC_BIT_1_SPACE  (3  * NEC_UNIT)  
  26. #define NEC_TRAILER_PULSE (1  * NEC_UNIT)  
  27. #define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */  
  28. #define NECX_REPEAT_BITS 1  
  29. enum nec_state {  
  30.  STATE_INACTIVE,  
  31.  STATE_HEADER_SPACE,  
  32.  STATE_BIT_PULSE,  
  33.  STATE_BIT_SPACE,  
  34.  STATE_TRAILER_PULSE,  
  35.  STATE_TRAILER_SPACE,  
  36. };  
  37. /**  
  38.  * ir_nec_decode() - Decode one NEC pulse or space  
  39.  * @dev: the struct rc_dev descriptor of the device  
  40.  * @duration: the struct ir_raw_event descriptor of the pulse/space  
  41.  *  
  42.  * This function returns -EINVAL if the pulse violates the state machine  
  43.  */  
  44. static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)  
  45.  
  46.  struct nec_dec *data = &dev->raw->nec;  
  47.  u32 scancode;  
  48.  u8 address, not_address, command, not_command;  
  49.  bool send_32bits = false 
  50.  if (!(dev->enabled_protocols & RC_BIT_NEC))  
  51.   return 0;  
  52.  if (!is_timing_event(ev)) {  
  53.   if (ev.reset)  
  54.    data->state = STATE_INACTIVE 
  55.   return 0;  
  56.  }  
  57.  IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",  
  58.      data->state, TO_US(ev.duration), TO_STR(ev.pulse));  
  59.  switch (data->state) {  
  60.  case STATE_INACTIVE:  
  61.   if (!ev.pulse)  
  62.    break;  
  63.   if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {  
  64.    data->is_nec_x = false 
  65.    data->necx_repeat = false 
  66.   } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))  
  67.    data->is_nec_x = true 
  68.   else  
  69.    break;  
  70.   data->count = 0 
  71.   data->state = STATE_HEADER_SPACE 
  72.   return 0;  
  73.  case STATE_HEADER_SPACE:  
  74.   if (ev.pulse)  
  75.    break;  
  76.   if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {  
  77.    data->state = STATE_BIT_PULSE 
  78.    return 0;  
  79.   } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {  
  80.    if (!dev->keypressed) {  
  81.     IR_dprintk(1, "Discarding last key repeat: event after key up\n");  
  82.    } else {  
  83.     rc_repeat(dev); 
  84.     IR_dprintk(1, "Repeat last key\n");  
  85.     data->state = STATE_TRAILER_PULSE 
  86.    }  
  87.    return 0;  
  88.   }  
  89.   break; 
  90.  case STATE_BIT_PULSE:  
  91.   if (!ev.pulse)  
  92.    break;  
  93.   if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))  
  94.    break;  
  95.   data->state = STATE_BIT_SPACE 
  96.   return 0;  
  97.  case STATE_BIT_SPACE:  
  98.   if (ev.pulse)  
  99.    break;  
  100.   if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&  
  101.    geq_margin(ev.duration, 
  102.     NEC_TRAILER_SPACE, NEC_UNIT / 2)) {  
  103.     IR_dprintk(1, "Repeat last key\n");  
  104.     rc_repeat(dev);  
  105.     data->state = STATE_INACTIVE 
  106.     return 0;  
  107.   } else if (data->count > NECX_REPEAT_BITS)  
  108.    data->necx_repeat = false 
  109.   data->bits <<= 1;  
  110.   if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2) 
  111.    data->bits |= 1;  
  112.   else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))  
  113.    break;  
  114.   data->count++;  
  115.   if (data->count == NEC_NBITS)  
  116.    data->state = STATE_TRAILER_PULSE 
  117.   else  
  118.    data->state = STATE_BIT_PULSE 
  119.   return 0;  
  120.  case STATE_TRAILER_PULSE:  
  121.   if (!ev.pulse)  
  122.    break;  
  123.   if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))  
  124.    break; 
  125.   data->state = STATE_TRAILER_SPACE 
  126.   return 0; 
  127.  case STATE_TRAILER_SPACE:  
  128.   if (ev.pulse)  
  129.    break;  
  130.   if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))  
  131.    break;  
  132.   address     = bitrev8((data->bits >> 24) & 0xff);  
  133.   not_address = bitrev8((data->bits >> 16) & 0xff);  
  134.   command     = bitrev8((data->bits >>  8) & 0xff);  
  135.   not_command = bitrev8((data->bits >>  0) & 0xff);  
  136.   if ((command ^ not_command) != 0xff) {  
  137.    IR_dprintk(1, "NEC checksum error: received 0x%08x\n",  
  138.        data->bits);  
  139.    send_32bits = true 
  140.   }  
  141.   if (send_32bits) {  
  142.    /* NEC transport, but modified protocol, used by at  
  143.     * least Apple and TiVo remotes */  
  144.    scancode = data->bits;  
  145.    IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode);  
  146.   } else if ((address ^ not_address) != 0xff) {  
  147.    /* Extended NEC */  
  148.    scancode = address     << 16 |  
  149.        not_address <<  8 |  
  150.        command;  
  151.    IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);  
  152.   } else {  
  153.    /* Normal NEC */  
  154.    scancode = address << 8 | command;  
  155.    IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);  
  156.   }  
  157.   if (data->is_nec_x)  
  158.    data->necx_repeat = true 
  159.   rc_keydown(dev, RC_TYPE_NEC, scancode, 0);  
  160.   data->state = STATE_INACTIVE 
  161.   return 0;  
  162.  }  
  163.  IR_dprintk(1, "NEC decode failed at count %d state %d (%uus %s)\n",  
  164.      data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));  
  165.  data->state = STATE_INACTIVE 
  166.  return -EINVAL;  
  167.  
  168. static struct ir_raw_handler nec_handler = {  
  169.  .protocols = RC_BIT_NEC 
  170.  .decode  = ir_nec_decode 
  171. };  
  172. static int __init ir_nec_decode_init(void)  
  173.  
  174.  ir_raw_handler_register(&nec_handler);  
  175.  printk(KERN_INFO "IR NEC protocol handler initialized\n");  
  176.  return 0; 
  177.  
  178. static void __exit ir_nec_decode_exit(void)  
  179.  
  180.  ir_raw_handler_unregister(&nec_handler);  
  181.  
  182. module_init(ir_nec_decode_init);  
  183. module_exit(ir_nec_decode_exit);   
  184. MODULE_LICENSE("GPL");  
  185. MODULE_AUTHOR("Mauro Carvalho Chehab");  
  186. MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");  
  187. MODULE_DESCRIPTION("NEC IR protocol decoder"); 

参考文章中的dts文件:

  1. gpio-ir-receiver {  
  2.     compatible = "gpio-ir-receiver" 
  3.     gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>; //连接红外的中断引脚  
  4.     active_low = <1>;                     //红外接收器是否将信号取反,有些红外接收器会将接收到的高低电平信号反向输出,比如我使用的hx1838红外接收器  
  5.     linux,rc-map-name = "rc-hx18380-carmp3"; //红外scancode与实际input_evnent code映射表名称,要在rc_register_device注册,具体见gpio-ir-recv.c  
  6.     allowed_protos = <0x100>; /*NEC protocol*/ //保留,驱动中并未使用  
  7. }; 

另一个文件里面调用的

ir-nec-decoder.c

Linux红外驱动重点解析

这个函数是Linux内核中的红外处理申请函数

Linux红外驱动重点解析

这里主要是注册一个解码的结构体

ir-nec-decoder.c

Linux红外驱动重点解析

3.中断处理程序解析

 

gpio-ir-recv.c

Linux红外驱动重点解析

ir_raw_event_store_edge() 这个函数用来计算电平的持续时间。

ir_raw_event_handle() 用来处理这个电平表示什么含义。

Linux红外驱动重点解析

驱动程序里面,首先是判断当前GPIO电平,如果是低电平,就进入红外解析,如果不是,或者获取失败,就退出程序。

4.红外数据处理程序解析

内核专门开了一个线程来处理数据解析

rc-ir-raw.c

Linux红外驱动重点解析

Linux红外驱动重点解析

处理函数其实就是处理电平时间长短来决定数字信号

ir-nec-decoder.c

Linux红外驱动重点解析

这里是判断头,这个时间和9ms进行比较

Linux红外驱动重点解析

9ms 从哪里来的,可以看看这里

ir-nec-decoder.c

Linux红外驱动重点解析

Linux红外驱动重点解析

拿到头后,这个switch函数就继续往下跑

ir-nec-decoder.c

Linux红外驱动重点解析

Linux红外驱动重点解析

然后就是判断 1 和 0  的时候了

Linux红外驱动重点解析

Linux红外驱动重点解析

ir-nec-decoder.c

Linux红外驱动重点解析

上面那个就是1,下面那个就是0。

4.然后数据怎么上报呢?

 

ir-nec-decoder.c

Linux红外驱动重点解析

这里是在另一个模块中注册的映射

不同的红外键值对应不同的上报按键键值

rc-trekstor.c

Linux红外驱动重点解析

原文链接:https://mp.weixin.qq.com/s/mwjY69oSF8WjnZ2B8a8Xeg