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


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");
相关推荐
承渊政道14 分钟前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.3 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落5 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨5 小时前
WSL2的安装与使用
linux·wsl
微小的鱼5 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng5 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮6 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
Linux-lucky18 小时前
45-Linux学习之旅之防火墙与WEB加固
linux·前端·网络·学习·ubuntu
禁默18 小时前
启元 Q1 二次开发实践:Ubuntu 部署与仿真验证,从 PrimeConsole 到 ROS 2 Humble + RViz
linux·运维·ubuntu
skywalk816318 小时前
把 去也网站 从 Ubuntu 搬到 FreeBSD:一次 Service Jail + nginx 的部署实录
linux·运维·nginx·ubuntu·freebsd