一、input输入子系统框架

下 图是input输入子系统框架,输入子系统由输入子系统核心层(input core),驱动层和事件处理层(Event Handler)三部分组成。一个输入事件,比如滑动触摸屏都是通过input driver -> input core -> event handler -> user space 到达用户空间传给应用程序。

event hander事件处理层主要和用户空间交互,接收用户空间下发的file operation操作命令,生成/dev/input/xx设备节点供用户空间进行file operations操作; 

input core层负责管理系统中的input dev设备 和input hander事件处理,并起到承上启下作用,负责输入设备和input handler之间信息传输;

input driver为具体用户设备驱动,输入设备由struct input-dev 结构表示,并由input_register_device和input_unregister_device来注册和卸载;

输入子系统结构方框图如下图:

二、输入事件驱动--->evdev_handler的实现大致分析

Linux
输入子系统已经建立好了几个handler,用来处理几类常见的事件,如鼠标、键盘、摇杆等。其中最为基础的是evdev_handler,它是在
driver/input/evdev.c中实现的。它能够接收任意类型的事件,任意id的设备都可以和它匹配连接,它对应的设备节点为/dev/eventX,次设备号的范围为64~95。

evdev输入事件驱动,为输入子系统提供了一个默认的事件处理方法。其接收来自底层驱动的大多数事件,并使用相应的逻辑对其进行处理。

module_exit(evdev_exit);//初始化evdev_handlerstatic int __init evdev_init(void){

    return input_register_handler(&evdev_handler);}
/**一般事件驱动定义了evdev_handler结构表示自己,
*并尝试去找到与handler中id_table相匹配的输入设备。*/static struct input_handler evdev_handler = {.event               =  evdev_event,    
            
其中有:#define EVDEV_MINOR_BASE 64

.id_table           =  evdev_ids,};

MODULE_DEVICE_TABLE(input, evdev_ids);
static const struct input_device_id evdev_ids[] = {{ .driver_info = 1 },/* Matches all devices */{ },/* Terminating zero entry */};/**不管是事件驱动还是输入设备驱动在初始化时注册自身到全局链表中,并尝试与对应的输入设备驱动或事件驱动连接,*最终的操作都是调用事件驱动的XX_connect(...)完成两者的连接的。*/static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id){struct evdev *evdev;int minor;int error;
for (minor = 0; minor < EVDEV_MINORS; minor++)if (!evdev_table[minor])break;

其中有定义:int open;
char name[16];
wait_queue_head_t wait;
spinlock_t client_lock; /* protects client_list */
struct device dev;

表示evdev_handler所表示的32个设备,这个循环为了找到空的一项



if (minor == EVDEV_MINORS) {    //return -ENFILE;}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);if (!evdev)return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);    //初始化spin_lock_init(&evdev->client_lock);mutex_init(&evdev->mutex);init_waitqueue_head(&evdev->wait);
dev_set_name(&evdev->dev, "event%d", minor);        //event对应节点号,event0/evdev->minor = minor;
evdev->handle.dev = input_get_device(dev);    //挂载到对evdev中handle的初始化,这些初始化的目的是使input_dev和input_handler联系起来。evdev->handle.name = dev_name(&evdev->dev);evdev->handle.handler = handler;evdev->handle.private = evdev;
evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);       //生成设备号evdev->dev.class = &input_class;        //input的class类下evdev->dev.parent = &dev->dev;evdev->dev.release = evdev_free;device_initialize(&evdev->dev);            //设备初始化
/*input_register_handle()最终完成了两者的连接,具体实现可研究其实现源码。input_register_handle -登记一个新的 input handle,此功能将一个新的而一旦打开使用input_open_device(),events事件可以随时跟随。*/error = input_register_handle(&evdev->handle);    //error = evdev_install_chrdev(evdev);    //初始化字符设备if (error)goto err_unregister_handle;
error = device_add(&evdev->dev);        //添加一个设备if (error)goto err_cleanup_evdev;
return 0;
err_cleanup_evdev:                           evdev_cleanup(evdev);err_unregister_handle:                           input_unregister_handle(&evdev->handle);err_free_evdev:                           put_device(&evdev->dev);return error;}

对主设备号为INPUT_MAJOR的设备结点进行操作,会将操作集转换成handler的操作集。在evdev_handler中定义了一个fops集合,被赋值为evdev_fops的指针,static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;  //得到了在evdev_table[]中的序号

int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;

if (evdev)
mutex_unlock(&evdev_table_mutex);

其中:
int head;
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct list_head node;

evdev_open_device
(evdev);       //打开输入设备

static int evdev_open_device(struct evdev *evdev)
{
int retval;
retval = mutex_lock_interruptible(&evdev->mutex);
if (retval)
return retval;
if (!evdev->exist)      //判断设备的存在

    retval = -ENODEV;

input_open_device打开evdev对应的handle
        if (retval)
}
return retval;
if (error)
goto err_free_client;

 err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
 err_put_evdev:
put_device(&evdev->dev);
return error;
}


       return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);}
static long evdev_ioctl_handler(struct file *file, unsigned int cmdvoid __user *p, int compat_mode){struct evdev_client *client = file->private_data;struct evdev *evdev = client->evdev;int retval;retval = mutex_lock_interruptible(&evdev->mutex);if (retval)return retval;if (!evdev->exist) {retval = -ENODEV;goto out;}retval = evdev_do_ioctl(file, cmd, p, compat_mode); out:mutex_unlock(&evdev->mutex);return retval;}

 

 

static long evdev_do_ioctl(struct file *file, unsigned int cmd,

                               void __user *p, int compat_mode)

{

         struct evdev_client *client = file->private_data;

         struct evdev *evdev = client->evdev;

         struct input_dev *dev = evdev->handle.dev;

         struct input_absinfo abs;

         struct ff_effect effect;

         int __user *ip = (int __user *)p;

         unsigned int i, t, u, v;

         unsigned int size;

         int error;

 

         /* First we check for fixed-length commands */

         switch (cmd) {

 

         case EVIOCGVERSION:    

 /* 设置重复类事件 */

   %

输入事件驱动---evdev_handler的大致实现流程(修整版)的更多相关文章

  1. Android 输入管理服务-输入事件到达之后的处理流程

    接上一篇博客"Android 输入管理服务启动过程的流程".这两天分析了Android 输入管理服务接收到输入事件之后的处理流程,详细流程例如以下面两图所看到的: 接下图

  2. 面试突击72:输入URL之后会执行什么流程?

    在浏览器中输入 URL 之后,它会执行以下几个流程: 执行 DNS 域名解析: 封装 HTTP 请求数据包: 封装 TCP 请求数据包: 建立 TCP 连接(3 次握手): 参数从客户端传递到服务器端 ...

  3. springboot 大致启动流程

    SpringApplication的run方法的实现是我们本次旅程的主要线路,该方法的主要流程大体可以归纳如下: 1) 如果我们使用的是SpringApplication的静态run方法,那么,这个方 ...

  4. Java-->发牌流程修改版

    --> 这一次要封装得狠一点... package com.xm.ddz; // 每一张牌的属性 public class Card { private String flowerColor; ...

  5. struts2框架的大致处理流程

    1,浏览器发送请求,例如请求 /mypage.action /report/myreport.pdf等. 2,核心控制器FilterDispatcher根据请求决定调用合适的Action. 3,Web ...

  6. tp 大致执行流程

    http://www.thinkphp.cn/code/305.html http://document.thinkphp.cn/manual_3_2.html#wechat

  7. Shiro在Web环境下集成Spring的大致工作流程

    1,Shiro提供了对Web环境的支持,其通过一个 ShiroFilter 入口来拦截需要安全控制的URL,然后进行相应的控制.      ①配置的 ShiroFilter 实现类为:org.spri ...

  8. input输入子系统

    一.什么是input输入子系统? 1.Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等,Linux系统是如何管理如此之多的不同类型.不同原理.不同的输入信 ...

  9. INPUT输入子系统【转】

    转自:https://www.cnblogs.com/deng-tao/p/6094049.html 1.Linux系统支持的输入设备繁多,例如键盘.鼠标.触摸屏.手柄或者是一些输入设备像体感输入等等 ...

随机推荐

  1. JS 数组迭代方法

    var arr = [3,4,5,6,7,"a"]; var isNum = function(elem,index,AAA){return !isNaN(elem);} var ...

  2. CentOS 6.5下Zabbix的安装配置

    1.确保开发环境lamp已经安装 2.下载zabbix 官方下载地址:http://www.zabbix.com/download.php 选择和自己系统对应的版本,这里选择安装与Linux内核为2. ...

  3. CSS中隐藏内容的3种方法及属性值

    CSS中隐藏内容的3种方法及属性值 (2011-02-11 13:33:59)   在制作网页时,隐藏内容也是一种比较常用的手法,它的作用一般有:隐藏文本/图片.隐藏链接.隐藏超出范围的内容.隐藏弹出 ...

  4. redmine computed custom field formula tips

    项目中要用到Computed custom field插件,公式不知道怎么写,查了些资料,记录在这里. 1.http://apidock.com/ruby/Time/strftime 查看ruby的字 ...

  5. 用shell脚本监控进程是否存在 不存在则启动的实例

    用shell脚本监控进程是否存在 不存在则启动的实例,先上代码干货: #!/bin/shps -fe|grep processString |grep -v grepif [ $? -ne 0 ]th ...

  6. 自定义CollectionViewLayout

    转自answer-huang的博客 原文出自:Custom Collection View Layouts    UICollectionView在iOS6中第一次被介绍,也是UIKit视图类中的一颗 ...

  7. sass心得

    1.sass的安装:(1)下载安装Ruby,记得安装的时候勾选第二项,(2)打开控制面板gem install sass(人品好的话,一下子就能安装成功)(3)如果(2)安装不成功进行一下步骤:gem ...

  8. Python 学习随笔1

    在一个列表中,找出重复数组的位置. 比如在列表name = [1, 5, 8, 22, 56, 2, 8, 45, 7, 2, 35, 2, 486, 2, 152, 111, 265, 2, 2]中 ...

  9. 使用cocoaPods和遇到的问题以及解决办法

    上一篇说到cocoaPods的安装,本篇就来说说cocoaPods的使用和遇到一些问题的解决办法( ⊙ o ⊙ ) 一.cocoaPods的创建使用 1.cd进入所在的项目目录 2.创建Podfile ...

  10. 双层路由设置,WAN口和LAN口连接的方法设置

    WAN口设置方法,社路由器分别为路1 和路2 1 路2的LAN口地址改为172.16.1.1,重启 2 笔记本改成172.16.1.X,然后进入设置,在里面WAN地址设置为静态地址 192.168.1 ...