diff -r 000000000000 -r a41df078684a kernel/eka/drivers/medata/pccd_ata.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/medata/pccd_ata.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -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 + +const TInt KMaxSectorsPerRead=32; +const TInt KMaxSectorsPerWrite=8; +const TInt KMaxSectorsPerFormat=8; +const TInt KMaxBytesPerRead=(KMaxSectorsPerRead<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: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)<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: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 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("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("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=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 (iCmdOutOffsetAta: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("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 (iCmdOutOffsetInterruptDisable(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("CardIsReadyAndVerified()!=KErrNone) + return KErrNotReady; + if (aCheckPower && Kern::MachinePowerStatus()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("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(">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); + 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: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: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; iiPartitionBaseAddr=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;iIsDefaultBootPartition()) + { + 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;iIsValidDosPartition() || 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; + } +