Input子系统详解Word文件下载.docx
- 文档编号:21251310
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:20
- 大小:26.41KB
Input子系统详解Word文件下载.docx
《Input子系统详解Word文件下载.docx》由会员分享,可在线阅读,更多相关《Input子系统详解Word文件下载.docx(20页珍藏版)》请在冰豆网上搜索。
button.c:
Can'
'
tallocateirq%d\n"
button_irq);
return-EBUSY;
}
button_dev.evbit[0]=BIT(EV_KEY);
button_dev.keybit[LONG(BTN_0)]=BIT(BTN_0);
input_register_device(&
staticvoid__exitbutton_exit(void)
input_unregister_device(&
free_irq(BUTTON_IRQ,button_interrupt);
module_init(button_init);
module_exit(button_exit);
这是个最简单使用input子系统的例子,权且引出这input子系统,这个驱动中主要涉及input子系统的函数下面一一列出,后面会有详细的介绍:
1)set_bit(EV_KEY,button_dev.evbit);
set_bit(BTN_0,button_dev.keybit);
分别用来设置设备所产生的事件以及上报的按键值。
Structiput_dev中有两个成员,一个是evbit.一个是keybit,分别用表示设备所支持的动作和按键类型。
2)input_register_device(&
用来注册一个inputdevice.
3)input_report_key()
用于给上层上报一个按键动作
4)input_sync()
用来告诉上层,本次的事件已经完成了.
5)input_unregister_device()
用来注销一个input_dev设备
四.Input子系统探幽
(1)input设备注册分析
Input设备注册的接口为:
input_register_device()。
代码如下:
intinput_register_device(structinput_dev*dev)
staticatomic_tinput_no=ATOMIC_INIT(0);
structinput_handler*handler;
constchar*path;
interror;
__set_bit(EV_SYN,dev->
evbit);
init_timer(&
dev->
timer);
if(!
rep[REP_DELAY]&
&
!
rep[REP_PERIOD]){
timer.data=(long)dev;
timer.function=input_repeat_key;
rep[REP_DELAY]=250;
rep[REP_PERIOD]=33;
在前面的分析中曾分析过。
Input_device的evbit表示该设备所支持的事件。
在这里将其EV_SYN置位,即所有设备都支持这个事件。
如果dev->
rep[REP_DELAY]和dev->
rep[REP_PERIOD]没有设值,则将其赋默认值。
这主要是处理重复按键的。
getkeycode)
getkeycode=input_default_getkeycode;
setkeycode)
setkeycode=input_default_setkeycode;
snprintf(dev->
dev.bus_id,sizeof(dev->
dev.bus_id),
"
input%ld"
(unsignedlong)atomic_inc_return(&
input_no)-1);
error=device_add(&
dev);
if(error)
returnerror;
path=kobject_get_path(&
dev.kobj,GFP_KERNEL);
printk(KERN_INFO"
input:
%sas%s\n"
name?
dev->
name:
"
Unspecifieddevice"
path?
path:
N/A"
);
kfree(path);
error=mutex_lock_interruptible(&
input_mutex);
if(error){
device_del(&
如果inputdevice没有定义getkeycode和setkeycode.则将其赋默认值。
还记得在键盘驱动中的分析吗?
这两个操作函数就可以用来取键的扫描码和设置键的扫描码。
然后调用device_add()将input_dev中封装的device注册到sysfs。
list_add_tail(&
node,&
input_dev_list);
list_for_each_entry(handler,&
input_handler_list,node)
input_attach_handler(dev,handler);
input_wakeup_procfs_readers();
mutex_unlock(&
return0;
这里就是重点了,将inputdevice挂到input_dev_list链表上.然后,对每一个挂在input_handler_list的handler调用input_attach_handler().在这里的情况有好比设备模型中的device和driver的匹配。
所有的inputdevice都挂在input_dev_list链上。
所有的handler都挂在input_handler_list上。
看一下这个匹配的详细过程。
匹配是在input_attach_handler()中完成的。
staticintinput_attach_handler(structinput_dev*dev,structinput_handler*handler)
conststructinput_device_id*id;
if(handler->
blacklist&
input_match_device(handler->
blacklist,dev))
return-ENODEV;
id=input_match_device(handler->
id_table,dev);
id)
error=handler->
connect(handler,dev,id);
if(error&
error!
=-ENODEV)
printk(KERN_ERR
failedtoattachhandler%stodevice%s,"
error:
%d\n"
handler->
name,kobject_name(&
dev.kobj),error);
如果handle的blacklist被赋值。
要先匹配blacklist中的数据跟dev->
id的数据是否匹配。
匹配成功过后再来匹配handle->
id和dev->
id中的数据。
如果匹配成功,则调用handler->
connect()。
来看一下具体的数据匹配过程,这是在input_match_device()中完成的。
staticconststructinput_device_id*input_match_device(conststructinput_device_id*id,
structinput_dev*dev)
inti;
for(;
id->
flags||id->
driver_info;
id++){
if(id->
flags&
INPUT_DEVICE_ID_MATCH_BUS)
bustype!
=dev->
id.bustype)
continue;
INPUT_DEVICE_ID_MATCH_VENDOR)
vendor!
id.vendor)
INPUT_DEVICE_ID_MATCH_PRODUCT)
product!
id.product)
INPUT_DEVICE_ID_MATCH_VERSION)
version!
id.version)
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);
returnid;
returnNULL;
MATCH_BIT宏的定义如下:
#defineMATCH_BIT(bit,max)
for(i=0;
i<
BITS_TO_LONGS(max);
i++)
if((id->
bit[i]&
bit[i])!
=id->
bit[i])
break;
if(i!
=BITS_TO_LONGS(max))
由此看到。
在id->
flags中定义了要匹配的项。
定义INPUT_DEVICE_ID_MATCH_BUS。
则是要比较inputdevice和inputhandler的总线类型。
INPUT_DEVICE_ID_MATCH_VENDOR,INPUT_DEVICE_ID_MATCH_PRODUCT,INPUT_DEVICE_ID_MATCH_VERSION分别要求设备厂商。
设备号和设备版本。
如果id->
flags定义的类型匹配成功。
或者是id->
flags没有定义,就会进入到MATCH_BIT的匹配项了。
从MATCH_BIT宏的定义可以看出。
只有当iputdevice和inputhandler的id成员在evbit,keybit,…swbit项相同才会匹配成功。
而且匹配的顺序是从evbit,keybit到swbit.只要有一项不同,就会循环到id中的下一项进行比较。
简而言之,注册inputdevice的过程就是为inputdevice设置默认值,并将其挂以input_dev_list.与挂载在input_handler_list中的handler相匹配。
如果匹配成功,就会调用handler的connect函数.
(2)handler注册分析
Handler注册的接口如下所示:
intinput_register_handler(structinput_handler*handler)
structinput_dev*dev;
intretval;
retval=mutex_lock_interruptible(&
if(retval)
returnretval;
INIT_LIST_HEAD(&
h_list);
fops!
=NULL){
if(input_table[handler->
minor>
>
5]){
retval=-EBUSY;
gotoout;
input_table[handler->
5]=handler;
input_handler_list);
list_for_each_entry(dev,&
input_dev_list,node)
out:
minor表示对应input设备节点的次设备号.以handler->
minor右移五位做为索引值插入到input_table[]中..之后再来分析input_talbe[]的作用。
然后将handler挂到input_handler_list中.然后将其与挂在input_dev_list中的inputdevice匹配.这个过程和inputdevice的注册有相似的地方.都是注册到各自的链表,然后与另外一条链表的对象相匹配.
(3)handle的注册
intinput_register_handle(structinput_handle*handle)
structinput_handler*handler=handle->
handler;
structinput_dev*dev=handle->
dev;
/*
*Wetakedev->
mutexheretopreventracewith
*input_release_device().
*/
mutex);
list_add_tail_rcu(&
handle->
d_node,&
synchronize_rcu();
h_node,&
start)
start(handle);
在这个函数里所做的处理其实很简单.将handle挂到所对应inputdevice的h_list链表上.还将handle挂到对应的handler的hlist链表上.如果handler定义了start函数,将调用之。
到这里,我们已经看到了inputdevice,handler和handle是怎么关联起来的了。
(4)event事件的处理
我们在开篇的时候曾以linuxkernel文档中自带的代码作分析.提出了几个事件上报的API.这些API其实都是input_event()的封装,代码如下:
voidinput_event(structinput_dev*dev,
unsignedinttype,unsignedintcode,intvalue)
unsignedlongflags;
//判断设备是否支持这类事件
if(is_event_supported(type,dev->
evbit,EV_MAX)){
spin_lock_irqsave(&
event_lock,flags);
//利用键盘输入来调整随机数产生器
add_input_randomness(type,code,value);
input_handle_event(dev,type,code,value);
spin_unlock_irqrestore(&
先判断设备产生的这个事件是否合法.如果合法,流程转入到input_handle_event()中,代码如下:
staticvoidinput_handle_event(structinput_dev*dev,
intdisposition=INPUT_IGNORE_EVENT;
switch(type){
caseEV_SYN:
switch(code){
caseSYN_CONFIG:
disposition=INPUT_PASS_TO_ALL;
caseSYN_REPORT:
sync){
sync=1;
disposition=INPUT_PASS_TO_HANDLERS;
caseEV_KEY:
//判断按键值是否被支持
if(is_event_supported(code,dev->
keybit,KEY_MAX)&
!
test_bit(code,dev->
key)!
=value){
if(value!
=2){
__change_bit(code,dev->
key);
if(value)
input_start_autorepeat(dev,code);
caseEV_SW:
swbit,SW_MAX)&
sw)!
sw);
caseEV_ABS:
absbit,ABS_MAX)){
value=input_defuzz_abs_event(value,
abs[code],dev->
absfuzz[code]);
if(dev->
abs[code]!
abs[code]=value;
caseEV_REL:
relbit,REL_MAX)&
value)
caseEV_MSC:
mscbit,MSC_MAX))
caseEV_LED:
ledbit,LED_MAX)&
led)!
led);
caseEV_SND:
sndbit,SND_MAX)){
snd)!
=!
value)
snd);
caseEV_REP:
if(code<
=REP_MAX&
value>
=0&
rep[code]!
rep[code]=value;
disposition=INPUT_PASS_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Input 子系统 详解
![提示](https://static.bdocx.com/images/bang_tan.gif)