红联Linux门户
Linux帮助

uClinux下的驱动移植心得

发布时间:2008-05-22 16:33:31来源:红联作者:Drcede
最近修改uClinux下的fb驱动成功,先把最近的工作写一个文档保存下来,以备今后查阅。

uClinux下的驱动和标准的,基于module的驱动还是有一些区别的,但不是太大。先明确几个概念:系统调用、主设备号、方法、内核

系统调用:编过linux下应用程序的人肯定知道,想使用linux下的设备是要通过调用一些C函数来实现的。

具体的说就是open( ),release( ),read( ),write( ),ioctrl( ),mmap( )等。这些C函数对应着linux下的系统调用,open,release,read,write,ioctrl,mmap等。系统调用是驱动的唯一用户。系统调用向内核要求使用某种设备,然后由内核决定调用那种驱动程序来使用硬件。

主设备号:前面说内核使用驱动程序,但内核如何把一种系统调用请求和某种具体的设备驱动相关联呢?这就要用到主设备号。

主设备号是内核用于识别某种设备驱动的唯一标志。例如fb0设备的主设备号是major 29,即是说,凡是主设备号为29的设备都是fb设备,都要调用fb驱动。驱动程序的注册其实就是将自己的驱动程序和主设备号相关联,然后让系统知道, “我在这里”。这样,内核就可以把系统调用请求转化为对相应设备驱动的具体函数调用。

方法:驱动程序应该是可重入的,应该只提供一种正确的使用硬件设备的方法,而不能干涉上层如何使用它。

内核:内核实质上是用户程序和底层驱动之间的一个中间层,它捕获系统调用、中断请求等等信息,调用相应的驱动程序或中断处理程序来进行。当然,这是仅仅站在驱动的角度上说的,实际上它还负责任务调度、内存管理,多线程同步等等工作。

下面,结合FrameBuffer驱动具体说一下在我们的开发平台上如何进行驱动的修改。

首先,我们要搞清楚fb驱动到底和什么文件有关。这种信息的来源主要有两个:

其一是makefile;

makefile 是一种嵌套结构,也就是说,上层很复杂的Makefile我们其实没有必要完全搞明白。具体的说,我们的fb驱动在linux2.6.x\drivers \video文件夹下面。那么,相关的makefile也肯定在这个文件夹下面。打开它,在其中找到了这样几行:

obj-$(CONFIG_FB) += fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o softcursor.o

……….

obj-$(CONFIG_FB_BFIN_7171)+= bfin_ad7171fb.o bfin_ad7171fb_config.o videoupdate.o

很清楚的,我们可以看出,如果想加入FB驱动的话,就一定要生成fbmem.o fbmon.o fbcmap.o fbsysfs.o modedb.o softcursor.o这几个.o文件。根据编译规则,这些.o文件应该是由和他们同名的.c或.s文件生成的,在文件夹里寻找,很容易找到了 fbmem.c,fbmon.c,fbcmap.c等文件。

再看FB_BFIN_7171,它依赖于三个.o文件,也很容易找到他们的.c,.s文件。

这里要说明一下,我们实际上使用了新内核(来自ADI网站的Release版)中的源文件,bfin_ad7171fb_main.c 和rgb2ycbcr.S。

Makefile中的语句是

obj-$(CONFIG_FB_BFIN_7171) += bfin_ad7171fb.o

bfin_ad7171fb-objs := bfin_ad7171fb_main.o rgb2ycbcr.o

然后说一下CONFIG_FB_BFIN_7171的意义,这个变量是定义在Kconfig中的,Kconfig也是嵌套调用的,由make调用, video目录下也有相应的kconfig文件,可以打开看看,建议google “kconfig 语法”来获取更多信息。总之里面有这样一段:

config FB_BFIN_7171

bool "Blackfin ADI7171 video encoder on uClinux"

depends on FB && BFIN

help

This is the framebuffer device for a AD7171 video encoder

attached to a Blackfin on the PPI port.

If your Blackfin board has a 7171 select Y.

这样看的很清楚了吧,make menuconfig时读取kconfig,然后所做的配置就是给FB_BFIN_7171之类的bool变量赋值,这样,在make按照 makefile进行编译的时候,就能根据这些变量决定某些.o文件是不是必需的,要不要编译或检查更新。

其二,看doc,该资源在linux-2.6.x\Documentation目录下。

以fb驱动为例,该文件夹下面有fb文件夹,里面说明了fb驱动所需的文件和文件之间的关系。在framebuffer.txt有详细的说明。

看懂了doc,就可以开始改了。

先说明一下关于常见的硬件相关的头文件和宏的定义都在哪里的问题。uClinux下的头文件很有特色,首先,在我们进行make menuconfig时其实作了很多工作。在\linux-2.6.x\include下有一个名叫asm的文件,它是在make menuconfig后生成的,可以用记事本把它打开,里面是

!asm-bfinnommu,这东西的意思就是一个link,可以看作快捷方式之类的东西,你可以在include下找到asm-bfinnommu文件夹,所以当你写

#include 时,

实际上等于写#include ,为什么这样呢?主要是为了对于一个系列的产品尽量少的修改代码,比如配置为arm平台,asm就指向asm-arm,这样写程序比较方便。

同理的,打开asm-bfinnommu可以找到mach文件,它指向mach-bf561文件夹,当然也是,平台是533就指向mach-bf533,#include

就等于#include 。OK?

这样相信大家找头文件时就不会有什么问题了。

作底层驱动时还有一些宏,在ADI提供的新核里有,也说一下。因为我们还是要参考新核里的很多东西,毕竟公司给的核实在功能太少。给寄存器赋值时经常看到这样的东西:bfin_read_PPI1_CONTROL()你说它是个函数吧,找不到声明,宏的话又好像在头文件里找不到,其实它确实是个宏,这样的宏有一大批,在新内核中给寄存器赋值都是用的这种宏。你可以头文件中找到#include ,打开这个文件,你会找到下面的define

#include

再打开mach下的blackfin.h,找到#include "cdefBF561.h",打开该文件,你会发现该宏的定义,

#define bfin_read_PPI1_CONTROL() bfin_read16(PPI1_CONTROL)

然后,bfin_read16(PPI1_CONTROL)又是虾米?它定义在mach-common下的def_LPBlackfin.h中,

#define bfin_read16(addr) ({ unsigned __v; \

__asm__ __volatile__ ("NOP;\n\t"\

"%0 = w[%1] (z);\n\t"\

: "=d"(__v) : "a"(addr)); (unsigned short)__v; })

OK,真相大白了。这就是给16位寄存器赋值的汇编宏。上面的

#define bfin_read_PPI1_CONTROL() bfin_read16(PPI1_CONTROL)

定义就是把这个宏具体化了,具体化为给某一个寄存器赋值。很巧妙吧?

好了,我们终于把该先解决的问题都解决了,开始安心看驱动源码和改动了。最主要的文件是fbmem.c虽然里面的内容基本上是不用改的。Fbmem.c中实现了

static struct file_operations fb_fops = {

.owner = THIS_MODULE,

.read = fb_read,

.write = fb_write,

.ioctl = fb_ioctl,

#ifdef CONFIG_COMPAT

.compat_ioctl = fb_compat_ioctl,

#endif

.mmap = fb_mmap,

.open = fb_open,

.release = fb_release,

#ifdef HAVE_ARCH_FB_UNMAPPED_AREA

.get_unmapped_area = get_fb_unmapped_area,

#endif

};

该结构定义在fb.h中,里面的fb_write等等是函数指针。实现fb设备的驱动功能。这些函数指针指向的函数体都在此文件中,但是实际上,这些函数没有硬件操作的功能,实际的操作函数还在更下层。注意看可以发现,有一个很重要的结构体:

struct fb_info {

int node;

int flags;

struct fb_var_screeninfo var; /* Current var */

struct fb_fix_screeninfo fix; /* Current fix */

struct fb_monspecs monspecs; /* Current Monitor specs */

struct work_struct queue; /* Framebuffer event queue */

struct fb_pixmap pixmap; /* Image hardware mapper */

struct fb_pixmap sprite; /* Cursor hardware mapper */

struct fb_cmap cmap; /* Current cmap */

struct list_head modelist; /* mode list */

struct fb_videomode *mode; /* current mode */

struct fb_ops *fbops;

struct device *device;

struct class_device *class_device; /* sysfs per device attrs */

#ifdef CONFIG_FB_TILEBLITTING

struct fb_tile_ops *tileops; /* Tile Blitting */

#endif

char __iomem *screen_base; /* Virtual address */

unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */

void *pseudo_palette; /* Fake palette of 16 colors */

#define FBINFO_STATE_RUNNING 0

#define FBINFO_STATE_SUSPENDED 1

u32 state; /* Hardware state i.e suspend */

void *fbcon_par; /* fbcon use-only private area */

/* From here on everything is device dependent */

void *par;

};

里面有fops结构体,fops结构体中有一系列的函数指针,它们是真正执行硬件操作的函数。

这些函数在bfin_ad7171fb_main.c中。所以,真正硬件相关的东西最终肯定在一个包含了硬件名称的.c或.s文件中。

因此,我们要改的只有bfin_ad7171fb_main.c这一个文件。怎么改这个问题比较简单,硬件要做的无非就是写一些配置寄存器,读一些寄存器,分配中断什么的。具体的操作我们是有厂家提供的能在VDSP++下面运行的测试程序的,这种测试程序虽然不是linux下的程序,但是对硬件的有效操作是被证实了的。这样的话,我们要做的就很清楚了,就是在VDSP++下面把程序看懂,搞清楚配置了什么东西,然后找一下原有驱动里面的配置,寄存器名称,等等,还有板子上有一块控制逻辑的CPLD这个的配置需要参考手册。例程里也是有的。

进行修改,改完后在uClinux-dist目录下面进行make menuconfig然后再make就可以了。

以上就是整个的改写流程了。
文章评论

共有 4 条评论

  1. youyin 于 2009-12-09 14:59:53发表:

    谢了,,

  2. leslielg 于 2008-06-15 13:59:21发表:

    想看下fb_imageblit那几个dummy函数怎么处理的

  3. leslielg 于 2008-06-15 13:58:12发表:

    能把bfin_ad7171fb_main.c和bfin_ad7171fb.h的内容贴上来么?谢谢

  4. suplayer 于 2008-05-22 20:15:25发表:

    去12257379QQ群,看看