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 事件进行匹配   input.h

 

3、handler->connect(handler, dev, id);///调用evdev_handler 的 connect 函数(.connect = evdev_connect

 

4、evdev_connect(struct input_handler *handler, struct input_dev *dev,

const struct input_device_id *id)

 

5、cdev_init(&evdev->cdev, &evdev_fops);//// 初始化一个 cdev

 

6、device_add(&evdev->dev);///把初始化好的 evdev 添加到内核

 

              Linux input子系统学习总结(二)----Input事件驱动_第1张图片

  在系统启动时系统会注册input事件驱动 evdev_handler,通过遍历系统中已经存在input设备,并与之进行匹配,匹配成功即条用connect函数

创建evdev设备,即input设备节点,初始化完成之后,上层应用程序通过evdev_fops对输入设备节点进行open/write/read/ioctrl等一系列操作,

从而完成input输入子系统的整个功能实现;

 

 

二、关键代码段

 1 static struct input_handler evdev_handler = { 
 2     .event        = evdev_event,
 3     .events        = evdev_events,
 4     .connect    = evdev_connect,
 5     .disconnect    = evdev_disconnect,
 6     .legacy_minors    = true,
 7     .minor        = EVDEV_MINOR_BASE,///次设备号从64开始
 8     .name        = "evdev",
 9     .id_table    = evdev_ids,
10 };
11 
12 static int __init evdev_init(void)
13 {
14     return input_register_handler(&evdev_handler); ///注册 evdev_handler 这个input事件驱动
15 }

 

 1 int input_register_handler(struct input_handler *handler)///把input 事件驱动注册到内核
 2 {
 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);///把 handler的 node 加到 input_handler_list这个双向链表,之后就可以通过这个链表访问所有的input_handler
13 
14     list_for_each_entry(dev, &input_dev_list, node)  
15         input_attach_handler(dev, handler);////inout 设备和 input 事件进行匹配
16 
17     input_wakeup_procfs_readers();
18 
19     mutex_unlock(&input_mutex);
20     return 0;
21 }

 

 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);///input_dev 和 input_handler 通过id_table进行匹配  7     if (!id)
 8         return -ENODEV;
 9 
10     error = handler->connect(handler, dev, id);///如果返回id不为空就执行handler 的 connect  ---> 调用 evdev.c 的 connect 函数
11     if (error && error != -ENODEV)
12         pr_err("failed to attach handler %s to device %s, error: %d\n",
13                handler->name, kobject_name(&dev->dev.kobj), error);
14 
15     return error;
16 }

 

 1 /*
 2  * Create new evdev device. Note that input core serializes calls
 3  * to connect and disconnect.
 4  */
 5 static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
 6              const struct input_device_id *id)
 7 {
 8     struct evdev *evdev;
 9     int minor;
10     int dev_no;
11     int error;
12 
13     minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true);//动态分配一个新的设备号minor
14     if (minor < 0) {
15         error = minor;
16         pr_err("failed to reserve new minor: %d\n", error);
17         return error;
18     }
19 
20     evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);///初始化evdev ,为evdev分配空间
21     if (!evdev) {
22         error = -ENOMEM;
23         goto err_free_minor;
24     }
25 
26     INIT_LIST_HEAD(&evdev->client_list);///初始化队列
27     spin_lock_init(&evdev->client_lock);
28     mutex_init(&evdev->mutex);
29     init_waitqueue_head(&evdev->wait);///初始化等待队列
30     evdev->exist = true;
31 
32     dev_no = minor;
33     /* Normalize device number if it falls into legacy range */
34     if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS)
35         dev_no -= EVDEV_MINOR_BASE;
36     dev_set_name(&evdev->dev, "event%d", dev_no);///给设备设置名字(event0、event1、...)
37 
38     evdev->handle.dev = input_get_device(dev);
39     evdev->handle.name = dev_name(&evdev->dev);
40     evdev->handle.handler = handler;
41     evdev->handle.private = evdev;
42 
43     evdev->dev.devt = MKDEV(INPUT_MAJOR, minor);////根据主设备号(主设备号都是13)和次设备号生成一个设备号(次设备号从64开始)
44     evdev->dev.class = &input_class;
45     evdev->dev.parent = &dev->dev;
46     evdev->dev.release = evdev_free;
47     device_initialize(&evdev->dev);///对设备进行初始化
48 
49     error = input_register_handle(&evdev->handle);///注册 handle,handle 用来关联 input_dev 和 input_handler
50     if (error)
51         goto err_free_evdev;
52 
53     cdev_init(&evdev->cdev, &evdev_fops);//// 初始化一个 cdev
54     evdev->cdev.kobj.parent = &evdev->dev.kobj;
55     error = cdev_add(&evdev->cdev, evdev->dev.devt, 1);
56     if (error)
57         goto err_unregister_handle;
58 
59     error = device_add(&evdev->dev);///把初始化好的 evdev 添加到内核
60     if (error)
61         goto err_cleanup_evdev;
62 
63     return 0;
64 
65  err_cleanup_evdev:
66     evdev_cleanup(evdev);
67  err_unregister_handle:
68     input_unregister_handle(&evdev->handle);
69  err_free_evdev:
70     put_device(&evdev->dev);
71  err_free_minor:
72     input_free_minor(minor);
73     return error;
74 }

 

如下图 ,在linux 系统上 /dev/input这个路径下可以看到已经注册好的input设备节点,input设备的主设备号都是13,其中 

按键设备的次设备号从64~95,鼠标设备的次设备号从32~63。

 Linux input子系统学习总结(二)----Input事件驱动_第2张图片

你可能感兴趣的:(Linux input子系统学习总结(二)----Input事件驱动)