Linux/Android——input_handler之evdev (四)【转】

本文转载自:

在前文Linux/Android——input子系统核心 (三)中概括了总体的结构,以及介绍了input核心的职责,其中有说道注册input设备时会去匹配已有的事件处理器handler,

而这个handler也是存放在一个链表里面的,这里介绍下input子系统中的事件处理input_handler机制.

撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42238377#t6

evdev:

/kernel/drivers/input下众多事件处理器handler其中的一个,可以看下源码/kernel/drivers/input/evdev.c中的模块init:

[objc] view plain copy

  1. static int __init evdev_init(void)
  2. {
  3. return input_register_handler(&evdev_handler);
  4. }

这个初始化就是往input核心中注册一个input_handler类型的evdev_handler,调用的是input.c提供的接口,input_handler结构前文有介绍,看下evdev_handler的赋值:

[objc] view plain copy

  1. static struct input_handler evdev_handler = {
  2. .event      = evdev_event,
  3. .connect    = evdev_connect,
  4. .disconnect = evdev_disconnect,
  5. .fops       = &evdev_fops,
  6. .minor      = EVDEV_MINOR_BASE,
  7. .name       = "evdev",
  8. .id_table   = evdev_ids,
  9. };

赋值各个函数指针!

input_register_handler:

可以看到上面的evdev handler 就是调用这个接口注册到input核心中的,同样evdev.c同目录下也还有其它的handler,有兴趣可以看看它们的init函数,都是会调用到这个接口去注册的.

[objc] view plain copy

  1. /**
  2. * input_register_handler - register a new input handler
  3. * @handler: handler to be registered
  4. *
  5. * This function registers a new input handler (interface) for input
  6. * devices in the system and attaches it to all input devices that
  7. * are compatible with the handler.
  8. */
  9. int input_register_handler(struct input_handler *handler)
  10. {
  11. struct input_dev *dev;
  12. int retval;
  13. retval = mutex_lock_interruptible(&input_mutex);
  14. if (retval)
  15. return retval;
  16. INIT_LIST_HEAD(&handler->h_list);
  17. if (handler->fops != NULL) {
  18. if (input_table[handler->minor >> 5]) {
  19. retval = -EBUSY;
  20. goto out;
  21. }
  22. input_table[handler->minor >> 5] = handler; //给input.c定义的全局handler 数组赋值,evdev handler的次设备号为64,这里除以32,赋值在input_table[2]
  23. }
  24. list_add_tail(&handler->node, &input_handler_list);  //添加进handler 链表
  25. list_for_each_entry(dev, &input_dev_list, node)   //同样遍历input_dev这个链表,依次调用下面的input_attach_handler去匹配input_dev,这个跟input_dev注册的时候的情形类似
  26. input_attach_handler(dev, handler);
  27. input_wakeup_procfs_readers();
  28. out:
  29. mutex_unlock(&input_mutex);
  30. return retval;
  31. }

input核心中保存的handler数组:

[objc] view plain copy

  1. static struct input_handler *input_table[8];

这是保存注册到input核心中的handler数组,因为在之前input注册的时候注册的字符设备主设备号为13.字符设备的次设备号为0~255,可以有256个设备,

这里后面会看到一个handler可以connect处理32个input设备,所以input体系中,最多拥有8个handler

这个匹配过程和上一篇中的过程是一样的,最后匹配上的话会调用匹配上的handler 中connect指针指向的函数.

另外可以注意的是evdev是匹配所有设备的,因为:

[objc] view plain copy

  1. static const struct input_device_id evdev_ids[] = {
  2. { .driver_info = 1 },   /* Matches all devices */
  3. { },            /* Terminating zero entry */
  4. };

如果没有特定的handler添加进handler链表,那么在匹配的时候,只要有这个evdev的handler,最后都会匹配到evdev,这个具体可以去看看上篇的匹配过程.

我这边调试的是usb触摸屏,所以用的是evdev的handler,下面看下evdev的connect.

evdev_connect:

注册的evdev_handler中connect指向的函数为evdev_connect:

[objc] view plain copy

  1. /*
  2. * Create new evdev device. Note that input core serializes calls
  3. * to connect and disconnect so we don‘t need to lock evdev_table here.
  4. */
  5. static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
  6. const struct input_device_id *id)
  7. {
  8. struct evdev *evdev;
  9. int minor;
  10. int error;
  11. for (minor = 0; minor < EVDEV_MINORS; minor++)
  12. if (!evdev_table[minor])
  13. break;
  14. if (minor == EVDEV_MINORS) {
  15. pr_err("no more free evdev devices\n");
  16. return -ENFILE;
  17. }
  18. // 可以看到这里evdev handler匹配连接好的设备都以evdev 类型存在这个evdev_table数组的,这个数组大小为32个,这就是我上面说到的,为什么只有8个handler
  19. //这里是判断evdev的32个位置中是否有空
  20. evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); //为上面定义的*evdev分配内存空间
  21. if (!evdev)
  22. return -ENOMEM;
  23. INIT_LIST_HEAD(&evdev->client_list); //以下都是对这个 evdev的初始化了
  24. spin_lock_init(&evdev->client_lock);
  25. mutex_init(&evdev->mutex);
  26. init_waitqueue_head(&evdev->wait);
  27. dev_set_name(&evdev->dev, "event%d", minor);  //给这个evdev命名
  28. evdev->exist = true;
  29. evdev->minor = minor;   // 以minor为索引赋值
  30. evdev->handle.dev = input_get_device(dev);  //evdev中的handle变量的初始化 ,后面分析这个handle ,这里面保存的就是已经匹配成功的input_dev 和 handler
  31. evdev->handle.name = dev_name(&evdev->dev);
  32. evdev->handle.handler = handler;
  33. evdev->handle.private = evdev;
  34. evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
  35. evdev->dev.class = &input_class;
  36. evdev->dev.parent = &dev->dev;
  37. evdev->dev.release = evdev_free;
  38. device_initialize(&evdev->dev);
  39. error = input_register_handle(&evdev->handle); //把这个evdev中初始化好的handle 注册到input核心中去,代表一个匹配成功的组合
  40. if (error)
  41. goto err_free_evdev;
  42. error = evdev_install_chrdev(evdev);  //把这个初始化好的evdev添加到上面说到过的evdev_table数组,以minor索引序号
  43. if (error)
  44. goto err_unregister_handle;
  45. error = device_add(&evdev->dev); //把这个device 添加到/sys/class/input/下面,所以我们可以看到/dev/input下面看到:event0~31 字样字符设备文件,这就是在上面命名的
  46. if (error)
  47. goto err_cleanup_evdev;
  48. return 0;
  49. err_cleanup_evdev:
  50. evdev_cleanup(evdev);
  51. err_unregister_handle:
  52. input_unregister_handle(&evdev->handle);
  53. err_free_evdev:
  54. put_device(&evdev->dev);
  55. return error;
  56. }

evdev:

这里的evdev变量的结构如下:

[objc] view plain copy

  1. struct evdev
  2. {
  3. int open; //打开标志
  4. int minor; //次设备号
  5. struct input_handle handle; //包含的handle
  6. wait_queue_head_t wait; //等待队列
  7. struct evdev_client __rcu *grab; //强制绑定的evdev_client结构
  8. struct list_head client_list; //evdev_client 链表,这说明一个evdev设备可以处理多个evdev_client,可以有多个进程访问evdev设备
  9. spinlock_t client_lock; /* protects client_list */
  10. struct mutex mutex;
  11. struct device dev;
  12. bool exist;
  13. };

关于这个结构变量我的理解是抽象出来一个设备,代表一个input_dev与其匹配好的handler的组合(handle),可以看作提供给事件处理层的一个封装.

input_handle:

这个代表一个匹配成功的input dev和 handler组合,定义在input.h中,每个evdev中包含一个input_handle,并且注册到input核心中:

[objc] view plain copy

  1. /**
  2. * struct input_handle - links input device with an input handler
  3. * @private: handler-specific data
  4. * @open: counter showing whether the handle is ‘open‘, i.e. should deliver
  5. *    events from its device
  6. * @name: name given to the handle by handler that created it
  7. * @dev: input device the handle is attached to
  8. * @handler: handler that works with the device through this handle
  9. * @d_node: used to put the handle on device‘s list of attached handles
  10. * @h_node: used to put the handle on handler‘s list of handles from which
  11. *    it gets events
  12. */
  13. struct input_handle {
  14. voidvoid *private;  //指向上面封装的evdev
  15. int open;
  16. const charchar *name;
  17. struct input_dev *dev;   //input 设备
  18. struct input_handler *handler;  // 一个input的handler
  19. struct list_head    d_node;  //链表结构
  20. struct list_head    h_node;
  21. };

input_register_handle:

看看这个handle的注册,不要和handler搞混淆了,这不是一个概念~

[objc] view plain copy

  1. /**
  2. * input_register_handle - register a new input handle
  3. * @handle: handle to register
  4. *
  5. * This function puts a new input handle onto device‘s
  6. * and handler‘s lists so that events can flow through
  7. * it once it is opened using input_open_device().
  8. *
  9. * This function is supposed to be called from handler‘s
  10. * connect() method.
  11. */
  12. int input_register_handle(struct input_handle *handle)
  13. {
  14. struct input_handler *handler = handle->handler;
  15. struct input_dev *dev = handle->dev;  //取出两个成员
  16. ...
  17. /*
  18. * Filters go to the head of the list, normal handlers
  19. * to the tail.
  20. */
  21. if (handler->filter)
  22. list_add_rcu(&handle->d_node, &dev->h_list);
  23. else
  24. list_add_tail_rcu(&handle->d_node, &dev->h_list);
  25. //把这个handle的d_node 加到对应input_dev的h_list链表里面
  26. ...
  27. list_add_tail_rcu(&handle->h_node, &handler->h_list);
  28. //把这个handle的h_node 加到对应input_handler的h_list链表里面
  29. ...
  30. }

这个注册是把handle 本身的链表加入到它自己的input_dev 以及 input_handler的h_list链表中,这样以后就可以通过h_list遍历到这个handle,

这样就实现了三者的绑定联系.

另外在evdev中还有个结构:

[objc] view plain copy

  1. struct evdev_client {
  2. unsigned int head;  //buffer数组的索引头
  3. unsigned int tail;   //buffer数组的索引尾
  4. unsigned int packet_head; /* [future] position of the first element of next packet */
  5. spinlock_t buffer_lock; /* protects access to buffer, head and tail */
  6. struct wake_lock wake_lock;
  7. bool use_wake_lock;
  8. char name[28];
  9. struct fasync_struct *fasync;    //异步通知函数
  10. struct evdev *evdev;  //包含一个evdev变量
  11. struct list_head node;  //链表
  12. unsigned int bufsize;
  13. struct input_event buffer[];   //input_event数据结构的数组,input_event代表一个事件,基本成员:类型(type),编码(code),值(value)
  14. };

这个结构会在evdev被打开的时候 创建,这里关于evdev的初始以及在input系统中承接作用暂时介绍到这里,

前文 Linux/Android——输入子系统input_event传递 (二)中有记录从设备驱动传递上来的event是怎么到input核心,然后接着往上传递的,接下来就是用到evdev传递了.下篇介绍.

时间: 2024-12-14 04:58:06

Linux/Android——input_handler之evdev (四)【转】的相关文章

Linux/Android——input_handler之evdev

在前文Linux/Android--input子系统核心中概括了总体的结构,以及介绍了input核心的职责,其中有说道注册input设备时会去匹配已有的事件处理器handler, 而这个handler也是存放在一个链表里面的,这里介绍下input子系统中的事件处理input_handler机制. 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42238377#t6 evdev: /kernel/drivers/input下众多事

ubuntu下搭建android开发环境(四)核心篇安装AndroidStudio、sdk、jdk(by 星空武哥)

转载请标注原创地址:http://blog.csdn.net/lsyz0021/article/details/52215996 所有的软件均在ubuntu 14.04 LTS下测试 ubuntu下搭建android开发环境(一)安装ubuntu系统 ubuntu下搭建android开发环境(二)设置ubuntu的root管理员密码 ubuntu下搭建android开发环境(三)ubuntu安装搜狗输入法 ubuntu下搭建android开发环境(四)核心篇安装AndroidStudio.sdk

Android bluetooth介绍(四): a2dp connect流程分析

关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_get_properties.AUDIO.DBUS版本:基于android4.2之前版本 bluez内核:linux/linux3.08系统:android/android4.1.3.4作者:xubin341719(欢迎转载,请注明作者,请尊重版权谢谢)欢迎指正错误,共同学习.共同进步!! Andr

Linux/Android——Input系统之InputReader (七)

在前文Linux/Android--Input系统之frameworks层InputManagerService (六)  这里介绍了android层input服务的启动,其中启动了一个读取来自底层event事件的线程. 而在Linux/Android--input系统之 kernel层 与 frameworks层交互 (五)有分析到是通过一个event%d的设备文件交互的,也就是说android层是通过读取event%d来获取event的,这个工作就是InputReader 撰写不易,转载需注

Linux/Android——input子系统核心

之前的博客有涉及到linux的input子系统,这里学习记录一下input模块. input子系统,作为管理输入设备与系统进行交互的中枢,任何的输入设备驱动都要通过input向内核注册其设备, 常用的输入设备也就是鼠标,键盘,触摸屏. 稍微细分一点整个输入体系,就是 硬件驱动层,input核心中转层,事件处理层.层次之间传递都以event事件的形式,这其中input连接上下层,分别提供接口. 之前有分析usbtouchscreen的驱动,也就是硬件驱动部分,这里简单记录一下input核心中转处理

热烈庆祝华清远见2014嵌入式系统(Linux&amp;Android)开发就业培训课程全面升级

近日,华清远见公开宣布:2014嵌入式系统 (Linux&Android)开发就业培训课程再次升级!据悉,华清远见如今已经持续10年,一直保持课程每年2次的更新的频率.华清远见的每 次课程更新都能够带给行业一些新的思路和方向,这次也不例外.通过知情人,我们了解到华清远见此次针对嵌入式培训和Anrdoid培训两个方向均有重大变 革. 首先,华清远见嵌入式系统 (Linux&Android)开发就业培训课程升级后主课程中全面采用自主研发的Cortex-A9 四核ARM硬件平台.这也是目前在嵌入

Linux/Android——input子系统核心 (三)【转】

本文转载自:http://blog.csdn.net/jscese/article/details/42123673 之前的博客有涉及到linux的input子系统,这里学习记录一下input模块. input子系统,作为管理输入设备与系统进行交互的中枢,任何的输入设备驱动都要通过input向内核注册其设备, 常用的输入设备也就是鼠标,键盘,触摸屏. 稍微细分一点整个输入体系,就是 硬件驱动层,input核心中转层,事件处理层.层次之间传递都以event事件的形式,这其中input连接上下层,分

【转载】小结一下linux 2.6内核的四种IO调度算法

在LINUX 2.6中,有四种关于IO的调度算法,下面综合小结一下: 1) NOOP NOOP算法的全写为No Operation.该算法实现了最最简单的FIFO队列,所有IO请求大致按照先来后到的顺序进行操作.之所以说“大致”,原因是NOOP在FIFO的基础上还做了相邻IO请求的合并,并不是完完全全按照先进先出的规则满足IO请求.NOOP假定I/O请求由驱动程序或者设备做了优化或者重排了顺序(就像一个智能控制器完成的工作那样).在有些SAN环境下,这个选择可能是最好选择.Noop 对于 IO

Android——数据存储(四种方式之一)SharedPrefereces

Android--数据存储(四种方式) 1.SharedPrefereces   轻量级.XML  存储文件名,数据保存在data/data/basepackage/shared_prefs/myopt.xml中   实例-收藏-记住密码自动登录 //一种轻量级的数据存储方式//通过KEY 存入数据--putxxxx(key,value) 取出数据--getxxxx(key  default)   2.读写SD卡  SD的根目录  适用于数据流读写 3.SQLite  轻量级.dp文件多用于手机