linux input framework(1) -- 框架概述
- 了解linux input framework
1.input输入子系统框架
输入子系统由输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 input driver -> Input core -> Event handler -> userspace 到达用户空间传给应用程序。
-
输入子系统设备驱动层,主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。
-
核心层,为设备驱动层提供了规范和接口。设备驱动层只要关心如何驱动硬件并获得硬件数据(例如按下的按键数据),然后调用核心层提供的接口,核心层会自动把数据提交给事件处理层。
-
事件处理层,则是用户编程的接口(设备节点),并处理驱动层提交的数据处理。
-
/dev/input目录下显示的是已经注册在内核中的设备编程接口,用户通过open这些设备文件来打开不同的输入设备进行硬件操作。
-
事件处理层为不同硬件类型提供了用户访问及处理接口。例如当我们打开设备/dev/input/mice时,会调用到事件处理层的Mouse Handler来处理输入事件,这也使得设备驱动层无需关心设备文件的操作,因为Mouse Handler已经有了对应事件处理的方法。
-
输入子系统由内核代码drivers/input/input.c构成,它的存在屏蔽了用户到设备驱动的交互细节,为设备驱动层和事件处理层提供了相互通信的统一界面。
2.linux input 事件处理框架
2.1.分配、注册、注销input设备
struct input_dev *input_allocate_device(void)
int input_register_device(struct input_dev *dev)
void input_unregister_device(struct input_dev *dev)
2.2.设置input设备支持的事件类型、事件码、事件值的范围、input_id等信息
usb_to_input_id(dev, &input_dev->id);//设置bustype、vendo、product等
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);//支持的事件类型
input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);// EV_LED事件支持的事件码
for (i = 0; i < 255; i++)
set_bit(usb_kbd_keycode[i], input_dev->keybit); //EV_KEY事件支持的事件码
include/linux/input.h定义支持的类型:
# Event code Specifies
0x00 EV_SYN Separate/synchronize other events (e.g. SYN_REPORT/SYN_MT_REPORT), or report events lost (SYN_DROPPED)
0x01 EV_KEY Key press (KEY_*) or touch (BTN_TOUCH)
0x02 EV_REL Relative changes to a property. Changes relayed through REL_[XYZ] values.
0x03 EV_ABS Absolute coordinates for an event. Values are usually ABS_[XYZ], or ABS_MT for multi-touch
0x04 EV_MSC Miscellaneous codes
0x05 EV_SW Binary switches. E.g. SW_JACK_PHYSICAL_INSERT for headphone insertion
0x11 EV_LED Used for device LEDs, if any
0x12 EV_SND Used for sound devices
0x14 EV_REP Used for auto-repeating events
0x15 EV_FF Used for force-feedback capable devices (e.g. joysticks). An EVIOCSFF ioctl may be used to upload force feedback effects
0x16 EV_PWR Reserved for power events. Largely unused
0x17 EV_FF_STATUS Used for force-feedback capable devices.
一个设备可以支持一个或多个事件类型。每个事件类型下面还需要设置具体的触发事件码。比如:EV_KEY事件,需要定义其支持哪些按键事件码。
2.3.如果需要,设置input设备的打开、关闭、写入数据时的处理方法
input_dev->open = usb_kbd_open;
input_dev->close = usb_kbd_close;
input_dev->event = usb_kbd_event;
2.4.在发生输入事件时,向子系统报告事件
用于报告EV_KEY、EV_REL、EV_ABS等事件的函数有:
void input_report_key(struct input_dev *dev, unsigned int code, int value)
void input_report_rel(struct input_dev *dev, unsigned int code, int value)
void input_report_abs(struct input_dev *dev, unsigned int code, int value)
3.Event Handler层解析
3.1.Input输入子系统数据结构关系图
3.2.input_handler结构体
以evdev.c中的evdev_handler为例:
static struct input_handler evdev_handler = {
.event = evdev_event, //向系统报告input事件,系统通过read方法读取
.connect = evdev_connect, //和input_dev匹配后调用connect构建
.disconnect = evdev_disconnect,
.fops = &evdev_fops, //event设备文件的操作方法
.minor = EVDEV_MINOR_BASE, //次设备号基准值
.name = "evdev",
.id_table = evdev_ids, //匹配规则
};
3.3.input字符设备注册过程
drivers/input/input.c中:
static int __init input_init(void)
{
int err;
err = class_register(&input_class);
……
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
……
}
input_fops定义:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
Input_dev和input_handler匹配后调用input_handler的connect。以evdev_handler为例:
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
dev_t devt;
int minor;
int error;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return -ENFILE;
}
evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);//为每个匹配evdev_handler的设备创建一个evdev。
if (!evdev)
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);
init_waitqueue_head(&evdev->wait);
evdev->exist = 1;
evdev->minor = minor;
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
sprintf(evdev->name, "event%d", minor);
evdev_table[minor] = evdev;//记录evdev的位置,字符设备/dev/input/evnetx访问时根据次设备号及EVDEV_MINOR_BASE终在evdev_open中找到对应的evdev
devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
cdev = class_device_create(&input_class, &dev->cdev, devt,dev->cdev.dev, evdev->name);//创建了event字符设备节点
……
}
4.输入设备驱动案例
案例代码描述了一个button设备,产生的事件通过BUTTON_PORT引脚获取,当有按下/释放发生时,BUTTON_IRQ被触发,以下是驱动的源代码:
#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);
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;
}
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);
button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
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);
上一篇: linux下的python的变量
推荐阅读
-
Linux内核学习笔记(1)-- 进程管理概述
-
Linux platform总线(1):总体框架
-
46.Linux-分析rc红外遥控平台驱动框架,修改内核的NEC解码函数BUG(1)
-
搭建PHP官方框架zend framework 2(LINUX),zendframework_PHP教程
-
搭建PHP官方框架zend framework 2(LINUX),zendframework
-
业余框架整合-SSHD-(1)-整体概述(2011-12-03更新)
-
业余框架整合-SSHD-(1)-整体概述(2011-12-03更新)
-
linux设备驱动(1)字符设备框架及操作
-
linux input framework(1) -- 框架概述
-
Mybatis框架概述1