Linux驱动之输入子系统

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux驱动之输入子系统相关的知识,希望对你有一定的参考价值。


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驱动之输入子系统的主要内容,如果未能解决你的问题,请参考以下文章

Linux——Linux驱动之使用输入子系统设计按键驱动实战(输入子系统基本概念代码获取上报信息相关函数解析)

Linux驱动之输入子系统简析

Linux驱动开发之输入子系统

020_linux驱动之_输入子系统按键应用

linux驱动之触摸屏驱动程序

Linux设备驱动之input子系统

(c)2006-2024 SYSTEM All Rights Reserved IT常识