当前位置:
首页 >
软件天地 >
企业新闻 > 详细内容
- uClinux驱动编写心得(uClinux2.4+S3C44B0X)
- 发布时间:2009/10/28 阅读次数:1748 字体大小: 【小】 【中】【大】
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
在任何地方执行这个语句 就可以看到板子上的灯亮了。