输入子系统之按键驱动

上一篇博文《input输入子系统框架分析》,尝试使用这种驱动模型来看一个按键驱动程序。

下面的程序是根据韦东山老师写的代码进行修改的,我的开发板是tq2440。

button.c文件:

#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>

struct pin_desc{
	int irq;
	char *name;
	unsigned int pin;
	unsigned int key_val;
};

struct pin_desc pins_desc[4] = {
	{IRQ_EINT1, "S1", S3C2410_GPF1, KEY_L},
	{IRQ_EINT4, "S2", S3C2410_GPF4, KEY_S},
	{IRQ_EINT2, "S3", S3C2410_GPG2, KEY_ENTER},
	{IRQ_EINT0, "S4", S3C2410_GPG0, KEY_LEFTSHIFT},
};

static struct input_dev *buttons_dev;
static struct pin_desc *irq_pd;
static struct timer_list buttons_timer;

/* 去抖动按键设计要点:在中断处理函数启动定时器 */
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	/* 10ms后启动定时器 */
	irq_pd = (struct pin_desc *)dev_id;
	mod_timer(&buttons_timer, jiffies+HZ/100);
	return IRQ_RETVAL(IRQ_HANDLED);
}
/* 定时器处理函数 */
static void buttons_timer_function(unsigned long data)
{
	struct pin_desc * pindesc = irq_pd;
	unsigned int pinval;

	if (!pindesc)
		return;

	pinval = s3c2410_gpio_getpin(pindesc->pin);

	if (pinval)
	{
		/* 松开 : 最后一个参数: 0-松开, 1-按下 */
		input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);//向input核心层上报事件
		input_sync(buttons_dev); //发送同步信号
	}
	else
	{
		/* 按下 */
		input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
		input_sync(buttons_dev);
	}
}

static int buttons_init(void)
{
	int i;

	/* 1. 分配一个input_dev结构体 */
	buttons_dev = input_allocate_device();;

	/* 2. 设置 */
	/* 2.1 能产生哪类事件 */
	set_bit(EV_KEY, buttons_dev->evbit);
	set_bit(EV_REP, buttons_dev->evbit);

	/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
	set_bit(KEY_L, buttons_dev->keybit);
	set_bit(KEY_S, buttons_dev->keybit);
	set_bit(KEY_ENTER, buttons_dev->keybit);
	set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);

	/* 3. 注册按键输入设备 */
	input_register_device(buttons_dev);

	/* 4. 硬件相关的操作 */
	init_timer(&buttons_timer);//初始化定时器timer_list结构体
	buttons_timer.function = buttons_timer_function; //设置定时器响应函数
	add_timer(&buttons_timer); //把定时器添加到内核定时器链表

	for (i = 0; i < 4; i++)
	{//注册中断
		request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
	}

	return 0;
}

static void buttons_exit(void)
{
	int i;
	for (i = 0; i < 4; i++)
	{
		free_irq(pins_desc[i].irq, &pins_desc[i]);
	}

	del_timer(&buttons_timer);
	input_unregister_device(buttons_dev);
	input_free_device(buttons_dev);
}

module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");

驱动程序内容比较少,结合注释也容易理解,不再另做解析。

编译好这个驱动模块之后,加载进内核,发现生成了/dev/event1

使用hexdump指令测试驱动程序:

(1)hexdump /dev/event1

(2)然后按下一次按键,会打印如下数据:

0000000   0bb2 0000    0e48  000c    0001    0026    0001  0000

0000010   0bb2 0000    0e54  000c    0000    0000    0000  0000

0000020   0bb2 0000    5815  000e    0001    0026    0000  0000

0000030   0bb2 0000    581f   000e    0000    0000    0000  0000

(地址)                (秒)              (微妙)         (类)     (code)       (value)

小结:编写一个input驱动程序,需要我们完成哪些主要共作?

主要是完成设备驱动层的事情,事件处理层和核心层属于内核提供的稳定代码,正常只需要我们理解其中的工作原理,知道输入子系统的框架就好。

设备驱动层的工作在上一篇博文中第三点有小结。

时间: 2024-10-18 07:49:49

输入子系统之按键驱动的相关文章

基于输入子系统的按键驱动程序

输入子系统框图: 基于输入子系统的按键驱动程序步骤: 1.分配input_dev结构体 2.设置这个结构体 3.注册 4.硬件相关操作(有数据产生时调用 input_event来上报). 1.分配input_dev结构体 首先要定义这个结构体:static struct input_dev *buttons_dev; 然后在init函数中进行以下操作:buttons_dev = input_allocate_device(); 2.设置这个结构体 使用set_bit来设置这一个位,能设置以下参数

输入子系统------键盘按键驱动程序

由上一节的输入子系统的框架分析可知,其分三层:设备驱动层,核心层,事件驱动层 我们在为某种设备的编写驱动层,只需要关心设备驱动层,即如何驱动设备并获得硬件数据(如按下的按键数据),然后调用核心层提供的接口,核心层就会自动把数据提交给事件处理层.在输入子系统中,事件驱动是标准的,适用于所有输入类的.我们的设备可以利用一个已经存在的,合适的输入事件驱动,通过输入核心,和用户应用程序接口. 一.编写设备驱动层的流程 1.分配一个input--dev结构体 2.设置input_dev的成员 3.注册in

ARM Linux 驱动Input子系统之按键驱动测试

上一篇已经谈过,在现内核的中引入设备树之后对于内核驱动的编写,主要集中在硬件接口的配置上了即xxxx.dts文件的编写. 在自己的开发板上移植按键驱动: 1.根据开发板的原理图 确定按键的硬件接口为:GPIO2_2.GPIO2_3.GPIO2_5.GPIO0_30. 修改dts文件使其与原理图的按键接口一致. gpio_buttons: [email protected]0 { compatible = "gpio-keys"; #address-cells = <1>;

Linux驱动之输入子系统框架

    好记性不如烂笔头,整理一下笔记~ Linux驱动之输入子系统框架 输入子系统将该类驱动划分为3部分 1.核心层 input.c 2.设备层 Gpio_keys.c ... 3.事件处理层 Evdev.c 事件处理层为纯软件的东西,设备层涉及底层硬件,它们通过核心层建立联系,对外提供open write等接口. 1.我们首先来看,核心层 input.c如何向外界提供接口 在 input_init 中注册了字符设备驱动 register_chrdev(INPUT_MAJOR, "input&

Linux 驱动——Button8(输入子系统)

输入子系统由驱动层.输入子系统核心.事件处理层三部分组成.一个输入事件,如鼠标移动.键盘按下等通过Driver->Inputcore->Event handler->userspace的顺序到达用户控件的应用程序. 其中核心层提供一些设备层与事件层公用的函数,比如说注册函数.反注册函数.事件到来的处理函数等等:事件层其实在Linux内核里面已经帮我们写好了很多有关的事件:而设备层就跟我们新添加到输入系统的具体设备相关了.这里以JZ2440开发板上的4个按键作为输入子系统的按键:它定义的功

Linux输入子系统框架分析(1)

在Linux下的输入设备键盘.触摸屏.鼠标等都可以用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层,事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备驱动层将输入事件上报给核心层input.c,核心层找到匹配的事件层,将事件交给事件层处理,事件层处理完后传递到用户空间. 我们最终要搞清楚的是在用户空间调用open和read最终在内核中是怎样处理的,向内核上报的事件又是谁处理的,处理完后是怎样传递到用户空间的? 上面两个图是输入子系统的框架. 下面

Linux输入子系统

在Linux中,按键.触摸屏.鼠标等等输入设备都可以依靠输入子系统提供的接口函数来实现他们的设备驱动,在输入子系统中,系统已经完成了这些输入设备的共性,所以根据子系统提供的接口,只需要完成各自的独特性即可完成一个输入设备的设备驱动. Linux中,输入子系统由设备驱动层.核心层.事件处理层这三层组成.设备驱动层讲底层输入设备的响应转化为标准的输入事件,事件处理层就为应用程序提供统一的设备访问接口来跟底层交互数据,核心层则是连接驱动层和事件处理层的桥梁. 在输入子系统中重要的结构体就是input_

Android 输入子系统

输入子系统模型: 输入子系统由设备驱动层(input device driver),核心层(input core)和事件驱动层(event driver)三部份组成. 任何一次输入事件, 如鼠标移动, 按键按下, 都需要通过InputDeviceDriver- >InputCore- >EventDrive才能到达用 户 空间的应用程序. 设备驱动层:将底层的硬件输入转化为统一事件型式, 向输入核心( InputCore)汇报.v 输入核心层:为设备驱动层提供输入设备注册与操作接口 , 如:为

20150301 IMX257 输入子系统

20150301 IMX257 输入子系统 2015-03-01 李海沿 一.输入子系统 1.输入子系统结构体定义 struct input_dev{ const char *name; 设备名 const char *phys; 设备在系统中路径 const char *uniq; struct input_id id; 用于匹配input hander参数 unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long