接昨天上篇:
说到了input_fops,下面接上:
input_fops:
1: /*打开操作*/
2: input_open_file
3: /*不做操作*/
4: noop_llseek
input_open_file:
1: /*从inode获取minor,获得handler,取得handler的fops,并执行它的open操作*/
2: /*根据inode获取次设备号,再由次设备号算出它在input_table中的位置*/
3: handler = input_table[iminor(inode) >> 5];
4: if (handler)
5: new_fops = fops_get(handler->fops);
6:
7: old_fops = file->f_op;
8: file->f_op = new_fops;
9:
10: err = new_fops->open(inode, file);
11:
12: fops_put(old_fops);
13:
这里用到了handler,看handler是怎么注册的:
input_register_handler:
1: /*初始化handler的h_list*/
2: INIT_LIST_HEAD(&handler->h_list);
3: /*根据handler的minor将handler放到相应的input_table位置中*/
4: if (handler->fops != NULL) {
5: if (input_table[handler->minor >> 5]) {
6: retval = -EBUSY;
7: goto out;
8: }
9: input_table[handler->minor >> 5] = handler;
10: }
11: /*将handler通过node连接到input_handler_list链表中*/
12: list_add_tail(&handler->node, &input_handler_list);
13: /*遍历input_dev_list链表,找出与这个handler匹配的input_dev
14: *并和它connect,匹配和connect的操作就是input_attach_handler
15: *所做的事情
16: */
17: list_for_each_entry(dev, &input_dev_list, node)
18: input_attach_handler(dev, handler);
19: /*唤醒input_devices_poll_wait的等待队列*/
20: input_wakeup_procfs_readers();
这里说到注册handler的时候要遍历input_dev链表,那么input_dev是在哪里注册的呢?
这里当然必须提到input_dev的注册函数input_register_device,在用它注册input_dev
之前必须要分配一个input_dev并且设置它能够做的事情,这里要用input_allocate_device来分配,
用__set_bit,input_set_capability,input_set_abs_params等来设置input_dev的支持的事件evbit,
以及将所支持事件的bit数组中支持的值置相应位。这都是注册具体设备时根据设备支持的事件进行
设置了。设置完这些东西就可以注册这个input_dev了:
input_register_device:
1: /* 对每个输入设备都设置EV_SYN位 */
2: __set_bit(EV_SYN, dev->evbit);
3:
4: /* 清除保留位 */
5: __clear_bit(KEY_RESERVED, dev->keybit);
6:
7: /* 注册设备时没有提到evbit位,都把它们清除掉 */
8: input_cleanse_bitmasks(dev);
9:
10: /*如果没有设置get_keycode[_new]/set_keycode[_new],
11: *则使用input.c中定义的默认方法*/
12: if (!dev->getkeycode && !dev->getkeycode_new)
13: dev->getkeycode_new = input_default_getkeycode;
14:
15: if (!dev->setkeycode && !dev->setkeycode_new)
16: dev->setkeycode_new = input_default_setkeycode;
17:
18: dev_set_name(&dev->dev, "input%ld",
19: (unsigned long) atomic_inc_return(&input_no) - 1);
20: /*增加设备,这里会干很多设备core层的事情*/
21: error = device_add(&dev->dev);
22:
23: /*这里跟注册handler的时候相似,把input_dev加到input_dev_list
24: *链表中,然后遍历handler的链表,找到与这个input_dev匹配的handler
25: *再把它们connect*/
26: list_add_tail(&dev->node, &input_dev_list);
27:
28: list_for_each_entry(handler, &input_handler_list, node)
29: input_attach_handler(dev, handler);
30: /*唤醒等待队列*/
31: input_wakeup_procfs_readers();
32:
在input_allocate_device分配input_dev的时候,给它的设备type设置为
input_dev_type,文件中一大部分代码都是为了完成这个device_type的
成员。最重要的就是input_dev_attr_groups。
在proc_init的时候两个文件handlers,devices,给它们注册的文件操作符分别是
input_handlers_fileops,input_devices_fileops,文件中也有一大部分代码
是为了完成这两个文件操作符的实现。
余下的就是input提供的接口了,就不细说了,用到的时候看看就OK,主要是要对框架了解清楚。
====================================================
我们在写驱动的时候常常会用到input_event,input_sync等,这些都是通过事件层来做的,这就需要了解evdev.c,
看看这个事件设备是怎么搞的。
evdev.c
先看最下面evdev_init:
1: input_register_handler(&evdev_handler)
注册了一个input_handler:evdev_handler。
1: static struct input_handler evdev_handler = {
2: .event = evdev_event,
3: .connect = evdev_connect,
4: .disconnect = evdev_disconnect,
5: .fops = &evdev_fops,
6: .minor = EVDEV_MINOR_BASE,
7: .name = "evdev",
8: .id_table = evdev_ids,
9: };
name不用多说,EVDEV_MINOR_BASE是64,按照minor >> 5的算法,它应该把这个handler指针放到
input_table[1]中,evdev_ids是input_device_id数组,在input_match_device,也就是input_attach_handler
中调用的用来匹配input_dev和handler的函数中用来进行匹配,根据id->flags还有handler里的那些*bit和dev->id
的相应成员进行匹配,这里evdev_ids中,只设置了driver_info,根据匹配函数,它是跟所有的device都匹配的,
It's a bitch.......
整个evdev.c实际上就是实现这个input_handler的各个具体操作函数。
evdev_connect:
对evdev进行初始化,从evdev_table中找出第一个没有被用过的minor,做为它的minor
初始化它的handle成员的dev和handler,初始化它的dev成员。
然后调用input_register_handle,注册handle,它把handle的d_node加到input_dev的
h_list链表,把h_node加到handler的h_list链表,这样就把这个handle同时跟input_dev和
handler关联起来。evdev_install_chrdev把初始化好的这个evdev加到evdev_table中,最后
调用device_add增加这个evdev设备。connect大功告成。
evdev_disconnect:
不用解释。反向操作。
evdev_event:
把input事件发给所有的client.
了解了框架再去看具体操作的核心代码就不会迷糊了。
高万龙(冷月X)
2011.4.8