本文转载自: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调用到,这个启动逻辑,后续有机会去学习一下,

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

  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. }

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

可以看下注册方法函数:

  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:

  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 链表:

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

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

  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:

  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 的结构:

  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:

  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 原型:

  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 :

  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 中定义:

  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 的处理机制~

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

  1. Linux/Android——input系统之 kernel层 与 frameworks层交互 (五)【转】

    本文转载自:http://blog.csdn.net/jscese/article/details/42291149 之前的四篇博文记录的都是linux中的input体系相关的东西,最底层以我调试的u ...

  2. Linux/Android——Input系统之InputMapper 处理 (八)【转】

    本文转载自:http://blog.csdn.net/jscese/article/details/43561773 前文Linux/Android——Input系统之InputReader (七)介 ...

  3. Linux/Android——Input系统之InputReader (七)【转】

    本文转载自:http://blog.csdn.net/jscese/article/details/42739197 在前文Linux/Android——Input系统之frameworks层Inpu ...

  4. Linux/Android——Input系统之frameworks层InputManagerService (六)【转】

    本文转载自:http://blog.csdn.net/u013491946/article/details/72638954 版权声明:免责声明: 本人在此发文(包括但不限于汉字.拼音.拉丁字母)均为 ...

  5. linux内核input子系统解析【转】

    转自:http://emb.hqyj.com/Column/Column289.htm 时间:2017-01-04作者:华清远见 Android.X windows.qt等众多应用对于linux系统中 ...

  6. linux kernel input 子系统分析

    Linux 内核为了处理各种不同类型的的输入设备 , 比如说鼠标 , 键盘 , 操纵杆 , 触摸屏 , 设计并实现了一个对上层应用统一的试图的抽象层 , 即是Linux 输入子系统 . 输入子系统的层 ...

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

    本文转载自:http://blog.csdn.net/jscese/article/details/42099381 在前文Linux/Android——usb触摸屏驱动 - usbtouchscre ...

  8. linux driver: input子系统

    <韦东山Linux视频第2期_从零写驱动\第13课第1节 输入子系统概念介绍_P.wmv> 本视频对输入子系统的结构进行了详细的剖析,通过本视频,可以了解到input核心包括了设备和han ...

  9. ARM Linux 驱动Input子系统之按键驱动测试

    上一篇已经谈过,在现内核的中引入设备树之后对于内核驱动的编写,主要集中在硬件接口的配置上了即xxxx.dts文件的编写. 在自己的开发板上移植按键驱动: 1.根据开发板的原理图 确定按键的硬件接口为: ...

随机推荐

  1. Linux从入门到适应(一):VSCode C++环境配置

    作为在Windows环境下习惯使用Visual Studio IDE的人,对于Linux环境下的Vim编辑使用十分难受,虽然网上很多人说vim非常牛逼和强大,但是我更加习惯于使用VS code的界面, ...

  2. Python学习笔记(1)——Python的概述(Python的环境、变量、数据类型、基本运算)

    Table of Contents 1. Python概述 1.1. Python基础知识 1.2. 运行环境 1.3. Python的格式 1.4. Python的变量. 2. Python的数据类 ...

  3. linux性能优化cpu-01性能指标

    学习性能优化的第一步,一定要了解性能指标. 性能指标是什么? 当我们看到性能指标时一定先想到“高并发”.“响应快”,这个两个指标也对应着性能优化的两个核心指标—— “吞吐率”和“低延迟”. 这两个指标 ...

  4. 安装composer及切换镜像为国内镜像

    一.下载composer php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 下面的 ...

  5. RNNCell使用

    目录 Recap input dim, hidden dim SimpleRNNCell Single layer RNN Cell Multi-Layers RNN RNN Layer Recap ...

  6. add list of symbols in latex

    * add list of symbols -- latex 1. createa new tex file named "toc.tex' with the following conte ...

  7. 集训第六周 数学概念与方法 J题 数论,质因数分解

    Description Tomorrow is contest day, Are you all ready? We have been training for 45 days, and all g ...

  8. 【转】ASP.NET MVC 4 RC的JS/CSS打包压缩功能

    原文链接:http://www.cnblogs.com/shanyou/archive/2012/06/22/2558580.html 打包(Bundling)及压缩(Minification)指的是 ...

  9. Fiddler简介与Web抓包,远程抓包(IE、360、谷歌、火狐)

    Fiddler简介以及web抓包 一.Fiddler简介 简单来说,Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯.网上简介很多,我们不多说. 二 ...

  10. JDK的安装和环境变量配置

    1.安装JDK开发环境 下载网站: http://www.oracle.com/technetwork/java/javase/downloads/index.html 进入后选择Accept Lic ...