Linux驱动 | input 子系统详解

系统 Linux
Linux输入设备种类繁杂,常见的包括触摸屏、键盘、鼠标、摇杆等;这些输入设备属于字符设备,而linux将这些设备的共同特性抽象出来,Linux input 子系统就产生了。

[[420659]]

1. 模块概述

1.1.相关资料和代码研究

  1. drivers/input/ 
  2. include/uapi/linux/input-event-codes.h 

2. 模块功能

linux核心的输入框架

3. 模块学习

3.1.概述

Linux输入设备种类繁杂,常见的包括触摸屏、键盘、鼠标、摇杆等;这些输入设备属于字符设备,而linux将这些设备的共同特性抽象出来,Linux input 子系统就产生了。

3.2.软件架构

输入子系统是由设备驱动层(input driver)、输入核心层(input core)、输入事件处理层(input event handle)组成,具体架构如图4.1所示:

(1)input设备驱动层:负责具体的硬件设备,将底层的硬件输入转化为统一的事件形式,向input核心层和汇报;*(2)input核心层:连接input设备驱动层与input事件处理层,向下提供驱动层的接口,向上提供事件处理层的接口;*(3)input事件处理层:为不同硬件类型提供了用户访问以及处理接口,将硬件驱动层传来的事件报告给用户程序。

在input子系统中,每个事件的发生都使用事件(type)->子事件(code)->值(value) 所有的输入设备的主设备号都是13,input-core通过次设备来将输入设备进行分类,如0-31是游戏杆,32-63是鼠标(对应Mouse Handler)、64-95是事件设备(如触摸屏,对应Event Handler)。

Linux输入子系统支持的数据类型

定义的按键值

  1. #define KEY_RESERVED           0 
  2. #define KEY_ESC                 1 
  3. #define KEY_1                   2 
  4. #define KEY_2                   3 
  5. #define KEY_3                   4 
  6. #define KEY_4                   5 
  7. #define KEY_5                   6 
  8. #define KEY_6                   7 
  9. #define KEY_7                   8 
  10. #define KEY_8                   9 
  11. #define KEY_9                   10 
  12. #define KEY_0                   11 
  13. ... 

3.3.数据结构

三个数据结构input_dev,input_handle,input_handler之间的关系如图4.2、4.3所示

  1. input_dev:是硬件驱动层,代表一个input设备。 
  2. input_handler:是事件处理层,代表一个事件处理器。 
  3. input_handle:属于核心层,代表一个配对的input设备与input事件处理器。 
  4. input_dev 通过全局的input_dev_list链接在一起,设备注册的时候完成这个操作。 

input_handler 通过全局的input_handler_list链接在一起。事件处理器注册的时候实现了这个操作(事件处理器一般内核自带,不需要我们来写)

input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_dev 和 input_handler 的h_list上了。通过input_dev 和input_handler就可以找到input_handle在设备注册和事件处理器,注册的时候都要进行配对工作,配对后就会实现链接。通过input_handle也可以找到input_dev和input_handler。

我们可以看到,input_device和input_handler中都有一个h_list,而input_handle拥有指向input_dev和input_handler的指针,也就是说input_handle是用来关联input_dev和input_handler的。

那么为什么一个input_device和input_handler中拥有的是h_list而不是一个handle呢?因为一个device可能对应多个handler,而一个handler也不能只处理一个device,比如说一个鼠标,它可以对应even handler,也可以对应mouse handler,因此当其注册时与系统中的handler进行匹配,就有可能产生两个实例,一个是evdev,另一个是mousedev,而任何一个实例中都只有一个handle。至于以何种方式来传递事件,就由用户程序打开哪个实例来决定。后面一个情况很容易理解,一个事件驱动不能只为一个甚至一种设备服务,系统中可能有多种设备都能使用这类handler,比如event handler就可以匹配所有的设备。在input子系统中,有8种事件驱动,每种事件驱动最多可以对应32个设备,因此dev实例总数最多可以达到256个

3.3.1. Input_dev

输入设备

  1. /* include/linux/input.h */ 
  2. struct input_dev { 
  3.      const char *name;  /* 设备名称 */ 
  4.      const char *phys;  /* 设备在系统中的路径 */ 
  5.      const char *uniq;  /* 设备唯一id */ 
  6.      struct input_id id;  /* input设备id号 */ 
  7.  
  8.      unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; 
  9.  
  10.      unsigned long evbit[BITS_TO_LONGS(EV_CNT)];  /* 设备支持的事件类型,主要有EV_SYNC,EV_KEY,EV_KEY,EV_REL,EV_ABS等*/  
  11. unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];  /* 按键所对应的位图 */ 
  12.      unsigned long relbit[BITS_TO_LONGS(REL_CNT)];  /* 相对坐标对应位图 */ 
  13.      unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];  /* 决定左边对应位图 */ 
  14.      unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  /* 支持其他事件 */ 
  15.      unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  /* 支持led事件 */ 
  16.      unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  /* 支持声音事件 */ 
  17.      unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  /* 支持受力事件 */ 
  18.      unsigned long swbit[BITS_TO_LONGS(SW_CNT)];  /* 支持开关事件 */ 
  19.  
  20.      unsigned int hint_events_per_packet;  /*  平均事件数*/ 
  21.  
  22.      unsigned int keycodemax;  /* 支持最大按键数 */ 
  23.      unsigned int keycodesize;  /* 每个键值字节数 */ 
  24.      void *keycode;  /* 存储按键值的数组的首地址 */ 
  25.  
  26.      int (*setkeycode)(struct input_dev *dev, 
  27.                  const struct input_keymap_entry *ke, unsigned int *old_keycode); 
  28.      int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke); 
  29.  
  30.      struct ff_device *ff;  /* 设备关联的反馈结构,如果设备支持 */ 
  31.  
  32.      unsigned int repeat_key;  /* 最近一次按键值,用于连击 */ 
  33.      struct timer_list timer;  /* 自动连击计时器 */ 
  34.  
  35.      int rep[REP_CNT];  /* 自动连击参数 */ 
  36.  
  37.      struct input_mt *mt;  /* 多点触控区域 */ 
  38.  
  39.      struct input_absinfo *absinfo;  /* 存放绝对值坐标的相关参数数组 */ 
  40.  
  41.      unsigned long key[BITS_TO_LONGS(KEY_CNT)];  /* 反应设备当前的案件状态 */ 
  42.      unsigned long led[BITS_TO_LONGS(LED_CNT)];  /* 反应设备当前的led状态 */ 
  43.      unsigned long snd[BITS_TO_LONGS(SND_CNT)];  /* 反应设备当前的声音状态 */ 
  44.      unsigned long sw[BITS_TO_LONGS(SW_CNT)];  /* 反应设备当前的开关状态 */ 
  45.  
  46.      int (*open)(struct input_dev *dev);  /* 第一次打开设备时调用,初始化设备用 */ 
  47.      void (*close)(struct input_dev *dev);  /* 最后一个应用程序释放设备事件,关闭设备 */ 
  48.      int (*flush)(struct input_dev *dev, struct file *file); /* 用于处理传递设备的事件 */ 
  49. int (*event)(struct input_dev *dev, unsigned int type, unsigned int code,          int value);  /* 事件处理函数,主要是接收用户下发的命令,如点亮led */ 
  50.  
  51.      struct input_handle __rcu *grab;  /* 当前占有设备的input_handle */ 
  52.  
  53.      spinlock_t event_lock;  /* 事件锁 */ 
  54.      struct mutex mutex;  /* 互斥体 */ 
  55.  
  56.      unsigned int users;  /* 打开该设备的用户数量(input_handle) */ 
  57.      bool going_away;  /* 标记正在销毁的设备 */ 
  58.  
  59.      struct device dev;  /* 一般设备 */ 
  60.  
  61.      struct list_head h_list;  /* 设备所支持的input handle */ 
  62.      struct list_head node;  /* 用于将此input_dev连接到input_dev_list */ 
  63.  
  64.      unsigned int num_vals;  /* 当前帧中排队的值数 */ 
  65.      unsigned int max_vals;  /*  队列最大的帧数*/ 
  66.      struct input_value *vals;  /*  当前帧中排队的数组*/ 
  67.  
  68.      bool devres_managed; /* 表示设备被devres 框架管理,不需要明确取消和释放*/ 
  69. }; 

3.3.2. Input_handler

处理具体的输入事件的具体函数

  1. /* include/linux/input.h */ 
  2. struct input_handler { 
  3.  
  4.      void *private;  /* 存放handle数据 */ 
  5.  
  6. void (*event)(struct input_handle *handle, unsigned int type, unsigned  int code, int value); 
  7.      void (*events)(struct input_handle *handle, 
  8.              const struct input_value *vals, unsigned int count); 
  9. bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); 
  10.      bool (*match)(struct input_handler *handler, struct input_dev *dev); 
  11. int (*connect)(struct input_handler *handler, struct input_dev *dev, const  struct input_device_id *id); 
  12.      void (*disconnect)(struct input_handle *handle); 
  13.      void (*start)(struct input_handle *handle); 
  14.  
  15.      bool legacy_minors; 
  16.      int minor; 
  17.      const char *name;  /* 名字 */ 
  18.  
  19.      const struct input_device_id *id_table;  /* input_dev匹配用的id */ 
  20.  
  21. struct list_head h_list; /* 用于链接和handler相关的handle,input_dev与input_handler配对之后就会生成一个input_handle结构 */ 
  22.      struct list_head node;  /* 用于将该handler链入input_handler_list,链接所有注册到内核的所有注册到内核的事件处理器 */ 
  23. }; 

3.3.3. Input_handle

连接输入设备和处理函数

  1. /* include/linux/input.h */ 
  2. struct input_handle { 
  3.      void *private;  /* 数据指针 */ 
  4.  
  5.      int open;  /* 打开标志,每个input_handle 打开后才能操作 */ 
  6.      const char *name;  /* 设备名称 */ 
  7.  
  8.      struct input_dev *dev;  /* 指向所属的input_dev */ 
  9.      struct input_handler *handler;  /* 指向所属的input_handler */ 
  10.  
  11.      struct list_head d_node;  /* 用于链入所指向的input_dev的handle链表 */ 
  12.      struct list_head h_node;  /* 用于链入所指向的input_handler的handle链表 */ 
  13. }; 

3.3.4. Evdev

字符设备事件

  1. /* drivers/input/evdev.c */ 
  2. struct evdev { 
  3.      int open;    /* 设备被打开的计数 */ 
  4.      struct input_handle handle;  /* 关联的input_handle */  
  5.      wait_queue_head_t wait;  /* 等待队列,当前进程读取设备,没有事件产生时, 
  6. 进程就会sleep */ 
  7.      struct evdev_client __rcu *grab;  /* event响应 */ 
  8. struct list_head client_list;  /* evdev_client链表,说明evdev设备可以处理多个 evdev _client,可以有多个进程访问evdev设备 */ 
  9.      spinlock_t client_lock; 
  10.      struct mutex mutex; 
  11.      struct device dev; 
  12.      struct cdev cdev; 
  13.      bool exist;   /* 设备存在判断 */ 
  14. }; 

3.3.5. evdev_client

字符设备事件响应

  1. /* drivers/input/evdev.c */ 
  2. struct evdev_client { 
  3.      unsigned int head;  /* 动态索引,每加入一个event到buffer中,head++ */ 
  4.      unsigned int tail;  /* 动态索引,每取出一个buffer中到event,tail++ */ 
  5.      unsigned int packet_head;  /* 数据包头部 */ 
  6.      spinlock_t buffer_lock;   
  7.      struct fasync_struct *fasync;  /* 异步通知函数 */ 
  8.      struct evdev *evdev;   
  9.      struct list_head node;  /* evdev_client链表项 */ 
  10.      int clkid; 
  11.      unsigned int bufsize; 
  12.      struct input_event buffer[];  /* 用来存放input_dev事件缓冲区 */ 
  13. }; 

3.3.6. Evdev_handler

evdev_handler事件处理函数

  1. /* drivers/input/input.c */ 
  2. static struct input_handler evdev_handler = { 
  3.      .event  = evdev_event,   /* 事件处理函数, */   
  4.      .events = evdev_events,  /* 事件处理函数, */ 
  5.      .connect = evdev_connect, /* 连接函数,将事件处理和输入设备联系起来 */ 
  6.      .disconnect = evdev_disconnect,  /* 断开该链接 */ 
  7.      .legacy_minors = true
  8.      .minor  = EVDEV_MINOR_BASE, 
  9.      .name  = "evdev", /* handler名称 */ 
  10.      .id_table = evdev_ids, /* 断开该链接 */ 
  11. }; 

3.3.7. input_event

标准按键编码信息

  1. /* drivers/input/evdev.c */ 
  2. struct input_event {                                                             
  3.     struct timeval time;   /* 事件发生的时间  */                                 
  4.     __u16 type;             /* 事件类型 */                                       
  5.     __u16 code;             /* 事件码 */                                         
  6.     __s32 value;            /* 事件值 */                                         
  7. };    

3.3.8. input_id

和input输入设备相关的id信息

  1. /* include/uapi/linux/input.h */ 
  2. struct input_id {   
  3.     __u16 bustype;  /* 总线类型 */   
  4.     __u16 vendor;  /* 生产厂商 */   
  5.     __u16 product;  /* 产品类型 */  
  6.     __u16 version;  /* 版本 */ 
  7.  }; 

3.3.9. input_device_id

  1. /* include/uapi/linux/input.h */ 
  2. struct input_device_id { 
  3.  
  4.      kernel_ulong_t flags; 
  5.  
  6.      __u16 bustype;  /* 总线类型 */ 
  7.      __u16 vendor;  /* 生产厂商 */ 
  8.      __u16 product;  /* 产品类型 */ 
  9.      __u16 version;  /* 版本 */ 
  10.  
  11.      kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1]; 
  12.      kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1]; 
  13.      kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1]; 
  14.      kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1]; 
  15.      kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1]; 
  16.      kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1]; 
  17.      kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1]; 
  18.      kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1]; 
  19.      kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1]; 
  20.      kernel_ulong_t propbit[INPUT_DEVICE_ID_PROP_MAX / BITS_PER_LONG + 1]; 
  21.  
  22.      kernel_ulong_t driver_info; 
  23. }; 

3.3.10. input_even

输入事件的传递已input_event为基本单位

  1. struct input_event { 
  2.  struct timeval time; //时间戳 
  3.      __u16 type; //事件总类型 
  4.      __u16 code; //事件子类型 
  5.      __s32 value; //事件值 
  6. }; 

3.4. Linux input 子系统关键流程

核心层,执行的时候会注册设备号,然后在handler层注册input_handler,也就是evdev_handler会注册到核心层维护的链表中。

然后进行硬件初始化获取数据,而且需要将设备注册到链表中。注册进来就就会遍历input_handler_list链表,找到对应的handler,匹配成功后会调用connect方法。connect分配evdev,evdev就记录了input_handler和input_device之间的关系,同时创建设备节点,还会注册cdev从而可以让应用调用。

当应用程序调用open,read等接口的时候就会调用input_handler层实现的xxx_open,那么open就会分配好evdev_client,最终在input_dev层上报数据的时候会自动调用input_handler,input_handler就会调用events填充上报的数据到缓冲区client,此时如果没有唤醒队列的话应用read的时候会阻塞,而唤醒队列后最终使用copy_to_user来给应用数据。设备驱动程序上报事件的函数有:

  1. input_report_key //上报按键事件 
  2. input_report_rel //上报相对坐标事件 
  3. input_report_abs //上报绝对坐标事件 
  4. input_report_ff_status 
  5. input_report_switch 
  6. input_sync //上报完成后需要调用这些函数来通知系统处理完整事件  
  7. input_mt_sync //上报完成后需要调用这些函数来通知系统处理完整事件 

这些函数其实是input_event函数的封装,调用的都是input_event函数,在输入设备驱动(input_dev)中,一般通过轮询或中断方式获取输入事件的原始值(raw value),经过处理后再使用input_event()函数上报;核心层将事件数据(type、code、value)打包、分发至事件处理器;调用关系为:input_event->input_handle_event->input_pass_values,这一函数都在input.c实现。

3.4.1. Input 设备注册流程

输入设备注册过程如图4.3所示

图4.3 输入设备注册流程图

3.4.2. 连接设备流程

连接设备流程如图4.4所示

图4.4 连接设备流程图

3.4.3. 事件上报流程

事件上报流程如图4.5所示

3.4.4. 数据读取流程

数据读取流程如图4.6所示

3.5.关键函数解析

3.5.1. input_init

input子系统使用subsys_initcall宏修饰input_init()函数在内核启动阶段被调用。input_init()函数在内核启动阶段被调用。input_init()函数的主要工作是:在sys文件系统下创建一个设备类(/sys/class/input),调用register_chrdev()函数注册input设备。

  1. /* drivers/input/input.c */ 
  2. static int __init input_init(void) 
  3.      int err; 
  4.  
  5.      err = class_register(&input_class);  /* 注册类,放在sys/class下 */   
  6.      if (err) { 
  7.           pr_err("unable to register input_dev class\n"); 
  8.           return err; 
  9.      } 
  10.  
  11.      err = input_proc_init();  /* 在proc目录下建立相关目录 */ 
  12.      if (err) 
  13.           goto fail1; 
  14.  
  15.      err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), 
  16.         INPUT_MAX_CHAR_DEVICES, "input");  /* 注册字符设备编号,INPUT_MAJOR   永远是13 */   
  17.      if (err) { 
  18.           pr_err("unable to register char major %d", INPUT_MAJOR); 
  19.           goto fail2; 
  20.      } 
  21.  
  22.      return 0; 
  23.  
  24.  fail2: input_proc_exit(); 
  25.  fail1: class_unregister(&input_class); 
  26.      return err; 

3.5.2. Input_register_device

  1. /* drivers/input/input.c */ 
  2. int input_register_device(struct input_dev *dev) 
  3.     struct atomic_t  input_no = ATOMIC_INIT(0); 
  4.      struct input_devres *devres = NULL
  5.      struct input_handler *handler; 
  6.      unsigned int packet_size; 
  7.      const char *path; 
  8.      int error; 
  9.  
  10.      if (dev->devres_managed) { 
  11.           devres = devres_alloc(devm_input_device_unregister, 
  12.                   sizeof(*devres), GFP_KERNEL); 
  13.       if (!devres) 
  14.            return -ENOMEM; 
  15.  
  16.       devres->input = dev; 
  17.  } 
  18.  
  19.      /* 每个input_device都会产生EV_SYN/SYN_REPORT时间,所以就放在一起设置 */ 
  20.      __set_bit(EV_SYN, dev->evbit); 
  21.  
  22.      /* KEY_RESERVED is not supposed to be transmitted to userspace. */ 
  23.      __clear_bit(KEY_RESERVED, dev->keybit); 
  24.  
  25.      /* 没有设置的位,确保被清零 */ 
  26.      input_cleanse_bitmasks(dev); 
  27.      /*  */ 
  28.      packet_size = input_estimate_events_per_packet(dev); 
  29.      if (dev->hint_events_per_packet < packet_size) 
  30.            dev->hint_events_per_packet = packet_size; 
  31.  
  32.      dev->max_vals = dev->hint_events_per_packet + 2; 
  33.      dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL); 
  34.      if (!dev->vals) { 
  35.           error = -ENOMEM; 
  36.           goto err_devres_free; 
  37.      } 
  38.  
  39.     /* 如果延时周期是程序预先设定的,那么是由驱动自动处理,主要是为了处理重复按键 */ 
  40.      init_timer(&dev->timer); 
  41.      if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) { 
  42.           dev->timer.data = (long) dev; 
  43.           dev->timer.function = input_repeat_key; 
  44.           dev->rep[REP_DELAY] = 250; 
  45.           dev->rep[REP_PERIOD] = 33; 
  46.       } 
  47.  
  48.      if (!dev->getkeycode)  /* 获取按键值 */ 
  49.           dev->getkeycode = input_default_getkeycode; 
  50.  
  51.      if (!dev->setkeycode)  /* 设置按键值 */ 
  52.           dev->setkeycode = input_default_setkeycode; 
  53.  
  54.      error = device_add(&dev->dev);  /* 将dev注册到sys */ 
  55.      if (error) 
  56.           goto err_free_vals; 
  57.  
  58.      path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); 
  59.      pr_info("%s as %s\n"
  60.       dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); 
  61.      kfree(path); 
  62.  
  63.      error = mutex_lock_interruptible(&input_mutex); 
  64.      if (error) 
  65.           goto err_device_del; 
  66.  
  67.      list_add_tail(&dev->node, &input_dev_list);  /* 将新的dev放入链表中 */ 
  68. /* 遍历input_handler_list链表中的所有input_handler,是否支持这个新input_dev ; 
  69. 若两者支持,便进行连接 */ 
  70.      list_for_each_entry(handler, &input_handler_list, node) 
  71.       input_attach_handler(dev, handler);  
  72.  
  73.      input_wakeup_procfs_readers(); 
  74.  
  75.      mutex_unlock(&input_mutex); 
  76.  
  77.      if (dev->devres_managed) { 
  78.       dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n"
  79.            __func__, dev_name(&dev->dev)); 
  80.       devres_add(dev->dev.parent, devres); 
  81.   } 
  82.  return 0; 
  83.  
  84. err_device_del: 
  85.      device_del(&dev->dev); 
  86. err_free_vals: 
  87.      kfree(dev->vals); 
  88.      dev->vals = NULL
  89. err_devres_free: 
  90.      devres_free(devres); 
  91.      return error; 
  92. EXPORT_SYMBOL(input_register_device); 

input_dev_list和input_handler_list是全局的一个链表

  1. static LIST_HEAD(input_dev_list); 
  2. static LIST_HEAD(input_handler_list); 

list_for_each_entry是一个宏,展开如下 获取input_handler_list的每一项和input_dev匹配,通过for循环遍历.

  1. for (handler = list_first_entry(input_handler_list, &handler, node);  
  2.      &handler->node != (input_handler_list);      
  3.      &handler = list_next_entry(&handler, node)) 
  4.  
  5.      input_attach_handler(dev, handler); 

list_first_entry 获得第一个列表元素 list_next_entry 获得下一个列表元素

3.5.3. input_register_handle

注册一个handle,链接input_handler和input_dev的h_list

  1. /* drivers/input/input.c */ 
  2. int input_register_handle(struct input_handle *handle) 
  3.      struct input_handler *handler = handle->handler; 
  4.      struct input_dev *dev = handle->dev; 
  5.      int error; 
  6.  
  7.      error = mutex_lock_interruptible(&dev->mutex); 
  8.      if (error) 
  9.          return error; 
  10.      
  11.      if (handler->filter) 
  12.           list_add_rcu(&handle->d_node, &dev->h_list); 
  13.      else 
  14.          list_add_tail_rcu(&handle->d_node, &dev->h_list); 
  15. /* 将handle的d_node,链接到其相关的input_dev的h_list链表中  */ 
  16.  
  17.      mutex_unlock(&dev->mutex); 
  18.  
  19.      list_add_tail_rcu(&handle->h_node, &handler->h_list); 
  20. /* 将handle的h_node,链接到其相关的input_handler的h_list链表中 */ 
  21.  
  22.      if (handler->start) 
  23.           handler->start(handle); 
  24.  
  25.  return 0; 
  26. EXPORT_SYMBOL(input_register_handle); 

3.5.4. input_register_handler

注册一个事件,进行匹配设备和事件的绑定

  1. /* drivers/input/input.c */ 
  2. int input_register_handler(struct input_handler *handler) 
  3.      struct input_dev *dev; 
  4.      int error; 
  5.  
  6.      error = mutex_lock_interruptible(&input_mutex); 
  7.      if (error) 
  8.           return error; 
  9.  
  10.     INIT_LIST_HEAD(&handler->h_list); 
  11.  
  12.      list_add_tail(&handler->node, &input_handler_list);  /* 连接到input_handler_list链表中 */ 
  13. /* 遍历input_dev_list,配对 input_dev 和 handler */ 
  14.      list_for_each_entry(dev, &input_dev_list, node) 
  15.       input_attach_handler(dev, handler);  /* event节点加入列表 */ 
  16.  
  17.      input_wakeup_procfs_readers(); 
  18.  
  19.      mutex_unlock(&input_mutex); 
  20.      return 0; 
  21. EXPORT_SYMBOL(input_register_handler); 

3.5.5. evdev_connect

事件处理器evdev,生成一个新的evdev设备,连接input核心,回调函数。

  1. /* drivers/input/evdev.c */ 
  2. static int evdev_connect(struct input_handler *handler, struct input_dev *dev, 
  3.     const struct input_device_id *id) 
  4.      struct evdev *evdev; 
  5.      int minor; 
  6.      int dev_no; 
  7.      int error; 
  8.     /* 获取次设备号,从evdev_table中找到一个未使用的最小的数组项,最大值32 */ 
  9.      minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); 
  10.      if (minor < 0) { 
  11.           error = minor; 
  12.           pr_err("failed to reserve new minor: %d\n", error); 
  13.           return error; 
  14.      } 
  15.     /* 分配空间 */ 
  16.      evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); 
  17.      if (!evdev) { 
  18.           error = -ENOMEM; 
  19.           goto err_free_minor; 
  20.      } 
  21. /* 初始化client_list链表头,代表多少应用读写这个设备 */ 
  22.      INIT_LIST_HEAD(&evdev->client_list);     
  23.      spin_lock_init(&evdev->client_lock);  /* 加锁 */  
  24.      mutex_init(&evdev->mutex);  /*  */ 
  25. init_waitqueue_head(&evdev->wait);  /* 初始化等待队列,当evdev没有数据可读时,就 在 该队列上睡眠 */ 
  26.      evdev->exist = true;  /* 设备存在 */ 
  27.  
  28.      dev_no = minor; 
  29.   
  30.      if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) 
  31.           dev_no -= EVDEV_MINOR_BASE; 
  32.      dev_set_name(&evdev->dev, "event%d", dev_no);  /* 设置设备名为eventX */ 
  33.  
  34.      evdev->handle.dev = input_get_device(dev);  /* 获取设备 */ 
  35.      evdev->handle.name = dev_name(&evdev->dev);  /* 设备名称 */ 
  36.      evdev->handle.handler = handler;  /* handler绑定 */   
  37.      evdev->handle.private = evdev;  /* evdev数据指向 */ 
  38.  
  39.      evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);  /* sysfs下的设备号 */ 
  40.      evdev->dev.class = &input_class;  /* 将input_class作为设备类 */ 
  41.      evdev->dev.parent = &dev->dev;  /* input_dev作为evdev的父设备 */ 
  42.      evdev->dev.release = evdev_free;  /* 释放函数 */ 
  43.      device_initialize(&evdev->dev);  /* 初始化设备 */ 
  44.         /* 注册一个handle处理事件 */ 
  45.      error = input_register_handle(&evdev->handle); if (error) 
  46.           goto err_free_evdev; 
  47.  
  48.      cdev_init(&evdev->cdev, &evdev_fops);  /* 字符设备初始化 */ 
  49.  
  50.      error = cdev_device_add(&evdev->cdev, &evdev->dev);  /* 添加字符设备 */ 
  51.      if (error) 
  52.           goto err_cleanup_evdev; 
  53.  
  54.      return 0; 
  55.  
  56. err_cleanup_evdev: 
  57.      evdev_cleanup(evdev); 
  58. err_unregister_handle: 
  59.      input_unregister_handle(&evdev->handle); 
  60. err_free_evdev: 
  61.      put_device(&evdev->dev); 
  62. err_free_minor: 
  63.      input_free_minor(minor); 
  64.      return error; 

(1)是在保存区驱动设备名字,比如下图(键盘驱动)event1:因为没有设置设备号,默认从小到大排序,其中event0是表示input子系统,所以键盘驱动名字就是event1。

(2)是保存驱动设备的主次设备号,其中主设备号INPUT_MAJOR=13,次设备号=EVSEV_MINOR_BASE+驱动程序本身设备号。

(3)会在/sys/class/input类下创建驱动设备event%d,比如键盘驱动event1

(4)最终进入input_register_handler()函数来注册handle。

3.5.6. input_attach_handler

设备匹配具体实现

  1. /* drivers/input/input.c */ 
  2. static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)   
  3. {   
  4.     const struct input_device_id *id;   
  5.     int error;   
  6.  
  7. /* blacklist是handler该忽略input设备类型 */     
  8.     if (handler->blacklist && input_match_device(handler->blacklist, dev))   
  9.         return -ENODEV;   
  10.         id = input_match_device(handler->id_table, dev);   
  11.     /* 这个是主要的配对函数,匹配handler和device的ID */ 
  12.     if (!id)   
  13.         return -ENODEV;   
  14.    
  15.     error = handler->connect(handler, dev, id);   
  16.     /* 配对成功调用handler的connect函数,这个函数在事件处理器中定义,主要生成一个input_handle结构,并初始化,还生成一个事件处理器相关的设备结构 */ 
  17.     if (error && error != -ENODEV)   
  18.         printk(KERN_ERR   
  19.             "input: failed to attach handler %s to device %s, "   
  20.             "error: %d\n",   
  21.             handler->name, kobject_name(&dev->dev.kobj), error);   
  22.         /* 出错处理 */   
  23.     return error;   
  24.  } 

3.5.7. input_match_device

比较input_dev中的id和handler支持的id,存放在handler中的id_table。

  1. /* drivers/input/input.c */ 
  2. static const struct input_device_id *input_match_device(struct input_handler *handler, struct input_dev *dev) 
  3.      const struct input_device_id *id; 
  4.     /* 遍历id_table的id匹配 */ 
  5.      for (id = handler->id_table; id->flags || id->driver_info; id++) { 
  6.           if (input_match_device_id(dev, id) && 
  7.               (!handler->match || handler->match(handler, dev))) { 
  8.                return id; 
  9.           } 
  10.       } 
  11.  
  12.      return NULL

3.5.8. input_allocate_device

初始化input_dev设备

  1. /* drivers/input/evdev.c */ 
  2. struct input_dev *input_allocate_device(void) 
  3.      static atomic_t input_no = ATOMIC_INIT(-1); 
  4.      struct input_dev *dev; 
  5. /* 遍历id_table的id匹配 */ 
  6.      dev = kzalloc(sizeof(*dev), GFP_KERNEL); 
  7.      if (dev) { 
  8.           dev->dev.type = &input_dev_type; 
  9.           dev->dev.class = &input_class; 
  10.           device_initialize(&dev->dev); 
  11.           mutex_init(&dev->mutex); 
  12.           spin_lock_init(&dev->event_lock); 
  13.           timer_setup(&dev->timer, NULL, 0); 
  14.           INIT_LIST_HEAD(&dev->h_list); 
  15.           INIT_LIST_HEAD(&dev->node); 
  16.  
  17.            dev_set_name(&dev->dev, "input%lu"
  18.         (unsigned long)atomic_inc_return(&input_no)); 
  19.  
  20.   __module_get(THIS_MODULE); 
  21.  } 
  22.  
  23.  return dev; 
  24. EXPORT_SYMBOL(input_allocate_device); 

3.5.9. input_event

调用input_handle_event进行事件处理 dev是上报事件的设备,type是事件总类型,code是事件子类型,value是事件值。

  1. /* drivers/input/input.c */ 
  2. void (struct input_dev *dev, unsigned int type, unsigned int code, int value) 
  3.      unsigned long flags; 
  4.     /* 判断输入事件是否支持该设备 */ 
  5.      if (is_event_supported(type, dev->evbit, EV_MAX)) { 
  6. spin_lock_irqsave(&dev->event_lock, flags);  /* 事件加锁 */ 
  7.           input_handle_event(dev, type, code, value); /* 发送事件调用input_pass_values */ 
  8.           spin_unlock_irqrestore(&dev->event_lock, flags); 
  9.      } 
  10. }EXPORT_SYMBOL(input_event); 

3.5.10. input_handle_event

按键上报的处理函数

  1. /* drivers/input/input.c */ 
  2. static void input_handle_event(struct input_dev *dev, 
  3.           unsigned int type, unsigned int code, int value) 
  4. {   /* 处理事件 */ 
  5.      int disposition = input_get_disposition(dev, type, code, &value); 
  6. /* 处理EV_SYN事件 */ 
  7.      if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) 
  8.           add_input_randomness(type, code, value); 
  9. /* 一些特殊事件需要对dev也上报,比如led */ 
  10.      if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) 
  11.           dev->event(dev, type, code, value); 
  12.  
  13.      if (!dev->vals) 
  14.           return
  15.     /* 向上层handler汇报事件 */ 
  16.      if (disposition & INPUT_PASS_TO_HANDLERS) { 
  17.           struct input_value *v; 
  18.  
  19.           if (disposition & INPUT_SLOT) { 
  20.                v = &dev->vals[dev->num_vals++]; 
  21.                v->type = EV_ABS; 
  22.                v->code = ABS_MT_SLOT; 
  23.                v->value = dev->mt->slot; 
  24.           } 
  25. /* 缓存event事件 */ 
  26.           v = &dev->vals[dev->num_vals++]; 
  27.           v->type = type; 
  28.           v->code = code; 
  29.           v->value = value; 
  30.      } 
  31.     /* 向上层handler汇报事件,刷新缓冲区,上报event事件 */ 
  32.      if (disposition & INPUT_FLUSH) { 
  33.           if (dev->num_vals >= 2) 
  34.                input_pass_values(dev, dev->vals, dev->num_vals); 
  35.           dev->num_vals = 0; 
  36.        /* 缓冲的时间超过上限,也进行上报处理 */ 
  37.      } else if (dev->num_vals >= dev->max_vals - 2) { 
  38.           dev->vals[dev->num_vals++] = input_value_sync; 
  39.           input_pass_values(dev, dev->vals, dev->num_vals);/* 上报event事件 */ 
  40.           dev->num_vals = 0; 
  41.      } 

3.5.11. input_get_disposition

获取input事件类型

  1. /* drivers/input/input.c */ 
  2. static int input_get_disposition(struct input_dev *dev, 
  3.      unsigned int type, unsigned int code, int *pval) 
  4.      int disposition = INPUT_IGNORE_EVENT;  /* 定义初始变量,如果没有更新,最后忽略 */ 
  5.      int value = *pval; 
  6.      /* 处理各类事件 */ 
  7.      switch (type) { 
  8. /* 同步事件 */ 
  9.          case EV_SYN: 
  10.              switch (code) { 
  11.              case SYN_CONFIG: 
  12.                   disposition = INPUT_PASS_TO_ALL; 
  13.                   break; 
  14.  
  15.               case SYN_REPORT: 
  16.                     disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH; 
  17.                     break; 
  18.               case SYN_MT_REPORT: 
  19.                     disposition = INPUT_PASS_TO_HANDLERS; 
  20.                     break; 
  21.       } 
  22.       break; 
  23.  
  24.      case EV_KEY: 
  25.         /* 判断是否支持该键,同时判断按键状态是否改变 */ 
  26.          if (is_event_supported(code, dev->keybit, KEY_MAX)) { 
  27. if (value == 2) { 
  28.                     disposition = INPUT_PASS_TO_HANDLERS; 
  29.                     break; 
  30.                } 
  31. /* 判断value是否改变 */ 
  32.           if (!!test_bit(code, dev->key) != !!value) { 
  33.                 __change_bit(code, dev->key);  /* 按位取反 */ 
  34.                 disposition = INPUT_PASS_TO_HANDLERS; 
  35.           } 
  36.       } 
  37.       break; 
  38.  
  39.      case EV_SW: 
  40.       if (is_event_supported(code, dev->swbit, SW_MAX) && 
  41.           !!test_bit(code, dev->sw) != !!value) { 
  42.  
  43.            __change_bit(code, dev->sw); 
  44.              disposition = INPUT_PASS_TO_HANDLERS; 
  45.       } 
  46.       break; 
  47.  
  48.      case EV_ABS: 
  49.           if (is_event_supported(code, dev->absbit, ABS_MAX)) 
  50.                disposition = input_handle_abs_event(dev, code, &value); 
  51.  
  52.            break; 
  53.  
  54.      case EV_REL: 
  55.           if (is_event_supported(code, dev->relbit, REL_MAX) && value) 
  56.                  disposition = INPUT_PASS_TO_HANDLERS; 
  57.  
  58.            break; 
  59.  
  60.      case EV_MSC: 
  61.           if (is_event_supported(code, dev->mscbit, MSC_MAX)) 
  62.                disposition = INPUT_PASS_TO_ALL; 
  63.  
  64.           break; 
  65.  
  66.      case EV_LED: 
  67.           if (is_event_supported(code, dev->ledbit, LED_MAX) && 
  68.               !!test_bit(code, dev->led) != !!value) { 
  69.  
  70.               __change_bit(code, dev->led); 
  71.              disposition = INPUT_PASS_TO_ALL; 
  72.          } 
  73.          break; 
  74.  
  75.       case EV_SND: 
  76.            if (is_event_supported(code, dev->sndbit, SND_MAX)) { 
  77.                  if (!!test_bit(code, dev->snd) != !!value) 
  78.                       __change_bit(code, dev->snd); 
  79.                  disposition = INPUT_PASS_TO_ALL; 
  80.           } 
  81.           break; 
  82.  
  83.       case EV_REP: 
  84.            if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) { 
  85.                 dev->rep[code] = value; 
  86.                 disposition = INPUT_PASS_TO_ALL; 
  87.            } 
  88.          break; 
  89.  
  90.      case EV_FF: 
  91.       if (value >= 0) 
  92.           disposition = INPUT_PASS_TO_ALL; 
  93.          break; 
  94.  
  95.      case EV_PWR: 
  96.           disposition = INPUT_PASS_TO_ALL; 
  97.           break; 
  98.      } 
  99.  
  100.      *pval = value; 
  101.      return disposition; 

3.5.12. input_pass_event

调用input_pass_values

  1. /* drivers/input/input.c */ 
  2. static void input_pass_event(struct input_dev *dev, 
  3.         unsigned int type, unsigned int code, int value) 
  4.      struct input_value vals[] = { { type, code, value } }; 
  5.  
  6.      input_pass_values(dev, vals, ARRAY_SIZE(vals));  /* 调用input_pass_values */ 

3.5.13. input_pass_values

上报事件的处理

  1. /* drivers/input/input.c */ 
  2. static void input_pass_values(struct input_dev *dev, 
  3.          struct input_value *vals, unsigned int count
  4.      struct input_handle *handle; 
  5.      struct input_value *v; 
  6.  
  7.      if (!count
  8.           return
  9.  
  10.      rcu_read_lock(); 
  11.     /* grab是强制为input device绑定的handler ,如果存在就直接调用 */ 
  12.      handle = rcu_dereference(dev->grab); 
  13.      if (handle) { 
  14.           count = input_to_handler(handle, vals, count); 
  15.      } else { 
  16.     /* 如果device绑定具体的handle,则遍历这个dev上的所有handle,向应用层open过的发送信息 */   
  17.           list_for_each_entry_rcu(handle, &dev->h_list, d_node) 
  18.            if (handle->open) { 
  19.                 count = input_to_handler(handle, vals, count); 
  20.                 if (!count
  21.                      break; 
  22.           } 
  23.      } 
  24.  
  25.      rcu_read_unlock(); 
  26.  
  27.      /* 按键事件自动回复 */ 
  28.      if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { 
  29.           for (v = vals; v != vals + count; v++) { 
  30.                if (v->type == EV_KEY && v->value != 2) { 
  31.                     if (v->value) 
  32.                          input_start_autorepeat(dev, v->code); 
  33.                     else 
  34.                          input_stop_autorepeat(dev); 
  35.                } 
  36.           } 
  37.      } 

函数最终就会调用到handler->event,对事件进行处理。

3.5.14. input_to_handler

  1. /* drivers/input/input.c */ 
  2. static unsigned int input_to_handler(struct input_handle *handle, 
  3.    struct input_value *vals, unsigned int count
  4.      struct input_handler *handler = handle->handler; 
  5.      struct input_value *end = vals; 
  6.      struct input_value *v; 
  7.  
  8.      if (handler->filter) { 
  9.           for (v = vals; v != vals + count; v++) { 
  10.                if (handler->filter(handle, v->type, v->code, v->value)) 
  11.                     continue
  12.                if (end != v) 
  13.                     *end = *v; 
  14.                end++; 
  15.           } 
  16.           count = end - vals; 
  17.      } 
  18.  
  19.      if (!count
  20.           return 0; 
  21.  
  22.      if (handler->events) 
  23.           handler->events(handle, vals, count); 
  24.      else if (handler->event) 
  25.           for (v = vals; v != vals + count; v++) 
  26.                handler->event(handle, v->type, v->code, v->value); 
  27.  
  28.      return count

3.5.15. evdev_events

事件处理函数

  1. /* drivers/input/evdev.c */ 
  2. static void evdev_events(struct input_handle *handle, 
  3.         const struct input_value *vals, unsigned int count
  4.      struct evdev *evdev = handle->private; 
  5.      struct evdev_client *client; 
  6.      ktime_t time_mono, time_real; 
  7.        /* 获取时间信息 */ 
  8.      time_meno = ktime_get(); 
  9.      time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); 
  10.  
  11.      rcu_read_lock(); 
  12.  
  13.      client = rcu_dereference(evdev->grab); 
  14.  /* 如果该evdev有个专用的client,那么就将事件发给它,如果发送给它,如果该evdev不存在专用的 cliect,那就把该事件发送给evdev上client_list链表上所有的client */ 
  15.      if (client) 
  16.           evdev_pass_values(client, vals, count, ev_time);   /* 打包数据 */ 
  17.      else 
  18.           list_for_each_entry_rcu(client, &evdev->client_list, node) 
  19.    evdev_pass_values(client, vals, count, ev_time); 
  20.  
  21.  rcu_read_unlock(); 

3.5.16. evdev_pass_values

填充event数据。

  1. /* drivers/input/evdev.c */ 
  2. static void evdev_pass_values(struct evdev_client *client, 
  3.          const struct input_value *vals, unsigned int count, ktime_t *ev_time) 
  4.      struct evdev *evdev = client->evdev;  
  5.      const struct input_value *v; 
  6.      struct input_event event; 
  7.      struct timespec64 ts; 
  8.      bool wakeup = false
  9.  
  10.      if (client->revoked) 
  11.           return
  12.  
  13.      ts = ktime_to_timespec64(ev_time[client->clk_type]); /* 获取时间戳 */ 
  14.      event.input_event_sec = ts.tv_sec; 
  15.      event.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; 
  16.  
  17.      /* 中断禁止, 获取锁 */ 
  18.     spin_lock(&client->buffer_lock); 
  19.     /* 多个数据 */ 
  20.      for (v = vals; v != vals + count; v++) { 
  21.           if (__evdev_is_filtered(client, v->type, v->code)) 
  22.                 continue
  23.  
  24.           if (v->type == EV_SYN && v->code == SYN_REPORT) { 
  25.                /* drop empty SYN_REPORT */ 
  26.                if (client->packet_head == client->head) 
  27.                       continue
  28.                wakeup = true
  29.           } 
  30.         /* 数据重新封装为event对象 */ 
  31.           event.type = v->type; 
  32.           event.code = v->code; 
  33.           event.value = v->value; 
  34.           __pass_event(client, &event);// 在里面做消息传递 
  35.      } 
  36.  
  37.      spin_unlock(&client->buffer_lock); 
  38.       /* 唤醒队列 */ 
  39.      if (wakeup) 
  40.           wake_up_interruptible(&evdev->wait); 

3.5.17. __pass_event

设备驱动上报事件并不是直接传递给用户空间的,在通用事件处理器(evdev)中,事件被缓冲存在缓冲区中。__pass_event函数里会将input_event放到client结构结构体的环形缓冲区里,即evdev_client结构体的buffer,用户程序通过read()函数从环形缓冲区中获取input_event事件。

  1. /* drivers/input/evdev.c */ 
  2. static void __pass_event(struct evdev_client *client, 
  3.     const struct input_event *event) 
  4.      client->buffer[client->head++] = *event; /*将事件赋值给客户端的input_event缓冲区*/ 
  5.      client->head &= client->bufsize - 1; /*对头head自增指向下一个元素空间 */ 
  6.  
  7.     /*当队头head与队尾tail相等时,说明缓冲区已满 */ 
  8.      if (unlikely(client->head == client->tail)) { 
  9.           /* 
  10.            * This effectively "drops" all unconsumed events, leaving 
  11.            * EV_SYN/SYN_DROPPED plus the newest event in the queue. 
  12.           */ 
  13.           client->tail = (client->head - 2) & (client->bufsize - 1); 
  14. client->buffer[client->tail].input_event_sec = event->input_event_sec; 
  15.           client->buffer[client->tail].input_event_usec = event->input_event_usec; 
  16.           client->buffer[client->tail].type = EV_SYN; 
  17.           client->buffer[client->tail].code = SYN_DROPPED; 
  18.           client->buffer[client->tail].value = 0; 
  19. client->packet_head = client->tail; 
  20.      } 
  21.       /* 当遇到EV_SYN/ SYN_REPORT同步事件时,packet_head移动到对头head位置*/ 
  22.      if (event->type == EV_SYN && event->code == SYN_REPORT) { 
  23.           client->packet_head = client->head; 
  24.           kill_fasync(&client->fasync, SIGIO, POLL_IN); 
  25. static int evdev_connect(struct input_handler *handler, struct input_dev *dev, 
  26.     const struct input_device_id *id) 
  27.      struct evdev *evdev; 
  28.      int minor; 
  29.      int dev_no; 
  30.      int error; 
  31.  
  32.      minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); 
  33.      if (minor < 0) { 
  34.           error = minor; 
  35.           pr_err("failed to reserve new minor: %d\n", error); 
  36.           return error; 
  37.      } 
  38.  
  39.      evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); 
  40.      if (!evdev) { 
  41.           error = -ENOMEM; 
  42.           goto err_free_minor; 
  43.      } 
  44.  
  45.      INIT_LIST_HEAD(&evdev->client_list); 
  46.      spin_lock_init(&evdev->client_lock); 
  47.      mutex_init(&evdev->mutex); 
  48.      init_waitqueue_head(&evdev->wait); 
  49.      evdev->exist = true
  50.  
  51.      dev_no = minor; 
  52.      /* Normalize device number if it falls into legacy range */ 
  53.      if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) 
  54.           dev_no -= EVDEV_MINOR_BASE; 
  55.  
  56. /*这里我们能看到最终生成的设备文件,例如event0、event1等待 
  57.      dev_set_name(&evdev->dev, "event%d", dev_no);  
  58.  
  59.      evdev->handle.dev = input_get_device(dev); 
  60.      evdev->handle.name = dev_name(&evdev->dev); 
  61.      evdev->handle.handler = handler; 
  62.      evdev->handle.private = evdev; 
  63.  
  64.     /*在设备驱动视图/sys/class/input/和/sys/devices/目录下产生eventx设备,最终依event机制和mdev在/dev目录生成对应的设备文件*/ 
  65.      evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); 
  66.      evdev->dev.class = &input_class; 
  67.      evdev->dev.parent = &dev->dev; 
  68.      evdev->dev.release = evdev_free; 
  69.      device_initialize(&evdev->dev); 
  70.  
  71.      error = input_register_handle(&evdev->handle); 
  72.      if (error) 
  73.           goto err_free_evdev; 
  74.  
  75.      cdev_init(&evdev->cdev, &evdev_fops); 
  76.      evdev->cdev.kobj.parent = &evdev->dev.kobj; 
  77.      error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); 
  78.      if (error) 
  79.           goto err_unregister_handle; 
  80.  
  81.      error = device_add(&evdev->dev); 
  82.      if (error) 
  83.           goto err_cleanup_evdev; 
  84.  
  85.      return 0; 
  86.  
  87. err_cleanup_evdev: 
  88.      evdev_cleanup(evdev); 
  89. err_unregister_handle: 
  90.      input_unregister_handle(&evdev->handle); 
  91. err_free_evdev: 
  92.      put_device(&evdev->dev); 
  93. err_free_minor: 
  94.      input_free_minor(minor); 
  95.  
  96.      return error; 
  97.      } 

3.5.18. evdev_connect

创建一个新的evdev 设备

3.5.19. input_proc_init

创建对应的目录结构

  1. /* drivers/input/input.c */ 
  2. static int __init input_proc_init(void) 
  3.      struct proc_dir_entry *entry; 
  4. /* 在/proc/bus目录下创建input */ 
  5.      proc_bus_input_dir = proc_mkdir("bus/input"NULL); 
  6.      if (!proc_bus_input_dir) 
  7.           return -ENOMEM; 
  8. /* 在/proc/bus/input目录下创建devices文件 */ 
  9.      entry = proc_create("devices", 0, proc_bus_input_dir, &input_devices_fileops); 
  10.      if (!entry) 
  11.           goto fail1; 
  12. /* 在/proc/bus/input目录下创建handlers文件 */ 
  13.      entry = proc_create("handlers", 0, proc_bus_input_dir, &input_handlers_fileops); 
  14.      if (!entry) 
  15.           goto fail2; 
  16.  
  17.      return 0; 
  18. fail2:  
  19. remove_proc_entry("devices", proc_bus_input_dir); 
  20. fail1:  
  21. remove_proc_entry("bus/input"NULL); 
  22.      return -ENOMEM; 

3.5.20. input_set_capability

设置输入设备可以上报哪些事件,需要注意一次只能设置一个事件,如果设备上报多个事件,需要重复调用

  1. /* drivers/input/input.c */ 
  2. void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) 
  3.      switch (type) { 
  4.          case EV_KEY: 
  5.           __set_bit(code, dev->keybit); 
  6.           break; 
  7.  
  8.          case EV_REL: 
  9.           __set_bit(code, dev->relbit); 
  10.           break; 
  11.  
  12.          case EV_ABS: 
  13.           input_alloc_absinfo(dev); 
  14.           if (!dev->absinfo) 
  15.                return
  16.  
  17.           __set_bit(code, dev->absbit); 
  18.           break; 
  19.  
  20.          case EV_MSC: 
  21.           __set_bit(code, dev->mscbit); 
  22.           break; 
  23.  
  24.         case EV_SW: 
  25.          __set_bit(code, dev->swbit); 
  26.          break; 
  27.  
  28.          case EV_LED: 
  29.           __set_bit(code, dev->ledbit); 
  30.           break; 
  31.  
  32.          case EV_SND: 
  33.           __set_bit(code, dev->sndbit); 
  34.           break; 
  35.  
  36.         case EV_FF: 
  37.          __set_bit(code, dev->ffbit); 
  38.          break; 
  39.  
  40.        case EV_PWR: 
  41.         /* do nothing */ 
  42.         break; 
  43.  
  44.      default
  45.       pr_err("%s: unknown type %u (code %u)\n", __func__, type, code); 
  46.       dump_stack(); 
  47.       return
  48.  } 
  49.  
  50.      __set_bit(type, dev->evbit); 
  51. EXPORT_SYMBOL(input_set_capability); 

3.5.21. evdev_read

读取event数据

  1. static ssize_t evdev_read(struct file *file, char __user *buffer, 
  2.      size_t count, loff_t *ppos) 
  3.      struct evdev_client *client = file->private_data; 
  4.      struct evdev *evdev = client->evdev; 
  5.      struct input_event event; 
  6.      size_t read = 0; 
  7.      int error; 
  8.  
  9.      if (count != 0 && count < input_event_size()) 
  10.           return -EINVAL; 
  11.  
  12.      for (;;) { 
  13.           if (!evdev->exist || client->revoked) 
  14.                 return -ENODEV; 
  15. /* client的环形缓冲区中没有数据并且是非阻塞的,那么返回-EAGAIN,也就是try again */ 
  16.           if (client->packet_head == client->tail &&(file->f_flags & O_NONBLOCK)) 
  17.                 return -EAGAIN; 
  18.  
  19.          /* 
  20.           * count == 0 is special - no IO is done but we check 
  21.           * for error conditions (see above). 
  22.           */ 
  23.           if (count == 0) 
  24.                break; 
  25. /* 如果获得了数据,就取出来 */ 
  26.           while (read + input_event_size() <= count && 
  27.               evdev_fetch_next_event(client, &event)) { 
  28. /* 传给用户 */ 
  29.           if (input_event_to_user(buffer + read, &event)) 
  30.                return -EFAULT; 
  31.  
  32.             read += input_event_size(); 
  33.     } 
  34.  
  35.       if (read
  36.            break; 
  37. /* 如果没有数据,并且是阻塞的,则在等待队列上等待 */ 
  38.       if (!(file->f_flags & O_NONBLOCK)) { 
  39.            error = wait_event_interruptible(evdev->wait, 
  40.              client->packet_head != client->tail || !evdev->exist || client->revoked); 
  41.        if (error) 
  42.             return error; 
  43.       } 
  44.  } 
  45.  
  46.  return read

如果read进行进入休眠状态,则会被evdev_event函数唤醒

4. 模块测试

4.1.测试概述

应用有两条路径,如下所示 /sys/class/input

  1. console:/sys/class/input # ls 
  2. event0 event1 event2 input0 input1 input2 mice 

/dev/input

  1. console:/dev/input # ls 
  2. event0 event1 event2 mice 

查看设备信息

  1. $ cat /proc/bus/input/devices 
  2. I: Bus=0000 Vendor=0000 Product=0000 Version=0000 
  3. N: Name="lombo-ir" 
  4. P: Phys=lombo-ir/input0 
  5. S: Sysfs=/devices/platform/4014800.ir/rc/rc0/input0 
  6. U: Uniq= 
  7. H: Handlers=event0 
  8. B: PROP=0 
  9. B: EV=100013 
  10. B: KEY=1 0 0 0 0 0 0 0 1680 0 0 ffc 
  11. B: MSC=10 

event节点里面存放的数据都是没有经过处理的原始数据流。cat 对应的eventX节点就可以查看输入的数据。

  1. $ cat event0 

4.2.应用测试

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <sys/ioctl.h> 
  4. #include <sys/time.h> 
  5. #include <sys/types.h> 
  6. #include <fcntl.h> 
  7. #include <unistd.h> 
  8. #include <errno.h> 
  9. #include <time.h> 
  10. #include <linux/input.h> 
  11.  
  12.  
  13. int main(void) 
  14.     int ret; 
  15.     int fd; 
  16.  
  17.     struct input-event value; 
  18.  
  19.     fd = open("/dev/input/event1", O_RDWR); 
  20.     if (fd < 0) { 
  21.          printf("open event1 failed %d\n", fd); 
  22.          return 0; 
  23.     } 
  24.  
  25.     while(1) { 
  26.           ret = read(fd, &value, sizeof(value)); 
  27.           if (ret < 0) 
  28.                printf("read failed\n"); 
  29.    
  30.           printf("input type:%d code:%d value:%d\n", value.type, 
  31.                value.code, value.value); 
  32.      } 
  33.     return 0; 

本文转载自微信公众号「一口Linux」

 

责任编辑:姜华 来源: 一口Linux
相关推荐

2021-12-15 10:02:25

鸿蒙HarmonyOS应用

2021-08-10 11:30:30

Linux代码中断控制器

2021-08-03 15:10:26

Linux代码驱动

2017-02-28 18:26:09

Linuxinput子系统编程

2015-10-19 17:36:19

MOST内核Linux

2013-01-06 13:06:02

2017-09-11 15:35:43

AndroidInput系统框架

2021-08-17 14:39:00

鸿蒙HarmonyOS应用

2021-07-22 08:03:08

Windows 操作系统Linux

2016-07-22 10:50:56

Linux内核无线子系统

2021-12-08 08:41:31

Linux 中断子系统Linux 系统

2021-04-06 11:18:47

LinuxWWAN子系统驱动

2016-10-17 08:49:15

WindowsLinuxArch Linux

2021-09-02 15:27:54

鸿蒙HarmonyOS应用

2022-04-01 15:18:04

HarmonyHDF 驱动鸿蒙

2021-06-07 08:13:11

LinuxIDLE 子系统

2021-03-05 11:52:50

LinuxSPI驱动详解

2022-01-16 07:41:46

Windows 11操作系统微软

2022-04-12 09:05:30

Linux时钟

2022-03-28 19:19:45

Linux时间子系统
点赞
收藏

51CTO技术栈公众号