关闭

LINUX设备驱动之输入子系统(三)

标签: linuxinputstructreporttablekeyboard
913人阅读 评论(0) 收藏 举报
分类:

三.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中。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:75328次
    • 积分:975
    • 等级:
    • 排名:千里之外
    • 原创:18篇
    • 转载:33篇
    • 译文:0篇
    • 评论:5条
    文章分类
    最新评论