1. 基本數(shù)據(jù)結(jié)構(gòu)和使用示例
input_event數(shù)據(jù)結(jié)構(gòu)如下:
- struct input_event {
- struct timeval time;
- __u16 type;
- __u16 code;
- __s32 value;
- };
input_dev數(shù)據(jù)結(jié)構(gòu)如下:
- struct input_dev {
- const char *name;
- const char *phys;
- const char *uniq;
- struct input_id id;
-
- unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
-
- unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
- unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
- unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
- unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
- unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
- unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
- unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
- unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
- unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
-
- unsigned int hint_events_per_packet;
-
- unsigned int keycodemax;
- unsigned int keycodesize;
- void *keycode;
-
- int (*setkeycode)(struct input_dev *dev,
- const struct input_keymap_entry *ke,
- unsigned int *old_keycode);
- int (*getkeycode)(struct input_dev *dev,
- struct input_keymap_entry *ke);
-
- struct ff_device *ff;
-
- unsigned int repeat_key;
- struct timer_list timer;
-
- int rep[REP_CNT];
-
- struct input_mt_slot *mt;
- int mtsize;
- int slot;
- int trkid;
-
- struct input_absinfo *absinfo;
-
- unsigned long key[BITS_TO_LONGS(KEY_CNT)];
- unsigned long led[BITS_TO_LONGS(LED_CNT)];
- unsigned long snd[BITS_TO_LONGS(SND_CNT)];
- unsigned long sw[BITS_TO_LONGS(SW_CNT)];
-
- int (*open)(struct input_dev *dev);
- void (*close)(struct input_dev *dev);
- int (*flush)(struct input_dev *dev, struct file *file);
- int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
-
- struct input_handle __rcu *grab;
-
- spinlock_t event_lock;
- struct mutex mutex;
-
- unsigned int users;
- bool going_away;
-
- bool sync;
-
- struct device dev;
-
- struct list_head h_list;
- struct list_head node;
- }
比如TouchScrenn報(bào)告一個(gè)TouchDown事件給Input子系統(tǒng),其代碼如下:
- input_report_abs(inputdevice, ABS_X, 100);
- input_report_abs(inputdevice, ABS_Y, 200);
- input_report_key(inputdevice, BTN_TOUCH, 1);
-
- static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
- {
- input_event(dev, EV_ABS, code, value);
- }
-
- static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
- {
- input_event(dev, EV_KEY, code, !!value);
- }
-
-
-
-
-
-
-
-
-
-
-
- void input_event(struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
- {
- unsigned long flags;
-
- if (is_event_supported(type, dev->evbit, EV_MAX)) {
-
- spin_lock_irqsave(&dev->event_lock, flags);
- add_input_randomness(type, code, value);
- input_handle_event(dev, type, code, value);
- spin_unlock_irqrestore(&dev->event_lock, flags);
- }
- }
它將調(diào)用input_pass_event,input_pass_event代碼如下:
- static void input_pass_event(struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
- {
- struct input_handler *handler;
- struct input_handle *handle;
-
- rcu_read_lock();
-
- handle = rcu_dereference(dev->grab);
- if (handle)
- handle->handler->event(handle, type, code, value);
- else {
- bool filtered = false;
-
- list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
- if (!handle->open)
- continue;
-
- handler = handle->handler;
- if (!handler->filter) {
- if (filtered)
- break;
-
- handler->event(handle, type, code, value);
-
- } else if (handler->filter(handle, type, code, value))
- filtered = true;
- }
- }
-
- rcu_read_unlock();
- }
上面的handler就是下面的evdev_handler.
2. evdev & input core & input_dev初始化
在kernel中,調(diào)用函數(shù)evdev_read,此函數(shù)從client->buffer中(evdev_client *client = file->private_data;)copy對(duì)應(yīng)的input_event到用戶提供的buffer。這些input_event數(shù)據(jù)如何從input_handle_event到client->buffer中的呢? 它是在evdev_event中實(shí)現(xiàn)的。
- <span style="font-size:10px;">static struct input_handler evdev_handler = {
- .event = evdev_event,
- .connect = evdev_connect,
- .disconnect = evdev_disconnect,
- .fops = &evdev_fops,
- .minor = EVDEV_MINOR_BASE,
- .name = "evdev",
- .id_table = evdev_ids,
- };</span>
input_dev如何與evdev_handler關(guān)聯(lián)起來(lái)的呢? 它只在evdev_init中調(diào)用input_register_handler(&evdev_handler)被注冊(cè)了。其關(guān)聯(lián)關(guān)系如下:
a)在input_register_handler中,把evdev_handler增加到input_handler_list中
b)在input_register_device中,通過(guò)input_attach_handler(dev, handler),尋找input_handler_list中哪一個(gè)input_handler與需要注冊(cè)的設(shè)備相匹配,找到匹配的,則調(diào)用此input_handler的connect把input_handler與注冊(cè)的input_device關(guān)聯(lián)起來(lái),這樣新注冊(cè)的input_device就有對(duì)應(yīng)的處理方法了。
- <span style="font-size:10px;">static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
- {
- const struct input_device_id *id;
- int error;
-
- id = input_match_device(handler, dev);
- if (!id)
- return -ENODEV;
-
- error = handler->connect(handler, dev, id);
- if (error && error != -ENODEV)
- pr_err("failed to attach handler %s to device %s, error: %d\n",
- handler->name, kobject_name(&dev->dev.kobj), error);
-
- return error;
- } </span>
c)如果匹配上了,就調(diào)用evdev_handler->connect函數(shù)(evdev_connect),它把此evdev_handler保存在新設(shè)備的handle->handler中(evdev->handle.handler = handler;)。這樣在input_pass_event就可以調(diào)用evdev->handle.handler.event了。
d)input_handle把input_device和input_handler關(guān)聯(lián)起來(lái),其數(shù)據(jù)結(jié)構(gòu)如下:
- struct input_handle {
-
- void *private;
-
- int open;
- const char *name;
-
- struct input_dev *dev;
- struct input_handler *handler;
-
- struct list_head d_node;
- struct list_head h_node;
- };
e)evdev為事件字符設(shè)備( Event char devices)提供了訪問(wèn)原始輸入設(shè)備事件的方法,即它是做具體事的東東,對(duì)于事件字符設(shè)備,當(dāng)我們調(diào)用open, read, write最終都會(huì)調(diào)用它的函數(shù),即evdev_fops中的對(duì)應(yīng)函數(shù)。有了evdev和input core,設(shè)備驅(qū)動(dòng)程序就很簡(jiǎn)單了.
e.1)首先調(diào)用input_allocate_device 創(chuàng)建一個(gè)input_dev對(duì)象
e.2)然后設(shè)備input_dev的各種屬性以告訴input core你將提供哪些事件
e.3)最后調(diào)用input_register_device把input_dev注冊(cè)到input core
f)input_register_device
前面講過(guò),在input_register_device中,它將在input_handler_list 尋找與input_dev匹配的input_handler,然后調(diào)用input_handler的connect函數(shù),即evdev_connect。在evdev_connect中,它將創(chuàng)建evdev對(duì)象,并以evdev->minor作為索引把它放在evdev_table數(shù)組中。evdev數(shù)據(jù)結(jié)構(gòu)如下:
- struct evdev {
- int open;
- int minor; //在evdev_table中的索引
- struct input_handle handle; //連接input_dev和input_handler
- wait_queue_head_t wait;
- struct evdev_client __rcu *grab; // 用戶每調(diào)用一次open,將創(chuàng)建一個(gè)evdev_client
- struct list_head client_list;
- spinlock_t client_lock; /* protects client_list */
- struct mutex mutex;
- struct device dev;
- bool exist;
- };
-
- struct evdev_client {
- unsigned int head;
- unsigned int tail;
- unsigned int packet_head; /* [future] position of the first element of next packet */
- spinlock_t buffer_lock; /* protects access to buffer, head and tail */
- struct wake_lock wake_lock;
- char name[28];
- struct fasync_struct *fasync;
- struct evdev *evdev;
- struct list_head node;
- unsigned int bufsize;
- struct input_event buffer[]; //存放所有這個(gè)設(shè)備產(chǎn)生的input_event,由evdev_event寫入
- };
在evdev_connect,它設(shè)置設(shè)備名,初始化input_handle中各個(gè)數(shù)據(jù)成員(關(guān)鍵是其input_dev和input_handler),然后再調(diào)用input_register_handle把evdev中的input_handle添加到input_dev的h_lis鏈表中,并且把此input_handle添加到input_handler的h_list鏈表中。從此它們的三角關(guān)系建立完成。注:當(dāng)用戶每打開一次它就要?jiǎng)?chuàng)建一個(gè)evdev_client,并加入到client_list鏈表中,當(dāng)input_dev產(chǎn)生事件時(shí),evdev_event函數(shù)將把此input_event放入evdev->client_list鏈表中的每個(gè)evdev_client的buffer中。它們的關(guān)系如下圖所示:

3. Kernel中數(shù)據(jù)讀取流程
在kernel中調(diào)用evdev_read來(lái)讀取數(shù)據(jù),其函數(shù)原型如下:
static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
其讀取流程為:
1)從前面得知在打開設(shè)備文件時(shí),創(chuàng)建了一個(gè)evdev_client,并把此client保存在file的private_data中,所以現(xiàn)在從file->private_data中取出evdev_client
2)從前面得知此evdev_client中保存有在evdev_connect時(shí)創(chuàng)建的evdev,從而可以得到對(duì)應(yīng)的evdev對(duì)象
3)從client->buffer中讀取事件,并copy到用戶提供的buffer中。前面講過(guò),client->buffer中的事件是當(dāng)input_dev報(bào)告事件給Input core時(shí),由evdev_event把input_event事件放入client->buffer中的。