织梦CMS - 轻松建站从此开始!

罗索

uClinux驱动编写心得(uClinux2.4+S3C44B0X)

落鹤生 发布于 2010-10-10 14:35 点击:次 
下面的内容绝大部分不是我写的,我是根据网上前辈高手的教程一步一步来做的。但是,在编译的过程中发现资料还是有点错误和关键点的遗漏。昨晚加上今天一整天,回忆编译的过程,稍微有点理解编译的方法了。
TAG:

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

目录里要建立makefile文件,内容如下
===============================
EXEC = ledtest
OBJS = ledtest.o

all: $(EXEC)
$(EXEC): $(OBJS)
         $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

romfs:
         $(ROMFSINST) /bin/$(EXEC)
clean:
          rm -f $(EXEC) *.elf *.gdb *.o
================================
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 编译
0) make menuconfig
要选中Kernel和User那两个选项,在kernel中的能找到“Test LED Driver”选项,勾上,在user中能找到“LEDtest”,也要勾上,保存退出。

1)make dep
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
在任何地方执行这个语句 就可以看到板子上的灯亮了。

 

(aokikyon)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201010/10285.html]
本文出处:百度博客 作者:aokikyon
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容