以前,看過國嵌關(guān)于input子系統(tǒng)的視頻課程,說實話,我看完后腦子里很亂,給我的印象好像是input子系統(tǒng)驅(qū)動是一個全新的驅(qū)動架構(gòu),疑惑相當(dāng)多。前幾天在網(wǎng)上,看到有很多人介紹韋東山老師的linux驅(qū)動課程很不錯,于是,我就買了第二期的視頻,看了韋老師講解的input子系統(tǒng)視頻課程后,我完全明白了整個input子系統(tǒng)的工作機制。為了方便以后查閱,對input子系統(tǒng)的整體框架總結(jié)如下: 典型的輸入設(shè)備(如鍵盤、鼠標(biāo))的工作機制都是差不多的,都是在設(shè)備有動作時,向CPU產(chǎn)生一個中斷,通知它讀取相應(yīng)的數(shù)據(jù)。Linux為了方便開發(fā)這一類驅(qū)動,它實現(xiàn)了這類驅(qū)動的通用部分,只留下與設(shè)備相關(guān)的部分,這樣使得開發(fā)這一類驅(qū)動更加方便。 在Linux中,Input子系統(tǒng)由三大部分組成,它們是Input子系統(tǒng)核心層、Input子系統(tǒng)事件處理層和Input子系統(tǒng)設(shè)備驅(qū)動層。在通常情況下,Input子系統(tǒng)核心層和Input子系統(tǒng)事件處理層都已經(jīng)實現(xiàn)了,而作為驅(qū)動開發(fā)者,我們僅僅只需要完成Input子系統(tǒng)設(shè)備驅(qū)動層。 對于一個完整的驅(qū)動程序,我們首先需要確定設(shè)備的主設(shè)備號,次設(shè)備號,然后向系統(tǒng)注冊該設(shè)備,最后實現(xiàn)file_operations結(jié)構(gòu)體中的函數(shù)。在Input子系統(tǒng)中,這些步驟會分布到不同的層中,最后三個層通過一些聯(lián)系構(gòu)成了一個完整的驅(qū)動程序。 在input子系統(tǒng)中有三個比較中要的結(jié)構(gòu)體,它們分別是input_handler結(jié)構(gòu)體、input_dev結(jié)構(gòu)體、input_handle結(jié)構(gòu)體。它們的具體代碼如下: struct input_handler { void *private; //driver相關(guān)數(shù)據(jù) void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); //input_event函數(shù)會調(diào)用此函數(shù) int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); const struct file_operations *fops; //file_operation結(jié)構(gòu)體,會替換input.c里的file_operation結(jié)構(gòu)體 int minor; const char *name; //input_handler名稱 const struct input_device_id *id_table; const struct input_device_id *blacklist; struct list_head h_list; //與該handler相關(guān)的handle struct list_head node; }; struct input_dev { const char *name; const char *phys; const char *uniq; struct input_id id; 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 keycodemax; unsigned int keycodesize; void *keycode; int (*setkeycode)(struct input_dev *dev, int scancode, int keycode); int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode); struct ff_device *ff; unsigned int repeat_key; struct timer_list timer; int sync; int abs[ABS_MAX + 1]; int rep[REP_MAX + 1]; 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 absmax[ABS_MAX + 1]; int absmin[ABS_MAX + 1]; int absfuzz[ABS_MAX + 1]; int absflat[ABS_MAX + 1]; int absres[ABS_MAX + 1]; 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 *grab; spinlock_t event_lock; struct mutex mutex; unsigned int users; bool going_away; struct device dev; struct list_head h_list; //與該input_dev相關(guān)的handle struct list_head node; }; struct input_handle { void *private; int open; const char *name; struct input_dev *dev; //指向input_dev struct input_handler *handler; //指向input_handler struct list_head d_node; struct list_head h_node; }; 在Input.c(drivers/input)的input_init函數(shù)中,有: err=register_chrdev(INPUT_MAJOR, "input", &input_fops) 它向系統(tǒng)中注冊了一個主設(shè)備號為INPUT_MAJOR(13),名為input的設(shè)備。而它的file_operations結(jié)構(gòu)體,如下所示: static const struct file_operations input_fops = { .owner = THIS_MODULE, .open = input_open_file, }; 它僅僅實現(xiàn)了open函數(shù),為沒有實現(xiàn)其他函數(shù)。其實其他函數(shù)會在其open函數(shù)中實現(xiàn)。 在input_open_file函數(shù)中,會把Input子系統(tǒng)的事件處理層相關(guān)結(jié)構(gòu)體handler的file_operations賦值給input_fops,從而完整的實現(xiàn)了file_operations結(jié)構(gòu)體。具體實現(xiàn)的代碼: new_fops = fops_get(handler->fops) file->f_op = new_fops; 從這里我們可以看出一個Input子系統(tǒng)的驅(qū)動的file_operations結(jié)構(gòu)體是在handler結(jié)構(gòu)體中實現(xiàn)的。 對于input_handler結(jié)構(gòu)體,它是input子系統(tǒng)中事件處理層相關(guān)的結(jié)構(gòu)體,對于一個具體的事件處理,需要向事件處理層注冊這樣一個結(jié)構(gòu)體,如在鼠標(biāo)的事件處理程序mousedev.c的mousedev_init函數(shù)中,會調(diào)用input_register_handler函數(shù),注冊一個具體的handler。而在input_register_handler函數(shù)中,會將handler添加到input_handler_list中,然后在input_dev_list中尋找相匹配的dev。具體代碼: list_for_each_entry(dev, &input_dev_list, node) input_attach_handler(dev, handler); 因而,要形成一個完成的驅(qū)動,則必須有相應(yīng)的dev。 對于input_dev結(jié)構(gòu)體,它是input子系統(tǒng)中設(shè)備驅(qū)動層相關(guān)的結(jié)構(gòu)體,對于一個具體的設(shè)備,需要向設(shè)備驅(qū)動層注冊這樣一個結(jié)構(gòu)體,如在鼠標(biāo)的設(shè)備驅(qū)動程序usbmouse.c的usb_mouse_probe函數(shù)中,會調(diào)用input_register_device函數(shù),注冊一個具體的dev。而在input_register_device函數(shù)中,會將dev添加到input_dev_list中,然后再input_handler_list尋找相匹配的handler。具體代碼: list_add_tail(&dev->node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node) input_attach_handler(dev, handler); 在input_attach_handler函數(shù)中,會調(diào)用input_match_device函數(shù),將input_dev_list中的dev與handler相匹配或?qū)nput_handler_list中的handler與dev相匹配,匹配成功后就會調(diào)用handler中的connect函數(shù)。而在connect函數(shù)中,會通過handle結(jié)構(gòu)體將匹配好的handler和dev聯(lián)系起來。如mousedev.c中,connect函數(shù)中調(diào)用了mousedev_create函數(shù),而在mousedev_create函數(shù)中,將handle結(jié)構(gòu)中的handler指向匹配好的handler,而dev指向匹配好的dev,然后會調(diào)用input_register_handle函數(shù)。 mousedev->handle.dev = input_get_device(dev); mousedev->handle.name = dev_name(&mousedev->dev); error = input_register_handle(&mousedev->handle); 在 input_register_handle函數(shù)中,將input_handle結(jié)構(gòu)體中的d_node和h_node成員分別添加到了匹配好的dev結(jié)構(gòu)體的h_list中和匹配好的handler結(jié)構(gòu)體的h_list中。 struct input_handler *handler = handle->handler; struct input_dev *dev = handle->dev; list_add_tail_rcu(&handle->d_node, &dev->h_list); list_add_tail(&handle->h_node, &handler->h_list); 這樣,Input驅(qū)動程序中的設(shè)備驅(qū)動和事件處理就這樣無縫連接起來了,無論是我們先有了handler還是先有了dev,input子系統(tǒng)都會找了與之匹配的dev或handler,使得三部分之間更加整體化。 |