九鼎创展论坛中文版English
登录 | 立即注册 设为首页收藏本站 切换到宽版
查看: 3846|回复: 2
打印 上一主题 下一主题

x4412&ibox项目实战49-input子系统之按键驱动实验

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-17 15:48:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
Linux 的输入子系统不仅支持鼠标、键盘等常规输入设备,而且还支持蜂鸣器、触摸屏等设备。输入子系统又叫input子系统。其构建非常灵活,只需要调用一些简单的函数,就可以将一个输入设备的功能呈现给应用程序。其结构图如下:

编写一个input子系统驱动程序,用于检测按键的中断,并将按键信息上报给应用。在kernel/drivers/input/keyboard目录下新建x4412_keys.c文件,编辑内容如下:
  1. #include <linux/irq.h>  
  2. #include <linux/interrupt.h>
  3. #include <linux/module.h>
  4. #include <linux/types.h>
  5. #include <linux/fs.h>
  6. #include <linux/errno.h>
  7. #include <linux/sched.h>
  8. #include <linux/init.h>
  9. #include <linux/cdev.h>
  10. #include <asm/uaccess.h>
  11. #include <linux/slab.h>
  12. #include <linux/device.h>
  13. #include <mach/gpio.h>
  14. #include <linux/input.h>
  15. /* 定义并初始化等待队列头 */
  16. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
  17. static struct class *cdrv_class;
  18. static struct device *cdrv_device;
  19. void x4412_eint_do_tasklet(unsigned long data);
  20. DECLARE_TASKLET(x4412_eint_tasklet,x4412_eint_do_tasklet,0);
  21. typedef struct pin_desc
  22. {
  23.          unsigned int pin;
  24.          unsigned int key_val;
  25. }pin_desc;
  26. static struct pin_desc pins_desc[6] =
  27. {
  28.         {EXYNOS4_GPX1(0),0x01},//LEFT
  29.         {EXYNOS4_GPX1(3),0x02},//RIGHT
  30.         {EXYNOS4_GPX1(2),0x03},//UP
  31.          {EXYNOS4_GPX1(1),0x04},//DOWN
  32.          {EXYNOS4_GPX1(5),0x05},//MENU
  33.          {EXYNOS4_GPX1(4),0x06},//BACK
  34. };
  35. static struct input_dev *button_dev;   /*输入设备结构体*/
  36. struct pin_desc *pin_desc_p;
  37. static int ev_press = 0;
  38. int major;
  39. void x4412_eint_do_tasklet(unsigned long data)
  40. {
  41.          unsigned int pinval,state;
  42.          pinval = gpio_get_value(pin_desc_p->pin);
  43.          if(pinval)
  44.          {
  45.                    state = 0;
  46.          }
  47.          else
  48.          {
  49.                    state = 1;
  50.          }
  51.          ev_press = 1;
  52.          printk("int:pin_desc_p->key_val=0x%x\r\n",pin_desc_p->key_val);
  53.          input_report_key(button_dev, BTN_0, state);  /*向输入子系统报告产生按键事件*/
  54.         input_sync(button_dev);    /*通知接收者,一个报告发送完毕*/
  55.          wake_up_interruptible(&button_waitq);
  56. }
  57. /* 用户中断处理函数 */
  58. static irqreturn_t x4412_buttons_irq(int irq, void *dev_id)
  59. {
  60.          pin_desc_p = (struct pin_desc *)dev_id;
  61.          tasklet_schedule(&x4412_eint_tasklet);
  62.          return IRQ_HANDLED;
  63. }
  64. static int x4412_eint_open(struct inode * inode, struct file * filp)
  65. {
  66.          return 0;
  67. }
  68. static int x4412_eint_release(struct inode *inode, struct file *file)
  69. {
  70.          int irq;
  71.          irq = gpio_to_irq(pins_desc[0].pin);
  72.          free_irq(irq, &pins_desc[0]);
  73.          irq = gpio_to_irq(pins_desc[1].pin);
  74.          free_irq(irq,&pins_desc[1]);
  75.          irq = gpio_to_irq(pins_desc[2].pin);
  76.          free_irq(irq,&pins_desc[2]);
  77.        irq = gpio_to_irq(pins_desc[3].pin);
  78.          free_irq(irq, &pins_desc[3]);
  79.          irq = gpio_to_irq(pins_desc[4].pin);
  80.          free_irq(irq,&pins_desc[4]);
  81.          irq = gpio_to_irq(pins_desc[5].pin);
  82.          free_irq(irq,&pins_desc[5]);
  83.          return 0;
  84. }
  85. static const struct file_operations x4412_eint_fops =
  86. {
  87.          .owner = THIS_MODULE,
  88.          .open = x4412_eint_open,
  89.          .release = x4412_eint_release,
  90. };
  91. /* 驱动入口函数 */
  92. static int x4412_eint_init(void)
  93. {
  94.          int ret,irq;
  95.          major = register_chrdev(0, "x4412-key", &x4412_eint_fops);
  96.          cdrv_class = class_create(THIS_MODULE, "x4412-eint");
  97.          cdrv_device = device_create(cdrv_class, NULL, MKDEV(major, 0), NULL, "x4412-eint");
  98.          irq = gpio_to_irq(pins_desc[0].pin);
  99.          ret = request_irq(irq, x4412_buttons_irq,IRQ_TYPE_EDGE_BOTH,  "LEFT", &pins_desc[0]);
  100.          if(ret)
  101.                    printk("request irq_eint8 error!\r\n");
  102.          irq = gpio_to_irq(pins_desc[1].pin);
  103.          ret = request_irq(irq, x4412_buttons_irq,IRQ_TYPE_EDGE_BOTH, "RIGHT",&pins_desc[1]);
  104.          if(ret)
  105.                    printk("request irq_eint11 error!\r\n");
  106.          irq = gpio_to_irq(pins_desc[2].pin);
  107.          ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "UP",   &pins_desc[2]);
  108.          if(ret)
  109.                    printk("request irq_eint10 error!\r\n");
  110.          irq = gpio_to_irq(pins_desc[3].pin);
  111.          ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "DOWN", &pins_desc[3]);
  112.          if(ret)
  113.                    printk("request irq_eint9 error!\r\n");
  114.          irq = gpio_to_irq(pins_desc[4].pin);
  115.          ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "MENU", &pins_desc[4]);
  116.          if(ret)
  117.                    printk("request irq_eint13 error!\r\n");
  118.          irq = gpio_to_irq(pins_desc[5].pin);
  119.          ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "BACK", &pins_desc[5]);
  120.          if(ret)
  121.                    printk("request irq_eint12 error!\r\n");
  122.          pin_desc_p = kmalloc(sizeof(struct pin_desc), GFP_KERNEL);
  123.          if(!pin_desc_p)
  124.          {
  125.                    return -ENOMEM;
  126.          }
  127.          button_dev = input_allocate_device();     /*分配一个设备结构体*/
  128.          if (!button_dev)
  129.         {
  130.            printk(KERN_ERR "x4412-key.c: Not enough memory\n");
  131.                        ret = -ENOMEM;
  132.                        goto err_free_irq;
  133.         }
  134.          button_dev->name = "x4412-key";
  135.         button_dev->evbit[0] = BIT_MASK(EV_KEY);    /*设置按键信息*/
  136.         button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
  137.          ret = input_register_device(button_dev);      /*注册一个输入设备*/
  138.         if (ret)
  139.         {
  140.                 printk(KERN_ERR "x4412-key.c: Failed to register device\n");
  141.                 goto err_free_dev;
  142.         }
  143.          return 0;
  144. err_free_dev:
  145.         input_free_device(button_dev);
  146. err_free_irq:
  147.         free_irq(irq, x4412_buttons_irq);
  148.         return ret;
  149. }
  150. /* 驱动出口函数 */
  151. static void x4412_eint_exit(void)
  152. {
  153.          int irq;
  154.          irq = gpio_to_irq(pins_desc[0].pin);
  155.          free_irq(irq, &pins_desc[0]);
  156.          irq = gpio_to_irq(pins_desc[1].pin);
  157.          free_irq(irq,&pins_desc[1]);
  158.          irq = gpio_to_irq(pins_desc[2].pin);
  159.          free_irq(irq,&pins_desc[2]);
  160.        irq = gpio_to_irq(pins_desc[3].pin);
  161.          free_irq(irq, &pins_desc[3]);
  162.          irq = gpio_to_irq(pins_desc[4].pin);
  163.          free_irq(irq,&pins_desc[4]);
  164.          irq = gpio_to_irq(pins_desc[5].pin);
  165.          free_irq(irq,&pins_desc[5]);
  166.          unregister_chrdev(major, "x4412-key");
  167.          device_unregister(cdrv_device);  //卸载类下的设备
  168.          class_destroy(cdrv_class);       //卸载类
  169. }
  170. module_init(x4412_eint_init);  //用于修饰入口函数
  171. module_exit(x4412_eint_exit);  //用于修饰出口函数
  172. MODULE_AUTHOR("www.9tripod.com");
  173. MODULE_LICENSE("GPL");
复制代码
       结合源码,可以总结出添加一个输入子系统的几大步骤:
       第一步:定义一个输入子系统结构体:
  1. static struct input_dev *button_dev;
复制代码
       第二步:通过input_allocate_device函数分配一个输入子系统结构体:
  1. button_dev = input_allocate_device();
复制代码
       第三步:定义输入子系统名称:
  1. button_dev->name = "x4412-key";
复制代码
       第四步:设置产生的事件及键值:
  1. button_dev->evbit[0] = BIT_MASK(EV_KEY);    /*设置按键信息*/
  2. button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
复制代码
       第五步:注册一个输入设备:
  1. ret = input_register_device(button_dev);
复制代码
       第六步:当有输入事件产生时,向输入子系统报告产生的事件:
  1. input_report_key(button_dev, BTN_0, state);
复制代码
       第七步:通知接收者:
  1. input_sync(button_dev);
复制代码
       修改kernel/drivers/input/keyboard/Makefile文件,找到如下内容:
  1. obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
复制代码
       修改为:
  1. obj-$(CONFIG_KEYBOARD_GPIO)            += x4412_keys.o
复制代码
       make menuconfig指令中,找到
  1. Device Drivers  --->Input device support  --->Keyboards  --->GPIO Buttons
复制代码
       将驱动设置成模块,编译内核后,将会在kernel/drivers/input/keyboard目录下生成目标文件x4412_keys.ko
       ubuntu用户目录或samba目录下新建测试程序x4412_keys-app.c,用于读取按键键值。编辑内容如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/ioctl.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #include <sys/select.h>
  9. #include <sys/time.h>
  10. #include <errno.h>
  11. #include <linux/input.h>
  12. int main(void)
  13. {
  14.          int buttons_fd;
  15.          int key_value,i=0,count;
  16.          struct input_event ev_key;
  17.          buttons_fd = open("/dev/input/event3", O_RDWR);
  18.          if (buttons_fd < 0)
  19.          {
  20.                   perror("open device buttons");
  21.                    exit(1);
  22.          }
  23.          for (;;)
  24.          {
  25.                    count = read(buttons_fd,&ev_key,sizeof(struct input_event));
  26.                    for(i=0; i<(int)count/sizeof(struct input_event); i++)
  27.                    if(ev_key.type==EV_KEY)
  28.                             printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code-1,ev_key.value);
  29.                    if(ev_key.type==EV_SYN)
  30.                             printf("syn event\n\n");
  31.          }
  32.          close(buttons_fd);
  33.          return 0;
  34. }
复制代码
       测试程序通过open函数打开输入子系统的设备节点,通过如下指令查询驱动的设备节点:
  1. cat /proc/bus/input/devices
复制代码
       查询结果如下:
  1. [root@x4412 mnt]# cat /proc/bus/input/devices
  2. I: Bus=0018 Vendor=dead Product=beef Version=28bb
  3. N: Name="ft5x06-ts"
  4. P: Phys=input/ts
  5. S: Sysfs=/devices/virtual/input/input0
  6. U: Uniq=
  7. H: Handlers=kbd event0
  8. B: PROP=0
  9. B: EV=b
  10. B: KEY=400 0 4 0 2000000 0 40000800 40 0 0 0
  11. B: ABS=2650000 1000003

  12. I: Bus=0000 Vendor=0000 Product=0000 Version=0000
  13. N: Name="gsensor"
  14. P: Phys=
  15. S: Sysfs=/devices/virtual/input/input1
  16. U: Uniq=
  17. H: Handlers=event1
  18. B: PROP=0
  19. B: EV=9
  20. B: ABS=100 7

  21. I: Bus=0019 Vendor=0000 Product=0000 Version=0000
  22. N: Name="gpio_ir_recv"
  23. P: Phys=
  24. S: Sysfs=/devices/virtual/rc/rc0/input2
  25. U: Uniq=
  26. H: Handlers=kbd event2
  27. B: PROP=0
  28. B: EV=100013
  29. B: KEY=60000 2008000 0 40400800 1e16c0 0 0 10004ffc
  30. B: MSC=10

  31. I: Bus=0000 Vendor=0000 Product=0000 Version=0000
  32. N: Name="x4412-key"
  33. P: Phys=
  34. S: Sysfs=/devices/virtual/input/input3
  35. U: Uniq=
  36. H: Handlers=event3
  37. B: PROP=0
  38. B: EV=3
  39. B: KEY=1 0 0 0 0 0 0 0 0

  40. [root@x4412 mnt]#
复制代码
       这些都是输入子系统设备,其中x4412-key对应的设备节点为event3。编译测试程序,加载驱动模块后,使用测试程序测试效果如下:
  1. [root@x4412 mnt]# insmod x4412-key.ko
  2. [   47.368709] input: x4412-key as /devices/virtual/input/input3
  3. [root@x4412 mnt]# ./x4412-key-app
  4. [   53.388507] int:pin_desc_p->key_val=0x1
  5. count=16
  6. type:1,code:255,value:1
  7. count=16
  8. syn event
复制代码
回复

使用道具 举报

沙发
发表于 2014-12-12 12:19:52 | 只看该作者
非常感谢您的分享~~~~~~~~
回复 支持 反对

使用道具 举报

板凳
发表于 2014-12-15 15:26:46 | 只看该作者
怎么才能看见啊??
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳市九鼎创展科技官方论坛 ( 粤ICP备11028681号-2  

GMT+8, 2024-5-3 11:09 , Processed in 0.020810 second(s), 19 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表