Chinaunix首页 | 论坛 | 博客
  • 博客访问: 231581
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-20 14:21
文章分类

全部博文(76)

文章存档

2015年(76)

我的朋友

分类: 其他平台

2015-03-17 13:00:33

ok6410 linux的第一个驱动LED驱动

//驱动程序代码

  1. /**************************************************************************************************************** 
  2.  * 文件名称 :   led_drive.c 
  3.  * 简介       :   OK6410 LED驱动 
  4.  * 作者       :   异灵元(cp1300@139.com) 
  5.  * 创建时间 :   2012/08/27 17:28 
  6.  * 修改时间 :   2012/08/27 
  7.  * 说明       :   OK6410 开发板(S3C6410)LED(GPIO)驱动 
  8.  ****************************************************************************************************************/  
  9.   
  10. //系统头文件  
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17. #include   
  18. #include   
  19. #include   
  20. #include   
  21. #include   
  22. #include   
  23. #include   
  24. #include   
  25. #include   
  26. #include   
  27. #include   
  28. #include   
  29. #include   
  30. #include   
  31. #include   
  32. #include   
  33. //--------------------------//  
  34. #include   
  35. #include   
  36. #include   
  37. //--------------------------//  
  38. #include   
  39. #include   
  40. #include   
  41.   
  42.   
  43. ///////////////////////////////////////////////  
  44. //驱动模块名称  
  45. #define DEVICE_NAME "OK6410_LED"  
  46.   
  47. //函数声明  
  48. ///////////////////////////////////////////////  
  49. static long OK6410_LED_ioctl(  
  50.         struct file *file,  
  51.         unsigned int cmd,  
  52.         unsigned long arg);  
  53. static ssize_t OK6410_LED_write(  
  54.         struct file *file,  
  55.         const char __user *buff,  
  56.         size_t size,  
  57.         loff_t *loff);  
  58. static ssize_t OK6410_LED_read(  
  59.         struct file *file,  
  60.         char __user *buff,  
  61.         size_t size,  
  62.         loff_t *loff);  
  63. ///////////////////////////////////////////////////  
  64.   
  65.   
  66. /*  这个结构是字符设备驱动的核心 
  67. *   当应用程序操作设备文件所提供的open,read,write等函数, 
  68. *   最终会调用到这个结构中的对应函数 
  69. */  
  70. static struct file_operations dev_fops = {  
  71.         .owner              = THIS_MODULE,      //这是一个宏,指向编译模块时自动创建的__this_module变量  
  72.         .unlocked_ioctl     = OK6410_LED_ioctl,  
  73.         .read               = OK6410_LED_read,  
  74.         .write              = OK6410_LED_write  
  75. };  
  76.   
  77. //注册驱动所使用的相关信息  
  78. static struct miscdevice misc = {  
  79.         .minor = MISC_DYNAMIC_MINOR,  
  80.         .name = DEVICE_NAME,                        //驱动模块名称  
  81.         .fops = &dev_fops,  
  82. };  
  83.   
  84. //LED设备访问信号量  
  85. struct semaphore led_sem;  
  86.   
  87.   
  88. /**************************************************************************************************************** 
  89. *函数名        :   static int  __init OK6410_LED_init(void) 
  90. *功能       : LED模块初始化函数 
  91. *参数       : 无 
  92. *返回       : 0:成功;<0:失败 
  93. *依赖       :     linux底层宏定义 
  94. *作者       : 异灵元(cp1300@139.com) 
  95. *创建时间   :   2012/08/27 17:28 
  96. *最后修改时间:    2012/08/27 17:28 
  97. *说明     :   初始化LED硬件,注册LED驱动 
  98. ****************************************************************************************************************/  
  99. static int  __init OK6410_LED_init(void)  
  100. {  
  101.     int ret;  
  102.     unsigned int reg;  
  103.   
  104.     //GPIOM0-3 推挽输出  
  105.     reg = readl(S3C64XX_GPMCON);    //获取GPIOM寄存器数据  
  106.     reg &= (~0xffff);                   //清除之前设置  
  107.     reg |= 0x1111;                  //推挽输出  
  108.     writel(reg,S3C64XX_GPMCON);     //配置IO模式  
  109.     reg = readl(S3C64XX_GPMDAT);    //读取输出寄存器之前数据  
  110.     reg |= 0xf;  
  111.     writel(reg,S3C64XX_GPMDAT);     //写入1,让所有的灯都熄灭  
  112.   
  113.     ret = misc_register(&misc);     //注册驱动  
  114.     if(ret < 0)  
  115.     {  
  116.         printk(KERN_ALERT DEVICE_NAME " can't initialized LED!\n");  
  117.         return ret;  
  118.     }  
  119.     init_MUTEX(&led_sem);           //注册信号量  
  120.     printk(KERN_ALERT DEVICE_NAME " initialized\n");  
  121.     return 0;                           //返回成功  
  122. }  
  123.   
  124.   
  125. /**************************************************************************************************************** 
  126. *函数名        :   static long OK6410_LED_ioctl( 
  127.                         struct file *file, 
  128.                         unsigned int cmd, 
  129.                         unsigned long arg) 
  130. *功能       : 发送命令给LED驱动模块,无实际作用,直接返回0 
  131. *参数       : 无作用 
  132. *返回       : 0 
  133. *依赖       :     无 
  134. *作者       : 异灵元(cp1300@139.com) 
  135. *创建时间   :   2012/08/27 17:28 
  136. *最后修改时间:    2012/08/27 17:28 
  137. *说明     :   无 
  138. ****************************************************************************************************************/  
  139. static long OK6410_LED_ioctl(  
  140.         struct file *file,  
  141.         unsigned int cmd,  
  142.         unsigned long arg)  
  143. {  
  144.     return 0;  
  145. }  
  146.   
  147.   
  148. /**************************************************************************************************************** 
  149. *函数名        :   static ssize_t OK6410_LED_write( 
  150.                         struct file *file, 
  151.                         const char __user *buff, 
  152.                         size_t size, 
  153.                         loff_t *loff) 
  154. *功能       : 写数据到LED驱动模块,低电平灯亮 
  155. *参数       : file:文件指针(无作用);buff:数据缓冲区指针;buff:数据数量;loff:无作用 
  156. *返回       : 0:成功;<0:失败 
  157. *依赖       :     linux底层宏 
  158. *作者       : 异灵元(cp1300@139.com) 
  159. *创建时间   :   2012/08/27 17:43 
  160. *最后修改时间:    2012/08/27 17:43 
  161. *说明     :   点灯函数,低电平亮,0-3BIT有效;对应4个LED 
  162. ****************************************************************************************************************/  
  163. static ssize_t OK6410_LED_write(  
  164.         struct file *file,  
  165.         const char __user *buff,  
  166.         size_t size,  
  167.         loff_t *loff)  
  168. {  
  169.     unsigned int reg;  
  170.   
  171.     if(down_interruptible(&led_sem))    //获取信号量  
  172.         return -ERESTARTSYS;  
  173.     reg = readl(S3C64XX_GPMDAT);  
  174.     reg &= (~0xf);  
  175.     reg |= buff[0] & 0xf;  
  176.     writel(reg,S3C64XX_GPMDAT);  
  177.     up(&led_sem);                           //释放信号量  
  178.   
  179.     return 0;  
  180. }  
  181.   
  182.   
  183. /**************************************************************************************************************** 
  184. *函数名        :   static ssize_t OK6410_LED_read( 
  185.                         struct file *file, 
  186.                         char __user *buff, 
  187.                         size_t size, 
  188.                         loff_t *loff) 
  189. *功能       : 读LED状态,低电平灯亮 
  190. *参数       : file:文件指针(无作用);buff:数据缓冲区指针;buff:数据数量;loff:无作用 
  191. *返回       : 0:成功;<0:失败 
  192. *依赖       :     linux底层宏 
  193. *作者       : 异灵元(cp1300@139.com) 
  194. *创建时间   :   2012/08/27 17:48 
  195. *最后修改时间:    2012/08/27 17:48 
  196. *说明     :   读取灯的状态,低电平灯亮,0-3bit有效;对应4个LED 
  197. ****************************************************************************************************************/  
  198. static ssize_t OK6410_LED_read(  
  199.         struct file *file,  
  200.         char __user *buff,  
  201.         size_t size,  
  202.         loff_t *loff)  
  203. {  
  204.     unsigned int reg;  
  205.   
  206.     if(down_interruptible(&led_sem))    //获取信号量  
  207.         return -ERESTARTSYS;  
  208.     reg = readl(S3C64XX_GPMDAT);  
  209.     buff[0] = reg | 0xfffffff0;  
  210.     up(&led_sem);                           //释放信号量  
  211.   
  212.     return 0;  
  213. }  
  214.   
  215.   
  216.   
  217. /**************************************************************************************************************** 
  218. *函数名        :   static void __exit OK6410_LED_exit(void) 
  219. *功能       : 卸载LED驱动 
  220. *参数       : 无 
  221. *返回       : 无 
  222. *依赖       :     linux底层宏 
  223. *作者       : 异灵元(cp1300@139.com) 
  224. *创建时间   :   2012/08/27 17:50 
  225. *最后修改时间:    2012/08/27 17:50 
  226. *说明     :   卸载驱动 
  227. ****************************************************************************************************************/  
  228. static void __exit OK6410_LED_exit(void)  
  229. {  
  230.     unsigned int reg;  
  231.   
  232.     //GPIOM0-3 输入  
  233.     reg = readl(S3C64XX_GPMCON);    //获取GPIOM寄存器数据  
  234.     reg &= (~0xffff);                   //清除之前设置  
  235.     writel(reg,S3C64XX_GPMCON);     //配置IO模式  
  236.     misc_deregister(&misc);         //卸载驱动  
  237. }  
  238.   
  239.   
  240.   
  241. //动态加载驱动接口(必须)  
  242. module_init(OK6410_LED_init);  
  243. module_exit(OK6410_LED_exit);  
  244. //其它信息(非必需)  
  245. MODULE_AUTHOR("cp1300@139.com");                        //驱动程序作者  
  246. MODULE_DESCRIPTION("OK6410(S3C6410) LED Driver");   //一些描述信息  
  247. MODULE_LICENSE("GPL");  //遵循的协议  


//测试代码
  1. /**************************************************************************************************************** 
  2.  * 文件名称 :   led_drive_test.c 
  3.  * 简介       :   OK6410 LED驱动测试程序 
  4.  * 作者       :   异灵元(cp1300@139.com) 
  5.  * 创建时间 :   2012/08/27 18:04 
  6.  * 修改时间 :   2012/08/27 
  7.  * 说明       :   OK6410 开发板(S3C6410)LED(GPIO)驱动测试程序 
  8.  ****************************************************************************************************************/  
  9.   
  10.   
  11. #include   
  12. #include   
  13. #include   
  14. #include   
  15. #include   
  16. #include   
  17.   
  18.   
  19.   
  20. int main(void)  
  21. {  
  22.     int fd;  
  23.     int retval;  
  24.     unsigned char led;  
  25.   
  26.     //LED测试  
  27.     printf("LED test...\n");  
  28.     fd = open("/dev/OK6410_LED",O_RDWR);        //open led  
  29.     if(fd == -1)  
  30.     {  
  31.         printf("open led error!\n");  
  32.         exit(-1);  
  33.     }  
  34.     else  
  35.     {  
  36.         printf("open led ok!\n");  
  37.     }  
  38.     while(1)  
  39.     {  
  40.         for(retval = 0;retval < 4;retval ++)  
  41.         {  
  42.             led = 1 << retval;  
  43.             led = ~led;  
  44.             write(fd,&led,sizeof((unsigned char)1));  
  45.             //read(fd,&led,sizeof((unsigned char)1));  
  46.             //printf("LED = 0x%X\n",led);  
  47.             usleep(1000 * 100); //100MS  
  48.         }  
  49.   
  50.         for(retval = 2;retval > 0;retval --)  
  51.         {  
  52.             led = 1 << retval;  
  53.             led = ~led;  
  54.             write(fd,&led,sizeof((unsigned char)1));  
  55.             //read(fd,&led,sizeof((unsigned char)1));  
  56.             //printf("LED = 0x%X\n",led);  
  57.             usleep(1000 * 100); //100MS  
  58.         }  
  59.   
  60.     }  
  61.     close(fd);  
  62.     exit(0);  
  63. }  

本驱动程序使用的是混杂设备驱动模型,主设备号为10,使用次设备号来区分不同的设备,使用宏MISC_DYNAMIC_MINOR可以自动分配次设备号。
makefile代码如下:
ifneq ($(KERNELRELEASE),)
obj-m:=led_drive.o
else
KERNELDIR:=/opt/kernel/linux-3.0.1
PWD:=$(shell pwd)
default:
	$(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:
	rm -rf *.o *.mod.c *.mod.o *~ module* Module*
endif
KERNELDIR为内核路径,led_drive.o中的led_drive来自于源码文件名led_drive.c
执行make编译完成后会在模块源码目录下生成led_drive.ko
在开发板创建目录/lib/modules/3.0.1/,3.0.1为内核版本,可以通过cat /proc/version查看。将led_drive.ko拷贝至/lib/modules/3.0.1/,执行insmod led_drive.ko,会在/dev/目录下生成设备文件OK6410_LED。执行ls -l OK6410_LED 可以看到其主设备号为10,自动分配的次设备号为54。执行应用程序led_drive_test,可观察到led出现流水灯效果。
阅读(984) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~