分类:
2012-03-14 15:35:40
原文地址:LINUX设备驱动之输入子系统(三) 作者:eric_fang
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 /* 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];
输入子系统把主设备号为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中。