Chinaunix首页 | 论坛 | 博客
  • 博客访问: 631435
  • 博文数量: 75
  • 博客积分: 988
  • 博客等级: 准尉
  • 技术积分: 1269
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-10 15:44
文章分类

全部博文(75)

文章存档

2022年(1)

2019年(1)

2018年(1)

2016年(9)

2015年(7)

2013年(6)

2012年(40)

2011年(10)

分类: LINUX

2012-03-15 14:42:08

上一节总体概括了输入子系统的组成及实现方法。主要是由input.c核心层,input_device“硬件”层和input_handler_dev"软件“层。硬件层和软件层都是通过向核心层来注册设备。对于每一个input_dev调用input_attach_handler,根据input_handler中的id_table来判断能否支持这个input_dev。根据注册input_dev或input_handler时,会两两比较input_dev和input_handler,根据input_handler的id_table判断这个input_handler能否支持这个input_dev,如果可以则调用input_handler的connect函数建立“连接”。


点击(此处)折叠或打开

  1. /* 参考drivers\input\keyboard\gpio_keys.c */

  2. #include <linux/module.h>
  3. #include <linux/version.h>

  4. #include <linux/init.h>
  5. #include <linux/fs.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/irq.h>
  8. #include <linux/sched.h>
  9. #include <linux/pm.h>
  10. #include <linux/sysctl.h>
  11. #include <linux/proc_fs.h>
  12. #include <linux/delay.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/input.h>
  15. #include <linux/irq.h>

  16. #include <asm/gpio.h>
  17. #include <asm/io.h>
  18. #include <asm/arch/regs-gpio.h>

  19. struct pin_desc{
  20.     int irq;
  21.     char *name;
  22.     unsigned int pin;
  23.     unsigned int key_val;
  24. };

  25. struct pin_desc pins_desc[4] = {
  26.     {IRQ_EINT0, "S2", S3C2410_GPF0, KEY_L},
  27.     {IRQ_EINT2, "S3", S3C2410_GPF2, KEY_S},
  28.     {IRQ_EINT11, "S4", S3C2410_GPG3, KEY_ENTER},
  29.     {IRQ_EINT19, "S5", S3C2410_GPG11, KEY_LEFTSHIFT},
  30. };

  31. static struct input_dev *buttons_dev;
  32. static struct pin_desc *irq_pd;
  33. static struct timer_list buttons_timer;

  34. static irqreturn_t buttons_irq(int irq, void *dev_id)
  35. {
  36.     /* 10ms后启动定时器 */
  37.     irq_pd = (struct pin_desc *)dev_id;
  38.     mod_timer(&buttons_timer, jiffies+HZ/100);
  39.     return IRQ_RETVAL(IRQ_HANDLED);
  40. }

  41. static void buttons_timer_function(unsigned long data)   // 按键处理函数
  42. {
  43.     struct pin_desc * pindesc = irq_pd;
  44.     unsigned int pinval;

  45.     if (!pindesc)
  46.         return;
  47.     
  48.     pinval = s3c2410_gpio_getpin(pindesc->pin);

  49.     if (pinval)
  50.     {
  51.         /* 松开 : 最后一个参数: 0-松开, 1-按下 , 2 - 重复 */
  52.         input_event(buttons_dev, EV_KEY, pindesc->key_val, 0);
  53.         input_sync(buttons_dev);      // 同步
  54.     }
  55.     else
  56.     {
  57.         /* 按下 */
  58.         input_event(buttons_dev, EV_KEY, pindesc->key_val, 1);
  59.         input_sync(buttons_dev);
  60.     }
  61. }

       /*
* 入口函数: buttons_init()
* 实现功能:  1.分配一个input_dev结构体
*      2.设置
*      3.注册
*      4.硬件相关的代码,比如在中断服务程序里面上报事件。
*/
  1. static int buttons_init(void)                             
  2. {
  3.     int i;
  4.     
  5.     /* 1. 分配一个input_dev结构体 */
  6.     buttons_dev = input_allocate_device();;

  7.     /* 2. 设置 */
  8.     /* 2.1 能产生哪类事件 */
  9.     set_bit(EV_KEY, buttons_dev->evbit);  // 按键事件
  10.     set_bit(EV_REP, buttons_dev->evbit);  // 重复事件
  11.     
  12.     /* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
  13.     set_bit(KEY_L, buttons_dev->keybit);
  14.     set_bit(KEY_S, buttons_dev->keybit);
  15.     set_bit(KEY_ENTER, buttons_dev->keybit);
  16.     set_bit(KEY_LEFTSHIFT, buttons_dev->keybit);

  17.     /* 3. 注册 */
  18.     input_register_device(buttons_dev);
  19.     
  20.     /* 4. 硬件相关的操作 */
  21.     init_timer(&buttons_timer);
  22.     buttons_timer.function = buttons_timer_function;
  23.     add_timer(&buttons_timer);
  24.     
  25.     for (i = 0; i < 4; i++)
  26.     {
  27.         request_irq(pins_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pins_desc[i].name, &pins_desc[i]);
  28.     }
  29.     
  30.     return 0;
  31. }

  32. static void buttons_exit(void)    // 出口函数
  33. {
  34.     int i;
  35.     for (i = 0; i < 4; i++)
  36.     {
  37.         free_irq(pins_desc[i].irq, &pins_desc[i]);   
  38.     }

  39.     del_timer(&buttons_timer);
  40.     input_unregister_device(buttons_dev);
  41.     input_free_device(buttons_dev);    
  42. }

  43. module_init(buttons_init);

  44. module_exit(buttons_exit);

  45. MODULE_LICENSE("GPL");
 先写出入口函数、出口函数的框架,并加以修饰,然后在入口函数里面实现1,分配一个input_dev结构体。2,对这个input_dev进行相关设置:能产生哪类事件,产生这类事件中的哪些事件。3,注册设备。4,硬件相关的操作。
          
Input.h里面有对相关事件的定义。
unsigned long evbit[NBITS(EV_MAX)];      // 表示能产生哪类事件
#define EV_SYN 0x00       // 同步类
#define EV_KEY 0x01       // 按键类
#define EV_REL 0x02       // 相对位移类事件 relation
#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
unsigned long keybit[NBITS(KEY_MAX)];    // 表示能产生哪些按键
unsigned long relbit[NBITS(REL_MAX)];    // 表示能产生哪些相对位移
unsigned long absbit[NBITS(ABS_MAX)];    // 表示能产生哪些绝对位移事件
unsigned long mscbit[NBITS(MSC_MAX)];    //
unsigned long ledbit[NBITS(LED_MAX)];    //
unsigned long sndbit[NBITS(SND_MAX)];    //
unsigned long ffbit[NBITS(FF_MAX)];      // 
unsigned long swbit[NBITS(SW_MAX)];      //

测试:
1. 
hexdump /dev/event1  (open(/dev/event1), read(), )   hexdump是以16进制显示。
           秒        微秒    类  code    value
0000000 0bb2 0000 0e48 000c 0001 0026 0001 0000     // code 值为26为十六进制,转为十进制为38. 
0000010 0bb2 0000 0e54 000c 0000 0000 0000 0000     // 而#define KEY_L 38
0000020 0bb2 0000 5815 000e 0001 0026 0000 0000
0000030 0bb2 0000 581f 000e 0000 0000 0000 0000

struct input_event {
struct timeval time;   // 占4字节
__u16 type;            // 占2字节 
__u16 code;            // 占2字节
__s32 value;           // 占4字节
};

2. 如果没有启动QT:   // 启动QT后,终端显示定位到LCD上,所以直接在串口终端上看不到想要的结果。
cat /dev/tty1
按:s2,s3,s4
就可以得到ls

或者:
exec 0
然后可以使用按键来输入
#define TTY_NORMAL 0
#define TTY_BREAK 1
#define TTY_FRAME 2
#define TTY_PARITY 3
#define TTY_OVERRUN 4
上面的就是将/dev/tty1改为普通模式,定义在tty.h中。

3. 如果已经启动了QT:
可以点开记事本
然后按:s2,s3,s4

只要按照输入子系统框架的4个要点来写驱动,然后加以完善就可以了,当然,完善的过程中肯定会碰到很多的问题,从分析源码入手,往往可以解决问题。这几次的笔记感觉就是照搬一些东西,但是慢慢的感觉真上来了,没有以前的那种恐怖感了。相信再多炼下,应该很快就上手。

另,现在新的内核驱动基本上都是挂platform总线上,我也问过做平板驱动的朋友,他说他们的驱动也是基本上都是挂platform上面。platform就是为了简化驱动程序的分析而创建的一个虚拟总线。当然也是现在很主流的。但是为了知道具体的工作原理和一些基本设备的驱动方式,我想等我学完后再综合起来看platform,我相信那时候看应该是很容易的,也容易理解得多。因为现在的学习过程中也会遇到很多不容易理解的,慢慢摸索了就明白了。
阅读(2747) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

重返人生2012-03-18 01:34:41

从分析源码入手,往往可以解决问题

夏冰软件2012-03-16 16:08:46

写的不错,学习一下