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

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

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

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2017-2020 Dock
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信