Linux输入子系统之我见(一)

本章介绍Linux输入子系统的基本概念。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_________ _ _______ _________
\__ __/( ( /|( ____ )|\ /|\__ __/
) ( | \ ( || ( )|| ) ( | ) (
| | | \ | || (____)|| | | | | |
| | | (\ \) || _____)| | | | | |
| | | | \ || ( | | | | | |
___) (___| ) \ || ) | (___) | | |
\_______/|/ )_)|/ (_______) )_(
_______ ______ _______ _______
( ____ \|\ /|( ___ \ ( ____ \|\ /|( ____ \
| ( \/| ) ( || ( ) )| ( \/( \ / )| ( \/
| (_____ | | | || (__/ / | (_____ \ (_) / | (_____
(_____ )| | | || __ ( (_____ ) \ / (_____ )
) || | | || ( \ \ ) | ) ( ) |
/\____) || (___) || )___) )/\____) | | | /\____) |
\_______)(_______)|/ \___/ \_______) \_/ \_______)

1.分层

Linux输入子系统分为三层:

  • 输入子系统事件处理层(EventHandler):用户编程的接口,并处理驱动层提交的数据。
  • 输入子系统核心层(InputCore),为设备驱动层提供接口,核心层会自动把数据提交给事件处理层。
  • 输入子系统设备驱动层,实现对硬件的读写访问,中断设置、并把硬件产生的事件转换为核心层定义的规范提交给事件处理层
1
2
3
4
5
6
7
8
9
核心层
/ \
/ \
事件处理层 设备驱动层
/ (键盘、鼠标、TS)
/
设备节点
(/dev/input/event*)
(/dev/input/misc)

输入子系统核心代码为driver/input/input.c

2.编程要点

在使用Linux输入子系统进行编程时,需要进行一下三步:

  • 分配Input Device结构体
  • 在该结构体中设置该设备支持的事件类型及具体事件
  • 编写硬件处理函数,如使用中断监听按键的动作
  • 将需要处理的事件提交到InputCore
  • 将该设备注册到子系统中

    2.1 输入子系统支持的事件类型

    | 事件码 | 数字值 | 说明 |
    | :—-: |:——:| :—-:|
    |EV_SYN | 0x00 |同步事件 |
    | EV_KEY| 0x01 |按键事件|
    |EV_REL | 0x02 | 相对坐标 |
    | EV_ABS | 0x03 | 绝对坐标 |
    | EV_MSC | 0x04 | 其他 |
    | EV_SW | 0x05 | 开关 |
    | EV_LED | 0x11 | 按键 设备灯 |
    | EV_SND | 0x12 | 声音 |
    | EV_REP | 0x14 | 重复 |
    | EV_FF | 0x15 | 力反馈 |
    | EV_PWR | 0x16 | 电源 |
    | EV_FF_STATUS | 0x17 | 力反馈状态 |
    我们所实现的每个设备驱动都可以选择一个或多个进行上报给InputCore

    3.简单示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #include <linux/input.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    static struct input_dev *button_dev;
    static void button_interrupt(int irq, void*dummy, struct pt_regs *fp)
    {
    //上报事件
    input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
    //在上报后sync通知Core有事件要处理
    input_sync(button_dev);
    }
    static int __init button_init(void)
    {
    int error;
    //请求中断,并且在中断服务函数中进行事件上报
    if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button",NULL)) {
    printk(KERN_ERR"button.c: Can't allocate irq %d\n", button_irq);
    return -EBUSY;
    }
    // 1.分配结构体
    button_dev = input_allocate_device();
    if (!button_dev) {
    printk(KERN_ERR"button.c: Not enough memory\n");
    error = -ENOMEM;
    goto err_free_irq;
    }
    //支持事件类型 按键
    button_dev->evbit[0] = BIT(EV_KEY);
    //支持按键 BTN_0
    button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
    //向InputCore注册该设备驱动
    error = input_register_device(button_dev);
    if (error) {
    printk(KERN_ERR"button.c: Failed to register device\n");
    goto err_free_dev;
    }
    return 0;
    err_free_dev:
    input_free_device(button_dev);
    err_free_irq:
    free_irq(BUTTON_IRQ, button_interrupt);
    return error;
    }
    static void __exit button_exit(void)
    {
    input_unregister_device(button_dev);
    free_irq(BUTTON_IRQ, button_interrupt);
    }
    module_init(button_init);
    module_exit(button_exit);

由上面的源码可知,相对于自己完全实现字符设备类型驱动而言,我们所进行的编码量已经大为减少。而且层次更为清楚。

版权声明:本文为博主原创文章,转载需声明为转载内容并添加原文地址。

原文地址:http://coderdock.com

Dock wechat
欢迎您扫一扫上面的微信公众号,订阅我的公众号