本章介绍Linux输入子系统的基本概念。
_________ _ _______ _________
\__ __/( ( /|( ____ )|\ /|\__ __/
) ( | \ ( || ( )|| ) ( | ) (
| | | \ | || (____)|| | | | | |
| | | (\ \) || _____)| | | | | |
| | | | \ || ( | | | | | |
___) (___| ) \ || ) | (___) | | |
\_______/|/ )_)|/ (_______) )_(
_______ ______ _______ _______
( ____ \|\ /|( ___ \ ( ____ \|\ /|( ____ \
| ( \/| ) ( || ( ) )| ( \/( \ / )| ( \/
| (_____ | | | || (__/ / | (_____ \ (_) / | (_____
(_____ )| | | || __ ( (_____ ) \ / (_____ )
) || | | || ( \ \ ) | ) ( ) |
/\____) || (___) || )___) )/\____) | | | /\____) |
\_______)(_______)|/ \___/ \_______) \_/ \_______)
1.分层
Linux输入子系统分为三层:
* 输入子系统事件处理层(EventHandler):用户编程的接口,并处理驱动层提交的数据。
* 输入子系统核心层(InputCore),为设备驱动层提供接口,核心层会自动把数据提交给事件处理层。
* 输入子系统设备驱动层,实现对硬件的读写访问,中断设置、并把硬件产生的事件转换为核心层定义的规范提交给事件处理层
核心层
/ \
/ \
事件处理层 设备驱动层
/ (键盘、鼠标、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.简单示例
#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