10. input子系统


1. 输入子系统概述

• 作用:
Linux输入子系统为各类输入设备(如键盘、鼠标、触摸屏)提供统一的驱动框架,实现:

  • 统一驱动接口:标准化设备驱动开发。

  • 兼容性:支持不同厂商设备无缝接入。

  • 事件抽象:将硬件信号转换为标准输入事件(如按键、坐标)。

• 核心组件:

  • 设备驱动层:直接操作硬件(如读取GPIO状态)。

  • 核心层:管理设备与事件处理模块的交互。

  • 事件处理层:向用户空间提供设备节点(如/dev/input/eventX)。 alt text


2. 设备节点与输入设备的关联

• 设备节点类型:

  • 通用节点:/dev/input/eventX(X为数字)。

  • 专用节点:如/dev/input/mouse0(直接标识设备类型)。

• 确定设备节点的方法:

  1. 查看设备信息:

    cat /proc/bus/input/devices
    

    输出示例:

    I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
    N: Name="AT Translated Set 2 keyboard"
    P: Phys=isa0060/serio0/input0
    H: Handlers=sysrq kbd event1
    
    • 关键字段:
      H: Handlers=event1表示设备节点为/dev/input/event1。

  2. 试探性测试:

    sudo hexdump /dev/input/event1  # 按下键盘按键观察输出
    sudo cat /dev/input/mouse0      # 移动鼠标观察输出
    

3. RK3568开发板输入设备实例

• 开发板输入设备:

  • 触摸屏、红外接收器、ADC按键、耳机接口。

• 查看设备节点:

ls /dev/input/  # 输出:event0 event1 event2 event3 event4

• 详细设备信息:

cat /proc/bus/input/devices

输出示例:

# 触摸屏
N: Name="Goodix Capacitive TouchScreen"
H: Handlers=event2

# ADC按键
N: Name="adc-keys"
H: Handlers=event3

• 测试设备事件:

hexdump /dev/input/event2  # 触摸屏幕查看坐标事件
hexdump /dev/input/event3  # 按下ADC按键查看按键事件

4. 输入事件解析

• 事件结构体(参考linux/input.h):

struct input_event {
    struct timeval time;  // 时间戳
    __u16 type;           // 事件类型(如EV_KEY、EV_ABS)
    __u16 code;           // 事件代码(如KEY_A、ABS_X)
    __s32 value;          // 事件值(如1表示按下,0表示释放)
};

• 常见事件类型:

  • EV_KEY:按键事件(如键盘、按键)。

  • EV_ABS:绝对坐标事件(如触摸屏)。

  • EV_REL:相对坐标事件(如鼠标)。


5. 编写输入设备驱动(示例)

• 步骤:

  1. 注册输入设备:

    #include <linux/input.h>
    
    struct input_dev *input_dev = input_allocate_device();
    input_dev->name = "Custom Input Device";
    set_bit(EV_KEY, input_dev->evbit);    // 支持按键事件
    set_bit(KEY_A, input_dev->keybit);     // 定义按键A
    input_register_device(input_dev);     // 注册设备
    
  2. 上报事件(在中断中触发):

    input_report_key(input_dev, KEY_A, 1);  // 按下按键A
    input_sync(input_dev);                  // 同步事件
    
  3. 用户空间读取事件:

    // 示例应用:读取事件并打印
    struct input_event ev;
    int fd = open("/dev/input/event2", O_RDONLY);
    read(fd, &ev, sizeof(ev));
    printf("Type: %d, Code: %d, Value: %d\n", ev.type, ev.code, ev.value);
    

6. 常见问题与调试

• 问题1:设备节点未生成

  • 原因:驱动未正确注册或设备树配置错误。

  • 解决:检查dmesg日志,确认驱动加载成功。

• 问题2:事件无响应

  • 调试方法:

    evtest /dev/input/event2  # 交互式测试工具
    

• 问题3:多设备冲突

  • 解决:在设备树中禁用默认驱动(如心跳灯)。


总结

Linux输入子系统通过标准化接口简化了输入设备驱动开发,开发者只需关注硬件操作和事件上报。通过/proc/bus/input/devices和hexdump工具可快速验证设备节点与硬件的对应关系,结合事件结构体和驱动API,能高效实现自定义输入设备驱动。