【OK210试用体验】+第七篇☞led驱动源代码加深入分析 - 在线问答 - 电子技术论坛 - 最好最受欢迎电子论坛!

【OK210试用体验】+第七篇☞led驱动源代码加深入分析

杨永胜 ( 楼主 ) 2015-8-13 18:37:32  只看该作者 倒序浏览
` 本帖最后由 iysheng 于 2015-8-13 18:37 编辑

经过这么长时间的学习,今天可以深入分析一下简单的字符驱动程序led驱动的源代码了。
首先说明,本次驱动的编写,我主要使用了open,write,unlocked_ioctl等函数,使用write函数的原因主要是我想测试一下自己的想法,结果虽然可以,但是还不是很完美,所以,本次我主要发出来我写的基于unlocked_ioctl函数对led的控制源代码极其一些重要的注释,其中肯定有很多的不严谨的部分,但是整个框架还是很完整的。我主要使用了两个函数:open(主要完成初始化led的控制寄存器),unlocked_ioctl(对led的数据寄存器进行操作)。
  1. #include
  2. #include
  3. #include //struct cdev,cdev_init,cdev_add
  4. #include //file_operations
  5. #include //ioremap(物理地址到虚拟地址的映射函数)
  6. #include "led.h"//自己定义的命令(LED_ON,LED_OFF)的头文件

  7. #define LEDCON 0xe0200340//声明控制寄存器的物理地址
  8. #define LEDDAT 0xe0200344//声明数据寄存器的无力地址

  9. unsigned int *led_config; //定义控制寄存器物理地址映射后的地址指针
  10. unsigned int *led_data; //定义数据寄存器物理地址映射后的地址指针

  11. struct cdev leddev;//声明字符设备leddev
  12. dev_t devnum;//定义主设备号

  13. //定义open函数
  14. int led_open (struct inode *inode, struct file *filp){
  15.     led_config = ioremap(LEDCON, 4);//映射控制寄存器的物理地址
  16.     writel(0x11110000, led_config);//写入控制寄存器,使其output模式
  17.    
  18.     led_data = ioremap(LEDDAT, 4);//映射数据寄存器的物理地址
  19.     printk(KERN_INFO"welcome to ysled:
  20. ");//输出欢迎信息
  21.     return 0;
  22. }

  23. long led_ioctl (struct file *filp, unsigned int cmd, unsigned long arg){
  24.     if (cmd == LED_ON)//判断cmd(是点亮还是熄灭led)
  25.     {
  26.             switch (arg)//判断是对第几个led灯的操作
  27. {
  28.                 case 0:
  29.                     writeb(0x70, led_data);//点亮第一个led
  30.                     break;
  31.                 case 1:
  32.                     writeb(0xb0, led_data);
  33.                     break;
  34.                 case 2:
  35.                     writeb(0xd0, led_data);
  36.                     break;
  37.                 case 3:
  38.                     writeb(0xe0, led_data);
  39.                     break;
  40.                 default:
  41.                     printk(KERN_WARNING"no this led,please input 0 to 3!
  42. ");//输出警告信息
  43.                     break;                    
  44.             }
  45.     }
  46.     else if (cmd == LED_OFF)
  47.     {
  48.         switch (arg)
  49.             {
  50.                 case 0:
  51.                     writeb(0x80, led_data);//熄灭第一个led
  52.                     break;
  53.                 case 1:
  54.                     writeb(0x40, led_data);
  55.                     break;
  56.                 case 2:
  57.                     writeb(0x20, led_data);
  58.                     break;
  59.                 case 3:
  60.                     writeb(0x10, led_data);
  61.                     break;
  62.                 default:
  63.                     printk(KERN_WARNING"no this led,please input 0 to 3!
  64. ");//输出警告信息
  65.                     break;                    
  66.             }        
  67.     }
  68.     return 0;
  69. }

  70. //声明设备的一系列操作函数,本次主要使用了open,unlocked_ioctl函数
  71. static struct file_operations led_fops = {
  72.     .open = led_open,
  73.     .unlocked_ioctl = led_ioctl,
  74. };

  75. //led初始化函数,模块的入口
  76. static int led_init(void){
  77.     cdev_init(&leddev, &led_fops);//初始化leddev,建立和操作他的函数的联系
  78.     alloc_chrdev_region(&devnum, 0, 1, "ysled");//给字符设备leddev分配空间,其中0表示,从设备号从0开始编号,1表示1个设备
  79.     cdev_add(&leddev, devnum, 1); //注册设备,1表示1个设备。
  80.     return 0;   
  81. }

  82. //模块卸载函数
  83. static void led_exit(void){
  84.     cdev_del(&leddev);
  85.     unregister_chrdev_region(devnum, 1);
  86. }



  87. MODULE_LICENSE("GPL");//模块基于GPL协议,这样可以避免一个LICENSE的警告

  88. module_init(led_init);//宏定义模块入口函数
  89. module_exit(led_exit);//宏定义模块写在函数
复制代码
上面就是led驱动程序的源代码,涉及到的头文件led.h如下:
  1. #define LED_MAGIC 'L'//定义命令类型,也就是表示是led的命令
  2. #define LED_ON _IOW(LED_MAGIC, 0, char)//声明点亮led的命令码,LED_ON是一个unisgned int型的数据
  3. #define LED_OFF _IOW(LED_MAGIC, 1, char)//声明熄灭led的命令码,LED_OFF是一个unisgned int的数据,从驱动源代码的函数声明中可以看出来,_IOW是一个构造命令的宏
复制代码
接下来就是测试程序了,这时候,就简单些了(但是我写的write函数版的驱动,我就是在编写测试程序的时候遇到了一些问题,现在还没搞清楚呢,所以我就不仔细分析write函数了,实际他们的原理还是类似的,就是一个重要的一点要球物理地址大虚拟之地的映射ioremap),接下来就附上我写的测试程序源代码:
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include "led.h"//声明的LED_ON, LED_OFF命令
  6. #include
  7. int main(int argc, char *argv[]){
  8.     int fd;
  9.     int cmd;//指示点亮还是熄灭led
  10.     unsigned long arg;//指示第几个led灯

  11.     if (argc < 3)
  12.     {
  13.         printf("please input the second and third para!
  14. ");//输出警告信息,要求命令格式要正确
  15.         return 0;
  16.     }
  17.    
  18.     cmd = atoi(argv[1]);//字符转换成int类型,要知道argv[1],argv[2]都是字符型指针
复制代码
行了,至此,关于led驱动部分的源代码以及相关的测试程序都已经上传了,接下来就是我的测试结果了,嘿嘿,见图如下:
#./qq 1 2 表示只有第3个led灯熄灭,现象正确

#./qq 0 3 表示只有第4个led灯亮,现象正确
嗯,好了,现在就先说到这里了。


`

0个回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /6 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-4-25 03:17 , Processed in 0.715215 second(s), Total 64, Slave 44 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表