Update contrib.
1 // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\drivers\medata\pccd_ata.cpp
18 #include "pbusmedia.h"
22 const TInt KErrBadDrqOnRead=-64;
23 const TInt KErrBadDrqOnWrite=-65;
24 const TInt KErrBadDrq=-66;
25 const TInt KErrAta=-67;
26 const TInt KErrBadPccdConfig=-68;
27 //const TInt KErrDriveChunkNotOpen=-69;
29 const TInt KAtaDriverPriority=KMediaDriverPriorityNormal;
30 //const TInt KAtaDriverPriority=KMediaDriverPriorityHigh;
32 _LIT(KPddName, "Media.Ata");
33 //_LIT(KPddName, "Media.Ata2");
36 #define SELECT_CONTIGUOUS_IO_CONFIG
37 //#define SELECT_PRIMARY_IO_CONFIG
38 //#define SELECT_MEMORY_CONFIG
40 //#define FORCE_8BIT_ACCESSES
42 // Special debug options
43 //#define SHOW_CARD_ERRORS
44 //#define DEBUG_WITH_HW_TRIGGER
45 //#define COUNT_TIMEOUTS
47 #if (defined(SHOW_CARD_ERRORS))
48 #define __KTRACE_CARD_ERROR(a,p) {p;}
49 #elif (defined(_DEBUG))
50 #define __KTRACE_CARD_ERROR(a,p) {if((KDebugNum(a)))p;}
52 #define __KTRACE_CARD_ERROR(a,p)
57 const TInt KMaxSectorsPerRead=32;
58 const TInt KMaxSectorsPerWrite=8;
59 const TInt KMaxSectorsPerFormat=8;
60 const TInt KMaxBytesPerRead=(KMaxSectorsPerRead<<KAtaSectorShift);
61 const TInt KMaxBytesPerWrite=(KMaxSectorsPerWrite<<KAtaSectorShift);
63 // Sector buffer size must be a multiple of sector size and at least as large
64 // as KMaxSectorsPerWrite.
65 const TInt KSectBufSizeInSectors=8;
66 const TInt KSectBufSizeInBytes=(KSectBufSizeInSectors<<KAtaSectorShift);
67 const TInt KSectBufSizeInBytesMinusOneSector=(KSectBufSizeInBytes-KAtaSectorSize);
69 const TInt KIdleCurrentInMilliAmps=1;
70 const TInt KReadCurrentInMilliAmps=39;
71 const TInt KWriteCurrentInMilliAmps=46;
73 const TInt KNotBusySyncTimeout=5;
74 const TInt KNotBusySyncRetryCount=10;
75 const TInt KDriveReadySyncTimeout=5;
78 const TInt KNotBusyTestInterval=30; // Check for not-busy once every 30ms
79 const TInt KBusyTimeOut=67; // Timeout after this many tests (67*30ms=2010ms)
81 const TInt KNotBusyTestInterval=5; // Check for not-busy once every 5ms
82 const TInt KBusyTimeOut=400; // Timeout after this many tests (400*5ms=2010ms)
85 class DPhysicalDeviceMediaAta : public DPhysicalDevice
88 DPhysicalDeviceMediaAta();
89 virtual TInt Install();
90 virtual void GetCaps(TDes8& aDes) const;
91 virtual TInt Create(DBase*& aChannel, TInt aMediaId, const TDesC8* anInfo, const TVersion& aVer);
92 virtual TInt Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer);
93 virtual TInt Info(TInt aFunction, TAny* a1);
96 class DPcCardMediaDriverAta : public DMediaDriver
99 DPcCardMediaDriverAta(TInt aMediaId);
100 virtual TInt Request(TLocDrvRequest& aRequest);
101 virtual TInt PartitionInfo(TPartitionInfo& anInfo);
102 virtual void NotifyPowerDown();
103 virtual void NotifyEmergencyPowerDown();
104 virtual void Close();
106 enum TCardStatus {ECardIdle,ECardRead,ECardWrite,ECardFormat};
107 inline TUint8 AtaRegister8(TUint aReg);
108 inline void SetAtaRegister8(TUint8 aValue,TUint aReg);
109 void ModifyAtaRegister8(TUint aClearMask,TUint aSetMask,TUint aReg);
110 void SelectDrive(TAtaDriveSelect aDrive);
111 TBool WaitForNotBusy();
112 TBool DriveReadyForCommand(TInt aDrive);
113 void SetLbaSectorAddress(TUint aSector);
114 void SetChsSectorAddress(TUint aSector);
115 TInt IssueAtaCommand(TUint8 aCmd,TUint aFirstSector,TInt aSectorCount);
116 TInt EmptySectBufferToTrg(TUint8 *aSrc,TUint aTrgOffset,TInt aLen);
117 TInt LoadSectBufferFromSrc(TInt aLen, TUint8* aBuf);
118 TInt LoadSectBufferFromDrive(TAny *aBuf);
119 TInt EmptySectBufferToDrive(TUint8 *aBuf);
120 TInt TransferSectBufferFromDrive(TAny *aBuf);
121 TInt FinishCommand();
122 TInt CheckForError();
123 TInt ProcessError(TInt anError);
124 TInt SectorBoundaryReadCheck(TUint aStartSector,TUint aStartSectOffset,Int64 anEndPos);
125 TInt SectorRead(TUint aFirstSector,TUint8 *aBuf,TInt aSectorCount=1,TUint8 aCmd=KAtaCmdReadSectors);
126 TInt CheckDevice(TBool aCheckPower);
127 TInt InitiateWriteCommand(TUint aFirstSector,TInt aSectorCount,TUint8 *aSectBuffer);
128 TInt ReadSectorsCommand(TUint aFirstSector,TUint aBufOffset,TInt aLen);
129 TInt IdentifyDrive();
130 void DumpIdentifyDriveInfo();
131 TInt ConfigAutoPowerDown();
136 TBool CardPoweredDown();
137 void IncrementSectBufPtr();
138 static void CardIreqDfcFunction(TAny* aPtr);
139 static void TimerDfcFunction(TAny* aPtr);
140 static void AsyncBusyTimerCallBack(TAny* aMediaDriver);
141 static void SyncBusyTimerCallBack(TAny* aBusyFlag);
142 static void CardIntCallBack(TAny* aPtr, TInt anId);
143 TBool DoCardNotBusy(TInt &anErr);
145 TBool DoCmdDfc(TInt &anErr);
146 void Complete(TInt anError);
147 TInt Caps(TLocalDriveCapsV6& anInfo);
151 TInt InitiateAsyncRead();
152 TInt InitiateAsyncWrite();
154 DPcCardSocket* iSocket;
155 TLocDrvRequest* iCurrentReq;
156 TPBusCallBack iCardIntCallBack;
157 RPccdWindow iDriveChunk;
158 TPccdMemType iMemoryType;
159 TDriveParameters iDriveInfo;
163 TInt iNotBusyTickCount;
165 TCardStatus iCardStatus;
166 TUint iCmdInOffset; // Progress counter for data received from src device
167 TUint iCmdOutOffset; // Progress counter for data delivered to target device
168 TUint iCmdEndOffset; // Marks point when transfer associated with command is complete
169 TUint iCmdLength; // Transfer length remaining
170 TUint iNextSector; // Next sector to transfer
171 TUint8 *iSectBufPtr; // Progress counter for tranfering data between card and sector buffer
172 TUint iSectBufOffset; // Offset within sector buffer to start of data involved in command (Reads only)
173 TBool iLastSectorBufUsed;
174 TUint iHiddenSectors;
176 TUint8 iSectorBuf[KSectBufSizeInBytes]; // Keep on 4byte boundary - put this last
177 TUint8 iLastSectorBuf[KAtaSectorSize]; // Holds last sector data for unaligned write
178 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
183 #ifdef COUNT_TIMEOUTS
186 TInt iImmediateNotBusy;
195 void DPcCardMediaDriverAta::Complete(TInt anError)
197 __KTRACE_OPT(KFAIL,Kern::Printf("mdrqc %08x %d",iCurrentReq,anError));
198 #ifdef COUNT_TIMEOUTS
202 Kern::Printf("I=%d T=%d M=%d CR=%d CW=%d",iInts,iTimeouts,iImmediateNotBusy,iChainedReads,iChainedWrites);
204 for (i=0; i<iIndex; i+=2)
205 Kern::Printf("%d: %08x %08x",i,iInfo[i],iInfo[i+1]);
209 TLocDrvRequest* pR=iCurrentReq;
213 DMediaDriver::Complete(*pR,anError);
217 inline TUint8 DPcCardMediaDriverAta::AtaRegister8(TUint aReg)
219 // Read from an 8 bit ATA register
223 return iDriveChunk.Read8(aReg);
226 inline void DPcCardMediaDriverAta::SetAtaRegister8(TUint8 aValue,TUint aReg)
228 // Write to an 8 bit ATA register
232 iDriveChunk.Write8(aReg,aValue);
235 void DPcCardMediaDriverAta::ModifyAtaRegister8(TUint aClearMask,TUint aSetMask,TUint aReg)
237 // Modify an 8 bit ATA register
241 SetAtaRegister8((TUint8)((AtaRegister8(aReg)&(~aClearMask))|aSetMask),aReg);
244 void DPcCardMediaDriverAta::SelectDrive(TAtaDriveSelect aDrive)
246 // Modify an 8 bit ATA register
250 ModifyAtaRegister8(KAtaDrvHeadDrive1,(0xA0|aDrive),KAtaSelectDriveHeadRdWr8);
253 TBool DPcCardMediaDriverAta::WaitForNotBusy()
255 // Poll busy flag (while card accesses the data buffer and command register).
260 // Before we start a timed loop, just check it isn't already not busy
261 __KTRACE_OPT(KPBUSDRV,Kern::Printf("WfnB"));
262 if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusBusy))
264 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
265 TUint c=NKern::TickCount();
267 volatile TBool timedOut=EFalse;
268 NTimer busyTimeout(SyncBusyTimerCallBack,(TAny*)&timedOut);
269 busyTimeout.OneShot(NKern::TimerTicks(KNotBusySyncTimeout));
272 if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusBusy)||timedOut)
276 busyTimeout.Cancel();
279 TInt retry=KNotBusySyncRetryCount;
280 while ((AtaRegister8(KAtaStatusRd8)&KAtaStatusBusy) && retry)
286 TBool ret=(AtaRegister8(KAtaStatusRd8) & KAtaStatusBusy);
287 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
288 c=NKern::TickCount()-c;
291 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:WaitForNotBusy-timeout(%xH) %d ms",AtaRegister8(KAtaStatusRd8),c));
295 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:WaitForNotBusy-OK %d ms",c));
301 TBool DPcCardMediaDriverAta::DriveReadyForCommand(TInt aDrive)
303 // Wait until selected drive is able to accept a command (5ms timeout).
307 // Select the drive were waiting on
308 SelectDrive((aDrive==1)?ESelectDrive1:ESelectDrive0);
309 if (!WaitForNotBusy())
312 volatile TBool timedOut=EFalse;
313 NTimer busyTimeout(SyncBusyTimerCallBack,(TAny*)&timedOut);
314 busyTimeout.OneShot(NKern::TimerTicks(KDriveReadySyncTimeout));
317 if (AtaRegister8(KAtaStatusRd8)&KAtaStatusRdy||timedOut)
321 busyTimeout.Cancel();
322 TBool ret=(AtaRegister8(KAtaStatusRd8) & KAtaStatusRdy);
323 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
325 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:DriveReadyForCommand-Fail(%xH)",AtaRegister8(KAtaStatusRd8)));
330 void DPcCardMediaDriverAta::SetLbaSectorAddress(TUint aSector)
332 // Setup the sector address ATA registers (LBA mode)
335 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:SetLbaSectorAddress (LBA: %xH)",aSector));
337 SetAtaRegister8((TUint8)aSector,KAtaLba7_0RdWr8);
338 SetAtaRegister8((TUint8)(aSector>>8),KAtaLba15_8RdWr8);
339 SetAtaRegister8((TUint8)(aSector>>16),KAtaLba23_16RdWr8);
340 TUint8 lba27_24=(TUint8)((aSector>>24)&0x0F);
341 ModifyAtaRegister8(KAtaDrvHeadLba27_24,(KAtaDrvHeadLbaOn|lba27_24),KAtaSelectDriveHeadRdWr8);
344 void DPcCardMediaDriverAta::SetChsSectorAddress(TUint aSector)
346 // Setup the sector address ATA registers (CHS mode)
350 TUint cylinder=0,head=0,sector=1;
351 if (iDriveInfo.iSectorsPerCylinder>0&&iDriveInfo.iSectorsPerTrack>0)
353 cylinder=aSector/iDriveInfo.iSectorsPerCylinder;
354 TUint remainder=aSector%iDriveInfo.iSectorsPerCylinder;
355 head=remainder/iDriveInfo.iSectorsPerTrack;
356 sector=(remainder%iDriveInfo.iSectorsPerTrack)+1;
359 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:SetChsSectorAddress (C: %xH H: %xH S: %xH)",cylinder,head,sector));
360 SetAtaRegister8((TUint8)sector,KAtaSectorNoRdWr8);
361 SetAtaRegister8((TUint8)cylinder,KAtaCylinderLowRdWr8);
362 SetAtaRegister8((TUint8)(cylinder>>8),KAtaCylinderHighRdWr8);
363 ModifyAtaRegister8((KAtaDrvHeadLbaOn|KAtaDrvHeadLba27_24),((TUint8)(head&0x0F)),KAtaSelectDriveHeadRdWr8);
366 TInt DPcCardMediaDriverAta::IssueAtaCommand(TUint8 aCmd,TUint aFirstSector,TInt aSectorCount)
368 // Issue an ATA command (Drive 0 only for now).
372 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:IssueAtaCommand(C:%x, FS:%x, SC:%x)",aCmd,aFirstSector,aSectorCount));
373 __KTRACE_OPT(KFAIL,Kern::Printf("A%02x,%d",aCmd,aSectorCount));
374 if (!WaitForNotBusy())
375 return(KErrTimedOut);
376 if (!DriveReadyForCommand(0))
379 if (aSectorCount==KMaxSectorsPerCmd)
381 SetAtaRegister8((TUint8)aSectorCount,KAtaSectorCountRdWr8);
382 if (iDriveInfo.iSupportsLba)
383 SetLbaSectorAddress(aFirstSector);
385 SetChsSectorAddress(aFirstSector);
386 __TRACE_TIMING(0x103);
387 SetAtaRegister8(aCmd,KAtaCommandWr8); // Issue the command
388 Kern::NanoWait(400); // Busy flag not asserted for 400ns
389 __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:IssueAtaCommand"));
393 TInt DPcCardMediaDriverAta::LoadSectBufferFromDrive(TAny *aBuf)
395 // Read a sector from the ATA card
399 if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusDrq))
401 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf(">Ata:LoadSectBufferFromDrive-Bad drq(%xH)",AtaRegister8(KAtaStatusRd8)));
402 return KErrBadDrqOnRead;
405 if (__IS_COMMON_MEM(iMemoryType))
406 iDriveChunk.Read(KAtaDataRdWrWinBase16,aBuf,KAtaSectorSize); // Use 1K window
407 else if (iMemoryType==EPccdIo16Mem)
408 iDriveChunk.ReadHWordMultiple(KAtaDataRdWr16,aBuf,(KAtaSectorSize>>1));
410 iDriveChunk.ReadByteMultiple(KAtaDataRdWr8,aBuf,KAtaSectorSize); // Must be EPccdIo8Mem
415 TInt DPcCardMediaDriverAta::TransferSectBufferFromDrive(TAny *aBuf)
417 // Read a sector from the ATA card
421 if (!WaitForNotBusy())
422 return(KErrTimedOut);
423 return(LoadSectBufferFromDrive(aBuf));
426 TInt DPcCardMediaDriverAta::EmptySectBufferToDrive(TUint8 *aBuf)
428 // Write a sector to the ATA card.
432 if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusDrq))
434 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf(">Ata:EmptySectBufferToDrive-Bad drq(%xH)",AtaRegister8(KAtaStatusRd8)));
435 return KErrBadDrqOnWrite;
438 if (__IS_COMMON_MEM(iMemoryType))
439 iDriveChunk.Write(KAtaDataRdWrWinBase16,aBuf,KAtaSectorSize); // Use 1K window
440 else if (iMemoryType==EPccdIo16Mem)
441 iDriveChunk.WriteHWordMultiple(KAtaDataRdWr16,aBuf,(KAtaSectorSize>>1));
443 iDriveChunk.WriteByteMultiple(KAtaDataRdWr8,aBuf,KAtaSectorSize); // Must be EPccdIo8Mem
448 TInt DPcCardMediaDriverAta::FinishCommand()
450 // Called each time a command has been issued to check if an error occured.
454 if (!WaitForNotBusy())
455 return(KErrTimedOut);
456 return(CheckForError());
459 TInt DPcCardMediaDriverAta::CheckForError()
461 // Called each time a command has been issued to check if an error occured.
465 TUint8 status=AtaRegister8(KAtaStatusRd8);
466 if (status&KAtaStatusDrq)
468 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:CheckForError-DRQ fail"));
471 if (status&KAtaStatusDwf)
473 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:CheckForError-DWF fail"));
476 if (status&KAtaStatusErr)
478 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:CheckForError-ERR fail"));
484 TInt DPcCardMediaDriverAta::ProcessError(TInt anError)
486 // An error has occured - lets get more information
490 if (anError==KErrAta&&AtaRegister8(KAtaStatusRd8)&KAtaStatusErr)
492 TUint8 basic=AtaRegister8(KAtaErrorRd8);
493 #if (defined(__EPOC32__) && (defined(_DEBUG) || defined(SHOW_CARD_ERRORS)))
494 TUint8 extended=0xFF; // invalid
495 SetAtaRegister8(KAtaCmdRequestSense,KAtaCommandWr8); // Issue command - request sense
496 Kern::NanoWait(400); // Busy flag not asserted for 400ns
498 if (!(AtaRegister8(KAtaStatusRd8)&KAtaStatusErr))
499 extended=AtaRegister8(KAtaErrorRd8);
500 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("Ata:ProcessError-Basic:%xH Ext:%xH)",basic,extended));
502 if (basic&KAtaErrorUnc)
504 else if (basic&(KAtaErrorBbk|KAtaErrorIdnf))
506 else if (basic&KAtaErrorAbort)
515 TInt DPcCardMediaDriverAta::EmptySectBufferToTrg(TUint8 *aSrc,TUint aTrgOffset,TInt aLen)
517 // Empty data from sector buffer (at specified offset within buffer) into
518 // destination descriptor.
522 TPtrC8 buf(aSrc,aLen);
523 return iCurrentReq->WriteRemote(&buf,aTrgOffset);
526 TInt DPcCardMediaDriverAta::LoadSectBufferFromSrc(TInt aLen, TUint8* aBuf)
528 // Load data from source descriptor into sector buffer
529 // Always called within exec. function.
533 TPtr8 buf(aBuf,aLen);
534 TInt r=iCurrentReq->ReadRemote(&buf,iCmdInOffset);
538 TInt DPcCardMediaDriverAta::ReadSectorsCommand(TUint aFirstSector,TUint aBufOffset,TInt aLen)
540 // Start off a read of multiple sectors from the drive (command completed under interrupt/dfc).
543 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:ReadSectors F:%x Off:%x L:%x",aFirstSector,aBufOffset,aLen));
545 __ASSERT_DEBUG(aBufOffset<(TUint)KAtaSectorSize,Kern::PanicCurrentThread(_L("ReadSectorsCommand"),0));
546 __ASSERT_DEBUG(aLen>0,Kern::PanicCurrentThread(_L("ReadSectorsCommand"),0));
548 // Sector count - allow for not starting on sector boundary by adding buffer offset. Allow for
549 // not ending on sector boundary by adding sectorsize-1. Then divide by sector size.
550 TInt tferSectorCount=(aLen+aBufOffset+KAtaSectorSizeMinusOne)>>KAtaSectorShift;
551 iNextSector+=tferSectorCount;
552 __ASSERT_DEBUG(tferSectorCount<=KMaxSectorsPerRead,Kern::PanicCurrentThread(_L("ReadSectorsCommand"),0));
554 if (!iSocket->CardIsReady())
555 return(KErrNotReady);
556 AtaRegister8(KAtaStatusRd8); // Clear any pending interrupt
557 iSocket->InterruptEnable(EPccdIntIReq,0); // Enable card interrupt
558 TInt err=IssueAtaCommand(KAtaCmdReadSectors,aFirstSector,tferSectorCount);
561 iSocket->InterruptDisable(EPccdIntIReq); // Disable card interrupt
562 iCardIreqDfc.Cancel();
565 iCommandError=KErrNone;
566 iNotBusyTickCount=KBusyTimeOut;
567 iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
571 TInt DPcCardMediaDriverAta::InitiateWriteCommand(TUint aFirstSector,TInt aSectorCount,TUint8 *aSectBuffer)
573 // Start off an asynchronous write to the card. If successful, it leaves with a
574 // timeout(ms timer) queued and card interrupts enabled.
577 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:InitWrCmd F:%x C:%x",aFirstSector,aSectorCount));
579 __ASSERT_DEBUG((aSectorCount>0 && aSectorCount<=KMaxSectorsPerWrite),Kern::PanicCurrentThread(_L("InitiateWriteCommand"),0));
581 TInt err=IssueAtaCommand(KAtaCmdWriteSectors,aFirstSector,aSectorCount);
584 if (!iSocket->CardIsReady())
585 return(KErrNotReady);
586 if (!WaitForNotBusy())
587 return(ProcessError(KErrTimedOut));
588 AtaRegister8(KAtaStatusRd8); // Clear any pending interrupt
589 iSocket->InterruptEnable(EPccdIntIReq,0); // Enable card interrupt
590 err=EmptySectBufferToDrive(aSectBuffer);
593 iSocket->InterruptDisable(EPccdIntIReq); // Disable card interrupt
594 iCardIreqDfc.Cancel();
595 return(ProcessError(err));
597 iCommandError=KErrNone;
598 iNotBusyTickCount=KBusyTimeOut;
599 iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
600 iNextSector+=aSectorCount;
604 TInt DPcCardMediaDriverAta::SectorBoundaryReadCheck(TUint aStartSector,TUint aStartSectOffset,Int64 anEndPos)
606 // Check for write request which doesn't lie entirely on a sector boundary and perform
607 // the appropriate sectors reads prior to writing if necessary
612 TUint endSectOffset=((TUint)anEndPos&(~KAtaSectorMask));
614 anEndPos>>=KAtaSectorShift;
615 TUint endSector=(TUint)anEndPos; // Sector number can't exceed 32bits
616 TInt sectors=(endSector-aStartSector)+1;
617 iLastSectorBufUsed=EFalse;
619 if (aStartSectOffset||endSectOffset)
621 // If it requires a read of two consecutive sectors then read them in one go
622 if (aStartSectOffset && endSectOffset && sectors==2)
623 return(SectorRead(aStartSector,&iSectorBuf[0],2,KAtaCmdReadSectors));
626 // If write starts off a sector boundary or is a single sector write ending
627 // off a sector boundary then read first sector
628 if (aStartSectOffset || (endSectOffset && sectors==1))
630 if ((err=SectorRead(aStartSector,&iSectorBuf[0]))!=KErrNone)
633 // If write doesn't end on a sector boundary then read the last sector
634 if (endSectOffset && sectors>1)
636 TUint8* p=iSectorBuf;
637 if (sectors<=KMaxSectorsPerWrite)
638 p+=(sectors-1)<<KAtaSectorShift;
642 iLastSectorBufUsed=ETrue;
644 return(SectorRead(endSector,p));
651 TInt DPcCardMediaDriverAta::SectorRead(TUint aFirstSector,TUint8 *aBuf,TInt aSectorCount,TUint8 aCmd)
653 // Read either 1 or 2 sectors into the sector buffer (synchronously)
658 if ( (err=IssueAtaCommand(aCmd,aFirstSector,aSectorCount))==KErrNone)
661 (err=TransferSectBufferFromDrive(aBuf))!=KErrNone||
662 (aSectorCount>1&&(err=TransferSectBufferFromDrive((TAny*)(aBuf+KAtaSectorSize)))!=KErrNone)||
663 (err=FinishCommand())!=KErrNone
665 err=ProcessError(err);
667 if (!iSocket->CardIsReady())
668 err=KErrNotReady; // If media change - return not ready rather than anything else.
672 void DPcCardMediaDriverAta::DumpIdentifyDriveInfo()
674 // Debug option to display the drive indentification info.
678 if (KDebugNum(KPBUSDRV))
680 for (TInt i=0;i<128;i+=8)
682 Kern::Printf("%02x%02x %02x%02x %02x%02x %02x%02x",iSectorBuf[i],iSectorBuf[i+1],iSectorBuf[i+2],iSectorBuf[i+3],iSectorBuf[i+4],\
683 iSectorBuf[i+5],iSectorBuf[i+6],iSectorBuf[i+7]);
689 TInt DPcCardMediaDriverAta::IdentifyDrive()
691 // Get drive charateristics
694 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:IdentifyDrive"));
697 if ((err=SectorRead(0,&iSectorBuf[0],1,KAtaCmdIdentifyDrive))!=KErrNone)
700 DumpIdentifyDriveInfo();
703 if (*(TUint16*)(&iSectorBuf[KAtaIdCapabilities])&KAtaIdCapLbaSupported)
705 // Card indicates it supports LBA
706 // Media size (in sectors) - 2 x halfwords @ KAtaIdTotalSectorsInLba.
707 iDriveInfo.iTotalSectorsInLba=*(TInt*)(&iSectorBuf[KAtaIdTotalSectorsInLba]);
708 s=iDriveInfo.iTotalSectorsInLba;
711 lba=ETrue; // Epson PC card reports LBA supported but LBA size in bytes becomes zero
714 iDriveInfo.iSupportsLba = lba;
718 if (*(TUint16*)(&iSectorBuf[KAtaIdTranslationParams])&KAtaIdTrParamsValid)
720 // Current translation parameters are valid
721 iDriveInfo.iCylinders=*(TUint16*)(&iSectorBuf[KAtaIdCurrentCylinders]);
722 iDriveInfo.iHeads=*(TUint16*)(&iSectorBuf[KAtaIdCurrentHeads]);
723 iDriveInfo.iSectorsPerTrack=*(TUint16*)(&iSectorBuf[KAtaIdCurrentSectorsPerTrack]);
728 iDriveInfo.iCylinders=*(TUint16*)(&iSectorBuf[KAtaIdDefaultCylinders]);
729 iDriveInfo.iHeads=*(TUint16*)(&iSectorBuf[KAtaIdDefaultHeads]);
730 iDriveInfo.iSectorsPerTrack=*(TUint16*)(&iSectorBuf[KAtaIdDefaultSectorsPerTrack]);
732 iDriveInfo.iSectorsPerCylinder=(iDriveInfo.iHeads*iDriveInfo.iSectorsPerTrack);
733 s=iDriveInfo.iCylinders;
734 s*=iDriveInfo.iSectorsPerCylinder;
736 if (iDriveInfo.iSectorsPerCylinder<=0||iDriveInfo.iSectorsPerTrack<=0)
740 __KTRACE_OPT(KPBUSDRV,Kern::Printf("LBA : %xH",iDriveInfo.iSupportsLba));
741 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Cylinders: %xH",iDriveInfo.iCylinders));
742 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Heads : %xH",iDriveInfo.iHeads));
743 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Sectors : %xH",iDriveInfo.iSectorsPerTrack));
744 __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:IdentifyDrive (TS:%lxH)",s));
745 SetTotalSizeInBytes(s);
749 TInt DPcCardMediaDriverAta::ConfigAutoPowerDown()
751 // Set auto power down period to something sensible
756 if ( (err=IssueAtaCommand(KAtaCmdIdle,0,200))==KErrNone) // 200x5mS=1S (aFirstSector doesn't matter).
758 if ((err=FinishCommand())!=KErrNone)
759 err=ProcessError(err);
761 __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:ConfigAutoPowerDown-%d",err));
765 TInt DPcCardMediaDriverAta::DoOpen()
767 // Open the media driver.
771 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:DoOpen"));
772 iCardIreqDfc.SetDfcQ(&iSocket->iDfcQ);
773 iTimerDfc.SetDfcQ(&iSocket->iDfcQ);
775 // Card ought to be ready but check we haven't had media change (this causes creation of card functions).
776 TInt err=iSocket->CardIsReadyAndVerified(); // this may also fail with OOM or corrupt
780 // Perform CIS validation - get back info. on card functions present.
782 if (iSocket->VerifyCard(pt)!=KErrNone)
785 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Check for ATA function, FuncCount=%d",pt.iFuncCount));
787 // Check for ATA fixed disk function.
791 for (f=0;f<pt.iFuncCount;f++)
793 if (pt.iFuncType[f]==EFixedDiskCard)
795 // Fixed disk function - check its an ATA.
796 TBuf8<KLargeTplBufSize> tpl;
797 cisRd.SelectCis(iSocket->iSocketNumber,f);
798 // Must start just after FuncId tuple.
799 if (cisRd.FindReadTuple(KCisTplFuncId,tpl)!=KErrNone)
801 while (cisRd.FindReadTuple(KCisTplFunce,tpl)==KErrNone)
803 if (tpl[2]==0x01 && tpl[3]==0x01) // Interface type - ATA
812 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Is ATA"));
814 // Determine best card configuration
817 TInt opt=KInvalidConfOpt;
818 while(cisRd.FindReadConfig(cf)==KErrNone)
821 cf.IsMachineCompatible(iSocket->iSocketNumber,KPccdCompatNoVccCheck) && // Hitachi card has no 3.3V config entry
822 #if defined (SELECT_MEMORY_CONFIG)
823 (cf.iValidChunks==1 && __IS_COMMON_MEM(cf.iChnk[0].iMemType) && cf.iChnk[0].iMemLen==0x800)
824 #elif defined (SELECT_PRIMARY_IO_CONFIG)
825 (cf.iValidChunks==2 && __IS_IO_MEM(cf.iChnk[0].iMemType) && __IS_IO_MEM(cf.iChnk[1].iMemType) && cf.iChnk[0].iMemBaseAddr==0x1F0)
827 // Choose 16 byte - contiguous i/o option
828 (cf.iValidChunks==1 && __IS_IO_MEM(cf.iChnk[0].iMemType) && cf.iChnk[0].iMemLen==0x10)
832 opt=cf.iConfigOption;
836 if (opt==KInvalidConfOpt)
837 return(KErrNotSupported);
838 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-ConfigOpt(%d)",opt));
839 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Pulsed Ints-%d",(cf.iInterruptInfo&KPccdIntPulse)));
841 // Now configure the card. First configure it to memory mode.
843 err=iSocket->RequestConfig(f,this,cf,0);
846 if (cf.iRegPresent&KConfigAndStatusRegM)
847 iSocket->WriteConfigReg(f,KConfigAndStatusReg,0);
848 if (cf.iRegPresent&KSocketAndCopyRegM)
849 iSocket->WriteConfigReg(f,KSocketAndCopyReg,0); // No twin cards
850 iSocket->ReleaseConfig(f,this);
852 cf.iConfigOption=(cf.iInterruptInfo&KPccdIntPulse)?opt:(opt|KConfOptLevIReqM);
853 // cf.iConfigOption=(opt|KConfOptLevIReqM); // Force level mode interrupts
854 #if defined (FORCE_8BIT_ACCESSES)
855 #if defined (SELECT_MEMORY_CONFIG)
856 cf.iChnk[0].iMemType=EPccdCommon8Mem; // Force it to 8bit Common.
858 cf.iChnk[0].iMemType=EPccdIo8Mem; // Force it to 8bit I/O.
862 if ((err=iSocket->RequestConfig(f,this,cf,0))!=KErrNone)
865 // Read back the config option register to verify it has been setup
867 if ((err=iSocket->ReadConfigReg(f,0,v))!=KErrNone||v!=(TUint8)cf.iConfigOption)
868 return KErrBadPccdConfig;
870 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Configured(%1xH) OK",v));
872 TUint flag=(cf.iActiveSignals&KSigWaitRequired)?KPccdRequestWait:0;
873 err=iDriveChunk.Create(iSocket,cf.iChnk[0],cf.iAccessSpeed,flag);
876 iDriveChunk.SetupChunkHw();
877 iMemoryType=cf.iChnk[0].iMemType;
878 __KTRACE_OPT(KPBUSDRV,Kern::Printf("Ata:DoOpen-Requested Mem OK"));
880 iSocket->InterruptDisable(EPccdIntIReq);
881 iCardIntCallBack.iSocket=iSocket;
882 iCardIntCallBack.Add();
883 SetAtaRegister8(0,KAtaDeviceCtlWr8); // Enable interrupts
885 SetCurrentConsumption(KIdleCurrentInMilliAmps);
886 __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:DoOpen-OK"));
890 TBool DPcCardMediaDriverAta::CardPoweredDown()
892 // Returns EFalse as long as card hasn't received power down (emergency or normal).
896 // Emergency power down may result in card being powered down before PC Card
897 // Controller status is updated - check for EPD as well as PC Card Contoller.
898 return(!Kern::PowerGood() || !iSocket->CardIsReady());
901 void DPcCardMediaDriverAta::IncrementSectBufPtr()
907 iSectBufPtr+=KAtaSectorSize;
908 if ((iSectBufPtr-&iSectorBuf[0])>=KSectBufSizeInBytes)
909 iSectBufPtr=&iSectorBuf[0];
912 TInt DPcCardMediaDriverAta::Request(TLocDrvRequest& m)
914 __KTRACE_OPT(KLOCDRV,Kern::Printf("Ata:Req %08x id %d",&m,m.Id()));
915 TInt r=KErrNotSupported;
917 if (id==DLocalDrive::ECaps)
919 TLocalDriveCapsV6& c=*(TLocalDriveCapsV6*)m.RemoteDes();
921 c.iSize=m.Drive()->iPartitionLen;
922 c.iPartitionType=m.Drive()->iPartitionType;
927 // a request is already in progress, so hold on to this one
928 __KTRACE_OPT(KLOCDRV,Kern::Printf("Ata:Req %08x ret 1",&m));
929 return KMediaDriverDeferRequest;
934 case DLocalDrive::ERead:
937 case DLocalDrive::EWrite:
940 case DLocalDrive::EFormat:
943 case DLocalDrive::EEnlarge:
944 case DLocalDrive::EReduce:
949 __KTRACE_OPT(KLOCDRV,Kern::Printf("Ata:Req %08x cmp %d",&m,r));
955 void DPcCardMediaDriverAta::NotifyPowerDown()
957 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyPowerDown"));
958 Complete(KErrNotReady);
962 void DPcCardMediaDriverAta::NotifyEmergencyPowerDown()
964 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NotifyEmergencyPowerDown"));
973 void DPcCardMediaDriverAta::TimerDfcFunction(TAny* aPtr)
975 // DFC callback from not-busy timer
978 DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aPtr;
979 __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf(">Ata:TimerDfcFunction TC:%d",md.iNotBusyTickCount));
981 if (!md.CardPoweredDown())
983 md.iDriveChunk.SetupChunkHw();
984 TUint8 status=md.AtaRegister8(KAtaStatusRd8); // Clears interrupt
985 if (!(status&KAtaStatusBusy))
987 // It is not-busy so process it as we would from an interrupt
988 __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("Card not busy"));
990 #ifdef COUNT_TIMEOUTS
992 md.iNewTimeOut=ETrue;
995 md.iInfo[md.iIndex++]=md.iCmdInOffset;
996 md.iInfo[md.iIndex++]=md.iCmdEndOffset;
1002 // still busy so count tick and restart timer
1003 if (--md.iNotBusyTickCount==0)
1005 __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("Timed out"));
1006 r=KErrTimedOut; // time out the request
1010 __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("Restart timer"));
1011 md.iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
1017 __KTRACE_OPT2(KPBUSDRV,KFAIL,Kern::Printf("<Ata:TimerDfcFunction r=%d",r));
1020 // card is not-busy, powered down or timed out
1021 md.iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
1022 md.iCardIreqDfc.Cancel(); // so we don't run this twice
1024 CardIreqDfcFunction(&md);
1028 void DPcCardMediaDriverAta::CardIntCallBack(TAny* aMediaDriver, TInt)
1030 // Card Interrupt callback
1033 __TRACE_TIMING(0x104);
1034 DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aMediaDriver;
1035 md.iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
1036 md.iCardIreqDfc.Add();
1037 #ifdef COUNT_TIMEOUTS
1042 void DPcCardMediaDriverAta::CardIreqDfcFunction(TAny* aPtr)
1045 DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aPtr;
1046 TInt err=md.iCommandError;
1047 TBool queueDfc=md.CardPoweredDown();
1050 else if (err!=KErrNone)
1051 queueDfc=ETrue; // timed out
1054 md.iDriveChunk.SetupChunkHw();
1055 TUint8 status=md.AtaRegister8(KAtaStatusRd8); // Clears interrupt
1056 if (!(status&KAtaStatusBusy))
1057 queueDfc=md.DoCardNotBusy(err);
1059 TBool cmd_done=EFalse;
1062 md.iCommandError=err;
1063 cmd_done=md.CmdDfc();
1067 // command still executing so reenable interrupts
1068 md.iSocket->InterruptEnable(EPccdIntIReq,0);
1072 // quickly check if card is already not busy
1073 // this handles cards which return data very quickly
1074 md.iDriveChunk.SetupChunkHw();
1075 TUint8 status=md.AtaRegister8(KAtaStatusRd8); // Clears interrupt
1076 if (!(status&KAtaStatusBusy))
1078 md.iSocket->InterruptDisable(EPccdIntIReq);
1079 md.iCardIreqDfc.Enque();
1080 #ifdef COUNT_TIMEOUTS
1081 ++md.iImmediateNotBusy;
1086 md.iBusyTimeout.Cancel();
1087 md.iTimerDfc.Cancel();
1088 md.iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
1093 TBool DPcCardMediaDriverAta::DoCardNotBusy(TInt &anErr)
1095 // Card not busy interrupt - return ETrue when need to queue dfc
1100 if (iCardStatus==ECardWrite || iCardStatus==ECardFormat)
1102 // For write/format commands we only update the out-pointer when the card becomes
1103 // not-busy following the point we transfered the block of data to the card.
1104 iCmdOutOffset+=(KAtaSectorSize-iSectBufOffset);
1106 if (iCmdOutOffset<iCmdEndOffset)
1108 TUint8* pB=iSectBufPtr;
1109 if (iLastSectorBufUsed && iCmdLength-iCmdOutOffset<=(TUint)KAtaSectorSize)
1110 pB=iLastSectorBuf; // use different buffer for last sector of unaligned write
1111 anErr=EmptySectBufferToDrive(pB);
1112 if (anErr!=KErrNone)
1114 if (iCardStatus==ECardWrite)
1115 iSectBufPtr+=KAtaSectorSize;
1119 anErr=CheckForError();
1123 if (iCardStatus==ECardRead)
1125 // For read commands we only update the in-pointer here. The out-pointer is
1126 // updated by the DFC as data is written to target thread
1128 // Before we read the data from the card, perform the in-pointer incremeting now.
1129 // If we are about to queue a DFC then let the DFC read from the card. Otherwise,
1130 // reading from the card may result in the next sector of data being available
1131 // before we're ready for it.
1133 // If first interrupt after command initiated then allow for sector buffer offset
1134 TInt toEOBuf=(iCmdInOffset==0)?(KAtaSectorSize-iSectBufOffset):KAtaSectorSize;
1135 TInt remaining=(TInt)(iCmdEndOffset-iCmdInOffset);
1136 iCmdInOffset+=Min(remaining,toEOBuf);
1137 if ((iSectBufPtr-&iSectorBuf[0])>=KSectBufSizeInBytesMinusOneSector || iCmdInOffset>=iCmdEndOffset)
1138 return(ETrue); // Queue a DFC
1141 anErr=LoadSectBufferFromDrive(iSectBufPtr);
1142 if (anErr!=KErrNone)
1144 IncrementSectBufPtr();
1150 void DPcCardMediaDriverAta::SyncBusyTimerCallBack(TAny* aBusyFlag)
1152 // Wait for not busy timeout callback
1156 *(TBool*)aBusyFlag=ETrue;
1159 void DPcCardMediaDriverAta::AsyncBusyTimerCallBack(TAny* aMediaDriver)
1161 // Wait for not busy timeout callback
1165 __KTRACE_OPT(KFAIL,Kern::Printf("!,"));
1166 DPcCardMediaDriverAta &md=*(DPcCardMediaDriverAta*)aMediaDriver;
1170 TBool DPcCardMediaDriverAta::CmdDfc()
1172 // Dfc to complete an asynchronous command
1178 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:CmdDfc status %d in %x out %x len %x",iCardStatus,iCmdInOffset,iCmdOutOffset,iCmdLength));
1180 iBusyTimeout.Cancel();
1182 if (DoCmdDfc(err)) // this requeues timer and reenables interrupts if command still executing
1184 // Command has been completed for one reason or other
1187 err=ProcessError(err);
1189 // If emergency power down on write/format - return abort rather than anything else.
1190 if (!Kern::PowerGood() && iCardStatus!=ECardRead)
1192 // If media change - return not ready rather than anything else.
1193 else if (!iSocket->CardIsReady())
1195 __KTRACE_OPT(KFAIL,Kern::Printf("a%d",err));
1198 // may need to issue another command here
1199 if (iCmdOutOffset<iCmdLength)
1201 if (iCardStatus==ECardRead)
1203 __KTRACE_OPT(KFAIL,Kern::Printf("+R"));
1204 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NewReadCmd"));
1206 #ifdef COUNT_TIMEOUTS
1209 err=InitiateAsyncRead();
1215 __KTRACE_OPT(KFAIL,Kern::Printf("+W"));
1216 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:NewWriteCmd"));
1217 #ifdef COUNT_TIMEOUTS
1220 err=InitiateAsyncWrite();
1226 iCardStatus=ECardIdle; // Command now complete
1227 SetCurrentConsumption(KIdleCurrentInMilliAmps);
1229 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1230 if (err!=KErrNone&&err!=KErrTooBig)
1232 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<DFC(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
1236 __TRACE_TIMING(0x109);
1243 TBool DPcCardMediaDriverAta::DoCmdDfc(TInt &anErr)
1245 // Return ETrue when complete
1249 if (CardPoweredDown())
1254 anErr=iCommandError;
1255 if (iCommandError!=KErrNone)
1258 if (iCardStatus==ECardWrite||iCardStatus==ECardFormat)
1262 // Read command, we postponed loading the last sector
1263 __TRACE_TIMING(0x105);
1264 if ((anErr=LoadSectBufferFromDrive(iSectBufPtr))!=KErrNone)
1267 // In case command still executing, queue another timeout and re-enable interrupts
1268 iSocket->InterruptEnable(EPccdIntIReq,0);
1269 iNotBusyTickCount=KBusyTimeOut;
1270 iBusyTimeout.OneShot(NKern::TimerTicks(KNotBusyTestInterval));
1272 __TRACE_TIMING(0x106);
1273 IncrementSectBufPtr();
1274 if ((anErr=EmptySectBufferToTrg(&iSectorBuf[0]+iSectBufOffset,iCmdOutOffset,iCmdInOffset-iCmdOutOffset))!=KErrNone)
1276 iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
1277 iBusyTimeout.Cancel();
1279 iCardIreqDfc.Cancel();
1282 __TRACE_TIMING(0x107);
1283 iSectBufOffset=0; // From now on we always start on sector boundary
1284 iCmdOutOffset=iCmdInOffset;
1285 if (iCmdOutOffset<iCmdEndOffset)
1287 iSocket->InterruptDisable(EPccdIntIReq); // Disable IREQ in controller
1288 iBusyTimeout.Cancel();
1290 iCardIreqDfc.Cancel();
1291 anErr=FinishCommand(); // This functions involves polling for not busy
1294 __TRACE_TIMING(0x108);
1297 DPhysicalDeviceMediaAta::DPhysicalDeviceMediaAta()
1303 iVersion=TVersion(KMediaDriverInterfaceMajorVersion,KMediaDriverInterfaceMinorVersion,KMediaDriverInterfaceBuildVersion);
1306 TInt DPhysicalDeviceMediaAta::Install()
1308 // Install the PC Card ATA Media PDD.
1311 return SetName(&KPddName);
1314 void DPhysicalDeviceMediaAta::GetCaps(TDes8 &/* aDes */) const
1316 // Return the media drivers capabilities.
1321 TInt DPhysicalDeviceMediaAta::Create(DBase*& aChannel, TInt aMediaId, const TDesC8* /*anInfo*/, const TVersion& aVer)
1323 // Create a PC Card ATA media driver.
1326 if (!Kern::QueryVersionSupported(iVersion,aVer))
1327 return KErrNotSupported;
1328 DPcCardMediaDriverAta* pD=new DPcCardMediaDriverAta(aMediaId);
1330 TInt r=KErrNoMemory;
1334 pD->OpenMediaDriverComplete(KErrNone);
1338 TInt DPhysicalDeviceMediaAta::Validate(TInt aDeviceType, const TDesC8* anInfo, const TVersion& aVer)
1340 if (!Kern::QueryVersionSupported(iVersion,aVer))
1341 return KErrNotSupported;
1342 if (aDeviceType!=MEDIA_DEVICE_PCCARD)
1343 return KErrNotSupported;
1347 TInt DPhysicalDeviceMediaAta::Info(TInt aFunction, TAny*)
1349 // Return the priority of this media driver
1352 if (aFunction==EPriority)
1353 return KAtaDriverPriority;
1354 return KErrNotSupported;
1357 DPcCardMediaDriverAta::DPcCardMediaDriverAta(TInt aMediaId)
1361 : DMediaDriver(aMediaId),
1362 iCardIntCallBack(CardIntCallBack,this,KPccdIntMaskIReq),
1363 iBusyTimeout(AsyncBusyTimerCallBack,this),
1364 iCardIreqDfc(CardIreqDfcFunction,this,2),
1365 iTimerDfc(TimerDfcFunction,this,2)
1368 iMemoryType=EPccdIo8Mem;
1369 // iCommandError=KErrNone;
1370 // TUint iCmdInOffset=0;
1371 // TUint iCmdOutOffset=0;
1373 // iSectBufPtr=NULL;
1374 // iSectBufOffset=0;
1375 iCardStatus=ECardIdle;
1376 // iHiddenSectors=0;
1380 TInt DPcCardMediaDriverAta::Open()
1382 // Open the media driver.
1386 // Open the driver and get drive characteristics
1387 iSocket=((DPcCardSocket*)((DPBusPrimaryMedia*)iPrimaryMedia)->iSocket);
1388 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:Open on socket %d",iSocket->iSocketNumber));
1395 if (!iSocket->CardIsReady())
1396 r=KErrNotReady; // If media change - return not ready rather than anything else.
1398 __KTRACE_OPT(KPBUSDRV,Kern::Printf("<Ata:Open-%d",r));
1402 TInt DPcCardMediaDriverAta::CheckDevice(TBool aCheckPower)
1404 // Check the device before initiating a command
1408 if (iSocket->CardIsReadyAndVerified()!=KErrNone)
1409 return KErrNotReady;
1410 if (aCheckPower && Kern::MachinePowerStatus()<ELow)
1411 return KErrBadPower;
1415 TInt DPcCardMediaDriverAta::DoRead()
1417 // Read from specified area of media.
1421 Int64 aPos=iCurrentReq->Pos();
1422 TInt aLength=(TInt)iCurrentReq->Length();
1424 iCmdOutOffset=0; // Progress monitor - data delivered to target
1425 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1426 iDbgPos=(TUint)aPos;
1429 err=CheckDevice(EFalse);
1432 iDriveChunk.SetupChunkHw(); // Enable our h/w chunk
1434 TUint sectorBufOffset=(TUint)aPos&(~KAtaSectorMask);
1435 Int64 firstSector=(aPos>>KAtaSectorShift);
1438 SetCurrentConsumption(KReadCurrentInMilliAmps);
1440 // Start an asynchronous read
1441 iCmdInOffset=0; // Data received from card
1442 iNextSector=(TUint)firstSector;
1443 iSectBufOffset=sectorBufOffset;
1444 err=InitiateAsyncRead();
1448 iCardStatus=ECardIdle;
1449 SetCurrentConsumption(KIdleCurrentInMilliAmps);
1450 if (!iSocket->CardIsReady())
1451 err=KErrNotReady; // If media change - return not ready rather than anything else.
1454 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1455 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:Read(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
1461 TInt DPcCardMediaDriverAta::InitiateAsyncRead()
1463 // Start an asynchronous read
1464 TInt cmdLen=Min(TInt(iCmdLength-iCmdInOffset),TInt(KMaxBytesPerRead-iSectBufOffset)); // Leave it on sector boundary if another read required
1465 iCmdEndOffset=iCmdInOffset+cmdLen; // Marks point when transfer is complete
1466 iSectBufPtr=&iSectorBuf[0];
1467 iCardStatus=ECardRead;
1468 __TRACE_TIMING(0x102);
1469 return ReadSectorsCommand(iNextSector,iSectBufOffset,cmdLen); // Sector number can't exceed 32bits
1472 TInt DPcCardMediaDriverAta::DoWrite()
1474 // Write to specified area of media.
1478 Int64 aPos=iCurrentReq->Pos();
1479 TInt aLength=(TInt)iCurrentReq->Length();
1481 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1482 iDbgPos=(TUint)aPos;
1485 err=CheckDevice(ETrue);
1488 iDriveChunk.SetupChunkHw(); // Enable our h/w chunk
1489 TUint sectorBufOffset=(TUint)aPos&(~KAtaSectorMask);
1490 Int64 firstSector=(aPos>>KAtaSectorShift);
1493 // for unaligned writes, first need to read the first and/or last sector
1494 err=SectorBoundaryReadCheck((TUint)firstSector,sectorBufOffset,aPos+iCmdLength);
1495 if (err==KErrNone) // Sector number can't exceed 32bits
1497 // Time to actually start the write. First alter the current consumption
1498 // and save the data required to complete the write (in the ISR)
1499 SetCurrentConsumption(KWriteCurrentInMilliAmps);
1500 iSectBufOffset=sectorBufOffset;
1502 iCmdOutOffset=0; // Progress monitor - data delivered to card
1503 iNextSector=(TUint)firstSector;
1504 iCardStatus=ECardWrite;
1505 err=InitiateAsyncWrite();
1508 SetCurrentConsumption(KIdleCurrentInMilliAmps);
1510 iCardStatus=ECardIdle;
1511 if (!Kern::PowerGood())
1512 err=KErrAbort; // If emergency power down - return abort rather than anything else.
1513 else if (!iSocket->CardIsReady())
1514 err=KErrNotReady; // If media change - return not ready rather than anything else.
1517 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1518 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:Write(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
1524 TInt DPcCardMediaDriverAta::InitiateAsyncWrite()
1526 iCmdOutOffset=iCmdInOffset;
1527 TInt remain=iCmdLength-iCmdInOffset;
1528 TInt cmdLen=Min(remain, KMaxBytesPerWrite-iSectBufOffset);
1529 TInt sectCount=(cmdLen+iSectBufOffset+KAtaSectorSize-1)>>KAtaSectorShift;
1530 iCmdEndOffset=iCmdOutOffset+cmdLen;
1531 iSectBufPtr=iSectorBuf;
1532 TUint8* pB=iSectorBuf;
1534 if (iCardStatus==ECardWrite)
1536 if (iLastSectorBufUsed && cmdLen==remain)
1538 // load data for sectors other than last into sector buffer
1539 TInt lengthExcludingLastSector=cmdLen &~ (KAtaSectorSize-1);
1540 if (lengthExcludingLastSector==cmdLen)
1541 lengthExcludingLastSector-=KAtaSectorSize;
1542 if (lengthExcludingLastSector)
1544 r=LoadSectBufferFromSrc(lengthExcludingLastSector,iSectorBuf+iSectBufOffset);
1547 iCmdInOffset+=lengthExcludingLastSector; // make sure we get right data for last sector
1551 // load last sector data into last sector buffer
1552 r=LoadSectBufferFromSrc(cmdLen-lengthExcludingLastSector,iLastSectorBuf);
1555 iCmdInOffset+=(cmdLen-lengthExcludingLastSector);
1559 // Load the the data from source in one go
1560 r=LoadSectBufferFromSrc(cmdLen,iSectorBuf+iSectBufOffset);
1563 iCmdInOffset+=cmdLen;
1567 iCmdInOffset+=cmdLen; // format command
1568 r=InCritical(); // this returns KErrNotReady if we are about to do postponed media change or power down
1571 r=InitiateWriteCommand(iNextSector,sectCount,pB);
1572 __KTRACE_OPT(KPBUSDRV,Kern::Printf("InitWrCmd ret %d",r));
1573 if (iCardStatus==ECardWrite)
1574 iSectBufPtr+=KAtaSectorSize;
1578 if (!Kern::PowerGood())
1579 r=KErrAbort; // If emergency power down - return abort rather than anything else.
1580 else if (!iSocket->CardIsReady())
1581 r=KErrNotReady; // If media change - return not ready rather than anything else.
1587 TInt DPcCardMediaDriverAta::DoFormat()
1589 // Format the specified area of the media.
1593 Int64 aPos=iCurrentReq->Pos();
1594 TInt aLength=(TInt)iCurrentReq->Length();
1596 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1597 iDbgPos=(TUint)aPos;
1600 err=CheckDevice(ETrue);
1603 iDriveChunk.SetupChunkHw(); // Enable our h/w chunk
1604 memset(iSectorBuf,0xff,KAtaSectorSize);
1605 Int64 firstSector=(aPos>>KAtaSectorShift);
1606 TInt sectCount=(aLength+KAtaSectorSizeMinusOne)>>KAtaSectorShift;
1607 iCmdLength=(sectCount<<KAtaSectorShift);
1608 sectCount=Min(KMaxSectorsPerFormat,(aLength+KAtaSectorSizeMinusOne)>>KAtaSectorShift);
1609 SetCurrentConsumption(KWriteCurrentInMilliAmps);
1611 iLastSectorBufUsed=EFalse;
1613 iCmdOutOffset=0; // Progress monitor - data delivered to card
1615 iSectBufPtr=&iSectorBuf[0];
1616 iNextSector=(TUint)firstSector;
1617 iCardStatus=ECardFormat;
1618 err=InitiateAsyncWrite();
1622 iCardStatus=ECardIdle;
1623 SetCurrentConsumption(KIdleCurrentInMilliAmps);
1625 if (!Kern::PowerGood())
1626 err=KErrAbort; // If emergency power down - return abort rather than anything else.
1627 else if (!iSocket->CardIsReady())
1628 err=KErrNotReady; // If media change - return not ready rather than anything else.
1631 #if (defined(_DEBUG) || defined(SHOW_CARD_ERRORS))
1632 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:Format(L:%d P:%xH)-%d",iDbgLen,iDbgPos,err));
1638 void DPcCardMediaDriverAta::Close()
1640 // Close the media driver - also called on media change
1644 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:Close"));
1646 Complete(KErrNotReady);
1648 DMediaDriver::Close();
1651 void DPcCardMediaDriverAta::DoClose()
1653 // Close the media driver
1657 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:DoClose"));
1658 iCardIntCallBack.Remove();
1659 iDriveChunk.Close();
1660 if (iCardFuncNum>=0)
1662 iSocket->ReleaseConfig(iCardFuncNum,this);
1666 __KTRACE_CARD_ERROR(KPBUSDRV,Kern::Printf("<Ata:DoClose(%d)",iDbgLastError));
1669 void DPcCardMediaDriverAta::Reset()
1671 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:Reset"));
1672 iBusyTimeout.Cancel(); // In case its currently queued
1673 iCardIreqDfc.Cancel(); // In case its currently queued
1675 iCardStatus=ECardIdle;
1676 SetCurrentConsumption(0);
1680 void DebugDump(const TMBRPartitionEntry& a)
1682 Kern::Printf("BootInd =%02x StartHead=%02x StartSect=%02x StartCyl=%02x",
1683 a.iX86BootIndicator, a.iStartHead, a.iStartSector, a.iStartCylinder);
1684 Kern::Printf("PartType=%02x EndHead =%02x EndSect =%02x EndCyl =%02x",
1685 a.iPartitionType, a.iEndHead, a.iEndSector, a.iEndCylinder);
1686 Kern::Printf("FirstSect=%08x NumSectors=%08x", a.iFirstSector, a.iNumSectors);
1689 void DebugDump(const TPartitionInfo& a)
1691 Kern::Printf("PartitionInfo: (C:%d)",a.iPartitionCount);
1693 for (i=0; i<KMaxPartitionEntries; ++i)
1695 const TPartitionEntry& e=a.iEntry[i];
1696 Kern::Printf(" Partition %d: B=%lxH L=%lxH I=%04x T=%04x", i, e.iPartitionBaseAddr,
1697 e.iPartitionLen, e.iBootIndicator, e.iPartitionType );
1702 void SetPartitionEntry(TPartitionEntry* aDest, const TMBRPartitionEntry* aSrc)
1704 // Set the partition entry details
1708 aDest->iPartitionBaseAddr=aSrc->iFirstSector;
1709 aDest->iPartitionBaseAddr<<=KAtaSectorShift;
1710 aDest->iPartitionLen=aSrc->iNumSectors;
1711 aDest->iPartitionLen<<=KAtaSectorShift;
1712 aDest->iBootIndicator=aSrc->iX86BootIndicator;
1713 aDest->iPartitionType=aSrc->iPartitionType;
1716 TInt DPcCardMediaDriverAta::PartitionInfo(TPartitionInfo& anInfo)
1718 // Return partition information on the media.
1722 __KTRACE_OPT(KPBUSDRV,Kern::Printf(">Ata:PartitionInfo"));
1723 if (iSocket->CardIsReadyAndVerified()!=KErrNone)
1724 return(KErrNotReady);
1725 TInt partitionCount=anInfo.iPartitionCount=0;
1727 // Read the first sector and check for a Master Boot Record
1729 if ((err=SectorRead(0,&iSectorBuf[0]))!=KErrNone)
1731 if (*(TUint16*)(&iSectorBuf[KMBRSignatureOffset])!=KMBRSignature)
1732 return(KErrCorrupt);
1734 // Move the partition entries to a 4 byte boundary
1735 memmove(&iSectorBuf[0],&iSectorBuf[KMBRFirstPartitionOffset],(sizeof(TMBRPartitionEntry)*KMBRMaxPrimaryPartitions));
1737 // Search for a x86 default boot partition - let this be the first
1738 TMBRPartitionEntry *pe=(TMBRPartitionEntry*)(&iSectorBuf[0]);
1740 TInt defaultPartitionNumber=-1;
1741 for (i=0;i<KMBRMaxPrimaryPartitions;i++,pe++)
1743 if (pe->IsDefaultBootPartition())
1745 SetPartitionEntry(anInfo.iEntry, pe);
1746 defaultPartitionNumber=i;
1747 iHiddenSectors=pe->iFirstSector;
1753 // Now add any other partitions
1754 pe=(TMBRPartitionEntry*)(&iSectorBuf[0]); // Reset it
1755 for (i=0;i<KMBRMaxPrimaryPartitions;i++,pe++)
1757 __KTRACE_OPT(KLOCDRV, Kern::Printf("Partition %d:",i));
1758 __KTRACE_OPT(KLOCDRV, DebugDump(*pe));
1759 if (defaultPartitionNumber==i)
1760 continue; // Already sorted
1761 if (pe->IsValidDosPartition() || pe->IsValidFAT32Partition())
1763 SetPartitionEntry(anInfo.iEntry+partitionCount, pe);
1767 anInfo.iPartitionCount=partitionCount;
1768 anInfo.iMediaSizeInBytes=TotalSizeInBytes();
1770 __KTRACE_OPT(KLOCDRV, DebugDump(anInfo));
1772 PartitionInfoComplete(KErrNone);
1776 TInt DPcCardMediaDriverAta::Caps(TLocalDriveCapsV6& aInfo)
1778 // Return the capabilities of the media
1781 aInfo.iType=EMediaHardDisk;
1782 aInfo.iConnectionBusType=EConnectionBusInternal;
1783 aInfo.iDriveAtt=KDriveAttLocal|KDriveAttRemovable;
1784 aInfo.iMediaAtt=KMediaAttFormattable;
1785 aInfo.iFileSystemId=KDriveFileSysFAT;
1786 aInfo.iHiddenSectors=iHiddenSectors;
1787 aInfo.iBlockSize=KAtaSectorSize;
1788 return KErrCompletion; // synchronous completion
1791 DECLARE_STANDARD_PDD()
1793 return new DPhysicalDeviceMediaAta;