输入子系统框架的驱动程序步骤:
1. 分配一个input_dev结构体
2. 设置
3. 注册
4. 硬件相关的代码,比如中断注册,定时器注册等等。
下面分别介绍下相关实现代码
1.分配一个input_dev结构体
input_dev在<linux/input.h>文件定义,结构体原型如下:
struct input_dev { const char *name; const char *phys; const char *uniq; struct input_id id; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; ....... }
/*1.分配一个input_dev结构*/ buttons_dev = input_allocate_device(); if (!buttons_dev) { printk("input_allocate failed!\n"); error = -ENOMEM; return error; }
/*2.设置 2.1 设置按键能产生哪类事件 */ set_bit(EV_KEY, buttons_dev->evbit); set_bit(EV_REP, buttons_dev->evbit); /* 2.2 设置能产生这类操作的哪些事件 */ set_bit(KEY_A, buttons_dev->keybit); set_bit(KEY_B, buttons_dev->keybit); 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);EV_KEY & EV_REP表示按键类,可重复
3.注册
error = input_register_device(buttons_dev); if (error) { printk("input_register_device failed!\n"); error = -ENOMEM; return error; }
/*3.硬件相关配置*/ /*3.1初始化定时器*/ init_timer(&buttons_timer); buttons_timer.function = mini2440_timer_handler; add_timer(&buttons_timer); /*3.2中断配置*/ for(i=0;i<BUTTON_NUM;i++) { error = request_irq(button_irqs[i].irq, button_irq,IRQ_TYPE_EDGE_BOTH,\ button_irqs[i].name,&button_irqs[i]); if (error) { printk("request_irq failed!\n"); error = -ENOMEM; return error; } }
#include <linux/module.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/gpio_keys.h> #include <linux/workqueue.h> #include <asm/gpio.h> static struct input_dev *buttons_dev; static struct timer_list buttons_timer; #define BUTTON_NUM 6 struct button_irq_desc { int irq; int pin; int pin_val; char *name; }; static struct button_irq_desc button_irqs [] = { {IRQ_EINT8 , S3C2410_GPG(0) , KEY_A , "KEY0"}, {IRQ_EINT11, S3C2410_GPG(3) , KEY_B , "KEY1"}, {IRQ_EINT13, S3C2410_GPG(5) , KEY_L , "KEY2"}, {IRQ_EINT14, S3C2410_GPG(6) , KEY_S , "KEY3"}, {IRQ_EINT15, S3C2410_GPG(7) , KEY_ENTER, "KEY4"}, {IRQ_EINT19, S3C2410_GPG(11), KEY_LEFTSHIFT, "KEY5"}, }; struct button_irq_desc * irq_pq; static irqreturn_t button_irq(int irq, void *dev_id) { irq_pq = (struct button_irq_desc *)dev_id; mod_timer(&buttons_timer,jiffies+HZ/100); return IRQ_RETVAL(IRQ_HANDLED); } static void mini2440_timer_handler(unsigned long dat) { struct button_irq_desc * pindesc = irq_pq; unsigned int pinval; if(!pindesc) return; pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval) { /* 松开 ,最后一个参数设置为0*/ input_event(buttons_dev,EV_KEY,pindesc->pin_val,0); input_sync(buttons_dev); } else { /* 按下 ,最后一个参数设置为1*/ input_event(buttons_dev,EV_KEY,pindesc->pin_val,1); input_sync(buttons_dev); } } static int mini2440_buttons_init(void) { int error,i; /*1.分配一个input_dev结构*/ buttons_dev = input_allocate_device(); if (!buttons_dev) { printk("input_allocate failed!\n"); error = -ENOMEM; return error; } /*2.设置 2.1 设置按键能产生哪类事件 */ set_bit(EV_KEY, buttons_dev->evbit); set_bit(EV_REP, buttons_dev->evbit); /* 2.2 设置能产生这类操作的哪些事件 */ set_bit(KEY_A, buttons_dev->keybit); set_bit(KEY_B, buttons_dev->keybit); 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); error = input_register_device(buttons_dev); if (error) { printk("input_register_device failed!\n"); error = -ENOMEM; return error; } /*3.硬件相关配置*/ /*3.1初始化定时器*/ init_timer(&buttons_timer); buttons_timer.function = mini2440_timer_handler; add_timer(&buttons_timer); /*3.2中断配置*/ for(i=0;i<BUTTON_NUM;i++) { error = request_irq(button_irqs[i].irq, button_irq,IRQ_TYPE_EDGE_BOTH,\ button_irqs[i].name,&button_irqs[i]); if (error) { printk("request_irq failed!\n"); error = -ENOMEM; return error; } } return 0; } static void mini2440_buttons_exit(void) { int i; for(i=0;i<BUTTON_NUM;i++) { free_irq(button_irqs[i].irq,&button_irqs[i]); } del_timer(&buttons_timer); input_unregister_device(buttons_dev); input_free_device(buttons_dev); } /* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(mini2440_buttons_init); module_exit(mini2440_buttons_exit); /* 描述驱动程序的一些信息,不是必须的 */ MODULE_LICENSE("GPL");
注意此时的event1路径在/dev/input下,非韦老师视频中的/dev/目录下。
使用hexdump命令测试
hexdump相关代码:
struct input_event { struct timeval time; //时间 __u16 type; //类 __u16 code; //类下事件的值 __s32 value; //0-松开, 1-按下,2-重复 }; struct timeval { __kernel_time_t tv_sec; //秒 __kernel_suseconds_t tv_usec; //微秒 };