Tiny6410 ——LED 驱动程序设计


1、驱动程序


①、led.h

[plain] view plain copy
  1. #ifndef _LED_H_  
  2. #define _LED_H_  
  3.   
  4. #define DEVICE_NAME "tiny6410_led"  
  5.   
  6. #define LED_IOC_MAGIC   'l'         // 幻数  
  7.   
  8. #define LED_IOCGETDAT   _IOR(LED_IOC_MAGIC,1,int)   // LED 命令  
  9. #define LED_IOCSETDAT   _IOW(LED_IOC_MAGIC,2,int)  
  10.   
  11. #define LED_IOC_MAXNR   2  
  12.   
  13.   
  14. #endif  


②、led.c

[plain] view plain copy
  1. #include <linux/module.h>  
  2. #include <linux/types.h>  
  3. #include <linux/fs.h>  
  4. #include <linux/errno.h>  
  5. #include <linux/mm.h>  
  6. #include <linux/sched.h>  
  7. #include <linux/init.h>  
  8. #include <linux/cdev.h>  
  9. #include <linux/slab.h>  
  10. #include <asm/io.h>  
  11. #include <asm/system.h>  
  12. #include <asm/uaccess.h>  
  13. #include <linux/ioport.h>  
  14. #include <asm/io.h>  
  15. #include <linux/miscdevice.h>  
  16.   
  17. #include "led.h"  
  18.   
  19. unsigned long GPIOK_VA_BASE;            // led 对应 GPIOK 虚拟地址  
  20.   
  21. #define GPIOK_CON0_VA   GPIOK_VA_BASE       // led 对应 GPIOK 寄存器虚拟地址  
  22. #define GPIOK_CON1_VA   GPIOK_VA_BASE + 0X4  
  23. #define GPIOK_DAT_VA    GPIOK_VA_BASE + 0X8  
  24. #define GPIOK_PUD_VA    GPIOK_VA_BASE + 0XC  
  25.   
  26. #define GPIOK_PA_BASE   0X7F008800      // led 对应 GPIOK 物理地址  
  27.   
  28. struct resource tiny6410_led_resource =   
  29. {  
  30.     .name   = "led_io_mem",  
  31.     .start  = GPIOK_PA_BASE,  
  32.     .end    = GPIOK_PA_BASE + 0X10,  
  33.     .flags  = IORESOURCE_MEM,  
  34. };  
  35.   
  36. /*  
  37.  * tiny6410_led_pin_setup  
  38.  * 完成申请,映射,映射获得的虚拟地址由全局变量 GPIOK_VA_BASE 获得。  
  39.  * 同时,对 GPIOK 的配置寄存器进行初始化,设置 led 对应端口为输出。  
  40.  */  
  41. static void tiny6410_led_pin_setup(void)  
  42. {  
  43.     unsigned long start = tiny6410_led_resource.start;  
  44.     unsigned long size = tiny6410_led_resource.end - start;  
  45.     unsigned long tmp;  
  46.   
  47.     /* 申请 I/O 内存 */  
  48.     request_mem_region(start,size,tiny6410_led_resource.name);  
  49.   
  50.     /* 映射 I/O 内存 */  
  51.     GPIOK_VA_BASE = (unsigned long)ioremap(start,size);  
  52.   
  53.     printk("<1>[GPIOK_VA_BASE = 0x%lx]\n",GPIOK_VA_BASE);  
  54.   
  55.     /* 对应管教设置为输出 */  
  56.     tmp = readl(GPIOK_CON0_VA);  
  57.     tmp = (tmp & ~(0xffff << 16)) | (0x1111 << 16);  
  58.     writel(tmp,GPIOK_CON0_VA);  
  59.   
  60.     /* 对应管脚置高,使 led 全灭 */  
  61.     tmp = readl(GPIOK_DAT_VA);  
  62.     tmp &= ~(0xf << 4);  
  63.     writel(tmp,GPIOK_DAT_VA);  
  64. }  
  65.   
  66. /*   
  67.  * tiny6410_led_pin_release(void)  
  68.  * led 端口释放函数比较简单,仅仅是进行申请和映射的逆过程  
  69.  */  
  70. static void tiny6410_led_pin_release(void)  
  71. {  
  72.     iounmap((void *)GPIOK_VA_BASE);  
  73.     release_mem_region(tiny6410_led_resource.start,  
  74.                 tiny6410_led_resource.end - tiny6410_led_resource.start);  
  75.   
  76. }  
  77.   
  78. /*   
  79.  * 读 led 对应 GPIO 数据寄存器值的操作函数。  
  80.  */  
  81. static unsigned long tiny6410_led_getdat(void)  
  82. {  
  83.     return((readl(GPIOK_DAT_VA) >> 4) & 0XF);  
  84. }  
  85.   
  86. /*   
  87.  * 写 led 对应 GPIO 数据寄存器值的操作函数  
  88.  */  
  89. static void tiny6410_led_setdat(int dat)  
  90. {  
  91.     unsigned long tmp;  
  92.       
  93.     tmp = readl(GPIOK_DAT_VA);  
  94.     tmp = (tmp & ~(0xf << 4)) | ((dat & 0xf) << 4);  
  95.     writel(tmp,GPIOK_DAT_VA);  
  96. }  
  97.   
  98. /*  
  99.  * 实现 led 的 I/O 操作函数  
  100.  * 对于命令 LED_IOCGETDAT,我们调用函数 tiny6410_led_getdat() 获得对应端口  
  101.  * 寄存器的值,并通过 put_user() 函数将它传回用户空间。同样,对于命令  
  102.  * LED_IOCSETDAT,则将用户空间传过来的值,通过函数 tiny6410_led_setdat()   
  103.  * 设置对应的寄存器。  
  104.  */  
  105. static long led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)  
  106. {  
  107.     int ioarg,ret;  
  108.     int err = 0;  
  109.   
  110.     /* 检测命令的有效性,通过系统定义的宏操作 */  
  111.     if(_IOC_TYPE(cmd) != LED_IOC_MAGIC)  
  112.         return -EINVAL;  
  113.     if(_IOC_NR(cmd) > LED_IOC_MAXNR)  
  114.         return -EINVAL;  
  115.   
  116.     /* 根据命令类型,来检测参数空间是否可以访问 */  
  117.     if(_IOC_DIR(cmd) & _IOC_READ)  
  118.         /* 这里 access_ok() 返回值中:1 成功!0 失败! */  
  119.         err = !access_ok(VERIFY_WRITE,(void *)arg,_IOC_SIZE(cmd));  
  120.     else if(_IOC_DIR(cmd) & _IOC_WRITE)  
  121.         err = !access_ok(VERIFY_READ,(void *)arg,_IOC_SIZE(cmd));  
  122.   
  123.     if(err)  
  124.         return -EFAULT;  
  125.   
  126.     /* 根据命令,执行相应的操作 */  
  127.     switch(cmd)  
  128.     {  
  129.         /* 获取 led 对应的 rGPIOKDAT */  
  130.         case LED_IOCGETDAT:  
  131.             ioarg = tiny6410_led_getdat();  
  132.             ret = __put_user(ioarg,(int *)arg);  
  133.             break;  
  134.   
  135.         /* 设置 led 对应的 rGPIOKDAT */  
  136.         case LED_IOCSETDAT:  
  137.             ret = __get_user(ioarg,(int *)arg);  
  138.             tiny6410_led_setdat(ioarg);  
  139.             break;  
  140.   
  141.         /* default */  
  142.         default:  
  143.             return -EINVAL;  
  144.     }  
  145.   
  146.     return ret;  
  147. }  
  148.   
  149. /*  
  150.  * 文件操作结构体  
  151.  */  
  152. static const struct file_operations dev_fops =  
  153. {  
  154.     .unlocked_ioctl = led_ioctl,  
  155.     .owner = THIS_MODULE,  
  156. };  
  157.   
  158. /*   
  159.  * 混杂设备  
  160.  * 在编写混杂型字符设备驱动中,主设备号已经确定,此设备号可以指定  
  161.  * MISC_DYNAMIC_MINOR,这样在注册设备时,内核会自动分配次设备号。  
  162.  */  
  163. static struct miscdevice misc =  
  164. {  
  165.     .minor = MISC_DYNAMIC_MINOR,        // 次设备号  
  166.     .name = DEVICE_NAME,            // 设备名  
  167.     .fops = &dev_fops,          // 文件操作  
  168. };  
  169.   
  170. /*  
  171.  * 设备驱动模块加载函数  
  172.  */  
  173. static int __init dev_init(void)  
  174. {  
  175.     int ret;  
  176.   
  177.     tiny6410_led_pin_setup();  
  178.   
  179.     ret = misc_register(&misc);  
  180.   
  181.     printk("<1>Initialized minor = %d\n",misc.minor);  
  182.                         // 在使用 misc_register() 注册  
  183.                         // 混杂设备后,还会在 /dev 目录  
  184.                         // 下自动创建设备节点,节点名称  
  185.                         // 由设备名 DEVICE_NAME 指定。  
  186.   
  187.     return ret;  
  188. }  
  189.   
  190. /* 模块卸载函数 */  
  191. static void __exit dev_exit(void)  
  192. {  
  193.     tiny6410_led_pin_release();  
  194.   
  195.     misc_deregister(&misc);  
  196.   
  197. }  
  198.   
  199. module_init(dev_init);  
  200. module_exit(dev_exit);  


③、Makefile


[plain] view plain copy
  1. ifneq ($(KERNELRELEASE),)  
  2. obj-m := led.o  
  3.   
  4. else  
  5. KDIR := /home/_Jana/linux-2.6.38  
  6.   
  7. all:  
  8.     make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-  
  9.   
  10. clean:  
  11.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order  
  12.   
  13. endif  


2、测试程序


①、led.h(跟上面的一样!)


②、app_led.c


[plain] view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <unistd.h>  
  5. #include <sys/types.h>  
  6. #include <sys/stat.h>  
  7. #include <fcntl.h>  
  8.   
  9. #include "led.h"  
  10.   
  11. #define DEV_NAME    "/dev/" DEVICE_NAME  
  12.   
  13. int binstr_to_int(char *binstr)  
  14. {  
  15.     int ret = 0;  
  16.     int i = 0;  
  17.     char bnum[5];  
  18.     memset(bnum,'0',4);  
  19.       
  20.     int len = strlen(binstr);  
  21.       
  22.     if(len > 4)  
  23.         strcpy(bnum,binstr + len - 4);  
  24.     else  
  25.         strcpy(bnum + 4 - len,binstr);  
  26.   
  27.     for(i = 0;i < 4;i ++)  
  28.     {  
  29.         ret <<= 1;  
  30.         ret += (bnum[i] == '0' ? 1 : 0);  
  31.     }  
  32.   
  33.     return ret;  
  34. }  
  35.   
  36. int main(int argc,char **argv)  
  37. {  
  38.     if(argc > 2)  
  39.     {  
  40.         printf("Usage: %s <binary code>\n"  
  41.             "example: %s 1001 -- Will turn on led 0 and 3,"  
  42.             "and turn off led 1 and 2.\n",argv[0],argv[0]);  
  43.       
  44.         _exit(EXIT_FAILURE);  
  45.     }  
  46.   
  47.     int fd,arg;  
  48.       
  49.     if((fd = open("/dev/tiny6410_led",O_RDWR)) == -1)  
  50.     {  
  51.         printf("Open dev error!\n");  
  52.         _exit(EXIT_FAILURE);  
  53.     }  
  54.       
  55.     if(argc == 1)  
  56.     {  
  57.         ioctl(fd,LED_IOCGETDAT,&arg);  
  58.         printf("led dat: %d.\n",arg);  
  59.     }  
  60.     else  
  61.     {  
  62.         arg = binstr_to_int(argv[1]);  
  63.         printf("arg = %d.\n",arg);  
  64.         ioctl(fd,LED_IOCSETDAT,&arg);  
  65.     }  
  66.   
  67.   
  68.     _exit(EXIT_SUCCESS);  


你可能感兴趣的:(Module,cmd,user,IOC,Access,makefile)