一、input输入子系统总体框架

Linux输入子系统将输入驱动抽象为三层:设备驱动层、核心层、事件处理层。

设备驱动层:将底层的硬件输入事件转化为统一事件形式,向输入核心(Input Core)汇报。

核心层:承上启下。为驱动提供设备和驱动注册等操作的函数接口。

事件处理层:和用户层交互,提供设备的read和write等函数。

二、输入子系统的分层分析

2.1 设备驱动层(用户编写)

从输入子系统的结构框图,我们可以看出设备驱动层和硬件联系得很紧密。因为硬件的多样性,导致设备驱动层要适应这种多样性,因此设备驱动层是易于变化的部分。编写输入子系统驱动的主要工作就在设备驱动层。input子系统的设备驱动层为了向上屏蔽硬件设备的差异,将硬件产生的事件统一用struct input_event来表示。

struct input_event{

struct timeval time;//事件发生的时间

unsigned short type;//事件的类型

unsigned short code;//事件的代码

unsigned int value; //事件的值

}

设备驱动程序的数据结构

struct input_dev {

const char *name;//设备名

const char *phys;

const char *uniq;

struct input_id id;//用于匹配事件处理层handler

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];//用于记录支持的事件类型的位图

unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];//记录支持的按键值的位图

unsigned long relbit[BITS_TO_LONGS(REL_CNT)];//记录支持的相对坐标的位图

unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];//记录支持的绝对坐标的位图

unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];

unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];

unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];

unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];

unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

unsigned int keycodemax;//支持的按键值的个数

unsigned int keycodesize;//每个键值的字节数

void *keycode;//存储按键值的数组首地址

int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);

int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);

struct ff_device *ff;

unsigned int repeat_key;//最近一次按键值,用于连击

struct timer_list timer;//自动连击计时器

int sync;//最后一次同步后没有新的事件置1

int abs[ABS_MAX + 1];

int rep[REP_MAX + 1];

unsigned long key[BITS_TO_LONGS(KEY_CNT)];//反映当前按键状态的位图

unsigned long led[BITS_TO_LONGS(LED_CNT)];//反映当前led状态的位图

unsigned long snd[BITS_TO_LONGS(SND_CNT)];//反映当前beep状态的位图

unsigned long sw[BITS_TO_LONGS(SW_CNT)];

int absmax[ABS_MAX + 1];

int absmin[ABS_MAX + 1];

int absfuzz[ABS_MAX + 1];

int absflat[ABS_MAX + 1];

int (*open)(struct input_dev *dev);//打开函数

void (*close)(struct input_dev *dev);//关闭函数

int (*flush)(struct input_dev *dev, struct file *file);//断开连接时冲洗数据

int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);//回调函数,可选

struct input_handle *grab;

spinlock_t event_lock;

struct mutex mutex;

unsigned int users;

int going_away;

struct device dev;

struct list_headh_list;//handle链表,通过它能够访问到和该设备相匹配的input_handler设备处理方法

struct list_headnode;//input_dev链表,通过它能够访问 系统中所有注册的input_dev设备

};

struct input_id {(将在2.3中讲到)

__u16 bustype;/*总线类型*/

__u16 vendor; /*生产商编号*/

__u16 product; /*产品编号*/

__u16 version;/* 版本号 */

};

设备驱动层编写主要内容:

1.为硬件设备分配一个input_dev结构体(使用函数input_allocate_device)

2.设置 input_dev结构体支持的事件

set_bit(EV_KEY, input_dev->evbit)

set_bit(KEY_ENTER, buttons_dev->keybit)(支持按键类型下的KEY_ENTER事件)

3.注册input_dev结构体

调用input_register_device(input_dev)

4.上报事件(一般在中断函数内)

input_event(input_dev ,type, code, value)

input_sync(input_dev)(上报事件结束);

2.2 核心层(内核自带)

核心层它主要的就是起过渡作用,这主要体现在input_open_file中;我们的应用程序使用open函数打开input设备文件,首先调用的就是核心层input.c中的input_open_file函数。通过该设备的次设备号找到与该设备相关联的操作函数。

static int input_open_file(struct inode *inode, struct file *file)

{

struct input_handler *handler;

handler = input_table[iminor(inode) >> 5];//根据设备的次设备号,获取该设备的input_handler

if (!handler || !(new_fops = fops_get(handler->fops))) { //提取handler里面的file_operations

err = -ENODEV;

goto out; }

file->f_op = new_fops; //将设备的fops赋值给它的文件描述符的f_op

err = new_fops->open(inode, file); //调用handler->fops->open实现文件的打开

}

2.3 事件处理层(内核自带)

事件处理层主要是为底层的设备提供读写操作的函数,用于和用户空间进行交互。input子系统使用struct input_handler代表设备的处理方法。

struct input_handler {

void *private;

void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);//当设备驱动层有事件          上报的时将导致该函数被调用

int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);//当调      用input_register_device和input_register_handler的时候将导致该函数被调用

void (*disconnect)(struct input_handle *handle);

void (*start)(struct input_handle *handle);

const struct file_operations *fops;//handler提供的读写等操作函数

int minor;//输入设备的次设备号

const char *name;

const struct input_device_id *id_table;//能和该input_handler匹配的input_dev的设备id

const struct input_device_id *blacklist;//禁止和该input_handler匹配的input_dev的设备id

struct list_head h_list ;//input_handle链表,能够通过它访问到和该input_handler相匹配的input_dev设备

struct list_head node;//input_handler链表,能够访问到系统所有的input_handler

};

当input_device或input_handler注册的时候,如果设备驱动层的input_device和事件处理层的input_handler有相匹配的话,input子系统就新建一个input_handle连联系它们。

structinput_handle {

void *private;

int open;

const char *name;

struct input_dev *dev; //指向input_dev设备

struct input_handler *handler; //指向input_handler设备处理方法

struct list_head d_node; //将该input_handle加入到它关联的input_dev的h_list链表中

struct list_head h_node; //将该input_handle加入到它关联的input_handler的h_list链表中

};

2.4  input子系统工作大致流程

input子系统会维护两个全局链表:   struct input_dev设备链表,struct input_handler设备处理方法链表

input子系统会维护一个全局数组:static struct input_handler *input_table[8];//按次设备号存储设备处理方法

1.设备驱动层

设备驱动层注册时调用input_register_device(),该函数完成如下工作:

首先将该struct input_dev设备加入到input子系统的全局设备链表中去,然后再分别取出struct input_handler链表中的每个设备处理方法,调用input_match_device(handler->id_table, dev)进行设备和设备处理方法的匹配,如果匹配成功那么将新建一个struct input_handle来连接struct input_dev和struct input_handler。

事件处理层:

2.事件处理层

内核其实都自带很多的input_handler设备处理方法,evdev.c,keybroad.c等,它们调用input_register_handler()注册,该函数完成的工作如下:

首先会根据注册的input_handler的次设备号将它放到一个input_table数组中去,当应用程序打开某个input设备节点时,就可以根据它的次设备号在input_table数组中找到它的处理方法。然后将该struct input_handler加入到input子系统的全局设备处理方法链表中去,最后再分别取出struct input_dev链表中的每个设备,调用input_match_device(handler->id_table, dev)进行设备和设备处理方法的匹配,如果匹配成功那么将新建一个struct input_handle来连接struct input_dev和struct input_handler。

3. 应用程序的open操作

当应用程序打开一个input设备节点的时候,会根据设备的次设备号在input_table数组里面选择它对应的input_handler,然后将该input_handler的文件操作函数赋给struct file *file。

4.底层的事件发生时

当硬件状态发生变化时,一般会引起一个中断,在这个中断中通过input_event(dev,type, code, value)向输入核心层上报事件,这将导致事件处理层input_handler的event(handle,type, code, value)将被调用。那么用户层就可以通过调用read/write进行设备读写了。

Linux输入事件类型EV_SW,Linux的input输入子系统:总体框架相关推荐

  1. C# 文本输入限制类型,datagridview单元格输入验证

    1.只能输入double类型 private void textBoxX6_KeyPress(object sender, KeyPressEventArgs e){{//数字0~9所对应的keych ...

  2. C# 文本输入限制类型,datagridview单元格输入验证

    1.只能输入double类型 private void textBoxX6_KeyPress(object sender, KeyPressEventArgs e) { { //数字09所对应的key ...

  3. print('两数之和为 %.1f' %(float(input('输入第一个数字:'))+float(input('输入第二个数字:'))))...

    There seems to be a syntax error in the code you provided. You can use the following code to print t ...

  4. python中输入数字函数_python中如何input输入为数字?

    在python中想要输入的数字,但是可能会出现输入为1,显示为'1',得到的并不是数字字符的情况.要想要input输入为数字,可使用eval()函数或使用int()转换. 方法一:使用eval()函数 ...

  5. linux 识别文件类型,技术|Linux 中 7 个判断文件系统类型的方法

    文件通过文件系统在磁盘及分区上命名.存储.检索以及更新,文件系统是在磁盘上组织文件的方式. 文件系统分为两个部分:用户数据和元数据(文件名.创建时间.修改时间.大小以及目录层次结构中的位置等). 在本 ...

  6. linux 复制指定类型,用Linux命令行实现删除和复制指定类型的文件

    (一)Linux 删除当前目录及子目录中所有某种类型的文件 方法1 : 此方法不能处理目录中带空格的那些. rm -rf `find . -name "*.example"` Li ...

  7. linux 设置媒介类型,CUPS Linux:帮助打印这些媒体类型:MS Excel,MS Word和HTML

    我需要在 Linux CUPS服务器中打印MS Excel,MS Word和HTML文件.当我尝试打印这些媒体类型后发生,这是我发现到现在: >对于MS Excel和MS Word文件: 当我尝 ...

  8. linux find 按类型查找,Linux find查找find命令详解

    玩蛇网推荐图文教程:python 列表 Linux命令有很多,今天要介绍的是常用的基础命令中的find命令.find是Linux系统管理员所喜爱用的必备工具命令之一,它的作用是可以很轻松地找到你想要的 ...

  9. linux查看命令类型,查看linux命令类型

    LINUX 虚拟机克隆与网络配置 虚拟机克隆后,启动之后发现网卡没有启动.发现提示错误信息"Device eth0 does not seem to be present, delaying ...

最新文章

  1. 【Vegas原创】SQL Sever系统表及系统procedure的总结
  2. 第一章:1.2.2系统分类(一)
  3. android classloader的功能和工作模式,Android中ClassLoader和java中ClassLoader有什么关系和不同...
  4. InfluxDB(官方使用说明)
  5. java 集成kafka单机版 适配jdk1.8
  6. 优达学城深度学习之二——矩阵数学和Numpy复习
  7. 内核网络设备的注册与初始化
  8. CoreMotion(加速计)
  9. Linux内核多线程——补充(各种平台下的多线程)
  10. [Linux程序设计][调试][splint]
  11. Activiti教程(一)activiti工作流简介
  12. 三菱a系列motion软体_三菱PLC全系列编程电缆制作方法
  13. ARM Cortex-M3/M4/M7 Hardfault异常分析
  14. 【OpenGrok代码搜索引擎】三、OpenGrok常用命令
  15. 前端base64解密
  16. php爆路径方法总结
  17. HALO:用于MR扫描器中实时头部对准的工具
  18. 潘爱民:计算机程序的演进——我的程序人生三十年
  19. linux怎么滑动命令行窗口_如何在Linux命令行界面愉快进行性能测试
  20. Android中动画类别及优缺点,安卓培训学习:注册广播及其优缺点

热门文章

  1. android 截屏 效率,android 截屏以及对该图进行模糊
  2. C#图片处理类(颜色透明化,图片切割,图片合并,图片旋转等)(转)
  3. PHP 多闪进群 群二维码 获取 验证 进群
  4. vue中$的作用是什么
  5. UML中组合和聚集的区别
  6. Sitecore Aliases
  7. xMate 七轴柔性协作机器人
  8. 华为 LDP回话建立的过程
  9. 正则表达式的介绍和使用
  10. 金融电商推广可行性活动概览