LINUX設備驅動之輸入子系統(三)

三.input_event事件的處理

事件的處理處理的接口函數爲input_event,在\linux\input.h中還定義了、input_report_keyinput_report_relinput_report_absinput_report_ff_statusinput_report_switchinput_syncinput_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與系統的隨機因子有關,這裏不討論,接着轉入0311input_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->eventinput_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行如果typeEV_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一定事件後激活atkbdevent_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,則調用該handlerevent函數,否則遍歷input_devh_list上的handle,在前面handle註冊的分析中已經知道handle掛到input_devh_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_rawcodekbd_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              /* No load-on-demand here? */

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              /*

1743              * That's _really_ odd. Usually NULL ->open means "nothing special",

1744              * not "no device". Oh, well...

1745              */

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];

輸入子系統把主設備號爲13256個次設備號分成8組,每組對應一個input_handler,存放在input_table數組中,現在我們可以理解上面的代碼片段了:當註冊input_handler時,如果其fops指針不爲NULL,就會分下列兩種情況:1input_table數組中相應索引的元素還沒指向某個input_handler,則將其指向這個input_handler2nput_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中。

發佈了18 篇原創文章 · 獲贊 2 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章