uClinux驱动实例 LED

uClinux驱动编写心得(uClinux2.4+S3C44B0X) 
  下面的内容绝大部分不是我写的,我是根据网上前辈高手的教程一步一步来做的。但是,在编译的过程中发现资料还是有点错误和关键点的遗漏。昨晚加上今天一整天,回忆编译的过程,稍微有点理解编译的方法了。晚上改了半个小时,搞定,驱动能用了,虽然仅仅是点个led灯,但是修正编译时的错误就像侦探破案一样,成功后心情真爽啊!我把我修正后的文章重新发出来,让更多人能看到。ps今天又搜索了一整天,还是没找到更多驱动相关的资料,希望大家能够提供下。 
  前期准备: 
  既然要编写uClinux驱动,就要在操作系统和硬件之间打交道,我用的板子是经典的S3C44B0X,驱动教程基于uClinux2.4版本,2.6版本不太一样,还没有找到资料。 
1) 需要掌握针对uClinux的打补丁、裁剪、编译全过程,自己可以编译一个完整的uClinux系统下载到开发板的flash中并正常工作。这方面的教程网上更多,我就下了数个版本。 
2) 需要熟悉S3C44B0X的硬件资源,本例子很简单,要想驱动其他东西就复杂咯。 

一共要编写2个C文件,一个是led.c,属于驱动文件,另外一个是ledtest.c属于用户程序,还有一个led.h头文件。 
  /////////////////////led.h文件内容/////////////////////////// 
  /****************************************Copyright (c)************************************************** 
  **               FREE 
  **--------------File Info------------------------------- 
  ** File Name: led.h 
  ** Last modified Date:   2008-6-3 
  ** Last Version: 1.0 
  ** Descriptions: User Configurable File 
  **---------------------------------------------------- 
  ** Created By: 
  ** Created date:    2008-6-3 
  ** Version: 1.0 
  ** Descriptions: First version 
  **------------------------------------------------- 
  ** Modified by:MAMAJINCO 
  ** Modified date:2006-9-9 
  ** Version:1.0 
  ** Descriptions:在此忠心感谢ZLG的模版 我的高质量编程意识起源于此 
  *****************************************************/ 
  //防止重复包含此文件而设置的宏 
  #ifndef __CONFIG_H 
  #define __CONFIG_H  
  //包含必要的头文件 
  #include <linux/config.h> 
  #include <linux/module.h> //模块必须包含的头文件 
  #include <linux/kernel.h>        /* printk()函数,用于向内核输出信息 */ 
  #include <linux/fs.h>            /* 很重要 其中包含了如file_opration等结构 此结构用于文件层接口 */ 
  #include <linux/errno.h>         /* 错误代码*/ 
  #include <asm/uaccess.h> 
  #include <linux/types.h> 
  #include <linux/mm.h> 
  #include <asm/arch/s3c44b0x.h>  
  /********************************/ 
  /*      应用程序配置              */ 
  /********************************/ 
  //以下根据需要改动 
  //定义主设备号 设备名称   
  #define LED_MAJOR_NR 231 //231~239 240~255都可以   
  #define DEVICE_NAME "led"                /* name for messaging */   
  #define SET_LED_OFF 0 
  #define SET_LED_ON   1  
  #endif 
  /************************End Of File 
  *********************************************************/ 


   
  ////////////////////led.c文件内容//////////////////////////////////// 
  /*************Copyright (c)************************** 
  **               FREE 
  **--------------File Info----------------------------------------- 
  ** File Name: led.c 
  ** Last modified Date:   
  ** Last Version: 1.0 
  ** Descriptions: User Configurable File 
  **---------------------------------------------------- 
  ** Created By: ZLG CHENMINGJI 
  ** Created date:    2006-9-9 
  ** Version: 1.0 
  ** Descriptions: First version 
  **-------------------------------------------------------- 
  ** Modified by:MAMAJINCO 
  ** Modified date: 
  ** Version:1.0 
  ** Descriptions:在此忠心感谢ZLG的模版 我的高质量编程意识起源于此 
  ***********************************************************/ 
  #include "led.h"//包含驱动头文件 
  
  /************************************************************ 
                 function announce 
  ******************************************************/ 
  //以下是关键函数的声明 
  static int led_open(struct inode *inode, struct file *filp);   
  //打开设备时用的 linux把设备当作文件管理 设备最好在用的时候再打开 尽量不要提前 
  static int led_release(struct inode *inode, struct file *filp); 
  static int led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 
                   unsigned long param);    
  //控制函数 这里用于控制LED亮与灭 
  int   led_init(void);//注册时用的 注意 模块注册的越早越好 
  void led_cleanup(void);//卸载时用的 
   
  /************************************************************* 
  **                   "全局和静态变量在这里定义"          
  **         global variables and static variables define here  
  /****************************************************************/   
  static struct file_operations LED_fops =         /* 前面基础部分提到的重要结构体了*/ 
  { 
       owner:       THIS_MODULE,   
  #if 0/*注意:#if 0-#endif里的代码是不编译的,但这里为了驱动模板讲解上的完整性仍然加上了*/ 
       llseek:      gpio_llseek, 
       read:        gpio_read, 
       write:       gpio_write, 
  #endif 
       ioctl:       led_ioctl,//控制函数 
       open:        led_open, //打开函数,打开文件时做初始化的 
       release:     led_release,//释放函数,关闭时调用 
  }; 
                    
  /************************************************************** 
  ** Function name: led_open 
  ** Descriptions:   open device 
  ** Input:inode:    information of device 
  **        filp:     pointer of file 
  ** Output 0:       OK 
  **         other:   not OK 
  ** Created by:     Chenmingji 
  ** Created Date:   2006-9-9 
  **------------------------------------------------------------- 
  ** Modified by:mamajinco 
  ** Modified Date: 2006-9-9 
  **-------------------------------------------------------------- 
  **************************************************************/ 
   
  static int led_open(struct inode *inode, struct file *filp) 
  { 
   /*初始化放在OPEN里*/  
   (*(volatile unsigned *)S3C44B0X_PCONC) &= 0xffffffc0; 
   (*(volatile unsigned *)S3C44B0X_PCONC) |= 0xffffffd5; /*GPIO C口0~2 设置为输出*/   
   (*(volatile unsigned *)S3C44B0X_PUPC) &= 0xffffffc0;/*GPIO C口0~2 设置为上拉*/   
        MOD_INC_USE_COUNT; 
        return 0;           
  } 
     
  /********************************************************* 
  ** Function name: led_release 
  ** Descriptions:   release device 
  ** Input:inode:    information of device 
  **        filp:     pointer of file 
  ** Output 0:       OK 
  **         other:   not OK 
  ** Created by:     Chenmingji 
  ** Created Date:   2006-9-9 
  **----------------------------------------------------- 
  ** Modified by: mamajinco 
  ** Modified Date: 2006-9-9 
  **-------------------------------------------------------- 
  ****************************************************/  
  static int led_release(struct inode *inode, struct file *filp) 
  { 
       MOD_DEC_USE_COUNT; 
       return(0); 
  } 
   
  /**************************************************** 
  ** Function name: led_ioctl 
  ** Descriptions:   IO control function 
  ** Input:inode:    information of device 
  **        filp:     pointer of file 
  **        cmd:      command 
  **        arg:      additive parameter 
  ** Output 0:       OK 
  **         other:   not OK 
  ** Created by:     Chenmingji 
  ** Created Date:   2006-9-9 
  **------------------------------------------------------- 
  ** Modified by: mamajinco 
  ** Modified Date: 2006-9-9 
  **---------------------------------------------------------- 
  ***********************************************************/   
  static int led_ioctl(struct inode *inode, struct file *filp, 
                          unsigned int cmd, unsigned long arg) 
  { 
       if( arg > 2 )//判断IO是否属于0-2 
   return -1; 
   
       switch(cmd) 
       { 
           case 0://把ARG传来的IO口编号转换成寄存器数据,把相应IO口置低 
            (*(volatile unsigned *)S3C44B0X_PDATC) |= 0x1 << arg; 
   
                break; 
   
           case 1://把ARG传来的IO口编号转换成寄存器数据,把相应IO口置高 
     (*(volatile unsigned *)S3C44B0X_PDATC) &= 0x0 << arg; 
                break; 
   
           default: 
     return -1; 
     break; 
       } 
       return 0; 
  } 
   
  /************************************************** 
  ** Function name: led_init 
  ** Descriptions:   init driver 
  ** Input:none 
  ** Output 0:       OK 
  **         other:   not OK 
  ** Created by:     Chenmingji 
  ** Created Date:   2006-9-9 
  **------------------------------------------------ 
  ** Modified by: mamajinco 
  ** Modified Date: 2006-9-9 
  **----------------------------------------------------- 
  *************************************************/   
  int led_init(void) 
  { 
       int   result;   
       result = register_chrdev(231,"led",   &LED_fops); 
  /*关键语句 用于注册 
  ** 注意!这是传统的注册方法 在2.4以上的linux版本中 加入了devfs设备文件系统 使注册更容易 但为了与大部分资料相**同 大家看的方便   这里仍然使用老方法*/ 
       if (result < 0) //用于异常检测 
       { 
           printk(KERN_ERR DEVICE_NAME ": Unable to get major %d\n", LED_MAJOR_NR ); //printk用于向内核输出信息 
           return(result); 
       } 
       printk(KERN_INFO DEVICE_NAME ": init OK\n");    
   return(0); 
  } 
   
   
  /************************************************************* 
  ** Function name: led_cleanup 
  ** Descriptions:   exit driver 
  ** Input:none 
  ** Output none 
  ** Created by:     Chenmingji 
  ** Created Date:   2006-9-9 
  **-------------------------------------------------------- 
  ** Modified by: mamajinco 
  ** Modified Date: 2006-9-9 
  **----------------------------------------------------- 
  **************************************************/   
  void led_cleanup(void) 
  { 
       unregister_chrdev(231, "led"); //与register_chrdev配对使用 用于清楚驱动 
  } 
   
  /*********************************************************** 
  **                             End Of File 
  ****************************************************/ 





  
  ///////////////////最后是ledtest.c文件内容/////////////////////// 
   
  /*********************Copyright (c)************************** 
  **               FREE 
  **--------------File Info---------------------------- 
  ** File Name: led.c 
  ** Last modified Date:   2006-9-9 
  ** Last Version: 1.0 
  ** Descriptions: User Configurable File 
  **------------------------------------------------------- 
  ** Created By: ZLG CHENMINGJI 
  ** Created date:    2006-9-9 
  ** Version: 1.0 
  ** Descriptions: First version 
  **-------------------------------------------------------- 
  ** Modified by:MAMAJINCO 
  ** Modified date:2006-9-9 
  ** Version:1.0 
  ** Descriptions:在此忠心感谢ZLG的模版 我的高质量编程意识起源于此 
  ********************************************************/  
  #include <stdio.h> 
  #include <stdlib.h> 
  #include <unistd.h> 
  #include <fcntl.h> 
  #include <sys/types.h> 
  #include <sys/stat.h> 
   
  void delay(int delay)//延时用函数 
  { 
   int i; 
   for(;delay>0;delay--) 
   { 
     for(i=0 ; i < 5000 ; i ++);   
   } 
  } 
   
  int main() 
  { 
   int fd1; 
   int j; 
   fd1= open("/dev/led" , O_RDWR);/*打开设备,就象打开文件一样简单*/ 
   if(fd1 == -1)/*异常处理*/ 
   { 
     printf ( "file can not be open" ); 
     return -1; 
   } 
   for (j =0 ; j< 10 ; j ++)/*重复10次*/ 
   { 
     ioctl(fd1 , 1 , 0);/*GPC0上LED亮*/ 
     delay(1000); 
     ioctl(fd1 , 0 , 0);/*GPC0上LED灭*/ 
     ioctl(fd1 , 1 , 1);/*GPC1上LED亮*/ 
     delay(1000); 
     ioctl(fd1 , 0 , 1);/*GPC1上LED灭*/ 
     ioctl(fd1 , 1 , 2);/*GPC2上LED亮*/ 
     delay(1000); 
     ioctl(fd1 , 0 , 2);/*GPC2上LED灭*/ 
     delay(1000); 
   }  
   close (fd1);/*关闭设备(文件)*/ 
   return 0; 
     
  } 
  /*********************************************************** 
  **                             End Of File 
  ****************************************************/ 
   
   

////////////////////////////////////////////////// 
现在有了led.h led.c ledtest.c三个文件了,正式开始吧 
   
  PART A 修改驱动 
1) 把led.h和led.c 丢到目录uClinux-dist/linux-2.4.x/drivers/char中 
2) 修改文件 
===============START============== 
uClinux-dist/linux-2.4.x/drivers/char/Makefile 
---------------------------------------------- 
obj-$(CONFIG_C5471_WDT) += wdt_c5471.o之后加 
obj-$(CONFIG_LED) += led.o 
================END============ 
3) 修改文件 
=================START=========== 
uClinux-dist/linux-2.4.x/drivers/char/Config.in 
----------------------------------------- 
if [ "$CONFIG_CPU_S3C44B0X" = "y" ]; then 
    bool 'Samsung S3C44B0X serial ports support' CONFIG_SERIAL_S3C44B0X之后加 
    bool 'Test LED Driver' CONFIG_LED 
================END================= 
4) 修改文件 
=================START============= 
uClinux-dist/linux-2.4.x/drivers/char/mem.c 
----------------------------------------- 
开头的地方扎堆加 
#ifdef CONFIG_LED 
extern void led_init(void); 
#endif 

int __init chr_dev_init(void)之后加 
#ifdef CONFIG_LED 
led_init(); 
#endif 
================END============== 
5) 继续修改文件 
=================START============ 
uClinux-dist/vendors/Samakmsung/44B0/Makefile 
----------------------------------------- 
ttypc,c,3,12 ttypd,c,3,13 ttype,c,3,14 ttypf,c,3,15\之后加 

led,c,231,0 \ 
================END============== 



PART B 修改用户程序 
1) 把ledtest.c丢入自己建立的目录uClinux-dist/user/ledtest 
2) 修改文件 
================START============ 
uClinux-dist/user/Makefile 
----------------------------------------- 
扎堆加个下面 
dir_$(CONFIG_USER_LEDTEST)    += ledtest 
=================END=============== 
3) 修改文件 
================START============ 
uClinux-dist/config/Configure.help 
----------------------------------------- 
扎堆加个下面 
CONFIG_USER_LEDTEST 
   Test the LED driver 
=================END============= 
4) 修改文件,就是在最后加上一段 
================START================ 
uClinux-dist/config/Configure.in 
----------------------------------------- 
############################## 
mainmenu_option next_comment 
comment 'LED driver test ' 

bool 'LEDtest' CONFIG_USER_LEDTEST 
endmenu 

############################### 
=================END============= 


PART C 编译 
1) make menuconfig 
要选中Kernel和User那两个选项,在kernel中的能找到“Test LED Driver”选项,勾上,在user中能找到“LEDtest”,也要勾上,保存退出。 
2) make clean 
3) make lib_only 
4) make user_only 
5) make romfs 
6) make image 
7) make 
我的led.c刚开始有不少问题,make会提示是多少行有问题,然后再回去改,还蛮不错的 

好了,生成bin文件了 

PART D 烧录 
只是我的板子的地址,但基本上差不多,在uboot中操作 
1) loadb 0x0c008000 
2) 发送bin文件 
3) erase 0x50000 0x1fffff 
4) cp 0x0c008000 0x50000 3370d   
  //3370d根据自己载入文件的大小除以4再加2,我是cdc2e/4+2的 
5) save 
6) reset 

如果没问题,应该能看到uClinux的界面了,下面在板子中运行 
1) cd /dev 
2)ls 
看见里面有个LED了吧? 
3) cd /proc 
4)cat devices 
看见驱动列表吧? 
led 231也应该在里面 
5)ledtest 
在任何地方执行这个语句 就可以看到板子上的灯亮了。 
__________________________
阿虚的电子小屋 
http://hi.baidu.com/aokikyon

你可能感兴趣的:(uClinux驱动实例 LED)