ImageVerifierCode 换一换
格式:DOCX , 页数:26 ,大小:28.22KB ,
资源ID:3480976      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/3480976.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Linux设备模型之input子系统详解.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Linux设备模型之input子系统详解.docx

1、Linux设备模型之input子系统详解Linux设备模型之input子系统详解一:前言 在键盘驱动代码分析的笔记中,接触到了input子系统。键盘驱动,键盘驱动将检测到的所有按键都上报给了input子系统。Input子系统是所有I/O设备驱动的中间层,为上层提供了一个统一的界面。例如,在终端系统中,我们不需要去管有多少个键盘,多少个鼠标。它只要从input子系统中去取对应的事件(按键,鼠标移位等)就可以了。今天就对input子系统做一个详尽的分析。 下面的代码是基于linux kernel 2.6.25.分析的代码主要位于kernel2.6.25/drivers/input下面。 二:使用i

2、nput子系统的例子 在内核自带的文档Documentation/input/input-programming.txt中。有一个使用input子系统的例子,并附带相应的说明。以此为例分析如下: #include #include #include #include #include static void button_interrupt(int irq, void *dummy, struct pt_regs *fp) input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1); input_sync(&button_dev); s

3、tatic int _init button_init(void) if (request_irq(BUTTON_IRQ, button_interrupt, 0, button, NULL) printk(KERN_ERR button.c: Cant allocate irq %dn, button_irq); return -EBUSY; button_dev.evbit0 = BIT(EV_KEY); button_dev.keybitLONG(BTN_0) = BIT(BTN_0); input_register_device(&button_dev); static void _e

4、xit button_exit(void) input_unregister_device(&button_dev); free_irq(BUTTON_IRQ, button_interrupt); module_init(button_init); module_exit(button_exit); 这个示例module代码还是比较简单,在初始化函数里注册了一个中断处理例程。然后注册了一个input device.在中断处理程序里,将接收到的按键上报给input子系统。 文档的作者在之后的分析里又对这个module作了优化。主要是在注册中断处理的时序上。在修改过后的代码里,为input de

5、vice定义了open函数,在open的时候再去注册中断处理例程。具体的信息请自行参考这篇文档。在资料缺乏的情况下,kernel自带的文档就是剖析kernel相关知识的最好资料。 文档的作者还分析了几个api函数。列举如下: 1):set_bit(EV_KEY, button_dev.evbit); set_bit(BTN_0, button_dev.keybit); 分别用来设置设备所产生的事件以及上报的按键值。Struct iput_dev中有两个成员,一个是evbit.一个是keybit.分别用表示设备所支持的动作和按键类型。 2): input_register_device(&but

6、ton_dev); 用来注册一个input device. 3): input_report_key() 用于给上层上报一个按键动作 4): input_sync() 用来告诉上层,本次的事件已经完成了。 5): NBITS(x) - returns the length of a bitfield array in longs for x bits LONG(x) - returns the index in the array in longs for bit x BIT(x) - returns the index in a long for bit x 这几个宏在input子系统中经常

7、用到。上面的英文解释已经很清楚了。 三:input设备注册分析。 Input设备注册的接口为:input_register_device()。代码如下: int input_register_device(struct input_dev *dev) static atomic_t input_no = ATOMIC_INIT(0); struct input_handler *handler; const char *path; int error; _set_bit(EV_SYN, dev-evbit); /* * If delay and period are pre-set by th

8、e driver, then autorepeating * is handled by the driver itself and we dont do it in input.c. */ init_timer(&dev-timer); if (!dev-repREP_DELAY & !dev-repREP_PERIOD) dev-timer.data = (long) dev; dev-timer.function = input_repeat_key; dev-repREP_DELAY = 250; dev-repREP_PERIOD = 33; 在前面的分析中曾分析过。Input_de

9、vice的evbit表示该设备所支持的事件。在这里将其EV_SYN置位,即所有设备都支持这个事件。如果dev-repREP_DELAY和dev-repREP_PERIOD没有设值,则将其赋默认值。这主要是处理重复按键的。 if (!dev-getkeycode) dev-getkeycode = input_default_getkeycode; if (!dev-setkeycode) dev-setkeycode = input_default_setkeycode; snprintf(dev-dev.bus_id, sizeof(dev-dev.bus_id), input%ld, (u

10、nsigned long) atomic_inc_return(&input_no) - 1); error = device_add(&dev-dev); if (error) return error; path = kobject_get_path(&dev-dev.kobj, GFP_KERNEL); printk(KERN_INFO input: %s as %sn, dev-name ? dev-name : Unspecified device, path ? path : N/A); kfree(path); error = mutex_lock_interruptible(&

11、input_mutex); if (error) device_del(&dev-dev); return error; 如果input device没有定义getkeycode和setkeycode.则将其赋默认值。还记得在键盘驱动中的分析吗?这两个操作函数就可以用来取键的扫描码和设置键的扫描码。然后调用device_add()将input_dev中封装的device注册到sysfs list_add_tail(&dev-node, &input_dev_list); list_for_each_entry(handler, &input_handler_list, node) input_

12、attach_handler(dev, handler); input_wakeup_procfs_readers(); mutex_unlock(&input_mutex); return 0; 这里就是重点了。将input device 挂到input_dev_list链表上。然后,对每一个挂在input_handler_list的handler调用input_attach_handler()。在这里的情况有好比设备模型中的device和driver的匹配。所有的input device都挂在input_dev_list链上。所有的handle都挂在input_handler_list上。

13、 看一下这个匹配的详细过程。匹配是在input_attach_handler()中完成的。代码如下: static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) const struct input_device_id *id; int error; if (handler-blacklist & input_match_device(handler-blacklist, dev) return -ENODEV; id = input_match_device(handler-id_

14、table, dev); if (!id) return -ENODEV; error = handler-connect(handler, dev, id); if (error & error != -ENODEV) printk(KERN_ERR input: failed to attach handler %s to device %s, error: %dn, handler-name, kobject_name(&dev-dev.kobj), error); return error; 如果handle的blacklist被赋值。要先匹配blacklist中的数据跟dev-id的

15、数据是否匹配。匹配成功过后再来匹配handle-id和dev-id中的数据。如果匹配成功,则调用handler-connect()。 来看一下具体的数据匹配过程,这是在input_match_device()中完成的。代码如下: static const struct input_device_id *input_match_device(const struct input_device_id *id, struct input_dev *dev) int i; for (; id-flags | id-driver_info; id+) if (id-flags & INPUT_DEVIC

16、E_ID_MATCH_BUS) if (id-bustype != dev-id.bustype) continue; if (id-flags & INPUT_DEVICE_ID_MATCH_VENDOR) if (id-vendor != dev-id.vendor) continue; if (id-flags & INPUT_DEVICE_ID_MATCH_PRODUCT) if (id-product != dev-id.product) continue; if (id-flags & INPUT_DEVICE_ID_MATCH_VERSION) if (id-version !=

17、 dev-id.version) continue; MATCH_BIT(evbit, EV_MAX); MATCH_BIT(, KEY_MAX); MATCH_BIT(relbit, REL_MAX); MATCH_BIT(absbit, ABS_MAX); MATCH_BIT(mscbit, MSC_MAX); MATCH_BIT(ledbit, LED_MAX); MATCH_BIT(sndbit, SND_MAX); MATCH_BIT(ffbit, FF_MAX); MATCH_BIT(swbit, SW_MAX); return id; return NULL; MATCH_BIT

18、宏的定义如下: #define MATCH_BIT(bit, max) for (i = 0; i biti & dev-biti) != id-biti) break; if (i != BITS_TO_LONGS(max) continue;由此看到。在id-flags中定义了要匹配的项。定义INPUT_DEVICE_ID_MATCH_BUS。则是要比较input device和input handler的总线类型。INPUT_DEVICE_ID_MATCH_VENDOR,INPUT_DEVICE_ID_MATCH_PRODUCT,INPUT_DEVICE_ID_MATCH_VERSION

19、分别要求设备厂商。设备号和设备版本。 如果id-flags定义的类型匹配成功。或者是id-flags没有定义,就会进入到MATCH_BIT的匹配项了。从MATCH_BIT宏的定义可以看出。只有当iput device和input handler的id成员在evbit, keybit, swbit项相同才会匹配成功。而且匹配的顺序是从evbit, keybit到swbit.只要有一项不同,就会循环到id中的下一项进行比较。 简而言之,注册input device的过程就是为input device设置默认值,并将其挂以input_dev_list.与挂载在input_handler_list中的

20、handler相匹配。如果匹配成功,就会调用handler的connect函数。 四:handler注册分析 Handler注册的接口如下所示: int input_register_handler(struct input_handler *handler) struct input_dev *dev; int retval; retval = mutex_lock_interruptible(&input_mutex); if (retval) return retval; INIT_LIST_HEAD(&handler-h_list); if (handler-fops != NULL)

21、 if (input_tablehandler-minor 5) retval = -EBUSY; goto out; input_tablehandler-minor 5 = handler; list_add_tail(&handler-node, &input_handler_list); list_for_each_entry(dev, &input_dev_list, node) input_attach_handler(dev, handler); input_wakeup_procfs_readers(); out: mutex_unlock(&input_mutex); ret

22、urn retval; handler-minor表示对应input设备节点的次设备号。以handler-minor右移五位做为索引值插入到input_table 中之后再来分析input_talbe 的作用。 然后将handler挂到input_handler_list中。然后将其与挂在input_dev_list中的input device匹配。这个过程和input device的注册有相似的地方。都是注册到各自的链表,.然后与另外一条链表的对象相匹配。 五:handle的注册 int input_register_handle(struct input_handle *handle) s

23、truct input_handler *handler = handle-handler; struct input_dev *dev = handle-dev; int error; /* * We take dev-mutex here to prevent race with * input_release_device()。 */ error = mutex_lock_interruptible(&dev-mutex); if (error) return error; list_add_tail_rcu(&handle-d_node, &dev-h_list); mutex_unl

24、ock(&dev-mutex); synchronize_rcu(); /* * Since we are supposed to be called from -connect() * which is mutually exclusive with -disconnect() * we cant be racing with input_unregister_handle() * and so separate lock is not needed here. */ list_add_tail(&handle-h_node, &handler-h_list); if (handler-st

25、art) handler-start(handle); return 0; 在这个函数里所做的处理其实很简单。将handle挂到所对应input device的h_list链表上。还将handle挂到对应的handler的hlist链表上。如果handler定义了start函数,将调用之。 到这里,我们已经看到了input device, handler和handle是怎么关联起来的了。以图的方式总结如下: 六:event事件的处理 我们在开篇的时候曾以linux kernel文档中自带的代码作分析。提出了几个事件上报的API.这些API其实都是input_event()的封装。代码如下: v

26、oid input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) unsigned long flags; /判断设备是否支持这类事件 if (is_event_supported(type, dev-evbit, EV_MAX) spin_lock_irqsave(&dev-event_lock, flags); /利用键盘输入来调整随机数产生器 add_input_randomness(type, code, value); input_handle_event(dev, type

27、, code, value); spin_unlock_irqrestore(&dev-event_lock, flags); 首先,先判断设备产生的这个事件是否合法。如果合法,流程转入到input_handle_event()中。 代码如下: static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) int disposition = INPUT_IGNORE_EVENT; switch (type) case EV_SYN: switch (c

28、ode) case SYN_CONFIG: disposition = INPUT_PASS_TO_ALL; break; case SYN_REPORT: if (!dev-sync) dev-sync = 1; disposition = INPUT_PASS_TO_HANDLERS; break; break; case EV_KEY: /判断按键值是否被支持 if (is_event_supported(code, dev-keybit, KEY_MAX) & !test_bit(code, dev-key) != value) if (value != 2) _change_bit(

29、code, dev-key); if (value) input_start_autorepeat(dev, code); disposition = INPUT_PASS_TO_HANDLERS; break; case EV_SW: if (is_event_supported(code, dev-swbit, SW_MAX) & !test_bit(code, dev-sw) != value) _change_bit(code, dev-sw); disposition = INPUT_PASS_TO_HANDLERS; break; case EV_ABS: if (is_event

30、_supported(code, dev-absbit, ABS_MAX) value = input_defuzz_abs_event(value, dev-abscode, dev-absfuzzcode); if (dev-abscode != value) dev-abscode = value; disposition = INPUT_PASS_TO_HANDLERS; break; case EV_REL: if (is_event_supported(code, dev-relbit, REL_MAX) & value) disposition = INPUT_PASS_TO_HANDLERS; break; case EV_MSC: if (is_event_supported(co

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1