Chinaunix首页 | 论坛 | 博客
  • 博客访问: 459454
  • 博文数量: 40
  • 博客积分: 1410
  • 博客等级: 军士长
  • 技术积分: 1396
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-22 19:26
个人简介

嵌入式系统工程师,从事视频、图像、网络、虚拟化等方面的底层软件开发与优化。

文章存档

2014年(4)

2013年(10)

2012年(14)

2011年(12)

分类: LINUX

2012-03-04 19:54:18

实验平台:Tiny6410 + Linux Kernel 2.6.38

本问主要实践下总线设备驱动模型输入子系统。功能上实现四个按键("l"、"s"、"Enter"、"Shift")控制下的LED等点亮和熄灭,并通过输入子系统向用户空间上报按键信息。用户空间程序打印按键信息。驱动测试可以参考USB那份总结。

点击(此处)折叠或打开

  1. //平台驱动:platform_driver

  2.   
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/init.h>
  6. #include <linux/fs.h>
  7. #include <linux/errno.h>
  8. #include <linux/cdev.h>
  9. #include <linux/types.h>
  10. #include <linux/device.h>
  11. #include <linux/mm.h>
  12. #include <linux/slab.h>
  13. #include <linux/sched.h>
  14. #include <linux/poll.h>
  15. #include <linux/ioctl.h>
  16. #include <linux/input.h>
  17. #include <linux/semaphore.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/irq.h>
  21. #include <linux/compiler.h>
  22. #include <asm/uaccess.h>
  23. #include <asm/irq.h>
  24. #include <asm/io.h>
  25. #include <asm/system.h>
  26. #include <mach/map.h>
  27. #include <mach/regs-gpio.h>
  28. #include <mach/gpio-bank-k.h>
  29. #include <mach/gpio-bank-n.h>
  30. #include <asm-generic/errno-base.h>

  31.   
  32. static struct timer_list button_control_leds_timer;
  33. static struct input_dev *button_control_leds_dev;
  34. static int led_tmp;
  35. static int button_control_leds_open(struct input_dev *dev)
  36. {
  37.     //all the leds went out
  38.     led_tmp = readl(S3C64XX_GPKDAT);
  39.     led_tmp |= 0x000000f0;
  40.     writel(led_tmp, S3C64XX_GPKDAT);

  41.   
  42.     return 0;
  43. }
  44. static void button_control_leds_close(struct input_dev *dev)
  45. {
  46.     //all the leds went out
  47.     led_tmp = readl(S3C64XX_GPKDAT);
  48.     led_tmp |= 0x000000f0;
  49.     writel(led_tmp, S3C64XX_GPKDAT);
  50. }
  51.  

  52.  
  53. //4. 定时器中断处理函数 static void button_control_leds_timer_function(unsigned long data)
  54. {
  55.     int button_value, invalid_keys;
  56.     /* GPN[3:0] is connected to buttons */
  57.  //4.1 读取按键值并上报给用户空间
  58.     button_value = readl(S3C64XX_GPNDAT) & 0x0000000f;
  59.     switch(~button_value & 0x0000000f) {
  60.         case 0x00000001: //key "l"
  61.             input_event(button_control_leds_dev, EV_KEY, KEY_L, 1);
  62.         break;
  63.         case 0x00000002: //key "s"
  64.             input_event(button_control_leds_dev, EV_KEY, KEY_S, 1);
  65.         break;
  66.         case 0x00000004: //key "Enter"
  67.             input_event(button_control_leds_dev, EV_KEY, KEY_ENTER, 1);
  68.         break;
  69.         case 0x00000009: //key "SHIFT" + key "l"
  70.             input_event(button_control_leds_dev, EV_KEY, KEY_LEFTSHIFT, 1);
  71.             input_event(button_control_leds_dev, EV_KEY, KEY_L, 1);
  72.         break;
  73.         case 0x0000000a: //key "SHIFT" + key "s"
  74.             input_event(button_control_leds_dev, EV_KEY, KEY_LEFTSHIFT, 1);
  75.             input_event(button_control_leds_dev, EV_KEY, KEY_S, 1);
  76.         break;
  77.         case 0x00000000: //no key is pressed
  78.             input_event(button_control_leds_dev, EV_KEY, KEY_L, 0);
  79.             input_event(button_control_leds_dev, EV_KEY, KEY_S, 0);
  80.             input_event(button_control_leds_dev, EV_KEY, KEY_ENTER, 0);
  81.             input_event(button_control_leds_dev, EV_KEY, KEY_LEFTSHIFT, 0);
  82.         break;
  83.         default: //invalid keys
  84.             invalid_keys = 1;
  85.         break;
  86.     }
  87.  //如果按键有效,就上报给用户空间
  88.     if(!invalid_keys)
  89.         input_sync(button_control_leds_dev);
  90.     else
  91.         invalid_keys = 0;
  92.  

  93.  
  94.     /* GPK[7:4] is connected to LEDs */
  95. //4.2 根据按键值,点亮相应的LED灯
  96.     led_tmp = readl(S3C64XX_GPKDAT);
  97.     switch(button_value) {
  98.         case 0x0000000e: //light led1
  99.             led_tmp |= 0x000000f0;
  100.             led_tmp &= 0xffffffef;
  101.         break;
  102.         case 0x0000000d: //light led2
  103.             led_tmp |= 0x000000f0;
  104.             led_tmp &= 0xffffffdf;
  105.         break;
  106.         case 0x0000000b: //light led3
  107.             led_tmp |= 0x000000f0;
  108.             led_tmp &= 0xffffffbf;
  109.         break;
  110.         case 0x00000007: //light led4
  111.             led_tmp |= 0x000000f0;
  112.             led_tmp &= 0xffffff7f;
  113.         break;
  114.         case 0x0000000f: //all the leds went out
  115.             led_tmp |= 0x000000f0;
  116.         break;
  117.         default: //light all the leds
  118.             led_tmp &= 0xffffff0f;
  119.         break;
  120.     }
  121.     writel(led_tmp, S3C64XX_GPKDAT);
  122. }
  123.  
  124.  //3. 按键中断处理函数
  125. static irqreturn_t button_control_leds_irq(int irq, void *dev_id)
  126. {
  127.     //3.1 修改定时器,10ms延时,防止按键抖动引起的多次处理
  128. mod_timer(&button_control_leds_timer, jiffies + HZ/100);

  129.   
  130.     return IRQ_RETVAL(IRQ_HANDLED);
  131. }

  132.  
  133. //2. 当设备和驱动匹配时,probe函数会被调用 static int button_control_leds_probe(struct platform_device *pdev)
  134. {
  135.     struct resource *res;
  136.     int ret, i, j;
  137.  
  138.   //2.1 输入子系统input_dev结构体的分配、设置和注册
  139.  //2.1.1 分配一个input_dev
  140.     button_control_leds_dev = input_allocate_device();
  141.  
  142.  //2.1.2 设置input_dev参数
  143.     set_bit(EV_KEY, button_control_leds_dev->evbit); //按键类型
  144.     set_bit(EV_REP, button_control_leds_dev->evbit); //支持重复按键
  145.     set_bit(KEY_L, button_control_leds_dev->keybit); //按键“l”
  146.     set_bit(KEY_S, button_control_leds_dev->keybit); //按键“s”
  147.     set_bit(KEY_ENTER, button_control_leds_dev->keybit); //按键“Enter”
  148.     set_bit(KEY_LEFTSHIFT, button_control_leds_dev->keybit); //按键“Shift”
  149.     button_control_leds_dev->open = button_control_leds_open; //open函数
  150.     button_control_leds_dev->close = button_control_leds_close; //close函数
  151.  //2.1.3 注册一个input_dev结构体
  152.     ret = input_register_device(button_control_leds_dev);
  153.     if(unlikely(ret))
  154.         goto fail1;

  155.  
  156. //2.2 定时器初始化、设置定时器中断处理函数、添加一个定时器
  157.     init_timer(&button_control_leds_timer);
  158.     button_control_leds_timer.function = button_control_leds_timer_function;
  159.     add_timer(&button_control_leds_timer);
  160.  
  161.  //2.3 获取平台设备资源、注册按键中断
  162.     for(i = 0; i < pdev->num_resources; i++) {
  163.  //2.3.1 获取平台设备资源:中断获取
  164.         res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
  165.         if(unlikely(res == NULL)) {
  166.             printk("Button %d: get platform resource failed!\n", i);
  167.             goto fail2;
  168.         }
  169.  //2.3.2 注册按键中断
  170.         ret = request_irq(res->start, button_control_leds_irq, \
  171.                 IRQ_TYPE_EDGE_BOTH, res->name, pdev);
  172.         if(unlikely(ret != 0)) {
  173.             printk("Button %d: request_irq failed\n", i);
  174.             goto fail3;
  175.         }
  176.     }
  177.     return 0;
  178. fail1:
  179.     input_unregister_device(button_control_leds_dev);
  180.     input_free_device(button_control_leds_dev);
  181.     return ret;

  182.   
  183. fail2:
  184.     del_timer(&button_control_leds_timer);
  185.     input_unregister_device(button_control_leds_dev);
  186.     input_free_device(button_control_leds_dev);
  187.     return -ENXIO;
  188.  
  189. fail3:
  190.     for(j = 0; j <= i; j++) {
  191.         res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
  192.         free_irq(res->start, pdev);
  193.     }
  194.     del_timer(&button_control_leds_timer);
  195.     input_unregister_device(button_control_leds_dev);
  196.     input_free_device(button_control_leds_dev);
  197.     return ret;
  198. }
  199.  
  200. static int button_control_leds_remove(struct platform_device *pdev)
  201. {
  202.     struct resource *res;
  203.     int i;

  204.   
  205.     for(i = 0; i < pdev->num_resources; i++) {
  206.         res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
  207.         free_irq(res->start, pdev);
  208.     }
  209.     del_timer(&button_control_leds_timer);
  210.     input_unregister_device(button_control_leds_dev);
  211.     input_free_device(button_control_leds_dev);
  212.  

  213.  
  214.     return 0;
  215. }
  216.  

  217.   
  218.  //1. 平台总线platform_driver结构体及其注册
  219. struct platform_driver button_control_leds_drv = {
  220.     .probe = button_control_leds_probe,
  221.     .remove = button_control_leds_remove,
  222.     .driver = {
  223.         .name = "button_control_leds",
  224.         .owner = THIS_MODULE,
  225.     }
  226. };
  227.  
  228. static int __init button_control_leds_init(void)
  229. {
  230.     platform_driver_register(&button_control_leds_drv);
  231.     return 0;
  232. }
  233.  
  234. static void __exit button_control_leds_exit(void)
  235. {
  236.     platform_driver_unregister(&button_control_leds_drv);
  237. }
  238. module_init(button_control_leds_init);
  239. module_exit(button_control_leds_exit);
  240. MODULE_AUTHOR("Jason Lu");
  241. MODULE_VERSION("0.1.0");
  242. MODULE_DESCRIPTION("Jason's blog: jason2012.blog.chinaunix.net");
  243. MODULE_LICENSE("Dual MPL/GPL");
  244. MODULE_ALIAS("Driver of button control leds");

  1. //平台设备:platform_device

  2. #include <linux/module.h>
  3. #include <linux/version.h>
  4. #include <linux/init.h>
  5. #include <linux/kernel.h>
  6. #include <linux/types.h>
  7. #include <linux/interrupt.h>
  8. #include <linux/list.h>
  9. #include <linux/timer.h>
  10. #include <linux/serial_core.h>
  11. #include <linux/platform_device.h>
  12. #include <mach/gpio.h>
  13. #include <mach/irqs.h>

 //1. 平台设备资源
  1. static struct resource button_control_leds_resource[] = {
  2.     [0] = {
  3.         .name    = "button 1",
  4.         .start    = IRQ_EINT(0),
  5.         .end        = IRQ_EINT(0),
  6.         .flags    = IORESOURCE_IRQ,
  7.     },
  8.     [1] = {
  9.         .name    = "button 2",
  10.         .start    = IRQ_EINT(1),
  11.         .end        = IRQ_EINT(1),
  12.         .flags    = IORESOURCE_IRQ,
  13.     },
  14.     [2] = {
  15.         .name    = "button 3",
  16.         .start    = IRQ_EINT(2),
  17.         .end        = IRQ_EINT(2),
  18.         .flags    = IORESOURCE_IRQ,
  19.     },
  20.     [3] = {
  21.         .name    = "button 4",
  22.         .start    = IRQ_EINT(3),
  23.         .end        = IRQ_EINT(3),
  24.         .flags    = IORESOURCE_IRQ,
  25.     },
  26. };

  27. static void button_control_leds_release(struct device * dev)
  28. {
  29. }

 //平台设备platform_device结构体
  1. static struct platform_device button_control_leds_dev = {
  2.     .name            = "button_control_leds",
  3.     .id                = -1,
  4.     .num_resources    = ARRAY_SIZE(button_control_leds_resource),
  5.     .resource            = button_control_leds_resource,
  6.     .dev = {
  7.             .release = button_control_leds_release,
  8.     },
  9. };
 //3. 注册一个平台设备
  1. static int button_control_leds_dev_init(void)
  2. {
  3.     platform_device_register(&button_control_leds_dev);
  4.     return 0;
  5. }

  6. static void button_control_leds_dev_exit(void)
  7. {
  8.     platform_device_unregister(&button_control_leds_dev);
  9. }

  10. module_init(button_control_leds_dev_init);
  11. module_exit(button_control_leds_dev_exit);

  12. MODULE_AUTHOR("Jason Lu");
  13. MODULE_VERSION("0.1.0");
  14. MODULE_DESCRIPTION("Jason's blog: jason2012.blog.chinaunix.net");
  15. MODULE_LICENSE("Dual MPL/GPL");
  16. MODULE_ALIAS("Device of button control leds");

  1. //用户空间程序

  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/ioctl.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>
  9. #include <sys/select.h>
  10. #include <sys/time.h>
  11. #include <errno.h>
  12. #include <linux/input.h>
  13. #include <string.h>

  14. /*
  15.  * The event structure itself
  16.  * struct input_event {
  17.  *     struct timeval time;
  18.  *    __u16 type;
  19.  *    __u16 code;
  20.  *    __s32 value;
  21.  * };
  22.  *
  23. */
  24. static int shift_flag; //shift键按下标志

  25. char * button_show(int code, int value);

  26. int main(int argc, char *argv[])
  27. {
  28.     int buttons_fd;
  29.     int count, i = 0;
  30.     char *a;
     //1. 定义一个input_event结构体
  1.     struct input_event ev_key;
     //2. 打开设备节点
  1.     buttons_fd = open("/dev/input/event1", O_RDWR);
  2.     if (buttons_fd < 0) {
  3.         perror("open device buttons");
  4.         exit(1);
  5.     }

  6.     for (;;) {
  7. //3. 读取按键信息到input_event结构体
  8.         count = read(buttons_fd, &ev_key, sizeof(struct input_event));

  9.         for(i=0; i<(int)count/sizeof(struct input_event); i++)
  10.     //4. 判断是否是按键类型
  11.             if(EV_KEY == ev_key.type) {
  12. //5. 打印按键信息
  13.                 a = button_show(ev_key.code, ev_key.value);
  14.                 printf("%s", a);
  15.             }
  16.     }    

  17.     close(buttons_fd);
  18.     return 0;
  19. }

  20. char * button_show(int code, int value)
  21. {
  22.     char *a;

  23.     if(value == 1) { //1. 按键按下
  24.         switch(code) {
  25.             case KEY_L:
  26.                 if(shift_flag)
  27.                     a = "Press the button \"L\"\n";
  28.                 else
  29.                     a = "Press the button \"l\"\n";
  30.             break;
  31.             case KEY_S:
  32.                 if(shift_flag)
  33.                     a = "Press the button \"S\"\n";
  34.                 else
  35.                     a = "Press the button \"s\"\n";
  36.             break;
  37.             case KEY_ENTER:
  38.                 a = "Press the button \"Enter\"\n";
  39.             break;
  40.             case KEY_LEFTSHIFT:
  41.                 shift_flag = 1;
  42.                 a = "Press the button \"LEFTSHIFT\"\n";
  43.             break;
  44.             default:
  45.                 a = "Unable to identify the key pressed!\n";
  46.             break;
  47.         }
  48.     }
  49.     else if(value == 2) //2. 重复按键
  50.         a = "Press the button repeatedly!\n";
  51.     else { //3. 按键松开
  52.         switch(code) {
  53.             case KEY_L:
  54.                 if(shift_flag)
  55.                     a = "Release the button \"L\"\n";
  56.                 else
  57.                     a = "Release the button \"l\"\n";
  58.                 break;
  59.             case KEY_S:
  60.                 if(shift_flag)
  61.                     a = "Release the button \"S\"\n";
  62.                 else
  63.                     a = "Release the button \"s\"\n";
  64.             break;
  65.             case KEY_ENTER:
  66.                 a = "Release the button \"Enter\"\n";
  67.             break;
  68.             case KEY_LEFTSHIFT:
  69.                 shift_flag = 0;
  70.                 a = "Release the button \"LEFTSHIFT\"\n";
  71.             break;
  72.             default:
  73.                 a = "Unable to identify the key released!\n";
  74.             break;
  75.         }
  76.     }

  77.     return a;
  78. }





阅读(3640) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~