全部博文(2759)
分类: 嵌入式
2013-08-10 09:23:10
原文地址:vxworks驱动开发原理——TFFS文件系统(6) 作者:哭泣的土地
接口结构PCMCIA_CTRL中记录了PCMCIA控制芯片和它所管理的flash卡的基本信息。表7.3列出了结构PCMCIA_CTRL的各个元素。
表格 7.3 结构Flsocket中的各个元素说明
元 素 |
描 述 |
int socks |
记录PCMCIA_CTRL结构变量中已经注册的socket的数量 |
int memBase |
内存映射的基地址,当计算机访问内部的flash卡时,访问地址Flsocket.window.start+memBase才对应的是flash的窗口起始地址。 |
PCMCIA_CHIP chip |
记录PCMCIA卡的状态及访问接口 |
PCMCIA_CARD card[MAX_SOCKETS] |
记录该PCMCIA设备控制的各socket中的flash卡的状态 |
表7.4列出了结构PCMCIA_CHIP的各个元素。
表格 7.4 结构PCMCIA_CHIP中的各个元素说明
元 素 |
描 述 |
int type |
PCMCIA控制器的型号 |
char *name |
PCMCIA控制器的名称 |
BOOL installed |
如果PCMCIA控制器驱动安装则置为TRUE |
int socks |
PCMCIA控制器支持的socket的数量 |
int flags |
PCMCIA控制器的标识 |
int intLevel |
PCMCIA控制器的CSC中断级,即连接的中断控制器的IrqNo |
int memWindows |
有效的内存映射窗口号 |
int ioWindows |
有效的IO映射窗口号 |
FUNCPTR reset |
PCMCIA控制器复位函数 |
FUNCPTR status |
PCMCIA控制器状态查询函数 |
FUNCPTR flagGet |
PCMCIA控制器标识查询函数 |
FUNCPTR flagSet |
PCMCIA控制器标识设置函数 |
FUNCPTR cscOn |
PCMCIA控制器CSC(card status change)监控打开函数 |
FUNCPTR cscOff |
PCMCIA控制器CSC(card status change)监控关闭函数 |
FUNCPTR cscPoll |
PCMCIA控制器CSC(card status change)查询函数 |
FUNCPTR irqGet |
PCMCIA控制器irqNo查询函数 |
FUNCPTR irqSet |
PCMCIA控制器irqNo设置函数 |
FUNCPTR iowinGet |
PCMCIA控制器IO窗口信息获取函数 |
FUNCPTR iowinSet |
PCMCIA控制器IO窗口信息设置函数 |
FUNCPTR memwinGet |
PCMCIA控制器内存窗口信息获取函数 |
FUNCPTR memwinSet |
PCMCIA控制器内存窗口信息设置函数 |
FUNCPTR showRtn |
PCMCIA控制器查看函数 |
表7.5列出了结构PCMCIA_CARD的各个元素。
表格 7.5 结构PCMCIA_CARD中的各个元素说明
元 素 |
描 述 |
int type |
卡的类型编号 |
int sock |
该卡槽的位置在该控制器上的编号 |
int ctrl |
控制器编号 |
BOOL detected |
TRUE表明卡槽中有卡 |
BOOL installed |
TRUE表明驱动已经安装 |
BOOL changed |
TRUE表明卡的状态已经改变 |
int regBase |
配置寄存器基地址 |
int regMask |
配置寄存器掩码 |
int cardStatus |
卡的状态 |
int initStatus |
初始状态 |
FUNCPTR cscIntr |
卡的中断处理函数 |
FUNCPTR showRtn |
状态查询函数 |
DL_LIST cisTupleList |
CIS tuple 链表 |
DL_LIST cisConfigList |
CIS config tuple链表 |
PCCARD_RESOURCE *pResource |
PCCARD_RESOURCE资源结构指针 |
BLK_DEV *pBlkDev |
Block启动设备 |
NETIF *pNetIf |
以太网启动设备 |
DOS_VOL_DESC *pDos |
DOS文件系统卷标描述符 |
函数库文件pcmciLib提供了socket控制芯片的中断初始化和中断实时处理功能,这些功能都是基于通用接口PCMCIA_CTRL结构来实现的。
在使用pcmciLib之前必须调用pcmciaInit()函数进行初始化,而且pcmciaInit()函数只能调用一次,这一次调用通常是在usrConfig.c文件的usrRoot()函数中完成的。
1. STATUS pcmciaInit (void)
该函数安装了事件处理接口并且运行了pcmciad()进程,pcmciad()进程是用类专门处理那些需要在任务级(相对于中断级)进程中执行的函数。而且他还创建了相应的消息队列并以此和pcmciad()进行通信。
pcmciaInit()主要完成了如下工作:
l 创建消息队列
l Spawn pcmciad()函数,该函数是一个无限循环,它不停地检查消息队列,如果有新的消息出现,则执行消息中的函数。
l 为计算机系统的socket芯片安装驱动。它采用用不同的驱动(存放在数组pcmciaAdapter[]中,这个数组在文件pccarkLib.c中定义)来尝试,如果尝试成功,同时也就安装好了socket芯片驱动函数。
l 连接CSC (Card Status Change)中断处理handler。
l 搜索所有socket,如果发现了PC 卡,则获取卡的 CIS (Card Information Structure)信息,决定卡的类型。如果该卡能够被支持需要分配相应的资源,并enable该卡。
l enable CSC中断。
结构PCMCIA_ADAPTER的定义
typedef struct pcmciaAdapter
{
int type; /* PCMCIA适配器的芯片类型如intel的82365L等 */
int ioBase; /* IO 基地址 */
int intVec; /* CSC 中断向量 */
int intLevel; /* CSC 中断 level */
FUNCPTR initRtn; /* 初始化函数 */
FUNCPTR showRtn; /* show函数 */
} PCMCIA_ADAPTER;
该结构的作用是识别系统中PCMCIA的控制芯片,如果能够正确识别则返回OK。在pccardLib库中则定义了两个PCMCIA结构变量。
PCMCIA_ADAPTER pcmciaAdapter [] =
{{PCMCIA_PCIC, PCIC_BASE_ADR, PCIC_INT_VEC, PCIC_INT_LVL, pcicInit, NULL},
{PCMCIA_TCIC, TCIC_BASE_ADR, TCIC_INT_VEC, TCIC_INT_LVL, tcicInit, NULL}}
pcmciaInit用pcmciaAdapter[]中的initRtn函数去尝试着对系统的PCMCIA芯片进行初始化操作,初始化成功initRtn函数返回OK。
如果socket中有卡,则需要调用(*pChip->cscPoll)()和(*pChip->cscOn)()进行初始化。(*pChip->cscPoll)()的作用是查询chip的CSC状态,查询后所有中断信号自动清除;(*pChip->cscOn)()的作用是打开chip的中断功能,这样确保CSC状态变化时能够输出中断。而后面sysIntEnablePIC的作用则是打开8259中断控制器的中断。
在文件pccardLib库也定义了
PCMCIA_CTRL pcmciaCtrl = {PCMCIA_SOCKS, PCMCIA_MEMBASE} ;
其中
#define PCMCIA_SOCKS 0x0
#define PCMCIA_MEMBASE 0x0
在文件Pc.h中定义,PCMCIA_SOCKS为0说明socket的个数是自动探测的。这也说明socket的个数是由PCMCIA_ADAPTER.initRtn函数来确定的。
最后要说明的是cisMuteSem变量,这个变量的作用是互斥信号,它在cisLib.c中定义。cisLib.c库将在后面说明。
注意:在函数初始化过程中如果各个初始化函数都初始化失败了就应该退出,在退出前需要释放掉系统之前分配的资源(如pcmciaMsgQId、pcmciadId),这点函数没有做;同样,如果pcmciadId分配失败,也要释放掉pcmciaMsgQId资源。这是一个bug。
2. LOCAL void pcmciaCscIntr (void)
卡的状态发生改变时的中断处理函数。主要做下列事情:
l 搜索所有socket看数否有CSC事件发生。如果有CSC事件发生检查socket的当前状态(CSC事件说明状态发生了变化,但并不知道现在是什么状态所以需要调用(* pChip->status) (sock)来获取当前的状态)。如果发现了有新的未处理的状态,则要需要调用(* pCard->cscIntr) (sock, csc)函数处理中断。
l 如果有卡插入,它将会要求PCMCIA daemon在任务级通过调用cisGet()函数,cisGet()函数读取CIS并确定卡的类型并初始化该卡的设备驱动。
l 如果有卡拔出,则它将会要求PCMCIA daemon在任务级通过调用cisFree()函数,该该函数将释放cisGet()函数分配的资源。
3. STATUS pcmciaJobAdd
(
VOIDFUNCPTR func,
int arg1,
int arg2,
int arg3,
int arg4,
int arg5,
int arg6
)
这个函数的作用将一个函数指针及参数填入到PCMCIA_MSG结构变量并发送到队列中,供pcmciad接收并处理。
之所以这么做主要是因为Vxworks为强实时系统,对中断处理时间的要求非常严格,通常只需要简单的几个动作就要完成中断处理并退出中断处理程序ISR,但是实际上中断要进行的操作可能会比较复杂,它需要对中断的类型进行判断,不同的中断类型需要不同的处理程序,这些处理可能还要等待资源等等,这样将导致ISR的处理时间可能会变得非常厂,从而扰乱了处理的时序,为此ISR采取了消息队列的形式,出现一次中断迅速对中断类型进行分析,选择合适的处理程序,注意这是并不是要马上执行处理程序,而是通过消息队列将处理函数及其参数发送出去,由外部普通task完成程序的执行。
函数pcmciaJobAdd的作用,就是将处理函数及其参数发送出去。
4. void pcmciad (void)
该函数由pcmciaInit() spawn在任务级运行,而不是在中断级运行。它的优先级为2,不要轻易删除该任务或修改该任务的优先级。
该函数是一个无限循环,它不停接收pcmciaMsgQId消息队列,如果收到新的有效的消息,就会自动运行消息中的函数及参数。为了确保消息的可靠发送,pcmciad函数的另一个任务就是检查看数否消息发生了新的丢失。它的检查机制是这样的:在发送的时候有一个变量pcmciaMsgsLost,每发送失败一次,pcmciaMsgsLost加1。而在pcmciad接收到消息的时候它会检查pcmciaMsgsLost的数值,如果发现pcmciaMsgsLost的数值和上次运行时数值不一致,就说明发生了新的消息传输失败。这种机制确保发生消息发送失败的情况下在ISR级别只是将数据记录下来,并不马上提示,从而确保中断处理程序尽可能快。而将消息发送失败的的信息打印出来的工作则是在任务级(也就是函数pcmciad)才完成的。
cisLib库文件的作用是读取PCMCIA设备的CIS(保存在attribute memory中),并根据这些基本信息对attiribute memory配置寄存器。
1. STATUS cisGet
(
int sock
)
该函数的作用从sock槽中的卡中读取CIS信息、对PC卡进行配置、并为PC卡分配相应的资源。
2. LOCAL STATUS cisTupleGet
(
int sock
)
获取PCMCIA设备的tuple并将其加入到队列pCard->cisTupleList中。关于tuple在CIS中的存放前面已经说过,这里需要说明的是tuple分两类,一类描述了PCMCIA设备的基本信息,这类tuple也是需要加入到cisTupleList中的tuple,而另一类tuple并不说明PCMCIA设备的配置,它只是说明tuple链的连接情况,函数cisTupleGet则是根据这类tuple建立起了一个完整的cisTupleList链表,建立起来的链表则不包含这类tuple信息。
3. LOCAL STATUS cisConfigGet
(
int sock
)
从pCard->cisTupleList中获取PCMCIA设备的配置信息。主要是两类tuple。CISTPL_CONFIG和CISTPL_CFTABLE_ENTRY。从这两个tuple中获取PCMCIA设备的一些配置信息。
有了这些信息之后就可以对PCMCIA的功能进行配置。
4. LOCAL STATUS cisResourceGet
(
int sock
)
根据cis中的配置链表的信息对PC卡进行配置。这个函数的实现过程比较简单,它也是用一个数组pccardEnabler[],其中每个元素都有一个函数指针enableRtn,如果该函数能够成功对PCMCIA设备进行识别并填充相应的结构变量pcmciaCtrl .chip.card[sock],则说明匹配成功。
pccardEnabler[]数组在文件pcCardLib.c中定义。同时在文件pcCardLib.c中还有个函数pccardTffsEnabler,也就是结构PCCARD_ENABLER中的元素enableRtn。它的作用是根据tuple list中的flash卡的信息,填充pcmciaCtrl .chip.card[sock]结构变量。成功则返回TRUE否则返回FALSE。
5. void cisFree
(
int sock
)
它的主要工作是恢复到最初始的状态。即复位pcmciaCtrl.chip.card[sock]结构变量;删除pCard->cisConfigList和pCard->cisTupleList;关闭socket电源;reset ioWindow和memory window;最后打开中断,继续检查是否有新的flash卡插入。
6. STATUS cisConfigregGet
(
int sock,
int reg,
int *pValue
)
读取配置寄存器中的数值。这个寄存器是在PCMCIA设备上而不是PCMCIA控制芯片上。主要是从attribute memory中读取,需要注意是对attribute memory中配置寄存器的写操作是如同普通内存一样直接进行赋值,而不是像写common memory那样需要特殊的写命令时序。
那么在window设置了attribute memory属性以后,如何确定访问的是cis还是配置寄存器呢?pcmcia规范中有这么个约定,cis的地址是从attribute memory中的地址0的位置开始的,而在cis的CISTPL_CONFIG tuple中则存放了两个数值pCard->regBase和pCard->maskBase,其中pCard->regBase则表示配置寄存器开始的地址;而pCard->maskBase则用位图的形式表示了相应的寄存器是否存在,如果存在那么pCard->maskBase的相应位是1。
与attribute memory属性相同,配置寄存器有效数据都保存在偶数字节。因此,2*reg首先得到偏离regbase位置的地址,然后得到在attribute memory中的地址:(char *)memWin.start +(pCard->regBase & 0xfff) + (reg * 2),最后转化为计算机系统的地址。
7. STATUS cisConfigregSet
(
int sock,
int reg,
int value
)
设定PCMCIA设备的配置寄存器。用于配置PCMCIA设备的功能。
.2.9 函数库cisLib