linux驱动之输入子系统

DS小龙哥 DS小龙哥     2022-11-30     462

关键词:


Linux驱动之输入子系统​

1.1 输入子系统简介

1.1.1 概念

在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。

其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。

1.1.2 输入子系统的好处

(1)统一了物理形态各异的相似的输入设备的处理功能。例如,各种鼠标,不论PS/2、USB、还是蓝牙,都被同样处理。

(2)提供了用于分发输入报告给用户应用程序的简单的事件(event)接口。你的驱动不必创建、管理/dev节点以及相关的访问方法。因此它能够很方便的调用输入API以发送鼠标移动、键盘按键,或触摸事件给用户空间。X windows这样的应用程序能够无缝地运行于输入子系统提供的event接口之上。

(3)抽取出了输入驱动的通用部分,简化了驱动,并提供了一致性。例如,输入子系统提供了一个底层驱动(成为serio)的集合,支持对串口和键盘控制器等硬件输入的访问。


1.1.3 输入子系统的接口

/dev/input或者/dev目录下显示的是已经注册在内核中的设备编程接口,用户通过open这些设备文件来打开不同的输入设备进行硬件操作。

输入子系统的接口:/dev/input目录。

[root@XiaoLong /]# ls /dev/input/* -l

crw-rw---- 1 root root 13, 64 May 16 01:44 /dev/input/event0

crw-rw---- 1 root root 13, 65 May 16 01:44 /dev/input/event1

crw-rw---- 1 root root 13, 63 May 16 01:44 /dev/input/mice

crw-rw---- 1 root root 13, 32 May 16 01:44 /dev/input/mouse0

输入子系统由内核代码 drivers/input/input.c 构成,它的存在屏蔽了用户到设备驱动的交互
细节,为设备驱动层和事件处理层提供了相互通信的统一界面。


有的系统的输入子系统的节点在 /dev/目录下:

[root@XiaoLong /]# ls /dev/* -l

crw-rw---- 1 root root 13, 64 May 16 01:44 /dev/event0

crw-rw---- 1 root root 13, 65 May 16 01:44 /dev/event1

crw-rw---- 1 root root 13, 63 May 16 01:44 /dev/mice

crw-rw---- 1 root root 13, 32 May 16 01:44 /dev/mouse0


事件处理层为不同硬件类型提供了用户访问及处理接口。例如当我们打开设备/dev/input/mice时,会调用到事件处理层的Mouse Handler来处理输入事件,这也使得设备驱动层无需关心设备文件的操作,因为Mouse Handler已经有了对应事件处理的方法。

输入子系统由内核代码drivers/input/input.c构成,它的存在屏蔽了用户到设备驱动的交互细节,为设备驱动层和事件处理层提供了相互通信的统一界面。


1.1.4 输入子系统的总体框架

Linux驱动之输入子系统​_输入子系统

图1-1


1.1.5 输入子系统的分层

Linux输入子系统包括三个层次,有上到下别是事件处理层(Event Handler)、核心层(Input Core)和驱动层(Input Driver)。

1.事件处理层:负责与用户程序打交道,将硬件驱动层传来的事件报告给用户程序。

2.核心层:是链接其他两个层之间的纽带与桥梁,向下提供驱动层的接口,向上提供事件处理层的接口。

3.驱动层:负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,键盘、鼠标、触摸屏等字符设备驱动功能的实现工作主要在这层。

在Input子系统三层框架中对应3个结构体。

1.结构体input_dev表示底层硬件设备,是所有输入设备的抽象。

2.handle是手柄的意思,结构体input_handle表示连接杆,连接底层硬件和上层事件处理层。

3.结构体input_handler表示事件处理器,是对事件处理的抽象。

事件处理层代码:

drivers\\Input\\Evdev.c

1.2 输入子系统的核心结构

1.2.1 input_dev结构

在驱动层需要实现struct input_dev结构,实现输入子系统的注册与注销。

在input.h定义了如下结构。

struct input_dev

const char *name; //设备名字--比如:键盘的名字

const char *phys; //设备在系统中的路径。比如:input/key0

const char *uniq; //全球唯一ID号

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


unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //记录支持的事件

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


unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //记录izhic的相对坐标

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 hint_events_per_packet;

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

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

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

int (*setkeycode)(struct input_dev *dev, const struct input_keymap_entry *ke, unsigned int *old_keycode);

int (*getkeycode)(struct input_dev *dev, struct input_keymap_entry *ke);

struct ff_device *ff;

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

struct timer_list timer; //自动连击计时器---选择了重复事件

int rep[REP_CNT];

struct input_mt_slot *mt;

int mtsize;

int slot;

int trkid;


struct input_absinfo *absinfo;


unsigned long key[BITS_TO_LONGS(KEY_CNT)];

unsigned long led[BITS_TO_LONGS(LED_CNT)];

unsigned long snd[BITS_TO_LONGS(SND_CNT)];

unsigned long sw[BITS_TO_LONGS(SW_CNT)];


打开函数---可以自己实现*/

int (*open)(struct input_dev *dev);


/*关闭函数---可以自己实现*/

void (*close)(struct input_dev *dev);


断开连接时,清除数据--可以自己实现*/

int (*flush)(struct input_dev *dev, struct file *file);


/*回调函数-主要是接收用户下发的命令,如点亮led*/

int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);


struct input_handle __rcu *grab;


spinlock_t event_lock;

struct mutex mutex;


unsigned int users;

bool going_away;


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


struct device dev;


struct list_headh_list; //handle链表,用于与input_handler相联系

struct list_headnode; // input_dev链表

/* 设备向输入子系统(input subsystem)注册后,会将该链表添加到系统维护的一个链表中去,从而系统可以管理这个设备*/


1.2.2 input_event事件结构

struct input_event 结构一般在应用层定义使用,用来接收事件层上报的事件。

struct input_event

struct timeval time; //本次上报时间戳

__u16 type; //本次数据的事件类型 (按键事件、相对坐标、绝对坐标)

__u16 code; //具体数值,如果是按键事件,则是键值

__s32 value; //和code相关标志,如果是按键,代表按下还是松开。

;

:事件的类型。(比如:按键事件EV_KEY ,绝对坐标EV_ABS)


:上报的按键值。

如果上报的是EV_KEY事件,code表示按键值。

如果上报的是EV_ABS事件,code表示坐标的类型(X或者Y)。

value :

如果上报的是EV_KEY事件,value就表示状态值。(0或者1或者重复值2)

如果上报的是EV_ABS事件,value就表示具体的坐标值。


1.2.3 时间结构体

struct timeval

__kernel_time_ttv_sec;/*秒 */

__kernel_suseconds_ttv_usec;/* 微秒 */

;


1.3 输入子系统API函数

1.3.1 动态分配input_dev结构体

函数原型

struct input_dev *input_allocate_device(void)

函数功能

该函数为struct input_dev结构体分配内存,并初始化该结构体的部分成员

函数参数

函数返回值

成功:struct input_dev结构体指针,指向分配的结构体 失败:NULL

所在头文件

include/linux/input.h

函数定义文件

drivers/input/input.c


1.3.2 释放input_dev结构体

函数原型

void input_free_device(struct input_dev *dev)

函数功能

释放input_allocate_device函数分配的 input_dev结构体

函数参数

struct input_dev结构体指针

函数返回值

所在头文件

include/linux/input.h

函数定义文件

drivers/input/input.c


1.3.3 注册输入子系统

函数原型

int input_register_device(struct input_dev *dev)

函数功能

该函数用于向输入子系统核心注册输入设备

函数参数

struct input_dev结构体指针

函数返回值

成功:返回0 失败:一个负的错误码

所在头文件

include/linux/input.h

函数定义文件

drivers/input/input.c


1.3.4 注销输入子系统

函数原型

void input_unregister_device(struct input_dev *)

函数功能

该函数用于注销一个输入设备

函数参数

struct input_dev结构体指针,指向要注销的设备对应的输入设备结构体

函数返回值

所在头文件

include/linux/input.h

函数定义文件

drivers/input/input.c


1.3.5 填充input_dev结构体

方法1:使用设置位的函数实现填充input_dev 结构体

static inline void __set_bit(int nr, volatile unsigned long *addr); //设置指定的位

static inline void __clear_bit(int nr, volatile unsigned long *addr); //清除指定的位

参数:

设置的值

设置的地址

示例:

__set_bit(EV_KEY, key_input->evbit); //设置支持按键事件

__set_bit(KEY_1,key_input->keybit); // 设置上报的按键值



方法2:通过input_set_capability函数

函数原型

void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

函数功能

设置输入子系统上报的事件类型和具体的按键值

函数参数

struct input_dev :结构体指针,指向要注销的设备对应的输入设备结构体

unsigned int type :事件类型

unsigned int code :事件类型对应的具体值

函数返回值

所在头文件

include/linux/input.h

函数定义文件

drivers/input/input.c


示例:

input_set_capability(input_dev,EV_KEY,KEY_1); //设置的上报事件类型和具体的值


1.3.6 向应用层上报事件

函数原型linux驱动之rtc子系统

Linux版本:linux3.5​Linux下RTC时间的读写分析​1.1.1系统时间与RTC时间​Linux系统下包含两个时间:系统时间和RTC时间。​系统时间:是由主芯片的定时器进行维护的时间,一般情况下都会选择芯片上最高精度的定时器作为系统时... 查看详情

linux驱动开发19-i2c子系统之客户驱动分析与移植

I2C子系统_设备驱动移植  用户程序通过I2C设备驱动程序访问步骤是这样的... 用户的操作函数---/sys/bus/i2c/devices/....->设备驱动的操作函数---->最终回调i2c-core的函数实现数据的通信。 AT24.C驱动追踪:(Linux内核已经... 查看详情

linux驱动之i2c子系统(代码片段)

目录一、I2C基本原理二、linux内核的I2C子系统详解1、linux内核的I2C驱动框架总览2、I2C子系统的4个关键结构体(kernel/include/linux/i2c.h)3、关键文件4、i2c-core.c初步分析(从后向前看)5、I2C总线的匹配机制(i2c-cor... 查看详情

linux内核驱动之gpio子系统gpio的使用

一 概述  Linux内核中gpio是最简单,最常用的资源(和 interrupt ,dma,timer一样)驱动程序,应用程序都能够通过相应的接口使用gpio,gpio使用0~MAX_INT之间的整数标识,不能使用负数,gpio与硬件体系密切相关的,不过... 查看详情

linux下usb驱动开发之usb光谱仪驱动

30.1USB简介​30.1.1什么是USB?​USB是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,USB就是简写,中文叫通用串行总线。最早出现在1995年... 查看详情

linux驱动开发input子系统(代码片段)

input子系统负责处理输入事件,属于字符设备。input子系统分为input驱动层、input核心层和input事件层。系统启动后,在/sys/class/input/路径下显示input子系统。input驱动层:输入设备的具体驱动程序,如按键驱动,... 查看详情

linux设备驱动之iio子系统——triggeredbuffersupport触发缓冲支持(代码片段)

Triggeredbuffersupport触发缓冲支持  在许多数据分析应用中,能够基于某些外部信号(触发器)捕获数据是比较有用的。这些触发器可能是:数据就绪信号连接到某个外部系统的IRQ线路(GPIO或其他)处理器周期性中断用户空间在s... 查看详情

linux输入设备自定义键盘input输入子系统gpio-keys按键驱动(代码片段)

文章目录前言查看include/uapi/linux/input.h设备树添加makemenuconfig驱动编译ko模块查看驱动运行状态查看/proc/bus/input/devices设备查看dev/input按键测试hexdump应用程序过程中问题及解决方法常见问题按键硬件注意前言设计板需要提供六个按... 查看详情

linux下编写usb驱动实例

1.1Linux下USB驱动开发介绍​USB是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,USB就是简写,中文叫通用串行总线。我们知道总线是用... 查看详情

linux驱动之配置内核

...f0c;裁剪内核就是根据你的硬件资源,将一些不需要的驱动裁剪掉,再把一些原本没有的驱动添加到内核,那么配置好的内核就适用于你特定的硬件平台。配置内核时,makezImage  makemenuconfig&#x 查看详情

linux设备驱动基础01之并发与竞态(代码片段)

...;最终造成内存数据混乱,严重的话会导致系统崩溃。驱动开发中要注意对共享资源的保护,需要管理对共享资源的并发访问。Linux系统产生并发访问的几个主要原因:(1)、多线程并发访问,Linux 查看详情

02_先学习输入系统应用编程(代码片段)

...g.net/weidongshan/linux/doc_and_source_for_drivers.git视频观看百问网驱动大全先学习输入系统应用编程1.百问网Linux视频体系2.建议在《Linux系列教程之快速入门》的《嵌入式Linux应用开发基础知识》的视 查看详情

linux设备驱动之字符设备驱动

一、linux系统将设备分为3类:字符设备、块设备、网络设备。应用程序调用的流程框图:三种设备的定义分别如下,字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后... 查看详情

输入子系统(input)框架解析(基于linux3.4.2)

我们自己写驱动的流程一般是:自己确定或由系统自动分配主设备号;建立fops结构;使用register_chrdev在初始化函数中进行注册;定义入口函数MODULE_INIT()和出口函数MODULE_EXIT()。但这种我们自己写的驱动程序,只有自己可以调用。... 查看详情

linux虚拟pinctrldemo驱动--debugfs之pinctrl分析(代码片段)

1.前言我们在调试Pinctrl子系统时,会使用到DebugFilesystem。在/sys/kernel/debug/目录下就会有pinctrl目录,如果该目录下没有任何目录或文件,说明debugfs功能没有被打开。可以参考这篇博客该功能:《问题一:/sys/kern... 查看详情

linux虚拟pinctrldemo驱动--debugfs之pinctrl分析(代码片段)

1.前言我们在调试Pinctrl子系统时,会使用到DebugFilesystem。在/sys/kernel/debug/目录下就会有pinctrl目录,如果该目录下没有任何目录或文件,说明debugfs功能没有被打开。可以参考这篇博客该功能:《问题一:/sys/kern... 查看详情

linux——linux驱动之imx6ull硬件平台下使用mfgtool工具进行系统烧写的原理及步骤总结(ubootkerneldtbrootfs)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《QT开发实战》《嵌入式通用开发实战》《从0到1学习嵌入式Linux开发》 查看详情

linux——linux驱动之imx6ull硬件平台下使用mfgtool工具进行系统烧写的原理及步骤总结(ubootkerneldtbrootfs)

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《QT开发实战》《嵌入式通用开发实战》《从0到1学习嵌入式Linux开发》 查看详情