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

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

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

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

答:

1. 分配一个input_dev结构体

2. 设置

3. 注册

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

问:如何分配input_dev结构体?

答:使用input_allocate_device函数

input_dev结构体的重要成员

[cpp] view
plain
?
  1. struct input_dev {
  2. const char *name;
  3. const char *phys;
  4. const char *uniq;
  5. struct input_id id;
  6. unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件
  7. unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键
  8. unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮
  9. unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
  10. unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
  11. unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
  12. unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
  13. unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
  14. ...
  15. }

问:第二步的设置,应该怎么设置,应该设置什么?

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

[cpp] view
plain
?
  1. /* 2.设置 */
  2. /* 2.1 设置按键能产生哪类事件 */
  3. set_bit(EV_KEY,buttons_dev->evbit);  //按键类事件
  4. set_bit(EV_REP,buttons_dev->evbit);  //重复类事件,比如按下按键L能重复打印L;按下后,能重复帮你上报事件(重复,说明肯定用到定时器)
  5. /* 2.2 设置能产生这类操作的哪些事件 */
  6. set_bit(KEY_L,buttons_dev->keybit);
  7. set_bit(KEY_S,buttons_dev->keybit);
  8. set_bit(KEY_ENTER,buttons_dev->keybit);
  9. set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);

问:有哪些类呢?

答:在input.h里有以下类

[cpp] view
plain
?
  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)函数来注册

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

答:申请定时器、申请中断操作

驱动源码:

[cpp] view
plain
?
  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. static struct pin_desc{
  20. int irq;
  21. unsigned char *name;
  22. unsigned int pin;
  23. unsigned int key_val;
  24. };
  25. static struct pin_desc pins_desc[4] = {
  26. {IRQ_EINT1,"K1",S3C2410_GPF1,KEY_L},
  27. {IRQ_EINT4,"K2",S3C2410_GPF4,KEY_S},
  28. {IRQ_EINT2,"K3",S3C2410_GPF2,KEY_ENTER},
  29. {IRQ_EINT0,"K4",S3C2410_GPF0,KEY_LEFTSHIFT},
  30. };
  31. static struct pin_desc *irq_pd;
  32. static struct input_dev *buttons_dev;
  33. static struct timer_list buttons_timer;
  34. /* 用户中断处理函数 */
  35. static irqreturn_t buttons_irq(int irq, void *dev_id)
  36. {
  37. irq_pd = (struct pin_desc *)dev_id;
  38. /* 修改定时器定时时间,定时10ms,即10秒后启动定时器
  39. * HZ 表示100个jiffies,jiffies的单位为10ms,即HZ = 100*10ms = 1s
  40. * 这里HZ/100即定时10ms
  41. */
  42. mod_timer(&buttons_timer, jiffies + (HZ /100));
  43. return IRQ_HANDLED;
  44. }
  45. /* 定时器处理函数 */
  46. static void buttons_timer_function(unsigned long data)
  47. {
  48. struct pin_desc *pindesc = irq_pd;
  49. unsigned int pinval;
  50. pinval = s3c2410_gpio_getpin(pindesc->pin);
  51. if(pinval)
  52. {
  53. /* 松开 最后一个参数: 0-松开, 1-按下 */
  54. input_event(buttons_dev,EV_KEY,pindesc->key_val,0);
  55. input_sync(buttons_dev);
  56. }
  57. else
  58. {
  59. /* 按下 */
  60. input_event(buttons_dev,EV_KEY,pindesc->key_val,1);
  61. input_sync(buttons_dev);
  62. }
  63. }
  64. /* 驱动入口函数 */
  65. static int buttons_input_init(void)
  66. {
  67. int i;
  68. /* 1.分配一个input_dev结构体 */
  69. buttons_dev = input_allocate_device();
  70. /* 2.设置 */
  71. /* 2.1 设置按键能产生哪类事件 */
  72. set_bit(EV_KEY,buttons_dev->evbit);
  73. set_bit(EV_REP,buttons_dev->evbit);
  74. /* 2.2 设置能产生这类操作的哪些事件 */
  75. set_bit(KEY_L,buttons_dev->keybit);
  76. set_bit(KEY_S,buttons_dev->keybit);
  77. set_bit(KEY_ENTER,buttons_dev->keybit);
  78. set_bit(KEY_LEFTSHIFT,buttons_dev->keybit);
  79. /* 3.注册 */
  80. input_register_device(buttons_dev);
  81. /* 4.硬件相关的设置 */
  82. /* 4.1 定时器相关的操作 */
  83. init_timer(&buttons_timer);
  84. buttons_timer.function = buttons_timer_function;
  85. add_timer(&buttons_timer);
  86. /* 4.2 申请中断 */
  87. for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
  88. {
  89. request_irq(pins_desc[i].irq, buttons_irq, IRQ_TYPE_EDGE_BOTH, pins_desc[i].name, &pins_desc[i]);
  90. }
  91. return 0;
  92. }
  93. /* 驱动出口函数 */
  94. static void buttons_input_exit(void)
  95. {
  96. int i;
  97. for(i = 0;i < sizeof(pins_desc)/sizeof(pins_desc[0]);i++)
  98. {
  99. free_irq(pins_desc[i].irq, &pins_desc[i]);
  100. }
  101. del_timer(&buttons_timer);
  102. input_unregister_device(buttons_dev);
  103. input_free_device(buttons_dev);
  104. }
  105. module_init(buttons_input_init);  //用于修饰入口函数
  106. module_exit(buttons_input_exit);  //用于修饰出口函数
  107. MODULE_AUTHOR("LWJ");
  108. MODULE_DESCRIPTION("Just for Demon");
  109. MODULE_LICENSE("GPL");  //遵循GPL协议

测试步骤方法一:

[cpp] view
plain
?
  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. ls

输入cat /dev/tty1命令后,顺序按下K1,K2,K3则会显示ls





2. 如果没有启动QT:

cat /dev/tty1

按:s2,s3,s4

就可以得到ls

或者:

exec 0</dev/tty1 (把标准输入改为tty1)

然后可以使用按键来输入



3. 如果已经启动了QT:    ( 因为启动了qt之后,串口返回的是乱码)

可以点开记事本

然后按:s2,s3,s4


测试步骤方法二、

[cpp] view
plain
?
  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  (16进制显示:这句话的意思是   先open(/dev/event1), 然后再read(), 读之后把里面的数据当做16进制显示出来)

                       秒             微秒          类    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
?
  1. struct input_event {
  2. struct timeval time; //时间
  3. __u16 type;          //类
  4. __u16 code;          //类下事件的值
  5. __s32 value;         //0-松开, 1-按下,2-重复
  6. };
  7. struct timeval {
  8. __kernel_time_t     tv_sec;         //秒
  9. __kernel_suseconds_t    tv_usec;    //微秒
  10. };

linux输入子系统之按键驱动的更多相关文章

  1. Linux输入子系统(一) _驱动编码

    输入设备都有共性:中断驱动+字符IO,基于分层的思想,Linux内核将这些设备的公有的部分提取出来,基于cdev提供接口,设计了输入子系统,所有使用输入子系统构建的设备都使用主设备号13,同时输入子系 ...

  2. linux输入子系统简述【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/7678035 1,linux输入子系统简述 其实驱动这部分大多还是转载别人的,linux ...

  3. linux-2.6.38 input子系统(用输入子系统实现按键操作)

    一.设备驱动程序 在上一篇随笔中已经分析,linux输入子系统分为设备驱动层.核心层和事件层.要利用linux内核中自带的输入子系统实现一个某个设备的操作,我们一般只需要完成驱动层的程序即可,核心层和 ...

  4. linux输入子系统(input subsystem)之evdev.c事件处理过程

    1.代码 input_subsys.drv.c 在linux输入子系统(input subsystem)之按键输入和LED控制的基础上有小改动,input_subsys_test.c不变. input ...

  5. Linux输入子系统(转)

    Linux输入子系统(Input Subsystem) 1.1.input子系统概述 输入设备(如按键,键盘,触摸屏,鼠标等)是典型的字符设备,其一般的工作机制是低层在按键,触摸等动作发生时产生一个中 ...

  6. Linux输入子系统框架分析(1)

    在Linux下的输入设备键盘.触摸屏.鼠标等都能够用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层.事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备 ...

  7. Linux输入子系统详解

    input输入子系统框架  linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(Input ...

  8. linux输入子系统

    linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(InputCore)和输入子系统设备驱 ...

  9. linux输入子系统概念介绍

    在此文章之前,我们讲解的都是简单的字符驱动,涉及的内容有字符驱动的框架.自动创建设备节点.linux中断.poll机制.异步通知.同步互斥.非阻塞.定时器去抖动. 上一节文章链接:http://blo ...

随机推荐

  1. python+mitmproxy抓包过滤+redis消息订阅+websocket实时消息发送,日志实时输出到web界面

    本实例实现需求 在游戏SDK测试中,经常需要测试游戏中SDK的埋点日志是否接入正确.本实例通过抓包(客户端http/https 请求)来判定埋点日志是是否接入正确. 实现细节:使用django项目,后 ...

  2. 第七届蓝桥杯C-B-10-最大比例/gcd变形

    最大比例 X星球的某个大奖赛设了M级奖励.每个级别的奖金是一个正整数.并且,相邻的两个级别间的比例是个固定值.也就是说:所有级别的奖金数构成了一个等比数列.比如:16,24,36,54其等比值为:3/ ...

  3. python协程函数应用 列表生成式 生成器表达式

    协程函数应用 列表生成式 生成器表达式   一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._n ...

  4. 内存保护机制及绕过方案——通过覆盖虚函数表绕过/GS机制

    1    GS内存保护机制 1.1    GS工作原理 栈中的守护天使--GS,亦称作Stack Canary / Cookie,从VS2003起开始启用(也就说,GS机制是由编译器决定的,跟操作系统 ...

  5. 图解MySQL 内连接、外连接、左连接、右连接、全连接

    用两个表(a_table.b_table),关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接.外连接( 左(外)连接.右(外)连接.全(外)连接). MySQL版 ...

  6. Struts2 用过滤器代替了 servlet ,???? 且不需要tomcat就可以直接做功能测试

    Struts2  用过滤器代替了 servlet ,????  且不需要tomcat就可以直接做功能测试

  7. QGrapicsItem类

    这个类翻译了好久,实在是成员函数太多了,分享出来,希望对大家有用,多多支持哦~~ 详细介绍 QGraphicsItem类是视图框架的一部分,是在一个QGraphicsScene中最基本的图形类,它为绘 ...

  8. elasticsearch聚合案例--分组、求最大值再求最大值的均值

    一.需求 A.B.C代表3个用户,第二列代表各自的得分,求A.B.C的最好成绩以及A.B.C最好成绩的均值 A 10 A 11 A 13 B 11 B 11 B 12 C 10 C 10 C 11 C ...

  9. Asyphre for Delphi Xe4 Demo Running on iPad!

    Asyphre 4.0 . customize bitmap with asvf file.  compiled done!  check the video!

  10. 图解Fiddler如何抓手机APP数据包过滤抓取

    使用fidder抓取浏览器的包相信不是问题,那么使用fidder 抓取app的数据包呢??? 于是,找了一篇博客来学习一下,可以参考一下,根据自己的需求来实现. 在网上自己学习,然后整理了我所用到的, ...