linux输入子系统之按键驱动

来源:互联网 发布:手指泡水起皱 知乎 编辑:程序博客网 时间:2024/05/18 02:13

上一节中,我们讲解了Linux  input子系统的框架,到内核源码里详细分析了输入子系统的分离分层的框架等。

上一节文章链接:http://blog.csdn.net/lwj103862095/article/details/17733993

这一节,我们来以输入子系统的框架来写一个按键驱动。

问:怎么写符合输入子系统框架的驱动程序?

答:
1. 分配一个input_dev结构体: 在驱动中必须动态分配input_dev结构,使用input_allocate_device
2. 设置
set_bit
3. 注册:input_register_device(struct input_dev *dev)

4. 硬件相关的代码,比如在中断服务程序里上报事件

include/linux/input.h
void input_event(struct input_dev *dev, unsigned int type, unsigned int code,int value)
//input_report_key(struct input_dev *dev, unsigned int code, int value)
input_event(dev, EV_REL, code, value);其他类推

void input_sync(struct input_dev *dev)用于事件同步,它告知事件的接收者:驱动已经发出了一个完整的报告。
//
input_event(dev, EV_SYN, SYN_REPORT, 0);
void input_mt_sync(struct input_dev *dev)
//input_event(dev, EV_SYN, SYN_MT_REPORT, 0);


5、注销input设备,释放资源

void input_unregister_device(struct input_dev *dev

void input_free_device(struct input_dev *dev)

问:如何分配input_dev结构体?

答:使用input_allocate_device函数

input_dev结构体的重要成员

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. struct input_dev {  
  2.     const char *name;  
  3.     const char *phys;  
  4.     const char *uniq;  
  5.     struct input_id id;  
  6.   
  7.     unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件  
  8.     unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键  
  9.     unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮  
  10.     unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y  
  11.     unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];  
  12.     unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];  
  13.     unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];  
  14.     unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];  
  15.     ...  
  16. }  
问:第二步的设置,应该怎么设置,应该设置什么?

答:举例,在此按键驱动里

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. /* 2.设置 */  
  2. /* 2.1 设置按键能产生哪类事件 */  
  3. set_bit(EV_KEY,buttons_dev->evbit);  
  4. set_bit(EV_REP,buttons_dev->evbit);  
  5.   
  6. /* 2.2 设置能产生这类事件的哪些操作 */  
  7. set_bit(KEY_L,buttons_dev->keybit);  
  8. set_bit(KEY_S,buttons_dev->keybit);  
  9. set_bit(KEY_ENTER,buttons_dev->keybit);  
  10. set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);  

问:有哪些事件呢?

答:在input.h里有以下类

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #define EV_SYN          0x00    //同步事件 
  2. #define EV_KEY          0x01    //按键事件  
  3. #define EV_REL          0x02    //相对位移事件 (如:鼠标移动,报告相对最后一次位置的偏移)  
  4. #define EV_ABS          0x03    //绝对位移事件 (如:触摸屏或操作杆,报告绝对的坐标位置)
  5. #define EV_MSC          0x04    //其他  
  6. #define EV_SW           0x05  //开关
  7. #define EV_LED          0x11  //按键/设备灯
  8. #define EV_SND          0x12    //声音事件 
  9. #define EV_REP          0x14    //重复事件 
  10. #define EV_FF           0x15  //力反馈
  11. #define EV_PWR          0x16  //电源
  12. #define EV_FF_STATUS    0x17  //力反馈状态
  13. #define EV_MAX          0x1f  //事件类型最大个数和提供位掩码支持
  14. #define EV_CNT          (EV_MAX+1)  

问:如何注册?

答:使用input_register_device(struct input_dev *dev)函数来注册

问:此按键驱动的硬件操作包括哪些操作?

答:申请定时器、申请中断操作,上报事件

include/linux/input.h

void input_event(struct input_dev *dev, unsigned int type, unsigned int code,int value)
//input_report_key(struct input_dev *dev, unsigned int code, int value)
input_event(dev, EV_REL, code, value);其他类推

void input_sync(struct input_dev *dev) 用于事件同步,它告知事件的接收者:驱动已经发出了一个完整的报告。
//
input_event(dev, EV_SYN, SYN_REPORT, 0);
void input_mt_sync(struct input_dev *dev) 
//input_event(dev, EV_SYN, SYN_MT_REPORT, 0);

驱动源码:

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include <linux/kernel.h>  
  2. #include <linux/fs.h>  
  3. #include <linux/init.h>  
  4. #include <linux/delay.h>  
  5. #include <linux/irq.h>  
  6. #include <asm/uaccess.h>  
  7. #include <asm/irq.h>  
  8. #include <asm/io.h>  
  9. #include <linux/module.h>  
  10. #include <linux/device.h>         //class_create  
  11. #include <mach/regs-gpio.h>       //S3C2410_GPF1  
  12. //#include <asm/arch/regs-gpio.h>    
  13. #include <mach/hardware.h>  
  14. //#include <asm/hardware.h>  
  15. #include <linux/interrupt.h>  //wait_event_interruptible  
  16. #include <linux/poll.h>   //poll  
  17. #include <linux/fcntl.h>  
  18. #include <linux/input.h>  
  19.   
  20. static struct pin_desc{  
  21.     int irq;  
  22.     unsigned char *name;  
  23.     unsigned int pin;  
  24.     unsigned int key_val;  
  25. };  
  26.   
  27. static struct pin_desc pins_desc[4] = {  
  28.         {IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},  
  29.         {IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},  
  30.         {IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},  
  31.         {IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},  
  32. };   
  33.   
  34. static struct pin_desc *irq_pd;  
  35. static struct input_dev *buttons_dev;  
  36. static struct timer_list buttons_timer;  
  37.   
  38. /* 用户中断处理函数 */  
  39. static irqreturn_t buttons_irq(int irq, void *dev_id)  
  40. {  
  41.      int ret;
  42.     irq_pd = (struct pin_desc *)dev_id;  
  43.       
  44.     /* 修改定时器定时时间,定时10ms,即10秒后启动定时器 
  45.      * HZ是每秒系统节拍数,这里是100个jiffies,所以每个jiffies是10ms
  46.      */  
  47.     ret = mod_timer(&buttons_timer, jiffies + (HZ /100));  
  48.     if(ret == 1){
            printk("mod timer success\n");
        }
  49.     return IRQ_HANDLED;  
  50. }  
  51.   
  52.   
  53. /* 定时器处理函数 */  
  54. static void buttons_timer_function(unsigned long data)  
  55. {  
  56.     struct pin_desc *pindesc = irq_pd;  
  57.     unsigned int pinval;  
  58.     pinval = s3c2410_gpio_getpin(pindesc->pin);  
  59.   
  60.     if(pinval)  
  61.     {  
  62.         /* 松开 最后一个参数: 0-松开, 1-按下 */  
  63.         input_event(buttons_dev,EV_KEY,pindesc->key_val,0);
  64.        //等同input_report_key(buttons_dev,pindesc->key_val,0);
  65.         input_sync(buttons_dev);  
  66.       //等同input_sync(buttons_dev, EV_SYN, SYN_REPORT, 0);
  67.     }  
  68.     else  
  69.     {  
  70.         /* 按下 */  
  71.         input_event(buttons_dev,EV_KEY,pindesc->key_val,1);  
  72.         input_sync(buttons_dev);  
  73.     }  
  74. }  
  75.   
  76. /* 驱动入口函数 */  
  77. static int buttons_input_init(void)  
  78. {  
  79.     int i, ret;  
  80.       
  81.     /* 1.分配一个input_dev结构体 */  
  82.     buttons_dev = input_allocate_device();  
  83.   
  84.     /* 2.设置 */  
  85.     /* 2.1 设置按键能产生哪类事件 */  
  86.     set_bit(EV_KEY,buttons_dev->evbit);  
  87.     set_bit(EV_REP,buttons_dev->evbit); 
  88.     buttons_dev->name = "buttons"; 
  89.   
  90.     /* 2.2 设置能产生这类事件的哪些操作 */  
  91.     set_bit(KEY_L,buttons_dev->keybit);  
  92.     set_bit(KEY_S,buttons_dev->keybit);  
  93.     set_bit(KEY_ENTER,buttons_dev->keybit);  
  94.     set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);  
  95.       
  96.     /* 3.注册 */  
  97.     ret = input_register_device(buttons_dev);  
  98.     if(ret != 0){
  99. input_free_device(buttons_dev);
  100. return 0;
  101.     }
  102.       
  103.     /* 4.硬件相关的设置 */  
  104.     /* 4.1 定时器相关的操作 */  
  105.     init_timer(&buttons_timer); 
  106.     buttons_timer.function = buttons_timer_function;  
  107.     add_timer(&buttons_timer);  
  108.   
  109.     /* 4.2 申请中断 */    
  110.     for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)  
  111.     {  
  112.         request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);  
  113.     }  
  114.       
  115.     return 0;  
  116. }  
  117.   
  118. /* 驱动出口函数 */  
  119. static void buttons_input_exit(void)  
  120. {  
  121.     int i;  
  122.     for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)  
  123.     {  
  124.         free_irq(pins_desc[i].irq, &pins_desc[i]);  
  125.     }  
  126.     /*删除未执行的定时器*/
  127.     del_timer_sync(&buttons_timer);  
  128.     /*注销input设备,释放资源*/
  129.     input_unregister_device(buttons_dev);  
  130.     input_free_device(buttons_dev);  
  131. }  
  132.   
  133. module_init(buttons_input_init);  //用于修饰入口函数  
  134. module_exit(buttons_input_exit);  //用于修饰出口函数      
  135.   
  136. MODULE_AUTHOR("LWJ");  
  137. MODULE_DESCRIPTION("Just for Demon");  
  138. MODULE_LICENSE("GPL");  //遵循GPL协议  


测试步骤方法一:

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. [WJ2440]# ls  
  2. Qt                  first_test          second_test  
  3. TQLedtest           fourth_drv.ko       sixth_drv.ko  
  4. app_test            fourth_test         sixth_test  
  5. bin                 home                sixthdrvtest  
  6. buttons_all_drv.ko  lib                 sys  
  7. buttons_all_test    linuxrc             third_drv.ko  
  8. buttons_input.ko    mnt                 third_test  
  9. dev                 opt                 tmp  
  10. driver_test         proc                udisk  
  11. etc                 root                usr  
  12. fifth_drv.ko        sbin                var  
  13. fifth_test          sddisk              web  
  14. first_drv.ko        second_drv.ko  
  15. [WJ2440]# ls /dev/event* -l  
  16. crw-rw----    1 root     root       13,  64 Jan  2 06:04 /dev/event0  
  17. [WJ2440]# insmod buttons_input.ko   
  18. input: Unspecified device as /devices/virtual/input/input1  
  19. [WJ2440]# ls /dev/event* -l  
  20. crw-rw----    1 root     root       13,  64 Jan  2 06:04 /dev/event0  
  21. crw-rw----    1 root     root       13,  65 Jan  2 06:06 /dev/event1  
  22. [WJ2440]# cat /dev/tty1  
  23. [WJ2440]# cat /dev/tty1  
  24. ls  
  25.   
  26. ls  
输入cat /dev/tty1命令后,顺序按下K1,K2,K3则会显示ls

测试步骤方法二、

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. [WJ2440]# hexdump /dev/event1  
  2. 0000000 b738 495d 8456 0007 0001 0026 0001 0000  
  3. 0000010 b738 495d 846f 0007 0000 0000 0000 0000  
  4. 0000020 b738 495d 2fb8 000a 0001 0026 0000 0000  
  5. 0000030 b738 495d 2fc7 000a 0000 0000 0000 0000  
分析:

hexdump /dev/event1  (open(/dev/event1), read(), )
           秒        微秒    类  code    value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. struct input_event {  
  2.     struct timeval time; //时间  
  3.     __u16 type;          //类  
  4.     __u16 code;          //类下事件的值  
  5.     __s32 value;         //0-松开, 1-按下,2-重复  
  6. };  
  7.   
  8. struct timeval {  
  9.     __kernel_time_t     tv_sec;         //秒   
  10.     __kernel_suseconds_t    tv_usec;    //微秒  
  11. };  

可以再参考http://blog.chinaunix.net/uid-20672257-id-3149668.html


0 0
原创粉丝点击