linux input system 分析笔记

news/2024/5/17 19:28:34

1 struct input_dev 和 struct input_handler

1.1 简介

struct input_dev表示一个设备驱动层的输入设备。

struct input_handler是处理struct input_dev上报的事件的事件处理器。

1.2 全局变量input_dev_list,input_handler_list

输入设备链表:input_dev_list

事件处理器链表:input_handler_list

在input_register_device()函数里会将注册的struct input_dev结构体对象加入全局变量input_dev_list中。

在input_register_handler()函数里会将注册的struct input_handler结构体对象加入全局变量input_handler_list中。

1.3 struct input_dev 和 struct input_handler的匹配

1.3.1 匹配

input_register_device()函数会遍历事件处理器链表input_handler_list,根据id号查找匹配的struct input_handler。

input_register_handler()函数会遍历输入设备链表input_dev_list,根据id号查找匹配的struct input_handler。

一个输入设备可以关联多个事件处理器。

如果匹配成功,调用handler->connect();

1.3.2 不同struct input_handler的connect()函数

1.3.2.1 evdev_handler的evdev_connect();

evdev_connect()函数做以下工作:

  1. 调用input_register_handle()函数注册事件处理句柄struct input_handle。
  2. 注册字符设备文件/dev/input/eventX

evdev_handler会和所有的struct input_dev 对象匹配成功,所以有多少个struct input_dev 对象,/dev/input/目录下就会有多少个eventX设备文件。

1.3.2.2 mousedev_handler的mousedev_connect();

mousedev_connect()函数做以下工作:

  1. 调用input_register_handle()函数注册事件处理句柄struct input_handle。
  2. 注册字符设备文件/dev/input/mouseX
1.3.2.3 input_leds_handler的input_leds_connect();

input_leds_connect()函数做以下工作:

  1. 调用input_register_handle()函数注册事件处理句柄struct input_handle。
  2. 调用led_classdev_register()函数register a new object of LED class,会在/sys/class/leds/目录下生成"inputXXX"的目录。
1.3.2.4 其他struct input_handler

sysrq_handler

kbd_handler

1.4 查看系统下的struct input_dev 和 struct input_handler信息

1.4.1 /proc/bus/input/devices

信息如下:

I: Bus=0019 Vendor=0000 Product=0003 Version=0000                                                                                                       
N: Name="Sleep Button"
P: Phys=PNP0C0E/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0E:00/input/input0
U: Uniq=
H: Handlers=kbd event0 
B: PROP=0
B: EV=3
B: KEY=4000 0 0 I: Bus=0019 Vendor=0000 Product=0005 Version=0000
N: Name="Lid Switch"
P: Phys=PNP0C0D/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0D:00/input/input1
U: Uniq=
H: Handlers=event1 
B: PROP=0
B: EV=21
B: SW=1I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=PNP0C0C/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input2
U: Uniq=
H: Handlers=kbd event2 
B: PROP=0
B: EV=3
B: KEY=10000000000000 0I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input3
U: Uniq=
H: Handlers=kbd event3 
B: PROP=0
B: EV=3
B: KEY=10000000000000 0I: Bus=0011 Vendor=0001 Product=0001 Version=ab83
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input4
U: Uniq=
H: Handlers=sysrq kbd event4 leds 
B: PROP=0
B: EV=120013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7I: Bus=0011 Vendor=0002 Product=000a Version=0063
N: Name="TPPS/2 Elan TrackPoint"
P: Phys=isa0060/serio1/input0
S: Sysfs=/devices/platform/i8042/serio1/input/input6
U: Uniq=
H: Handlers=mouse2 event7 
B: PROP=21
B: EV=7
B: KEY=70000 0 0 0 0
B: REL=3I: Bus=0003 Vendor=413c Product=301a Version=0111
N: Name="PixArt Dell MS116 USB Optical Mouse"
P: Phys=usb-0000:00:14.0-7/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb3/3-7/3-7:1.0/0003:413C:301A.0002/input/input10
U: Uniq=
H: Handlers=mouse3 event8 
B: PROP=0
B: EV=17
B: KEY=70000 0 0 0 0
B: REL=903
B: MSC=10I: Bus=0019 Vendor=0000 Product=0000 Version=0000
N: Name="Intel HID events"
P: Phys=
S: Sysfs=/devices/platform/INTC1051:00/input/input11
U: Uniq=
H: Handlers=rfkill kbd event9 
B: PROP=0
B: EV=13
B: KEY=81000300000000 5000004000 1e294000000020 0
B: MSC=10......

1.4.2 /proc/bus/input/handlers

N: Number=0 Name=rfkill                                                                                                                                 
N: Number=1 Name=kbd
N: Number=2 Name=sysrq (filter)
N: Number=3 Name=mousedev Minor=32
N: Number=4 Name=evdev Minor=64
N: Number=5 Name=leds
N: Number=6 Name=joydev Minor=0

2 struct input_event(输入事件数据结构体)

2.1 struct input_event的定义(kernel-5.4.18)

一个输入事件包括时间戳、输入事件类型,事件编码(code)和事件值(value),具体信息如下:

struct input_event {
#if (__BITS_PER_LONG != 32 || !defined(__USE_TIME_BITS64)) && !defined(__KERNEL__)struct timeval time;
#define input_event_sec time.tv_sec
#define input_event_usec time.tv_usec
#else__kernel_ulong_t __sec;
#if defined(__sparc__) && defined(__arch64__)unsigned int __usec;
#else__kernel_ulong_t __usec;
#endif
#define input_event_sec  __sec
#define input_event_usec __usec
#endif__u16 type;__u16 code;__s32 value;
};

2.2 Event types

/** Event types*/#define EV_SYN          0x00
#define EV_KEY          0x01
#define EV_REL          0x02
#define EV_ABS          0x03
#define EV_MSC          0x04
#define EV_SW           0x05
#define EV_LED          0x11
#define EV_SND          0x12
#define EV_REP          0x14
#define EV_FF           0x15
#define EV_PWR          0x16
#define EV_FF_STATUS        0x17
#define EV_MAX          0x1f
#define EV_CNT          (EV_MAX+1)

EV_SYN、EV_KEY、EV_REL 和 EV_ABS网上资料很多,本文就不过多介绍了,后面会重点介绍EV_SW 和 EV_LED。

2.3 事件类型——EW_SW(0x05)

2.3.1 简介

EV_SW events describe stateful binary switches. For example, the SW_LID code is
used to denote when a laptop lid is closed.

                                Documentation/input/event-codes.rst

2.3.2 支持的事件编码(code)

/** Switch events*/#define SW_LID          0x00  /* set = lid shut */
#define SW_TABLET_MODE      0x01  /* set = tablet mode */
#define SW_HEADPHONE_INSERT 0x02  /* set = inserted */
#define SW_RFKILL_ALL       0x03  /* rfkill master switch, type "any"set = radio enabled */
#define SW_RADIO        SW_RFKILL_ALL   /* deprecated */
#define SW_MICROPHONE_INSERT    0x04  /* set = inserted */
#define SW_DOCK         0x05  /* set = plugged into dock */
#define SW_LINEOUT_INSERT   0x06  /* set = inserted */
#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
#define SW_VIDEOOUT_INSERT  0x08  /* set = inserted */
#define SW_CAMERA_LENS_COVER    0x09  /* set = lens covered */
#define SW_KEYPAD_SLIDE     0x0a  /* set = keypad slide out */
#define SW_FRONT_PROXIMITY  0x0b  /* set = front proximity sensor active */
#define SW_ROTATE_LOCK      0x0c  /* set = rotate locked/disabled */
#define SW_LINEIN_INSERT    0x0d  /* set = inserted */
#define SW_MUTE_DEVICE      0x0e  /* set = device disabled */
#define SW_PEN_INSERTED     0x0f  /* set = pen inserted */
#define SW_MAX          0x0f
#define SW_CNT          (SW_MAX+1)

2.3.3 事件编码——SW_LID 

笔记本电脑的屏幕上盖在合上 或者 掀开时会触发待机 或者 唤醒等操作,在linux内核里,驱动通过SW_LID事件编码向内核报告屏幕上盖是被合上 还是 被掀开。

事件值为1,表示笔记本电脑屏幕上盖被合上;

事件值为0,表示笔记本电脑屏幕上盖被掀开;

2.3.4 事件编码——SW_HEADPHONE_INSERT、SW_LINEOUT_INSERT、SW_LINEIN_INSERT

在很多机器上都会有以下的音频接口,驱动里会通过事件编码SW_HEADPHONE_INSERT、SW_LINEOUT_INSERT、SW_LINEIN_INSERT 和 SW_MICROPHONE_INSERT来通知系统有无插头接入。

2.3.5 通过evtest命令获取笔记本电脑上耳机插孔的耳机插头接入事件

2.3.5.1 判断哪个/dev/input/eventX支持EV_SW事件类型中的SW_HEADPHONE_INSERT 和 SW_MICROPHONE_INSERT

 在/proc/bus/input/devices文件内容中有以下信息。表示/dev/input/event14可以上报microphone是否接入,/dev/input/event15可以上报headphone是否接入。

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="sof-hda-dsp Mic"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/skl_hda_dsp_generic/sound/card0/input19
U: Uniq=
H: Handlers=event14 
B: PROP=0
B: EV=21
B: SW=10       //第4个bit为1,表示支持事件编码SW_MICROPHONE_INSERTI: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="sof-hda-dsp Headphone"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/skl_hda_dsp_generic/sound/card0/input20
U: Uniq=
H: Handlers=event15 
B: PROP=0
B: EV=21
B: SW=4        //第2个bit为1,表示支持事件编码SW_HEADPHONE_INSERT
2.3.5.2 通evtest抓取输入事件的数据
# evtest /dev/input/event14
Input driver version is 1.0.1
Input device ID: bus 0x0 vendor 0x0 product 0x0 version 0x0
Input device name: "sof-hda-dsp Mic"
Supported events:Event type 0 (EV_SYN)Event type 5 (EV_SW)Event code 4 (SW_MICROPHONE_INSERT) state 0
Properties:
Testing ... (interrupt to exit)
Event: time 1713156364.680074, type 5 (EV_SW), code 4 (SW_MICROPHONE_INSERT), value 1    //话筒插头接入
Event: time 1713156364.680074, -------------- SYN_REPORT ------------
Event: time 1713156369.338703, type 5 (EV_SW), code 4 (SW_MICROPHONE_INSERT), value 0    //拔掉话筒插头
Event: time 1713156369.338703, -------------- SYN_REPORT ------------

 

# evtest /dev/input/event15
Input driver version is 1.0.1
Input device ID: bus 0x0 vendor 0x0 product 0x0 version 0x0
Input device name: "sof-hda-dsp Headphone"
Supported events:Event type 0 (EV_SYN)Event type 5 (EV_SW)Event code 2 (SW_HEADPHONE_INSERT) state 0
Properties:
Testing ... (interrupt to exit)
Event: time 1713156221.813617, type 5 (EV_SW), code 2 (SW_HEADPHONE_INSERT), value 1    //耳机插头接入
Event: time 1713156221.813617, -------------- SYN_REPORT ------------
Event: time 1713156229.416541, type 5 (EV_SW), code 2 (SW_HEADPHONE_INSERT), value 0    //拔掉耳机插头
Event: time 1713156229.416541, -------------- SYN_REPORT ------------

2.4 事件类型——EV_LED

2.4.1 支持的事件编码(code)

/** LEDs*/#define LED_NUML        0x00
#define LED_CAPSL       0x01
#define LED_SCROLLL     0x02
#define LED_COMPOSE     0x03
#define LED_KANA        0x04
#define LED_SLEEP       0x05
#define LED_SUSPEND     0x06
#define LED_MUTE        0x07
#define LED_MISC        0x08
#define LED_MAIL        0x09
#define LED_CHARGING        0x0a
#define LED_MAX         0x0f
#define LED_CNT         (LED_MAX+1)

2.4.2 LED_NUML、LED_CAPSL 和 LED_SCROLLL

2.4.2.1 简介

普通键盘上有下面的3个LED灯

可以通过LED_NUML、LED_CAPSL 和 LED_SCROLLL 这几个事件编码来控制。

2.4.2.2 /sys/class/leds/

上面的“1.3.2.3”小节中描述了,led_classdev_register()函数中会register a new object of LED class,会在/sys/class/leds/目录下生成"inputXXX"的目录,如下:

/sys/class/leds/input4::capslock
/sys/class/leds/input4::numlock
/sys/class/leds/input4::scrolllock

每个目录下都有一个brightness文件,可以通过这个文件来控制LED灯的亮 和 灭。

echo 0 > /sys/class/leds/input4\:\:capslock/brightness    //熄灭键盘上的capslock灯
echo 1 > /sys/class/leds/input4\:\:capslock/brightness    //点亮键盘上的capslock灯

2.5 事件类型——EV_SND

蜂鸣器可以使用这个事件类型

3 输入事件的报告流程

3.1 简介

绝大多数的输入事件是通过驱动程序里调用input_event()函数来上报的,另外一种方法是应用程序通过/dev/input/eventX文件接口(evdev_write())来上报输入事件。

3.2 应用程序通过evdev_write()模拟输⼊事件

3.2.1 模拟输入SW_LID事件,让系统进入休眠状态

#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/input.h>int main()
{int fd, i, ret;struct input_event event;if((fd = open("/dev/input/event1", O_RDWR)) < 0){ return 1;}   event.type = EV_SW;event.code = SW_LID;event.value = 1;ret = write(fd, &event, sizeof(struct input_event));event.type = EV_SYN;event.code = SYN_REPORT;event.value = 0;ret = write(fd, &event, sizeof(struct input_event));close(fd);return 0;
}

3.2.2 模拟输入LED_CAPSL事件,让键盘上的capslock灯闪烁

#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/input.h>int main()
{int fd, i, ret;struct input_event event;if((fd = open("/dev/input/event19", O_RDWR)) < 0){ return 1;}   for( i=0; i <= 7; i++){event.type = EV_LED;event.code = LED_CAPSL;event.value = 1;ret = write(fd, &event, sizeof(struct input_event));event.type = EV_SYN;event.code = SYN_REPORT;event.value = 0;ret = write(fd, &event, sizeof(struct input_event));sleep(1);event.type = EV_LED;event.code = LED_CAPSL;event.value = 0;ret = write(fd, &event, sizeof(struct input_event));event.type = EV_SYN;event.code = SYN_REPORT;event.value = 0;ret = write(fd, &event, sizeof(struct input_event));sleep(1);}   close(fd);return 0;
}

4 扩展知识

4.1 ACPI中的相关设备

PNP0C0D: Lid Device

PNP0C0E: Sleep Button Device

PNP0C0C: Power Button Device

4.2 相关命令

evtest

xinput


http://www.mrgr.cn/p/24742387

相关文章

C语言中的控制语句(分支语句 if、switch、三目运算符)

程序执行的三大流程 顺序 : 从上向下&#xff0c; 顺序执行代码分支 : 根据条件判断&#xff0c; 决定执行代码的分支循环 : 让特定代码重复的执行 分支语句 条件语句用来根据不同的条件来执行不同的语句&#xff0c;C语言中常用的条件语句包括if语句和switch语句。 if 语句…

Ubuntu下部署gitlab

1.安装gitlab服务 1.安装依赖 在ubuntu下使用快捷键ctrl+alt+T打开命令行窗口,然后运行下面命令 sudo apt update sudo apt-get upgrade sudo apt-get install curl openssh-server ca-certificates postfixps:如果这一步有遇到弹出框的直接Tab切换到确定/ok按钮,然后回车即可…

组态控制方法

什么叫组态控制?从应用场景上来看,如果现在集成了一个系统,它既包括了生产A要用的全部I/O系统,又包括可生产B和C等等要用的全部I/O系统。但是ABC的生产I/O不一样(硬件组态不尽相同)。 这个时候我就想用一套程序(包括硬件组态)就能适配全部的ABC生产。另外我在切换硬件组…

模块介绍,包,json模块

【一】模块 1.什么是模块 模块就是一系列功能的结合体,可以直接使用 2.为什么要模块 极大地提升开发效率 3.模块的三种来源 【1】内置模块 无需下载,解释器自带,直接导入使用即可 【2】自定义模块 自己写的代码,封装成模块,自己用或者是发布到网上供别人使用 【3】第三方模…

七月论文审稿GPT第4.5版:通过15K条paper-review数据微调Llama2 70B(含各种坑)

前言 当我们3月下旬微调完Mixtral 8x7B之后(更多详见&#xff1a;七月论文大模型&#xff1a;含论文的审稿、阅读、写作、修订 )&#xff0c;下一个想微调的就是llama2 70B 因为之前积攒了不少微调代码和微调经验&#xff0c;所以3月底apple便通过5K的paper-review数据集成功…

v-bind与class,style属性的使用

class,style是各种dom元素的都具有的原生属性 class与:class的区别,直接使用class的话,后面跟的是常量,若使用:class,v-bind:class的话,后面需跟变量,可以实现动态地改变元素的样式 如下图代码: 在上述代码中,在button元素中,对class原生属性赋值了,也使用了:class的…

重温8年前项目部署

背景 同事表弟毕设&#xff0c;需要启动一个8年前GitHub项目&#xff01; 源码&#xff1a;GitHub - asinfo-ssyx/KindgartenPlatform: 幼儿园互动平台 部署步骤 一、Eclipse导入项目 使用 Projects from Folder or Archive 导入 选择项目目录 点击【选择文件夹】后如下 点…

WhaleScheduler为银行业全信创环境打造统一调度管理平台解决方案

项目背景 数字金融是数字经济的重要支撑和驱动力。近年来,我国针对数字金融的发展政策频频出台,《金融科技发展规划 (2022-2025年)》、《“十四五”数字经济发展规划》、《关于银行业保险业数字化转型的指导意见》、《金融标准化“十 四五”发展规划》等相继发布,顶层设计…

架构

我们以Spring Security中Servlet实现方式来介绍Spring Security整体架构,不会具体到具体的认证、授权来介绍Spring Security架构。如果让我们自己来写一个安全框架,我们需要将我们的框架置于项目中的哪个位置?很显然是在所有的请求到达Controller之前,在访问具体的某个Cont…

天花板!充值运营平台限时返场!

限时返场活动:活动有效期:2024-04-18 ~ 2024-04-28一、近期更新介绍 提现功能完善: 提现配置:多提现方式、日期限制、频率限制、金额限制、整数限制、单日限额、留存余额、代扣税率、手续费、可提现至余额(提现配置)提现记录:个人申请提现、后台审核自动(提现记录-及后…

【Docker系列】容器访问宿主机的Mysql

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

拖拽式工作流有哪几个优势?

拖拽式工作流优势特点突出,可以助力企业实现快速、高效、低成本的流程化办公。在信息技术迅猛发展的今天,如何助力中小型企业在数字化转型的过程中平稳过渡?又是如何让中小型企业摆脱数据孤岛、成本投入高等各种瓶颈和难题?低代码技术平台是近些年较为理想的平台产品,其中…

基于springboot的图书个性化推荐系统

介绍 图书个性化推荐系统的主要使用者分为管理员和学生,实现功能包括管理员:首页、个人中心、学生管理、图书分类管理、图书信息管理、图书预约管理、退换图书管理、管理员管理、留言板管理、系统管理,学生:首页、个人中心、图书预约管理、退换图书管理、我的收藏管理,前台…

java:多线程

多线程 在java程序中同时执行多个线程,每个线程独立执行不同的任务. 可以提高程序的性能和资源利用率,增加程序的并发性. 多线程的作用 1,提高程序性能 可以将一个任务分解成多个子任务并行处理,从而提高程序的运行速度 2,提高资源利用率 可以更好地利用CPU资源,提高CPU…

ThinkPHP 5.0.23 远程代码执行漏洞

漏洞检测工具 ThinkPHP 5.0 RCE检测工具 https://github.com/Lotus6/ThinkphpGUI/releases 解决办法 https://blog.csdn.net/sjsjshhs134654/article/details/131305418如果这篇文章对你有用,可以关注本人微信公众号获取更多ヽ(^ω^)ノ ~

【计算机毕业设计】点餐平台网站——后附源码

&#x1f389;**欢迎来到琛哥的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 琛哥&#xff0c;一名来自世界500强的资深程序猿&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 琛哥在深度学习任务中展现出卓越的能力&a…

Visual Components软件为您带来的价值 衡祖仿真

Visual Components具备丰富的3D仿真功能、快速建模能力、定制化应用程序逻辑和大量预定义组件库等多种特点,为自动化设备制造商、整合商、制造型公司提供简单、 快速和的设计方式,可以有效提高生产效率,并优化资源分配,避免制造过程中各种不可控事件带来的影响。Visual Com…

按吉他弦手不再疼痛的真正奧義!!~(姿勢

學吉他最痛苦的事情莫過”手痛”,網路上分析關於手痛的解決方式有好幾篇,不外乎就是…降弦、靠琴桁按弦、換弦的材質、換細弦、調弦距…等,我就不再多廢話講跟別人差不多的東西。但我發現有一件事情是很少老師提及的,那就是關於按弦的”姿勢”,其實姿勢/角度跟按弦的聲音好…