/*输入子系统分析 input.c*//*1. 为什么需要输入子系统? 由于我们平时用的输入设备比较杂乱,比较多。 比如: 鼠标,键盘, 触摸屏等。当我们写驱动的时候都需要注册字符设备文件或者混杂设备文件。所以出现了一种机制。这种机制就是把各种输入设备定义为input_device。 把处理这种设备的函数定义为input_handler。这个样以来,程序员只需要操作input_device,而input_handler则是已经为各种设备做好的处理函数了。这样的好处是对所有的设备进行一个统一和抽象处理。形成一个统一的接口。方便驱动的编写等。这种机制就是输入子系统。*//*分析: drivers/input/input.c*/static int __init input_init(void)
{int err;/*注册input类*/err = class_register(&input_class);if (err) {pr_err("unable to register input_dev class\n");return err;}err = input_proc_init();if (err)goto fail1;/*注册字符设备。主设备号13。 file_operations定义为input_fops*/err = register_chrdev(INPUT_MAJOR, "input", &input_fops);if (err) {pr_err("unable to register char major %d", INPUT_MAJOR);goto fail2;}return 0;
}/*而input_fops中只有一个open函数, 那如何read, write设备呢?*/
static const struct file_operations input_fops = {.owner = THIS_MODULE,.open = input_open_file,
};/*先进入open函数看看,都干了什么? */
static int input_open_file(struct inode *inode, struct file *file)
{struct input_handler *handler;const struct file_operations *old_fops, *new_fops = NULL;/*从input_table中根据次设备号找到handler, 获得handler中的fops, 赋值给new_fops*/handler = input_table[iminor(inode) >> 5];if (handler)new_fops = fops_get(handler->fops);/*将new_fops给file->f_op*/old_fops = file->f_op;file->f_op = new_fops;/*调用new_fops中的open函数。 也就是说input_open_file只是一个中转的过程。到头来还是调用设备注册时的fops中的open函数*/err = new_fops->open(inode, file);if (err) {fops_put(file->f_op);file->f_op = fops_get(old_fops);}
}/* 有一个问题? 那input_table是从那里赋值的?发现input_table是从 input_register_handle中得到的 */
int input_register_handler(struct input_handler *handler)
{struct input_dev *dev;int retval;INIT_LIST_HEAD(&handler->h_list);/*将传进来的hanler放入input_table中*/input_table[handler->minor >> 5] = handler;/*放入input_handler_list链表*/list_add_tail(&handler->node, &input_handler_list);/*遍历input_dev_list链表, 对于每个Input_dev结构, 调用input_attach_handler根据input_handler的id_table判断是否支持input_dev*/list_for_each_entry(dev, &input_dev_list, node)input_attach_handler(dev, handler);return retval;
}static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
{const struct input_device_id *id;int error;/*根据input_handler中的id_table判断是否支持input_dev。 如果支持则调用input_handler中的connect函数*/id = input_match_device(handler, dev);if (!id)return -ENODEV;error = handler->connect(handler, dev, id);return error;
}/*还有一个问题?那是谁调用input_register_handler函数的?*//*搜索工程,发现是各式各样的输入设备。 比如键盘, 鼠标, 游戏句柄等。 也就是说当调用input_register_handler函数时, 参数handler就是处理这类设备的操作集合。
*//*那么问题来了? 当我想实现一个按键操作LED灯的驱动程序时, 我应该如何实现? */int input_register_device(struct input_dev *dev)
{/*将input_dev放入input_dev_list链表中*/list_add_tail(&dev->node, &input_dev_list);/*遍历input_handler_list链表,对于每个input_handler结构,调用input_attach_handler看是否匹配。如果匹配则调用input_handler中的connect函数建立"连接"*/list_for_each_entry(handler, &input_handler_list, node)input_attach_handler(dev, handler);
}/*
那么, 如何建立连接?
*/      /*分析: evdev.c 一个特殊的handler例子*/
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
{//1. 分配一个evdev结构   evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//2. 初始化evdev->handle中的dev//   初始化evdev->handle中的hanler。 这样以来,input_handle就成handler与dev之间连接的桥梁了。evdev->handle.dev = input_get_device(dev);evdev->handle.name = dev_name(&evdev->dev);evdev->handle.handler = handler;evdev->handle.private = evdev;}//3. 注册input_handle
int input_register_handle(struct input_handle *handle)
{//input_handler->h_list = input_handle//input_dev->h_list = input_handlelist_add_tail_rcu(&handle->d_node, &dev->h_list);list_add_tail_rcu(&handle->h_node, &handler->h_list);
}/*
小结:当注册Input_dev时,会去input_handler的链表中, 从前到后,依次的根据input_handler中的id_table判断是否支持这个刚注册的input_dev。如果支持,则调用input_handler中的connect函数来建立连接。 所谓的建立连接,也就是建立一个input_handle结构。 这样的话handle中的dev指向input_devhandle中的handler指向Input_handler。 然后将input_handle放入input_dev的handle链表中,input_handle放如input_dev的链表中。当需要操作input_dev支持的Input_handler时, 就会去input_dev的handle链表中找到input_handle,然后同过input_handle中的handler找到input_handler。同理: 当注册input_handler时,会去input_dev的链表中, (省略, 和上面的操作几乎一样)
*//*那还有几个问题? 当应用程序read时, 我们的驱动程序应该干些什么?*///我们上面分析了,new_fops是从input_register_handler传进来的handler中的fops。 行,我们假设我们用的evdev这个事件处理handler/*分析evdev_read函数 */
static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{//如果循环缓冲区的头等于循环缓冲区的尾部,或者是不阻塞的。 则立刻返回if (client->packet_head == client->tail && evdev->exist &&(file->f_flags & O_NONBLOCK))return -EAGAIN;/*不过不是上述的情况,则立马休眠*/retval = wait_event_interruptible(evdev->wait,client->packet_head != client->tail || !evdev->exist);
}/*很明显,当read的时候,没有数据就立马休眠, 那当有数据时, 谁来唤醒呢? *//*毫无疑问,当数据来时,硬件先知道的。 当数据到达时, 就会触发中断。*/void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{//当事件发生时, 则调用input_event上报事件,则会调用input_handler中的event函数list_for_each_entry(handle, &dev->h_list, d_node)if (handle->open)handle->handler->event(handle, type, code, value);
}/*
总结:如何写一个符合输入子系统的驱动程序?
1. 分配一个input_dev结构
2. 设置input_dev
3. 注册input_dev
4. 硬件相关的代码,一般都在中断子程序中上报事件。
*/

Linxu 输入子系统分析相关推荐

  1. 7.Linux 输入子系统分析

    为什么要引入输入子系统? 在前面我们写了一些简单的字符设备的驱动程序,我们是怎么样打开一个设备并操作的呢? 一般都是在执行应用程序时,open一个特定的设备文件,如:/dev/buttons 1 .. ...

  2. linux input输入子系统分析《三》:S3C2440的触摸屏驱动实例

    1.1    本节阅读前提 本节的说明建立在前两节的基础之上,需要先阅读如下两篇章: linux input输入子系统分析<一>:初识input输入子系统 linux input输入子系统 ...

  3. [arm 驱动]Linux输入子系统分析

    首先说明一下,本文是基于Linux-2.6.38版本内核来分析Linux输入子系统架构和原理的.这阵子本来没有打算花时间来分析Linux input system的,然而当在研究S3C6410触摸屏驱 ...

  4. 12.Linux之输入子系统分析(详解)

    在此节之前,我们学的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥/非阻塞.定时器去抖动. 其中驱动框架如下: 1)写file_op ...

  5. linux input输入子系统分析《四》:input子系统整体流程全面分析

    1      input输入子系统整体流程 本节分析input子系统在内核中的实现,包括输入子系统(Input Core),事件处理层(Event Handler)和设备驱动层.由于上节代码讲解了设备 ...

  6. linux input输入子系统分析《一》:初识input输入子系统

    主要讲述本人在学习Linux内核input子系统的全部过程,如有分析不当,多谢指正.以下交流方式,文章欢迎转载,保留联系信息,以便交流. 邮箱:eabi010@gmail.com 主页:www.iel ...

  7. linux input输入子系统分析《二》:s3c2440的ADC简单驱动实例分析

    1      mini2440的ADC驱动实例 这节与输入子系统无关,出现在这里是因为后面的章节会讲到触摸屏输入子系统驱动,由于触摸屏也使用ADC,因此本节是为了说明ADC通过驱动代码是如何控制的. ...

  8. Linux输入子系统框架

    输入子系统 自己写的驱动程序,自己可以调用,我们自己写驱动的流程一般是,建立fops结构,使用register_chrdev在初始化函数中进行注册,在应用中使用open函数打开该设备.这种驱动不标准只 ...

  9. 4. Linux - 输入子系统框架详解

    输入子系统概述 Linux内核为了能够处理各种不同类型的输入设备,比如 触摸屏 ,鼠标 , 键盘 , 操纵杆 ,设计并实现了为驱动层程序的实现提供统一接口函数:为上层应用提供试图统一的抽象层 , 即是 ...

  10. 31.驱动--输入子系统

    linux input输入子系统分析<一>:初识input输入子系统_比特人生的专栏-CSDN博客_linux 输入子系统 linux input输入子系统分析<四>:inpu ...

最新文章

  1. 桌子上有个盘子_日本留学生活:留学生在餐厅刷盘子的传闻,竟然在自己身上上演...
  2. VMware 如何通过现有虚拟机克隆新的虚拟机
  3. bps、Bps、pps
  4. 3月13日 抽奖活动
  5. 11.3finally块控制的读取文件释放
  6. svn增量打包部署_持续集成、持续交付、持续部署(CI/CD)简介
  7. 剑网三虽然是游戏,但场面堪比电影大片,发布会会带来什么惊喜?
  8. 使用 jQuery UI Widget Factory 编写有状态的插件(Stateful Plugins)
  9. 【算法分析与设计】海盗分硬币问题
  10. labview周立功can通讯程序.rar_使用Labview进行CAN 通讯之dbc解析
  11. bzoj5017 [Snoi2017]炸弹
  12. 常用工具及插件下载, [复制链接]
  13. 51-nod(1443)(最短路)
  14. 初中生学计算机应用有什么好方面,计算机有哪些专业 初中毕业学习相关专业有发展吗...
  15. 餐饮管理系统开发源码
  16. 实战演习(九)——用python分析科比生涯数据
  17. 使用AT命令和GPRS无线模块开发(软件)
  18. PS_cs5快捷键大
  19. deploy 在私有仓库部署包 aven-metadata.xml 出现空文档报错 解决方案
  20. SQL链接EXCEL文件

热门文章

  1. 2.3线性表的链式表示和实现(静态链表)
  2. 计算字符串长度(英文占1个字符,中文汉字占2个字符)
  3. 关于前端程序员写前端用什么框架更好?
  4. Java 输出通过 InetAddress 获得的 IP 地址数组
  5. poj 1113 graham模板(水平序)
  6. 数据网格组件 Handsontable 不再开源,采用自拟的非商业许可证
  7. 使用宝塔控制面板建站时出现网页出现404错误怎么办?
  8. 1 0 .2 用于监视的工具和技术
  9. windows server 2003产生的 Minidmp蓝屏文件分析求助
  10. 用eclipse调用远程webservice生成客户端代码