3.3 组件驱动
系统启动时,TrueFFS将为BSP中所支持的每个flash设备创建一个组件驱动。正如图3-1所示(我上次翻译中的内容), tffsDrv()调用的最终目的时调用sysTffsInit()函数。为系统中所带的每个flash设备注册socket驱动所必须的工作都将由该函数完成。
大多数情况下,这意味着给socket驱动指定一个合适FLSocket结构体并安装函数指针。严格地讲,sysTffsInit()内部是不存在任何强加的组织的。但,为了可量测性,每个flash设备的细节是与xxxRegister()相关的,该函数因flash设备不同而不同。
最后,你的socket驱动必须提供两个全局函数:flFitInSocketWindow()和flDelayLoop()。(不能声明成LOCAL和static-这是当然的)。flFitInSocketWindow()函数返回flash阵列中一个独立的片子的容量(字节)。TFFS使用这个值来决定socket窗是否足够大。flDelayLoop()函数为TFFS提供一个适于硬件的等待方法(单位ms)。
3.3.1 如何写一个sysTffsInit()
sysTffsInit()函数是一个无参数也无返回值的函数。它至少要为每个flash设备调用一个注册程序。举一个最简单的例子,mv177BSP中sysTffs.c中定义的sysTffsInit():
LOCAL void sysTffsInit (void)
{
rfaRegister ();
}
这个BSP只支持一个flash设备,这样,它的sysTffsInit()也就只有一个rfaRegister()的调用。其他的BSP定义的sysTffsInit()则要复杂一些,比如:pc486中的sysTffsInit()有三个xxxRegister()调用:
#ifdef INCLUDE_SOCKET_DOC
(void) docRegister (); /* Disk On Chip */
#endif /* INCLUDE_SOCKET_DOC */
#ifdef INCLUDE_SOCKET_PCIC0
(void) pcRegister (0, PC_BASE_ADRS_0); /* flash card on socket 0 */
#endif /* INCLUDE_SOCKET_PCIC0 */
#ifdef INCLUDE_SOCKET_PCIC1
(void) pcRegister (1, PC_BASE_ADRS_1); /* flash card on socket 1 */
#endif /* INCLUDE_SOCKET_PCIC1 */
注意,每个xxxRegister()调用都有预编译信息。这些预编译信息中的宏在BSP的config.h中都有定义。使用这些宏,你可以有选择地控制哪些调用在编译时要包含在sysTffsInit()中。
3.3.2 如何写一个xxxRegister()
TFFS内部分配了一个FLSocket结构体数组,且TFFS使用这些结构体来找到需要与硬件打交道的SOCKET驱动函数(也有其他信息)。在你的xxxRegister()函数里,你必须在这些FLSocket结构体中找到一个合适的并初始化它的成员。可以调用flSocketOf( )来从TFFS中找到一个合适的FLSocket结构体:
FLSocket *flSocketOf(unsigned volNo)
作为输入,这个函数需要一个设备号(0-4)。完成调用后,该函数返回一个指向FLSocket结构体的指针。可参口如下程序段:
FLSocket vol = flSocketOf (noOfDrives);
if (noOfDrives >= DRIVES) return (flTooManyComponents);
tffsSocket[noOfDrives] = "RFA";
noOfDrives++;
变量noOfDrives和tffsSocket[]都是全局的。DRIVES是一个设为最大驱动器号(5,请勿改变)的符号常量。在你调用flSocketOf( )时,你必须使用全局变量noOfDrives作为volNo参数,而且在选择合适的FLSocket结构体成功后必须更新它。TFFS用这个全局变量计算已经创建了的本地flash设备的个数。同样地,你还需要更新tffsSocket[]数组的noOfDrives成员以便为刚才创建的驱动器包含一个lable。这个lable在tffsShow()和tffsShowAll()的输出时用到。
在返回FLSocket结构体指针后,你的xxxRegister()函数必须设置如下成员:
window.baseAddress
cardDetected
VccOn
VccOff
VppOn
VppOff
initSocket
setWindow
setMappingContext
getAndClearCardChangeIndicator
writeProtected
freeSocket
这些成员在前面都有详述。
3.3.3如何写一个flDelayLoop()
TFFS使用flDelayLoop( )函数来处理与flash硬件打交道所需要的时间。该函数的作用很简单,就是等待所需要的时钟周期数。其格式如下:
void flDelayLoop(int)
mv177BSP中的flDelayLoop()是如下定义的:
void flDelayLoop
(
int cycles /* 所需要的周期数 */
)
{
while (--cycles);
}
3.3.4 如何写一个flFitInSocketWindow( )函数
TFFS用flFitInSocketWindow( )来确认chipSize不会比windowSize大。其格式应如下:
long int flFitInSocketWindow
(
long int chipSize, /* size of single physical chip in bytes */
int interleaving, /* flash chip interleaving (1,2,4 etc) */
long int windowSize /* socket window size in bytes */
)
如果你的BSP使用自适应的窗口或者它把所有的flash都映射到窗口中,你定义的flFitInSocketWindow()可以简单地只返回chipSize作为函数值。
如果你的BSP使用固定的窗口,而且窗口并不足以将所有的flash媒体映射到主机的存储器,你的flFitInSocketWindow()函数就必须比较chipSize和windowSize的大小了,且返回一个适应windowSize的值。MTD映射函数使用flFitInSocketWindow()函数的返回值来调整FLSocket.chipSize的值。