linux字符驱动之查询按键

转自:http://blog.csdn.net/lwj103862095/article/details/17484041

在上一节中,我们讲解了如何自动创建设备节点,并用“最笨”的方法实现点亮LED。

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

这一节里,我们基于上一节的基础上,稍微改动一下,来实现一个查询方式的按键驱动。


问:既然是基于上一节的基础,只是稍微改动,改动了哪些?

答:框架是不变的,还是字符设备框架,硬件操作有稍微变动,上一节里,LED的GPIO设置为输出方式,这一节里,KEY的GPIO设置为输入方式;上一节里,LED驱动的核心函数实现了led_open,led_write,这一节里,KEY驱动的核心函数实现了key_open,key_read;最大不同点在于write函数和read函数,其他没什么不一样。


问:内核如何将数据传递给应用空间的程序?

答:上一节已经讲过了,使用copy_to_user函数。


详细请参考驱动源码:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <asm/uaccess.h>  
  2. #include <asm/irq.h>  
  3. #include <asm/io.h>  
  4. #include <linux/module.h>  
  5. #include <linux/device.h>     //class_create  
  6.   
  7. static struct class *seconddrv_class;  
  8. static struct device *seconddrv_device;  
  9.   
  10. volatile unsigned long *gpfcon = NULL;  
  11. volatile unsigned long *gpfdat = NULL;  
  12.   
  13. int major;  
  14. static int second_drv_open(struct inode * inode, struct file * filp)  
  15. {  
  16.     /*  K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0 
  17.      *  配置GPF1、GPF4、GPF2、GPF0为输入引脚 
  18.      */  
  19.      *gpfcon &= ~((0x3 << (1*2)) | (0x3 << (4*2)) | (0x3 << (2*2)) | (0x3 << (0*2)));  
  20.     return 0;  
  21. }  
  22.   
  23. static ssize_t second_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos)  
  24. {  
  25.     unsigned char key_vals[4];  
  26.     unsigned long val;      //用于接收按键值  
  27.   
  28.     if (size != sizeof(key_vals))  
  29.             return -EINVAL;  
  30.   
  31.     /*  K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0 
  32.      *  读GPF1、GPF4、GPF2、GPF0引脚值 
  33.      */  
  34.     val = *gpfdat;  
  35.     key_vals[0] = (val & (1<<1)) ? 1 : 0;  
  36.     key_vals[1] = (val & (1<<4)) ? 1 : 0;  
  37.     key_vals[2] = (val & (1<<2)) ? 1 : 0;  
  38.     key_vals[3] = (val & (1<<0)) ? 1 : 0;  
  39.   
  40.     /* 读出值后,将数据传给应用程序 */  
  41.     copy_to_user(user, key_vals, sizeof(key_vals));  
  42.   
  43.     return sizeof(key_vals);  
  44.       
  45. }  
  46. /* File operations struct for character device */  
  47. static const struct file_operations second_drv_fops = {  
  48.     .owner      = THIS_MODULE,  
  49.     .open       = second_drv_open,  
  50.     .read       = second_drv_read,  
  51. };  
  52.   
  53.   
  54. /* 驱动入口函数 */  
  55. static int second_drv_init(void)  
  56. {  
  57.     /* 主设备号设置为0表示由系统自动分配主设备号 */  
  58.     major = register_chrdev(0, "second_drv", &second_drv_fops);  
  59.   
  60.     /* 创建seconddrv类 */  
  61.     seconddrv_class = class_create(THIS_MODULE, "seconddrv");  
  62.   
  63.     /* 在seconddrv类下创建buttons设备,供应用程序打开设备*/  
  64.     seconddrv_device = device_create(seconddrv_class, NULL, MKDEV(major, 0), NULL, "buttons");  
  65.   
  66.     /* 将物理地址映射为虚拟地址 */  
  67.     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);  
  68.     gpfdat = gpfcon + 1;  
  69.       
  70.     return 0;  
  71. }  
  72.   
  73. /* 驱动出口函数 */  
  74. static void second_drv_exit(void)  
  75. {  
  76.     unregister_chrdev(major, "second_drv");  
  77.     device_unregister(seconddrv_device);  //卸载类下的设备  
  78.     class_destroy(seconddrv_class);     //卸载类  
  79.     iounmap(gpfcon);                    //解除映射  
  80. }  
  81.   
  82. module_init(second_drv_init);  //用于修饰入口函数  
  83. module_exit(second_drv_exit);  //用于修饰出口函数     
  84.   
  85. MODULE_AUTHOR("LWJ");  
  86. MODULE_DESCRIPTION("Just for Demon");  
  87. MODULE_LICENSE("GPL");  //遵循GPL协议  


应用测试程序源码:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include <sys/types.h>  
  3. #include <sys/stat.h>  
  4. #include <fcntl.h>  
  5. #include <unistd.h>  
  6.   
  7.   
  8. /* second_test 
  9.  */   
  10. int main(int argc ,char *argv[])  
  11.   
  12. {  
  13.     int fd;  
  14.     unsigned char key_vals[4];  
  15.     int cnt = 0;  //养成好习惯,用于计数时,一般初始化为0  
  16.       
  17.     fd = open("/dev/buttons",O_RDWR);  
  18.     if (fd < 0)  
  19.     {  
  20.         printf("open error\n");  
  21.     }  
  22.   
  23.     /* 查询方式死循环地读 */  
  24.     while(1)  
  25.     {  
  26.         read(fd,key_vals,sizeof(key_vals));  
  27.         if(!key_vals[0] || !key_vals[1] || (!key_vals[2]) || (!key_vals[3]))  
  28.         {  
  29.             printf("%04d key pressed: %d %d %d %d\n",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3]);  
  30.         }  
  31.     }  
  32.     return 0;  
  33. }  


测试步骤1:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. [WJ2440]# ls  
  2. Qt             etc            mnt            second_drv.ko  var  
  3. TQLedtest      first_drv.ko   opt            second_test    web  
  4. app_test       first_test     proc           sys  
  5. bin            home           root           tmp  
  6. dev            lib            sbin           udisk  
  7. driver_test    linuxrc        sddisk         usr  
  8. [WJ2440]# ls /dev/buttons -l  
  9. ls: /dev/buttons: No such file or directory  
  10. [WJ2440]# insmod second_drv.ko   
  11. [WJ2440]# lsmod   
  12. second_drv 2184 0 - Live 0xbf009000  
  13. [WJ2440]# ls /dev/buttons -l  
  14. crw-rw----    1 root     root      252,   0 Jan  2 01:52 /dev/buttons  
  15. [WJ2440]# ls sys/class/seconddrv/ -l  
  16. lrwxrwxrwx    1 root     root             0 Jan  2 01:52 buttons -> ../../devices/virtual/seconddrv/buttons  
  17. [WJ2440]# ./second_test   
  18. 0000 key pressed: 0 1 1 1  
  19. 0001 key pressed: 0 1 1 1  
  20. 0002 key pressed: 0 1 1 1  
  21. 0003 key pressed: 0 1 1 1  
  22. 0004 key pressed: 0 1 1 1  
  23. ....  
  24. 0305 key pressed: 1 0 1 1  
  25. 0306 key pressed: 1 0 1 1  
  26. 0307 key pressed: 1 0 1 1  
  27. 0308 key pressed: 1 0 1 1  
  28. 0309 key pressed: 1 0 1 1  
  29. ....  
  30. 0460 key pressed: 1 1 0 1  
  31. 0461 key pressed: 1 1 0 1  
  32. 0462 key pressed: 1 1 0 1  
  33. 0463 key pressed: 1 1 0 1  
  34. 0464 key pressed: 1 1 0 1  
  35. ....  
  36. 0615 key pressed: 1 1 1 0  
  37. 0616 key pressed: 1 1 1 0  
  38. 0617 key pressed: 1 1 1 0  
  39. 0618 key pressed: 1 1 1 0  
  40. 0619 key pressed: 1 1 1 0  

测试步骤2:

[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. [WJ2440]# ./second_test  &  
  2. [WJ2440]# top  
  3. Mem: 9988K used, 50176K free, 0K shrd, 0K buff, 7168K cached  
  4. CPU: 14.9% usr 84.8% sys  0.0% nic  0.0% idle  0.0% io  0.0% irq  0.1% sirq  
  5. Load average: 0.71 0.22 0.07 2/23 603  
  6.   PID  PPID USER     STAT   VSZ %MEM CPU %CPU COMMAND  
  7.   602   592 root     R     1432  2.3   0 99.0 ./second_test  
  8.   603   592 root     R     2092  3.4   0  0.7 top  
  9.   592     1 root     S     2092  3.4   0  0.0 -/bin/sh  
  10.     1     0 root     S     2088  3.4   0  0.0 init  
  11.   589     1 root     S     2088  3.4   0  0.0 /usr/sbin/telnetd -l /bin/login  
  12.   587     1 root     S     1508  2.5   0  0.0 EmbedSky_wdg  
  13.   573     2 root     SW<      0  0.0   0  0.0 [rpciod/0]  
  14.     5     2 root     SW<      0  0.0   0  0.0 [khelper]  
  15.   329     2 root     SW<      0  0.0   0  0.0 [nfsiod]  
  16.     2     0 root     SW<      0  0.0   0  0.0 [kthreadd]  
  17.     3     2 root     SW<      0  0.0   0  0.0 [ksoftirqd/0]  
  18.     4     2 root     SW<      0  0.0   0  0.0 [events/0]  
  19.    11     2 root     SW<      0  0.0   0  0.0 [async/mgr]  
  20.   237     2 root     SW<      0  0.0   0  0.0 [kblockd/0]  
  21.   247     2 root     SW<      0  0.0   0  0.0 [khubd]  
  22.   254     2 root     SW<      0  0.0   0  0.0 [kmmcd]  
  23.   278     2 root     SW       0  0.0   0  0.0 [pdflush]  
  24.   279     2 root     SW       0  0.0   0  0.0 [pdflush]  
  25.   280     2 root     SW<      0  0.0   0  0.0 [kswapd0]  
  26.   325     2 root     SW<      0  0.0   0  0.0 [aio/0]  

由测试步骤2可知,second_test进程在后台运行时,占用了将近99%的CPU利用率,显然,这种查询式驱动是不合理的,必将被取代。

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值