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


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 #include #include #include #include // 定义按键值(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软件开发性能优化
linux·c++·性能优化
Bruce_kaizy41 分钟前
c++ linux环境编程——文件io介绍以及open 、write 、read 三剑客深度详解
linux·服务器·c++·ubuntu·操作系统·文件io
亦良Cool1 小时前
VMware虚拟机ubuntu瘦身,解决虚拟机越用越大
linux·运维·ubuntu
星辰&与海2 小时前
KVM + QEMU虚拟化方案
linux·运维
宋浮檀s3 小时前
应急响应——恶意流量&攻击行为识别
linux·运维·网络·网络安全·应急响应
REDcker3 小时前
Linux OverlayFS详解
java·linux·运维
lwx9148523 小时前
Linux系统中用户锁定后如何解锁
linux·运维·服务器
zhangrelay4 小时前
ROS 2 Lyrical Luth启程-Ubuntu26.04-
linux·笔记·学习·ubuntu
WoY20204 小时前
使用iostat看磁盘IO
linux
kebidaixu4 小时前
VS Code Remote-SSH 远程开发:解决无法安装扩展、市场加载失败的问题
linux