嵌入式linux驱动-输入子系统笔记

2019-07-12 19:03发布

一、开发环境 1、内核:Linux 2.6.22.6; 2、JZ2440 3、ubuntu 9.10
二、过程 1、分配input_dev结构体    使用input_allocate_device函数,如: 先定义一个input_dev 结构体类型变量:static struct input_dev *key_dev;
使用input_allocate_device函数分配key_dev=input_allocate_device();
2、设置input_dev  input_dev结构体成员有: struct input_dev {  
    const char *name;  
    const char *phys;  
    const char *uniq;  
    struct input_id id;  
  
    unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件  
    unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键  
    unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮  
    unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y  
    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)];  
    ...  
 }
先设置哪类操作,再设置这类操作的哪些事件,如 /* 2.1 设置按键能产生哪类事件 */  set_bit(EV_KEY,key_dev->evbit);//EV_KEY表示按键操作
set_bit(EV_REP,key_dev->evbit);//EV_REP表示按键重复操作  
/* 2.2 设置能产生这类操作的哪些事件 */  
set_bit(KEY_L,key_dev->keybit);//KEY_L表示按了L键
set_bit(KEY_S,key_dev->keybit);//KEY_S表示按了S键
set_bit(KEY_ENTER,key_dev->keybit);//ENTER表示按了ENTER键
set_bit(KEY_LEFTSHIFT,key_dev->keybit);//KEY_LEFTSHIFT表示按了左边的SHIFT键
另外: input.h里有以下类
#define EV_SYN          0x00    //同步类  
#define EV_KEY          0x01    //按键类  
#define EV_REL          0x02    //相对位移类  
#define EV_ABS          0x03    //绝对位移类  
#define EV_MSC          0x04      
#define EV_SW           0x05  
#define EV_LED          0x11  
#define EV_SND          0x12    //声音类  
#define EV_REP          0x14    //重复类  
#define EV_FF           0x15  
#define EV_PWR          0x16  
#define EV_FF_STATUS        0x17  
#define EV_MAX          0x1f  
#define EV_CNT          (EV_MAX+1)  3、注册 使用input_register_device(struct input_dev *dev)函数来注册,如:input_register_device(key_dev);
4、硬件相关操作 具体应用具体写了。比如本实验中使用到定时器,初始化定时器,使用按键注册中断等。 5、程序 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct key_desc{ int irq; char *name; unsigned int pin; unsigned int key_val; }; struct key_desc key_desc[4]={ {IRQ_EINT0,"s2",S3C2410_GPF0,KEY_L}, {IRQ_EINT2,"s3",S3C2410_GPF2,KEY_S}, {IRQ_EINT11,"s4",S3C2410_GPG3,KEY_ENTER}, {IRQ_EINT19,"s5",S3C2410_GPG11,KEY_LEFTSHIFT}, }; static struct input_dev *key_dev; static struct key_desc *irq_tmp; static struct timer_list key_timer; static irqreturn_t key_irq(int irq, void *dev_id) {    // printk("key_irq!irq=%d ",irq); irq_tmp=(struct key_desc*)dev_id; mod_timer(&key_timer, jiffies + HZ/100); return IRQ_RETVAL(IRQ_HANDLED); } static void key_timer_func(unsigned long __data) { struct key_desc * keysdesc=irq_tmp; unsigned int keyval; //printk("key_timer_func! "); if (!keysdesc) { //printk("keysdesc "); return; } keyval=s3c2410_gpio_getpin(keysdesc->pin); if(keyval) {//松开 input_event(key_dev,EV_KEY,keysdesc->key_val,0); input_sync(key_dev); // printk("input_event0! "); } else {//按下 input_event(key_dev,EV_KEY,keysdesc->key_val,1); input_sync(key_dev); // printk("input_event1! "); } } static int  key_init(void) { int i; printk("key_init! "); //分配一个input_dev结构体 key_dev=input_allocate_device(); //设置 set_bit(EV_KEY,key_dev->evbit); set_bit(EV_REP,key_dev->evbit); set_bit(KEY_L,key_dev->keybit); set_bit(KEY_S,key_dev->keybit); set_bit(KEY_ENTER,key_dev->keybit); set_bit(KEY_LEFTSHIFT,key_dev->keybit); //注册 input_register_device(key_dev); //硬件相关操作 //定时器初始化 init_timer(&key_timer); key_timer.function = key_timer_func; add_timer(&key_timer); for(i=0;i<4;i++) { request_irq(key_desc[i].irq,key_irq ,IRQT_BOTHEDGE,key_desc[i].name,&key_desc[i]); } return 0; } static void key_exit(void) { int i; printk("key_exit! "); for(i=0;i<4;i++) { free_irq(key_desc[i].irq,&key_desc[i]); } del_timer(&key_timer); input_unregister_device(key_dev); input_free_device(key_dev); } module_init(key_init); module_exit(key_exit); MODULE_LICENSE("GPL");
三、架构相关 1、驱动中按键松开、按下时调用input_event()函数把keysdesc->key_val即结构体 struct key_desc key_desc[4]={
{IRQ_EINT0,"s1",S3C2410_GPF0,KEY_L},
{IRQ_EINT2,"s2",S3C2410_GPF2,KEY_S},
{IRQ_EINT11,"s3",S3C2410_GPG3,KEY_ENTER},
{IRQ_EINT19,"s4",S3C2410_GPG11,KEY_LEFTSHIFT},
};
中的KEY_L,KEY_S,KEY_ENTER,KEY_LEFTSHIFT,传递给内核。
input_event()函数中有: list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);

实现了从input_dev到input_handle到input_handler的调用。即从硬件层到两者的连接层到驱动层的调用。我们写的程序调用input_event()函数,input_event中通过dev->h_list找到input_handle,input_handle通过其成员handler找到event。 2、韦分层框架截图
四、命令 hexdump /dev/event1 hex显示/dev/event1 exec 0event,如下 # ls -l /dev/event*
ls: /dev/event*: No such file or directory
解决:配置内核时选上Device Drivers->Input device support->Event interface && Event debugging。下载新内核到板子上。再重新make下编写的输入子系统。 加载子系统后,结果如下 六、结果