input输入子系统

输入子系统:
1、定义:Linux系统支持的输入设备繁多,例如键盘、鼠标、触摸屏、手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型、不同原理、不同的输入信息的输入设备的呢?其实就是通过input输入子系统这套软件体系来完成的。
2、组成:输入子系统由驱动层、输入子系统核心、事件处理层三部分组成。
驱动层:将底层的硬件输入转化为统一事件形式,向输入核心(Input Core)汇报。
输入子系统核心:承上启下。为驱动层提供输入设备注册与操作接口,如:input_register_device;通知事件处理层对事件进行处理;在/Proc下产生相应的设备信息
事件处理层:主要是和用户空间交互。(Linux中在用户空间将所有的设备都当初文件来处理,由于在一般的驱动程序中都有提供fops接口,以及在/dev下生成相应的设备文件nod,这些操作在输入子系统中由事件处理层完成)
3、框架:
这里写图片描述
一个大致的工作流程就是,input device向上层报告–>input core接收报告,并根据在注册input device时建立好的连接选择哪一类handler来处理事件–>通过handler将数据存放在相应的 dev(evdev,mousedev…)实例的缓冲区中,等待应用程序来读取。
4、数据结构
struct input_dev 设备结构体,记录了设备的信息和支持的事件

struct input_dev {
    const char *name;   //设备名
    const char *phys;   //设备节点名称
    const char *uniq;   // 唯一的ID号,
    struct input_id id; // 输入设备ID,用于和event handler 匹配

    unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; //bitmap of device properties and quirks

    unsigned long evbit[BITS_TO_LONGS(EV_CNT)];  //设备支持的事件类型
    unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //按键 ex:上下左右 home
    unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //相对坐标 ex 鼠标
    unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //绝对坐标 ex 触摸屏
    unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //其他功能
    unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //指示灯
    unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //声音或警报
    unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //作用力
    unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //开关

    unsigned int hint_events_per_packet; /* average number of events generated by the device in a packet (between EV_SYN/SYN_REPORT events). Used by event handlers to estimate size of the buffer needed to hold events.*/

    unsigned int keycodemax; //设备支持最大按键值个数
    unsigned int keycodesize; //每个按键字节大小
    void *keycode; //按键池,指向按键值数组首地址

    int (*setkeycode)(struct input_dev *dev,
              const struct input_keymap_entry *ke,
              unsigned int *old_keycode); //修改按键值
    int (*getkeycode)(struct input_dev *dev,
              struct input_keymap_entry *ke); //获取按键值

    struct ff_device *ff; //强制更新输入设备的部分内容

    unsigned int repeat_key; //重复按键的键值
    struct timer_list timer; //连击时定时器

    int rep[REP_CNT]; //重复按键参数值

    struct input_mt_slot *mt; //pointer to multitouch state
    int mtsize;
    int slot;
    int trkid;

    struct input_absinfo *absinfo; /* array of struct input_absinfo elements holding information about absolute axes (current value, min, max, flat, fuzz, resolution) */

    unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //记录状态
    unsigned long led[BITS_TO_LONGS(LED_CNT)];
    unsigned long snd[BITS_TO_LONGS(SND_CNT)];
    unsigned long sw[BITS_TO_LONGS(SW_CNT)];

    int (*open)(struct input_dev *dev);
    void (*close)(struct input_dev *dev);
    int (*flush)(struct input_dev *dev, struct file *file); //输入设备断开后刷新函数
    int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); //事件处理

    struct input_handle __rcu *grab; //类似私有指针,可以访问到事件处理接口event

    spinlock_t event_lock; //自旋锁
    struct mutex mutex; //用于open close函数的连续访问互斥

    unsigned int users; //设备使用计数
    bool going_away; //不知

    bool sync; //是否上传同步ok

    struct device dev; //设备结构体

    struct list_head    h_list; //handle list
    struct list_head    node; // input dev list
};

struct input_handler:用来标识输入事件处理

1 struct input_handler {
 2 
 3     void *private;
 4 
 5     void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);/*event用于处理事件*/
 6     void (*events)(struct input_handle *handle,
 7                const struct input_value *vals, unsigned int count);
 8     bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
 9     bool (*match)(struct input_handler *handler, struct input_dev *dev);
10     int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);/*connect用于建立handler和device的联系*/
11     void (*disconnect)(struct input_handle *handle);/*disconnect用于解除handler和device的联系*/
12     void (*start)(struct input_handle *handle);
13 
14     bool legacy_minors;
15     int minor;//次设备号
16     const char *name;
17 
18     const struct input_device_id *id_table;//用于和input_dev匹配
19 
20     struct list_head    h_list;//用于链接和此input_handler相关的input_handle
21     struct list_head    node;//用于将该input_handler链入input_handler_list
22 };

input_handle:用来链接input_dev和input_handler
1 struct input_handle {
2
3 void *private;
4
5 int open;//记录设备的打开次数(有多少个应用程序访问设备)
6 const char *name;
7
8 struct input_dev *dev;//指向所属的device
9 struct input_handler *handler;//指向所属的handler
10
11 struct list_head d_node;//用于将此input_handle链入所属input_dev的h_list链表
12 struct list_head h_node;//用于将此input_handle链入所属input_handler的h_list链表
13 };
input_event:数据包 和 上传数据包`

struct input_event {
        struct timeval time;  //时间
        __u16 type;   // 数据类型:  按键数据/绝对数据/相对数据 
        __u16 code; // 类型中某个特定数据:  比如  上键,下键, 回车键,...
        __s32 value; // 状态: 按下会抬起
    };

struct input_device_id :设备id

struct input_device_id {
 2 
 3     kernel_ulong_t flags;    //  这个flag 表示我们的这个 input_device_id 是用来匹配下面的4个情况的哪一项
 4                                     //  flag == 1表示匹配总线  2表示匹配供应商   4表示匹配产品  8表示匹配版本
 5     __u16 bustype;
 6     __u16 vendor;
 7     __u16 product;
 8     __u16 version;
 9 
10     kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
11     kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
12     kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
13     kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
14     kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
15     kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
16     kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
17     kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
18     kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
19 
20     kernel_ulong_t driver_info;
21 };

5、主要函数:

1 static int __init input_init(void)
 2 {
 3     int err;
 4 
 5     input_init_abs_bypass();
 6 
 7     err = class_register(&input_class);                //  创建设备类    /sys/class/input
 8     if (err) {
 9         printk(KERN_ERR "input: unable to register input_dev class\n");
10         return err;
11     }
12 
13     err = input_proc_init();           //    proc文件系统相关的初始化
14     if (err)
15         goto fail1;
16 
17     err = register_chrdev(INPUT_MAJOR, "input", &input_fops);       //   注册字符设备驱动   主设备号13   input_fops 中只实现了open函数,所以他的原理其实和misc其实是一样的
18     if (err) {
19         printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
20         goto fail2;
21     }
22 
23     return 0;
24 
25  fail2:    input_proc_exit();
26  fail1:    class_unregister(&input_class);
27     return err;
28 }
1 static int input_open_file(struct inode *inode, struct file *file)
 2 {
 3     struct input_handler *handler;                                                //  定义一个input_handler指针
 4     const struct file_operations *old_fops, *new_fops = NULL;   //  定义两个file_operations指针
 5     int err;
 6 
 7     err = mutex_lock_interruptible(&input_mutex);
 8     if (err)
 9         return err;
10 
11     /* No load-on-demand here? */
12     handler = input_table[iminor(inode) >> 5];         //  通过次设备号在 input_table  数组中找到对应的 handler 
13     if (handler)
14         new_fops = fops_get(handler->fops);           //  将handler 中的fops 指针赋值给 new_fops
15 
16     mutex_unlock(&input_mutex);
17 
18     /*
19      * That's _really_ odd. Usually NULL ->open means "nothing special",
20      * not "no device". Oh, well...
21      */
22     if (!new_fops || !new_fops->open) {
23         fops_put(new_fops);
24         err = -ENODEV;
25         goto out;
26     }
27 
28     old_fops = file->f_op;           //   将 file->fops 先保存到 old_fops 中,以便出错时能够恢复
29     file->f_op = new_fops;          //   用new_fops 替换 file 中 fops 
30 
31     err = new_fops->open(inode, file);       //  执行 file->open  函数
32     if (err) {
33         fops_put(file->f_op);
34         file->f_op = fops_get(old_fops);
35     }
36     fops_put(old_fops);
37 out:
38     return err;
39 }
1 struct input_dev *input_allocate_device(void)
 2 {
 3     struct input_dev *dev;                 //   定义一个 input_dev  指针
 4 
 5     dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);   //  申请分配内存
 6     if (dev) {
 7         dev->dev.type = &input_dev_type;          //  确定input设备的 设备类型     input_dev_type
 8         dev->dev.class = &input_class;                //  确定input设备所属的设备类   class
 9         device_initialize(&dev->dev);                   //  input设备的初始化
10         mutex_init(&dev->mutex);                        //  互斥锁初始化
11         spin_lock_init(&dev->event_lock);            //  自旋锁初始化
12         INIT_LIST_HEAD(&dev->h_list);                 //  input_dev -> h_list 链表初始化
13         INIT_LIST_HEAD(&dev->node);                 //  input_dev -> node 链表初始化
14 
15         __module_get(THIS_MODULE);
16     }
17 
18     return dev;
19 }
1 int input_register_device(struct input_dev *dev)      //  注册input输入设备
 2 {
 3     static atomic_t input_no = ATOMIC_INIT(0);
 4     struct input_handler *handler;                          //  定义一个  input_handler 结构体指针
 5     const char *path;
 6     int error;
 7 
 8     /* Every input device generates EV_SYN/SYN_REPORT events. */
 9     __set_bit(EV_SYN, dev->evbit);                  //   每一个input输入设备都会发生这个事件
10 
11     /* KEY_RESERVED is not supposed to be transmitted to userspace. */
12     __clear_bit(KEY_RESERVED, dev->keybit);  //  清除KEY_RESERVED 事件对应的bit位,也就是不传输这种类型的事件
13 
14     /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
15     input_cleanse_bitmasks(dev);           //   确保input_dev中的用来记录事件的变量中没有提到的位掩码是干净的。
16 
17     /*
18      * If delay and period are pre-set by the driver, then autorepeating
19      * is handled by the driver itself and we don't do it in input.c.
20      */
21     init_timer(&dev->timer);
22     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
23         dev->timer.data = (long) dev;
24         dev->timer.function = input_repeat_key;
25         dev->rep[REP_DELAY] = 250;
26         dev->rep[REP_PERIOD] = 33;
27     }
28 
29     if (!dev->getkeycode)
30         dev->getkeycode = input_default_getkeycode;
31 
32     if (!dev->setkeycode)
33         dev->setkeycode = input_default_setkeycode;
34 
35     dev_set_name(&dev->dev, "input%ld",                                  //   设置input设备对象的名字    input+数字
36              (unsigned long) atomic_inc_return(&input_no) - 1);
37 
38     error = device_add(&dev->dev);         //   添加设备       例如:          /sys/devices/virtual/input/input0     
39     if (error)
40         return error;
41 
42     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);  //  获取input设备对象所在的路径      /sys/devices/virtual/input/input_xxx   
43     printk(KERN_INFO "input: %s as %s\n",
44         dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
45     kfree(path);
46 
47     error = mutex_lock_interruptible(&input_mutex);
48     if (error) {
49         device_del(&dev->dev);
50         return error;
51     }
52 
53     list_add_tail(&dev->node, &input_dev_list);             //   链表挂接:    将 input_dev->node 作为节点挂接到 input_dev_list  链表上
54 
55     list_for_each_entry(handler, &input_handler_list, node)  //  遍历input_handler_list 链表上的所有handler
56         input_attach_handler(dev, handler);                        //  将handler与input设备进行匹配
57 
58     input_wakeup_procfs_readers();                //  更新proc 文件系统
59 
60     mutex_unlock(&input_mutex);
61 
62     return 0;
63 }
1 int input_register_device(struct input_dev *dev)      //  注册input输入设备
 2 {
 3     static atomic_t input_no = ATOMIC_INIT(0);
 4     struct input_handler *handler;                          //  定义一个  input_handler 结构体指针
 5     const char *path;
 6     int error;
 7 
 8     /* Every input device generates EV_SYN/SYN_REPORT events. */
 9     __set_bit(EV_SYN, dev->evbit);                  //   每一个input输入设备都会发生这个事件
10 
11     /* KEY_RESERVED is not supposed to be transmitted to userspace. */
12     __clear_bit(KEY_RESERVED, dev->keybit);  //  清除KEY_RESERVED 事件对应的bit位,也就是不传输这种类型的事件
13 
14     /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
15     input_cleanse_bitmasks(dev);           //   确保input_dev中的用来记录事件的变量中没有提到的位掩码是干净的。
16 
17     /*
18      * If delay and period are pre-set by the driver, then autorepeating
19      * is handled by the driver itself and we don't do it in input.c.
20      */
21     init_timer(&dev->timer);
22     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
23         dev->timer.data = (long) dev;
24         dev->timer.function = input_repeat_key;
25         dev->rep[REP_DELAY] = 250;
26         dev->rep[REP_PERIOD] = 33;
27     }
28 
29     if (!dev->getkeycode)
30         dev->getkeycode = input_default_getkeycode;
31 
32     if (!dev->setkeycode)
33         dev->setkeycode = input_default_setkeycode;
34 
35     dev_set_name(&dev->dev, "input%ld",                                  //   设置input设备对象的名字    input+数字
36              (unsigned long) atomic_inc_return(&input_no) - 1);
37 
38     error = device_add(&dev->dev);         //   添加设备       例如:          /sys/devices/virtual/input/input0     
39     if (error)
40         return error;
41 
42     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);  //  获取input设备对象所在的路径      /sys/devices/virtual/input/input_xxx   
43     printk(KERN_INFO "input: %s as %s\n",
44         dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
45     kfree(path);
46 
47     error = mutex_lock_interruptible(&input_mutex);
48     if (error) {
49         device_del(&dev->dev);
50         return error;
51     }
52 
53     list_add_tail(&dev->node, &input_dev_list);             //   链表挂接:    将 input_dev->node 作为节点挂接到 input_dev_list  链表上
54 
55     list_for_each_entry(handler, &input_handler_list, node)  //  遍历input_handler_list 链表上的所有handler
56         input_attach_handler(dev, handler);                        //  将handler与input设备进行匹配
57 
58     input_wakeup_procfs_readers();                //  更新proc 文件系统
59 
60     mutex_unlock(&input_mutex);
61 
62     return 0;
63 }

1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
2 {
3 const struct input_device_id *id; // 定义一个input_device_id 的指针
4 int error;
5
6 id = input_match_device(handler, dev); // 通过这个函数进行handler与input设备的匹配工作
7 if (!id)
8 return -ENODEV;
9
10 error = handler->connect(handler, dev, id); // 匹配成功则调用 handler 中的 connect 函数进行连接
11 if (error && error != -ENODEV)
12 printk(KERN_ERR
13 “input: failed to attach handler %s to device %s, ”
14 “error: %d\n”,
15 handler->name, kobject_name(&dev->dev.kobj), error);
16
17 return error;
18 }
19

22 static const struct input_device_id *input_match_device(struct input_handler *handler,
23 struct input_dev *dev)
24 {
25 const struct input_device_id *id; // 定义一个 input_device_id 指针
26 int i;
27
28 for (id = handler->id_table; id->flags || id->driver_info; id++) { // 依次遍历handler->id_table 所指向的input_device_id 数组中的各个元素
29 // 依次进行下面的匹配过程
30 if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) // 匹配总线
31 if (id->bustype != dev->id.bustype)
32 continue;
33
34 if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) // 匹配供应商
35 if (id->vendor != dev->id.vendor)
36 continue;
37
38 if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) // 匹配产品
39 if (id->product != dev->id.product)
40 continue;
41
42 if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) // 匹配版本
43 if (id->version != dev->id.version)
44 continue;
45
46 // 下面的这些是匹配我们上传的事件是否属实
47 MATCH_BIT(evbit, EV_MAX);
48 MATCH_BIT(keybit, KEY_MAX);
49 MATCH_BIT(relbit, REL_MAX);
50 MATCH_BIT(absbit, ABS_MAX);
51 MATCH_BIT(mscbit, MSC_MAX);
52 MATCH_BIT(ledbit, LED_MAX);
53 MATCH_BIT(sndbit, SND_MAX);
54 MATCH_BIT(ffbit, FF_MAX);
55 MATCH_BIT(swbit, SW_MAX);
56
57 if (!handler->match || handler->match(handler, dev))
58 return id; // 如果数组中的某个匹配成功了就返回他的地址
59 }
60
61 return NULL;
62 }

1 int input_register_handler(struct input_handler *handler)    //  向核心层注册handler
 2 {
 3     struct input_dev *dev;          //  定义一个input_dev 指针
 4     int retval; 
 5 
 6     retval = mutex_lock_interruptible(&input_mutex);
 7     if (retval)
 8         return retval;
 9 
10     INIT_LIST_HEAD(&handler->h_list);      //  初始化 handler->h_list 链表
11 
12     if (handler->fops != NULL) {          //  如果 handler -> fops 存在
13         if (input_table[handler->minor >> 5]) {  //  如果input_table 数组中没有该handler  的位置了 则返回
14             retval = -EBUSY;
15             goto out;
16         }
17         input_table[handler->minor >> 5] = handler;  //  将 handler 指针存放在input_table 数组中去
18     }
19 
20     list_add_tail(&handler->node, &input_handler_list);   //  将 handler 通过 handler -> node 节点 挂接到 input_handler_list 链表上
21 
22     list_for_each_entry(dev, &input_dev_list, node)     //  遍历 input_dev_list 链表下挂接的所有的 input_dev 设备
23         input_attach_handler(dev, handler);          //  然后进行匹配
24 
25     input_wakeup_procfs_readers();             //  更新proc 文件系统
26 
27  out:
28     mutex_unlock(&input_mutex);
29     return retval;
30 }

猜你喜欢

转载自blog.csdn.net/qq_39937242/article/details/82631165