幸运儿不是我,因为我选择的路很难走.如果够出色也不能出头,至少要做到没第二个我.
分类: LINUX
2012-10-25 09:07:30
drivers/input/input.c
就是所谓的input的核心程序。
分析这个文件,先从input_init开始。
1: static int __init input_init(void)
2: {
3: err = class_register(&input_class);
4: err = input_proc_init();
5: err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
6: }
__init 把它放到了init.text段,初始化的时候会调用。函数去掉检查的情况,也就这么几行。class_register注册了一个device model里的class类型。具体会在__class_register里面调到
1: /*对class的私有数据进行了初始化工作*/
2: /*cp是一个class_private类型,class的私有类型*/
3: cp = kzalloc(sizeof(*cp), GFP_KERNEL);
4: /*初始化了klist的get/put函数,实际调用了get_device和put_device*/
5: klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
6: INIT_LIST_HEAD(&cp->class_interfaces);
7: kset_init(&cp->class_dirs);
8: __mutex_init(&cp->class_mutex, "struct class mutex", key);
9: error = kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
10:
11: /* set the default /sys/dev directory for devices of this class */
12: if (!cls->dev_kobj)
13: cls->dev_kobj = sysfs_dev_char_kobj;
14: /*注册kset,里面要先初始化kset,在这里获取kobject,就建立了目录了*/
15: error = kset_register(&cp->class_subsys);
16: /*这里建立attribute文件,遍历它的attribute,熟悉device model的话就知道attribute其实就对应着文件*/
17: error = add_class_attrs(class_get(cls));
18:
再回来到input_init中,下一个input_proc_init,这个函数主要建立input字系统在proc文件系统中的目录,文件,注册相应的fops.
这个很简单:
1: /*在proc下建立了input的目录*/
2: proc_bus_input_dir = proc_mkdir("bus/input", NULL);
3: /*在bus/input下建立两个文件devices和handlers,并注册了它们的fops,这两个fops是在input.c中定义的,fops的函数也是在input.c中定义.*/
4: entry = proc_create("devices", 0, proc_bus_input_dir,
5: &input_devices_fileops);
6: entry = proc_create("handlers", 0, proc_bus_input_dir,
7: &input_handlers_fileops);
8:
下面一个register_chardev注册了一个主设备号为INPUT_MAJOR,次设备号从0-256,文件操作符为input_fops的字符设备.
看完了input_init,再看看input.c中,后半部分就是fops的函数,前面是一些接口函数,中间是
handle和handler函数.
说到了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.
了解了框架再去看具体操作的核心代码就不会迷糊了。