码迷,mamicode.com
首页 > 其他好文 > 详细

输入子系统之按键驱动

时间:2015-04-21 22:38:41      阅读:244      评论:0      收藏:0      [点我收藏+]

标签:

上一篇博文《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驱动程序,需要我们完成哪些主要共作?

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

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


输入子系统之按键驱动

标签:

原文地址:http://blog.csdn.net/clb1609158506/article/details/45176717

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!