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

本文转载自:http://blog.csdn.net/jscese/article/details/42123673

之前的博客有涉及到linux的input子系统,这里学习记录一下input模块.

input子系统,作为管理输入设备与系统进行交互的中枢,任何的输入设备驱动都要通过input向内核注册其设备,

常用的输入设备也就是鼠标,键盘,触摸屏。

稍微细分一点整个输入体系,就是 硬件驱动层input核心中转层事件处理层.层次之间传递都以event事件的形式,这其中input连接上下层,分别提供接口.

之前有分析usbtouchscreen的驱动,也就是硬件驱动部分,这里简单记录一下input核心中转处理 input.c .

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

input_init:

源码位于/kernel/drivers/input/input.c ,模块初始调用口subsys_initcall(input_init),

由kernel启动的时候由kernel_init——>do_basic_setup();——>do_initcalls调用到,这个启动逻辑,后续有机会去学习一下,

这里首先调用到初始函数:

[objc] view plain copy

  1. static int __init input_init(void)
  2. {
  3. int err;
  4. err = class_register(&input_class); //注册input class,可在/sys/class下看到对应节点文件
  5. if (err) {
  6. pr_err("unable to register input_dev class\n");
  7. return err;
  8. }
  9. err = input_proc_init(); //proc fs的下的一些初始操作,函数原型在input.c,可查看/proc/bus/input
  10. if (err)
  11. goto fail1;
  12. err = register_chrdev(INPUT_MAJOR, "input", &input_fops); // 注册input字符设备,主节点为INPUT_MAJOR==13,可以去input_fops里看注册函数,注册到/dev/input
  13. if (err) {
  14. pr_err("unable to register char major %d", INPUT_MAJOR);
  15. goto fail2;
  16. }
  17. return 0;
  18. fail2:    input_proc_exit();
  19. fail1:    class_unregister(&input_class);
  20. return err;
  21. }

这就是最开始的初始化过程了.

可以看下注册方法函数:

[objc] view plain copy

  1. static const struct file_operations input_fops = {
  2. .owner = THIS_MODULE,
  3. .open = input_open_file,
  4. .llseek = noop_llseek,
  5. };

这里面关注open file方法即可,后面分析。

input.c中还有很多其它的接口以及全局数据,后面陆续联通,先从设备驱动最先调用到的注册 input_register_device

input_register_device:

[objc] view plain copy

  1. /**
  2. * input_register_device - register device with input core
  3. * @dev: device to be registered
  4. *
  5. * This function registers device with input core. The device must be
  6. * allocated with input_allocate_device() and all it‘s capabilities
  7. * set up before registering.
  8. * If function fails the device must be freed with input_free_device().
  9. * Once device has been successfully registered it can be unregistered
  10. * with input_unregister_device(); input_free_device() should not be
  11. * called in this case.
  12. */
  13. int input_register_device(struct input_dev *dev)
  14. {
  15. static atomic_t input_no = ATOMIC_INIT(0);
  16. //这个原子变量,代表总共注册的input设备,每注册一个加1,因为是静态变量,所以每次调用都不会清零的
  17. struct input_handler *handler;
  18. const charchar *path;
  19. int error;
  20. __set_bit(EV_SYN, dev->evbit);  //EN_SYN 这个是设备都要支持的事件类型,所以要设置
  21. /*
  22. * If delay and period are pre-set by the driver, then autorepeating
  23. * is handled by the driver itself and we don‘t do it in input.c.
  24. */
  25. // 这个内核定时器是为了重复按键而设置的
  26. init_timer(&dev->timer);
  27. if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
  28. dev->timer.data = (long) dev;
  29. dev->timer.function = input_repeat_key;
  30. dev->rep[REP_DELAY] = 250;
  31. dev->rep[REP_PERIOD] = 33;
  32. //如果没有定义有关重复按键的相关值,就用内核默认的
  33. }
  34. if (!dev->getkeycode)
  35. dev->getkeycode = input_default_getkeycode;
  36. if (!dev->setkeycode)
  37. dev->setkeycode = input_default_setkeycode;
  38. //以上设置的默认函数由input核心提供
  39. dev_set_name(&dev->dev, "input%ld",
  40. (unsigned long) atomic_inc_return(&input_no) - 1);
  41. //设置input_dev中device的名字,这个名字会在/class/input中出现
  42. error = device_add(&dev->dev);
  43. //将device加入到linux设备模型中去
  44. if (error)
  45. return error;
  46. path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
  47. printk(KERN_INFO "input: %s as %s\n",
  48. dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
  49. kfree(path);
  50. //这个得到路径名称,并打印出来
  51. error = mutex_lock_interruptible(&input_mutex);
  52. if (error) {
  53. device_del(&dev->dev);
  54. return error;
  55. }
  56. list_add_tail(&dev->node, &input_dev_list);
  57. // 将新分配的input设备连接到input_dev_list链表上
  58. list_for_each_entry(handler, &input_handler_list, node)
  59. input_attach_handler(dev, handler);
  60. //遍历input_handler_list链表,配对 input_dev 和 input_handler
  61. //input_attach_handler 这个函数是配对的关键,下面将详细分析
  62. input_wakeup_procfs_readers();
  63. // 和proc文件系统有关,暂时不考虑
  64. mutex_unlock(&input_mutex);
  65. return 0;
  66. }

可以看到前面都是一些初始设置,加入到input.c 的全局input_dev 链表里面,同时下面就行匹配对应handler的时候需要遍历 handler 链表:

[objc] view plain copy

  1. static LIST_HEAD(input_dev_list);
  2. static LIST_HEAD(input_handler_list);

可以看到用到了一个list_for_each_entry, 刚开始看到还没看懂,这是一个宏定义,原型是在/kernel/include/linux/list.h:

[objc] view plain copy

  1. /**
  2. * list_for_each_entry    -    iterate over list of given type
  3. * @pos:    the type * to use as a loop cursor.
  4. * @head:    the head for your list.
  5. * @member:    the name of the list_struct within the struct.
  6. */
  7. #define list_for_each_entry(pos, head, member)                \
  8. for (pos = list_entry((head)->next, typeof(*pos), member);    \
  9. &pos->member != (head);     \    //就是个for循环,跳出条件遍历了一遍,又回到链表头
  10. pos = list_entry(pos->member.next, typeof(*pos), member))

input_attach_handler(dev, handler)则是匹配这个要注册dev的handler:

[objc] view plain copy

  1. static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
  2. {
  3. const struct input_device_id *id;
  4. int error;
  5. id = input_match_device(handler, dev); //返回匹配的id,类型是struct input_device_id
  6. if (!id)
  7. return -ENODEV;
  8. error = handler->connect(handler, dev, id); //<span><span class="comment">//配对成功调用handler的connect函数,这个函数在事件处理器中定义,主要生成一个input_handle结构,并初始化,还生成一个事件处理器相关的设备结构</span></span>
  9. if (error && error != -ENODEV)
  10. pr_err("failed to attach handler %s to device %s, error: %d\n",
  11. handler->name, kobject_name(&dev->dev.kobj), error);
  12. return error;
  13. }

可以看下匹配 id 的结构:

[objc] view plain copy

  1. struct input_device_id {
  2. kernel_ulong_t flags;
  3. __u16 bustype;
  4. __u16 vendor;
  5. __u16 product;
  6. __u16 version;
  7. kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
  8. kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
  9. kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
  10. kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
  11. kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
  12. kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
  13. kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
  14. kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
  15. kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
  16. kernel_ulong_t driver_info;
  17. };

有两个函数input_match_device 以及 下面的 connect需要了解:

input_match_device:

[objc] view plain copy

  1. static const struct input_device_id *input_match_device(struct input_handler *handler,
  2. struct input_dev *dev)
  3. {
  4. const struct input_device_id *id;
  5. int i;
  6. for (id = handler->id_table; id->flags || id->driver_info; id++) {
  7. if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)  //匹配总线id
  8. if (id->bustype != dev->id.bustype)
  9. continue;
  10. if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)  //匹配生产商id
  11. if (id->vendor != dev->id.vendor)
  12. continue;
  13. if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) //匹配产品id
  14. if (id->product != dev->id.product)
  15. continue;
  16. if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) //匹配版本
  17. if (id->version != dev->id.version)
  18. continue;
  19. MATCH_BIT(evbit,  EV_MAX);  //匹配id的evbit和input_dev中evbit的各个位,如果不匹配则continue,数组中下一个设备
  20. MATCH_BIT(keybit, KEY_MAX);
  21. MATCH_BIT(relbit, REL_MAX);
  22. MATCH_BIT(absbit, ABS_MAX);
  23. MATCH_BIT(mscbit, MSC_MAX);
  24. MATCH_BIT(ledbit, LED_MAX);
  25. MATCH_BIT(sndbit, SND_MAX);
  26. MATCH_BIT(ffbit,  FF_MAX);
  27. MATCH_BIT(swbit,  SW_MAX);
  28. if (!handler->match || handler->match(handler, dev))
  29. return id;
  30. }
  31. return NULL;
  32. }

MATCH_bit 原型:

[objc] view plain copy

  1. #define MATCH_BIT(bit, max) \
  2. for (i = 0; i < BITS_TO_LONGS(max); i++) \
  3. if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
  4. break; \
  5. if (i != BITS_TO_LONGS(max)) \
  6. continue;

可以看到这么多步的目的除了初始以及添加input_dev到链表,就是为了去匹配 input_handler_list 中对应的handler ,

匹配的最终是需要比对handler以及input_dev中的 id,其中input_dev 中的id类型为 input_id :

[objc] view plain copy

  1. struct input_id {
  2. __u16 bustype;
  3. __u16 vendor;
  4. __u16 product;
  5. __u16 version;
  6. };

这跟上面 input_handler 结构里面的 input_device_id 匹配id 变量,来确认 handler!

在最开始的时候就有提到,整个input输入体系,分三个层次,现在的input核心层做的事就是:

在硬件驱动层调用 input_register_device时 ,往内核注册驱动的同时,根据硬件的相关id去匹配 适用的事件处理层(input_handler)!

这里匹配上之后就会调用对应 input_handler 的connect 函数。

input_handler:

input_dev 变量代表的是硬件设备,前文Linux/Android——输入子系统input_event传递 (二)中有介绍

input_handler 变量代表的是事件处理器

同样在input.h 中定义:

[objc] view plain copy

  1. /**
  2. * struct input_handler - implements one of interfaces for input devices
  3. * @private: driver-specific data
  4. * @event: event handler. This method is being called by input core with
  5. *  interrupts disabled and dev->event_lock spinlock held and so
  6. *  it may not sleep
  7. * @filter: similar to @event; separates normal event handlers from
  8. *  "filters".
  9. * @match: called after comparing device‘s id with handler‘s id_table
  10. *  to perform fine-grained matching between device and handler
  11. * @connect: called when attaching a handler to an input device
  12. * @disconnect: disconnects a handler from input device
  13. * @start: starts handler for given handle. This function is called by
  14. *  input core right after connect() method and also when a process
  15. *  that "grabbed" a device releases it
  16. * @fops: file operations this driver implements
  17. * @minor: beginning of range of 32 minors for devices this driver
  18. *  can provide
  19. * @name: name of the handler, to be shown in /proc/bus/input/handlers
  20. * @id_table: pointer to a table of input_device_ids this driver can
  21. *  handle
  22. * @h_list: list of input handles associated with the handler
  23. * @node: for placing the driver onto input_handler_list
  24. *
  25. * Input handlers attach to input devices and create input handles. There
  26. * are likely several handlers attached to any given input device at the
  27. * same time. All of them will get their copy of input event generated by
  28. * the device.
  29. *
  30. * The very same structure is used to implement input filters. Input core
  31. * allows filters to run first and will not pass event to regular handlers
  32. * if any of the filters indicate that the event should be filtered (by
  33. * returning %true from their filter() method).
  34. *
  35. * Note that input core serializes calls to connect() and disconnect()
  36. * methods.
  37. */
  38. struct input_handler {
  39. voidvoid *private;
  40. void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
  41. bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
  42. bool (*match)(struct input_handler *handler, struct input_dev *dev);
  43. int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);  //上面就是调用这个函数指针
  44. void (*disconnect)(struct input_handle *handle);
  45. void (*start)(struct input_handle *handle);
  46. const struct file_operations *fops;
  47. int minor;
  48. const charchar *name;
  49. const struct input_device_id *id_table; //这个就是上面说到的 会跟input_dev中的input_id 比对 id项的
  50. struct list_head    h_list;
  51. struct list_head    node;
  52. };

这个结构详细的含义,注释有。

这个结构里面暂时只需要理解的:

注册input_dev ,在事件处理数据链表里面匹配上 input_handler ,就会调用其 *connect 函数指针 进行连接,

将input_dev 跟 input_handler 进行绑定, 后续的运作事件的handler处理将会走这个input_handler的 *event !

在上篇input_event 传递中最后调用到event阶段.

这里简单记录到这里,下篇介绍input_handler 的处理机制~

时间: 2024-10-12 20:44:06

Linux/Android——input子系统核心 (三)【转】的相关文章

Linux/Android——input子系统核心

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

Linux/Android——Input系统之InputMapper 处理 (八)

前文Linux/Android--Input系统之InputReader (七)介绍到了inputreader的运作流程,如何获取events到初步的分发,依次分析到InputMapper做第一步的处理. 前文有解析Mapper类型的依赖规则,不做重述.,这里单以触摸屏input_device 对应的SingleTouchInputMapper 为例. 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/43561773本博文来自[

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系统之frameworks层InputManagerService (六)

上一篇Linux/Android--input系统之 kernel层 与 frameworks层交互 (五)中有介绍kernel层一下以及与android这边frameworks层之间的联系,算是打通android 应用层与 kernel驱动层,对整个input系统的学习是至关重要的,其中frameworks层只是简单记录了几个接入点,这里开始分析frameworks层的细节部分. 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/

Linux/Android——输入子系统input_event传递

在前文Linux/Android--usb触摸屏驱动 - usbtouchscreen中记录了如何在kernel中添加input device 类型为touchscreen的驱动, 这在整个输入体系中是最下层的设备驱动部分,往上一层就是linux内核的管理驱动input系统,kernel中的源码位置:/kernel/drivers/input/input.c 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/42099381 到目前

linux kernel input 子系统分析

Linux 内核为了处理各种不同类型的的输入设备 , 比如说鼠标 , 键盘 , 操纵杆 , 触摸屏 , 设计并实现了一个对上层应用统一的试图的抽象层 , 即是Linux 输入子系统 . 输入子系统的层次结构体如下 从底层到上层 , input 子系统由 设备驱动层 , 核心层 , 以及事件处理层3个部分组成 当一个鼠标移动, 一个按键按下或弹起 , 它都需要从底层设备驱动-->核心层-->事件处理层 -->用户空间 , 层层上报 , 一直到运用程序. 应用这个input  子系统有如下优

linux的Input子系统获取Device Name

linux内核提供了一个Input子系统来实现的,Input子系统会在/dev/input/路径下创建我们硬件输入设备的节点,一般情况下在我们的 手机中这些节点是以eventXX来命名的,如event0,event1等等,可以利用EVIOCGNAME获取此事件结点名称.这就是android 中对于input事件处理数据的来源点. --------------- 通过ioctl命令EVIOCGNAME,能获取dev/input/event*对应的Device Name. 实例: openInput

Linux/Android——输入子系统input_event传递 (二)【转】

本文转载自:http://blog.csdn.net/jscese/article/details/42099381 在前文Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)中记录了如何在kernel中添加input device 类型为touchscreen的驱动, 这在整个输入体系中是最下层的设备驱动部分,往上一层就是linux内核的管理驱动input系统,kernel中的源码位置:/kernel/drivers/input/input.c 撰写不易,转

linux driver: input子系统

<韦东山Linux视频第2期_从零写驱动\第13课第1节 输入子系统概念介绍_P.wmv> 本视频对输入子系统的结构进行了详细的剖析,通过本视频,可以了解到input核心包括了设备和handler,设备和handler之间是如何建立联系的,一个输入事件是如何响应的. <韦东山Linux视频第2期_从零写驱动\第13课第2节 输入子系统第编写驱动程序_P.wmv> 本视频主要教授如何在系统的框架下,编写一个输入子系统的驱动.一个输入事件的具体响应函数,注册等.