分类: 嵌入式
2013-08-01 16:47:54
socket通常指的是插槽,比如SD卡插槽等等。它的作用就是检测卡的状态(存在与否)、为数据卡供电、提供地址map功能等等。一般来说,计算机系统有一个PCMCIA控制芯片,该芯片可以控制多个socket插槽。而结构Flsocket就是为了描述一个socket而建立的。结构Flsocket构成了一组与硬件无关的通用接口,该通用接口可以被上层直接调用而无需关注具体的硬件细节。
表7.2列出了结构Flsocket的元素。
表格 7.2 结构Flsocket中的各个元素说明
元 素 |
描 述 |
|
unsigned volNo |
socket的序号 |
|
unsigned serialNo |
socket在socket控制器上的序列号 |
|
FLBoolean cardChanged |
表明flash卡的状态发生了变化 |
|
int VccUsers |
当前Vcc的用户数 |
|
int VppUsers |
当前Vpp的用户数 |
|
PowerState VccState |
Vcc供电状态 |
|
PowerState VppState |
Vpp供电状态 |
|
FLBoolean remapped |
当map window发生变化时变量为TRUE |
|
void (*powerOnCallback)(void *flash) |
Vcc加电的回调函数 |
|
window |
unsigned int baseAddress |
物理地址(4k为一个单位) |
unsigned int currentPage |
当前window的map地址 |
|
void FAR0 * base |
指向window的指针 |
|
long int size |
window的大小,2的整数次幂 |
|
unsigned speed |
响应速度,ns |
|
unsigned busWidth |
数据宽度,8或者16bit |
|
FLBoolean (*cardDetected)(FLSocket vol) |
检查socket中是否有卡存在 0 = 卡不存在, other = 存在 |
|
void (*VccOn)(FLSocket vol) |
打开Vcc |
|
void (*VccOff)(FLSocket vol) |
关闭Vcc |
|
FLStatus (*VppOn)(FLSocket vol) |
打开Vpp,Vpp是编程电压,随着技术的发展Vpp可以和Vcc共用一个电压 |
|
void (*VppOff)(FLSocket vol) |
关闭Vpp |
|
FLStatus (*initSocket)(FLSocket vol) |
进行Flsocket结构及控制器必要的初始化 |
|
void (*setWindow)(FLSocket vol) |
在硬件中设置当前窗口所有的参数:基地址、窗口大小、速度及数据宽度。需要设置的数据都保存在window结构中。如果不能满足参数window.size中要求的window size,则window size就会在可能的情况下设置一个更大的size,无论如何,window.size中应该包含实际的window的size。 |
|
void (*setMappingContext)(FLSocket vol, unsigned page) |
设定window mapping寄存器 |
|
FLBoolean (*getAndClearCardChangeIndicator)(FLSocket vol) |
返回socket中flash卡的改变状态指示,如果已经发生了状态改变则要清除该状态 |
|
FLBoolean (*writeProtected)(FLSocket vol) |
返回socket槽的写保护状态 |
|
void (*freeSocket)(FLSocket vol) |
释放为这个socket动态分配的资源,这个函数将会在存在FLite的时候调用 |
上一节分析了结构Flsocket,每个Flsocket结构变量对应一个socket。而函数库Flsocket则管理了系统中所有的socket,它在库文件中定义了
FLSocket vols[DRIVES],
同时还定义了一个数组
#ifndef SINGLE_BUFFER
#ifdef MALLOC_TFFS
static FLBuffer *volBuffers[DRIVES];
#else
static FLBuffer volBuffers[DRIVES];
#endif
#endif
这样每个socket都有一个Flsocket结构变量和一个FLBuffer结构变量,FLBuffer变量用于暂时保存一个socket中某一sector中的信息。
函数库通过调用Flsocket结构中的函数,实现了一组与硬件无关的通用的函数接口供上层调用,如图7.5。
图7.5 函数库Flsocket与结构Flsocket的层次关系
下面是函数库Flsocket中各个函数的分析。
1. unsigned flSocketNoOf(const FLSocket vol)
返回一个FLSocket结构变量的编号(即元素volNo)。
注意:该编号是在函数flInit()中进行赋值的。其中元素volNo的数值等于该变量在数组FLSocket vols[DRIVES]的下表。
2. FLSocket *flSocketOf(unsigned volNo)
根据FLSocket结构变量的编号(数组FLSocket vols[DRIVES]的下标)找到其FLSocket结构变量的地址。
3. FLBuffer *flBufferOf(unsigned volNo)
根据Flsocket结构变量的编号Flsocket.volNo,返回其所属的FLBuffer结构变量的地址。
注意:当SINGLE_BUFFER为false时,数组FLSocket vols[DRIVES]中的每个元素即FLSocket结构变量和对应的buffer在volBuffers[DRIVES]数组中的下表是相同的。
4. FLBoolean flWriteProtected(FLSocket vol)
直接调用vol.writeProtected(&vol)返回socket的写保护状态,返回值0表明未写保护,即可写,其他值表明写保护。
5. void flResetCardChanged(FLSocket vol)
调用函数FLSocket.getAndClearCardChangeIndicator()获取卡的状态是否改变,并将变量FLSocket.cardChanged恢复为FLASE。
6. FLStatus flMediaCheck(FLSocket vol)
检查socket的状态,如果槽内有卡则需要调用vol.getAndClearCardChangeIndicator检测卡的状态是否改变,并返回相应的状态flDriveNotReady(卡不存在)、flDiskChange(状态改变)、flOK(状态不变)。
注意:flMediaCheck函数和flResetCardChanged区别在与后者在检查完状态之后将状态恢复为FLASE,而前者则不修改状态。
7. FLStatus flInitSockets(void)
该函数的作用是对socket控制器控制的所有的socket进行初始化。对每个socket来说,初始化包括如下几个方面:
调用函数flSetWindowSpeed(&vol,250)设置window的速度为250ns;
调用函数flSetWindowBusWidth(&vol,16)设置window的总线宽度为16位;
调用函数flSetWindowSize(&vol,2)设置window的大小为8K字节;
vol.cardChanged设置为flase,即初始状态;
如果宏定义SINGLE_BUFFER,说明所有的socket公用一个buffer;否则每个FLSocket结构变量都对应自己的buffer,此时如果定义了MALLOC_TFFS,则说明这个buffer空间是需要动态分配的,因此这里需要为每个socket动态分配一个buffer空间,对应的地址保存在volBuffers[DRIVERS]数组中,当然如果没有宏定义MALLOC_TFFS则volBuffers[DRIVERS]数组是静态分配的,这里就不需要分配了。见表7.3。
表格 7.3 数组volBuffers的定义和使用
|
Flsocket.c函数库 |
Fatlite.c函数库 |
|
SINGLE_BUFFER |
|
在文件Fatlite.c中定义FLBuffer buffer |
|
!SINGLE_BUFFER |
MALLOC_TFFS |
在文件Flsocket.c中定义static FLBuffer * volBuffers[DRIVES];而在函数flInitSocket中动态分配空间,并在flExitSocket函数中释放。 |
在文件Fatlite.c中定义 #define buffer (((Volume)vol).volBuffer) |
!MALLOC_TFFS |
直接在文件Flsocket.c中定义static FLBuffer volBuffers[DRIVES],这样既不需要动态分配,也不需要动态释放。 |
该函数还有两件要做的事情,就是关闭Vpp及Vcc同时设置相应的状态变量。
8. unsigned flGetMappingContext(FLSocket vol)
返回vol.window.currentPage,即当前页面号。
9. void FAR0 *flMap(FLSocket vol, CardAddress address)
将flash卡内地址映射为计算机系统内的地址。其中参数address为卡内的地址。
在变量Flsocket.window.currentPage中保存了当前的映射页面,它表明当前的某个页面已经被映射到系统内存中。在实际执行过程中有几种情况:
一是原来映射的页面和address所在的页面相同,则不需要映射,只需要返回该地址对应的计算机系统的地址即可;
二是原来映射的地址和当前不同,那么就需要重新进行映射。这个映射其实也比较简单,就是修改socket寄存器中offset中的数值,将其对应窗口的起始页对应为卡上地址为address所在的页面。具体的内容可以参考函数pcSetMappingContext。
三是如果currentPage对应的地址为UNDEFINED_MAPPING,此时还要调用函数vol.setWindow(&vol)进行必要的初始化,如设定窗口对应的计算机系统的开始页和结束页,然后再执行第二种情况的映射。
注意:Flsocket.remapped变量为TRUE表明重新映射结束。
10. void flSetWindowBusWidth(FLSocket vol, unsigned width)
设定FLSocket.window.busWidth,此时原来映射的页面即失效了,需要将vol.window.currentPage修改为UNDEFINED_MAPPING。
11. void flSetWindowSpeed(FLSocket vol, unsigned nsec)
设定FLSocket.window.speed,此时原来映射的页面即失效了,需要将vol.window.currentPage修改为UNDEFINED_MAPPING。
12. void flSetWindowSize(FLSocket vol, unsigned sizeIn4KBunits)
设定FLSocket.window.size,此时原来映射的页面即失效了,需要将vol.window.currentPage修改为UNDEFINED_MAPPING。需要注意的是,参数sizeIn4Kbunits是以4KB为单位的,而FLSocket.window.size则是以1字节为单位的;FLSocket.window.baseAddress则是以4KB为单位的。
13. void flSocketSetBusy(FLSocket vol, FLBoolean state)
该函数定义了socket层的setbusy操作,根据参数state为TFFS_ON或者TFFS_OFF进行不同的操作。
如果TFFS_ON,则说明需要对socket进行操作,这时候置vol.window.currentPage = UNDEFINED_MAPPING,且vol.remapped = TRUE,表明需要remap。
如果TFFS_OFF,则说明当前socket的操作完毕,执行函数flIntervalRoutine(&vol)。
14. void flNeedVcc(FLSocket vol)
注册Vcc用户,如果当前Vcc是off的,那么这时候就需要打开。
15. void flDontNeedVcc(FLSocket vol)
注销一个Vcc用户。如果注销后用户数为0,那么这时候就需要关闭Vcc,这个函数并没有马上关闭,而是在函数flIntervalRoutine中完成的。
16. FLStatus flNeedVpp(FLSocket vol)
注册Vpp用户,如果当前Vpp是off的,那么这时候就需要打开。
17. void flDontNeedVpp(FLSocket vol)
注销一个Vpp用户。如果注销后用户数为0,那么这时候就需要关闭Vpp,这个函数并没有马上关闭,而是在函数flIntervalRoutine中完成的。
18. void flSetPowerOnCallback(FLSocket vol, void (*routine)(void *flash), void *flash)
设定回调函数vol.powerOnCallback。该函数在加电的时候由socket层调用。该函数通常是在flash一级定义的。
19. void flIntervalRoutine(FLSocket vol)
这是个周期执行的函数,由数库Fatlite中的函数flInit()启动对socketIntervalRoutine()函数的周期性调用,每个socketIntervalRoutine()执行周期都会调用flIntervalRoutine()函数。
它的作用是分别检查Vcc和Vpp的用户数,如果用户数为0,则需要关闭相应的Vcc和Vpp电源;它的另一个作用是检查卡的存在状态。
20. void flExitSocket(FLSocket vol)
对socket进行复位:调用flMap函数reset map寄存器;调用flDontNeedVcc函数将Vcc用户数减一,这是因为可能不止一个程序使用到Vcc,即使当前进行不再使用Vcc了,可能还有其他的进行需要Vcc;紧接着要调用函数flSocketSetBusy,它主要完成两部分工作,一是调用函数flIntervalRoutine(&vol,TFFS_OFF)检查Vcc和Vpp的用户数,检查卡的状态。
此外,该函数还要调用指针函数vol.freeSocket(&vol)释放先前分配的各种资源,如果在宏定义MALLOC_TFFS且!SINGLE_BUFFER的条件下,volBuffers[vol.volNo]是在函数flInitSockets中分配的,那么这时候还要释放这部分内存空间。