输入子系统--event层分析_第1页
输入子系统--event层分析_第2页
输入子系统--event层分析_第3页
免费预览已结束,剩余18页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、输入子系统 -event 层分析drivers/input/keyboard/gpio_keys.c:static int _devinit gpio_keys_probe(struct platform_device *pdev)struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;struct input_dev *input;int i, error;input = input_allocate_device();/ 申请input_dev 结构if (!input)return -ENOMEM; p

2、latform_set_drvdata(pdev, input);/ 把 input_dev 结构放好 (以后方便调用 ) input->evbit0 = BIT(EV_KEY);/ 目前 event 的类型不操作 32,所以你会看到对于 evbit 数组的操作都是对 evbit0 中的位 来进行操作 . input->name = pdev->name;input->phys = "gpio-keys/input0" input->dev.parent = &pdev->d

3、ev;input->id.bustype = BUS_HOST; input->id.vendor = 0x0001; input->duct = 0x0001;input->id.version = 0x0100; for (i = 0; i <pdata->nbuttons; i+) struct gpio_keys_button *button =&pdata->buttonsi;int irq = gpio_to_irq(button->gpio)

4、;unsigned int type = 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-ke

5、ys: unable to claimirq %d; error %dn",irq, error);goto fail; input_set_capability(input, type, button->code);error = input_register_device(input);/ 注册输入设备并和对应的 handler 处理函数挂钩if (error) printk(KERN_ERR "Unable to register gpio-keys input devicen");goto fail; return 0; fail:for (

6、i = i - 1; i >= 0; i-)free_irq(gpio_to_irq(pdata->buttonsi.gpio), pdev); input_free_device(input); return error;提到 input_dev 结构 ,以下谈一下我对于它的理解 :struct input_dev void *private; const char *name;const char *phys;const char *uniq;struct input_id id;/* 根据各种输入信号的类型来建立类型为 unsigned long 的数组 ,

7、* 数组的每 1bit 代表一种信号类型 , * 内核中会对其进行置位或清位操作来表示时间的发生和 被处理 .*/ unsigned long evbitNBITS(EV_MAX);unsigned long keybitNBITS(KEY_MAX);unsigned long relbitNBITS(REL_MAX);unsigned long absbitNBITS(ABS_MAX);unsigned long mscbitNBITS(MSC_MAX);unsigned long ledbitNBITS(LED_MAX);unsigned long sndbitNBITS(SND_MAX)

8、; unsigned long ffbitNBITS(FF_MAX);unsigned long swbitNBITS(SW_MAX); ;/* input_set_capability - mark device as capable of a certain event* dev: device that is capable of emitting or accepting event* type: type of the event (EV_KEY , EV_REL, etc.)* code: event code* In addition to setting up correspo

9、nding bit in appropriate capability* bitmap the function also adjusts dev->evbit.*/* 记录本设备对于哪些事件感兴趣 (对其进行处理 )*/ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)switch (type) case EV_KEY:_set_bit(code, dev->keybit);/ 比如按键 , 应该对哪 些键值的按键进行处理 (对于其它按键不予

10、理睬 )break; case EV_REL:_set_bit(code, dev->relbit);break; case EV_ABS:_set_bit(code, dev->absbit);break; case EV_MSC:_set_bit(code, dev->mscbit);break; case EV_SW:_set_bit(code, dev->swbit);break; case EV_LED:_set_bit(code, dev->ledbit);break; case EV_SND:_set_bit(

11、code, dev->sndbit);break; case EV_FF:_set_bit(code, dev->ffbit);break; default:printk(KERN_ERR"input_set_capability: unknown type %u(code %u)n",type, code);dump_stack();return;_set_bit(type, dev->evbit);/ 感觉和前面重复了(前面一经配置过一次了 )EXPORT_SYMBOL(input_set_capability);static

12、irqreturn_t gpio_keys_isr(int irq, void *dev_id)int i;struct platform_device *pdev = dev_id;struct gpio_keys_platform_data *pdata =pdev->dev.platform_data;struct input_dev *input = platform_get_drvdata(pdev);for (i = 0; i < pdata->nbuttons; i+) struct gpio_keys_button *button =&

13、amp;amp;pdata->buttonsi;int gpio = button->gpio;if (irq = gpio_to_irq(gpio) / 判断哪个键被按了 ? unsigned int type = button->type ?: EV_KEY;int state = (gpio_get_value(gpio)1 : 0) A button->activeow; 记录按键状态 input_event(input, type, button->code, !state);/ 汇报输入事 件input_sync

14、(input);/ 等待输入事件处理完成 return IRQ_HANDLED;/* input_event() - report new input event* dev: device that generated the event* type: type of the event* code: event code* value: value of the event* This function should be used by drivers implementing various input devices* See also input_inject_event()*/vo

15、id input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)struct input_handle *handle; if (type > EV_MAX| !test_bit(type, dev->evbit)/ 首先判断该事件类型是否有 效且为该设备所接受return; add_input_randomness(type, code, value); switch (code) case SYN_CONFIG:if (dev->event)

16、dev->event(dev, type, code, value);break; caseSYN_REPORT:if (dev->sync)return;dev->sync = 1;break;break; case EV_KEY:/* 这里需要满足几个条件 :* 1:键值有效 (不超出定义的键值的有效范围 )* 2:键值为设备所能接受 (属于该设备所拥有的键值范围 )* 3: 按键状态改变了*/ if (code > KEY_MAX| !test_bit(code, dev->keybit) | !test_bit(co

17、de, dev->key) = value)dev->key);/ 改变对应按键的状态 /* 如果你 希望按键未释放的时候不断汇报按键事件的话需要以下这 个 (在简单的 gpio_keys 驱动中不需要这个 ,暂时不去分析 ) */if (test_bit(EV_REP, dev->evbit) && dev->repREP_PERIOD && dev->repREP_DELAY && dev->timer.data

18、 && value) dev->repeat_key = code; mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->repREP_DELAY); break; if (type != EV_SYN) dev->sync = 0; if (dev->grab) dev->grab->handler->event(dev->grab, type, code, va

19、lue);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);# # 好了 ,下面再来研究一下 e

20、vent 层对于 input 层报告的这个键 盘输入事件是如何来处理的 .# #drivers/input/evdev.c:static struct input_handler evdev_handler = .event =evdev_event,.connect =evdev_connect,.disconnect =evdev_disconnect,.fops =&evdev_fops,.minor =EVDEV_MINOR_BASE,.name =evdev",.id_table =evdev_ids,;static void evdev_event(str

21、uct input_handle *handle, unsignedint type, unsigned int code, int value)struct evdev *evdev = handle->private;struct evdev_client *client; if(evdev->grab) client = evdev->grab;do_gettimeofday(&client->bufferclient->head.time );client->bufferclient-&

22、amp;gt;head.type = type;client->bufferclient->head.code = code;client->bufferclient->head.value = value;client->head = (client->head + 1)& (EVDEV_BUFFER_SIZE - 1); kill_fasync(&client->fasync, SIGIO, POLL_IN); else/* 遍厉 client_list 链表中

23、的 client 结构(代表些打开evdev的进程(个人理解A_A) */&evdev->client_list, node) /* 填充代表该输入信号的 struct input_event 结构 (事件 ,类型 ,键码 ,键值 ) */do_gettimeofday(&client->bufferclient->head.time );client->bufferclient->head.type = type;client->bufferclient->hea

24、d.code = code;client->bufferclient->head.value = value;/* 更新写指针 */ client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);kill_fasync(&client->fasync, SIGIO, POLL_IN);/ 通知 调用 input_sync 的进程 :输入事件经已处理完毕 ( 通知底层 ). wake_up_interruptible(&e

25、vdev->wait);/ 唤醒睡眠在 evdev->wait 等待队列等待输入信息的进程 (通知上层 ). # #好了 ,至此一个按键的输入事件处理完毕 ,现在再来从上到上 的来看看用户是如何获取这个输入事件的 .# #static const struct file_operations evdev_fops = .owner =THIS_MODULE,.read =evdev_read,.write =evdev_write,.poll =evdev_poll,.open =evdev_open,.release =evdev_release,.unlocke

26、d_ioctlevdev_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl = evdev_ioctl_compat,#endif.fasync =evdev_fasync,.flush =evdev_flush;static int evdev_open(struct inode *inode, struct file *file) struct evdev_client *client;struct evdev *evdev;int i = iminor(inode) - EVDEV_MINOR_BASE;int error;if (i >= E

27、VDEV_MINORS)return -ENODEV;evdev =evdev_tablei;if (!evdev | !evdev->exist)return -ENODEV;client =kzalloc(sizeof(struct evdev_client), GFP_KERNEL);if (!client)return -ENOMEM;client->evdev = evdev;/* 添加 evdev_client 结构到链表 evdev->client_list 中 (好让输入事件到来的时候填写该结构 并唤醒进程读取 ) */list_add

28、_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);return error;file->private_data =

29、client;/ 存放好 evdev_client 结构方便以后使用return 0;static ssize_t evdev_read(struct file *file, char _user *buffer, size_t count, loff_t *ppos)struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev;int retval; if (count <evdev_event_size()对于每次读取的数据大小是有一定的要

30、 求.return -EINV AL;if(client->head = client->tail && evdev->exist && (file->f_flags &O_NONBLOCK)/ 缓存中没有数据可读且设备是存在的 ,如果设置为 NONBLOCK 方式来读 ,立即返回 .return -EAGAIN;retval =wait_event_interruptible(evdev->wait,client->head !=

31、 client->tail| !evdev->exist);/ 否则等待缓存有数据可读或设备不存在(被移去 )if (retval)return retval; return -ENODEV;if (!evdev->exist)while(client->head != client->tail && retval + evdev_event_size() <= count) / 下面开始读取数据 struct input_event *event = (struct input

32、_event *) client->buffer + client->tail;/ 获取缓存中的读指针 if (evdev_event_to_user(buffer + retval, event)/ 返回数据给用 户return -EFAULT;client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);/ 更新读指针 retval += evdev_event_size(); return retval;呵呵,看到了吧,应用程序就是这样获取输入事件的A_A#

33、# #本来对于 gpio_keys 这样的驱动程序 ,只要当发生按键事件的 时候向上层应用程序汇报键值即可 .不过 ,对于一些带输出设 备(例如 led 灯)的输入设备来说 (例如键盘 ),上层应用程序同 样可以利用 event 层来读取或改变其状态 .请看以下代码 : # #static ssize_t evdev_write(struct file *file, const char _user *buffer, size_t count, loff_t *ppos)struct evdev_client *client = file->private_data;struct

34、 evdev *evdev = client->evdev;struct input_event event;int retval = 0;if (!evdev->exist)return -ENODEV;while (retval <count) if (evdev_event_from_user(buffer + retval, &event)/ 从用户处获取事件结构return -EFAULT; input_inject_event(&evdev->handle, event.type, event.

35、code, event.value);/ 往底层发送事件retval += evdev_event_size(); return retval;/* input_inject_event() - send input event from input handler* handle: input handle to send event through* type: type of the event* code: event codevalue: value of the event* Similar to input_event() but will ignore event if dev

36、ice is "grabbed" and handle* injecting event is not the one that owns the device.*/void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)if (!handle->dev->grab | handle->dev->grab = handle) input_event(handle-&g

37、t;dev, type, code, value); EXPORT_SYMBOL(input_inject_event);/* input_event() - report new input event* dev: device that generated the event* type: type of the event* code: event code* value: value of the eventThis function should be used by drivers implementingvarious input devices* See also input_inject_event()*/void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)struct input_handle *handle; if (type > EV

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论