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 添加到内核
在系统启动时系统会注册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。