|
|
/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
toshiba.c
Abstract:
This module supplies functions that control the Toshiba SD controller. Based on the Toshiba "Pelican3"
Author(s):
Neil Sandlin (neilsa) Jan 1 2002
Revisions: --*/
#include "pch.h"
#include "toshiba.h"
//
// Internal References
//
VOID ToshibaInitializeController( IN PFDO_EXTENSION FdoExtension );
VOID ToshibaInitializeFunction( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension );
ULONG ToshibaGetPendingEvents( IN PFDO_EXTENSION FdoExtension );
VOID ToshibaEnableEvent( IN PFDO_EXTENSION FdoExtension, IN ULONG EventMask );
VOID ToshibaDisableEvent( IN PFDO_EXTENSION FdoExtension, IN ULONG EventMask );
VOID ToshibaAcknowledgeEvent( IN PFDO_EXTENSION FdoExtension, IN ULONG EventMask );
NTSTATUS ToshibaSetPower( IN PFDO_EXTENSION FdoExtension, IN BOOLEAN Enable, OUT PULONG pDelayTime );
NTSTATUS ToshibaResetHost( IN PFDO_EXTENSION FdoExtension, IN UCHAR Phase, OUT PULONG pDelayTime );
VOID ToshibaSetLED( IN PFDO_EXTENSION FdoExtension, IN BOOLEAN Enable ); VOID ToshibaSetFunctionType( IN PFDO_EXTENSION FdoExtension, IN UCHAR FunctionType );
BOOLEAN ToshibaDetectCardInSocket( IN PFDO_EXTENSION FdoExtension );
BOOLEAN ToshibaIsWriteProtected( IN PFDO_EXTENSION FdoExtension );
NTSTATUS ToshibaCheckStatus( IN PFDO_EXTENSION FdoExtension );
NTSTATUS ToshibaSDCommand( IN PFDO_EXTENSION FdoExtension, IN PSD_WORK_PACKET WorkPacket );
NTSTATUS ToshibaSDGetResponse( IN PFDO_EXTENSION FdoExtension, IN PSD_WORK_PACKET WorkPacket );
VOID ToshibaStartBlockOperation( IN PFDO_EXTENSION FdoExtension ); VOID ToshibaSetBlockParameters( IN PFDO_EXTENSION FdoExtension, IN USHORT SectorCount ); VOID ToshibaEndBlockOperation( IN PFDO_EXTENSION FdoExtension );
VOID ToshibaReadDataPort( IN PFDO_EXTENSION FdoExtension, IN PUCHAR Buffer, IN ULONG Length );
VOID ToshibaWriteDataPort( IN PFDO_EXTENSION FdoExtension, IN PUCHAR Buffer, IN ULONG Length );
UCHAR ToshibaReadRegisterUchar( IN PFDO_EXTENSION FdoExtension, IN USHORT Register );
USHORT ToshibaReadRegisterUshort( IN PFDO_EXTENSION FdoExtension, IN USHORT Register );
VOID ToshibaWriteRegisterUshort( IN PFDO_EXTENSION FdoExtension, IN USHORT Register, IN USHORT Data );
ULONG ToshibaReadRegisterUlong( IN PFDO_EXTENSION FdoExtension, IN USHORT Register );
VOID ToshibaWriteRegisterUlong( IN PFDO_EXTENSION FdoExtension, IN USHORT Register, IN ULONG Data );
//
// Internal Data
//
SD_FUNCTION_BLOCK ToshibaSupportFns = { ToshibaInitializeController, ToshibaInitializeFunction, ToshibaSetPower, ToshibaResetHost, ToshibaSetLED, ToshibaSetFunctionType, ToshibaDetectCardInSocket, ToshibaIsWriteProtected, ToshibaCheckStatus, ToshibaSDCommand, ToshibaSDGetResponse, ToshibaStartBlockOperation, ToshibaSetBlockParameters, ToshibaEndBlockOperation, ToshibaReadDataPort, ToshibaWriteDataPort, ToshibaEnableEvent, ToshibaDisableEvent, ToshibaGetPendingEvents, ToshibaAcknowledgeEvent };
VOID DebugDumpRegs( IN PFDO_EXTENSION FdoExtension ) { #if DBG
if (SdbusDebugMask & SDBUS_DEBUG_DUMP_REGS) { USHORT i,j; USHORT buffer[8]; USHORT offset; USHORT count = 0; ULONG skip = 0x03000000; USHORT index; offset = 0; for (j = 0; j < 8; j++) { for (i = 0; i < 8; i++) { index = offset + (i*2); if (skip & (1 << (index/2))) { buffer[i] = 0xFEFE; } else { buffer[i] = ToshibaReadRegisterUshort(FdoExtension, index); } count++; } DebugPrint((SDBUS_DEBUG_DUMP_REGS, "%04x: %04x %04x %04x %04x-%04x %04x %04x %04x\n", offset, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7])); offset += 16; if (offset == 0x40) { offset = 0x100; } } } #endif
}
// ---------------------------------------------------------------
// External interface routines
// ---------------------------------------------------------------
VOID ToshibaInitializeController( IN PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
Arguments:
Return value:
--*/ { USHORT data; UCHAR configData;
DebugPrint((SDBUS_DEBUG_DEVICE, "ToshibaInitializeController\n"));
//
// The Toshiba device appears to need this in order to function at all
//
// SetPciConfigSpace(FdoExtension, 0x40, &configData, 1);
configData = 0x1F; // Clock enable
SetPciConfigSpace(FdoExtension, TOCFG_CLOCK_CONTROL, &configData, 1); configData = 0x08; // Power control
SetPciConfigSpace(FdoExtension, TOCFG_POWER_CTL1, &configData, 1);
data = ToshibaReadRegisterUshort(FdoExtension, TOMHC_HOST_CORE_VERSION); DebugPrint((SDBUS_DEBUG_DEVICE, "TOMHC_HOST_CORE_VERSION - %x\n", data));
ToshibaWriteRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK, 0xFFFFFFFF); ToshibaWriteRegisterUlong(FdoExtension, TOIOHC_INTERRUPT_MASK, 0xFFFFFFFF);
//
// start the controller off in memory mode
//
ToshibaSetFunctionType(FdoExtension, SDBUS_FUNCTION_TYPE_MEMORY); }
VOID ToshibaInitializeFunction( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension ) /*++
Routine Description:
Arguments:
Return value:
--*/ { ULONG sdRca = FdoExtension->RelativeAddr;
DebugPrint((SDBUS_DEBUG_DEVICE, "ToshibaInitializeFunction(%d)\n", PdoExtension->Function)); if (PdoExtension->Function == 8) { //
// Memory function
//
} else { }
}
NTSTATUS ToshibaSetPower( IN PFDO_EXTENSION FdoExtension, IN BOOLEAN Enable, OUT OPTIONAL PULONG pDelayTime ) /*++
Routine Description:
Arguments:
Return value:
--*/ { UCHAR reg; UCHAR mask; UCHAR data;
GetPciConfigSpace(FdoExtension, TOCFG_POWER_CTL2, ®, 1);
mask = 0x03; reg &= ~mask;
if (Enable) { reg |= TO_POWER_33; }
SetPciConfigSpace(FdoExtension, TOCFG_POWER_CTL2, ®, 1);
if (pDelayTime) { *pDelayTime = 0x5dc; } return STATUS_SUCCESS; }
NTSTATUS ToshibaResetHost( IN PFDO_EXTENSION FdoExtension, IN UCHAR Phase, OUT PULONG pDelayTime ) { NTSTATUS status; UCHAR data;
switch(Phase) { case 0: data = 0x0B; SetPciConfigSpace(FdoExtension, TOCFG_CLOCK_CONTROL, &data, 1); ToshibaWriteRegisterUshort(FdoExtension, TOMHC_SOFTWARE_RESET, 0); *pDelayTime = 0x5dc; status = STATUS_MORE_PROCESSING_REQUIRED; break; case 1: ToshibaWriteRegisterUshort(FdoExtension, TOMHC_SOFTWARE_RESET, 1);
ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_SOFTWARE_RESET, 0); *pDelayTime = 0x5dc; status = STATUS_MORE_PROCESSING_REQUIRED; break;
case 2: ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_SOFTWARE_RESET, 1);
// ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CLOCK_AND_WAIT_CONTROL,
// ToshibaReadRegisterUshort(FdoExtension, TOIOHC_CLOCK_AND_WAIT_CONTROL) & 0xFCFC);
//
// turn off IOHC clock enable and card wait
//
ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CLOCK_AND_WAIT_CONTROL, ToshibaReadRegisterUshort(FdoExtension, TOIOHC_CLOCK_AND_WAIT_CONTROL) & ~(TOIO_CWCF_CLOCK_ENABLE | TOIO_CWCF_CARD_WAIT)); //
// turn off MHC clock enable
//
ToshibaWriteRegisterUshort(FdoExtension, TOMHC_CARD_CLOCK_CTL, ToshibaReadRegisterUshort(FdoExtension, TOMHC_CARD_CLOCK_CTL) & ~TO_CCC_CLOCK_ENABLE); //
// Turn on MHC clock enable
//
ToshibaWriteRegisterUshort(FdoExtension, TOMHC_CARD_CLOCK_CTL, // (TO_CCC_CLOCK_ENABLE | TO_CCC_CLOCK_DIVISOR_128));
TO_CCC_CLOCK_ENABLE); //
// Turn on IOHC clock enable and card wait
//
ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CLOCK_AND_WAIT_CONTROL, (TOIO_CWCF_CLOCK_ENABLE | TOIO_CWCF_CARD_WAIT)); data = 0x1F; SetPciConfigSpace(FdoExtension, TOCFG_CLOCK_CONTROL, &data, 1);
*pDelayTime = 0x3e8; status = STATUS_MORE_PROCESSING_REQUIRED; break;
case 3: status = STATUS_SUCCESS; break; }
return status; }
VOID ToshibaSetLED( IN PFDO_EXTENSION FdoExtension, IN BOOLEAN Enable ) { }
//
// Event handling functions
//
ULONG EventMaskToHardwareMask( ULONG EventMask ) { ULONG hardwareMask = 0; if (EventMask & SDBUS_EVENT_INSERTION) { hardwareMask |= TO_EVT_CARD_INSERTION; } if (EventMask & SDBUS_EVENT_REMOVAL) { hardwareMask |= TO_EVT_CARD_REMOVAL; } if (EventMask & SDBUS_EVENT_CARD_RESPONSE) { hardwareMask |= TO_EVT_RESPONSE; } if (EventMask & SDBUS_EVENT_CARD_RW_END) { hardwareMask |= TO_EVT_RW_END; } if (EventMask & SDBUS_EVENT_BUFFER_EMPTY) { hardwareMask |= TO_EVT_BUFFER_EMPTY; } if (EventMask & SDBUS_EVENT_BUFFER_FULL) { hardwareMask |= TO_EVT_BUFFER_FULL; } return hardwareMask; } ULONG HardwareMaskToEventMask( ULONG HardwareMask ) { ULONG eventMask = 0; if (HardwareMask & TO_EVT_CARD_INSERTION) { eventMask |= SDBUS_EVENT_INSERTION; } if (HardwareMask & TO_EVT_CARD_REMOVAL) { eventMask |= SDBUS_EVENT_REMOVAL; } if (HardwareMask & TO_EVT_RESPONSE) { eventMask |= SDBUS_EVENT_CARD_RESPONSE; } if (HardwareMask & TO_EVT_RW_END) { eventMask |= SDBUS_EVENT_CARD_RW_END; } if (HardwareMask & TO_EVT_BUFFER_EMPTY) { eventMask |= SDBUS_EVENT_BUFFER_EMPTY; } if (HardwareMask & TO_EVT_BUFFER_FULL) { eventMask |= SDBUS_EVENT_BUFFER_FULL; } return eventMask; }
VOID ToshibaEnableEvent( IN PFDO_EXTENSION FdoExtension, IN ULONG EventMask ) /*++
Routine Description:
Arguments:
Return value:
--*/ { ULONG data; ULONG cardEvents, ctlrEvents, ioCardEvent; ULONG mask; DebugPrint((SDBUS_DEBUG_EVENT, "EnableEvent: %08x\n", EventMask)); FdoExtension->CurrentlyEnabledEvents |= EventMask; ctlrEvents = EventMask & (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL); EventMask &= ~(SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL); ioCardEvent = EventMask & SDBUS_EVENT_CARD_INTERRUPT; EventMask &= ~SDBUS_EVENT_CARD_INTERRUPT; cardEvents = EventMask; mask = EventMaskToHardwareMask(cardEvents); if (mask) { data = ToshibaReadRegisterUlong(FdoExtension, FdoExtension->InterruptMaskReg); data &= ~mask; ToshibaWriteRegisterUlong(FdoExtension, FdoExtension->InterruptMaskReg, data); } mask = EventMaskToHardwareMask(ctlrEvents); if (mask) { data = ToshibaReadRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK); data &= ~mask; ToshibaWriteRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK, data); } if (ioCardEvent) { USHORT usData; usData = ToshibaReadRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL); usData &= ~TOIO_CICF_CARD_INTMASK; ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL, usData); } }
VOID ToshibaDisableEvent( IN PFDO_EXTENSION FdoExtension, IN ULONG EventMask ) /*++
Routine Description:
Arguments:
Return value:
--*/ { ULONG data; ULONG cardEvents, ctlrEvents, ioCardEvent; ULONG mask;
FdoExtension->CurrentlyEnabledEvents &= ~EventMask; ctlrEvents = EventMask & (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL); EventMask &= ~(SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL); ioCardEvent = EventMask & SDBUS_EVENT_CARD_INTERRUPT; EventMask &= ~SDBUS_EVENT_CARD_INTERRUPT; cardEvents = EventMask; mask = EventMaskToHardwareMask(cardEvents); if (mask) { data = ToshibaReadRegisterUlong(FdoExtension, FdoExtension->InterruptMaskReg); data |= mask; ToshibaWriteRegisterUlong(FdoExtension, FdoExtension->InterruptMaskReg, data); }
mask = EventMaskToHardwareMask(ctlrEvents); if (mask) { data = ToshibaReadRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK); data |= mask; ToshibaWriteRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK, data); } if (ioCardEvent) { USHORT usData; usData = ToshibaReadRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL); usData |= TOIO_CICF_CARD_INTMASK; ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL, usData); } }
ULONG ToshibaGetPendingEvents( IN PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
Arguments:
Return value:
--*/ { ULONG statusMask, eventMask; ULONG mhcEvent = 0, iohcEvent = 0, iocardEvent = 0; USHORT usData;
//
// The Pelican3 has interrupt status spread out everywhere. First try
// the memory host controller
//
statusMask = ToshibaReadRegisterUlong(FdoExtension, TOMHC_CARD_STATUS); eventMask = ToshibaReadRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK);
// turn off undefined bits
statusMask &= 0x837F031D; // turn off bits that are masked
statusMask &= ~eventMask; mhcEvent = HardwareMaskToEventMask(statusMask); if (statusMask && (mhcEvent == 0)) { // got an interrupt, but we don't know what type
ASSERT(FALSE); eventMask |= statusMask; ToshibaWriteRegisterUlong(FdoExtension, TOMHC_INTERRUPT_MASK, eventMask); } //
// Now try the IO host controller
//
if (!mhcEvent) { statusMask = ToshibaReadRegisterUlong(FdoExtension, TOIOHC_CARD_STATUS); eventMask = ToshibaReadRegisterUlong(FdoExtension, TOIOHC_INTERRUPT_MASK); // turn off undefined bits
statusMask &= 0xA37F0005; // turn off bits that are masked
statusMask &= ~eventMask; iohcEvent = HardwareMaskToEventMask(statusMask); if (statusMask && (iohcEvent == 0)) { // got an interrupt, but we don't know what type
ASSERT(FALSE); eventMask |= statusMask; ToshibaWriteRegisterUlong(FdoExtension, TOIOHC_INTERRUPT_MASK, eventMask); } //
// get IO card interrupt
//
usData = ToshibaReadRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL); if ((usData & TOIO_CICF_CARD_INTERRUPT) && ((usData & TOIO_CICF_CARD_INTMASK)==0)) { if (ToshibaDetectCardInSocket(FdoExtension)) { iocardEvent = SDBUS_EVENT_CARD_INTERRUPT; } else { //
// the card is gone, this must be spurious
//
usData |= TOIO_CICF_CARD_INTMASK; ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL, usData); } } } return mhcEvent | iohcEvent | iocardEvent; }
VOID ToshibaAcknowledgeEvent( IN PFDO_EXTENSION FdoExtension, IN ULONG EventMask ) /*++
Routine Description:
Arguments:
Return value:
--*/ { ULONG hardwareMask = EventMaskToHardwareMask(EventMask); ULONG data; USHORT interruptMaskReg, cardStatusReg;
if (EventMask & SDBUS_EVENT_CARD_INTERRUPT) { //
// No need to clear io card IRQ, just reenable it
//
USHORT usData; usData = ToshibaReadRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL); usData &= ~TOIO_CICF_CARD_INTMASK; ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CARD_INTERRUPT_CONTROL, usData); return; }
if (EventMask & (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL)) { interruptMaskReg = TOMHC_INTERRUPT_MASK; cardStatusReg = TOMHC_CARD_STATUS; } else { interruptMaskReg = FdoExtension->InterruptMaskReg; cardStatusReg = FdoExtension->CardStatusReg; }
//
// Clear event in status register
//
data = ToshibaReadRegisterUlong(FdoExtension, cardStatusReg); DebugPrint((SDBUS_DEBUG_EVENT, "AcknowledgeEvent: %08x - cardstatus %08x\n", EventMask, data)); data &= ~hardwareMask; ToshibaWriteRegisterUlong(FdoExtension, cardStatusReg, data);
#if DBG
data = ToshibaReadRegisterUlong(FdoExtension, cardStatusReg); DebugPrint((SDBUS_DEBUG_EVENT, "AcknowledgeEvent: new cardstatus %08x\n", data)); #endif
//
// Reenable event
//
FdoExtension->CurrentlyEnabledEvents |= EventMask; data = ToshibaReadRegisterUlong(FdoExtension, interruptMaskReg); data &= ~hardwareMask; ToshibaWriteRegisterUlong(FdoExtension, interruptMaskReg, data); }
VOID ToshibaSetFunctionType( IN PFDO_EXTENSION FdoExtension, IN UCHAR FunctionType ) { ULONG currentlyEnabledEvents = FdoExtension->CurrentlyEnabledEvents;
if (FunctionType == FdoExtension->FunctionType) { return; }
//
// The pelican3 implements these event masks in two places, so disable and reenable them
//
if (currentlyEnabledEvents) { ToshibaDisableEvent(FdoExtension, currentlyEnabledEvents); } switch(FunctionType) {
case SDBUS_FUNCTION_TYPE_MEMORY: ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_CLOCK_AND_WAIT_CONTROL, 0x100);
ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_TRANSACTION_CONTROL, ToshibaReadRegisterUshort(FdoExtension, TOIOHC_TRANSACTION_CONTROL) & 0xEFFF);
FdoExtension->ArgumentReg = TOMHC_ARGUMENT; FdoExtension->CmdReg = TOMHC_COMMAND; FdoExtension->CardStatusReg = TOMHC_CARD_STATUS; FdoExtension->ResponseReg = TOMHC_RESPONSE; FdoExtension->InterruptMaskReg = TOMHC_INTERRUPT_MASK; break;
case SDBUS_FUNCTION_TYPE_IO:
FdoExtension->ArgumentReg = TOIOHC_ARGUMENT; FdoExtension->CmdReg = TOIOHC_COMMAND; FdoExtension->CardStatusReg = TOIOHC_CARD_STATUS; FdoExtension->ResponseReg = TOIOHC_RESPONSE_0; FdoExtension->InterruptMaskReg = TOIOHC_INTERRUPT_MASK; break;
default: ASSERT(FALSE); }
if (currentlyEnabledEvents) { ToshibaEnableEvent(FdoExtension, currentlyEnabledEvents); }
FdoExtension->FunctionType = FunctionType; }
BOOLEAN ToshibaDetectCardInSocket( IN PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
Arguments:
Return value:
--*/ { USHORT data;
data = ToshibaReadRegisterUshort(FdoExtension, TOMHC_CARD_STATUS); return !((data & TO_STS_CARD_PRESENT) == 0); }
BOOLEAN ToshibaIsWriteProtected( IN PFDO_EXTENSION FdoExtension ) { USHORT data;
data = ToshibaReadRegisterUshort(FdoExtension, TOMHC_CARD_STATUS); return ((data & TO_STS_WRITE_PROTECT) == 0); }
#if 0
BOOLEAN ToshibaClearStatus( IN PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
Arguments:
Return value:
--*/ {
//
// This was stuff that was done before the first SEND... it is unclear how
// much should be moved to the send
//
ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_TRANSACTION_CONTROL, ToshibaReadRegisterUshort(FdoExtension, TOIOHC_TRANSACTION_CONTROL) & 0xEFFF);
ToshibaWriteRegisterUshort(FdoExtension, TOMHC_BUFFER_CTL_AND_ERR, ToshibaReadRegisterUshort(FdoExtension, TOMHC_BUFFER_CTL_AND_ERR) & 0x7D00);
ToshibaWriteRegisterUshort(FdoExtension, TOMHC_CARD_STATUS, ToshibaReadRegisterUshort(FdoExtension, TOMHC_CARD_STATUS) & 0xFFFA);
return TRUE; } #endif
NTSTATUS ToshibaCheckStatus( IN PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
Arguments:
Return value:
--*/ { ULONG cardStatus; ULONG errorStatus; NTSTATUS status = STATUS_SUCCESS; DebugDumpRegs(FdoExtension);
cardStatus = ToshibaReadRegisterUlong(FdoExtension, FdoExtension->CardStatusReg);
if (FdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) { errorStatus = cardStatus & (TOMHC_BCE_CMD_INDEX_ERROR | TOMHC_BCE_CRC_ERROR | TOMHC_BCE_END_BIT_ERROR | TOMHC_BCE_CMD_TIMEOUT | TOMHC_BCE_DATA_TIMEOUT | TOMHC_BCE_FIFO_OVERFLOW | TOMHC_BCE_FIFO_UNDERFLOW | TOMHC_BCE_ILLEGAL_ACCESS); } else { errorStatus = cardStatus & (TOMHC_BCE_CMD_INDEX_ERROR | // TOMHC_BCE_CRC_ERROR |
TOMHC_BCE_END_BIT_ERROR | TOMHC_BCE_CMD_TIMEOUT | TOMHC_BCE_DATA_TIMEOUT | TOMHC_BCE_FIFO_OVERFLOW | TOMHC_BCE_FIFO_UNDERFLOW | TOMHC_BCE_ILLEGAL_ACCESS); } if (errorStatus) { DebugPrint((SDBUS_DEBUG_WARNING, "CheckStatus detected Error! status = %08x\n", errorStatus)); //ISSUE: NEED TO IMPLEMENT: I/O error handling
ToshibaWriteRegisterUlong(FdoExtension, FdoExtension->CardStatusReg, cardStatus & ~errorStatus); // possibilities:
// STATUS_PARITY_ERROR
// STATUS_DEVICE_DATA_ERROR
// STATUS_DEVICE_POWER_FAILURE
// STATUS_DEVICE_NOT_READY
// STATUS_IO_TIMEOUT
// STATUS_INVALID_DEVICE_STATE
// STATUS_IO_DEVICE_ERROR
// STATUS_DEVICE_PROTOCOL_ERROR
// STATUS_DEVICE_REMOVED
// STATUS_POWER_STATE_INVALID
status = STATUS_IO_DEVICE_ERROR; }
return status; }
NTSTATUS ToshibaSDCommand( IN PFDO_EXTENSION FdoExtension, IN PSD_WORK_PACKET WorkPacket ) /*++
Routine Description:
Arguments:
Return value:
--*/ { USHORT cmdWord; ULONG Flags = WorkPacket->Flags; NTSTATUS status;
ToshibaWriteRegisterUlong(FdoExtension, FdoExtension->ArgumentReg, WorkPacket->Argument);
cmdWord = WorkPacket->Cmd;
switch (WorkPacket->ResponseType) { case SDCMD_RESP_NONE: cmdWord |= TOMHC_CMD_RESP_NONE; break;
case SDCMD_RESP_1: case SDCMD_RESP_5: case SDCMD_RESP_6: cmdWord |= 0x400; break;
case SDCMD_RESP_2: cmdWord |= 0x600; break;
case SDCMD_RESP_3: case SDCMD_RESP_4: cmdWord |= 0x700; break;
case SDCMD_RESP_1B: case SDCMD_RESP_5B: cmdWord |= 0x500; break;
default: ASSERT(FALSE); return STATUS_UNSUCCESSFUL; }
//
// Add flags
//
if (Flags & SDCMDF_ACMD) { cmdWord |= TOMHC_CMD_ACMD; }
if (Flags & SDCMDF_DATA) { cmdWord |= TOMHC_CMD_NTDT; }
if (Flags & SDCMDF_MULTIBLOCK) { cmdWord |= TOMHC_CMD_MSSL; }
if (Flags & SDCMDF_READ) { cmdWord |= TOMHC_CMD_RWDI; }
//
// Write Cmd and flags to command register
//
DebugPrint((SDBUS_DEBUG_DEVICE, "SEND: Cmd%d (0x%04x) arg = 0x%08x\n", WorkPacket->Cmd, cmdWord, WorkPacket->Argument)); ToshibaWriteRegisterUshort(FdoExtension, FdoExtension->CmdReg, cmdWord); return STATUS_SUCCESS; }
NTSTATUS ToshibaSDGetResponse( IN PFDO_EXTENSION FdoExtension, IN PSD_WORK_PACKET WorkPacket ) /*++
Routine Description:
Arguments:
Return value:
--*/ { // ULONG cardStatus;
UCHAR i; PUCHAR pRespPtr; NTSTATUS status = STATUS_SUCCESS;
pRespPtr = (PUCHAR) WorkPacket->ResponseBuffer; for (i=0; i<SDBUS_RESPONSE_BUFFER_LENGTH; i++) { *pRespPtr++ = ToshibaReadRegisterUchar(FdoExtension, FdoExtension->ResponseReg+i); }
return status; }
VOID ToshibaStartBlockOperation( IN PFDO_EXTENSION FdoExtension ) { ToshibaWriteRegisterUshort(FdoExtension, TOMHC_CARD_CLOCK_CTL, 0x100); ToshibaWriteRegisterUshort(FdoExtension, TOMHC_OPTIONS, 0x40e0); } VOID ToshibaSetBlockParameters( IN PFDO_EXTENSION FdoExtension, IN USHORT Length ) { if (FdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) { ToshibaWriteRegisterUshort(FdoExtension, TOMHC_CARD_TRANSFER_LENGTH, 512); ToshibaWriteRegisterUshort(FdoExtension, TOMHC_STOP_INTERNAL, 0x100); ToshibaWriteRegisterUshort(FdoExtension, TOMHC_TRANSFER_SECTOR_COUNT, Length); } else {
ToshibaWriteRegisterUshort(FdoExtension, TOIOHC_TRANSFER_DATA_LEN_SELECT, Length); } } VOID ToshibaEndBlockOperation( IN PFDO_EXTENSION FdoExtension ) { ToshibaWriteRegisterUshort(FdoExtension, TOMHC_BUFFER_CTL_AND_ERR, 0); }
VOID ToshibaReadDataPort( IN PFDO_EXTENSION FdoExtension, IN PUCHAR Buffer, IN ULONG Length ) /*++
Routine Description:
The data port must be accessed maintaining DWORD alignment. So for example: IN DWORD 130 IN DWORD 130 is the same as
IN USHORT 130 IN USHORT 132 IN UCHAR 130 IN UCHAR 131 IN UCHAR 132 IN UCHAR 133
Arguments:
Return value:
--*/ { USHORT i; ULONG dwordCount, wordCount, byteCount; PULONG ulBuffer = (PULONG) Buffer; PUSHORT usBuffer; USHORT port = (FdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) ? TOMHC_DATA_PORT : TOIOHC_DATA_TRANSFER; PUCHAR portAddress = ((PUCHAR)FdoExtension->HostRegisterBase + port);
dwordCount = Length / 4; wordCount = (Length % 4) / 2; byteCount = (Length % 4) % 2; for (i = 0; i < dwordCount; i++) { READ_REGISTER_BUFFER_ULONG((PULONG) portAddress, ulBuffer, 1); ulBuffer++; } if (wordCount) { usBuffer = (PUSHORT) ulBuffer; ASSERT(wordCount == 1); READ_REGISTER_BUFFER_USHORT((PUSHORT) portAddress, usBuffer, 1); usBuffer++; } if (byteCount) { PUCHAR ucBuffer = (PUCHAR) usBuffer; ASSERT(byteCount == 1);
// maintain byte order within ULONG dataport
portAddress++; portAddress++; READ_REGISTER_BUFFER_UCHAR((PUCHAR) portAddress, ucBuffer, 1); } }
VOID ToshibaWriteDataPort( IN PFDO_EXTENSION FdoExtension, IN PUCHAR Buffer, IN ULONG Length ) { USHORT i; ULONG dwordCount, wordCount, byteCount; PULONG ulBuffer = (PULONG) Buffer; PUSHORT usBuffer; USHORT port = (FdoExtension->FunctionType == SDBUS_FUNCTION_TYPE_MEMORY) ? TOMHC_DATA_PORT : TOIOHC_DATA_TRANSFER; PUCHAR portAddress = ((PUCHAR)FdoExtension->HostRegisterBase + port);
dwordCount = Length / 4; wordCount = (Length % 4) / 2; byteCount = (Length % 4) % 2; for (i = 0; i < dwordCount; i++) { WRITE_REGISTER_BUFFER_ULONG((PULONG) portAddress, ulBuffer, 1); ulBuffer++; } if (wordCount) { usBuffer = (PUSHORT) ulBuffer; ASSERT(wordCount == 1); WRITE_REGISTER_BUFFER_USHORT((PUSHORT) portAddress, usBuffer, 1); usBuffer++; } if (byteCount) { PUCHAR ucBuffer = (PUCHAR) usBuffer; ASSERT(byteCount == 1);
// maintain byte order within ULONG dataport
portAddress++; portAddress++; WRITE_REGISTER_BUFFER_UCHAR((PUCHAR) portAddress, ucBuffer, 1); } }
// ---------------------------------------------------------------
// Internal routines
// ---------------------------------------------------------------
UCHAR ToshibaReadRegisterUchar( IN PFDO_EXTENSION FdoExtension, IN USHORT Register )
/*++
Routine Description:
This routine will read a byte from the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket from which we should read Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{ UCHAR byte; //
// Sanity check in case controller wasn't started
//
if (FdoExtension->HostRegisterBase) { byte = READ_REGISTER_UCHAR((PUCHAR) ((PUCHAR)FdoExtension->HostRegisterBase + Register)); } else { byte = 0xff; } return byte; }
USHORT ToshibaReadRegisterUshort( IN PFDO_EXTENSION FdoExtension, IN USHORT Register )
/*++
Routine Description:
This routine will read a byte from the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket from which we should read Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{ USHORT word; //
// Sanity check in case controller wasn't started
//
if (FdoExtension->HostRegisterBase) { word = READ_REGISTER_USHORT((PUSHORT) ((PUCHAR)FdoExtension->HostRegisterBase + Register)); } else { word = 0xff; } return word; }
VOID ToshibaWriteRegisterUshort( IN PFDO_EXTENSION FdoExtension, IN USHORT Register, IN USHORT Data )
/*++
Routine Description:
This routine will read a byte from the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket from which we should read Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{ //
// Sanity check in case controller wasn't started
//
if (FdoExtension->HostRegisterBase) { WRITE_REGISTER_USHORT((PUSHORT) ((PUCHAR)FdoExtension->HostRegisterBase + Register), Data); } }
ULONG ToshibaReadRegisterUlong( IN PFDO_EXTENSION FdoExtension, IN USHORT Register )
/*++
Routine Description:
This routine will read a byte from the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket from which we should read Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{ ULONG dword; //
// Sanity check in case controller wasn't started
//
if (FdoExtension->HostRegisterBase) { dword = READ_REGISTER_ULONG((PULONG) ((PUCHAR)FdoExtension->HostRegisterBase + Register)); } else { dword = 0xff; } return dword; }
VOID ToshibaWriteRegisterUlong( IN PFDO_EXTENSION FdoExtension, IN USHORT Register, IN ULONG Data )
/*++
Routine Description:
This routine will read a byte from the specified socket EXCA register
Arguments:
Socket -- Pointer to the socket from which we should read Register -- The register to be read
Return Value:
The data returned from the port.
--*/
{ //
// Sanity check in case controller wasn't started
//
if (FdoExtension->HostRegisterBase) { WRITE_REGISTER_ULONG((PULONG) ((PUCHAR)FdoExtension->HostRegisterBase + Register), Data); } }
|