input子系统学习之四:核心层

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了input子系统学习之四:核心层相关的知识,希望对你有一定的参考价值。

核心层:给事件层和设备层提供接口,规范编程接口。

一.  输入子系统核心分析。

    1.输入子系统核心对应与/drivers/input/input.c文件,这个也是作为一个模块注册到内核的。所以首先分析模块初始化函数。

 

1 .cnblogs

 

  

2. 输入子系统的核心其他部分都是提供的接口,向上连接事件处理层,向下连接驱动层。
    向下对驱动层的接口主要有:
    input_allocate_device    这个函数主要是分配一个input_dev接口,并初始化一些基本的成员,这就是我们不能简单用kmalloc分配input_dev结构的原因,因为缺少了一些初始化。

 

技术分享
 1 /**
 2  * input_allocate_device - allocate memory for new input device
 3  *
 4  * Returns prepared struct input_dev or NULL.
 5  *
 6  * NOTE: Use input_free_device() to free devices that have not been
 7  * registered; input_unregister_device() should be used for already
 8  * registered devices.
 9  */
10 struct input_dev *input_allocate_device(void)
11 {
12     struct input_dev *dev;
13 
14     dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
15     if (dev) {
16         dev->dev.type = &input_dev_type;
17         dev->dev.class = &input_class;
18         device_initialize(&dev->dev);
19         mutex_init(&dev->mutex);
20         spin_lock_init(&dev->event_lock);
21         INIT_LIST_HEAD(&dev->h_list);
22         INIT_LIST_HEAD(&dev->node);
23 
24         __module_get(THIS_MODULE);
25     }
26 
27     return dev;
28 }
View Code

  

    input_register_device  注册一个input设备

技术分享
 1 /**
 2  * input_register_device - register device with input core
 3  * @dev: device to be registered
 4  *
 5  * This function registers device with input core. The device must be
 6  * allocated with input_allocate_device() and all it‘s capabilities
 7  * set up before registering.
 8  * If function fails the device must be freed with input_free_device().
 9  * Once device has been successfully registered it can be unregistered
10  * with input_unregister_device(); input_free_device() should not be
11  * called in this case.
12  */
13 int input_register_device(struct input_dev *dev)
14 {
15     static atomic_t input_no = ATOMIC_INIT(0);
16     struct input_handler *handler;
17     const char *path;
18     int error;
19 
20     __set_bit(EV_SYN, dev->evbit);
21     /*调用__set_bit()函数设置 input_dev 所支持的事件类型。
22     事件类型由 input_dev 的evbit 成员来表示,在这里将其 EV_SYN 置位,
23     表示设备支持同步事件类型。一个设备可以支持一种或者多种事件类型。*/
24 
25     /*
26      * If delay and period are pre-set by the driver, then autorepeating
27      * is handled by the driver itself and we don‘t do it in input.c.
28      */
29 
30     init_timer(&dev->timer);/*初始化一个 timer 定时器,这个定时器是为处理重复击键而定义的。*/  
31     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {//若两个都为空,按如下默认设置,主要为自动处理重复按键定义的
32         dev->timer.data = (long) dev;
33         dev->timer.function = input_repeat_key;
34         dev->rep[REP_DELAY] = 250;
35         dev->rep[REP_PERIOD] = 33;
36     }
37 
38     if (!dev->getkeycode)//getkeycode函数为空,使用默认的getkeycode函数
39         dev->getkeycode = input_default_getkeycode;
40 
41     if (!dev->setkeycode)//setkeycode函数为空,使用默认的setkeycode函数
42         dev->setkeycode = input_default_setkeycode;
43     /* input_default_setkeycode()。input_default_getkeycode()函数用来得到指定位置的键值。
44     input_default_setkeycode()函数用来设置键值。*/ 
45     
46     dev_set_name(&dev->dev, "input%ld",
47              (unsigned long) atomic_inc_return(&input_no) - 1);
48   /*设置 input_dev 中的 device 的名字,名字以 input0、input1、input2、input3、input4等
49   的形式出现在 sysfs 文件系统中。*/ 
50     error = device_add(&dev->dev);
51     if (error)
52         return error;
53 
54     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
55     printk(KERN_INFO "input: %s as %s\n",
56         dev->name ? dev->name : "Unspecified device", path ? path : "N/A");//打印设备的路径,输出调试信息。  
57     kfree(path);
58 
59     error = mutex_lock_interruptible(&input_mutex);
60     if (error) {
61         device_del(&dev->dev);
62         return error;
63     }
64 
65     list_add_tail(&dev->node, &input_dev_list);
66     /*调用 list_add_tail()函数将 input_dev 加入 input_dev_list 链表中,
67     input_dev_list 链表中包含了系统中所有的 input_dev 设备。*/  
68     list_for_each_entry(handler, &input_handler_list, node)
69     input_attach_handler(dev, handler);
70     /*input_attach_handler()函数用来匹配 input_dev 和 handler,只有匹配成功才能进行下一步的关联操作 */  
71 
72     input_wakeup_procfs_readers();
73     
74     mutex_unlock(&input_mutex);
75 
76     return 0;
77 }
View Code

  input_event              这个函数很重要,是驱动层向input子系统核心报告事件的函数,在事件传递过程中再分析。

技术分享
 1 /**
 2  * input_event() - report new input event
 3  * @dev: device that generated the event
 4  * @type: type of the event
 5  * @code: event code
 6  * @value: value of the event
 7  *
 8  * This function should be used by drivers implementing various input
 9  * devices. See also input_inject_event().
10  */
11 
12 void input_event(struct input_dev *dev,
13          unsigned int type, unsigned int code, int value)
14 {
15     unsigned long flags;
16 
17     if (is_event_supported(type, dev->evbit, EV_MAX)) {
18 
19         spin_lock_irqsave(&dev->event_lock, flags);
20 
21         /*add_input_randomness()函数对事件发送没有一点用处,只是用来对随机数熵池增加一些贡献,
22         因为按键输入是一种随机事件,所以对熵池是有贡献的。  */
23         add_input_randomness(type, code, value);
24         input_handle_event(dev, type, code, value);
25         spin_unlock_irqrestore(&dev->event_lock, flags);
26     }
27 }
View Code


    向上对事件处理层接口主要有:

  input_handle_event       判断事件类型,让事件层对应的handler处理

技术分享
  1 static void input_handle_event(struct input_dev *dev,
  2                    unsigned int type, unsigned int code, int value)
  3 {
  4     
  5     int disposition = INPUT_IGNORE_EVENT;
  6     /*定义了一个 disposition 变量,该变量表示使用什么样的方式处理事件。
  7     此处初始化为 INPUT_IGNORE_EVENT,表示如果后面没有对该变量重新赋值,则忽略这个事件。*/
  8     switch (type) {
  9 
 10     case EV_SYN:
 11         switch (code) {
 12         case SYN_CONFIG:
 13             disposition = INPUT_PASS_TO_ALL;
 14             break;
 15 
 16         case SYN_REPORT:
 17             if (!dev->sync) {
 18                 dev->sync = 1;
 19                 disposition = INPUT_PASS_TO_HANDLERS;
 20             }
 21             break;
 22         case SYN_MT_REPORT:
 23             dev->sync = 0;
 24             disposition = INPUT_PASS_TO_HANDLERS;
 25             break;
 26         }
 27         break;
 28 
 29     case EV_KEY:
 30         if (is_event_supported(code, dev->keybit, KEY_MAX) &&
 31             !!test_bit(code, dev->key) != value) {//调用 is_event_supported()函数判断是否支持该按键
 32                 //调用 test_bit()函数来测试按键状态是否改变。
 33             if (value != 2) {
 34                 __change_bit(code, dev->key);/*调用__change_bit()函数改变键的状态。*/  
 35                 if (value)
 36                     input_start_autorepeat(dev, code);
 37                 else
 38                     input_stop_autorepeat(dev);
 39             }
 40 
 41             disposition = INPUT_PASS_TO_HANDLERS;
 42             /*将 disposition变量设置为 INPUT_PASS_TO_HANDLERS,表示事件需要 handler 来处理。*/
 43         }
 44         break;
 45 
 46     case EV_SW:
 47         if (is_event_supported(code, dev->swbit, SW_MAX) &&
 48             !!test_bit(code, dev->sw) != value) {
 49 
 50             __change_bit(code, dev->sw);
 51             disposition = INPUT_PASS_TO_HANDLERS;
 52         }
 53         break;
 54 
 55     case EV_ABS:
 56         if (is_event_supported(code, dev->absbit, ABS_MAX)) {
 57 
 58             if (test_bit(code, input_abs_bypass)) {
 59                 disposition = INPUT_PASS_TO_HANDLERS;
 60                 break;
 61             }
 62 
 63             value = input_defuzz_abs_event(value,
 64                     dev->abs[code], dev->absfuzz[code]);
 65 
 66             if (dev->abs[code] != value) {
 67                 dev->abs[code] = value;
 68                 disposition = INPUT_PASS_TO_HANDLERS;
 69             }
 70         }
 71         break;
 72 
 73     case EV_REL:
 74         if (is_event_supported(code, dev->relbit, REL_MAX) && value)
 75             disposition = INPUT_PASS_TO_HANDLERS;
 76 
 77         break;
 78 
 79     case EV_MSC:
 80         if (is_event_supported(code, dev->mscbit, MSC_MAX))
 81             disposition = INPUT_PASS_TO_ALL;
 82 
 83         break;
 84 
 85     case EV_LED:
 86         if (is_event_supported(code, dev->ledbit, LED_MAX) &&
 87             !!test_bit(code, dev->led) != value) {
 88 
 89             __change_bit(code, dev->led);
 90             disposition = INPUT_PASS_TO_ALL;
 91         }
 92         break;
 93 
 94     case EV_SND:
 95         if (is_event_supported(code, dev->sndbit, SND_MAX)) {
 96 
 97             if (!!test_bit(code, dev->snd) != !!value)
 98                 __change_bit(code, dev->snd);
 99             disposition = INPUT_PASS_TO_ALL;
100         }
101         break;
102 
103     case EV_REP:
104         if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
105             dev->rep[code] = value;
106             disposition = INPUT_PASS_TO_ALL;
107         }
108         break;
109 
110     case EV_FF:
111         if (value >= 0)
112             disposition = INPUT_PASS_TO_ALL;
113         break;
114 
115     case EV_PWR:
116         disposition = INPUT_PASS_TO_ALL;
117         break;
118     }
119 
120     if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)/*处理 EV_SYN 事件,这里并不对其进行关心。*/  
121         dev->sync = 0;
122 
123     /*首先判断 disposition 等于 INPUT_PASS_TO_DEVICE,然后判断 dev->event 是否对其指定了一个处理函数,
124     如果这些条件都满足,则调用自定义的 dev->event()函数处理事件。有些事件是发送给设备,
125     而不是发送给 handler 处理的。event()函数用来向输入子系统报告一个将要发送给设备的事件,
126     例如让 LED 灯点亮事件、蜂鸣器鸣叫事件等。当事件报告给输入子系统后,就要求设备处理这个事件。*/    
127     if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
128         dev->event(dev, type, code, value);
129 
130     if (disposition & INPUT_PASS_TO_HANDLERS)  //如果事件需要 handler 处理,则调用 input_pass_event()函数 
131         input_pass_event(dev, type, code, value);
132 }
View Code

    input_pass_event   找到对应的handler,然后调用事件处理器处理

技术分享
 1 static void input_pass_event(struct input_dev *dev,
 2                  unsigned int type, unsigned int code, int value)
 3 {
 4     struct input_handle *handle;
 5 
 6     rcu_read_lock();
 7     /*表示如果没有为 input device 强制指定 handler,为 grab 赋值,
 8     即就会遍历 input device->h_list 上的 handle 成员。
 9     如果该 handle 被打开,表示该设备已经被一个用户进程使用。
10     就会调用与输入设备对应的 handler 的 event()函数。注意,
11     只有在 handle 被打开的情况下才会接收到事件,这就是说,
12     只有设备被用户程序使用时,才有必要向用户空间导出信息。*/  
13     handle = rcu_dereference(dev->grab);
14     if (handle)
15         handle->handler->event(handle, type, code, value);
16     else
17         list_for_each_entry_rcu(handle, &dev->h_list, d_node)
18             if (handle->open)
19                 handle->handler->event(handle,
20                             type, code, value);
21     rcu_read_unlock();
22 }
View Code

    input_attach_handler  将事件处理器和设备进行连接

技术分享
 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     if (handler->blacklist && input_match_device(handler->blacklist, dev))
 7         return -ENODEV;
 8    /*首先判断 handler 的 blacklist 是否被赋值,如果被赋值,则匹配 blacklist 中的数据跟 dev->id 
 9    的数据是否匹配。blacklist 是一个 input_device_id*的类型,其指向 input_device_id的一个表,
10    这个表中存放了驱动程序应该忽略的设备。即使在 id_table 中找到支持的项,也应该忽略这种设备。*/ 
11     id = input_match_device(handler->id_table, dev);
12     if (!id)
13         return -ENODEV;
14 
15     error = handler->connect(handler, dev, id);//连接设备和处理函数
16     if (error && error != -ENODEV)
17         printk(KERN_ERR
18             "input: failed to attach handler %s to device %s, "
19             "error: %d\n",
20             handler->name, kobject_name(&dev->dev.kobj), error);
21 
22     return error;
23 }
View Code

  input_match_device     事件处理器可以对一种或几种类型的事件进行处理,在连接前,先找到支持这类设备的事件处理器

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

    input_register_handler   注册一个事件处理器

技术分享
 1 /**
 2  * input_register_handler - register a new input handler
 3  * @handler: handler to be registered
 4  *
 5  * This function registers a new input handler (interface) for input
 6  * devices in the system and attaches it to all input devices that
 7  * are compatible with the handler.
 8  */
 9 int input_register_handler(struct input_handler *handler)
10 {
11     struct input_dev *dev;
12     int retval;
13 
14     retval = mutex_lock_interruptible(&input_mutex);
15     if (retval)
16         return retval;
17 
18     INIT_LIST_HEAD(&handler->h_list);
19 
20     if (handler->fops != NULL) {
21         if (input_table[handler->minor >> 5]) {
22             retval = -EBUSY;
23             goto out;
24         }
25         input_table[handler->minor >> 5] = handler;
26     }
27 
28     list_add_tail(&handler->node, &input_handler_list);
29 
30     list_for_each_entry(dev, &input_dev_list, node);
31         input_attach_handler(dev, handler);
32 
33     input_wakeup_procfs_readers();
34 
35  out:
36     mutex_unlock(&input_mutex);
37     return retval;
38 }
View Code

    input_register_handle    注册一个input_handle结构

技术分享
 1 /**
 2  * input_register_handle - register a new input handle
 3  * @handle: handle to register
 4  *
 5  * This function puts a new input handle onto device‘s
 6  * and handler‘s lists so that events can flow through
 7  * it once it is opened using input_open_device().
 8  *
 9  * This function is supposed to be called from handler‘s
10  * connect() method.
11  */
12 int input_register_handle(struct input_handle *handle)
13 {
14     struct input_handler *handler = handle->handler;
15     struct input_dev *dev = handle->dev;
16     int error;
17 
18     /*
19      * We take dev->mutex here to prevent race with
20      * input_release_device().
21      */
22     error = mutex_lock_interruptible(&dev->mutex);
23     if (error)
24         return error;
25     list_add_tail_rcu(&handle->d_node, &dev->h_list);
26     mutex_unlock(&dev->mutex);
27 
28     /*
29      * Since we are supposed to be called from ->connect()
30      * which is mutually exclusive with ->disconnect()
31      * we can‘t be racing with input_unregister_handle()
32      * and so separate lock is not needed here.
33      */
34     list_add_tail(&handle->h_node, &handler->h_list);
35 
36     if (handler->start)
37         handler->start(handle);
38 
39     return 0;
40 }
View Code

 

以上是关于input子系统学习之四:核心层的主要内容,如果未能解决你的问题,请参考以下文章

linux内核学习之四 系统调用

vue学习之四组件系统

大数据学习之四——HDFS

Mybatis学习之核心原理代码详解

javascript实例学习之四——javascript分页

iOS学习之代码块(Block)