嵌入式linux按键驱动编写记录

2019-07-12 19:04发布

嵌入式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; }