Chinaunix首页 | 论坛 | 博客
  • 博客访问: 208617
  • 博文数量: 32
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 850
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-22 15:50
文章存档

2014年(16)

2013年(16)

分类: 嵌入式

2013-12-10 09:39:43

                        初试MINI2440按键驱动—查询方式(polling)
开发环境    
                SYSTEM       :  Ubuntu-12.04

                Board        :  Mini2440-t35
                Bootloader   :  u-boot-1.1.6
                Kernel       :  Linux-2.6.22.6
                CROSS_COMPILE: arm-linux-gcc v3.4.5
一、搭建程序框架

点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <asm/arch/regs-gpio.h>
  6. #include <asm/hardware.h>

  7. #define DEVICE_NAME "MINI2440_BUTTONS" //设备名称
  8. #define DEVICE_MAJOR      231     //主设备号

  9. static struct file_operations buttons_polling_drv_fops = {
  10.     .owner = THIS_MODULE,
  11. };

  12. static int __init buttons_polling_drv_init(void)
  13. {
  14.     int ret;
  15.     ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &buttons_polling_drv_fops);
  16.     if(ret < 0)
  17.     {
  18.         printk(DEVICE_NAME "\t can't register major number!\n");
  19.     }
  20.     printk(DEVICE_NAME"\t initialized!\n");
  21.     return 0;
  22. }
  23. static void __exit buttons_polling_drv_exit(void)
  24. {
  25.     unregister_chrdev(DEVICE_MAJOR, DEVICE_NAME);
  26. }

  27. module_init(buttons_polling_drv_init);
  28. module_exit(buttons_polling_drv_exit);
  29. MODULE_LICENSE("GPL");
 Makefile内容:

点击(此处)折叠或打开

  1. KERN_DIR = /home/wangtisheng/work/kernel/linux-2.6.22.6-mini2440

  2. all:
  3.         make -C $(KERN_DIR) M=`pwd` modules

  4. clean:
  5.         make -C $(KERN_DIR) M=`pwd` modules clean
  6.         rm -rf modules.order

  7. obj-m += buttons_polling_drv.o
二、实现file_operations结构体buttons_polling_drv_fops中的各函数,本实例只是构造了open、read函数。
   
要操作S3C2440的IO口,首先要进行IO的初始化,根据MINI2440的原理图,应将按键对应GPIO口设置为输出模式,内核源码arch/arm/plat_s3c24xx/gpio.c中提供了初始化管脚功能的函数void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function),将初始化函数写在buttons_polling_drv_open函数中,代码如下:

点击(此处)折叠或打开

  1. static unsigned long buttons_polling_table[] = {
  2.     S3C2410_GPG0,
  3.     S3C2410_GPG3,
  4.     S3C2410_GPG5,
  5.     S3C2410_GPG6,
  6.     S3C2410_GPG7,
  7.     S3C2410_GPG11,
  8. };
  9. static unsigned long buttons_polling_cfg_table[] = {
  10.     S3C2410_GPB0_INP,
  11.     S3C2410_GPB3_INP,
  12.     S3C2410_GPB5_INP,
  13.     S3C2410_GPB6_INP,
  14.     S3C2410_GPB7_INP,
  15.     S3C2410_GPB8_INP,
  16. };

  17. static int buttons_polling_drv_open(struct inode *inode, struct file *file)
  18. {
  19.     int i;
  20.     
  21.     for (i = 0; i < 6; i++) {
  22.         s3c2410_gpio_cfgpin(buttons_polling_table[i], buttons_polling_cfg_table[i]);
  23.     }
  24.     return 0;
  25. }
        添加读取按键对应GPIO口状态的函数,内核源码arch/arm/plat_s3c24xx/gpio.c中提供了设置GPIO状态的函数unsigned int s3c2410_gpio_getpin(unsigned int pin)s3c2410_gpio_getpin()的返回值是GPxDAT寄存器的值与所要读取的GPIO对应的bit mask相与以后的值,0表示该GPIO对应的bit为0, 非0表示该bit为1。根据MINI2440原理图,当按键无动作,即按键没有被按下时GPIO口状态为1,反之为0。
        注:内核提供了专门的函数用于访问用户空间的指针:
                int copy_from_user(void *to,const void __user *from,int n);             //从用户空间拷贝数据到内核空间
                int copy_to_user(void __user *to,const void *form,int n);                 //从内核区中读取数据到用户区
    内核空间 :
            Linux操作系统,特别是它的内核,用一种简单而有效的方法管理机器的硬件,给用户提供一个简捷而统一的编程接口。同样的,内核,特别是它的设备驱动程序,是连接最终用户/程序员和硬件的一座桥或者说是接口。任何子程序或者函数只要是内核的一部分(例如:模块,和设备驱动),那它也就是内核空间的一部分。
    用户空间.:
            最终用户的应用程序,像UNIX的shell或者其它的GUI的程序(例如,gedit),都是用户空间的一部分。很显然,这些应用程序需要和系统的硬件进行交互。但是,他们不是直接进行,而是通过内核支持的函数进行。

点击(此处)折叠或打开

  1. ssize_t buttons_polling_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
  2. {
  3.     unsigned char key_vals[6];
  4.     
  5.     if(size != sizeof(key_vals))
  6.         return -EINVAL;

  7.     key_vals[0] = (s3c2410_gpio_getpin(S3C2410_GPG0) & (1<<0)) ? 1 : 0;    //值为1表示按键没有被按下,反之按键被按下
  8.     key_vals[1] = (s3c2410_gpio_getpin(S3C2410_GPG3) & (1<<3)) ? 1 : 0;
  9.     key_vals[2] = (s3c2410_gpio_getpin(S3C2410_GPG5) & (1<<5)) ? 1 : 0;
  10.     key_vals[3] = (s3c2410_gpio_getpin(S3C2410_GPG6) & (1<<6)) ? 1 : 0;
  11.     key_vals[4] = (s3c2410_gpio_getpin(S3C2410_GPG7) & (1<<7)) ? 1 : 0;
  12.     key_vals[5] = (s3c2410_gpio_getpin(S3C2410_GPG11) & (1<<11)) ? 1 : 0;

  13.     copy_to_user(buf,key_vals,sizeof(key_vals));
  14.         
  15.     return sizeof(key_vals);        
  16. }
三、测试驱动程序buttons_polling_drv_test.c

点击(此处)折叠或打开

  1. #include <fcntl.h>
  2. #include <stdio.h>

  3. int main(int argc,char **argv)
  4. {
  5.     int fd;
  6.     unsigned char key_vals[6];
  7.     int cnt = 0;
  8.     
  9.     fd = open("/dev/MINI2440_BUTTONS", O_RDWR);
  10.     if(fd < 0)
  11.     {
  12.         printf("can't open\n");
  13.     }
  14.     
  15.     while(1)
  16.     {
  17.         read(fd,key_vals,sizeof(key_vals));
  18.         if( !key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3] || !key_vals[4] || !key_vals[5] )
  19.         {
  20.             printf("%4d key pressed %d %d %d %d %d %d\n",cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5]);
  21.         }
  22.     }
  23.     return 0;
  24. }
    执行如下命令即可得到测试程序的可执行文件:   
                arm-linux-gcc -o buttons_polling_drv_test buttons_polling_drv_test.c
四、驱动加载、测试
    将模块
buttons_polling_drv.ko
和测试程序buttons_polling_drv_test拷贝至根文件系统根目录,我的开发板mini2440采用NFS方式挂载根文件系统。

        挂载模块
            # insmod
buttons_polling_drv.ko

            # cat /proc/devices
        至此即可看到驱动程序已挂载如下:
            231 MINI2440_BUTTONS
        创建该设备节点
            # mknod /dev/
MINI2440_BUTTONS 
c 231 0

              驱动测试:
                  执行 # ./buttons_polling_drv_test执行按键驱动测试程序,当有按键按下时出现如下结果,
                                                            
        将程序后台运行,使用top命令查看各进程的占用资源情况,可以看到
buttons_polling_drv_test进程占用了CPU的99%的资源,可见查询方式是非常消耗CPU资源的,下一步将该程序修改为中断方式实现。

完整代码如下:
buttons_polling_drv.rar
阅读(1820) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~