【Linux驱动】红外接收器HS0038,适用于100ask_imx6ull

【零】程序的总体框架:
设备树→预设信息→驱动.ko→文件ctl进行初始化→GPIO中断→定时器以及事件存储→nec_decode→scancode→map键值→上传input系统
为了复习设备树相关的操作,在这里使用设备树来进行一些预设,总体包括gpio、active_low、map_name、allowed_protos 这四个最主要的属性,这一点与参考代码100ask_irda.c是不一样的。参考源码并没有使用到设备树,所有的属性都是直接预设在程序中,申请IO直接通过IO号进行申请。
【一】设备树:

 pinctrl_irda:irdagrp{
    
    
            fsl,pins = <
            MX6UL_PAD_CSI_VSYNC__GPIO4_IO19            0x000010B0    
            >;
        };

这部分添加至&iomuxc节点下。

myirda{
    
    
        compatible = "myirda,irdadrv";//驱动程序要找的名字
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_irda>;//引脚定义
        gpios = <&gpio4 19 GPIO_ACTIVE_HIGH>;//默认1为高
        active_low = <1>;//编码是否反向
        linux,rc-map-name = "rc-hs0038-nec";//使用前需要注册映射
        allowed_protos = <0x200>;//填0为可使用所有protocol,默认为NEC
   };

设备树中没什么好说的,主要就是包括几个基本属性,其中active_low、linux,rc-map-name、allowed_protos这三个属性在驱动程序中需要用到。
这里简要介绍一下设备树属性读取的代码:

  struct device_node *np = pdev->dev.of_node;
  enum of_gpio_flags flags;
  int gpio;
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  gpio = of_get_gpio_flags(np, 0, &flags);
  if (gpio < 0) {
    
    
		if (gpio != -EPROBE_DEFER)
			printk("Failed to get gpio flags (%d)\n", gpio);
		return gpio;
 }
 irda_dev.gpio_nr = gpio;
 irda_dev.active_low = of_property_read_bool(np,"active_low");
	/* probe() takes care of map_name == NULL or allowed_protos == 0 */
 irda_dev.map_name = of_get_property(np, "linux,rc-map-name", NULL);
 ret = of_property_read_u32_array(np, "allowed_protos",
 &irda_dev.allowed_protos,1);

和大多数从设备树中读取相关配置差不多,比较麻烦的就是读取map_name、active_low以及allowed_protos,简要介绍一下这三个配置是干嘛的。
map_name: 通过NEC解码得到的数据与input键值的映射表的名字
active_low:是否在解码时进行反向编码(比如说原电平是高,但是解码时当它是低,为什么要这样做,是因为NEC协议的电平,详情看参考博客)
allowed_protos:允许的解码器种类,这里0x200表示的是RC_BIT_NEC,它定义在:
rc-map.h
点开此头文件,可找到RC_BIT_NEC定义为:1ULL<<RC_TYPE_NEC,结合上方对RC_TYPE_NEC的定义可知:RC_BIT_NEC = 1ULL<< 9 即0x200
【二】应用层APP
之所以先说应用层APP的原因是个人建议先从抄应用层的代码开始学习Irda,除非你压根就不使用input系统和Linux系统内集成的NEC解码器,裸机电平解析可参考博客4。
应用层的代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>
#include <linux/input.h>

#define EVENT_PATH  "/dev/input/event"
#define GPIO_IRDA_DEVICE_NAME	"gpio_irda-ir"
#define IRDA_IOC_MAGIC    'i'
#define IRDA_IOCINIT      _IOW(IRDA_IOC_MAGIC, 0, int)
#define GPIO0 ((4-1)*32+19)

struct event_msg{
    
    
  int value;
  int code;
};

static struct  event_msg msg;

int getEventNumber(char *name)
{
    
    
    FILE *fd;
    int i, len, num;
    char *str;
    char buf[64], temp[4];
    int flag = 0, file_row = 0, cur_row = 0;
    
    fd = fopen("/proc/bus/input/devices", "r"); 
    if(fd == NULL) 
    {
    
    
        printf("getEventNumber:Can not open file\r\n");
        return -1;
    }
    
    while(!feof(fd))
    {
    
    
        flag = fgetc(fd);
        if(flag == '\n')
            file_row++;
    }
    file_row = file_row + 1; 
    fseek(fd, 0, SEEK_SET);
    
    cur_row = 1;
    while(cur_row < file_row)
    {
    
    
        memset(buf, 0x00, sizeof(buf)); 
        fgets(buf,sizeof(buf),fd); 
        cur_row ++;
        
        if(strstr(buf, name) != NULL)
        {
    
    
            for(i=0; i<5; i++)
            {
    
    
                memset(buf, 0x00, sizeof(buf));
                fgets(buf,sizeof(buf),fd);
                if(strstr(buf, "Handlers") != NULL)
                {
    
    
                    str = strchr(buf,'event') + 1;
                    strncpy(temp, str, 1);
                    num = (int)(temp[0]-'0');

                    fclose(fd);
                    return num;
                }
            }
        }   
    }
    fclose(fd);
    return -1;
}

int main(int argc,char **argv)
{
    
    
   char *filename;
   char event_path[30];
   int ret = 0;
   int fd;
   int fd_event;
   int event_num = 0;
   int pin = GPIO0;
   struct input_event ev;

   if(argc!=2)
   {
    
    
     printf("Usage:%s <dev>\n",argv[0]);
     return -1;
   }
   filename = argv[1];

   fd = open(filename,O_RDWR);
   if(fd<0)
   {
    
    
     printf("Open file fail!\n");
     goto ERROR;
   }
   
   if(ioctl(fd,IRDA_IOCINIT,&pin)<0)
   {
    
    
     printf("Init Irda fail!\n");
     goto ERROR;
   }else
   {
    
    
     printf("Init Irda successful\n");
   }
   
   event_num = getEventNumber(GPIO_IRDA_DEVICE_NAME);
   printf("event num = %d\n",event_num);
   sprintf(event_path,"%s%d",EVENT_PATH,event_num);
   printf("%s\n",event_path);
   fd_event = open(event_path,O_RDONLY);
   if(fd_event < 0)
   {
    
    
    printf("Open event file fail!\n");
     goto ERROR;
   }
   
   while(1)
   {
    
    
    ret = read(fd_event, &ev, sizeof(struct input_event));
    if (ret < 0) {
    
    
        printf("IRDA: read event error!\n");
    }else
    {
    
    
      if(ev.type == EV_KEY)
     {
    
    
      msg.code  = ev.code;
      msg.value = ev.value;
      printf("Msg->code:%d Msg->value:%d\n",msg.code,msg.value);
     }
    }
   }
   ERROR:
   close(fd);
   close(fd_event);
   return 0;
}

这里最为核心的函数就是getEventNumber函数,不过这里并不是笔者实现的,而是笔者从模组参考代码中刨到的,它的功能非常重要,即通过设备名找到对应的event文件号。而笔者只是通过它找到的文件号重新形成了一个打开目录罢了,这里注意数值的长度是30,如果你的目录比较长要记得加长。
有的人可能会比较疑惑,为什么作者从设备树里整到了gpio还需要把io数值传入ioctl?实际上,这是为了与默认设备做兼容。在100ask_imx6ull板子中有一个默认的红外接收设备:/dev/irda,如果你和我一样对于自己的驱动程序怎么搞都搞不好的话,可以先使用这个应用程序加载官方默认的红外接收设备文件试试,以此来排除硬件层面的问题。使用方法为:./irda_app /dev/irda
[ 2072.596999] Registered IR keymap rc-100ask-nec
[ 2072.608106] input: gpio_irda-ir as /devices/virtual/rc/rc0/input3
[ 2072.623950] evbug: Connected device: input3 (gpio_irda-ir at gpio_irda-ir/input0)
[ 2072.642712] rc rc0: gpio_irda-ir as /devices/virtual/rc/rc0
[ 2072.655263] input: MCE IR Keyboard/Mouse (gpio-irda-rc) as /devices/virtual/input/input4
[ 2072.677303] evbug: Connected device: input4 (MCE IR Keyboard/Mouse (gpio-irda-rc) at /input0)
以上为正常运行时的打印,由此使用官方的红外遥控器即可出现键值打印。
在官方的代码中,在ioctl传入gpio之后才会开始申请gpio,因此不用担心会不会因为官方驱动而影响自家驱动申请不到gpio的情况,只要你不是同时运行两个程序。
最后在while(1)中读取ev的值,其中code为上传到Input系统的KEY代码(可不是NEC解码的值),value为键值,1表示按下,0表示松开。所以在按一次并松开时,会打印两行同一code但不同val,如下:
Msg->code:116 Msg->value:1
Msg->code:116 Msg->value:0
【三】驱动程序

#include <linux/module.h>
#include <linux/poll.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <media/rc-core.h>
#include <linux/platform_data/media/gpio-ir-recv.h>

#define irda_NAME    "myirda"
#define GPIO_IRDA_DRIVER_NAME	"gpio-irda-rc"
#define GPIO_IRDA_DEVICE_NAME	"gpio_irda-ir"
#define IRDA_IOC_MAGIC    'i'
#define IRDA_IOCINIT      _IOW(IRDA_IOC_MAGIC, 0, int)


struct gpio_rc_dev {
    
    
	struct rc_dev *rcdev;
  int gpio_nr;
	bool active_low;
	struct timer_list flush_timer;
};

struct irda_device{
    
    
  /*file*/
  int major;
  dev_t devid;
  struct cdev cdev;
  struct class *class;
  struct device *device;
  /*irda dev*/
  int gpio_nr;
	bool active_low;
  u32 allowed_protos;
  const char   *map_name;
};

static struct irda_device irda_dev;
static struct gpio_rc_dev *gpio_dev;
static struct rc_dev *rcdev;

static struct rc_map_table hs0038_nec[] = {
    
    
    {
    
     0x45, KEY_POWER},
    {
    
     0x47, KEY_MENU},

    {
    
     0x44, KEY_T},//Test
    {
    
     0x40, KEY_VOLUMEUP},
    {
    
     0x43, KEY_BACK},//RETURN

    {
    
     0x07, KEY_LAST},
    {
    
     0x15, KEY_PLAYPAUSE},
    {
    
     0x09, KEY_NEXT},
    
    {
    
     0x16, KEY_0},
    {
    
     0x19, KEY_VOLUMEDOWN},
    {
    
     0x0d, KEY_C},
    
    {
    
     0x0c, KEY_1},
    {
    
     0x18, KEY_2},
    {
    
     0x5e, KEY_3},
    {
    
     0x08, KEY_4},
    {
    
     0x1c, KEY_5},
    {
    
     0x5a, KEY_6},
    {
    
     0x42, KEY_7},
    {
    
     0x52, KEY_8}, 
    {
    
     0x4a, KEY_9},
};

static struct rc_map_list nec_hs0038_map = {
    
    
    .map = {
    
    
        .scan    = hs0038_nec,
        .size    = ARRAY_SIZE(hs0038_nec),
        .rc_type = RC_TYPE_NEC, //RC_TYPE_UNKNOWN //echo nec > /sys/class/rc/rc0/protocols
        .name    = "rc-hs0038-nec",
    }
};


static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
    
    
	struct gpio_rc_dev *gpio_dev = dev_id;
	int gval;
	int rc = 0;
	enum raw_event_type type = IR_SPACE;
	gval = gpio_get_value(gpio_dev->gpio_nr);
	if (gval < 0)
		goto err_get_value;

	if (gpio_dev->active_low)
		gval = !gval;

	if (gval == 1)
		type = IR_PULSE;
  
	rc = ir_raw_event_store_edge(gpio_dev->rcdev, type);
	if (rc < 0)
		goto err_get_value;
	mod_timer(&gpio_dev->flush_timer,
		  jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout));
	ir_raw_event_handle(gpio_dev->rcdev);
err_get_value:
	return IRQ_HANDLED;
}

static void flush_timer(unsigned long arg)
{
    
    
	struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg;
	
  DEFINE_IR_RAW_EVENT(ev);

	ev.timeout = true;
	ev.duration = gpio_dev->rcdev->timeout;
	ir_raw_event_store(gpio_dev->rcdev, &ev);
	ir_raw_event_handle(gpio_dev->rcdev);
}

static int irda_init(void)
{
    
    
	int rc;

	gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL);
	if (!gpio_dev)
		return -ENOMEM;

	rcdev = rc_allocate_device();
	if (!rcdev) {
    
    
		rc = -ENOMEM;
		goto err_allocate_device;
	}
  
  rc = rc_map_register(&nec_hs0038_map);
  if(rc<0)
  {
    
    
    printk("failed to map hs0038!\n");
    goto err_map_register;
  }

	rcdev->priv = gpio_dev;
	rcdev->driver_type = RC_DRIVER_IR_RAW;
	rcdev->input_name = GPIO_IRDA_DEVICE_NAME;
	rcdev->input_phys = GPIO_IRDA_DEVICE_NAME "/input0";
	rcdev->input_id.bustype = BUS_HOST;
	rcdev->input_id.vendor = 0x0001;
	rcdev->input_id.product = 0x0001;
	rcdev->input_id.version = 0x0100;
	rcdev->dev.parent = NULL;
	rcdev->driver_name = GPIO_IRDA_DRIVER_NAME;
	rcdev->min_timeout = 0;
	rcdev->timeout = MS_TO_NS(125);
	rcdev->max_timeout = 10 * MS_TO_NS(125);
  if(irda_dev.allowed_protos)
  {
    
    
    rcdev->allowed_protocols = irda_dev.allowed_protos;
    printk("Use devtree protocols\n");
  }else
  {
    
    
    rcdev->allowed_protocols = RC_BIT_ALL;//RC_BIT_NEC;
    printk("Use default protocols\n");
  }
	rcdev->map_name = irda_dev.map_name?irda_dev.map_name:"rc-hs0038-nec";
	
	gpio_dev->rcdev = rcdev;
	gpio_dev->gpio_nr = irda_dev.gpio_nr;
	gpio_dev->active_low = irda_dev.active_low;
  
	setup_timer(&gpio_dev->flush_timer, flush_timer, (unsigned long)gpio_dev);
  
  rc = gpio_request(gpio_dev->gpio_nr, "gpio-irda-recv");
	if (rc < 0)
	{
    
    
    printk("gpio_request fail!\n");
    goto err_gpio_request;
  }else
  {
    
    
    printk("gpio_request successful!\n");
  }
  rc  = gpio_direction_input(gpio_dev->gpio_nr);
	if (rc < 0)
  {
    
    
    printk("gpio_direction fail\n");
    goto err_gpio_direction_input;
  }else
  {
    
    
    printk("gpio_direction successful!\n");
  }
  
	rc = rc_register_device(rcdev);
	if (rc < 0) {
    
    
		printk("failed to register rc device\n");
		goto err_register_rc_device;
	}
	
	rc = request_any_context_irq(gpio_to_irq(gpio_dev->gpio_nr),
				                       gpio_ir_recv_irq,
			                         IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
					                    "gpio-irda-irq", gpio_dev);
	if (rc < 0)
		goto err_request_irq;
	
	return 0;
err_request_irq:
	rc_unregister_device(rcdev);
	rcdev = NULL;
err_gpio_request:
err_gpio_direction_input:
  gpio_free(gpio_dev->gpio_nr);
err_register_rc_device:
	rc_free_device(rcdev);
err_map_register:
  rc_map_unregister(&nec_hs0038_map);
err_allocate_device:
	kfree(gpio_dev);
	return rc;

}

static ssize_t irda_drv_read(struct file *file,char __user *buf,size_t size,loff_t *offset)
{
    
    
    printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
    return 0;
}

static int irda_drv_open(struct inode *node,struct file *file)
{
    
    
    printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
    return 0;
}

static int irda_drv_close(struct inode *node,struct file *file)
{
    
    
  printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
  free_irq(gpio_to_irq(gpio_dev->gpio_nr),gpio_dev);
  del_timer_sync(&gpio_dev->flush_timer);
  rc_unregister_device(gpio_dev->rcdev);
  gpio_free(gpio_dev->gpio_nr);
  kfree(gpio_dev);
  rc_map_unregister(&nec_hs0038_map);
  return 0;
}

static long  irda_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
    
    
	int ret = 0;
  printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
	switch(cmd) {
    
    
	case IRDA_IOCINIT:
		ret = irda_init();
		break;	
	default:
		ret = -ENOTTY;
		break;
	}
	
	return ret;
}
static struct file_operations irda_drv = {
    
    
  .owner =  THIS_MODULE,
  .open  =  irda_drv_open,
  .read  =  irda_drv_read,
  .release = irda_drv_close,
  .unlocked_ioctl = irda_ioctl,
};

static int irda_probe(struct platform_device *pdev)
{
    
    
  int ret = 0;
  struct device_node *np = pdev->dev.of_node;
	enum of_gpio_flags flags;
	int gpio;

  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	gpio = of_get_gpio_flags(np, 0, &flags);
	if (gpio < 0) {
    
    
		if (gpio != -EPROBE_DEFER)
			printk("Failed to get gpio flags (%d)\n", gpio);
		return gpio;
	}
	irda_dev.gpio_nr = gpio;
  irda_dev.active_low = of_property_read_bool(np,"active_low");
	/* probe() takes care of map_name == NULL or allowed_protos == 0 */
	irda_dev.map_name = of_get_property(np, "linux,rc-map-name", NULL);
	ret = of_property_read_u32_array(np, "allowed_protos", &irda_dev.allowed_protos,1);
   if(irda_dev.major)
  {
    
    
   irda_dev.devid = MKDEV(irda_dev.major,0);
   ret = register_chrdev_region(irda_dev.devid,1,irda_NAME);
   printk("register successful\r\n");
  }else
  {
    
    
    ret = alloc_chrdev_region(&irda_dev.devid,0,1,irda_NAME);
    irda_dev.major = MAJOR(irda_dev.devid);
    printk("alloc_chrdev successful\r\n");
  }
  if(ret<0){
    
    
    printk("%s Couldn't alloc_chrdev_region,ret = %d\r\n",irda_NAME,ret); 
    goto ERROR;
  }
  cdev_init(&irda_dev.cdev,&irda_drv);
  ret = cdev_add(&irda_dev.cdev,irda_dev.devid,1);
  if(ret<0)
  {
    
    
    printk("Cannot add cdev\n");
    goto ERROR;
  }

  irda_dev.class = class_create(THIS_MODULE,irda_NAME);
  if(IS_ERR(irda_dev.class))
  {
    
    
   printk("Cannot create class\n");
   goto ERROR;
  }else
  {
    
    
    printk("class_create successful\r\n");
  }
  
  irda_dev.device = device_create(irda_dev.class,NULL,irda_dev.devid,NULL,irda_NAME);
  if(IS_ERR(irda_dev.device))
  {
    
    
    printk("Cannot create device\n");
    goto ERROR;
  }else
  {
    
    
    printk("device_create successful\r\n");
  }
  return 0;
ERROR:
  unregister_chrdev_region(irda_dev.devid, 1);
  return -1;
}

static int irda_remove(struct platform_device *pdev)
{
    
    
 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
 gpio_free(irda_dev.gpio_nr);
 cdev_del(&irda_dev.cdev);
 unregister_chrdev_region(irda_dev.devid,1);
 device_destroy(irda_dev.class,irda_dev.devid);
 class_destroy(irda_dev.class);
 return 0;
}


static const struct of_device_id my_irda[]=
{
    
    
  {
    
     .compatible = "myirda,irdadrv"},
  {
    
     },
};

static struct platform_driver irda_driver = {
    
    
  .probe = irda_probe,
  .remove = irda_remove,
  .driver = {
    
    
    .name = "myirda",
    .of_match_table = my_irda,
  },
};

static int __init irda_modules_init(void)
{
    
    
   int err;
   printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
   /* 1.register led_drv*/
   err = platform_driver_register(&irda_driver);
   return err;
}

/* 5. Exit Function */
static void __exit irda_modules_exit(void)
{
    
    
  printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
  platform_driver_unregister(&irda_driver);
}

/* 6. complete dev information*/

module_init(irda_modules_init);//init 
module_exit(irda_modules_exit);//exit

MODULE_LICENSE("GPL");

程序的主要架构为:从设备树读取属性→文件ioctl→初始化→gpio中断→记录电平/定时器→解码器→input系统
设备树方面不再做解释,主要是两方面。
其一,初始化阶段:
主要初始化了rcdev的一系列属性以及针对从设备树上读取的属性来更改rcdev的属性,包括active_low、allowed_protos、map-name。
值得注意的是,在使用这个map-name之前,先使用了rc_map_register(&nec_hs0038_map)去注册它,并再关闭文件时进行了注销。这种写法是参考博客1,官方的做法是创建一个独立的.C文件,并将其作为模组进行装载到系统中,这里做法有点不一样,比较省事吧。
其二,中断与定时器:
这里的代码基本上就是从官方代码gpio-ir-recv.c上copy而来,主要的逻辑是:红外接收器→GPIO电平变化→中断触发→中断处理函数→记录电平→处理函数→定时器→定时器函数→事件保存与处理。
下面来讲一下map映射的原理:
nec scancode→KEY事件,即从NEC解码的数据映射至Linux input系统的按键事件。
第一个方面:如何获得scancode?
如果懒的话可直接复制官方的map,即:100ask_rc-nec.c中的内容。但是你一定要用它的通用模组的遥控器,否则可能出现scancode值没有映射的问题,这样的话就没有打印了,并且在read event文件时是阻塞阅读,没有打印就不会上报,就会和卡死一样。所以,针对于一般的情况,我们需要取得在内核打印的sancode,方法很简单,在ir-nec-decoder.c中的ir_nec_decode函数的case STATE_TRAILER_SPACE下最后几行的rc_keydown(dev,scancode,0)前加上一行打印,printk(“NEC sancode 0x%04x\n”,scancode)即可。加上之后,一定要注意要重新编译大内核并替换,以确保内核中的代码改变。
加上了之后打印可能为这样(要打开printk的打印等级):
[ 2115.955807] NEC scancode 0x0044
Msg->code:20 Msg->value:1
[ 2116.094961] NEC scancode 0x0044
Msg->code:20 Msg->value:0
那么现在还有一个问题,如何做到遥控器上的按键和input系统的按键相对应呢?这就不得不说到map了。
例如本代码中自定义的map中的这一行:{ 0x44, KEY_T},
它的意思是:scancode为0x44时,input系统键值上传字母"T"。实际上因为KEY中没有KEY_TEST,因此笔者使用KEY_T来替代遥控器上的Test按键。包括KEY_C也是替代遥控器上的C键。遥控器如下图:
红外遥控器
值得注意的是,KEY_POWER以及其他的KEY键值都定义在 include/uapi/linux/input-event-codes.h中,如果你使用了一个其中没有定义的KEY键值,那么在编译时就会报错,如下:编译报错
解决办法时两种:在input-event-codes.h中找其他的键值去替换或者是直接在里面重新定义一个键值,重新定义的话也是需要重新编译大内核的噢。
在介绍完了这个之后,细心的小盆友可能已经发现,笔者的按键映射map是按照遥控器从左到右,从上到下依次排序的。
【四】Makefile

KERN_DIR = //home/book/100ask_imx6ull-sdk/Linux-4.9.88

all:
	make -C $(KERN_DIR) M=`pwd` modules
	$(CROSS_COMPILE)gcc -o irda_app irda_app.c


clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f irda_app


obj-m   +=irda_my_drv.o 

【五】使用

insmod irda_my_drv.ko
./irda_app /dev/myirda

【六】挖坑:既然学会了红外遥控器,不如用它来控制控制东西?接下来学习PWM控制电机,就拿它来控制电机吧!这样就完成了一个红外遥控器电风扇的简单项目。
参考博客:
https://www.cnblogs.com/lifexy/p/9783694.html
https://www.cnblogs.com/lifexy/p/9783914.html
https://blog.51cto.com/u_15315240/5110205
https://blog.csdn.net/weixin_71478434/article/details/126511672?ops_request_misc=&request_id=&biz_id=102&utm_term=Linux%20Irda%20%E5%BA%94%E7%94%A8&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-126511672.142v88control,239v2insert_chatgpt&spm=1018.2226.3001.4187
https://blog.csdn.net/qq_41683305/article/details/124844274
https://blog.csdn.net/obanaganastar/article/details/124350911
参考代码:
100ask_irda.c
100ask_rc-nec.c
gpio-ir-recv.c

猜你喜欢

转载自blog.csdn.net/qq_32006213/article/details/131283807