Linux-3.0.8 input subsystem代码阅读笔记

  先乱序记录一下阅读Linux input subsystem代码的笔记。

  

  在input device driver的入口代码部分,需要分配并初始化input device结构,内核提供的API是input_allocate_device(),代码如下:

 1 struct input_dev *input_allocate_device(void)
 2 {
 3     struct input_dev *dev;
 4 
 5     dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
 6     if (dev) {
 7         dev->dev.type = &input_dev_type;
 8         dev->dev.class = &input_class;
 9         device_initialize(&dev->dev);
10         mutex_init(&dev->mutex);
11         spin_lock_init(&dev->event_lock);
12         INIT_LIST_HEAD(&dev->h_list);
13         INIT_LIST_HEAD(&dev->node);
14 
15         __module_get(THIS_MODULE);
16     }
17 
18     return dev;
19 }

  此API的工作就是分配内存并初始化结构,这里调用了device_initialize,在input_device_register中还会调用device_add,这两个API合起来就是device_register要做的工作。有了constructor还要有destructor,就是input_free_device,代码如下:

1 void input_free_device(struct input_dev *dev)
2 {
3     if (dev)
4         input_put_device(dev);
5 }

  初始化input device支持事件的时候可以使用input_set_capability(),这个函数的代码如下:

 1 void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
 2 {
 3     switch (type) {
 4     case EV_KEY:
 5         __set_bit(code, dev->keybit);
 6         break;
 7 
 8     case EV_REL:
 9         __set_bit(code, dev->relbit);
10         break;
11 
12     case EV_ABS:
13         __set_bit(code, dev->absbit);
14         break;
15 
16     case EV_MSC:
17         __set_bit(code, dev->mscbit);
18         break;
19 
20     case EV_SW:
21         __set_bit(code, dev->swbit);
22         break;
23 
24     case EV_LED:
25         __set_bit(code, dev->ledbit);
26         break;
27 
28     case EV_SND:
29         __set_bit(code, dev->sndbit);
30         break;
31 
32     case EV_FF:
33         __set_bit(code, dev->ffbit);
34         break;
35 
36     case EV_PWR:
37         /* do nothing */
38         break;
39 
40     default:
41         pr_err("input_set_capability: unknown type %u (code %u)\n",
42                type, code);
43         dump_stack();
44         return;
45     }
46 
47     __set_bit(type, dev->evbit);
48 }

  通过代码可以看到,如果一个设备需要支持多种事件的话,需要多次调用该API,而不能使用按位或的形式传参。

  现在input device初始化完成了,应该向系统注册了,使用的API是input_register_device(),代码如下:

 1 int input_register_device(struct input_dev *dev)
 2 {
 3     static atomic_t input_no = ATOMIC_INIT(0);
 4     struct input_handler *handler;
 5     const char *path;
 6     int error;
 7 
 8     /* Every input device generates EV_SYN/SYN_REPORT events. */
 9     __set_bit(EV_SYN, dev->evbit);
10 
11     /* KEY_RESERVED is not supposed to be transmitted to userspace. */
12     __clear_bit(KEY_RESERVED, dev->keybit);
13 
14     /* Make sure that bitmasks not mentioned in dev->evbit are clean. */
15     input_cleanse_bitmasks(dev);
16 
17     if (!dev->hint_events_per_packet)
18         dev->hint_events_per_packet =
19                 input_estimate_events_per_packet(dev);
20 
21     /*
22      * If delay and period are pre-set by the driver, then autorepeating
23      * is handled by the driver itself and we don't do it in input.c.
24      */
25     init_timer(&dev->timer);
26     if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
27         dev->timer.data = (long) dev;
28         dev->timer.function = input_repeat_key;
29         dev->rep[REP_DELAY] = 250;
30         dev->rep[REP_PERIOD] = 33;
31     }
32 
33     if (!dev->getkeycode)
34         dev->getkeycode = input_default_getkeycode;
35 
36     if (!dev->setkeycode)
37         dev->setkeycode = input_default_setkeycode;
38 
39     dev_set_name(&dev->dev, "input%ld",
40              (unsigned long) atomic_inc_return(&input_no) - 1);
41 
42     error = device_add(&dev->dev);
43     if (error)
44         return error;
45 
46     path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
47     pr_info("%s as %s\n",
48         dev->name ? dev->name : "Unspecified device",
49         path ? path : "N/A");
50     kfree(path);
51 
52     error = mutex_lock_interruptible(&input_mutex);
53     if (error) {
54         device_del(&dev->dev);
55         return error;
56     }
57 
58     list_add_tail(&dev->node, &input_dev_list);
59 
60     list_for_each_entry(handler, &input_handler_list, node)
61         input_attach_handler(dev, handler);
62 
63     input_wakeup_procfs_readers();
64 
65     mutex_unlock(&input_mutex);
66 
67     return 0;
68 }

  这个函数做了以下几件事:

  第一,因为所有的输入设备都需要支持EV_SYN,所以有必要明确置位一下,而KEY_RESERVED事件是不被支持的,所以清除掉。而对于当前设备没有明确表示支持的事件默认不支持,要清除掉相关的bitmap,代码如下:

 1 static void input_cleanse_bitmasks(struct input_dev *dev)
 2 {
 3     INPUT_CLEANSE_BITMASK(dev, KEY, key);
 4     INPUT_CLEANSE_BITMASK(dev, REL, rel);
 5     INPUT_CLEANSE_BITMASK(dev, ABS, abs);
 6     INPUT_CLEANSE_BITMASK(dev, MSC, msc);
 7     INPUT_CLEANSE_BITMASK(dev, LED, led);
 8     INPUT_CLEANSE_BITMASK(dev, SND, snd);
 9     INPUT_CLEANSE_BITMASK(dev, FF, ff);
10     INPUT_CLEANSE_BITMASK(dev, SW, sw);
11 }
1 #define INPUT_CLEANSE_BITMASK(dev, type, bits)                \
2     do {                                \
3         if (!test_bit(EV_##type, dev->evbit))            \
4             memset(dev->bits##bit, 0,            \
5                 sizeof(dev->bits##bit));        \
6     } while (0)

  清除bitmap的时候,首先看dev->evbit[]中是否指定EV_KEY EV_REL EV_ABS EV_MSC EV_LED EV_SND EV_FF EV_SW,若不指定,就把相关的xxxbit数组中所有元素清零,逻辑很简单,但是实现的时候,注意一下宏的使用方式,dev->bits##bit,以前接触的##连接符,都是变动的部分放在最后,变动部分的前面加上##,但是这里变动部分在前面,反而在其后面加##,注意使用方式。

  第二,初始化定时器,设置重复事件,可见,如果用户没有明确指定重复的延迟和周期的话,输入子系统将延迟初始化为默认值250ms,周期是33ms,目前还不知道这部分的意义,估计需要结合具体的输入设备才能理解。

  第三,设置设备的名字,这里的device_add将向系统注册一个设备,如果用户空间有udev或者mdev的话,将在/dev下产生相应的设备节点。

  第四,list_add_tail(&dev->node, &input_dev_list),在操作系统中所谓的注册,其实就是将某单独的数据结构,通过链表或者填充数组的方式让内核可以通过某链表头或者数组找到它,因此,这里的input_dev_list显然就是一个全局变量,链表头。

  第五,这是十分重要的一步,list_for_each_entry(handler, &input_handler_list, node)

                  input_attach_handler(dev, handler);

简而言之,这一步逐一将系统中存在的struct input_handler与当前要注册的input_device进行匹配,若匹配成功,则调用handler->match(),进一步还会调用handler->connect(),显然这些函数指针指向的回调函数都是事件处理层决定的,例如evdev.c中向系统注册的evdev_handler指定的相关函数是evdev_connect,这里就不展开了。

猜你喜欢

转载自www.cnblogs.com/tech-lqh/p/9256355.html