驱动程序之驱动程序之_1_字符设备_9_输入子系统_2_实例
本文中input_handler层使用evdev,在input_dev层编写按键实例
基本流程:
1、编写入口函数,分配、设置、注册input_dev结构体,并且完成硬件初始化
2、编写出口函数,完成与入口函数相反的操作
3、声明、定义硬件相关结构体和定时器
4、编写按键中断服务程序
5、编写定时器中断服务程序,定时时间为10ms,用于消抖
6、添加相关头文件
附上完整代码
#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 <linux/irq.h>
#include <linux/gpio_keys.h>
#include <asm/gpio.h>
/* 结构体的声明和定义 */
typedef struct{
unsigned char *pucDevName;
int dwIrq;
unsigned long dwIrqFlags;
unsigned int dwPin;
unsigned int dwVal;
}buttons_desc, *pbuttons_desc;
buttons_desc g_tButtonsDesc[4] =
{
{"S2",IRQ_EINT0, IRQT_BOTHEDGE,S3C2410_GPF0 ,KEY_L},
{"S3",IRQ_EINT2, IRQT_BOTHEDGE,S3C2410_GPF2 ,KEY_S},
{"S4",IRQ_EINT11,IRQT_BOTHEDGE,S3C2410_GPG3 ,KEY_ENTER},
{"S5",IRQ_EINT19,IRQT_BOTHEDGE,S3C2410_GPG11,KEY_LEFTSHIFT},
};
static struct input_dev *g_ptButtonsDev;
static struct timer_list g_tButtonsTimer;
static pbuttons_desc g_ptButtonsDescSelect;
/* 定时器中断服务程序 */
static void buttons_timer_isr(unsigned long data)
{
pbuttons_desc g_ptButtonsDescTmp = g_ptButtonsDescSelect;
if(!g_ptButtonsDescTmp)
return ;
if(s3c2410_gpio_getpin(g_ptButtonsDescTmp->dwPin)) //松开
{
input_event(g_ptButtonsDev,EV_KEY,g_ptButtonsDescTmp->dwVal,0);
input_sync(g_ptButtonsDev);
}
else
{
input_event(g_ptButtonsDev,EV_KEY,g_ptButtonsDescTmp->dwVal,1);
input_sync(g_ptButtonsDev);
}
}
/* 按键中断服务程序 */
static irqreturn_t buttons_isr(int irq, void *dev_id)
{
g_ptButtonsDescSelect = (pbuttons_desc)dev_id;
mod_timer(&g_tButtonsTimer, jiffies + HZ / 100);
return IRQ_RETVAL(IRQ_HANDLED);
}
/* 入口函数 */
static int input_init(void)
{
int i;
int iError;
/* 分配设置注册结构体 */
g_ptButtonsDev = input_allocate_device();
set_bit(EV_KEY, g_ptButtonsDev->evbit);
set_bit(EV_REP, g_ptButtonsDev->evbit);
set_bit(KEY_L, g_ptButtonsDev->keybit);
set_bit(KEY_S, g_ptButtonsDev->keybit);
set_bit(KEY_LEFTSHIFT,g_ptButtonsDev->keybit);
set_bit(KEY_ENTER, g_ptButtonsDev->keybit);
input_register_device(g_ptButtonsDev);
/* 创建定时器并设置其中断服务程序 */
init_timer(&g_tButtonsTimer);
g_tButtonsTimer.function = buttons_timer_isr;
add_timer(&g_tButtonsTimer);
/* 设置按键中断 */
for(i = 0;i < 4;i++)
iError = request_irq(g_tButtonsDesc[i].dwIrq,buttons_isr,g_tButtonsDesc[i].dwIrqFlags,
g_tButtonsDesc[i].pucDevName,&g_tButtonsDesc[i]);
return 0;
}
/* 出口函数 */
static void input_exit(void)
{
int i;
/* 关闭按键中断 */
for(i = 0;i < 4;i++)
free_irq(g_tButtonsDesc[i].dwIrq,&g_tButtonsDesc[i]);
/* 销毁定时器 */
del_timer(&g_tButtonsTimer);
/* 销毁结构体 */
input_unregister_device(g_ptButtonsDev);
}
module_init(input_init);
module_exit(input_exit);
MODULE_LICENSE("GPL");
测试方法:
cat /dev/event*
加载驱动设备,再次cat /dev/event*,会多出一个event
1、hexdump /dev/event1(event1是加载驱动设备后新出现的event,根据实际情况修改),按下按键会回显按键事件的时间、键值码、类型等信息
2、cat /dev/tty1,按下字母按键,再按下回车按键,会回显字母信息,由于使能了REP事件,所以按键长按有效
3、exec 0</dev/tty1,按下’l’,‘s’,再按下"enter",这时不仅回显信息,并且按键传入控制台,效果相当于键盘输入"ls"