--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/medata/pccd_ata.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,1795 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\drivers\medata\pccd_ata.cpp
+//
+//
+
+#include "pbusmedia.h"
+#include "platform.h"
+#include "ata.h"
+
+const TInt KErrBadDrqOnRead=-64;
+const TInt KErrBadDrqOnWrite=-65;
+const TInt KErrBadDrq=-66;
+const TInt KErrAta=-67;
+const TInt KErrBadPccdConfig=-68;
+//const TInt KErrDriveChunkNotOpen=-69;
+
+const TInt KAtaDriverPriority=KMediaDriverPriorityNormal;
+//const TInt KAtaDriverPriority=KMediaDriverPriorityHigh;
+
+_LIT(KPddName, "Media.Ata");
+//_LIT(KPddName, "Media.Ata2");
+
+// One of these
+#define SELECT_CONTIGUOUS_IO_CONFIG
+//#define SELECT_PRIMARY_IO_CONFIG
+//#define SELECT_MEMORY_CONFIG
+
+//#define FORCE_8BIT_ACCESSES
+
+// Special debug options
+//#define SHOW_CARD_ERRORS
+//#define DEBUG_WITH_HW_TRIGGER
+//#define COUNT_TIMEOUTS
+
+#if (defined(SHOW_CARD_ERRORS))
+#define __KTRACE_CARD_ERROR(a,p) {p;}
+#elif (defined(_DEBUG))
+#define __KTRACE_CARD_ERROR(a,p) {if((KDebugNum(a)))p;}
+#else
+#define __KTRACE_CARD_ERROR(a,p)
+#endif
+
+#include <pccard.h>
+
+const TInt KMaxSectorsPerRead=32;
+const TInt KMaxSectorsPerWrite=8;
+const TInt KMaxSectorsPerFormat=8;
+const TInt KMaxBytesPerRead=(KMaxSectorsPerRead<<KAtaSectorShift);
+const TInt KMaxBytesPerWrite=(KMaxSectorsPerWrite<<KAtaSectorShift);
+
+// Sector buffer size must be a multiple of sector size and at least as large
+// as KMaxSectorsPerWrite.
+const TInt KSectBufSizeInSectors=8;
+const TInt KSectBufSizeInBytes=(KSectBufSizeInSectors<<KAtaSectorShift);
+const TInt KSectBufSizeInBytesMinusOneSector=(KSectBufSizeInBytes-KAtaSectorSize);
+
+const TInt KIdleCurrentInMilliAmps=1;
+const TInt KReadCurrentInMilliAmps=39;
+const TInt KWriteCurrentInMilliAmps=46;
+
+const TInt KNotBusySyncTimeout=5;
+const TInt KNotBusySyncRetryCount=10;
+const TInt KDriveReadySyncTimeout=5;
+
+#ifdef _DEBUG
+const TInt KNotBusyTestInterval=30; // Check for not-busy once every 30ms
+const TInt KBusyTimeOut=67; // Timeout after this many tests (67*30ms=2010ms)
+#else
+const TInt KNotBusyTestInterval=5; // Check for not-busy once every 5ms
+const TInt KBusyTimeOut=400; // Timeout after this many tests (400*5ms=2010ms)
+#endif
+
+class DPhysicalDeviceMediaAta : public DPhysicalDevice
+ {
+public:
+ DPhysicalDeviceMediaAta();
+ virtual TInt Install();
+ virtual void GetCaps(TDes8& aDes) const;
+ virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* anInfo, const TVersion& aVer);
+ virtual TInt Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer);
+ virtual TInt Info(TInt aFunction, TAny* a1);
+ };
+
+class DPcCardMediaDriverAta : public DMediaDriver
+ {
+public:
+ DPcCardMediaDriverAta(TInt aMediaId);
+ virtual TInt Request(TLocDrvRequest& aRequest);
+ virtual TInt PartitionInfo(TPartitionInfo& anInfo);
+ virtual void NotifyPowerDown();
+ virtual void NotifyEmergencyPowerDown();
+ virtual void Close();
+public:
+ enum TCardStatus {ECardIdle,ECardRead,ECardWrite,ECardFormat};
+ inline TUint8 AtaRegister8(TUint aReg);
+ inline void SetAtaRegister8(TUint8 aValue,TUint aReg);
+ void ModifyAtaRegister8(TUint aClearMask,TUint aSetMask,TUint aReg);
+ void SelectDrive(TAtaDriveSelect aDrive);
+ TBool WaitForNotBusy();
+ TBool DriveReadyForCommand(TInt aDrive);
+ void SetLbaSectorAddress(TUint aSector);
+ void SetChsSectorAddress(TUint aSector);
+ TInt IssueAtaCommand(TUint8 aCmd,TUint aFirstSector,TInt aSectorCount);
+ TInt EmptySectBufferToTrg(TUint8 *aSrc,TUint aTrgOffset,TInt aLen);
+ TInt LoadSectBufferFromSrc(TInt aLen, TUint8* aBuf);
+ TInt LoadSectBufferFromDrive(TAny *aBuf);
+ TInt EmptySectBufferToDrive(TUint8 *aBuf);
+ TInt TransferSectBufferFromDrive(TAny *aBuf);
+ TInt FinishCommand();
+ TInt CheckForError();
+ TInt ProcessError(TInt anError);
+ TInt SectorBoundaryReadCheck(TUint aStartSector,TUint aStartSectOffset,Int64 anEndPos);
+ TInt SectorRead(TUint aFirstSector,TUint8 *aBuf,TInt aSectorCount=1,TUint8 aCmd=KAtaCmdReadSectors);
+ TInt CheckDevice(TBool aCheckPower);
+ TInt InitiateWriteCommand(TUint aFirstSector,TInt aSectorCount,TUint8 *aSectBuffer);
+ TInt ReadSectorsCommand(TUint aFirstSector,TUint aBufOffset,TInt aLen);
+ TInt IdentifyDrive();
+ void DumpIdentifyDriveInfo();
+ TInt ConfigAutoPowerDown();
+ TInt Open();
+ TInt DoOpen();
+ void DoClose();
+ void Reset();
+ TBool CardPoweredDown();
+ void IncrementSectBufPtr();
+ static void CardIreqDfcFunction(TAny* aPtr);
+ static void TimerDfcFunction(TAny* aPtr);
+ static void AsyncBusyTimerCallBack(TAny* aMediaDriver);
+ static void SyncBusyTimerCallBack(TAny* aBusyFlag);
+ static void CardIntCallBack(TAny* aPtr, TInt anId);
+ TBool DoCardNotBusy(TInt &anErr);
+ TBool CmdDfc();
+ TBool DoCmdDfc(TInt &anErr);
+ void Complete(TInt anError);
+ TInt Caps(TLocalDriveCapsV6& anInfo);
+ TInt DoRead();
+ TInt DoWrite();
+ TInt DoFormat();
+ TInt InitiateAsyncRead();
+ TInt InitiateAsyncWrite();
+public:
+ DPcCardSocket* iSocket;
+ TLocDrvRequest* iCurrentReq;
+ TPBusCallBack iCardIntCallBack;
+ RPccdWindow iDriveChunk;
+ TPccdMemType iMemoryType;
+ TDriveParameters iDriveInfo;
+ NTimer iBusyTimeout;
+ TDfc iCardIreqDfc;
+ TDfc iTimerDfc;
+ TInt iNotBusyTickCount;
+ TInt iCommandError;
+ TCardStatus iCardStatus;
+ TUint iCmdInOffset; // Progress counter for data received from src device
+ TUint iCmdOutOffset; // Progress counter for data delivered to target device
+ TUint iCmdEndOffset; // Marks point when transfer associated with command is complete
+ TUint iCmdLength; // Transfer length remaining
+ TUint iNextSector; // Next sector to transfer
+ TUint8 *iSectBufPtr; // Progress counter for tranfering data between card and sector buffer
+ TUint iSectBufOffset; // Offset within sector buffer to start of data involved in command (Reads only)
+ TBool iLastSectorBufUsed;
+ TUint iHiddenSectors;
+ TInt iCardFuncNum;
+ TUint8 iSectorBuf[KSectBufSizeInBytes]; // Keep on 4byte boundary - put this last
+ TUint8 iLastSectorBuf[KAtaSectorSize]; // Holds last sector data for unaligned write
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ TInt iDbgLastError;
+ TInt iDbgPos;
+ TInt iDbgLen;
+#endif
+#ifdef COUNT_TIMEOUTS
+ TInt iInts;
+ TInt iTimeouts;
+ TInt iImmediateNotBusy;
+ TInt iChainedReads;
+ TInt iChainedWrites;
+ TBool iNewTimeOut;
+ TInt iIndex;
+ TInt iInfo[8];
+#endif
+ };
+
+void DPcCardMediaDriverAta::Complete(TInt anError)
+ {
+ __KTRACE_OPT(KFAIL,Kern::Printf("mdrqc %08x %d",iCurrentReq,anError));
+#ifdef COUNT_TIMEOUTS
+ if (iNewTimeOut)
+ {
+ iNewTimeOut=EFalse;
+ Kern::Printf("I=%d T=%d M=%d CR=%d CW=%d",iInts,iTimeouts,iImmediateNotBusy,iChainedReads,iChainedWrites);
+ TInt i;
+ for (i=0; i<iIndex; i+=2)
+ Kern::Printf("%d: %08x %08x",i,iInfo[i],iInfo[i+1]);
+ iIndex=0;
+ }
+#endif
+ TLocDrvRequest* pR=iCurrentReq;
+ if (pR)
+ {
+ iCurrentReq=NULL;
+ DMediaDriver::Complete(*pR,anError);
+ }
+ }
+
+inline TUint8 DPcCardMediaDriverAta::AtaRegister8(TUint aReg)
+//
+// Read from an 8 bit ATA register
+//
+ {
+
+ return iDriveChunk.Read8(aReg);
+ }
+
+inline void DPcCardMediaDriverAta::SetAtaRegister8(TUint8 aValue,TUint aReg)
+//
+// Write to an 8 bit ATA register
+//
+ {
+
+ iDriveChunk.Write8(aReg,aValue);
+ }
+
+void DPcCardMediaDriverAta::ModifyAtaRegister8(TUint aClearMask,TUint aSetMask,TUint aReg)
+//
+// Modify an 8 bit ATA register
+//
+ {
+
+ SetAtaRegister8((TUint8)((AtaRegister8(aReg)&(~aClearMask))|aSetMask),aReg);
+ }
+
+void DPcCardMediaDriverAta::SelectDrive(TAtaDriveSelect aDrive)
+//
+// Modify an 8 bit ATA register
+//
+ {
+
+ ModifyAtaRegister8(KAtaDrvHeadDrive1,(0xA0|aDrive),KAtaSelectDriveHeadRdWr8);
+ }
+
+TBool DPcCardMediaDriverAta::WaitForNotBusy()
+//
+// Poll busy flag (while card accesses the data buffer and command register).
+// 8mS timeout.
+//
+ {
+
+ // Before we start a timed loop, just check it isn't already not busy
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("WfnB"));
+ if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusBusy))
+ return(ETrue);
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ TUint c=NKern::TickCount();
+#endif
+ volatile TBool timedOut=EFalse;
+ NTimer busyTimeout(SyncBusyTimerCallBack,(TAny*)&timedOut);
+ busyTimeout.OneShot(NKern::TimerTicks(KNotBusySyncTimeout));
+ FOREVER
+ {
+ if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusBusy)||timedOut)
+ break;
+ }
+ if (!timedOut)
+ busyTimeout.Cancel();
+ else
+ {
+ TInt retry=KNotBusySyncRetryCount;
+ while ((AtaRegister8(KAtaStatusRd8)&KAtaStatusBusy) && retry)
+ {
+ NKern::Sleep(1);
+ retry--;
+ }
+ }
+ TBool ret=(AtaRegister8(KAtaStatusRd8) & KAtaStatusBusy);
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ c=NKern::TickCount()-c;
+ if (ret)
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:WaitForNotBusy-timeout(%xH) %d ms",AtaRegister8(KAtaStatusRd8),c));
+ }
+ else
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:WaitForNotBusy-OK %d ms",c));
+ }
+#endif
+ return(!ret);
+ }
+
+TBool DPcCardMediaDriverAta::DriveReadyForCommand(TInt aDrive)
+//
+// Wait until selected drive is able to accept a command (5ms timeout).
+//
+ {
+
+ // Select the drive were waiting on
+ SelectDrive((aDrive==1)?ESelectDrive1:ESelectDrive0);
+ if (!WaitForNotBusy())
+ return(EFalse);
+
+ volatile TBool timedOut=EFalse;
+ NTimer busyTimeout(SyncBusyTimerCallBack,(TAny*)&timedOut);
+ busyTimeout.OneShot(NKern::TimerTicks(KDriveReadySyncTimeout));
+ FOREVER
+ {
+ if (AtaRegister8(KAtaStatusRd8)&KAtaStatusRdy||timedOut)
+ break;
+ }
+ if (!timedOut)
+ busyTimeout.Cancel();
+ TBool ret=(AtaRegister8(KAtaStatusRd8) & KAtaStatusRdy);
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ if (!ret)
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:DriveReadyForCommand-Fail(%xH)",AtaRegister8(KAtaStatusRd8)));
+#endif
+ return(ret);
+ }
+
+void DPcCardMediaDriverAta::SetLbaSectorAddress(TUint aSector)
+//
+// Setup the sector address ATA registers (LBA mode)
+//
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:SetLbaSectorAddress (LBA: %xH)",aSector));
+
+ SetAtaRegister8((TUint8)aSector,KAtaLba7_0RdWr8);
+ SetAtaRegister8((TUint8)(aSector>>8),KAtaLba15_8RdWr8);
+ SetAtaRegister8((TUint8)(aSector>>16),KAtaLba23_16RdWr8);
+ TUint8 lba27_24=(TUint8)((aSector>>24)&0x0F);
+ ModifyAtaRegister8(KAtaDrvHeadLba27_24,(KAtaDrvHeadLbaOn|lba27_24),KAtaSelectDriveHeadRdWr8);
+ }
+
+void DPcCardMediaDriverAta::SetChsSectorAddress(TUint aSector)
+//
+// Setup the sector address ATA registers (CHS mode)
+//
+ {
+
+ TUint cylinder=0,head=0,sector=1;
+ if (iDriveInfo.iSectorsPerCylinder>0&&iDriveInfo.iSectorsPerTrack>0)
+ {
+ cylinder=aSector/iDriveInfo.iSectorsPerCylinder;
+ TUint remainder=aSector%iDriveInfo.iSectorsPerCylinder;
+ head=remainder/iDriveInfo.iSectorsPerTrack;
+ sector=(remainder%iDriveInfo.iSectorsPerTrack)+1;
+ }
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:SetChsSectorAddress (C: %xH H: %xH S: %xH)",cylinder,head,sector));
+ SetAtaRegister8((TUint8)sector,KAtaSectorNoRdWr8);
+ SetAtaRegister8((TUint8)cylinder,KAtaCylinderLowRdWr8);
+ SetAtaRegister8((TUint8)(cylinder>>8),KAtaCylinderHighRdWr8);
+ ModifyAtaRegister8((KAtaDrvHeadLbaOn|KAtaDrvHeadLba27_24),((TUint8)(head&0x0F)),KAtaSelectDriveHeadRdWr8);
+ }
+
+TInt DPcCardMediaDriverAta::IssueAtaCommand(TUint8 aCmd,TUint aFirstSector,TInt aSectorCount)
+//
+// Issue an ATA command (Drive 0 only for now).
+//
+ {
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:IssueAtaCommand(C:%x, FS:%x, SC:%x)",aCmd,aFirstSector,aSectorCount));
+ __KTRACE_OPT(KFAIL,Kern::Printf("A%02x,%d",aCmd,aSectorCount));
+ if (!WaitForNotBusy())
+ return(KErrTimedOut);
+ if (!DriveReadyForCommand(0))
+ return KErrTimedOut;
+
+ if (aSectorCount==KMaxSectorsPerCmd)
+ aSectorCount=0;
+ SetAtaRegister8((TUint8)aSectorCount,KAtaSectorCountRdWr8);
+ if (iDriveInfo.iSupportsLba)
+ SetLbaSectorAddress(aFirstSector);
+ else
+ SetChsSectorAddress(aFirstSector);
+ __TRACE_TIMING(0x103);
+ SetAtaRegister8(aCmd,KAtaCommandWr8); // Issue the command
+ Kern::NanoWait(400); // Busy flag not asserted for 400ns
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:IssueAtaCommand"));
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::LoadSectBufferFromDrive(TAny *aBuf)
+//
+// Read a sector from the ATA card
+//
+ {
+
+ if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusDrq))
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf(">Ata:LoadSectBufferFromDrive-Bad drq(%xH)",AtaRegister8(KAtaStatusRd8)));
+ return KErrBadDrqOnRead;
+ }
+
+ if (__IS_COMMON_MEM(iMemoryType))
+ iDriveChunk.Read(KAtaDataRdWrWinBase16,aBuf,KAtaSectorSize); // Use 1K window
+ else if (iMemoryType==EPccdIo16Mem)
+ iDriveChunk.ReadHWordMultiple(KAtaDataRdWr16,aBuf,(KAtaSectorSize>>1));
+ else
+ iDriveChunk.ReadByteMultiple(KAtaDataRdWr8,aBuf,KAtaSectorSize); // Must be EPccdIo8Mem
+
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::TransferSectBufferFromDrive(TAny *aBuf)
+//
+// Read a sector from the ATA card
+//
+ {
+
+ if (!WaitForNotBusy())
+ return(KErrTimedOut);
+ return(LoadSectBufferFromDrive(aBuf));
+ }
+
+TInt DPcCardMediaDriverAta::EmptySectBufferToDrive(TUint8 *aBuf)
+//
+// Write a sector to the ATA card.
+//
+ {
+
+ if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusDrq))
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf(">Ata:EmptySectBufferToDrive-Bad drq(%xH)",AtaRegister8(KAtaStatusRd8)));
+ return KErrBadDrqOnWrite;
+ }
+
+ if (__IS_COMMON_MEM(iMemoryType))
+ iDriveChunk.Write(KAtaDataRdWrWinBase16,aBuf,KAtaSectorSize); // Use 1K window
+ else if (iMemoryType==EPccdIo16Mem)
+ iDriveChunk.WriteHWordMultiple(KAtaDataRdWr16,aBuf,(KAtaSectorSize>>1));
+ else
+ iDriveChunk.WriteByteMultiple(KAtaDataRdWr8,aBuf,KAtaSectorSize); // Must be EPccdIo8Mem
+
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::FinishCommand()
+//
+// Called each time a command has been issued to check if an error occured.
+//
+ {
+
+ if (!WaitForNotBusy())
+ return(KErrTimedOut);
+ return(CheckForError());
+ }
+
+TInt DPcCardMediaDriverAta::CheckForError()
+//
+// Called each time a command has been issued to check if an error occured.
+//
+ {
+
+ TUint8 status=AtaRegister8(KAtaStatusRd8);
+ if (status&KAtaStatusDrq)
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:CheckForError-DRQ fail"));
+ return KErrBadDrq;
+ }
+ if (status&KAtaStatusDwf)
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:CheckForError-DWF fail"));
+ return(KErrWrite);
+ }
+ if (status&KAtaStatusErr)
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:CheckForError-ERR fail"));
+ return KErrAta;
+ }
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::ProcessError(TInt anError)
+//
+// An error has occured - lets get more information
+//
+ {
+
+ if (anError==KErrAta&&AtaRegister8(KAtaStatusRd8)&KAtaStatusErr)
+ {
+ TUint8 basic=AtaRegister8(KAtaErrorRd8);
+#if (defined(__EPOC32__) && (defined(_DEBUG) || defined(SHOW_CARD_ERRORS)))
+ TUint8 extended=0xFF; // invalid
+ SetAtaRegister8(KAtaCmdRequestSense,KAtaCommandWr8); // Issue command - request sense
+ Kern::NanoWait(400); // Busy flag not asserted for 400ns
+ WaitForNotBusy();
+ if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusErr))
+ extended=AtaRegister8(KAtaErrorRd8);
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:ProcessError-Basic:%xH Ext:%xH)",basic,extended));
+#endif
+ if (basic&KAtaErrorUnc)
+ return(KErrDied);
+ else if (basic&(KAtaErrorBbk|KAtaErrorIdnf))
+ return(KErrCorrupt);
+ else if (basic&KAtaErrorAbort)
+ return(KErrCancel);
+ else
+ return(KErrUnknown);
+ }
+ else
+ return(anError);
+ }
+
+TInt DPcCardMediaDriverAta::EmptySectBufferToTrg(TUint8 *aSrc,TUint aTrgOffset,TInt aLen)
+//
+// Empty data from sector buffer (at specified offset within buffer) into
+// destination descriptor.
+//
+ {
+
+ TPtrC8 buf(aSrc,aLen);
+ return iCurrentReq->WriteRemote(&buf,aTrgOffset);
+ }
+
+TInt DPcCardMediaDriverAta::LoadSectBufferFromSrc(TInt aLen, TUint8* aBuf)
+//
+// Load data from source descriptor into sector buffer
+// Always called within exec. function.
+//
+ {
+
+ TPtr8 buf(aBuf,aLen);
+ TInt r=iCurrentReq->ReadRemote(&buf,iCmdInOffset);
+ return r;
+ }
+
+TInt DPcCardMediaDriverAta::ReadSectorsCommand(TUint aFirstSector,TUint aBufOffset,TInt aLen)
+//
+// Start off a read of multiple sectors from the drive (command completed under interrupt/dfc).
+//
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:ReadSectors F:%x Off:%x L:%x",aFirstSector,aBufOffset,aLen));
+
+ __ASSERT_DEBUG(aBufOffset<(TUint)KAtaSectorSize,Kern::PanicCurrentThread(_L("ReadSectorsCommand"),0));
+ __ASSERT_DEBUG(aLen>0,Kern::PanicCurrentThread(_L("ReadSectorsCommand"),0));
+
+ // Sector count - allow for not starting on sector boundary by adding buffer offset. Allow for
+ // not ending on sector boundary by adding sectorsize-1. Then divide by sector size.
+ TInt tferSectorCount=(aLen+aBufOffset+KAtaSectorSizeMinusOne)>>KAtaSectorShift;
+ iNextSector+=tferSectorCount;
+ __ASSERT_DEBUG(tferSectorCount<=KMaxSectorsPerRead,Kern::PanicCurrentThread(_L("ReadSectorsCommand"),0));
+
+ if (!iSocket->CardIsReady())
+ return(KErrNotReady);
+ AtaRegister8(KAtaStatusRd8); // Clear any pending interrupt
+ iSocket->InterruptEnable(EPccdIntIReq,0); // Enable card interrupt
+ TInt err=IssueAtaCommand(KAtaCmdReadSectors,aFirstSector,tferSectorCount);
+ if (err!=KErrNone)
+ {
+ iSocket->InterruptDisable(EPccdIntIReq); // Disable card interrupt
+ iCardIreqDfc.Cancel();
+ return err;
+ }
+ iCommandError=KErrNone;
+ iNotBusyTickCount=KBusyTimeOut;
+ iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::InitiateWriteCommand(TUint aFirstSector,TInt aSectorCount,TUint8 *aSectBuffer)
+//
+// Start off an asynchronous write to the card. If successful, it leaves with a
+// timeout(ms timer) queued and card interrupts enabled.
+//
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:InitWrCmd F:%x C:%x",aFirstSector,aSectorCount));
+
+ __ASSERT_DEBUG((aSectorCount>0 && aSectorCount<=KMaxSectorsPerWrite),Kern::PanicCurrentThread(_L("InitiateWriteCommand"),0));
+
+ TInt err=IssueAtaCommand(KAtaCmdWriteSectors,aFirstSector,aSectorCount);
+ if (err!=KErrNone)
+ return(err);
+ if (!iSocket->CardIsReady())
+ return(KErrNotReady);
+ if (!WaitForNotBusy())
+ return(ProcessError(KErrTimedOut));
+ AtaRegister8(KAtaStatusRd8); // Clear any pending interrupt
+ iSocket->InterruptEnable(EPccdIntIReq,0); // Enable card interrupt
+ err=EmptySectBufferToDrive(aSectBuffer);
+ if (err!=KErrNone)
+ {
+ iSocket->InterruptDisable(EPccdIntIReq); // Disable card interrupt
+ iCardIreqDfc.Cancel();
+ return(ProcessError(err));
+ }
+ iCommandError=KErrNone;
+ iNotBusyTickCount=KBusyTimeOut;
+ iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
+ iNextSector+=aSectorCount;
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::SectorBoundaryReadCheck(TUint aStartSector,TUint aStartSectOffset,Int64 anEndPos)
+//
+// Check for write request which doesn't lie entirely on a sector boundary and perform
+// the appropriate sectors reads prior to writing if necessary
+//
+ {
+
+ TInt err;
+ TUint endSectOffset=((TUint)anEndPos&(~KAtaSectorMask));
+ anEndPos-=1;
+ anEndPos>>=KAtaSectorShift;
+ TUint endSector=(TUint)anEndPos; // Sector number can't exceed 32bits
+ TInt sectors=(endSector-aStartSector)+1;
+ iLastSectorBufUsed=EFalse;
+
+ if (aStartSectOffset||endSectOffset)
+ {
+ // If it requires a read of two consecutive sectors then read them in one go
+ if (aStartSectOffset && endSectOffset && sectors==2)
+ return(SectorRead(aStartSector,&iSectorBuf[0],2,KAtaCmdReadSectors));
+ else
+ {
+ // If write starts off a sector boundary or is a single sector write ending
+ // off a sector boundary then read first sector
+ if (aStartSectOffset || (endSectOffset && sectors==1))
+ {
+ if ((err=SectorRead(aStartSector,&iSectorBuf[0]))!=KErrNone)
+ return(err);
+ }
+ // If write doesn't end on a sector boundary then read the last sector
+ if (endSectOffset && sectors>1)
+ {
+ TUint8* p=iSectorBuf;
+ if (sectors<=KMaxSectorsPerWrite)
+ p+=(sectors-1)<<KAtaSectorShift;
+ else
+ {
+ p=iLastSectorBuf;
+ iLastSectorBufUsed=ETrue;
+ }
+ return(SectorRead(endSector,p));
+ }
+ }
+ }
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::SectorRead(TUint aFirstSector,TUint8 *aBuf,TInt aSectorCount,TUint8 aCmd)
+//
+// Read either 1 or 2 sectors into the sector buffer (synchronously)
+//
+ {
+
+ TInt err;
+ if ( (err=IssueAtaCommand(aCmd,aFirstSector,aSectorCount))==KErrNone)
+ {
+ if (
+ (err=TransferSectBufferFromDrive(aBuf))!=KErrNone||
+ (aSectorCount>1&&(err=TransferSectBufferFromDrive((TAny*)(aBuf+KAtaSectorSize)))!=KErrNone)||
+ (err=FinishCommand())!=KErrNone
+ )
+ err=ProcessError(err);
+ }
+ if (!iSocket->CardIsReady())
+ err=KErrNotReady; // If media change - return not ready rather than anything else.
+ return(err);
+ }
+
+void DPcCardMediaDriverAta::DumpIdentifyDriveInfo()
+//
+// Debug option to display the drive indentification info.
+//
+ {
+#ifdef _DEBUG
+ if (KDebugNum(KPBUSDRV))
+ {
+ for (TInt i=0;i<128;i+=8)
+ {
+ Kern::Printf("%02x%02x %02x%02x %02x%02x %02x%02x",iSectorBuf[i],iSectorBuf[i+1],iSectorBuf[i+2],iSectorBuf[i+3],iSectorBuf[i+4],\
+ iSectorBuf[i+5],iSectorBuf[i+6],iSectorBuf[i+7]);
+ }
+ }
+#endif
+ }
+
+TInt DPcCardMediaDriverAta::IdentifyDrive()
+//
+// Get drive charateristics
+//
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:IdentifyDrive"));
+
+ TInt err;
+ if ((err=SectorRead(0,&iSectorBuf[0],1,KAtaCmdIdentifyDrive))!=KErrNone)
+ return(err);
+
+ DumpIdentifyDriveInfo();
+ TBool lba=EFalse;
+ Int64 s=0;
+ if (*(TUint16*)(&iSectorBuf[KAtaIdCapabilities])&KAtaIdCapLbaSupported)
+ {
+ // Card indicates it supports LBA
+ // Media size (in sectors) - 2 x halfwords @ KAtaIdTotalSectorsInLba.
+ iDriveInfo.iTotalSectorsInLba=*(TInt*)(&iSectorBuf[KAtaIdTotalSectorsInLba]);
+ s=iDriveInfo.iTotalSectorsInLba;
+ s<<=KAtaSectorShift;
+ if (s>0)
+ lba=ETrue; // Epson PC card reports LBA supported but LBA size in bytes becomes zero
+ }
+
+ iDriveInfo.iSupportsLba = lba;
+ if (!lba)
+ {
+ // LBA not supported
+ if (*(TUint16*)(&iSectorBuf[KAtaIdTranslationParams])&KAtaIdTrParamsValid)
+ {
+ // Current translation parameters are valid
+ iDriveInfo.iCylinders=*(TUint16*)(&iSectorBuf[KAtaIdCurrentCylinders]);
+ iDriveInfo.iHeads=*(TUint16*)(&iSectorBuf[KAtaIdCurrentHeads]);
+ iDriveInfo.iSectorsPerTrack=*(TUint16*)(&iSectorBuf[KAtaIdCurrentSectorsPerTrack]);
+ }
+ else
+ {
+ // Use defaults
+ iDriveInfo.iCylinders=*(TUint16*)(&iSectorBuf[KAtaIdDefaultCylinders]);
+ iDriveInfo.iHeads=*(TUint16*)(&iSectorBuf[KAtaIdDefaultHeads]);
+ iDriveInfo.iSectorsPerTrack=*(TUint16*)(&iSectorBuf[KAtaIdDefaultSectorsPerTrack]);
+ }
+ iDriveInfo.iSectorsPerCylinder=(iDriveInfo.iHeads*iDriveInfo.iSectorsPerTrack);
+ s=iDriveInfo.iCylinders;
+ s*=iDriveInfo.iSectorsPerCylinder;
+ s<<=KAtaSectorShift;
+ if (iDriveInfo.iSectorsPerCylinder<=0||iDriveInfo.iSectorsPerTrack<=0)
+ return(KErrCorrupt);
+ }
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("LBA : %xH",iDriveInfo.iSupportsLba));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Cylinders: %xH",iDriveInfo.iCylinders));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Heads : %xH",iDriveInfo.iHeads));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Sectors : %xH",iDriveInfo.iSectorsPerTrack));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:IdentifyDrive (TS:%lxH)",s));
+ SetTotalSizeInBytes(s);
+ return(KErrNone);
+ }
+
+TInt DPcCardMediaDriverAta::ConfigAutoPowerDown()
+//
+// Set auto power down period to something sensible
+//
+ {
+
+ TInt err;
+ if ( (err=IssueAtaCommand(KAtaCmdIdle,0,200))==KErrNone) // 200x5mS=1S (aFirstSector doesn't matter).
+ {
+ if ((err=FinishCommand())!=KErrNone)
+ err=ProcessError(err);
+ }
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:ConfigAutoPowerDown-%d",err));
+ return(err);
+ }
+
+TInt DPcCardMediaDriverAta::DoOpen()
+//
+// Open the media driver.
+//
+ {
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:DoOpen"));
+ iCardIreqDfc.SetDfcQ(&iSocket->iDfcQ);
+ iTimerDfc.SetDfcQ(&iSocket->iDfcQ);
+
+ // Card ought to be ready but check we haven't had media change (this causes creation of card functions).
+ TInt err=iSocket->CardIsReadyAndVerified(); // this may also fail with OOM or corrupt
+ if (err!=KErrNone)
+ return err;
+
+ // Perform CIS validation - get back info. on card functions present.
+ TPccdType pt;
+ if (iSocket->VerifyCard(pt)!=KErrNone)
+ return(KErrUnknown);
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Check for ATA function, FuncCount=%d",pt.iFuncCount));
+
+ // Check for ATA fixed disk function.
+ TCisReader cisRd;
+ TInt f;
+ TBool isAta=EFalse;
+ for (f=0;f<pt.iFuncCount;f++)
+ {
+ if (pt.iFuncType[f]==EFixedDiskCard)
+ {
+ // Fixed disk function - check its an ATA.
+ TBuf8<KLargeTplBufSize> tpl;
+ cisRd.SelectCis(iSocket->iSocketNumber,f);
+ // Must start just after FuncId tuple.
+ if (cisRd.FindReadTuple(KCisTplFuncId,tpl)!=KErrNone)
+ continue;
+ while (cisRd.FindReadTuple(KCisTplFunce,tpl)==KErrNone)
+ {
+ if (tpl[2]==0x01 && tpl[3]==0x01) // Interface type - ATA
+ isAta=ETrue;
+ }
+ if (isAta)
+ break;
+ }
+ }
+ if (!isAta)
+ return(KErrUnknown);
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Is ATA"));
+
+ // Determine best card configuration
+ cisRd.Restart();
+ TPcCardConfig cf;
+ TInt opt=KInvalidConfOpt;
+ while(cisRd.FindReadConfig(cf)==KErrNone)
+ {
+ if (
+ cf.IsMachineCompatible(iSocket->iSocketNumber,KPccdCompatNoVccCheck) && // Hitachi card has no 3.3V config entry
+#if defined (SELECT_MEMORY_CONFIG)
+ (cf.iValidChunks==1 && __IS_COMMON_MEM(cf.iChnk[0].iMemType) && cf.iChnk[0].iMemLen==0x800)
+#elif defined (SELECT_PRIMARY_IO_CONFIG)
+ (cf.iValidChunks==2 && __IS_IO_MEM(cf.iChnk[0].iMemType) && __IS_IO_MEM(cf.iChnk[1].iMemType) && cf.iChnk[0].iMemBaseAddr==0x1F0)
+#else
+ // Choose 16 byte - contiguous i/o option
+ (cf.iValidChunks==1 && __IS_IO_MEM(cf.iChnk[0].iMemType) && cf.iChnk[0].iMemLen==0x10)
+#endif
+ )
+ {
+ opt=cf.iConfigOption;
+ break;
+ }
+ }
+ if (opt==KInvalidConfOpt)
+ return(KErrNotSupported);
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-ConfigOpt(%d)",opt));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Pulsed Ints-%d",(cf.iInterruptInfo&KPccdIntPulse)));
+
+ // Now configure the card. First configure it to memory mode.
+ cf.iConfigOption=0;
+ err=iSocket->RequestConfig(f,this,cf,0);
+ if (err!=KErrNone)
+ return(err);
+ if (cf.iRegPresent&KConfigAndStatusRegM)
+ iSocket->WriteConfigReg(f,KConfigAndStatusReg,0);
+ if (cf.iRegPresent&KSocketAndCopyRegM)
+ iSocket->WriteConfigReg(f,KSocketAndCopyReg,0); // No twin cards
+ iSocket->ReleaseConfig(f,this);
+
+ cf.iConfigOption=(cf.iInterruptInfo&KPccdIntPulse)?opt:(opt|KConfOptLevIReqM);
+// cf.iConfigOption=(opt|KConfOptLevIReqM); // Force level mode interrupts
+#if defined (FORCE_8BIT_ACCESSES)
+#if defined (SELECT_MEMORY_CONFIG)
+ cf.iChnk[0].iMemType=EPccdCommon8Mem; // Force it to 8bit Common.
+#else
+ cf.iChnk[0].iMemType=EPccdIo8Mem; // Force it to 8bit I/O.
+#endif
+#endif
+
+ if ((err=iSocket->RequestConfig(f,this,cf,0))!=KErrNone)
+ return(err);
+
+ // Read back the config option register to verify it has been setup
+ TUint8 v;
+ if ((err=iSocket->ReadConfigReg(f,0,v))!=KErrNone||v!=(TUint8)cf.iConfigOption)
+ return KErrBadPccdConfig;
+ iCardFuncNum=f;
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Configured(%1xH) OK",v));
+
+ TUint flag=(cf.iActiveSignals&KSigWaitRequired)?KPccdRequestWait:0;
+ err=iDriveChunk.Create(iSocket,cf.iChnk[0],cf.iAccessSpeed,flag);
+ if (err!=KErrNone)
+ return(err);
+ iDriveChunk.SetupChunkHw();
+ iMemoryType=cf.iChnk[0].iMemType;
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Requested Mem OK"));
+
+ iSocket->InterruptDisable(EPccdIntIReq);
+ iCardIntCallBack.iSocket=iSocket;
+ iCardIntCallBack.Add();
+ SetAtaRegister8(0,KAtaDeviceCtlWr8); // Enable interrupts
+
+ SetCurrentConsumption(KIdleCurrentInMilliAmps);
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:DoOpen-OK"));
+ return(KErrNone);
+ }
+
+TBool DPcCardMediaDriverAta::CardPoweredDown()
+//
+// Returns EFalse as long as card hasn't received power down (emergency or normal).
+//
+ {
+
+ // Emergency power down may result in card being powered down before PC Card
+ // Controller status is updated - check for EPD as well as PC Card Contoller.
+ return(!Kern::PowerGood() || !iSocket->CardIsReady());
+ }
+
+void DPcCardMediaDriverAta::IncrementSectBufPtr()
+//
+//
+//
+ {
+
+ iSectBufPtr+=KAtaSectorSize;
+ if ((iSectBufPtr-&iSectorBuf[0])>=KSectBufSizeInBytes)
+ iSectBufPtr=&iSectorBuf[0];
+ }
+
+TInt DPcCardMediaDriverAta::Request(TLocDrvRequest& m)
+ {
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Ata:Req %08x id %d",&m,m.Id()));
+ TInt r=KErrNotSupported;
+ TInt id=m.Id();
+ if (id==DLocalDrive::ECaps)
+ {
+ TLocalDriveCapsV6& c=*(TLocalDriveCapsV6*)m.RemoteDes();
+ r=Caps(c);
+ c.iSize=m.Drive()->iPartitionLen;
+ c.iPartitionType=m.Drive()->iPartitionType;
+ return r;
+ }
+ if (iCurrentReq)
+ {
+ // a request is already in progress, so hold on to this one
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Ata:Req %08x ret 1",&m));
+ return KMediaDriverDeferRequest;
+ }
+ iCurrentReq=&m;
+ switch (id)
+ {
+ case DLocalDrive::ERead:
+ r=DoRead();
+ break;
+ case DLocalDrive::EWrite:
+ r=DoWrite();
+ break;
+ case DLocalDrive::EFormat:
+ r=DoFormat();
+ break;
+ case DLocalDrive::EEnlarge:
+ case DLocalDrive::EReduce:
+ default:
+ r=KErrNotSupported;
+ break;
+ }
+ __KTRACE_OPT(KLOCDRV,Kern::Printf("Ata:Req %08x cmp %d",&m,r));
+ if (r!=KErrNone)
+ iCurrentReq=NULL;
+ return r;
+ }
+
+void DPcCardMediaDriverAta::NotifyPowerDown()
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyPowerDown"));
+ Complete(KErrNotReady);
+ Reset();
+ }
+
+void DPcCardMediaDriverAta::NotifyEmergencyPowerDown()
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyEmergencyPowerDown"));
+ TInt r=KErrNotReady;
+ if (iCritical)
+ r=KErrAbort;
+ EndInCritical();
+ Complete(r);
+ Reset();
+ }
+
+void DPcCardMediaDriverAta::TimerDfcFunction(TAny* aPtr)
+//
+// DFC callback from not-busy timer
+//
+ {
+ DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aPtr;
+ __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf(">Ata:TimerDfcFunction TC:%d",md.iNotBusyTickCount));
+ TInt r=1;
+ if (!md.CardPoweredDown())
+ {
+ md.iDriveChunk.SetupChunkHw();
+ TUint8 status=md.AtaRegister8(KAtaStatusRd8); // Clears interrupt
+ if (!(status&KAtaStatusBusy))
+ {
+ // It is not-busy so process it as we would from an interrupt
+ __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("Card not busy"));
+ r=KErrNone;
+#ifdef COUNT_TIMEOUTS
+ ++md.iTimeouts;
+ md.iNewTimeOut=ETrue;
+ if (md.iIndex<=6)
+ {
+ md.iInfo[md.iIndex++]=md.iCmdInOffset;
+ md.iInfo[md.iIndex++]=md.iCmdEndOffset;
+ }
+#endif
+ }
+ else
+ {
+ // still busy so count tick and restart timer
+ if (--md.iNotBusyTickCount==0)
+ {
+ __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("Timed out"));
+ r=KErrTimedOut; // time out the request
+ }
+ else
+ {
+ __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("Restart timer"));
+ md.iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
+ }
+ }
+ }
+ else
+ r=KErrNotReady;
+ __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("<Ata:TimerDfcFunction r=%d",r));
+ if (r<=0)
+ {
+ // card is not-busy, powered down or timed out
+ md.iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
+ md.iCardIreqDfc.Cancel(); // so we don't run this twice
+ md.iCommandError=r;
+ CardIreqDfcFunction(&md);
+ }
+ }
+
+void DPcCardMediaDriverAta::CardIntCallBack(TAny* aMediaDriver, TInt)
+//
+// Card Interrupt callback
+//
+ {
+ __TRACE_TIMING(0x104);
+ DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aMediaDriver;
+ md.iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
+ md.iCardIreqDfc.Add();
+#ifdef COUNT_TIMEOUTS
+ ++md.iInts;
+#endif
+ }
+
+void DPcCardMediaDriverAta::CardIreqDfcFunction(TAny* aPtr)
+ {
+
+ DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aPtr;
+ TInt err=md.iCommandError;
+ TBool queueDfc=md.CardPoweredDown();
+ if (queueDfc)
+ err=KErrNotReady;
+ else if (err!=KErrNone)
+ queueDfc=ETrue; // timed out
+ else
+ {
+ md.iDriveChunk.SetupChunkHw();
+ TUint8 status=md.AtaRegister8(KAtaStatusRd8); // Clears interrupt
+ if (!(status&KAtaStatusBusy))
+ queueDfc=md.DoCardNotBusy(err);
+ }
+ TBool cmd_done=EFalse;
+ if (queueDfc)
+ {
+ md.iCommandError=err;
+ cmd_done=md.CmdDfc();
+ }
+ if (!queueDfc)
+ {
+ // command still executing so reenable interrupts
+ md.iSocket->InterruptEnable(EPccdIntIReq,0);
+ }
+ if (!cmd_done)
+ {
+ // quickly check if card is already not busy
+ // this handles cards which return data very quickly
+ md.iDriveChunk.SetupChunkHw();
+ TUint8 status=md.AtaRegister8(KAtaStatusRd8); // Clears interrupt
+ if (!(status&KAtaStatusBusy))
+ {
+ md.iSocket->InterruptDisable(EPccdIntIReq);
+ md.iCardIreqDfc.Enque();
+#ifdef COUNT_TIMEOUTS
+ ++md.iImmediateNotBusy;
+#endif
+ }
+ else
+ {
+ md.iBusyTimeout.Cancel();
+ md.iTimerDfc.Cancel();
+ md.iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
+ }
+ }
+ }
+
+TBool DPcCardMediaDriverAta::DoCardNotBusy(TInt &anErr)
+//
+// Card not busy interrupt - return ETrue when need to queue dfc
+//
+ {
+
+ anErr=KErrNone;
+ if (iCardStatus==ECardWrite || iCardStatus==ECardFormat)
+ {
+ // For write/format commands we only update the out-pointer when the card becomes
+ // not-busy following the point we transfered the block of data to the card.
+ iCmdOutOffset+=(KAtaSectorSize-iSectBufOffset);
+ iSectBufOffset=0;
+ if (iCmdOutOffset<iCmdEndOffset)
+ {
+ TUint8* pB=iSectBufPtr;
+ if (iLastSectorBufUsed && iCmdLength-iCmdOutOffset<=(TUint)KAtaSectorSize)
+ pB=iLastSectorBuf; // use different buffer for last sector of unaligned write
+ anErr=EmptySectBufferToDrive(pB);
+ if (anErr!=KErrNone)
+ return(ETrue);
+ if (iCardStatus==ECardWrite)
+ iSectBufPtr+=KAtaSectorSize;
+ }
+ else
+ {
+ anErr=CheckForError();
+ return(ETrue);
+ }
+ }
+ if (iCardStatus==ECardRead)
+ {
+ // For read commands we only update the in-pointer here. The out-pointer is
+ // updated by the DFC as data is written to target thread
+
+ // Before we read the data from the card, perform the in-pointer incremeting now.
+ // If we are about to queue a DFC then let the DFC read from the card. Otherwise,
+ // reading from the card may result in the next sector of data being available
+ // before we're ready for it.
+
+ // If first interrupt after command initiated then allow for sector buffer offset
+ TInt toEOBuf=(iCmdInOffset==0)?(KAtaSectorSize-iSectBufOffset):KAtaSectorSize;
+ TInt remaining=(TInt)(iCmdEndOffset-iCmdInOffset);
+ iCmdInOffset+=Min(remaining,toEOBuf);
+ if ((iSectBufPtr-&iSectorBuf[0])>=KSectBufSizeInBytesMinusOneSector || iCmdInOffset>=iCmdEndOffset)
+ return(ETrue); // Queue a DFC
+ else
+ {
+ anErr=LoadSectBufferFromDrive(iSectBufPtr);
+ if (anErr!=KErrNone)
+ return(ETrue);
+ IncrementSectBufPtr();
+ }
+ }
+ return(EFalse);
+ }
+
+void DPcCardMediaDriverAta::SyncBusyTimerCallBack(TAny* aBusyFlag)
+//
+// Wait for not busy timeout callback
+//
+ {
+
+ *(TBool*)aBusyFlag=ETrue;
+ }
+
+void DPcCardMediaDriverAta::AsyncBusyTimerCallBack(TAny* aMediaDriver)
+//
+// Wait for not busy timeout callback
+//
+ {
+
+ __KTRACE_OPT(KFAIL,Kern::Printf("!,"));
+ DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aMediaDriver;
+ md.iTimerDfc.Add();
+ }
+
+TBool DPcCardMediaDriverAta::CmdDfc()
+//
+// Dfc to complete an asynchronous command
+//
+ {
+
+ TInt err;
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:CmdDfc status %d in %x out %x len %x",iCardStatus,iCmdInOffset,iCmdOutOffset,iCmdLength));
+
+ iBusyTimeout.Cancel();
+ iTimerDfc.Cancel();
+ if (DoCmdDfc(err)) // this requeues timer and reenables interrupts if command still executing
+ {
+ // Command has been completed for one reason or other
+ EndInCritical();
+ if (err!=KErrNone)
+ err=ProcessError(err);
+
+ // If emergency power down on write/format - return abort rather than anything else.
+ if (!Kern::PowerGood() && iCardStatus!=ECardRead)
+ err=KErrAbort;
+ // If media change - return not ready rather than anything else.
+ else if (!iSocket->CardIsReady())
+ err=KErrNotReady;
+ __KTRACE_OPT(KFAIL,Kern::Printf("a%d",err));
+ if (err==KErrNone)
+ {
+ // may need to issue another command here
+ if (iCmdOutOffset<iCmdLength)
+ {
+ if (iCardStatus==ECardRead)
+ {
+ __KTRACE_OPT(KFAIL,Kern::Printf("+R"));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NewReadCmd"));
+ iSectBufOffset=0;
+#ifdef COUNT_TIMEOUTS
+ ++iChainedReads;
+#endif
+ err=InitiateAsyncRead();
+ if (err==KErrNone)
+ return ETrue;
+ }
+ else
+ {
+ __KTRACE_OPT(KFAIL,Kern::Printf("+W"));
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NewWriteCmd"));
+#ifdef COUNT_TIMEOUTS
+ ++iChainedWrites;
+#endif
+ err=InitiateAsyncWrite();
+ if (err==KErrNone)
+ return ETrue;
+ }
+ }
+ }
+ iCardStatus=ECardIdle; // Command now complete
+ SetCurrentConsumption(KIdleCurrentInMilliAmps);
+
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ if (err!=KErrNone&&err!=KErrTooBig)
+ {
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<DFC(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
+ iDbgLastError=err;
+ }
+#endif
+ __TRACE_TIMING(0x109);
+ Complete(err);
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+TBool DPcCardMediaDriverAta::DoCmdDfc(TInt &anErr)
+//
+// Return ETrue when complete
+//
+ {
+
+ if (CardPoweredDown())
+ {
+ anErr=KErrNotReady;
+ return(ETrue);
+ }
+ anErr=iCommandError;
+ if (iCommandError!=KErrNone)
+ return(ETrue);
+
+ if (iCardStatus==ECardWrite||iCardStatus==ECardFormat)
+ return(ETrue);
+ else
+ {
+ // Read command, we postponed loading the last sector
+ __TRACE_TIMING(0x105);
+ if ((anErr=LoadSectBufferFromDrive(iSectBufPtr))!=KErrNone)
+ return(ETrue);
+
+ // In case command still executing, queue another timeout and re-enable interrupts
+ iSocket->InterruptEnable(EPccdIntIReq,0);
+ iNotBusyTickCount=KBusyTimeOut;
+ iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
+
+ __TRACE_TIMING(0x106);
+ IncrementSectBufPtr();
+ if ((anErr=EmptySectBufferToTrg(&iSectorBuf[0]+iSectBufOffset,iCmdOutOffset,iCmdInOffset-iCmdOutOffset))!=KErrNone)
+ {
+ iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
+ iBusyTimeout.Cancel();
+ iTimerDfc.Cancel();
+ iCardIreqDfc.Cancel();
+ return(ETrue);
+ }
+ __TRACE_TIMING(0x107);
+ iSectBufOffset=0; // From now on we always start on sector boundary
+ iCmdOutOffset=iCmdInOffset;
+ if (iCmdOutOffset<iCmdEndOffset)
+ return(EFalse);
+ iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
+ iBusyTimeout.Cancel();
+ iTimerDfc.Cancel();
+ iCardIreqDfc.Cancel();
+ anErr=FinishCommand(); // This functions involves polling for not busy
+ return(ETrue);
+ }
+ __TRACE_TIMING(0x108);
+ }
+
+DPhysicalDeviceMediaAta::DPhysicalDeviceMediaAta()
+//
+// Constructor
+//
+ {
+ iUnitsMask=0x1;
+ iVersion=TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
+ }
+
+TInt DPhysicalDeviceMediaAta::Install()
+//
+// Install the PC Card ATA Media PDD.
+//
+ {
+ return SetName(&KPddName);
+ }
+
+void DPhysicalDeviceMediaAta::GetCaps(TDes8 &/* aDes */) const
+//
+// Return the media drivers capabilities.
+//
+ {
+ }
+
+TInt DPhysicalDeviceMediaAta::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /*anInfo*/, const TVersion& aVer)
+//
+// Create a PC Card ATA media driver.
+//
+ {
+ if (!Kern::QueryVersionSupported(iVersion,aVer))
+ return KErrNotSupported;
+ DPcCardMediaDriverAta* pD=new DPcCardMediaDriverAta(aMediaId);
+ aChannel=pD;
+ TInt r=KErrNoMemory;
+ if (pD)
+ r=pD->Open();
+ if (r==KErrNone)
+ pD->OpenMediaDriverComplete(KErrNone);
+ return r;
+ }
+
+TInt DPhysicalDeviceMediaAta::Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer)
+ {
+ if (!Kern::QueryVersionSupported(iVersion,aVer))
+ return KErrNotSupported;
+ if (aDeviceType!=MEDIA_DEVICE_PCCARD)
+ return KErrNotSupported;
+ return KErrNone;
+ }
+
+TInt DPhysicalDeviceMediaAta::Info(TInt aFunction, TAny*)
+//
+// Return the priority of this media driver
+//
+ {
+ if (aFunction==EPriority)
+ return KAtaDriverPriority;
+ return KErrNotSupported;
+ }
+
+DPcCardMediaDriverAta::DPcCardMediaDriverAta(TInt aMediaId)
+//
+// Constructor.
+//
+ : DMediaDriver(aMediaId),
+ iCardIntCallBack(CardIntCallBack,this,KPccdIntMaskIReq),
+ iBusyTimeout(AsyncBusyTimerCallBack,this),
+ iCardIreqDfc(CardIreqDfcFunction,this,2),
+ iTimerDfc(TimerDfcFunction,this,2)
+ {
+
+ iMemoryType=EPccdIo8Mem;
+// iCommandError=KErrNone;
+// TUint iCmdInOffset=0;
+// TUint iCmdOutOffset=0;
+// iCmdEndOffset=0;
+// iSectBufPtr=NULL;
+// iSectBufOffset=0;
+ iCardStatus=ECardIdle;
+// iHiddenSectors=0;
+ iCardFuncNum=-1;
+ }
+
+TInt DPcCardMediaDriverAta::Open()
+//
+// Open the media driver.
+//
+ {
+
+ // Open the driver and get drive characteristics
+ iSocket=((DPcCardSocket*)((DPBusPrimaryMedia*)iPrimaryMedia)->iSocket);
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:Open on socket %d",iSocket->iSocketNumber));
+ TInt r=DoOpen();
+ if (r==KErrNone)
+ r=IdentifyDrive();
+ if (r!=KErrNone)
+ {
+ DoClose();
+ if (!iSocket->CardIsReady())
+ r=KErrNotReady; // If media change - return not ready rather than anything else.
+ }
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:Open-%d",r));
+ return r;
+ }
+
+TInt DPcCardMediaDriverAta::CheckDevice(TBool aCheckPower)
+//
+// Check the device before initiating a command
+//
+ {
+
+ if (iSocket->CardIsReadyAndVerified()!=KErrNone)
+ return KErrNotReady;
+ if (aCheckPower && Kern::MachinePowerStatus()<ELow)
+ return KErrBadPower;
+ return KErrNone;
+ }
+
+TInt DPcCardMediaDriverAta::DoRead()
+//
+// Read from specified area of media.
+//
+ {
+
+ Int64 aPos=iCurrentReq->Pos();
+ TInt aLength=(TInt)iCurrentReq->Length();
+ TInt err;
+ iCmdOutOffset=0; // Progress monitor - data delivered to target
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ iDbgPos=(TUint)aPos;
+ iDbgLen=aLength;
+#endif
+ err=CheckDevice(EFalse);
+ if (err==KErrNone)
+ {
+ iDriveChunk.SetupChunkHw(); // Enable our h/w chunk
+
+ TUint sectorBufOffset=(TUint)aPos&(~KAtaSectorMask);
+ Int64 firstSector=(aPos>>KAtaSectorShift);
+ iCmdLength=aLength;
+
+ SetCurrentConsumption(KReadCurrentInMilliAmps);
+
+ // Start an asynchronous read
+ iCmdInOffset=0; // Data received from card
+ iNextSector=(TUint)firstSector;
+ iSectBufOffset=sectorBufOffset;
+ err=InitiateAsyncRead();
+ if (err==KErrNone)
+ return KErrNone;
+
+ iCardStatus=ECardIdle;
+ SetCurrentConsumption(KIdleCurrentInMilliAmps);
+ if (!iSocket->CardIsReady())
+ err=KErrNotReady; // If media change - return not ready rather than anything else.
+ }
+
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:Read(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
+ iDbgLastError=err;
+#endif
+ return err;
+ }
+
+TInt DPcCardMediaDriverAta::InitiateAsyncRead()
+ {
+ // Start an asynchronous read
+ TInt cmdLen=Min(TInt(iCmdLength-iCmdInOffset),TInt(KMaxBytesPerRead-iSectBufOffset)); // Leave it on sector boundary if another read required
+ iCmdEndOffset=iCmdInOffset+cmdLen; // Marks point when transfer is complete
+ iSectBufPtr=&iSectorBuf[0];
+ iCardStatus=ECardRead;
+ __TRACE_TIMING(0x102);
+ return ReadSectorsCommand(iNextSector,iSectBufOffset,cmdLen); // Sector number can't exceed 32bits
+ }
+
+TInt DPcCardMediaDriverAta::DoWrite()
+//
+// Write to specified area of media.
+//
+ {
+
+ Int64 aPos=iCurrentReq->Pos();
+ TInt aLength=(TInt)iCurrentReq->Length();
+ TInt err;
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ iDbgPos=(TUint)aPos;
+ iDbgLen=aLength;
+#endif
+ err=CheckDevice(ETrue);
+ if (err==KErrNone)
+ {
+ iDriveChunk.SetupChunkHw(); // Enable our h/w chunk
+ TUint sectorBufOffset=(TUint)aPos&(~KAtaSectorMask);
+ Int64 firstSector=(aPos>>KAtaSectorShift);
+ iCmdLength=aLength;
+
+ // for unaligned writes, first need to read the first and/or last sector
+ err=SectorBoundaryReadCheck((TUint)firstSector,sectorBufOffset,aPos+iCmdLength);
+ if (err==KErrNone) // Sector number can't exceed 32bits
+ {
+ // Time to actually start the write. First alter the current consumption
+ // and save the data required to complete the write (in the ISR)
+ SetCurrentConsumption(KWriteCurrentInMilliAmps);
+ iSectBufOffset=sectorBufOffset;
+ iCmdInOffset=0;
+ iCmdOutOffset=0; // Progress monitor - data delivered to card
+ iNextSector=(TUint)firstSector;
+ iCardStatus=ECardWrite;
+ err=InitiateAsyncWrite();
+ if (err==KErrNone)
+ return KErrNone;
+ SetCurrentConsumption(KIdleCurrentInMilliAmps);
+ }
+ iCardStatus=ECardIdle;
+ if (!Kern::PowerGood())
+ err=KErrAbort; // If emergency power down - return abort rather than anything else.
+ else if (!iSocket->CardIsReady())
+ err=KErrNotReady; // If media change - return not ready rather than anything else.
+ }
+
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:Write(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
+ iDbgLastError=err;
+#endif
+ return err;
+ }
+
+TInt DPcCardMediaDriverAta::InitiateAsyncWrite()
+ {
+ iCmdOutOffset=iCmdInOffset;
+ TInt remain=iCmdLength-iCmdInOffset;
+ TInt cmdLen=Min(remain, KMaxBytesPerWrite-iSectBufOffset);
+ TInt sectCount=(cmdLen+iSectBufOffset+KAtaSectorSize-1)>>KAtaSectorShift;
+ iCmdEndOffset=iCmdOutOffset+cmdLen;
+ iSectBufPtr=iSectorBuf;
+ TUint8* pB=iSectorBuf;
+ TInt r=KErrNone;
+ if (iCardStatus==ECardWrite)
+ {
+ if (iLastSectorBufUsed && cmdLen==remain)
+ {
+ // load data for sectors other than last into sector buffer
+ TInt lengthExcludingLastSector=cmdLen &~ (KAtaSectorSize-1);
+ if (lengthExcludingLastSector==cmdLen)
+ lengthExcludingLastSector-=KAtaSectorSize;
+ if (lengthExcludingLastSector)
+ {
+ r=LoadSectBufferFromSrc(lengthExcludingLastSector,iSectorBuf+iSectBufOffset);
+ if (r!=KErrNone)
+ return r;
+ iCmdInOffset+=lengthExcludingLastSector; // make sure we get right data for last sector
+ }
+ else
+ pB=iLastSectorBuf;
+ // load last sector data into last sector buffer
+ r=LoadSectBufferFromSrc(cmdLen-lengthExcludingLastSector,iLastSectorBuf);
+ if (r!=KErrNone)
+ return r;
+ iCmdInOffset+=(cmdLen-lengthExcludingLastSector);
+ }
+ else
+ {
+ // Load the the data from source in one go
+ r=LoadSectBufferFromSrc(cmdLen,iSectorBuf+iSectBufOffset);
+ if (r!=KErrNone)
+ return r;
+ iCmdInOffset+=cmdLen;
+ }
+ }
+ else
+ iCmdInOffset+=cmdLen; // format command
+ r=InCritical(); // this returns KErrNotReady if we are about to do postponed media change or power down
+ if (r==KErrNone)
+ {
+ r=InitiateWriteCommand(iNextSector,sectCount,pB);
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf("InitWrCmd ret %d",r));
+ if (iCardStatus==ECardWrite)
+ iSectBufPtr+=KAtaSectorSize;
+ }
+ if (r!=KErrNone)
+ {
+ if (!Kern::PowerGood())
+ r=KErrAbort; // If emergency power down - return abort rather than anything else.
+ else if (!iSocket->CardIsReady())
+ r=KErrNotReady; // If media change - return not ready rather than anything else.
+ EndInCritical();
+ }
+ return r;
+ }
+
+TInt DPcCardMediaDriverAta::DoFormat()
+//
+// Format the specified area of the media.
+//
+ {
+
+ Int64 aPos=iCurrentReq->Pos();
+ TInt aLength=(TInt)iCurrentReq->Length();
+ TInt err;
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ iDbgPos=(TUint)aPos;
+ iDbgLen=aLength;
+#endif
+ err=CheckDevice(ETrue);
+ if (err==KErrNone)
+ {
+ iDriveChunk.SetupChunkHw(); // Enable our h/w chunk
+ memset(iSectorBuf,0xff,KAtaSectorSize);
+ Int64 firstSector=(aPos>>KAtaSectorShift);
+ TInt sectCount=(aLength+KAtaSectorSizeMinusOne)>>KAtaSectorShift;
+ iCmdLength=(sectCount<<KAtaSectorShift);
+ sectCount=Min(KMaxSectorsPerFormat,(aLength+KAtaSectorSizeMinusOne)>>KAtaSectorShift);
+ SetCurrentConsumption(KWriteCurrentInMilliAmps);
+
+ iLastSectorBufUsed=EFalse;
+ iCmdInOffset=0;
+ iCmdOutOffset=0; // Progress monitor - data delivered to card
+ iSectBufOffset=0;
+ iSectBufPtr=&iSectorBuf[0];
+ iNextSector=(TUint)firstSector;
+ iCardStatus=ECardFormat;
+ err=InitiateAsyncWrite();
+ if (err==KErrNone)
+ return KErrNone;
+
+ iCardStatus=ECardIdle;
+ SetCurrentConsumption(KIdleCurrentInMilliAmps);
+
+ if (!Kern::PowerGood())
+ err=KErrAbort; // If emergency power down - return abort rather than anything else.
+ else if (!iSocket->CardIsReady())
+ err=KErrNotReady; // If media change - return not ready rather than anything else.
+ }
+
+#if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:Format(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
+ iDbgLastError=err;
+#endif
+ return err;
+ }
+
+void DPcCardMediaDriverAta::Close()
+//
+// Close the media driver - also called on media change
+//
+ {
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:Close"));
+ EndInCritical();
+ Complete(KErrNotReady);
+ DoClose();
+ DMediaDriver::Close();
+ }
+
+void DPcCardMediaDriverAta::DoClose()
+//
+// Close the media driver
+//
+ {
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:DoClose"));
+ iCardIntCallBack.Remove();
+ iDriveChunk.Close();
+ if (iCardFuncNum>=0)
+ {
+ iSocket->ReleaseConfig(iCardFuncNum,this);
+ iCardFuncNum=-1;
+ }
+ Reset();
+ __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:DoClose(%d)",iDbgLastError));
+ }
+
+void DPcCardMediaDriverAta::Reset()
+ {
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:Reset"));
+ iBusyTimeout.Cancel(); // In case its currently queued
+ iCardIreqDfc.Cancel(); // In case its currently queued
+ iTimerDfc.Cancel();
+ iCardStatus=ECardIdle;
+ SetCurrentConsumption(0);
+ }
+
+#ifdef KLOCDRV
+void DebugDump(const TMBRPartitionEntry& a)
+ {
+ Kern::Printf("BootInd =%02x StartHead=%02x StartSect=%02x StartCyl=%02x",
+ a.iX86BootIndicator, a.iStartHead, a.iStartSector, a.iStartCylinder);
+ Kern::Printf("PartType=%02x EndHead =%02x EndSect =%02x EndCyl =%02x",
+ a.iPartitionType, a.iEndHead, a.iEndSector, a.iEndCylinder);
+ Kern::Printf("FirstSect=%08x NumSectors=%08x", a.iFirstSector, a.iNumSectors);
+ }
+
+void DebugDump(const TPartitionInfo& a)
+ {
+ Kern::Printf("PartitionInfo: (C:%d)",a.iPartitionCount);
+ TInt i;
+ for (i=0; i<KMaxPartitionEntries; ++i)
+ {
+ const TPartitionEntry& e=a.iEntry[i];
+ Kern::Printf(" Partition %d: B=%lxH L=%lxH I=%04x T=%04x", i, e.iPartitionBaseAddr,
+ e.iPartitionLen, e.iBootIndicator, e.iPartitionType );
+ }
+ }
+#endif
+
+void SetPartitionEntry(TPartitionEntry* aDest, const TMBRPartitionEntry* aSrc)
+//
+// Set the partition entry details
+//
+ {
+
+ aDest->iPartitionBaseAddr=aSrc->iFirstSector;
+ aDest->iPartitionBaseAddr<<=KAtaSectorShift;
+ aDest->iPartitionLen=aSrc->iNumSectors;
+ aDest->iPartitionLen<<=KAtaSectorShift;
+ aDest->iBootIndicator=aSrc->iX86BootIndicator;
+ aDest->iPartitionType=aSrc->iPartitionType;
+ }
+
+TInt DPcCardMediaDriverAta::PartitionInfo(TPartitionInfo& anInfo)
+//
+// Return partition information on the media.
+//
+ {
+
+ __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:PartitionInfo"));
+ if (iSocket->CardIsReadyAndVerified()!=KErrNone)
+ return(KErrNotReady);
+ TInt partitionCount=anInfo.iPartitionCount=0;
+
+ // Read the first sector and check for a Master Boot Record
+ TInt err;
+ if ((err=SectorRead(0,&iSectorBuf[0]))!=KErrNone)
+ return(err);
+ if (*(TUint16*)(&iSectorBuf[KMBRSignatureOffset])!=KMBRSignature)
+ return(KErrCorrupt);
+
+ // Move the partition entries to a 4 byte boundary
+ memmove(&iSectorBuf[0],&iSectorBuf[KMBRFirstPartitionOffset],(sizeof(TMBRPartitionEntry)*KMBRMaxPrimaryPartitions));
+
+ // Search for a x86 default boot partition - let this be the first
+ TMBRPartitionEntry *pe=(TMBRPartitionEntry*)(&iSectorBuf[0]);
+ TInt i;
+ TInt defaultPartitionNumber=-1;
+ for (i=0;i<KMBRMaxPrimaryPartitions;i++,pe++)
+ {
+ if (pe->IsDefaultBootPartition())
+ {
+ SetPartitionEntry(anInfo.iEntry, pe);
+ defaultPartitionNumber=i;
+ iHiddenSectors=pe->iFirstSector;
+ partitionCount++;
+ break;
+ }
+ }
+
+ // Now add any other partitions
+ pe=(TMBRPartitionEntry*)(&iSectorBuf[0]); // Reset it
+ for (i=0;i<KMBRMaxPrimaryPartitions;i++,pe++)
+ {
+ __KTRACE_OPT(KLOCDRV, Kern::Printf("Partition %d:",i));
+ __KTRACE_OPT(KLOCDRV, DebugDump(*pe));
+ if (defaultPartitionNumber==i)
+ continue; // Already sorted
+ if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition())
+ {
+ SetPartitionEntry(anInfo.iEntry+partitionCount, pe);
+ partitionCount++;
+ }
+ }
+ anInfo.iPartitionCount=partitionCount;
+ anInfo.iMediaSizeInBytes=TotalSizeInBytes();
+
+ __KTRACE_OPT(KLOCDRV, DebugDump(anInfo));
+
+ PartitionInfoComplete(KErrNone);
+ return KErrNone;
+ }
+
+TInt DPcCardMediaDriverAta::Caps(TLocalDriveCapsV6& aInfo)
+//
+// Return the capabilities of the media
+//
+ {
+ aInfo.iType=EMediaHardDisk;
+ aInfo.iBattery=EBatNotSupported;
+ aInfo.iDriveAtt=KDriveAttLocal|KDriveAttRemovable;
+ aInfo.iMediaAtt=KMediaAttFormattable;
+ aInfo.iFileSystemId=KDriveFileSysFAT;
+ aInfo.iHiddenSectors=iHiddenSectors;
+ aInfo.iBlockSize=KAtaSectorSize;
+ return KErrCompletion; // synchronous completion
+ }
+
+DECLARE_STANDARD_PDD()
+ {
+ return new DPhysicalDeviceMediaAta;
+ }
+