Tornado之TrueFFS编程者指南
2012-10-08
seasoblue
标签:

Tornado之TrueFFS编程者指南(六)-By George (续)

按:看了seasoblue兄如此辛苦地翻译了TrueFFS编程者指南1-5,心想不能老是伸手要吃要穿,自己应当做点什么,就心血来潮也翻译起来。seasoblue兄谦虚说自己对TrueFFS造诣不深,其实大家心里明白他是大牛,因为字里行间已现山露水。我需要说明的是我对TrueFFS确实是啥屁不懂,仅仅是想学学,顺便照着字面就翻译了,字里行间肯定是破绽百出。之所以还厚着脸贴出来,是希望大方之家(如seasoblue、xiaohua等)能多多斧正,俺也好早点入门。

第三章:如何写socket驱动与MTD

1,简介

这一章将为你提供FLASH存储器、tffs与VXWORKS的接口。它将阐述所有对socket驱动和MTD至关重要的函数和结构体。其中我们最关心的两个结构体是FLFlash和FLSocket。

tffs内部分配了一个包含5个FLFlash结构体的阵列(array),每个都对应一个可能的flash设备。tffs使用这些FLFlash结构体来存储数据和函数指针(这些函数是用于管理FLASH设备的)。比如,tffs使用MTD函数来处理对FLASH煤质基本的读写操作,而FLFlash结构体就包含这些MTD函数指针。当运行一个MTD识别程序时,系统就安装了这些函数指针。

FLFlash结构体还包含一个指向FLSocket结构体的指针。tffs使用这些FLSocket结构体来存储数据和函数指针(所不同的是,这些函数是用于处理与FLASH设备的硬件接口的,也就是socket接口)。从我们的sysTffsInit()到xxxRegister()程序调用时,则安装这些函数。

用TFFS注册我们的socket驱动:

在VXWORKS中包含TFFS将会使usrRoot()调用tffsDrv()。而这将发起一个函数调用链:如下图

这些函数调用的目的之一就是用TFFS注册我们的socket驱动函数。

多数情况下,注册工作都发生在xxxRegister()中(这个函数的定义在sysTffs.c中)。该函数能更新FLSocket结构体。而此时,TFFS已经对应socket驱动中的服务程序给FLSocket结构体赋予了一个设备号(也即卷标)。TFFS调用FLSocket结构体中引用的函数来处理与Flash设备的硬件接口。

给FLASH技术确定一个MTD;

要创建一个TFFS块设备,我们必须调用tffsDevCreate()。这一调用也将发起一个函数调用链。如图3-2

这些函数调用的目的之一是确认合适的MTD。该确认过程在flIdentifyFlash()中。flIdentifyFlash()通过逐个执行xxxIdentify()表中的程序来确定合适的MTD。(相同的MTD是可以在多个不同的FLASH卷标中同时有效的)。

一旦找到合适的MTD,确认程序就会更新FLFlash结构体中的数据以及指向用于读、写、擦除、映射等操作的MTD程序指针。此外,确认过程还将完成在当前FLFlash结构体中涉及的FLSocket结构体的初始化。

2,关于FLFlash结构体和FLSocket结构体

tffs最多可以处理5个TFFS块设备。它给每个FLFlash结构体和FLSocket结构体都分配一个可能存在的FLASH设备。当使用TFFS注册我们的socket驱动时,系统也同时对这些结构体进行初始化。

多数情况下,注册也将更新FLFlash中socket成员涉及的FLSocket结构体。而FLFlash结构体的初始化使通过运行一个MTD确认程序来完成的。因为,确认程序依赖于FLSocket结构体中所涉及的函数,所以我们必须在运行MTD确认程序之前安装号socket驱动。

2.1 FLFlash之庐山真面目

几乎所有的FLFlash结构体成员都是通过MTD确认程序设定的,这样它就可以通过检测flash硬件获取它所需要的绝大多数数据。唯一例外的是socket成员,它是通过TFFS内部函数设定的。

FLFlash结构体在h/tffs/flflash.h中有定义:

typedef struct tFlash FLFlash; /* forward definition */

struct tFlash {

FlashType type;/* flash device type (JEDEC id) */

long int erasableBlockSize;/* smallest erasable area */

long int chipSize;/* chip size */

intnoOfChips;/* no. of chips in array */

intinterleaving;/* chip interleaving */

unsigned flags;/* special options */

void* mtdVars;/* MTD private area for socket */

FLSocket * socket;/* FLSocket for this drive */

/* MTD-supplied flash map function */

void FAR0 * (*map)(FLFlash *, CardAddress, int);

/* MTD-supplied flash read function */

FLStatus (*read)(FLFlash *, CardAddress, void FAR1 *, int, int);

/* MTD-supplied flash write function */

FLStatus (*write)(FLFlash *,CardAddress,const void FAR1 *,int,int)

/* MTD-supplied flash erase function */

FLStatus (*erase)(FLFlash *, int, int);

/* callback to execute after power up */

void (*setPowerOnCallback)(FLFlash *);

};

说明:

(1) type: JEDEC ID用于标识FLASH存储器的硬件。该成员的值在MTD确认程序中设定;

(2) erasableBlockSize:大小,单位为字节,为flash存储器一个可擦除块的大小。该值通过交叉计算而得,因此当在MTD中设定该值时,通常用如下格式:

vol.erasableBlockSize=aValue*vol.interleaving;

其中,aValue就是未与其它flash芯片交叉存取的可擦除块的大小。

(3) chipsize:单片flash得存储容量,单位字节。通过MTD中的外部函数flFitInSocketWindow()设定。

(4)noOfChips: 构成FLASH存储阵列的flash存储器的片数;

(5)interleaving: flash存储阵列的交叉存取参数,必须为2的整数幂(如1,2,4等)。用于定义在一个存储芯片上,两个字节连续媒体的地址差异。

(6)flags:bits0-7 保留用于TFFS;bits8-15 保留用于MTD;

(7)mtdVars:该区域如果被MTD占用,mtd的确认程序则将它初始化为一个指针指向一个特定的存储区。比如,16位AMD设备的MTD使用该成员存储一个指针,该指向存有AMD特有的FLASH参数。

(8)socket:是个指向FLSocket结构体的指针。而这个FLSocket结构体含有指向socket层函数的指针和数据。当我们注册socket驱动时,该FLSocket结构体中涉及的函数将被安装。而且,因为TFFS要使用这些socket驱动函数来寻址FLASH存储器,所以我们必须在运行MTD确认程序之前注册我们的socket驱动。

(9)map: 一个指向flash存储器映射(MAP)函数的指针,该函数将flash映射到存储器的一个区域。TFFS初始化时默认将这个指针成员指向一个适合所有NOR flash存储器类型的映射函数。NAND或其他类型FLASH必须用另外一个指向使用拷贝映射机制的程序指针来替换默认的。

(10)read:一个指向flash读函数的指针。在MTD确认程序之前,系统就将该成员指针初始化指向一个适合所有NORflash存储器类型的读函数。其实,读flash的过程是通过从一个映射窗口拷贝来实现的。如果默认的read指针不适合我们的flash设备,MTD确认程序需要更新这个指针成员以便让她指向正确的函数;如果正好适合,那当然不需要改。

(11)write:一个指向flash写函数的指针。该成员默认指向的程序在发现FLASH的写函数不合适时将返回一个写保护错误信息。同read指针类似,write指针一样需要MTD确认程序将它指向一个合适的函数。

(12)erase:一个指向flash擦除函数的指针。在发现擦除函数与flash设备不匹配时,该指针默认指向的函数也将返回一个写操作错误信息。erase指针一样需要MTD确认程序将它指向一个合适的函数。

(13) setPowerOnCallback:TFFS在flash设备上电后应当执行一个函数以便挂接该设备,setPowerOnCallback成员就是指向这个函数的指针。(需要注意,不要混淆了setPowerOnCallback成员和FLSocket结构体中的PowerOnCallback成员)。对许多flash存储设备而言,这个函数并不必须。

2.2 FLSocket之庐山真面目

作为socket驱动的开发人员,我们最需要关心的就是FLSocket结构体的初始化。这个结构体为TFFS提供了指向处理flash硬件接口的函数指针。一般情况下,怎样实现这些flash接口函数相对软件来说更需要硬件细节。

相应地,FLSocket结构体的成员描述指出了风河提供的BSP,这样我们就可以用来作例子。但是,在使用这些BSP时,我们需要对特定的硬件特别谙熟。

FLSocket结构体在h/tffs/flsocket.h中有定义:

typedef struct tSocket FLSocket; /* forward definition */

struct tSocket {

unsigned volNo;/* volume no. of socket */

unsigned serialNo;/* serial no. of socket on controller */

FLBoolean cardChanged;/* need media change notification */

int VccUsers;/* no. of current VCC users */

int VppUsers;/* No. of current VPP users */

PowerState VccState;/* actual VCC state */

PowerState VppState;/* actual VPP state */

FLBoolean remapped;/* set to TRUE if the socket window is moved */

void (*powerOnCallback)(void *flash);/* notification routine for Vcc on */

void * flash;/* flash object for callback */

struct {/* window state */

unsigned int baseAddress;/* physical base as a 4K page */

unsigned int currentPage;/* our current window page mapping */

void FAR0 * base;/* pointer to window base */

long int size;/* window size (must by power of 2) */

unsigned speed;/* in nsec. */

unsigned busWidth;/* 8 or 16 bits */

} window;

FLBoolean (*cardDetected) (FLSocket vol);

void (*VccOn) (FLSocket vol);

void (*VccOff) (FLSocket vol);

#ifdef SOCKET_12_VOLTS

FLStatus (*VppOn)(FLSocket vol);

void (*VppOff)(FLSocket vol);

#endif/* SOCKET_12_VOLTS */

FLStatus (*initSocket) (FLSocket vol);

void (*setWindow) (FLSocket vol);

void (*setMappingContext) (FLSocket vol, unsigned page);

FLBoolean (*getAndClearCardChangeIndicator) (FLSocket vol);

FLBoolean (*writeProtected) (FLSocket vol);

#ifdef EXIT

void (*freeSocket) (FLSocket vol);

#endif

};

(1)volNo: 卷标号,除非通过MTD确认程序,否则不要改其值;

(2)serialNo: 可自使用的结构体成员,典型值设为0;

(3)cardChanged: 该成员的作用是追踪监测是否有flash卡改变,监测周期为100ms,监测函数为cardDetected成员中的函数。如果cardDetected返回值FALSE,则cardChanged被设为TRUE。如果FLASH媒体不可移动,则该成员应设为FALSE。如果为TRUE,在TFFS寻址FLASH时,它将重新挂接FLASH设备。

(4)VccUsers: 内部使用,无需改变。

(5)VppUsers: 内部使用,无需改变。

(6)VccState: 内部使用,无需改变。

(7)VppState: 内部使用,无需改变。

(8) remapped: 内部使用。TFFS使用该成员追踪检测window是否被重映射过。如果我们写自己的MTD映射函数,应在返回值之前设定该成员。

(9)powerOnCallback:通过我们的xxxRegister()函数设定。tffs在调用VccOn成员中的xxxRegister()函数后调用此处的函数。如果没有必要使用该成员,可将其设为空指针。

(10)flash: 内部使用,无需改变其值。该成员用于支持可移动的flash媒体,且通过TFFS动态设置。

(11)window.baseAddress: 通过我们的xxxRegister()函数设定。在这个上下文中,一个窗口就是主机系统MEM的一部分,通过这个窗口,一部分媒体空间可直接寻址并可进行地址设定。window.baseAddress成员按4000页保存着这个主机系统的内存地址(也即窗口基地址除以4K)。之所以这样做是为了防止重建时基地址的页结盟(此处不懂)。

(12)window.currentPage:内部使用。用于存储当前映射的window页。

(13)window.base: 通过在setWindow成员中提供的函数设定。TFFS使用window.base来存放FLASH存储器上存储窗口的基地址。

(14)window.size:通过在setWindow成员中提供的函数设定。 TFFS使用window.size来存放FLASH存储器上存储窗口的大小。

(15)window.speed:内部使用。不要通过socket驱动改变此值。TFFS主要用它来存放完成flash设备互操作所需要的时

间。初始化后一般的默认值为250ns,但风河提供的MTD将它复位为120ns。如果我们自己写MTD,一定要在映射函数中正确地复位该成员值。

(16)window.busWidth:内部使用。用于存储flash的位宽是8位还是16位。最初的复位值是16,但风河提供的MTD都设位8。如果自己写MTD,也需要在映射函数中正确设置。

(17)cardDetected:通过我们的xxxRegister()函数初始化。它指向一个用于标识PCMICIA槽上有无flash存储卡的函数。对不可移动的媒体,这个函数通常返回TRUE。如果这个函数返回FALSE,则cardChanged为TRUE。函数的巡检周期为100ms。

(18)VccOn:通过xxxRegister()函数设定。该成员指向一个用于打开flash操作电源的函数。当媒体空闲时,系统会关掉电源以省电,而在再次访问flash媒体前,系统会调用该函数来再次打开电源。

在打开电源时,只有等到操作电压稳定了,VccOn函数才会返回值,如果必要,还需要调用flDelayMsec()或空闲语句来等待VCC稳定。

(19)VccOff:通过xxxRegister()函数设定。该成员指向一个用于关闭flash操作电源的函数。通常,在系统相当空闲的情况下,电源才会关闭。

(20)VppOn:通过xxxRegister()函数设定。系统通常调用该程序来打开编程电源(Vpp通常为12V,而vcc通常为3.3或5V)。由于并不是所有的flash芯片都需要这个电压,因而,只有当定义了SOCKET_12_VOLTS后这个成员才会被包含。

VppOn的函数返回状况与VccOn类似。

(21)VppOff:通过xxxRegister()函数设定。系统通常调用该程序来关闭编程电源。同样地,只有当定义了SOCKET_12_VOLTS后这个成员才会被包含。

(22)initSocket:通过xxxRegister()函数设定。系统在试图访问套接字之前调用与该成员相关的函数。TFFS用这个函数来处理在访问套接字之前的一些必要的初始化,尤其是当这些初始化在套接字注册时不能完成时。比方说,如果你在套接字注册时没有做硬件检测,或者flash存储器是可移动的,这个函数应当检测flash媒体,并在它移动后作出正确的回应。

(22)setWindow:通过xxxRegister()函数设定。系统调用该成员指向的函数来更新window结构体中的关键成员。为大多数硬件写一个setWindow函数,通常需要做如下几步:

* 按4000页设定window.baseAddress为基地址。页就是window的基地址除以4000。

* 调用flSetWindowSize()并以4K单位指定window大小。

TFFS假定访问窗口总是独占式的。也就是说,在设定这些窗口特征之一后,系统就不再允许你的应用程序直接改变他们了,否则将破坏它。唯一的例外就是映射寄存器。因为,TFFS在它访问flash后总是重新建立寄存器,你的应用程序也许会为了别的目的映射这些窗口而不是TFFS。但是,我们千万不能在中断函数中这么做。

系统如果带有多个socket驱动,请确认窗口的基地址各不相同。此外,我们还必须计算窗口大小并确认他们没有重叠。

(23)setMappingContext:通过xxxRegister()函数设定。该成员指向一个用于设定window映射寄存器的函数。因为,焊在板子上的flash阵列通常将全部的flash都映射到RAM,所以他们不需要这个函数。但众所周知,ss5 BSP相关的flash阵列是个例外。还有,使用PCMCIA槽的flash卡使用这个函数来寻址映射寄存器,以便将有效的flash地址转移到主机的内存窗口。

(24)getAndClearCardChangeIndicator:通过xxxRegister()函数设定。这个函数读取硬件卡改变标志并清除。如果你没有这种硬件,可将它设为空指针。

(25)writeProtected:通过xxxRegister()函数设定。它指向一个可以获取当前媒体写保护开关状态的函数。当然,前提是假设这个写保护开关存在。

(26)freeSocket:通过xxxRegister()函数设定。它指向的函数可以释放被socket驱动内部保留的资源。

共 4 页   上一页1234下一页
可能会用到的工具/仪表
相关文章
推荐文章
热门文章
章节目录
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号