input子系统——架构、驱动、应用程序

一、input子系统架构

input子系统由驱动层drivers,输入子系统核心层input core,事件处理层event handler组成。

一个输入事件,通过输入设备发给系统如鼠标移动,键盘按键按下等通过device driver->input core(handler->event函数)->event handler->user space的顺序到达用户空间传给应用程序。

一个输出事件,通过系统发给输入设备,通过user space->event handler->input core(dev->event函数)->device driver

1、驱动功能层:负责和底层的硬件设备打交道,将底层硬件设备对用户输入的响应转换为标准的输入事件以后再向上发送给输入系统核心层

2、Input系统核心层:由driver/input/input.c及相关头文件实现,他对下提供了设备驱动层的接口,对上提供了事件处理层的变成接口。

3、事件处理层将硬件设备上报的事件分发到用户空间和内核。

结构图如下:

等待上传照片

二、编写input驱动需要的函数

1)包含头文件<linux/input.h>,他是input子系统的接口,提供了必要的定义消息

2)Input_allocate_device()

分配了一个Input device的结构,设置他的bit field来告诉input子系统他能产生或者接收什么事件。

3)input_register_device(struct input_dev *dev)

将dev结构体添加到input_dev_list全局链表中去

通过input_attach_handler(struct input_dev *dev, struct input_handler *handler)来查找对应的handler,

input_attach_handler里面实际调用了input_match_device(const struct input_device_id *id,struct input_dev *dev)

一旦input_attach_handler找到了对应的handler,就执行handler->connect

4)input_report_key(struct input_dev *dev, unsigned int code, int value)

5)input_sync(struct input_dev *dev)

告诉事件的接收者,到此为止为一次完整的消息。比如我们在touch screen上获得了x、y的值,要使作为一次事件,那么将input_sync加在report x、y值得后面。

6)其他的事件type,输出事件处理

其他的事件有:

EV_LED:用作键盘的LED灯

EV_SND:用作键盘的蜂鸣器

他和键盘事件很相似,只不过键盘事件是INPUT_PASS_TO_DEVICE,而输出事件是INPUT_PASS_TO_HANDLERS,从系统到输入设备的驱动程序,如果你的驱动程序要处理这些事件,必须设置evbit中相应位,而且要实现一个回调函数。

struct input_dev *button_dev;

button_dev->event = button_event;这个便是处理输出事件的回调函数

三、普通按键实现input驱动例子

/*
drivers->input core->event handler
function: this file is button driver
date: 20150101
author: lei_wang
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/input.h>

static struct input_dev *button_dev;

static irqreturn_t button_intr(int irq, void *dev_id)
{
	int val;
	val = s3c2410_gpio_getpin(S3C2410_GPG(0));
//	printk(KERN_INFO "key value is %d\n", val);

	input_report_key(button_dev, BTN_0, val);
	input_sync(button_dev);

	return IRQ_RETVAL(IRQ_HANDLED);
}

static int __init button_init(void)
{
	int ret;
	ret = request_irq(IRQ_EINT8, button_intr, IRQ_TYPE_EDGE_BOTH, "button0", NULL);
	if (ret) {
		printk(KERN_ERR "%s request failed\n", __func__);
		return -ENODEV;
	}

	button_dev = input_allocate_device();
	if (!button_dev) {
		printk(KERN_ERR "button.c: Not enough memory\n");
		free_irq(IRQ_EINT8, NULL);
		return -ENOMEM;
	}

	button_dev->name = "button0";
	button_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY);
	button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);

	ret = input_register_device(button_dev);
	if (ret) {
		printk(KERN_ERR "button.c: Failed to register device\n");
		input_free_device(button_dev);
		free_irq(IRQ_EINT8, NULL);
		return -ENODEV;
	}

	printk(KERN_INFO "button init ok!\n");
	return 0;
}

static void __exit button_exit(void)
{
	input_unregister_device(button_dev);
	input_free_device(button_dev);
	free_irq(IRQ_EINT8, NULL);

	printk(KERN_INFO "button exit ok!\n");
}

module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Realsil Luckywang");

Makefile如下:

obj-m = button.o
KERNELDIR ?=/home/lei/linux-2.6.32.2
modules:
	$(MAKE) -C $(KERNELDIR) M=$(shell pwd) modules
clean:
	rm -rf *.o *.mod.c *.order *.symvers

Include/linux/bitops.h中定义了

#define BIT(nr) (1UL << (nr))

#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))

#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)

#define BTN_0 0x100

button_dev->evbit[0] = BIT_MASK(EV_KEY);

button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);

说明:

1)上面的0x100表示BTN_0这个bit在所有的bit中是0x100(bit
256)位,那么

BIT_WORD(BTN_0)代表bit 256在keybit这个数组的第几个数组(第8个)

BIT_MASK(BTN_0)代表bit 256在keybit这个数组的第几个数组里面的值(第8个数组的bit0)

2)事件类型type——编码code——值value

evbit是事件数组,evbit这个事件数组里面可以放很多事件类型,比如key、abs等

事件key里面又有很多具体编码BTN_0、BTN_TOUCH等

事件abs里面也有很多具体编码ABS_X、ABS_Y等

不同编码有不同的值

另外http://blog.csdn.net/ylyuanlu/article/details/6704744 这篇博客对以下说的挺详细的

1)input子系统的struct input_dev、struct handler的注册

2)struct input_dev与struct input_handler怎么互相匹配(类似于device和driver匹配)

3)事件处理过程

四、例子对应的应用程序

/*
20150101
just a simple input test code
lei_wang
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/input.h>

int main()
{
	int fd;
	int version;
	int ret;
	struct input_event ev;

	fd = open("/dev/input/event1", O_RDONLY);
	if (fd < 0) {
		printf("open file failed\n");
		exit(1);
	}

	ioctl(fd, EVIOCGVERSION, &version);
	printf("evdev driver version is 0x%x: %d.%d.%d\n",
					version, version>>16, (version>>8) & 0xff, version & 0xff);

	while (1) {
		ret = read(fd, &ev, sizeof(struct input_event));
		if (ret < 0) {
			printf("read event error!\n");
			exit(1);
		}

		if (ev.type == EV_KEY)
			printf("type %d,code %d, value %d\n", ev.type, ev.code, ev.value);
	}

	return 0;
}

以上只是一个简单的应用程序测试。当你按下K1的时候,串口终端会有显示的input dev上报的按键的消息。

另外还有很多里面ioctl调用的内容没有实验,具体可以参考这篇博客http://www.cnblogs.com/leaven/archive/2011/02/12/1952793.html,对ioctl的每个case以及read调用都试一遍,找到自己的体会。

时间: 2024-08-06 17:37:27

input子系统——架构、驱动、应用程序的相关文章

[arm驱动]input system 子系统的驱动编写

更多可参考 Linux输入子系统分析 input 子系统架构总结 1.定义一个static struct input_dev结构体 static struct input_dev *mybutton_dev; 2.初始化时分配input_dev结构体 mybutton_dev = input_allocate_device();//分配 input_dev /*能产生的事件类型 1. #define EV_SYN 0x00 /*表示设备支持所有的事件*/ 2. #define EV_KEY 0x

input子系统

以前,看过国嵌关于input子系统的视频课程,说实话,我看完后脑子里很乱,给我的印象好像是input子系统驱动是一个全新的驱动架构,疑惑相当多.前几天在网上,看到有很多人介绍韦东山老师的linux驱动课程很不错,于是,我就买了第二期的视频,看了韦老师讲解的input子系统视频课程后,我完全明白了整个input子系统的工作机制.为了方便以后查阅,对input子系统的整体框架总结如下: 典型的输入设备(如键盘.鼠标)的工作机制都是差不多的,都是在设备有动作时,向CPU产生一个中断,通知它读取相应的数

platform 总线input子系统上的按键中断

什么时候唤醒? 报告事件input_event(dev,x)  input_event(dev,y) input_event(dev,SYN) -------------------- Linux内核中的总线设备驱动 总线   include/device.h Struct bus_type { Name; Match;//(匹配规则,匹配设备和设备驱动) }: 注册:bus_register(....) 注销:bus_unregister(...): 设备 Struct device{ Str

Linux input子系统编程、分析与模板

输入设备都有共性:中断驱动+字符IO,基于分层的思想,Linux内核将这些设备的公有的部分提取出来,基于cdev提供接口,设计了输入子系统,所有使用输入子系统构建的设备都使用主设备号13,同时输入子系统也支持自动创建设备文件,这些文件采用阻塞的IO读写方式,被创建在"/dev/input/"下.如下图所示.内核中的输入子系统自底向上分为设备驱动层,输入核心层,事件处理层.由于每种输入的设备上报的事件都各有不同,所以为了应用层能够很好识别上报的事件,内核中也为应用层封装了标准的接口来描述

关于linux input device输入子系统架构及android中的框架

关于linux input device输入子系统架构及android中的框架 应用app和windowmanagerservice的input event通信方式 在Native层的InputChannel就是一个通道,仅仅是一个通道,仅仅具有通信功能,不包含其他的.至于从数据流动方向,与InputChannel无关.数据流向是由InputPublisher和InputConsumer在组合了InputChannel后决定的.把InputChannel由应用程序传递到WindowManageS

鼠标驱动之-sys节点-input子系统

首先需要了解sys节点和linux驱动编程的知识,在linux内核<linux/>下有着对应的实现.本例实现创建sys节点,外围程序通过input子系统控制鼠标位置. 第一步编写驱动代码,创建sys节点: #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/input.h> #include <

Android驱动之 Linux Input子系统之TP——A/B(Slot)协议

utm_source=tuicool&utm_medium=referral">点击打开链接 将A/B协议这部分单独拿出来说一方面是由于这部分内容是比較easy忽视的.周围大多数用到input子系统的开发者也不甚理解.还有一方面是由于这部分知识一旦扩展到TP(触摸屏Touch Panel)的多点触摸就要与Middleware/Framework一起结合起来看才干全然掌握,复杂性所在. 这里的Middleware/Framework是针对android来说的,本人从事android这

Linux input 子系统应用之按键驱动

硬件平台:s5pv210 软件平台:Linux2.6.35.7 应用程序:inputk2_app.c #include <stdio.h> #include <fcntl.h> #include <linux/input.h> #include <sys/types.h> #include <unistd.h> int main(int argc, char** argv) { int fd; int count; int i = 0; int

Android驱动之 Linux Input子系统之TP——A/B(Slot)协议【转】

转自:http://www.thinksaas.cn/topics/0/646/646797.html 将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围大多数用到input子系统的开发人员也不甚理解:另一方面是由于这部分知识一旦扩展到TP(触摸屏Touch Panel)的多点触摸就要与Middleware/Framework一起结合起来看才能完全掌握,复杂性所在.这里的Middleware/Framework是针对android来说的,本人从事android这几个层次的