输入子系统event层分析.docx

上传人:b****5 文档编号:11890708 上传时间:2023-04-08 格式:DOCX 页数:14 大小:20.09KB
下载 相关 举报
输入子系统event层分析.docx_第1页
第1页 / 共14页
输入子系统event层分析.docx_第2页
第2页 / 共14页
输入子系统event层分析.docx_第3页
第3页 / 共14页
输入子系统event层分析.docx_第4页
第4页 / 共14页
输入子系统event层分析.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

输入子系统event层分析.docx

《输入子系统event层分析.docx》由会员分享,可在线阅读,更多相关《输入子系统event层分析.docx(14页珍藏版)》请在冰豆网上搜索。

输入子系统event层分析.docx

输入子系统event层分析

输入子系统--event层分析

drivers/input/keyboard/gpio_keys.c:

staticint__devinitgpio_keys_probe(structplatform_device*pdev)

{

structgpio_keys_platform_data*pdata=pdev->dev.platform_data;

structinput_dev*input;

inti,error;input=input_allocate_device();//申请input_dev结构

if(!

input)

return-ENOMEM;platform_set_drvdata(pdev,input);//把input_dev结构放好(以后方便调用)input->evbit[0]=BIT(EV_KEY);//目前event的类型不操作32,所以你会看到对于evbit数组的操作都是对evbit[0]中的位来进行操作.input->name=pdev->name;

input->phys="gpio-keys/input0";

input->dev.parent=&pdev->dev;input->id.bustype=BUS_HOST;

input->id.vendor=0x0001;

input->id.product=0x0001;

input->id.version=0x0100;for(i=0;i<pdata->nbuttons;i++){

structgpio_keys_button*button=&pdata->buttons[i];

intirq=gpio_to_irq(button->gpio);

unsignedinttype=button->type?

:

EV_KEY;set_irq_type(irq,IRQ_TYPE_EDGE_BOTH);/*根据用户所指定的gpio_keys来申请中断和注册中断处理函数*/

error=request_irq(irq,gpio_keys_isr,IRQF_SAMPLE_RANDOM,

button->desc?

button->desc:

"gpio_keys",

pdev);

if(error){

printk(KERN_ERR"gpio-keys:

unabletoclaimirq%d;error%d\n",

irq,error);

gotofail;

}input_set_capability(input,type,button->code);

}error=input_register_device(input);//注册输入设备,并和对应的handler处理函数挂钩

if(error){

printk(KERN_ERR"Unabletoregistergpio-keysinputdevice\n");

gotofail;

}return0;fail:

for(i=i-1;i>=0;i--)

free_irq(gpio_to_irq(pdata->buttons[i].gpio),pdev);input_free_device(input);returnerror;

}提到input_dev结构,以下谈一下我对于它的理解:

structinput_dev{void*private;constchar*name;

constchar*phys;

constchar*uniq;

structinput_idid;/*

*根据各种输入信号的类型来建立类型为unsignedlong的数组,*数组的每1bit代表一种信号类型,*内核中会对其进行置位或清位操作来表示时间的发生和被处理.

*/unsignedlongevbit[NBITS(EV_MAX)];

unsignedlongkeybit[NBITS(KEY_MAX)];

unsignedlongrelbit[NBITS(REL_MAX)];

unsignedlongabsbit[NBITS(ABS_MAX)];

unsignedlongmscbit[NBITS(MSC_MAX)];

unsignedlongledbit[NBITS(LED_MAX)];

unsignedlongsndbit[NBITS(SND_MAX)];

unsignedlongffbit[NBITS(FF_MAX)];

unsignedlongswbit[NBITS(SW_MAX)];.........................................

};/**

*input_set_capability-markdeviceascapableofacertainevent

*@dev:

devicethatiscapableofemittingoracceptingevent

*@type:

typeoftheevent(EV_KEY,EV_REL,etc...)

*@code:

eventcode

*

*Inadditiontosettingupcorrespondingbitinappropriatecapability

*bitmapthefunctionalsoadjustsdev->evbit.

*//*记录本设备对于哪些事件感兴趣(对其进行处理)*/

voidinput_set_capability(structinput_dev*dev,unsignedinttype,unsignedintcode)

{

switch(type){

caseEV_KEY:

__set_bit(code,dev->keybit);//比如按键,应该对哪些键值的按键进行处理(对于其它按键不予理睬)

break;caseEV_REL:

__set_bit(code,dev->relbit);

break;caseEV_ABS:

__set_bit(code,dev->absbit);

break;caseEV_MSC:

__set_bit(code,dev->mscbit);

break;caseEV_SW:

__set_bit(code,dev->swbit);

break;caseEV_LED:

__set_bit(code,dev->ledbit);

break;caseEV_SND:

__set_bit(code,dev->sndbit);

break;caseEV_FF:

__set_bit(code,dev->ffbit);

break;default:

printk(KERN_ERR

"input_set_capability:

unknowntype%u(code%u)\n",

type,code);

dump_stack();

return;

}__set_bit(type,dev->evbit);//感觉和前面重复了(前面一经配置过一次了)

}

EXPORT_SYMBOL(input_set_capability);staticirqreturn_tgpio_keys_isr(intirq,void*dev_id)

{

inti;

structplatform_device*pdev=dev_id;

structgpio_keys_platform_data*pdata=pdev->dev.platform_data;

structinput_dev*input=platform_get_drvdata(pdev);for(i=0;i<pdata->nbuttons;i++){

structgpio_keys_button*button=&pdata->buttons[i];

intgpio=button->gpio;if(irq==gpio_to_irq(gpio)){//判断哪个键被按了?

unsignedinttype=button->type?

:

EV_KEY;

intstate=(gpio_get_value(gpio)?

1:

0)^button->active_low;//记录按键状态input_event(input,type,button->code,!

!

state);//汇报输入事件

input_sync(input);//等待输入事件处理完成

}

}returnIRQ_HANDLED;

}/*

*input_event()-reportnewinputevent

*@dev:

devicethatgeneratedtheevent

*@type:

typeoftheevent

*@code:

eventcode

*@value:

valueoftheevent

*

*Thisfunctionshouldbeusedbydriversimplementingvariousinputdevices

*Seealsoinput_inject_event()

*/

voidinput_event(structinput_dev*dev,unsignedinttype,unsignedintcode,intvalue)

{

structinput_handle*handle;if(type>EV_MAX||!

test_bit(type,dev->evbit))//首先判断该事件类型是否有效且为该设备所接受

return;add_input_randomness(type,code,value);switch(type){caseEV_SYN:

switch(code){

caseSYN_CONFIG:

if(dev->event)

dev->event(dev,type,code,value);

break;caseSYN_REPORT:

if(dev->sync)

return;

dev->sync=1;

break;

}

break;caseEV_KEY:

/*

*这里需要满足几个条件:

*1:

键值有效(不超出定义的键值的有效范围)*2:

键值为设备所能接受(属于该设备所拥有的键值范围)*3:

按键状态改变了

*/if(code>KEY_MAX||!

test_bit(code,dev->keybit)||!

!

test_bit(code,dev->key)==value)

return;if(value==2)

break;change_bit(code,dev->key);//改变对应按键的状态/*如果你希望按键未释放的时候不断汇报按键事件的话需要以下这个(在简单的gpio_keys驱动中不需要这个,暂时不去分析)*/

if(test_bit(EV_REP,dev->evbit)&&

dev->rep[REP_PERIOD]&&dev->rep[REP_DELAY]&&

dev->timer.data&&value){

dev->repeat_key=code;

mod_timer(&dev->timer,jiffies+msecs_to_jiffies(dev->rep[REP_DELAY]));

}break;

........................................................if(type!

=EV_SYN)

dev->sync=0;if(dev->grab)

dev->grab->handler->event(dev->grab,type,code,value);

else

/*

*循环调用所有处理该设备的handle(event,mouse,ts,joy等),*如果有进程打开了这些handle(进行读写),则调用其对应的event接口向气汇报该输入事件.

*/

list_for_each_entry(handle,&dev->h_list,d_node)

if(handle->open)

handle->handler->event(handle,type,code,value);

}

EXPORT_SYMBOL(input_event);#########################################################################

好了,下面再来研究一下event层对于input层报告的这个键盘输入事件是如何来处理的.

#########################################################################drivers/input/evdev.c:

staticstructinput_handlerevdev_handler={

.event=evdev_event,

.connect=evdev_connect,

.disconnect=evdev_disconnect,

.fops=&evdev_fops,

.minor=EVDEV_MINOR_BASE,

.name="evdev",

.id_table=evdev_ids,

};staticvoidevdev_event(structinput_handle*handle,unsignedinttype,unsignedintcode,intvalue)

{

structevdev*evdev=handle->private;

structevdev_client*client;if(evdev->grab){

client=evdev->grab;do_gettimeofday(&client->buffer[client->head].time);

client->buffer[client->head].type=type;

client->buffer[client->head].code=code;

client->buffer[client->head].value=value;

client->head=(client->head+1)&(EVDEV_BUFFER_SIZE-1);kill_fasync(&client->fasync,SIGIO,POLL_IN);

}else

/*遍厉client_list链表中的client结构(代表些打开evdev的进程(个人理解^_^))*/

list_for_each_entry(client,&evdev->client_list,node){

/*填充代表该输入信号的structinput_event结构(事件,类型,键码,键值)*/

do_gettimeofday(&client->buffer[client->head].time);

client->buffer[client->head].type=type;

client->buffer[client->head].code=code;

client->buffer[client->head].value=value;

/*更新写指针*/

client->head=(client->head+1)&(EVDEV_BUFFER_SIZE-1);kill_fasync(&client->fasync,SIGIO,POLL_IN);//通知调用input_sync的进程:

输入事件经已处理完毕(通知底层).

}wake_up_interruptible(&evdev->wait);//唤醒睡眠在evdev->wait等待队列等待输入信息的进程(通知上层).

}###################################################################################

好了,至此一个按键的输入事件处理完毕,现在再来从上到上的来看看用户是如何获取这个输入事件的.

###################################################################################staticconststructfile_operationsevdev_fops={

.owner=THIS_MODULE,

.read=evdev_read,

.write=evdev_write,

.poll=evdev_poll,

.open=evdev_open,

.release=evdev_release,

.unlocked_ioctl=evdev_ioctl,

#ifdefCONFIG_COMPAT

.compat_ioctl=evdev_ioctl_compat,

#endif

.fasync=evdev_fasync,

.flush=evdev_flush

};staticintevdev_open(structinode*inode,structfile*file)

{

structevdev_client*client;

structevdev*evdev;

inti=iminor(inode)-EVDEV_MINOR_BASE;

interror;if(i>=EVDEV_MINORS)

return-ENODEV;evdev=evdev_table[i];if(!

evdev||!

evdev->exist)

return-ENODEV;client=kzalloc(sizeof(structevdev_client),GFP_KERNEL);

if(!

client)

return-ENOMEM;client->evdev=evdev;

/*添加evdev_client结构到链表evdev->client_list中(好让输入事件到来的时候填写该结构并唤醒进程读取)*/

list_add_tail(&client->node,&evdev->client_list);if(!

evdev->open++&&evdev->exist){

error=input_open_device(&evdev->handle);

if(error){

list_del(&client->node);

kfree(client);

returnerror;

}

}file->private_data=client;//存放好evdev_client结构方便以后使用

return0;

}staticssize_tevdev_read(structfile*file,char__user*buffer,size_tcount,loff_t*ppos)

{

structevdev_client*client=file->private_data;

structevdev*evdev=client->evdev;

intretval;if(count<evdev_event_size())//对于每次读取的数据大小是有一定的要求.

return-EINVAL;if(client->head==client->tail&&evdev->exist&&(file->f_flags&O_NONBLOCK))//缓存中没有数据可读且设备是存在的,

如果设置为NONBLOCK方式来读,立即返回.

return-EAGAIN;retval=wait_event_interruptible(evdev->wait,

client->head!

=client->tail||!

evdev->exist);//否则等待缓存有数据可读或设备不存在(被移去)

if(retval)

returnretval;if(!

evdev->exist)

return-ENODEV;while(client->head!

=client->tail&&retval+evdev_event_size()<=count){//下面开始读取数据structinput_event*event=(structinput_event*)client->buffer+client->tail;//获取缓存中的读指针if(evdev_event_to_user(buffer+retval,event))//返回数据给用户

return-EFAULT;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 学科竞赛

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

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