Eric Fang 2010-02-04
--------------------------------------------------------------
本站分析linux核心源碼,版本号為2.6.32.3
轉載請注明出處:http://ericfang.cublog.cn/
--------------------------------------------------------------
接上一篇文章繼續分析。
三.input_event事件的處理
事件的處理處理的接口函數為input_event,在/linux/input.h中還定義了、 input_report_key、input_report_rel、input_report_abs、input_report_ff_status、input_report_switch、input_sync、input_mt_sync等函數,這些函數都是input_event函數的封裝,用于下層驅動向輸入子系統上報事件,另外input_inject_event函數用于輸入子系統向裝置産生事件。
input_event函數定義如下:
0302 void input_event(struct input_dev *dev,
0303 unsigned int type, unsigned int code, int value)
0304 {
0305 unsigned long flags;
0306
0307 if (is_event_supported(type, dev->evbit, EV_MAX)) {
0308
0309 spin_lock_irqsave(&dev->event_lock, flags);
0310 add_input_randomness(type, code, value);
0311 input_handle_event(dev, type, code, value);
0312 spin_unlock_irqrestore(&dev->event_lock, flags);
0313 }
0314 }
先看看第0307行的判斷:
0065 static inline int is_event_supported(unsigned int code,
0066 unsigned long *bm, unsigned int max)
0067 {
0068 return code <= max && test_bit(code, bm);
0069 }
判斷事件是否合法,即dev->evbit是否定義了type位。
如果is_event_supported傳回非0則先去獲得dev->event_lock自旋鎖并關中斷,第0310與系統的随機因子有關,這裡不讨論,接着轉入0311行input_handle_event函數:
0165 static void input_handle_event(struct input_dev *dev,
0166 unsigned int type, unsigned int code, int value)
0167 {
0168 int disposition = INPUT_IGNORE_EVENT;
0169
0170 switch (type) {
0171
0172 case EV_SYN:
0173 switch (code) {
0174 case SYN_CONFIG:
0175 disposition = INPUT_PASS_TO_ALL;
0176 break;
0177
0178 case SYN_REPORT:
0179 if (!dev->sync) {
0180 dev->sync = 1;
0181 disposition = INPUT_PASS_TO_HANDLERS;
0182 }
0183 break;
0184 case SYN_MT_REPORT:
0185 dev->sync = 0;
0186 disposition = INPUT_PASS_TO_HANDLERS;
0187 break;
0188 }
0189 break;
0190
0191 case EV_KEY:
0192 if (is_event_supported(code, dev->keybit, KEY_MAX) &&
0193 !!test_bit(code, dev->key) != value) {
0194
0195 if (value != 2) {
0196 __change_bit(code, dev->key);
0197 if (value)
0198 input_start_autorepeat(dev, code);
0199 else
0200 input_stop_autorepeat(dev);
0201 }
0202
0203 disposition = INPUT_PASS_TO_HANDLERS;
0204 }
0205 break;
0206
0207 case EV_SW:
0208 if (is_event_supported(code, dev->swbit, SW_MAX) &&
0209 !!test_bit(code, dev->sw) != value) {
0210
0211 __change_bit(code, dev->sw);
0212 disposition = INPUT_PASS_TO_HANDLERS;
0213 }
0214 break;
0215
0216 case EV_ABS:
0217 if (is_event_supported(code, dev->absbit, ABS_MAX)) {
0218
0219 if (test_bit(code, input_abs_bypass)) {
0220 disposition = INPUT_PASS_TO_HANDLERS;
0221 break;
0222 }
0223
0224 value = input_defuzz_abs_event(value,
0225 dev->abs[code], dev->absfuzz[code]);
0226
0227 if (dev->abs[code] != value) {
0228 dev->abs[code] = value;
0229 disposition = INPUT_PASS_TO_HANDLERS;
0230 }
0231 }
0232 break;
0233
0234 case EV_REL:
0235 if (is_event_supported(code, dev->relbit, REL_MAX) && value)
0236 disposition = INPUT_PASS_TO_HANDLERS;
0237
0238 break;
0239
0240 case EV_MSC:
0241 if (is_event_supported(code, dev->mscbit, MSC_MAX))
0242 disposition = INPUT_PASS_TO_ALL;
0243
0244 break;
0245
0246 case EV_LED:
0247 if (is_event_supported(code, dev->ledbit, LED_MAX) &&
0248 !!test_bit(code, dev->led) != value) {
0249
0250 __change_bit(code, dev->led);
0251 disposition = INPUT_PASS_TO_ALL;
0252 }
0253 break;
0254
0255 case EV_SND:
0256 if (is_event_supported(code, dev->sndbit, SND_MAX)) {
0257
0258 if (!!test_bit(code, dev->snd) != !!value)
0259 __change_bit(code, dev->snd);
0260 disposition = INPUT_PASS_TO_ALL;
0261 }
0262 break;
0263
0264 case EV_REP:
0265 if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
0266 dev->rep[code] = value;
0267 disposition = INPUT_PASS_TO_ALL;
0268 }
0269 break;
0270
0271 case EV_FF:
0272 if (value >= 0)
0273 disposition = INPUT_PASS_TO_ALL;
0274 break;
0275
0276 case EV_PWR:
0277 disposition = INPUT_PASS_TO_ALL;
0278 break;
0279 }
0280
0281 if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
0282 dev->sync = 0;
0283
0284 if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
0285 dev->event (dev, type, code, value);
0286
0287 if (disposition & INPUT_PASS_TO_HANDLERS)
0288 input_pass_event(dev, type, code, value);
0289 }
第0168~0279根據輸入參數type,和code設定disposition的值,disposition的值為下列四種情況之一:
0160 #define INPUT_IGNORE_EVENT 0
忽略事件;
0161 #define INPUT_PASS_TO_HANDLERS 1
事件需要handler來處理;
0162 #define INPUT_PASS_TO_DEVICE 2
事件需要device來處理;
0163 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
事件同時需要handler和device來處理
接着0284~0288行根據disposition的值選擇執行dev->event和input_pass_event函數。
首先看0285行這個event回調函數,對于atkbd鍵盤驅動,在注冊input_dev時有下列語句:
input_dev->event = atkbd_event;
atkbd_event函數如下:
0624 static int atkbd_event(struct input_dev *dev,
0625 unsigned int type, unsigned int code, int value)
0626 {
0627 struct atkbd *atkbd = input_get_drvdata(dev);
0628
0629 if (!atkbd->write)
0630 return -1;
0631
0632 switch (type) {
0633
0634 case EV_LED:
0635 atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
0636 return 0;
0637
0638 case EV_REP:
0639 if (!atkbd->softrepeat)
0640 atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT);
0641 return 0;
0642 }
0643
0644 return -1;
0645 }
第0629行如果裝置不自持往裝置寫操作,則傳回-1。
第0634行如果type為EV_LED類型事件,則調用atkbd_schedule_event_work函數:
0605 static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
0606 {
0607 unsigned long delay = msecs_to_jiffies(50);
0608
0609 if (time_after(jiffies, atkbd->event_jiffies + delay))
0610 delay = 0;
0611
0612 atkbd->event_jiffies = jiffies;
0613 set_bit(event_bit, &atkbd->event_mask);
0614 wmb();
0615 schedule_delayed_work(&atkbd->event_work, delay);
0616 }
這個函數會在delay一定事件後激活atkbd的event_work程序,這個程序會告訴裝置閃爍led等會或設定重複延遲時間。如果你有興趣可以參考/drivers/input/keyboard/ atkbd.c中相關代碼。
接着看input_handle_event函數第0288行,調用handler處理的函數input_pass_event:
0091 static void input_pass_event(struct input_dev *dev,
0092 unsigned int type, unsigned int code, int value)
0093 {
0094 struct input_handle *handle;
0095
0096 rcu_read_lock();
0097
0098 handle = rcu_dereference(dev->grab);
0099 if (handle)
0100 handle->handler->event(handle, type, code, value);
0101 else
0102 list_for_each_entry_rcu(handle, & dev->h_list, d_node)
0103 if (handle->open)
0104 handle->handler->event(handle,
0105 type, code, value);
0106 rcu_read_unlock();
0107 }
第0098~0105行,如果input_dev指定了handler,則調用該handler的event函數,否則周遊input_dev的h_list上的handle,在前面handle注冊的分析中已經知道handle挂到input_dev的h_list連結清單上。這裡要強調一點:dev->h_list上所有的handle,隻要其open字段不為0,就會執行其handle->handler->event函數。對于kbd_handler相應的event函數為kbd_event,看一下這個函數:
1296 static void kbd_event(struct input_handle *handle, unsigned int event_type,
1297 unsigned int event_code, int value)
1298 {
1299 if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
1300 kbd_rawcode(value);
1301 if (event_type == EV_KEY)
1302 kbd_keycode(event_code, value, HW_RAW(handle->dev));
1303 tasklet_schedule(&keyboard_tasklet);
1304 do_poke_blanked_console = 1;
1305 schedule_console_callback();
1306 }
根據event_type的值調用kbd_rawcode和kbd_keycode,然後排程keyboard_tasklet tasklet,接着調用schedule_console_callback函數,這部分涉及到tty的内容,等後面分析tty驅動時再進一步分析這部分。
四.輸入子系統的初始化
到這裡,已經基本清楚了輸入子系統的結構了,但還有一個疑點,在注冊handler函數input_register_handler中的下列代碼片段中:
1611 if (handler->fops != NULL) {
1612 if (input_table[handler->minor >> 5]) {
1613 retval = -EBUSY;
1614 goto out;
1615 }
1616 input_table[handler->minor >> 5] = handler;
1617 }
這個input_table數組有什麼作用呢?要明白這點得從輸入子系統的初始化講起,初始化函數如下:
1779 static int __init input_init(void)
1780 {
1781 int err;
1782
1783 input_init_abs_bypass();
1784
1785 err = class_register(&input_class);
1786 if (err) {
1787 printk(KERN_ERR "input: unable to register input_dev class/n");
1788 return err;
1789 }
1790
1791 err = input_proc_init();
1792 if (err)
1793 goto fail1;
1794
1795 err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
1796 if (err) {
1797 printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
1798 goto fail2;
1799 }
1800
1801 return 0;
1802
1803 fail2: input_proc_exit();
1804 fail1: class_unregister(&input_class);
1805 return err;
1806 }
第1785行注冊了一個名為”input”的類,所有input device都屬于這個類,在sysfs中,所有input device的目錄都位于/dev/class/input下面。
第1791在/proc下面建立相關的互動檔案:
0965 static int __init input_proc_init(void)
0966 {
0967 struct proc_dir_entry *entry;
0968
0969 proc_bus_input_dir = proc_mkdir("bus/input", NULL);
0970 if (!proc_bus_input_dir)
0971 return -ENOMEM;
0972
0973 entry = proc_create("devices", 0, proc_bus_input_dir,
0974 &input_devices_fileops);
0975 if (!entry)
0976 goto fail1;
0977
0978 entry = proc_create("handlers", 0, proc_bus_input_dir,
0979 &input_handlers_fileops);
0980 if (!entry)
0981 goto fail2;
0982
0983 return 0;
0984
0985 fail2: remove_proc_entry("devices", proc_bus_input_dir);
0986 fail1: remove_proc_entry("bus/input", NULL);
0987 return -ENOMEM;
0988 }
第1795行,調用register_chrdev函數注冊了主裝置号為INPUT_MAJOR(即13)次裝置号為0~255的字元裝置。其檔案操作指針為input_fops,也即主裝置号為13的裝置的檔案操作指針為input_fops,其定義如下:
1766 static const struct file_operations input_fops = {
1767 .owner = THIS_MODULE,
1768 .open = input_open_file,
1769 };
看一下這個open函數:
1728 static int input_open_file(struct inode *inode, struct file *file)
1729 {
1730 struct input_handler *handler;
1731 const struct file_operations *old_fops, *new_fops = NULL;
1732 int err;
1733
1734 lock_kernel();
1735
1736 handler = input_table[iminor(inode) >> 5];
1737 if (!handler || !(new_fops = fops_get(handler->fops))) {
1738 err = -ENODEV;
1739 goto out;
1740 }
1741
1742
1746 if (!new_fops->open) {
1747 fops_put(new_fops);
1748 err = -ENODEV;
1749 goto out;
1750 }
1751 old_fops = file->f_op;
1752 file->f_op = new_fops;
1753
1754 err = new_fops->open(inode, file);
1755
1756 if (err) {
1757 fops_put(file->f_op);
1758 file->f_op = fops_get(old_fops);
1759 }
1760 fops_put(old_fops);
1761 out:
1762 unlock_kernel();
1763 return err;
1764 }
第1736行,看到我們熟悉的input_table數組了,其定義如下:
0063 static struct input_handler *input_table[8];
輸入子系統把主裝置号為13的256個次裝置号分成8組,每組對應一個input_handler,存放在input_table數組中,現在我們可以了解上面的代碼片段了:當注冊input_handler時,如果其fops指針不為NULL,就會分下列兩種情況:1,input_table數組中相應索引的元素還沒指向某個input_handler,則将其指向這個input_handler,2,nput_table數組中相應索引的元素已經指向某個input_handler,則不會注冊這個input_handler。
繼續看input_open_file函數,獲得裝置号inode對應的handler後,如果其fops->open不為空,則會改變相應檔案的f_op指針,将其指向該open,然後調用它,如果open傳回非0,就會恢複相應檔案的f_op指針并傳回不能成功打開檔案。
小結:輸入子系統到這裡就全部分析完了,本次在分析過程中以at鍵盤驅動為例子,如果你還想了解更多更深入,可以去閱讀核心的evdev子產品,其對應的input_handler比對了所有的input device,代碼位于/drivers/input/evdev.c中。