Linux子程序的调用,Linux input 子系统范例和基本函数解析

其返回一个指向input_dev类型的指针,该结构体是一个输入设备结构体,包含了输入设备的相关信息(按键码、设备名、支持的事件)。

input_register_device()

这个函数是输入子系统核心(inputcore)提供的函数。它将input_dev结构体注册到输入子系统核心中(input_dev结构体必须由input_allocate_device()函数来分配的)。

如果函数注册失败,必须调用input_free_device()函数来释放分配的空间。

如果函数注册成功,在卸载函数中应该调用input_unregister_device()函数来注销输入设备结构体。

我们看一下函数原型:

intinput_register_device(structinput_dev*dev)

{

//定义一些函数中将用到的局部变量

staticatomic_tinput_no=ATOMIC_INIT(0);

structinput_handler*handler;

constchar*path;

interror;

//设置input_dev所支持的事件类型,由evbit成员来表示。具体类型在后面归纳。

__set_bit(EV_SYN,dev->evbit);

//初始化timer定时器,用来处理重复点击按键。(去抖)

init_timer(&dev->timer);

//如果rep[REP_DELAY]和[REP_PERIOD]没有设值,则赋默认值。为了去抖。

if(!dev->rep[REP_DELAY]&&!dev->rep[REP_PERIOD]){

dev->timer.data=(long)dev;

dev->timer.function=input_repeat_key;

dev->rep[REP_DELAY]=250;

dev->rep[REP_PERIOD]=33;

}

//检查下列两个函数是否被定义,没有被定义则赋默认值。

if(!dev->getkeycode)

dev->getkeycode=input_default_getkeycode;//得到指定位置键值

if(!dev->setkeycode)

dev->setkeycode=input_default_setkeycode;//设置指定位置键值

//设置input_dev中device的名字为inputN

//将如input0input1input2出现在sysfs文件系统中

dev_set_name(&dev->dev,"input%ld",(unsignedlong)atomic_inc_return(&input_no)-1);

//将input->dev包含的device结构注册到Linux设备模型中。

//并在文件系统中表现出来

error=device_add(&dev->dev);

if(error)

returnerror;

//打印设备的路径并输出调试信息

path=kobject_get_path(&dev->dev.kobj,GFP_KERNEL);

printk(KERN_INFO"input:%sas%s\n",

dev->name?dev->name:

"Unspecifieddevice",path?:"N/A");

kfree(path);

error=mutex_lock_interruptible(&input_mutex);

if(error){

device_del(&dev->dev);

returnerror;

}

//将input_dev加入input_dev_list链表中(这个链表中包含有所有input设备)

list_add_tail(&dev->node,&input_dev_list);

list_for_each_entry(handler,&input_handler_list,node);

//调用input_attatch_handler()函数匹配handler和input_dev。

//这个函数很重要,在后面单独分析。

input_attach_handler(dev,handler);

input_wakeup_procfs_readers();

mutex_unlock(&input_mutex);

return0;

}

给evbit设置的,input_dev所支持的事件类型:

#defineEV_SYN0x00/*表示设备支持所有的事件*/

#defineEV_KEY0x01/*键盘或者按键,表示一个键码*/

#defineEV_REL0x02/*鼠标设备,表示一个相对的光标位置结果*/

#defineEV_ABS0x03/*手写板产生的值,其是一个绝对整数值*/

#defineEV_MSC0x04/*其他类型*/

#defineEV_LED0x11/*LED灯设备*/

#defineEV_SND0x12/*蜂鸣器,输入声音*/

#defineEV_REP0x14/*允许重复按键类型*/

#defineEV_PWR0x16/*电源管理事件*/

input_attatch_handler()

这个函数用来匹配input_dev和handler,匹配成功才进行关联。

函数代码如下

staticintinput_attach_handler(structinput_dev*dev,

structinput_handler*handler)

{

//input_device_id这个结构体表示设备的标识,存储了设备信息。

conststructinput_device_id*id;/*输入设备的指针*/

interror;

//先判断handler的blacklist有无赋值,然后判断是否匹配

//blacklist是一个input_device_id*类型,指向了一个表,表中存放的是该驱动程序应该忽略的设备

if(handler->blacklist&&input_match_device(handler->blacklist,dev))

return-ENODEV;

/***设备和处理函数之间的匹配***/

//匹配handler->id_table指向的列表中的设备和dev->id数据

id=input_match_device(handler->id_table,dev);

if(!id)

return-ENODEV;

//匹配成功则调用handler->connect,连接handler和input_dev

error=handler->connect(handler,dev,id);/*连接设备和处理函数*/

if(error&&error!=-ENODEV)

printk(KERN_ERR

"input:failedtoattachhandler%stodevice%s,"

"error:%d\n",

handler->name,kobject_name(&dev->dev.kobj),error);

returnerror;

}

input_device_id结构体的定义:

structinput_device_id{

kernel_ulong_tflags;/*标志信息*/

__u16bustype;/*总线类型*/

__u16vendor;/*制造商ID*/

__u16product;/*产品ID*/

__u16version;/*版本号*/

...

kernel_ulong_tdriver_info;/*驱动额外的信息*/

};

input_match_device()

这个函数用来将input_dev和handler进行匹配。

handler-》id_table中定义了其支持input_dev设备。

staticconststructinput_device_id*input_match_device(conststruct

input_device_id*id,structinput_dev*dev)

{

inti;

//匹配id和dev->id中的信息

for(;id->flags||id->driver_info;id++){

if(id->flags&INPUT_DEVICE_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!=dev->id.version)//匹配版本号

continue;

MATCH_BIT(evbit,EV_MAX);

MATCH_BIT(keybit,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;

}

在上面,只有flags中的信息匹配成功,或者flags没有定义才会调用下面。

#defineMATCH_BIT(bit,max)\

for(i=0;i< BITS_TO_LONGS(max); i++) \

if((id->bit[i]&dev->bit[i])!=id->bit[i])\

break;\

if(i!=BITS_TO_LONGS(max))\

continue;

从宏定义中可以看到,

只有当inputdevice和inputhandler的ID成员在evbit、keybit、…swbit项相同才会匹配成功。而且匹配的顺序是从evbit、keybit到swbit。只要有一项不同,就会循环到ID中的下一项进行比较。

总结

在input的分配和注册中,我们分析了四个函数。

1.input_allocate_device在内存中为输入设备结构体分配空间并进行初始化。

2.input_register_device()-》input_attach_handler()-》input_match_device()

input_register_device

将input_dev结构体注册到输入子系统核心中。主要操作是初始化input_dev并将其device_add进Linux设备驱动模型中(在文件系统中创建inputN等文件);打印其路径;调用input_attach_handler匹配handler和input_dev。

input_attach_handler

匹配handler和input_dev。主要操作是,判断dev在不在devices的黑名单中,不在就调用input_match_device进行匹配,成功就调用handler-》connect连接设备和处理函数。

input_match_device

真正的将input_dev和handler进行匹配。主要操作是匹配id和dev-》id中的信息。包括bustype、vendor、product、version等;再匹配evbit事件类型、keybit按键类型等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值