我是靠谱客的博主 魁梧高跟鞋,最近开发中收集的这篇文章主要介绍输入子系统(二)函数调用分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

很多分析输入子系统的文章已经讲得很清楚了,这里主要是记录自己的学习过程。参考的几篇文章:

输入子系统学习笔记之按键实例编程

输入子系统学习笔记之源码分析1_框架性分析

输入子系统学习笔记之源码分析2_数据结构分析

输入子系统学习笔记之源码分析3_流程分析

三个重要结构体的说明参考输入子系统学习笔记之源码分析2_数据结构分析,很重要,输入子系统就是靠这三个结构体建立联系的。

drivers/input/input.c中有如下定义:

a. 声明了input_dev_list链表头,在input_register_device()函数中将input_dev结构体加入链表中。

input_register_device(struct input_dev *dev)

  -->list_add_tail(&dev->node, &input_dev_list);

b. 声明了input_handler_list链表头,在input_register_handler()函数中将input_handler结构体加入链表中。

input_register_handler(struct input_handler *handler)

  -->list_add_tail(&handler->node, &input_handler_list);

c. 定义input_handler指针数组,每个input_handler支持32个input_dev设备。

1 #define INPUT_DEVICES    256
2 static LIST_HEAD(input_dev_list);
3 static LIST_HEAD(input_handler_list);
4 static struct input_handler *input_table[8];

1. input_register_handler()的函数分析

事件处理程序是标准的,对于所有的输入类是通用的。所以一般而言我们要实现的设备驱动程序,而不是事件处理程序。

一般情况下,内核启动后就已经构造好了input_handler_list链表,如下图左侧部分。

调用input_register_handler()的函数一般位于evdev.c,joydev.c ,mousedev.c...等函数中的 xxx_init(void)函数中。

 1 static struct input_handler evdev_handler = {
 2     .event        = evdev_event,
 3     .connect    = evdev_connect,
 4     .disconnect    = evdev_disconnect,
 5     .fops        = &evdev_fops,
 6     .minor        = EVDEV_MINOR_BASE,
 7     .name        = "evdev",
 8     .id_table    = evdev_ids,
 9 };
10 
11 static int __init evdev_init(void)
12 {
13     return input_register_handler(&evdev_handler);
14     
15 }
 1 int input_register_handler(struct input_handler *handler)
 2 {
 3     struct input_dev *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);
11 
12     if (handler->fops != NULL) {
13         if (input_table[handler->minor >> 5]) {
14             retval = -EBUSY;
15             goto out;
16         }
17         input_table[handler->minor >> 5] = handler;
18     }
19 
20     list_add_tail(&handler->node, &input_handler_list);
21 
22     list_for_each_entry(dev, &input_dev_list, node)
23         input_attach_handler(dev, handler);
24 
25     input_wakeup_procfs_readers();
26 
27  out:
28     mutex_unlock(&input_mutex);
29     return retval;
30 }

2. input_register_device()函数分析

 写一个符合输入子系统框架的驱动一般分为四步:a. 分配一个input_dev结构体;b. 设置;c. input_register_device()注册;d. 硬件相关的代码

 1 struct input_dev *input;
 2 static int gq_key_init(void)
 3 {
 4     // 1 allocate input_dev struct
 5     input = input_allocate_device();
 6 
 7     // 2 set
 8     // 2.1 set which event to generate
 9     __set_bit(EV_KEY, input->evbit);
10     // 2.2 set which keys to generate
11     __set_bit(KEY_L,input->keybit);
12     __set_bit(KEY_S,input->keybit);
13     __set_bit(KEY_ENTER,input->keybit);
14     __set_bit(KEY_LEFTSHIFT,input->keybit);
15 
16     // 3 register
17     input_register_device(input);
18 
19     // 4 hardware 
20     return 0;
21 }

系统没调用一次input_register_device()函数就在input_dev_list链表上添加一个input_dev结构体,如下图左侧。

 1 int input_register_device(struct input_dev *dev)
 2 {
 3     static atomic_t input_no = ATOMIC_INIT(0);
 4     struct input_handler *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);
10 
11     /* KEY_RESERVED is not supposed to be transmitted to userspace. */
12     __clear_bit(KEY_RESERVED, dev->keybit);
13 
14     /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
15     input_cleanse_bitmasks(dev);
16 
17     if (!dev->hint_events_per_packet)
18         dev->hint_events_per_packet =
19                 input_estimate_events_per_packet(dev);
20 
21     /*
22      * If delay and period are pre-set by the driver, then autorepeating
23      * is handled by the driver itself and we don't do it in input.c.
24      */
25     init_timer(&dev->timer);
26     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
27         dev->timer.data = (long) dev;
28         dev->timer.function = input_repeat_key;
29         dev->rep[REP_DELAY] = 250;
30         dev->rep[REP_PERIOD] = 33;
31     }
32 
33     if (!dev->getkeycode)
34         dev->getkeycode = input_default_getkeycode;
35 
36     if (!dev->setkeycode)
37         dev->setkeycode = input_default_setkeycode;
38 
39     dev_set_name(&dev->dev, "input%ld",
40              (unsigned long) atomic_inc_return(&input_no) - 1);
41 
42     error = device_add(&dev->dev);
43     if (error)
44         return error;
45 
46     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
47     pr_info("%s as %sn",
48         dev->name ? dev->name : "Unspecified device",
49         path ? path : "N/A");
50     kfree(path);
51 
52     error = mutex_lock_interruptible(&input_mutex);
53     if (error) {
54         device_del(&dev->dev);
55         return error;
56     }
57 
58     list_add_tail(&dev->node, &input_dev_list);
59 
60     list_for_each_entry(handler, &input_handler_list, node)
61         input_attach_handler(dev, handler);
62 
63     input_wakeup_procfs_readers();
64 
65     mutex_unlock(&input_mutex);
66 
67     return 0;
68 }
input_register_device()

3. input_attach_handler()函数分析

input_register_handler()与input_register_device()函数中都会调用input_attach_handler()函数来匹配input_handler与input_device。

在input_register_handler()中会遍历整个input_dev_list中的input_device与当前注册的input_handler相匹配。

在input_register_device()中会遍历整个input_handler_list中的input_handler与当前注册的input_dev相匹配。

 input_attach_handler()中做两件事情:a.查看input_handler与input_device是否匹配;b.若匹配则调用handler->connect(handler,dev,id);

 1 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
 2 {
 3     const struct input_device_id *id;
 4     int error;
 5 
 6     id = input_match_device(handler, dev);
 7     if (!id)
 8         return -ENODEV;
 9 
10     error = handler->connect(handler, dev, id);
11     if (error && error != -ENODEV)
12         pr_err("failed to attach handler %s to device %s, error: %dn",
13                handler->name, kobject_name(&dev->dev.kobj), error);
14 
15     return error;
16 }

4. input_match_device()函数分析

这里用到两个结构体,input_device结构体中有struct input_id id;

struct input_handler 结构体中有const struct input_device_id *id_table;

是否匹配主要是检测input_device_id中的数组成员与input_device中对应的数组成员是否一致。

struct input_id {
    __u16 bustype;
    __u16 vendor;
    __u16 product;
    __u16 version;
};
struct input_device_id {

    kernel_ulong_t flags;

    __u16 bustype;
    __u16 vendor;
    __u16 product;
    __u16 version;

    kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
    kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];

    kernel_ulong_t driver_info;
};

 

 1 static const struct input_device_id *input_match_device(struct input_handler *handler,
 2                             struct input_dev *dev)
 3 {
 4     const struct input_device_id *id;
 5     int i;
 6 
 7     for (id = handler->id_table; id->flags || id->driver_info; id++) 
 8     {
 9 
10         if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
11             if (id->bustype != dev->id.bustype)
12                 continue;
13 
14         if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
15             if (id->vendor != dev->id.vendor)
16                 continue;
17 
18         if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
19             if (id->product != dev->id.product)
20                 continue;
21 
22         if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
23             if (id->version != dev->id.version)
24                 continue;
25 
26         MATCH_BIT(evbit,  EV_MAX);
27         MATCH_BIT(keybit, KEY_MAX);
28         MATCH_BIT(relbit, REL_MAX);
29         MATCH_BIT(absbit, ABS_MAX);
30         MATCH_BIT(mscbit, MSC_MAX);
31         MATCH_BIT(ledbit, LED_MAX);
32         MATCH_BIT(sndbit, SND_MAX);
33         MATCH_BIT(ffbit,  FF_MAX);
34         MATCH_BIT(swbit,  SW_MAX);
35 
36         if (!handler->match || handler->match(handler, dev))
37             return id;
38     }
39 
40     return NULL;
41 }
input_match_device()

5. handler->connect(handler, dev, id)函数分析

这里以evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)为例分析连接建立的过程。

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)

  -->evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//分配一个struct input_handle

  -->evdev->handle.dev = input_get_device(dev);//指向input_dev

  -->evdev->handle.handler = handler;//指向input_handler

  -->error = input_register_handle(&evdev->handle);

    -->list_add_tail_rcu(&handle->d_node, &dev->h_list);//与input_dev关联

    -->list_add_tail_rcu(&handle->h_node, &handler->h_list);//与input_handler关联

 建立连接后handler与device就通过handle关联起来了

 1 struct input_handle {
 2 
 3     void *private;
 4 
 5     int open;
 6     const char *name;
 7 
 8     struct input_dev *dev;
 9     struct input_handler *handler;
10 
11     struct list_head    d_node;
12     struct list_head    h_node;
13 };

转载于:https://www.cnblogs.com/yangjiguang/p/6042197.html

最后

以上就是魁梧高跟鞋为你收集整理的输入子系统(二)函数调用分析的全部内容,希望文章能够帮你解决输入子系统(二)函数调用分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部