/*++ 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)); }