📄 sdmemdiskio.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
// Copyright (c) 2002 BSQUARE Corporation. All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
// SD Memory Card driver disk IO implementation
#include "SDMemory.h"
///////////////////////////////////////////////////////////////////////////////
// SDMemCalcDataAccessClocks - Calculate the data access clocks
// Input: pMemCard - the memcard
// Output: pReadAccessClocks - Pointer to ULONG for read access clocks
// pWriteAccessClocks - Pointer to ULONG for write access clocks
// Return: TRUE or FALSE to indicate function success/failure
// Notes: Calculate data access times for memory devices. This calculation
// is to fine tune the data delay time
///////////////////////////////////////////////////////////////////////////////
BOOL SDMemCalcDataAccessClocks(PSD_MEMCARD_INFO pMemCard,
PULONG pReadAccessClocks,
PULONG pWriteAccessClocks)
{
SD_CARD_INTERFACE cardInterface; // current card interface
SD_API_STATUS status; // intermediate status
DOUBLE clockPeriodNs; // clock period in nano seconds
ULONG asyncClocks; // clocks required for the async portion
// fetch the card clock rate
status = SDCardInfoQuery(pMemCard->hDevice,
SD_INFO_CARD_INTERFACE,
&cardInterface,
sizeof(cardInterface));
if(!SD_API_SUCCESS(status)) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDMemCalcDataAccessClocks: Can't get card interface info\r\n")));
return FALSE;
}
if(0 == cardInterface.ClockRate) {
DEBUGCHK(FALSE);
return FALSE;
}
// if the clock rate is greater than 1 Ghz, this won't work
if(cardInterface.ClockRate > 1000000000) {
DEBUGCHK(FALSE);
return FALSE;
}
// calculate the clock period in nano seconds, clock rate is in Hz
clockPeriodNs = 1000000000 / cardInterface.ClockRate;
// calculate the async portion now that we know the clock rate
// make asyncClock an integer
asyncClocks = (ULONG)(pMemCard->CSDRegister.DataAccessTime.TAAC / clockPeriodNs);
// add the async and synchronous portions together for the read access
*pReadAccessClocks = asyncClocks + pMemCard->CSDRegister.DataAccessTime.NSAC;
// for the write access the clocks area multiple of the read clocks
*pWriteAccessClocks = (*pReadAccessClocks) * pMemCard->CSDRegister.WriteSpeedFactor;
DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDMemCalcDataAccessClocks: Tpd:%f ns, Asynch: %f ns, AsyncClocks:%d , SyncClocks: %d, ReadTotal: %d, Write Factor: %d WriteTotal: %d \n"),
clockPeriodNs,
pMemCard->CSDRegister.DataAccessTime.TAAC,
asyncClocks,
pMemCard->CSDRegister.DataAccessTime.NSAC,
*pReadAccessClocks,
pMemCard->CSDRegister.WriteSpeedFactor,
*pWriteAccessClocks));
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
// SDMemCardConfig - Initialise the memcard structure and card itself
// Input: pMemCard - SD memory card structure
// Output:
// Return: win32 status code
// Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD SDMemCardConfig( PSD_MEMCARD_INFO pMemCard )
{
DWORD status = ERROR_SUCCESS; // intermediate win32 status
DWORD dwSDHC; // high capacity value
SD_API_STATUS apiStatus; // intermediate SD API status
SD_CARD_INTERFACE cardInterface; // card interface
SD_DATA_TRANSFER_CLOCKS dataTransferClocks; // data transfer clocks
// retrieve CID Register contents
apiStatus = SDCardInfoQuery( pMemCard->hDevice,
SD_INFO_REGISTER_CID,
&(pMemCard->CIDRegister),
sizeof(SD_PARSED_REGISTER_CID) );
if(!SD_API_SUCCESS(apiStatus)) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDMemCardConfig: Can't read CID Register\r\n")));
return ERROR_GEN_FAILURE;
}
// Retrieve CSD Register contents
apiStatus = SDCardInfoQuery( pMemCard->hDevice,
SD_INFO_REGISTER_CSD,
&(pMemCard->CSDRegister),
sizeof(SD_PARSED_REGISTER_CSD) );
if(!SD_API_SUCCESS(apiStatus)) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDMemCardConfig: Can't read CSD Register\r\n")));
return ERROR_GEN_FAILURE;
}
// retreive the card's RCA
apiStatus = SDCardInfoQuery(pMemCard->hDevice,
SD_INFO_REGISTER_RCA,
&(pMemCard->RCA),
sizeof(pMemCard->RCA));
if(!SD_API_SUCCESS(apiStatus)) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDMemCardConfig: Can't read RCA \r\n")));
return ERROR_GEN_FAILURE;
}
// get write protect state
apiStatus = SDCardInfoQuery( pMemCard->hDevice,
SD_INFO_CARD_INTERFACE,
&cardInterface,
sizeof(cardInterface));
if(!SD_API_SUCCESS(apiStatus)) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDMemCardConfig: Can't read Card Interface\r\n")));
return ERROR_GEN_FAILURE;
}
// Get write protect state from Card Interface structure
pMemCard->WriteProtected = cardInterface.WriteProtected;
if( pMemCard->WriteProtected ) {
DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDMemCardConfig: Card is write protected\r\n")));
}
// get capacity information
apiStatus = SDCardInfoQuery( pMemCard->hDevice,
SD_INFO_HIGH_CAPACITY_SUPPORT,
&dwSDHC,
sizeof(dwSDHC));
if(!SD_API_SUCCESS(apiStatus)) {
pMemCard->HighCapacity = FALSE;
}
else {
pMemCard->HighCapacity = dwSDHC != 0;
}
if( pMemCard->HighCapacity ) {
DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDMemCardConfig: Card is high capacity (2.0+)\r\n")));
}
// If the card doesn't support block reads, then fail
if (!(pMemCard->CSDRegister.CardCommandClasses & SD_CSD_CCC_BLOCK_READ)) {
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDMemCardConfig: Card does not support block read\r\n")));
return ERROR_BAD_DEVICE;
}
// If the card doesn't support block writes, then mark the card as
// write protected
if (!(pMemCard->CSDRegister.CardCommandClasses & SD_CSD_CCC_BLOCK_WRITE)) {
DEBUGMSG(SDCARD_ZONE_INIT || SDCARD_ZONE_WARN, (TEXT("SDMemCardConfig: Card does not support block write; mark as WP\r\n")));
pMemCard->WriteProtected = TRUE;
}
// Calculate read and write data access clocks to fine tune access times
if( !SDMemCalcDataAccessClocks( pMemCard, &dataTransferClocks.ReadClocks, &dataTransferClocks.WriteClocks) ) {
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDMemCardConfig: Unable to calculate data access clocks\r\n")));
return ERROR_GEN_FAILURE;
}
// Call API to set the read and write data access clocks
apiStatus = SDSetCardFeature( pMemCard->hDevice,
SD_SET_DATA_TRANSFER_CLOCKS,
&dataTransferClocks,
sizeof(dataTransferClocks));
if(!SD_API_SUCCESS(apiStatus)) {
DEBUGMSG(SDCARD_ZONE_ERROR,(TEXT("SDMemCardConfig: Can't set data access clocks\r\n")));
return ERROR_GEN_FAILURE;
}
// FATFS only supports 512 bytes per sector so set that
pMemCard->DiskInfo.di_bytes_per_sect = SD_BLOCK_SIZE;
// indicate that we aren't using Cylinder/Head/Sector addressing,
// and that reads and writes are synchronous.
pMemCard->DiskInfo.di_flags = DISK_INFO_FLAG_CHS_UNCERTAIN |
DISK_INFO_FLAG_PAGEABLE;
// since we aren't using C/H/S addressing we can set the counts of these
// items to zero
pMemCard->DiskInfo.di_cylinders = 0;
pMemCard->DiskInfo.di_heads = 0;
pMemCard->DiskInfo.di_sectors = 0;
// Work out whether we have a Master Boot Record
switch( pMemCard->CSDRegister.FileSystem ) {
case SD_FS_FAT_PARTITION_TABLE:
// yes, we have a MBR
pMemCard->DiskInfo.di_flags |= DISK_INFO_FLAG_MBR;
break;
case SD_FS_FAT_NO_PARTITION_TABLE:
// no, we don't have a MBR
break;
default:
// ee don't do "Other" file systems
DEBUGMSG( SDCARD_ZONE_ERROR, (TEXT("SDMemCardConfig: Card indicates unsupported file system (non FAT)\r\n")));
return ERROR_GEN_FAILURE;
}
// calculate total number of sectors on the card
//
// NOTE:The bus is only using BLOCK units instead of BYTE units if
// the device type is SD (not MMC) and if the CSDVersion is SD_CSD_VERSION_CODE_2_0.
// Since we don't have access to the device type, we are checking to see if it is
// a high definition card. This should work for most cases.
//
if( pMemCard->CSDRegister.CSDVersion == SD_CSD_VERSION_CODE_2_0 &&
pMemCard->HighCapacity ) {
pMemCard->DiskInfo.di_total_sectors = pMemCard->CSDRegister.DeviceSize;
#ifdef _MMC_SPEC_42_
/**
* Description : If MMC card is on SPEC42
*/
} else if (pMemCard->CSDRegister.SpecVersion >= HSMMC_CSD_SPEC_VERSION_CODE_SUPPORTED )
{
#ifdef _FOR_MOVI_NAND_
/**
* Description : There is no way to distinguish between HSMMC and moviNAND.
* So, We assume that All HSMMC card is the moviNAND
*/
pMemCard->IsHSMMC = TRUE;
#endif
if( pMemCard->CSDRegister.SectorCount > 0)
{
DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("[SDMEM] This MMC card is on SPEC42.\n")));
pMemCard->DiskInfo.di_total_sectors = pMemCard->CSDRegister.SectorCount;
pMemCard->HighCapacity = TRUE;
}
else
{
pMemCard->DiskInfo.di_total_sectors = pMemCard->CSDRegister.DeviceSize/SD_BLOCK_SIZE;
}
#endif
} else {
pMemCard->DiskInfo.di_total_sectors = pMemCard->CSDRegister.DeviceSize/SD_BLOCK_SIZE;
}
// FATFS and the SD Memory file spec only supports 512 byte sectors. An SD Memory
// card will ALWAYS allow us to read and write in 512 byte blocks - but it might
// be configured for a larger size initially. We set the size to 512 bytes here if needed.
if( pMemCard->CSDRegister.MaxReadBlockLength != SD_BLOCK_SIZE ) {
// Set block length to 512 bytes
status = SDMemSetBlockLen( pMemCard, SD_BLOCK_SIZE );
}
return status;
}
///////////////////////////////////////////////////////////////////////////////
// SDMemRead - Read data from card into pSG scatter gather buffers
// Input: pMemCard - SD memory card structure
// pSG - Scatter Gather buffer structure from FATFS
// Output:
// Return: Status - windows status code
// Notes: Reads from the card are split into groups of size TransferBlockSize
// This is controlled by a registry entry for the driver.
///////////////////////////////////////////////////////////////////////////////
DWORD SDMemRead(PSD_MEMCARD_INFO pMemCard, PSG_REQ pSG)
{
DWORD NumBlocks;
DWORD StartBlock;
PUCHAR pBlockBuffer = NULL, pCardDataPtr = NULL;
PUCHAR pSGBuffer = NULL;
PUCHAR pSGBufferCursor = NULL;
DWORD status = ERROR_SUCCESS;
DWORD SGBufNum, SGBufLen, SGBufRemaining;
DWORD PartialStartBlock;
DWORD CardDataRemaining;
DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDMemory: +SDMemRead\r\n")));
PREFAST_DEBUGCHK(pSG);
// pSG is a sterile SG_REQ copy of the callers's SG_REQ; we can map the
// embedded pointers back into it
// validate the embedded sb_bufs
for (ULONG ul = 0; ul < pSG->sr_num_sg; ul += 1) {
if (
(NULL == pSG->sr_sglist[ul].sb_buf) ||
(0 == pSG->sr_sglist[ul].sb_buf)
) {
status = ERROR_INVALID_PARAMETER;
goto statusReturn;
}
}
// validate the I/O request
if ((pSG->sr_start > pSG->sr_start + pSG->sr_num_sec)
||(pSG->sr_start + pSG->sr_num_sec) > pMemCard->DiskInfo.di_total_sectors) {
status = ERROR_INVALID_PARAMETER;
goto statusReturn;
}
// get number of sectors
StartBlock = pSG->sr_start;
NumBlocks = pSG->sr_num_sec;
// cannot read more than 4GB at a time or SGBufLen will overflow
if (ULONG_MAX / SD_BLOCK_SIZE < NumBlocks) {
status = ERROR_INVALID_PARAMETER;
goto statusReturn;
}
DEBUGMSG(SDMEM_ZONE_DISK_IO, (TEXT("SDMemRead: Reading blocks %d-%d\r\n"),
StartBlock,
StartBlock+NumBlocks-1));
SGBufLen = 0;
// calculate total buffer space of scatter gather buffers
for (SGBufNum = 0; SGBufNum < pSG->sr_num_sg; SGBufNum++) {
SGBufLen += pSG->sr_sglist[SGBufNum].sb_len;
}
// check total SG buffer space is enough for reqeusted transfer size
if (SGBufLen < (NumBlocks * SD_BLOCK_SIZE)) {
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDMemRead: SG Buffer space %d bytes less than block read size %d bytes\r\n"),
SGBufLen,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -