1. SD Core设备的功能
在第二篇【SD总体结构】中,介绍了系统的各个层次,其中的Core主要包含了Core Xfer和SDM两个重要组件。Core这个词在软件设计中通常隐含着【封装】和【隔离】两个意思。【封装】指的是将其他外部组件需要的通用操作包装为简单易用的模块(或接口),让其他组件达到“拿来即用”的效果,这些模块通常隐藏了很多繁琐的细节,通常这些细节不应该由使用它的组件关心。由于SD设备可使用SDI传输,但要通过SPI总线完成一次完整的会话(发送命令、获取命令应答、数据传输),将在软件上有比较复杂的处理,比如发送命令时,首先要发送命令字,然后发送该命令对应的参数,之后读取应答数据,这过程中还需要处理命令字和应答数据的CRC计算等,这些需要使用多次SPI完成,这些工作在SD总线上,都是由SD控制器来完成的。另外,使用SPI模式下,与许多命令与应答结构都与SD模式不同,这些都需要软件来区分处理。对应应用层来说,只是想通过总线传输数据而已,不管你使用什么硬件,采取什么方式。Core Xfer的主要功能即使对SD和SPI两种传输模式的封装,或者说是对两种硬件控制器行为的统一。Xfer即为transfer,这说明,Core设备主要提供的是传输控制功能。【隔离】表示将各个组件的功能和生命周期独立。功能独立表示,组件之间不能直接感知到彼此的存在,生命周期独立表示,各个组件的产生和消亡并没有严格的先后顺序,换句话说,我可能需要你,但我不关心你什么时候来,何时走。SDM主要处理的就是隔离的问题。
本篇主要讲解Core
Xfer,即SD Core设备,SDM将在下一篇讲解。
2. SD Core设备实现简介
首先来看看SD Core设备的描述,在core/sdcore.h文件里面定义了如下结构体:
-
typedef struct lw_sdcore_device {
-
PVOID COREDEV_pvDevHandle; /* 设备句柄 */
-
INT COREDEV_iAdapterType; /* 所在的适配器类型 */
-
#define COREDEV_IS_SD(pcdev) (pcdev->COREDEV_iAdapterType == SDADAPTER_TYPE_SD)
-
#define COREDEV_IS_SPI(pcdev) (pcdev->COREDEV_iAdapterType == SDADAPTER_TYPE_SPI)
-
-
INT COREDEV_iDevSta;
-
#define COREDEV_STA_HIGHSPEED_EN (1 << 0)
-
#define COREDEV_HIGHSPEED_SET(pcdev) (pcdev->COREDEV_iDevSta |= COREDEV_STA_HIGHSPEED_EN)
-
#define COREDEV_IS_HIGHSPEED(pcdev) (pcdev->COREDEV_iDevSta & COREDEV_STA_HIGHSPEED_EN)
-
-
spinlock_t COREDEV_slLock;
-
-
INT (*COREDEV_pfuncCoreDevXfer)(PVOID pvDevHandle, PLW_SD_MESSAGE psdmsg, INT iNum);
-
INT (*COREDEV_pfuncCoreDevCtl)(PVOID pvDevHandle, INT iCmd, LONG lArg);
-
INT (*COREDEV_pfuncCoreDevDelet)(PVOID pvDevHandle);
-
-
} LW_SDCORE_DEVICE, *PLW_SDCORE_DEVICE
COREDEV_pvDevHandle:为实际的抽象设备句柄。显然,有SD适配器设备PLW_SD_DEVICE和SPI适配器设备PLW_SPI_DEVICE两种。由于SPI适配器设备本身的定义并未考虑到SD卡的应用,因此,实际上Core在内部将原始的SPI适配器包装为适合于SD协议传输的数据结构,COREDEV_pvDevHandle在SPI模式下时,实际对应的是该结构的一个对象。
COREDEV_iAdapterType:记录对应的适配器类型。
COREDEV_iDevSta:设备状态,应用层驱动需要一些设备的状态信息执行不同的操作。
之后的三个回调函数就是对应适配器下的操作函数。它们在创建Core设备时根据适配器类型初始化。创建Core设备的函数原型如下:
-
PLW_SDCORE_DEVICE API_SdCoreDevCreate(INT iAdapterType,
-
CPCHAR pcAdapterName,
-
CPCHAR pcDeviceName,
-
PLW_SDCORE_CHAN psdcorechan);
从该函数的参数,我们可以大致猜测它的工作过程:根据iAdapterType是SPI还是SD,调用对应的适配器设备创建函数,创建一个名称为pcDeviceName的适配器设备,它对应的适配器名称为pcAdapterName。之后为Core分配内存,设置Core设备成员变量。这里的参数psdcorechan为Core设备通道信息,其定义如下:
-
/***************************************************************************
-
SD 通道结构
-
***************************************************************************/
-
struct __sdcore_drv_funcs;
-
typedef struct __sdcore_drv_funcs SDCORE_DRV_FUNCS;
-
-
typedef struct __sdcore_chan {
-
SDCORE_DRV_FUNCS *SDCORECHA_pDrvFuncs;
-
} LW_SDCORE_CHAN, *PLW_SDCORE_CHAN;
-
-
/***************************************************************************
-
SD 驱动安装回调函数
-
***************************************************************************/
-
typedef INT (*SDCORE_CALLBACK_INSTALL)
-
(
-
PLW_SDCORE_CHAN psdcorechan, /* 安装回调使用的参数 驱动定义 */
-
INT iCallbackType, /* 安装的回调函数的类型 */
-
SDCORE_CALLBACK callback, /* 回调函数指针 */
-
PVOID pvCallbackArg /* 回调函数的参数 */
-
);
-
-
/***************************************************************************
-
SD SPI模式下的片选回调
-
***************************************************************************/
-
typedef VOID (*SDCORE_CALLBACK_SPICS_ENABLE)(PLW_SDCORE_CHAN psdcorechan);
-
typedef VOID (*SDCORE_CALLBACK_SPICS_DISABLE)(PLW_SDCORE_CHAN psdcorechan);
-
-
/***************************************************************************
-
SD 驱动结构
-
***************************************************************************/
-
struct __sdcore_drv_funcs {
-
SDCORE_CALLBACK_INSTALL callbackInstall;
-
SDCORE_CALLBACK_SPICS_ENABLE callbackSpicsEn;
-
SDCORE_CALLBACK_SPICS_DISABLE callbackSpicsDis;
-
};
SDCORE_DRV_FUNCS为设备需要的驱动函数集,当前包括SPI模式下从设备的片选操作,即使能片选和禁能片选,callbackInstall为控制器驱动层安装来自应用层的函数的一个回调函数,这里有点绕,直观点讲,就是控制器驱动层保存来自应用层定义的函数指针以及对应的函数参数,在控制器感知到指定的事件发生时,由控制器调用这些函数,以便快速通知应用层这些事件。LW_SDCORE_CHAN里面只有一个SDCORE_DRV_FUNCS类型的成员变量指针,那为什么不直接使用SDCORE_DRV_FUNCS呢,这是从可扩展性考虑的。通道的含义表示,它不仅仅包含函数操作,还可能包含一些数据信息。在SylixOS中,很多地方都使用了这样的处理方式。SD Core设备引出了以下两个最基本的函数:
-
INT API_SdCoreDevCtl(PLW_SDCORE_DEVICE psdcoredevice,
-
INT iCmd,
-
LONG lArg);
-
INT API_SdCoreDevTransfer(PLW_SDCORE_DEVICE psdcoredevice,
-
PLW_SD_MESSAGE psdMsg,
-
INT iNum);
对照上一篇讲的SD总线适配器引出的两个函数,可以看到参数非常相似,唯一的不同就是第一个参数由之前的总线适配器类型变为了现在的SD Core设备类型。这正说明,Core设备是对SD和SPI总线传输的封装。此外,还有以下两个函数:
-
INT API_SdCoreDevCmd(PLW_SDCORE_DEVICE psdcoredevice,
-
PLW_SD_COMMAND psdCmd,
-
UINT32 uiRetry);
-
INT API_SdCoreDevAppCmd(PLW_SDCORE_DEVICE psdcoredevice,
-
PLW_SD_COMMAND psdcmdAppCmd,
-
BOOL bIsBc,
-
UINT32 uiRetry);
这两个为最基本的仅发送SD命令的函数,分别针对一般命令和APP命令(SD协议定义的两类不同的命令类型),之所以提供这两个函数,是因为很多时候的操作不会涉及到数据传输而仅仅发送命令。
3. SD Core设备工具库
SD Core设备工具库里面所有的函数均是使用SD Core设备作为传输操作对象,实现一些SD协议里面常用的操作,这些操用于设备初始化和数据传输。这些工具函数位于core/sdcoreLib.h和core/sdiocoreLib.h,前者为对SD存储卡(包括MMC)卡相关协议的处理,后者为对SDIO设备的一些特有处理。这里不再具体讲解这些函数,有兴趣的读者可参照SD相关协议与源码实现进行理解。
阅读(2125) | 评论(0) | 转发(0) |