1. 程式人生 > >Linux-3.0.8 input subsystem代碼閱讀筆記

Linux-3.0.8 input subsystem代碼閱讀筆記

wak evdev dump 輸入子系統 延遲 cbi reg 用戶空間 rup

  先亂序記錄一下閱讀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,這裏就不展開了。

Linux-3.0.8 input subsystem代碼閱讀筆記