1、
上图是
input输入子系统框架,输入子系统由输入子系统核心层( Input Core
),驱动层和事件处理层(EventHandler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 input
driver -> Input core ->Event handler -> userspace
到达用户空间传给应用程序。
2、先来说下Input Core输入子系统核心层。在Linux中,输入子系统作为一个模块存在,向上,为用户层提供接口函数,向下,为驱动层程序提供统一的接口函数。主要在Input.c
(linux2.6.28\drivers\input)文件中:
- subsys_initcall(input_init);
- module_exit(input_exit);
- static int __init input_init(void)
- {
- int err;
- err = class_register(&input_class);//注册一个名为input的类
其中有:
- struct class input_class = {
- .name = "input",
- };
- if (err) {
- printk(KERN_ERR "input: unable to register input_dev class\n");
- return err;
- }
- err = input_proc_init();
- if (err)
- goto fail1;
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);注册了主设备号为INPUT_MAJOR的字符设备,操作函数集是:input_fops,如下所示:
- static const struct file_operations input_fops = {
- .owner = THIS_MODULE,
- .open = input_open_file,
- };
- if (err) {
- printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
- goto fail2;
- }
- return 0;
- fail2: input_proc_exit();
- fail1: class_unregister(&input_class);
- return err;
- }
- static void __exit input_exit(void) //做和input_init函数做相反的工作
- {
- input_proc_exit();
- unregister_chrdev(INPUT_MAJOR, "input");
- class_unregister(&input_class);
- }
2.1、接着看下input_open_file函数,源码如下:
- static int input_open_file(struct inode *inode, struct file *file)
- {
- struct input_handler *handler;
- const struct file_operations *old_fops, *new_fops = NULL;
- int err;
- lock_kernel();
- /* No load-on-demand here? */
- handler = input_table[iminor(inode) >> 5];
其中iminor(inode)为打开文件所对应的次设备号。input_table是一个struct
input_handler全局数组,只有8个元素,其定义为:
static struct input_handler *input_table[8];
首
先将设备结点的次设备号右移5位做为索引值到input_table中取对应项,从这里也可以看到,一个handler代表
32(1<<5)个设备结点,也就是一个handler最多可以处理32个设备结点。因为在input_table中取值是以次备号右移5位
为索引的,即第5位相同的次备号对应的是同一个索引。在input_register_handler()函数中
input_table[handler->minor >> 5] =
handler,其将handler赋给了input_table数组,所使用的规则也是右移5位。
其中input_handler结构体如下所示:
- /**
- * struct input_handler - implements one of interfaces for input devices
- * @private: driver-specific data
- * @event: event handler. This method is being called by input core with
- * interrupts disabled and dev->event_lock spinlock held and so
- * it may not sleep
- * @connect: called when attaching a handler to an input device
- * @disconnect: disconnects a handler from input device
- * @start: starts handler for given handle. This function is called by
- * input core right after connect() method and also when a process
- * that "grabbed" a device releases it
- * @fops: file operations this driver implements
- * @minor: beginning of range of 32 minors for devices this driver
- * can provide
- * @name: name of the handler, to be shown in /proc/bus/input/handlers
- * @id_table: pointer to a table of input_device_ids this driver can
- * handle
- * @blacklist: pointer to a table of input_device_ids this driver should
- * ignore even if they match @id_table
- * @h_list: list of input handles associated with the handler
- * @node: for placing the driver onto input_handler_list
- *
- * Input handlers attach to input devices and create input handles. There
- * are likely several handlers attached to any given input device at the
- * same time. All of them will get their copy of input event generated by
- * the device.
- *
- * Note that input core serializes calls to connect() and disconnect()
- * methods.
- */
- struct input_handler {
- void *private;
- void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
- int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
- void (*disconnect)(struct input_handle *handle);
- void (*start)(struct input_handle *handle);
- const struct file_operations *fops;
- int minor;
- const char *name;
- const struct input_device_id *id_table;
- const struct input_device_id *blacklist;
- struct list_head h_list;
- struct list_head node;
- };
-
- if (!handler || !(new_fops = fops_get(handler->fops))) {
- //检查handler是否存在
- err = -ENODEV;
- goto out;
- }
- /*
- * That's _really_ odd. Usually NULL ->open means "nothing special",
- * not "no device". Oh, well...
- */
- if (!new_fops->open) { //判断new_fops->open是否存在
- fops_put(new_fops);
- err = -ENODEV;
- goto out;
- }
- old_fops = file->f_op;
- file->f_op = new_fops;
- err = new_fops->open(inode, file); //使用新的open函数重新打开设备
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
- fops_put(old_fops);
- out:
- unlock_kernel();
- return err;
- }
阅读(283) | 评论(0) | 转发(0) |