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 }

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 }

  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 }

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

  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 }

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 }

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 }

  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 }

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 }

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 }

时间: 2024-10-12 07:13:56

input子系统学习之四:核心层的相关文章

Linux input子系统学习总结(二)----Input事件驱动

Input 事件驱动:  (主要文件 :drivers/input/evdev.c  .  drivers/input/input.h)基于kernel 4.0  一. 关键函数调用顺序: 1.input_register_handler(&evdev_handler); ///注册 evdev_handler 这个input事件驱evdev.c      2.input_attach_handler(dev, handler);////input 设备和 input 事件进行匹配   inpu

Linux/Android——input子系统核心

之前的博客有涉及到linux的input子系统,这里学习记录一下input模块. input子系统,作为管理输入设备与系统进行交互的中枢,任何的输入设备驱动都要通过input向内核注册其设备, 常用的输入设备也就是鼠标,键盘,触摸屏. 稍微细分一点整个输入体系,就是 硬件驱动层,input核心中转层,事件处理层.层次之间传递都以event事件的形式,这其中input连接上下层,分别提供接口. 之前有分析usbtouchscreen的驱动,也就是硬件驱动部分,这里简单记录一下input核心中转处理

Linux/Android——input子系统核心 (三)【转】

本文转载自:http://blog.csdn.net/jscese/article/details/42123673 之前的博客有涉及到linux的input子系统,这里学习记录一下input模块. input子系统,作为管理输入设备与系统进行交互的中枢,任何的输入设备驱动都要通过input向内核注册其设备, 常用的输入设备也就是鼠标,键盘,触摸屏. 稍微细分一点整个输入体系,就是 硬件驱动层,input核心中转层,事件处理层.层次之间传递都以event事件的形式,这其中input连接上下层,分

input子系统——架构、驱动、应用程序

一.input子系统架构 input子系统由驱动层drivers,输入子系统核心层input core,事件处理层event handler组成. 一个输入事件,通过输入设备发给系统如鼠标移动,键盘按键按下等通过device driver->input core(handler->event函数)->event handler->user space的顺序到达用户空间传给应用程序. 一个输出事件,通过系统发给输入设备,通过user space->event handler-&

Android驱动之 Linux Input子系统之TP——A/B(Slot)协议

utm_source=tuicool&utm_medium=referral">点击打开链接 将A/B协议这部分单独拿出来说一方面是由于这部分内容是比較easy忽视的.周围大多数用到input子系统的开发者也不甚理解.还有一方面是由于这部分知识一旦扩展到TP(触摸屏Touch Panel)的多点触摸就要与Middleware/Framework一起结合起来看才干全然掌握,复杂性所在. 这里的Middleware/Framework是针对android来说的,本人从事android这

input子系统

以前,看过国嵌关于input子系统的视频课程,说实话,我看完后脑子里很乱,给我的印象好像是input子系统驱动是一个全新的驱动架构,疑惑相当多.前几天在网上,看到有很多人介绍韦东山老师的linux驱动课程很不错,于是,我就买了第二期的视频,看了韦老师讲解的input子系统视频课程后,我完全明白了整个input子系统的工作机制.为了方便以后查阅,对input子系统的整体框架总结如下: 典型的输入设备(如键盘.鼠标)的工作机制都是差不多的,都是在设备有动作时,向CPU产生一个中断,通知它读取相应的数

linux kernel input 子系统分析

Linux 内核为了处理各种不同类型的的输入设备 , 比如说鼠标 , 键盘 , 操纵杆 , 触摸屏 , 设计并实现了一个对上层应用统一的试图的抽象层 , 即是Linux 输入子系统 . 输入子系统的层次结构体如下 从底层到上层 , input 子系统由 设备驱动层 , 核心层 , 以及事件处理层3个部分组成 当一个鼠标移动, 一个按键按下或弹起 , 它都需要从底层设备驱动-->核心层-->事件处理层 -->用户空间 , 层层上报 , 一直到运用程序. 应用这个input  子系统有如下优

Linux input 子系统应用之按键驱动

硬件平台:s5pv210 软件平台:Linux2.6.35.7 应用程序:inputk2_app.c #include <stdio.h> #include <fcntl.h> #include <linux/input.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char** argv) { int fd; int count; int i = 0; int

input子系统详解2

上一节大概了解了输入子系统的流程 这一节认真追踪一下代码 input.c: input_init(void)函数 1 static int __init input_init(void) 2 { 3 int err; 4 5 err = class_register(&input_class); 6 if (err) { 7 printk(KERN_ERR "input: unable to register input_dev class\n"); 8 return err;