注册一个输入设备. 系统有那些改变?


author: hjjdebug

date: 2026年 05月 26日 星期二 09:20:00 CST

descrip: 注册一个输入设备. 系统有那些改变?


文章目录

  • [1. 查看 /proc 目录的变化](#1. 查看 /proc 目录的变化)
  • [2. 查看 /sys/devices/.../目录](#2. 查看 /sys/devices/.../目录)
    • [2.1 关于设备文件目录下的event14 目录](#2.1 关于设备文件目录下的event14 目录)
  • [3. /dev 下目录变化](#3. /dev 下目录变化)
  • [4. 附录(测试代码)](#4. 附录(测试代码))

测试代码见附录. 代码很短,不足百行.
代码中那些分配内存,赋值等是容易理解的.
关键是下面这个函数,向系统注册, 则系统发生了什么变化?
这是跟系统打交道的函数,
ret = input_register_device(g_in_dev);

向系统注册一个输入设备, 当然系统就多管理了一个输入设备.

系统会通过伪文件系统/sysfs, /proc, 及其它方式把设备信息暴露给用户.

我们下面就来研究一下这些接口,以便更好的了解这个设备,使用这个设备.

实验步骤如下:

把文件编译成.ko文件(input_dev.ko)

然后安装模块,查看信息输出.

$ insmod input_dev.ko

$ dmesg

2512.487674 input_dev demo init

2512.487725 input: test_input_device as /devices/virtual/input/input15

2512.594059 input device register success

1. 查看 /proc 目录的变化

在 /proc/bus/input 目录下,有一个devices 文件, 记录了所有输入设备. 你这里新添加了一个输入设备,

$ cat devices 文件, 就会多出来一项设备记录. 如下:

I: Bus=0019 Vendor=1234 Product=5678 Version=0001

N: Name="test_input_device"

P: Phys=test_input/input0

S: Sysfs=/devices/virtual/input/input15

U: Uniq=

H: Handlers=kbd event14

B: PROP=0

B: EV=3

B: KEY=800

其中ID,name,phys, 就是我们填充的信息. 其它信息在/sysfs 中说明

kbdhandler,代表内核键盘子系统也能收到上报的 KEY 事件

重点看一下sysfs 系统文件目录

2. 查看 /sys/devices/.../目录

sysfs, 说明在/sys/devices/virtual/input/input15/目录下建立了对应的输入设备

设备的属性能够从这里得到.

hjj@hjj-laptop:/sys/devices/virtual/input/input15$ ll

总用量 0

drwxr-xr-x 6 root root 0 5月 26 08:16 ./

drwxr-xr-x 3 root root 0 5月 26 08:16 .../

drwxr-xr-x 2 root root 0 5月 26 08:16 capabilities/

drwxr-xr-x 3 root root 0 5月 26 08:16 event14/

drwxr-xr-x 2 root root 0 5月 26 08:16 id/

-r--r--r-- 1 root root 4096 5月 26 08:36 modalias

-r--r--r-- 1 root root 4096 5月 26 08:16 name

-r--r--r-- 1 root root 4096 5月 26 08:16 phys

drwxr-xr-x 2 root root 0 5月 26 08:36 power/

-r--r--r-- 1 root root 4096 5月 26 08:16 properties

lrwxrwxrwx 1 root root 0 5月 26 08:16 subsystem -> .../.../.../.../class/input/

-rw-r--r-- 1 root root 4096 5月 26 08:16 uevent

-r--r--r-- 1 root root 4096 5月 26 08:36 uniq

hjj@hjj-laptop:/sys/devices/virtual/input/input15$ cat name

test_input_device

hjj@hjj-laptop:/sys/devices/virtual/input/input15$ cat phys

test_input/input0

hjj@hjj-laptop:/sys/devices/virtual/input/input15$ cat properties

0

hjj@hjj-laptop:/sys/devices/virtual/input/input15$ cat uniq

hjj@hjj-laptop:/sys/devices/virtual/input/input15$ cat uevent

PRODUCT=19/1234/5678/1

NAME="test_input_device"

PHYS="test_input/input0"

PROP=0

EV=3

KEY=800

MODALIAS=input:b0019v1234p5678e0001-e0,1,kramlsfw

EV=3 说明

EV 是event bit, 支持的事件类型位图.

__set_bit(EV_KEY, g_in_dev->evbit); 是设置了位图1(bit1,EV_KEY=0x01) 为1

EV_REL = 0x02 (相对坐标,鼠标) 未设置

EV_ABS = 0x03 (绝对坐标,触摸屏),未设置

EV_SYN = 0x00 (同步事件, 默认开启).

所以 EV= EV_SYN(0) + EV_KEY(1) = 3

KEY=800 说明

KEY 是 key bit, 按键码位图集合

代码中

__set_bit(TEST_KEY_CODE, g_in_dev->keybit); //TEST_KEY_CODE(11)

是设置keybit 的第11位

KEY=0x800 就对应着第11位,代表按键0, 就是说它仅支持按键0, 当然,如果你想支持2个按键,

就再加一个,想支持101键盘,就加101个按键.

2.1 关于设备文件目录下的event14 目录

其中14代表的是系统登记的第14个输入事件,在/dev/input 目录下记录了所有输入事件

hjj@hjj-laptop:/sys/devices/virtual/input/input15/event14$ ll

总用量 0

drwxr-xr-x 3 root root 0 5月 26 08:16 ./

drwxr-xr-x 6 root root 0 5月 26 08:16 .../

-r--r--r-- 1 root root 4096 5月 26 09:00 dev

lrwxrwxrwx 1 root root 0 5月 26 08:16 device -> .../.../input15/

drwxr-xr-x 2 root root 0 5月 26 09:00 power/

lrwxrwxrwx 1 root root 0 5月 26 08:16 subsystem -> .../.../.../.../.../class/input/

-rw-r--r-- 1 root root 4096 5月 26 08:16 uevent

hjj@hjj-laptop:/sys/devices/virtual/input/input15/event14$ cat dev

13:78

事件文件uevent

hjj@hjj-laptop:/sys/devices/virtual/input/input15/event14$ cat uevent

MAJOR=13

MINOR=78

DEVNAME=input/event14

3. /dev 下目录变化

在/sysfs 中看到了event14, 在/sys/.../event14 的uevent中也看到input/event14

在/dev/input 下,确实看到了字符设备 event14, 其主设备号13, 子设备号78

hjj@hjj-laptop:/dev/input$ ll

总用量 0

drwxr-xr-x 4 root root 380 5月 26 08:16 ./

drwxr-xr-x 17 root root 3380 5月 26 07:35 .../

drwxr-xr-x 2 root root 120 5月 26 07:35 by-id/

drwxr-xr-x 2 root root 160 5月 26 07:35 by-path/

crw-rw---- 1 root input 13, 64 5月 26 07:35 event0

crw-rw---- 1 root input 13, 65 5月 26 07:35 event1

crw-rw---- 1 root input 13, 74 5月 26 07:35 event10

crw-rw---- 1 root input 13, 75 5月 26 07:35 event11

crw-rw---- 1 root input 13, 76 5月 26 07:35 event12

crw-rw---- 1 root input 13, 77 5月 26 07:35 event13

crw-rw---- 1 root input 13, 78 5月 26 08:16 event14 *************

crw-rw---- 1 root input 13, 66 5月 26 07:35 event2

crw-rw---- 1 root input 13, 67 5月 26 07:35 event3

crw-rw---- 1 root input 13, 68 5月 26 07:35 event4

crw-rw---- 1 root input 13, 69 5月 26 07:35 event5

crw-rw---- 1 root input 13, 70 5月 26 07:35 event6

crw-rw---- 1 root input 13, 71 5月 26 07:35 event7

crw-rw---- 1 root input 13, 72 5月 26 07:35 event8

crw-rw---- 1 root input 13, 73 5月 26 07:35 event9

其中event14 就是我们刚刚及建立的.

这是用户程序访问设备的接口文件

如果你rmmod input_device, 则上面内核暴露的对应的文件目录及文件都会消失

/proc/input/devices 中的项

/sysfs/... 对应的目录

/dev/input/对应的节点

4. 附录(测试代码)

cpp 复制代码
$cat input_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/delay.h>

// 定义按键值(KEY_0 代表数字0按键)
#define TEST_KEY_CODE  KEY_0

// 定义输入设备结构体指针
static struct input_dev *g_in_dev;

/*
 * 模拟按键上报函数(实际硬件中,会在GPIO中断中调用)
 * 这里仅做演示,手动上报按下+松开
 */
static void report_key_event(int pressed)
{
    // 上报按键事件:事件类型EV_KEY,按键码KEY_0,状态(1按下/0松开)
    input_report_key(g_in_dev, TEST_KEY_CODE, pressed);
    
    // 通知系统事件发送完成
    input_sync(g_in_dev);
}

/*
 * 驱动入口函数
 */
static int __init input_dev_demo_init(void)
{
    int ret;

    printk("input_dev demo init\n");

    // 1. 分配输入设备结构体
    g_in_dev = input_allocate_device();
    if (!g_in_dev) {
        printk(KERN_ERR "input_allocate_device failed\n");
        return -ENOMEM;
    }

    // 2. 设置输入设备基本信息
    g_in_dev->name = "test_input_device";  // 设备名称
    g_in_dev->phys = "test_input/input0"; // 设备物理路径
    g_in_dev->id.bustype = BUS_HOST;      // 总线类型,BUS_HOST(0x19)
    g_in_dev->id.vendor  = 0x1234;        // 厂商ID
    g_in_dev->id.product = 0x5678;        // 产品ID
    g_in_dev->id.version = 0x0001;        // 版本号

    // 3. 声明设备支持的事件类型和事件码
    // 支持按键类事件(EV_KEY)
    __set_bit(EV_KEY, g_in_dev->evbit); //EV_KEY(1)
    // 支持KEY_0这个按键
    __set_bit(TEST_KEY_CODE, g_in_dev->keybit); //TEST_KEY_CODE(11)

    // 4. 注册输入设备到内核
    ret = input_register_device(g_in_dev); //注册后发生了什么?
    if (ret) {
        printk(KERN_ERR "input_register_device failed\n");
        // 注册失败,释放已分配的内存
        input_free_device(g_in_dev);
        return ret;
    }

    // 模拟:上报一次按键按下 → 延时 → 按键松开
    report_key_event(1);
    msleep(100);
    report_key_event(0);

    printk("input device register success\n");
    return 0;
}

/*
 * 驱动出口函数
 */
static void __exit input_dev_demo_exit(void)
{
    printk("input_dev demo exit\n");
    
    // 注销输入设备
    input_unregister_device(g_in_dev);
}

module_init(input_dev_demo_init);
module_exit(input_dev_demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("demo");
MODULE_DESCRIPTION("Simple input_dev usage example");
相关推荐
暮云星影11 小时前
全志linux开发屏幕适配(一)屏幕参数设置说明
linux·arm开发
swordbob12 小时前
NIO 的 Channel 里有多个 BIO 吗?
linux·网络·nio
Fcy64812 小时前
Linux下 信号的保存与捕捉
linux·中断·信号的捕捉·信号的保存
A_humble_scholar13 小时前
Linux(九) 进程管理完全指南:从入门到实战
linux·运维·chrome
江华森13 小时前
Linux 操作命令完全指南
linux·运维
rjszcb14 小时前
Linux,sensor调试笔记1,修改帧率,以及曝光上不去问题
linux
C++ 老炮儿的技术栈14 小时前
Ubuntu root账号自动登陆
linux·运维·服务器·c语言·c++·ubuntu·visual studio
2301_7807896614 小时前
零信任架构中,身份感知防火墙(IAFW)的部署要点与最佳实践
linux·运维·服务器·人工智能·tcp/ip·架构
小狮子&15 小时前
ubuntu2604无法共享文件夹问题解决
linux·运维·服务器
biter down15 小时前
3:VMware Workstation 安装 Ubuntu 22.04 超详细教程
linux·运维·ubuntu