一.input子系统简介
Input 子系统是管理输入的子系统, 和 pinctrl 和 gpio 子系统一样, 都是 Linux 内核针对某一类设备而创建的框架。 input 子系统处理输入事务, 任何输入设备的驱动程序都可以通过 input 输入子系统提供的接口注册到内核, 利用子系统提供的功能来与用户空间交互。
输入设备总类繁杂, 包括按键, 键盘, 触摸屏, 鼠标, 摇杆等, 它们本身是字符设备, 不过内核为了能将这些设备的共性抽象出来, 简化驱动的开发, 建立了一个 Input 子系统。 用户只需要根据内核提供的 input 子系统下提供的 API 函数接口, 完成设备的注册即可。
对于驱动开发者不需要去关心应用层,只需要按照要求上报这些输入事件即可。 input 子系统分为 input 驱动层、 input 核心层、 input 事件处理层,最终给用户空间提供可访问的设备节点,input 子系统框架如:
可见在Linux内核空间,分为驱动层、核心层和事件层。编写驱动程序时只需要关注这三个层,它们的分工如下:
- 驱动层:输入设备的具体驱动程序,向核心层报告输入内容
- 核心层:为驱动层提供输入设备注册和操作接口,通知事件层对输入事件进行处理
- 事件层:和用户空间进行交互
二.input子系统测试命令
cat /proc/bus/input/devices
Bus=0011 Vendor=0001 Product=0001 Version=ab41: 这一行显示了设备的总线类型、供 应商ID、产品ID和固件版本。
Name="ATTranslatedSet 2 keyboard": 这一行显示了设备的名称.
Phys=isa0060/serio0/input0:这一行显示了设备的物理位置。
Sysfs=/devices/platform/i8042/serio0/input/input1:这一行显示了设备在sysfs文件系统中 的路径。
hexdump[选项] [文件]...
hexdump命令对输出信息 进行二进制内容查看,它可以将二进制文件以十六进制和ASCII码的形式进行显示。
三.input子系统重要接口
在编写 input 设备驱动的时候我们需要先申请一个 input_dev 结构体变量,使用input_allocate_device 函数来申请一个 input_dev,此函数原型如下所示:
struct input_dev *input_allocate_device(void)
函数参数和返回值含义如下:
参数:无。
返回值:申请到的 input_dev。
如果要注销的 input 设备的话需要使用 input_free_device函数来释放掉前面申请到的 input_dev,input_free_device 函数原型如下:
void input_free_device(struct input_dev *dev)
函数参数和返回值含义如下:
dev:需要释放的input_dev。
返回值:无。
申请好一个 input_dev 以后就需要初始化这个 input_dev,需要初始化的内容主要为事件类型(evbit)和事件值(keybit)这两种。input_dev 初始化完成以后就需要向 Linux 内核注册 input_dev
了,需要用到 input_register_device 函数,此函数原型如下:
int input_register_device(struct input_dev *dev)
函数参数和返回值含义如下:
dev:要注册的 input_dev 。
返回值:0,input_dev 注册成功;负值,input_dev 注册失败。
同样的,注销 input 驱动的时候也需要使用input_unregister_device 函数来注销掉前面注册的 input_dev,input_unregister_device 函数原型如下:
void input_unregister_device(struct input_dev *dev)
函数参数和返回值含义如下:
dev:要注销的 input_dev 。
返回值:无。
综上所述,input_dev 注册过程如下:
①、使用 input_allocate_device 函数申请一个 input_dev。
②、初始化 input_dev 的事件类型以及事件值。
③、使用 input_register_device 函数向 Linux 系统注册前面初始化好的 input_dev。
④、卸载input驱动的时候需要先使用input_unregister_device函数注销掉注册的input_dev,然后使用 input_free_device 函数释放掉前面申请的 input_dev。
四.编写最简单的设备驱动层代码
#include <linux/input.h>
#include <linux/module.h>
struct input_dev *myinput_dev;
static int myinput_dev_init(void)
{
int ret;
// 分配输入设备结构体
myinput_dev = input_allocate_device();
if (myinput_dev == NULL) {
printk("input_allocate_device error\n");
return -1;
}
// 设置输入设备的名称
myinput_dev->name = "myinput_dev";
// 设置输入设备支持的事件类型
__set_bit(EV_KEY, myinput_dev->evbit); // 设置支持按键事件
__set_bit(KEY_1, myinput_dev->keybit); // 设置支持按键1
// 注册输入设备
ret = input_register_device(myinput_dev);
if (ret < 0) {
printk("input_register_device error\n");
goto error;
}
return 0;
error:
// 注册失败,释放输入设备结构体
input_free_device(myinput_dev);
return ret;
}
static void myinput_dev_exit(void)
{
// 注销输入设备
input_unregister_device(myinput_dev);
}
module_init(myinput_dev_init);
module_exit(myinput_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("topeet");
cat /proc/bus/input/devices