input--->输出子系统

这篇博客主要探讨Linux驱动开发中的输入子系统,包括如何处理中断方式的按键驱动程序。内容涉及设备号的确定、file_operations结构体的构造、中断处理及read函数中的休眠与唤醒机制。此外,还介绍了输入处理器的注册以及平台驱动的注册过程,特别是.probe函数的使用,以及在中断服务程序中上报事件的细节。

回顾:以中断方式处理的“按键驱动程序”。

1.确定设备号。

int major;

static int third_drv_init(void)

{

        major = register_chrdev(0,"third_drv",&sencod_drv_fops);

2.构造一个“file_operations”结构体

3.open函数中申请中断.

4.read函数中,若没有按键按下就休眠

wait_event_unterruptible(button_waitq, ev_press);

有按键按下后,中断程序被调用:在终端服务程序里确定是哪个按键按下。最后唤醒案件程序

测试如下:

1 先open某个设备文件:

fd = open("/dev/buttons", O_RDWR);

2 接下来读取值

while(1)
{
    read(fd, &key_val, 1);
    printf("key_val = 0x%x\n", key_val);
}
上面的驱动程序和测试程序的缺点:
上面打开了一个特定的设备文件“ /dev/buttons ”。而一般写的应用程序不会去打开这个
/dev/buttons ”。一般打开的都是原有的文件,如“ dev/tty* , 还有可能是不需要打开什么
设备文件,而 是直接“ scanf() ”就去获得了按键的输入。

输入子系统框架

1 最上层(核心层):
drivers/input.c   
看驱动程序先看“入口函数”
static int __init input_init(void)
之前注册字符设备驱动的函数是自己写的。上面的注册是内核有的。

 

<think>我们在处理触摸调试日志时,通常需要解析包含触摸点ID、坐标(x, y)、触摸状态(如按下、移动、抬起)等信息。根据引用提供的上下文,我们可以从以下几个方面入手: 1. **日志来源**:触摸事件通常由触摸屏驱动生成,通过内核的input子系统传递到用户空间(引用[3])。用户空间程序从设备文件(如`/dev/input/eventX`)读取事件,这些事件以`struct input_event`的形式存在。 2. **事件结构**:在Linux系统中,触摸事件通常被组织为多个`input_event`结构体。一个完整的触摸点更新可能由多个事件组成,例如: - 时间戳事件(`EV_SYN`) - 触摸点ID(`EV_ABS`, 代码为`ABS_MT_TRACKING_ID`) - X坐标(`EV_ABS`, 代码为`ABS_MT_POSITION_X`) - Y坐标(`EV_ABS`, 代码为`ABS_MT_POSITION_Y`) - 压力(可选,`ABS_MT_PRESSURE`) - 触摸状态(通过`EV_KEY`或`EV_ABS`事件表示,如`BTN_TOUCH`) 3. **多触摸协议**:目前常用的多触摸协议有A协议(Type A)和B协议(Type B)。我们以更常见的Type B协议为例,因为它支持每个触摸点独立更新。 4. **日志解析示例**:假设我们有以下日志片段(模拟): ``` [ 12345.678] EV_ABS ABS_MT_TRACKING_ID 0 [ 12345.678] EV_ABS ABS_MT_POSITION_X 100 [ 12345.678] EV_ABS ABS_MT_POSITION_Y 200 [ 12345.678] EV_SYN SYN_REPORT 0 [ 12346.789] EV_ABS ABS_MT_TRACKING_ID -1 [ 12346.789] EV_SYN SYN_REPORT 0 ``` 这表示: - 在时间戳12345.678,有一个触摸点(ID=0)出现在(100,200)位置,然后通过`SYN_REPORT`提交这个更新(表示按下)。 - 在时间戳12346.789,触摸点ID=0被释放(ID设为-1),表示抬起。 5. **状态转换**:我们可以根据ID的出现和消失来跟踪触摸状态: - 当出现一个新的非负ID时,表示一个触摸点按下(Down)。 - 当这个ID的位置更新时,表示移动(Move)。 - 当这个ID被设为-1时,表示该触摸点抬起(Up)。 6. **代码解析思路**(参考引用[1]和[4]): - 读取事件流,按`SYN_REPORT`将事件分组(每个`SYN_REPORT`之前的事件属于同一帧)。 - 对于每一帧,解析其中的触摸点信息(ID, X, Y等)。 - 根据ID的变化判断状态。 下面是一个简化的伪代码示例(用于解析单点触摸日志): ```c // 定义触摸点结构 struct TouchPoint { int id; // 触摸点ID int x; // X坐标 int y; // Y坐标 int status; // 状态: 0-未使用, 1-按下, 2-移动, 3-抬起 }; void parse_events(FILE *log) { // 当前帧的事件 struct input_event ev; // 当前帧的触摸点 struct TouchPoint current_point = {-1, 0, 0, 0}; while (fread(&ev, sizeof(ev), 1, log)) { switch (ev.type) { case EV_ABS: switch (ev.code) { case ABS_MT_TRACKING_ID: // 如果ev.value>=0,表示新的触摸点按下;如果为-1,表示抬起 current_point.id = ev.value; if (ev.value >= 0) { current_point.status = 1; // Down } else { current_point.status = 3; // Up } break; case ABS_MT_POSITION_X: current_point.x = ev.value; if (current_point.status != 1) { // 如果不是按下状态,则是移动 current_point.status = 2; // Move } break; case ABS_MT_POSITION_Y: current_point.y = ev.value; break; } break; case EV_SYN: if (ev.code == SYN_REPORT) { // 提交当前帧的触摸点 if (current_point.id >= 0) { // 输出调试信息 printf("TouchPoint: id=%d, x=%d, y=%d, status=%s\n", current_point.id, current_point.x, current_point.y, (current_point.status == 1) ? "Down" : (current_point.status == 2) ? "Move" : "Up"); // 如果是抬起事件,重置触摸点 if (current_point.status == 3) { current_point.id = -1; } } } break; } } } ``` 注意:实际的多点触摸日志会有多个触摸点同时更新,需要维护一个触摸点列表。此外,不同的触摸设备可能有不同的上报方式,需要根据具体设备的协议调整解析逻辑。 7. **调试工具**:引用[2]提到了使用`getevent -l`命令来查看输入设备事件。这个命令输出的就是`input_event`结构体的内容。我们可以通过这个命令获取原始触摸事件流,然后根据上述方法解析。 8. **在Android中的集成**:引用[4]展示了在Android应用中读取触摸事件的示例。驱动程序解析触摸数据后,转换成`TouchEvent`对象,应用层通过监听`onTouch`事件获取。 §§相关问题§§ 1. 如何通过`getevent`命令捕获触摸屏事件并保存为日志? 2. 触摸屏驱动程序如何处理多指触摸? 3. 在Android系统中,触摸事件是如何从驱动传递到应用层的? 4. 如何编写一个解析多点触摸日志的脚本? </think>理解触摸调试日志的解析需要结合嵌入式系统、驱动程序和事件处理机制。以下是基于引用内容的完整解析指南: ### 一、触摸调试日志的关键组成 1. **触摸点ID** 用于区分多个同时触摸的点(多指触摸)。在日志中通常表示为`ID=n`或通过位掩码标识。 2. **坐标信息** - X坐标:水平位置(如`touch_x`) - Y坐标:垂直位置(如`touch_y`) 引用[1]中的提取方法: ```c uint16_t touch_x = (status & 0xFFFF0000) >> 16; // 高16位存储X坐标 uint16_t touch_y = status & 0x0000FFFF; // 低16位存储Y坐标 ``` 3. **触摸状态**(核心状态机) - `DOWN`:手指接触屏幕(状态码通常为`0x01`) - `MOVE`:手指在屏幕上移动(`0x02`) - `UP`:手指离开屏幕(`0x04`) - `INVALID`:无效触点(如`0x00`) 4. **其他关键字段** - 时间戳:事件发生的时间(纳秒级精度) - 触点压力值(可选) - 触点面积(可选) ### 二、典型日志格式解析 假设日志片段: `[ 438.120] EV_ABS ABS_MT_TRACKING_ID 0 [ 438.120] EV_ABS ABS_MT_POSITION_X 520 [ 438.120] EV_ABS ABS_MT_POSITION_Y 1280 [ 438.120] EV_KEY BTN_TOUCH 1 [ 438.120] EV_SYN SYN_REPORT 0` 对应解析: 1. **`ABS_MT_TRACKING_ID 0`** → 触点ID=0 2. **`ABS_MT_POSITION_X 520`** → X坐标520 3. **`ABS_MT_POSITION_Y 1280`** → Y坐标1280 4. **`BTN_TOUCH 1`** → 触摸状态为按下(1=DOWN) 5. **`SYN_REPORT`** → 事件组结束标志[^3] ### 三、解析工具与方法 1. **使用`getevent`工具捕获原始日志** ```bash adb shell getevent -lt /dev/input/eventX # 替换X为设备节点[^2] ``` `-t`参数添加时间戳,`-l`显示符号化事件名。 2. **Python解析脚本示例** ```python def parse_touch_log(log_line): if "ABS_MT_TRACKING_ID" in log_line: touch_id = int(log_line.split()[-1]) elif "ABS_MT_POSITION_X" in log_line: x = int(log_line.split()[-1]) elif "ABS_MT_POSITION_Y" in log_line: y = int(log_line.split()[-1]) elif "BTN_TOUCH" in log_line: state = "DOWN" if int(log_line.split()[-1]) == 1 else "UP" elif "SYN_REPORT" in log_line: return f"ID:{touch_id} | X:{x} Y:{y} | {state}" return None ``` 3. **驱动层解析参考** 如引用[4]所示,在驱动中解析原始数据: ```java // GT911驱动示例 List<TouchEvent> parseEvents(byte[] data) { int id = data[0] & 0x0F; // 低4位存储ID int x = (data[1] << 8) | data[2]; // X坐标(双字节) int stateFlag = (data[0] >> 6) & 0x03; // 状态标志位 String state = (stateFlag == 1) ? "DOWN" : (stateFlag == 2) ? "MOVE" : "UP"; } ``` ### 四、调试常见问题分析 | 日志现象 | 可能原因 | 解决方案 | |--------------------------|--------------------------|-----------------------| | 坐标值固定为0或最大值 | I²C通信故障/寄存器未配置 | 检查引用[1]的寄存器配置 | | 无`BTN_TOUCH`事件 | 驱动未上报按键事件 | 验证驱动input_dev初始化 | | ID跳跃或不连续 | 触摸点跟踪算法错误 | 检查`ABS_MT_TRACKING_ID`处理 | | 事件丢失 | 系统负载过高 | 使用`cat /proc/interrupts`检查中断 | ### 五、最佳实践建议 1. 启用内核输入子系统调试: ```bash echo 1 > /sys/module/input_core/parameters/debug_level ``` 2. 在Android框架层添加详细日志(参考引用[4]): ```java public boolean onTouch(View v, MotionEvent event) { Log.d("TOUCH_DEBUG", "ID:" + event.getPointerId(0) + " X:" + event.getX() + " Y:" + event.getY()); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值