You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
563 lines
16 KiB
563 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
card.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code to handle SD card operations like identification
|
|
and configuration.
|
|
|
|
Authors:
|
|
|
|
Neil Sandlin (neilsa) 1-Jan-2002
|
|
|
|
Environment:
|
|
|
|
Kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Internal References
|
|
//
|
|
|
|
VOID
|
|
SdbusReadCommonCIS(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PSD_CARD_DATA CardData
|
|
);
|
|
|
|
VOID
|
|
SdbusReadFunctionCIS(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PSD_FUNCTION_DATA FunctionData
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
SdbusGetCardConfigData(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
OUT PSD_CARD_DATA *pCardData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This enumerates the IO card present in the given SDBUS controller,
|
|
and updates the internal structures to reflect the new card state.
|
|
|
|
|
|
Arguments
|
|
|
|
|
|
Return value
|
|
|
|
Status
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
ULONG i;
|
|
ULONG relativeAddr = FdoExtension->RelativeAddr;
|
|
PSD_CARD_DATA cardData = NULL;
|
|
ULONG responseBuffer[4];
|
|
|
|
try{
|
|
|
|
if ((FdoExtension->numFunctions!=0) || FdoExtension->memFunction) {
|
|
PSD_FUNCTION_DATA functionData;
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x IO functions found=%d, memFunction=%s\n",
|
|
FdoExtension->DeviceObject, FdoExtension->numFunctions,
|
|
(FdoExtension->memFunction ? "TRUE" : "FALSE")));
|
|
|
|
//
|
|
// At this point, it would be good to verify if the previous enumeration matches
|
|
// the present one. This hokey mechanism is just to get something working.
|
|
// ISSUE: NEED TO IMPLEMENT: swapping SD cards while hibernated
|
|
//
|
|
|
|
|
|
cardData = ExAllocatePool(NonPagedPool, sizeof(SD_CARD_DATA));
|
|
if (cardData == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
leave;
|
|
}
|
|
|
|
RtlZeroMemory(cardData, sizeof(SD_CARD_DATA));
|
|
|
|
if (FdoExtension->memFunction) {
|
|
PUCHAR pResponse, pTarget;
|
|
UCHAR j;
|
|
|
|
cardData->SdCid = FdoExtension->SdCid;
|
|
cardData->SdCsd = FdoExtension->SdCsd;
|
|
for (j=0; j<5; j++) {
|
|
UCHAR data = cardData->SdCid.ProductName[4-j];
|
|
|
|
if ((data <= ' ') || data > 0x7F) {
|
|
break;
|
|
}
|
|
cardData->ProductName[j] = data;
|
|
}
|
|
}
|
|
|
|
if (FdoExtension->memFunction) {
|
|
//
|
|
// Read the SCR register
|
|
//
|
|
SdbusSendCmdSynchronous(FdoExtension, SDCMD_APP_CMD, SDCMD_RESP_1, relativeAddr, 0, NULL, 0);
|
|
//ISSUE: How do I get the data?
|
|
SdbusSendCmdSynchronous(FdoExtension, SDCMD_SEND_SCR, SDCMD_RESP_1, 0, SDCMDF_ACMD, NULL, 0);
|
|
}
|
|
|
|
|
|
if (FdoExtension->numFunctions) {
|
|
UCHAR function;
|
|
|
|
(*(FdoExtension->FunctionBlock->SetFunctionType))(FdoExtension, SDBUS_FUNCTION_TYPE_IO);
|
|
|
|
// This command seems to be needed to start reading tuples, but breaks memory
|
|
// enumeration (gets bad Cid, Csd)... need to figure that out later, since that
|
|
// would imply that a combo card wouldn't work.
|
|
SdbusReadCommonCIS(FdoExtension, cardData);
|
|
|
|
for (function=1; function<=FdoExtension->numFunctions; function++) {
|
|
|
|
functionData = ExAllocatePool(NonPagedPool, sizeof(SD_FUNCTION_DATA));
|
|
|
|
if (functionData == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
leave;
|
|
}
|
|
|
|
RtlZeroMemory(functionData, sizeof(SD_FUNCTION_DATA));
|
|
functionData->Function = function;
|
|
SdbusReadFunctionCIS(FdoExtension, functionData);
|
|
|
|
functionData->Next = cardData->FunctionData;
|
|
cardData->FunctionData = functionData;
|
|
}
|
|
}
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
|
|
}
|
|
} finally {
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
SdbusCleanupCardData(cardData);
|
|
} else {
|
|
*pCardData = cardData;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SdbusCleanupCardData(
|
|
IN PSD_CARD_DATA CardData
|
|
)
|
|
{
|
|
PSD_FUNCTION_DATA functionData;
|
|
PSD_FUNCTION_DATA nextFunctionData;
|
|
|
|
if (CardData != NULL) {
|
|
|
|
for (functionData = CardData->FunctionData; functionData != NULL; functionData = nextFunctionData) {
|
|
nextFunctionData = functionData->Next;
|
|
ExFreePool(functionData);
|
|
}
|
|
ExFreePool(CardData);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
UCHAR
|
|
SdbusReadCIAChar(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN ULONG ciaPtr
|
|
)
|
|
{
|
|
SD_RW_DIRECT_ARGUMENT argument;
|
|
UCHAR response;
|
|
|
|
argument.u.AsULONG = 0;
|
|
argument.u.bits.Address = ciaPtr;
|
|
|
|
SdbusSendCmdSynchronous(FdoExtension,
|
|
SDCMD_IO_RW_DIRECT,
|
|
SDCMD_RESP_5,
|
|
argument.u.AsULONG,
|
|
0,
|
|
&response,
|
|
sizeof(UCHAR));
|
|
|
|
return response;
|
|
}
|
|
|
|
|
|
VOID
|
|
SdbusWriteCIAChar(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN ULONG ciaPtr,
|
|
IN UCHAR data
|
|
)
|
|
{
|
|
SD_RW_DIRECT_ARGUMENT argument;
|
|
ULONG responseBuffer[4];
|
|
|
|
argument.u.AsULONG = 0;
|
|
argument.u.bits.Address = ciaPtr;
|
|
argument.u.bits.Data = data;
|
|
argument.u.bits.WriteToDevice = 1;
|
|
|
|
SdbusSendCmdSynchronous(FdoExtension,
|
|
SDCMD_IO_RW_DIRECT,
|
|
SDCMD_RESP_5,
|
|
argument.u.AsULONG,
|
|
0,
|
|
NULL,
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
USHORT
|
|
SdbusReadCIAWord(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN ULONG ciaPtr
|
|
)
|
|
{
|
|
USHORT data;
|
|
|
|
data = (USHORT) SdbusReadCIAChar(FdoExtension, ciaPtr+1) << 8;
|
|
data |= (USHORT) SdbusReadCIAChar(FdoExtension, ciaPtr);
|
|
return data;
|
|
}
|
|
|
|
ULONG
|
|
SdbusReadCIADword(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN ULONG ciaPtr
|
|
)
|
|
{
|
|
ULONG data;
|
|
|
|
data = (ULONG) SdbusReadCIAChar(FdoExtension, ciaPtr+3) << 24;
|
|
data |= (ULONG) SdbusReadCIAChar(FdoExtension, ciaPtr+2) << 16;
|
|
data |= (ULONG) SdbusReadCIAChar(FdoExtension, ciaPtr+1) << 8;
|
|
data |= (ULONG) SdbusReadCIAChar(FdoExtension, ciaPtr);
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SdbusReadCommonCIS(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PSD_CARD_DATA CardData
|
|
)
|
|
{
|
|
|
|
UCHAR cmd, link;
|
|
UCHAR i;
|
|
ULONG tupleCount = 0;
|
|
USHORT manfCode, manfInf;
|
|
UCHAR funcId;
|
|
UCHAR funcEType;
|
|
ULONG cisPtr;
|
|
ULONG index;
|
|
ULONG endStr;
|
|
UCHAR data;
|
|
|
|
CardData->CardCapabilities = SdbusReadCIAChar(FdoExtension,8);
|
|
|
|
//
|
|
// Get the common cisptr from the CCCR
|
|
//
|
|
|
|
cisPtr = ((SdbusReadCIAChar(FdoExtension, SD_CCCR_CIS_POINTER+2) << 16) +
|
|
(SdbusReadCIAChar(FdoExtension, SD_CCCR_CIS_POINTER+1) << 8) +
|
|
SdbusReadCIAChar(FdoExtension, SD_CCCR_CIS_POINTER));
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x cisPtr=%.06x\n",
|
|
FdoExtension->DeviceObject, cisPtr));
|
|
|
|
cmd = SdbusReadCIAChar(FdoExtension, cisPtr);
|
|
link = SdbusReadCIAChar(FdoExtension, cisPtr+1);
|
|
|
|
|
|
while((cmd != CISTPL_END) && (cmd != CISTPL_NULL)) {
|
|
tupleCount++;
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CIS %.06x cmd=%.02x link=%.02x\n",
|
|
FdoExtension->DeviceObject, cisPtr, cmd, link));
|
|
|
|
switch(cmd) {
|
|
|
|
case CISTPL_MANFID:
|
|
if (link < 4) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_MANFID invalid link %x\n",
|
|
FdoExtension->DeviceObject, link));
|
|
return;
|
|
}
|
|
|
|
CardData->MfgId = SdbusReadCIAWord(FdoExtension, cisPtr+2);
|
|
CardData->MfgInfo = SdbusReadCIAWord(FdoExtension, cisPtr+4);
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CISTPL_MANFID code=%x, inf=%x\n",
|
|
FdoExtension->DeviceObject, CardData->MfgId, CardData->MfgInfo));
|
|
break;
|
|
|
|
|
|
case CISTPL_VERS_1:
|
|
|
|
index = cisPtr+4;
|
|
endStr = index + (link - 2);
|
|
i = 0;
|
|
|
|
data = SdbusReadCIAChar(FdoExtension, index++);
|
|
while (data) {
|
|
if (index > endStr) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_VERS_1 parse error\n",
|
|
FdoExtension->DeviceObject));
|
|
return;
|
|
}
|
|
|
|
if (data >= ' ' && data < 0x7F) {
|
|
CardData->MfgText[i++] = data;
|
|
}
|
|
data = SdbusReadCIAChar(FdoExtension, index++);
|
|
}
|
|
|
|
CardData->MfgText[i] = 0;
|
|
|
|
i = 0;
|
|
|
|
data = SdbusReadCIAChar(FdoExtension, index++);
|
|
while (data) {
|
|
if (index > endStr) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_VERS_1 parse error\n",
|
|
FdoExtension->DeviceObject));
|
|
return;
|
|
}
|
|
|
|
if (data >= ' ' && data < 0x7F) {
|
|
CardData->ProductText[i++] = data;
|
|
}
|
|
data = SdbusReadCIAChar(FdoExtension, index++);
|
|
}
|
|
|
|
CardData->ProductText[i] = 0;
|
|
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CISTPL_VERS_1 %s %s\n",
|
|
FdoExtension->DeviceObject, CardData->MfgText, CardData->ProductText));
|
|
break;
|
|
|
|
|
|
case CISTPL_FUNCID:
|
|
if (link != 2) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCID invalid link %x\n",
|
|
FdoExtension->DeviceObject, link));
|
|
return;
|
|
}
|
|
|
|
funcId = SdbusReadCIAChar(FdoExtension, cisPtr+2);
|
|
|
|
if (funcId != 12) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCID invalid id %x\n",
|
|
FdoExtension->DeviceObject, funcId));
|
|
return;
|
|
}
|
|
break;
|
|
|
|
|
|
case CISTPL_FUNCE:
|
|
funcEType = SdbusReadCIAChar(FdoExtension, cisPtr+2);
|
|
|
|
if (funcEType == 0) {
|
|
USHORT blkSize;
|
|
UCHAR tranSpeed;
|
|
|
|
if (link != 4) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCE invalid type0 link %x\n",
|
|
FdoExtension->DeviceObject, link));
|
|
return;
|
|
}
|
|
|
|
blkSize = SdbusReadCIAWord(FdoExtension, cisPtr+3);
|
|
tranSpeed = SdbusReadCIAChar(FdoExtension, cisPtr+5);
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CISTPL_FUNCE 0 blksize %04x transpeed %02x\n",
|
|
FdoExtension->DeviceObject, blkSize, tranSpeed));
|
|
|
|
} else {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCE invalid funce type %x\n",
|
|
FdoExtension->DeviceObject, funcEType));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
cisPtr += link+2;
|
|
|
|
cmd = SdbusReadCIAChar(FdoExtension, cisPtr);
|
|
link = SdbusReadCIAChar(FdoExtension, cisPtr+1);
|
|
}
|
|
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CIS %.06x cmd=%.02x link=%.02x EXITING %d tuples read\n",
|
|
FdoExtension->DeviceObject, cisPtr, cmd, link, tupleCount));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SdbusReadFunctionCIS(
|
|
IN PFDO_EXTENSION FdoExtension,
|
|
IN PSD_FUNCTION_DATA FunctionData
|
|
)
|
|
{
|
|
UCHAR cmd, link;
|
|
UCHAR i;
|
|
ULONG tupleCount = 0;
|
|
UCHAR funcId;
|
|
UCHAR funcEType;
|
|
ULONG fbrPtr = FunctionData->Function*0x100;
|
|
ULONG cisPtr;
|
|
BOOLEAN hasCsa;
|
|
UCHAR data;
|
|
|
|
data = SdbusReadCIAChar(FdoExtension, fbrPtr);
|
|
|
|
FunctionData->IoDeviceInterface = data & 0xf;
|
|
hasCsa = ((data & 0x40) != 0);
|
|
|
|
|
|
cisPtr = ((SdbusReadCIAChar(FdoExtension, fbrPtr + SD_CCCR_CIS_POINTER + 2) << 16) +
|
|
(SdbusReadCIAChar(FdoExtension, fbrPtr + SD_CCCR_CIS_POINTER + 1) << 8) +
|
|
SdbusReadCIAChar(FdoExtension, fbrPtr + SD_CCCR_CIS_POINTER));
|
|
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x function %d cisPtr=%.06x interfaceCode=%d hasCsa=%s\n",
|
|
FdoExtension->DeviceObject, FunctionData->Function, cisPtr, FunctionData->IoDeviceInterface,
|
|
hasCsa ? "TRUE" : "FALSE"));
|
|
|
|
if (!cisPtr || (cisPtr == 0xFFFFFF)) {
|
|
return;
|
|
}
|
|
|
|
cmd = SdbusReadCIAChar(FdoExtension, cisPtr);
|
|
link = SdbusReadCIAChar(FdoExtension, cisPtr+1);
|
|
|
|
|
|
while((cmd != CISTPL_END) && (cmd != CISTPL_NULL)) {
|
|
tupleCount++;
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CIS %.06x cmd=%.02x link=%.02x\n",
|
|
FdoExtension->DeviceObject, cisPtr, cmd, link));
|
|
|
|
switch(cmd) {
|
|
|
|
|
|
case CISTPL_FUNCID:
|
|
if (link != 2) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCID invalid link %x\n",
|
|
FdoExtension->DeviceObject, link));
|
|
return;
|
|
}
|
|
|
|
funcId = SdbusReadCIAChar(FdoExtension, cisPtr+2);
|
|
|
|
if (funcId != 12) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCID invalid id %x\n",
|
|
FdoExtension->DeviceObject, funcId));
|
|
return;
|
|
}
|
|
break;
|
|
|
|
|
|
case CISTPL_FUNCE:
|
|
funcEType = SdbusReadCIAChar(FdoExtension, cisPtr+2);
|
|
|
|
if (funcEType == 1) {
|
|
UCHAR fInfo, ioRev, csaProp, opMin, opAvg, opMax, sbMin, sbAvg, sbMax;
|
|
USHORT blkSize, minBw, optBw;
|
|
ULONG cardPsn, csaSize, ocr;
|
|
|
|
if (link != 0x1C) {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCE invalid type1 link %x\n",
|
|
FdoExtension->DeviceObject, link));
|
|
return;
|
|
}
|
|
|
|
fInfo = SdbusReadCIAChar(FdoExtension, cisPtr+3);
|
|
ioRev = SdbusReadCIAChar(FdoExtension, cisPtr+4);
|
|
|
|
cardPsn = SdbusReadCIADword(FdoExtension, cisPtr+5);
|
|
csaSize = SdbusReadCIADword(FdoExtension, cisPtr+9);
|
|
|
|
csaProp = SdbusReadCIAChar(FdoExtension, cisPtr+13);
|
|
|
|
blkSize = SdbusReadCIAWord(FdoExtension, cisPtr+14);
|
|
|
|
ocr = SdbusReadCIADword(FdoExtension, cisPtr+16);
|
|
|
|
opMin = SdbusReadCIAChar(FdoExtension, cisPtr+20);
|
|
opAvg = SdbusReadCIAChar(FdoExtension, cisPtr+21);
|
|
opMax = SdbusReadCIAChar(FdoExtension, cisPtr+22);
|
|
|
|
sbMin = SdbusReadCIAChar(FdoExtension, cisPtr+23);
|
|
sbAvg = SdbusReadCIAChar(FdoExtension, cisPtr+24);
|
|
sbMax = SdbusReadCIAChar(FdoExtension, cisPtr+25);
|
|
|
|
minBw = SdbusReadCIAWord(FdoExtension, cisPtr+26);
|
|
optBw = SdbusReadCIAWord(FdoExtension, cisPtr+28);
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CISTPL_FUNCE 1\n",
|
|
FdoExtension->DeviceObject));
|
|
|
|
} else {
|
|
DebugPrint((SDBUS_DEBUG_FAIL, "fdo %08x CISTPL_FUNCE invalid funce type %x\n",
|
|
FdoExtension->DeviceObject, funcEType));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
cisPtr += link+2;
|
|
|
|
cmd = SdbusReadCIAChar(FdoExtension, cisPtr);
|
|
link = SdbusReadCIAChar(FdoExtension, cisPtr+1);
|
|
}
|
|
|
|
|
|
DebugPrint((SDBUS_DEBUG_ENUM, "fdo %08x CIS %.06x cmd=%.02x link=%.02x EXITING %d tuples read\n",
|
|
FdoExtension->DeviceObject, cisPtr, cmd, link, tupleCount));
|
|
|
|
}
|
|
|