嵌入式linux按键驱动编写记录
转自http://rainy0415.blog.163.com/blog/static/16851166201062155551110/
//内核版本:linux2.6.20
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEBUG 0
MODULE_AUTHOR("YUMEI");
MODULE_DESCRIPTION("");
MODULE_LICENSE("GPL");
//按键对应的键码,在include/linux/input.h中有对键码的定义
//代码植0~127为键盘上的按键代码
//0x110~0x116 为鼠标上按键代码,其中0x110(BTN_ LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标右键,0x112(BTN_ MIDDLE)为鼠标中键.
//其它代码含义请参看include/linux/input.h文件.
static unsigned char keyboard_scancode[] =
{
KEY_A,KEY_B,KEY_C,KEY_D
};
const char devname[] = "keyboard";
const char phyname[] = "/dev/input/keybaord";
//输入设备结构体
struct input_dev *keyboard_dev;
static int keyvalue[4];
//中断处理函数
irqreturn_t keyboard_interrupt_key1(int irq, void *dev_id)
{
unsigned int i;
//屏蔽中断号为AT91_PIN_PA25的中断
disable_irq(AT91_PIN_PA25);
mdelay(20);
if(at91_get_gpio_value(AT91_PIN_PA25))
{
keyvalue[0] = 1;
}
else
{
keyvalue[0] = 0;
}
mdelay(20);
if(keyvalue[0] == 0)
{
if(!at91_get_gpio_value(AT91_PIN_PA25))
{
/*
void input_report_key(struct input_dev*dev,unsigned int code,int value);
该函数用于向input subsystem 报告按键事件;
code 为按键键码,标准按键键码详见input.h
value:0为按键抬起;1为按键按下
*/
input_report_key(keyboard_dev,keyboard_scancode[0], 1);
input_sync(keyboard_dev);
while(!at91_get_gpio_value(AT91_PIN_PA25));
for(i=0;i<2;++i)
{
mdelay(20);
if(!at91_get_gpio_value(AT91_PIN_PA25))
{
break;
}
}
if(i >= 2)
{
#ifdef DEBUG
printk("KEY0
");
#endif
input_report_key(keyboard_dev,keyboard_scancode[0], 0);
input_sync(keyboard_dev);
}
}
}
//使能中断号为AT91_PIN_PA25的中断
enable_irq(AT91_PIN_PA25);
return 0;
}
int keyboard_open(struct input_dev *dev)
{
return 0;
}
void keyboard_close(struct input_dev *dev)
{
return 0;
}
int keyboard_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
return 0;
}
/*
//驱动模块加载函数
//说明:输入子系统(input subsystem)的驱动层的核心结构。
//头文件:include/linux/input.h
//结构体:struct input_dev
//成员说明:
struct input_dev
{
void *private; //可以指向任何输入设备驱动中的结构体数据
const char *name; //设备名字,如键盘名字。
const char *phys; //不清楚,但不是设备节点的名称,键盘类自动映射到/dev/input下的event0 或者 event1,可通过cat查看;
const char *uniq; //全球唯一的ID号
struct input_id id;//设备ID,包括生产厂商ID,产品ID等
unsigned long evbit[NBITS(EV_MAX)];//该设备驱动所能支持的事件。
//EV_SYN 同步事件
//EV_KEY 键盘事件
//EV_REL 相对坐标事件,用于鼠标
//EV_ABS 绝对坐标事件,用于摇杆
//EV_MSC 其他事件
//EV_LED LED灯事件
//EV_SND 声音事件
//EV_REP 重复按键事件
//EV_FF 受力事件
//EV_PWR 电源事件
//EV_FF_STATUS 受力状态事件
unsigned long keybit[NBITS(KEY_MAX)]; //支持事件的键值存放表,可参照include/linux/input.h,也可以自己定义
unsigned long relbit[NBITS(REL_MAX)]; //用于存放相对坐标值等
unsigned long absbit[NBITS(ABS_MAX)]; //用于存放绝对坐标值等
unsigned long mscbit[NBITS(MSC_MAX)]; //存放其他事件类型
unsigned long ledbit[NBITS(LED_MAX)]; //存放表示各种状态的LED值
unsigned long sndbit[NBITS(SND_MAX)]; //存放各种事件的声音
unsigned long ffbit[NBITS(FF_MAX)];
//存放受力设备的属性
unsigned long swbit[NBITS(SW_MAX)];
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
struct ff_device *ff;
unsigned int repeat_key; //存放重复按键时的键值
struct timer_list timer;
int state;
int sync;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];//存放重复按键时的延时,系统依靠这个延时时间来判断重复按键
//rep[0]表示开始要重复按键时的延时时间,即第1个键与第2个键(开始重复按键)之间的延时
//rep[1]此后重复按键之前的延时时间,直到按键抬起
//通俗解释就是,假如我按了一个“a”,并且一直按着,那么在显示出来的第一个a与第二个a之间的时间延时为rep[0],而此后的相邻两个a之间的延时为rep[1]
unsigned long key[NBITS(KEY_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)];
unsigned long sw[NBITS(SW_MAX)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
//底层与硬件相关的一组操作,若有具体定义,则会在input core层被调用,具体看input.c。
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle *grab; //该结构会在后文做具体介绍,这个指针用于占用输入设备用,如键盘
struct mutex mutex;
// serializes open and close operations
unsigned int users;
struct class_device cdev;
struct list_head
h_list; //h_list链表用于与input_handler相联系
struct list_head
node; //node链表:设备向输入子系统(input subsystem)注册后,会将该链表添加到系统维护的一个链表中去,从而系统可以管理这个设备
};
*/
static int __init keyboard_init(void)
{
int result;
unsigned int i;
#ifdef DEBUG
printk(KERN_ALERT "keyboard_test:%s,%s
",__DATE__,__TIME__);
#endif
//memset(keyboard_dev,0,sizeof(struct input_dev));
keyboard_dev = input_allocate_device();
keyboard_dev->private = keyboard_dev;
keyboard_dev->name = devname;
keyboard_dev->phys = phyname;
keyboard_dev->evbit[0] = BIT(EV_KEY);
for(i=0;i<4;++i)
{
set_bit(keyboard_scancode[i], keyboard_dev->keybit);
}
keyboard_dev->open = keyboard_open;
keyboard_dev->close = keyboard_close;
keyboard_dev->event = keyboard_event;
//向系统注册输入子系统驱动
result = input_register_device(keyboard_dev);
if (result < 0)
{
#ifdef DEBUG
printk("register device fail.
");
#endif
return result;
}
at91_set_gpio_input(AT91_PIN_PA25,0);
at91_set_gpio_input(AT91_PIN_PA26,0);
at91_set_gpio_input(AT91_PIN_PA27,0);
at91_set_gpio_input(AT91_PIN_PA28,0);
at91_set_deglitch(AT91_PIN_PA25,0);
at91_set_deglitch(AT91_PIN_PA26,0);
at91_set_deglitch(AT91_PIN_PA27,0);
at91_set_deglitch(AT91_PIN_PA28,0);
/*
request_irq的作用是申请使用IRQ并注册中断处理程序。
request_irq()函数位于kernel/irq/manage.c;
request_irq()函数的原型如下:
int request_irq(
unsigned int irq, //申请中断向量号,视具体芯片而定
irqreturn_t (*handler)(int, void *, struct pt_regs *), //中断处理函数
unsigned long irqflags, //中断类型
const char *devname, //设备名称
void *dev_id ); //设备结构体指针
*/
result = request_irq(AT91_PIN_PA25,keyboard_interrupt_key1, IRQF_TRIGGER_FALLING, "keyboard", keyboard_dev);
if (result < 0)
{
#ifdef DEBUG
printk("register irq fail.%d
",result);
#endif
return result;
}
return 0;
}
static void __exit keyboard_exit(void)
{
printk("stop keyboard
");
//释放中断资源
free_irq(AT91_PIN_PA25,&keyboard_dev);
//卸载输入子系统驱动
input_unregister_device(keyboard_dev);
printk(KERN_ALERT "stop clear keyboard
");
}
module_init(keyboard_init);
module_exit(keyboard_exit);
备注:驱动加载后,对应的设备文件为/dev/input/event0 或者 event1,可通过cat 命令进行查看;
可通过进程showkey -s查看按键扫描码,showkey -k 查看按键键码;
也可以通过如下程序进行查看;
应用层查看按键键码的程序如下:
#include
#include
#include
#include
#include
#include
struct input_event buff;
int fd;
int read_nu;
int main(int argc, char *argv[])
{
fd = open("/dev/input/event1", O_RDONLY);
if (fd < 0)
{
perror("can not open device usbkeyboard!");
exit(1);
}
int i = 0;
printf("--fd:%d--
",fd);
while(1)
{
while(read(fd,&buff,sizeof(struct input_event))==0)
{
;
}
//if(buff.code > 40)
printf("type:%d code:%d value:%d
",buff.type,buff.code,buff.value);
//#if 0
//i++;
//if(i > 12)
//{
//break;
//}
//#endif
}
close(fd);
return 1;
}