00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #define __IDE_C__
00058
00059 #include <stddef.h>
00060 #include <string.h>
00061
00062 #include <sys/timer.h>
00063 #include <sys/thread.h>
00064 #include <sys/event.h>
00065 #include <sys/atom.h>
00066 #include <sys/heap.h>
00067 #include <dev/irqreg.h>
00068
00069 #include <dev/ide.h>
00070 #include <dev/idep.h>
00071 #include <fs/typedefs.h>
00072
00073 #define HIBYTE(_x) (BYTE)((_x >> 8) & 0x00FF)
00074 #define LOBYTE(_x) (BYTE)(_x & 0x00FF)
00075
00076
00077
00078
00079
00080
00081
00082
00083 #define IDE_IRQ INT7
00084 #define IDE_INT_RISING_EDGE 0xC0
00085
00086 #define CF_IRQ INT6
00087 #define CF_INT_SENS_MASK 0x30
00088 #define CF_INT_FALLING_EDGE 0x20
00089 #define CF_INT_RISING_EDGE 0x30
00090
00091
00092 #define IDE_MAX_SUPPORTED_DEVICE 1
00093
00094 #define CF_AVAILABLE 0
00095 #define CF_NOT_AVAILABLE 1
00096
00097 #define INITTIMEOUT 10000
00098 #define DISKTIMEOUT 10000
00099 #define CONTROLLERTIMEOUT 200
00100 #define ATAPITIMEOUT 5000
00101
00102 #define IDEIn(x) pIDE[x]
00103 #define IDEOut(x,y) pIDE[x] = y
00104
00105
00106
00107
00108 #define IDE_SUPPORT_LBA 0x0001
00109 #define IDE_SUPPORT_LBA48 0x0002
00110 #define IDE_SUPPORT_PACKET 0x0004
00111
00112
00113
00114
00115 #define IDE_SUPPORT_INTRQ_PACKET 0x0008
00116
00117 #define IDE_CDROM_DEVICE 0x1000
00118 #define IDE_ZIP_DEVICE 0x2000
00119
00120 #define IDE_READ_ONLY 0x4000
00121 #define IDE_READY 0x8000
00122
00123
00124
00125
00126
00127 #define ATAPI_CFG_12_BYTE_MSK 0x0003
00128 #define ATAPI_CFG_INTRQ 0x0060
00129 #define ATAPI_CFG_REM_MEDIUM 0x0080
00130 #define ATAPI_CFG_DEVICE 0x1F00
00131 #define ATAPI_CFG_ATAPI 0xC000
00132
00133 #define ATAPI_IS_12_BYTE 0x0000
00134 #define ATAPI_USE_INTRQ 0x0020
00135 #define ATAPI_IS_DIRECT_ACCESS 0x0000
00136 #define ATAPI_IS_CDROM 0x0500
00137 #define ATAPI_IS_PACKET 0x8000
00138
00139
00140 typedef struct _drive {
00141
00142
00143
00144 WORD wFlags;
00145 BYTE bIDEMode;
00146 BYTE bDevice;
00147
00148 #if (IDE_SUPPORT_CHS == 1)
00149
00150
00151
00152 WORD wCylinders;
00153 WORD wHeads;
00154 WORD wSectorsPerTrack;
00155 DWORD dwOneSide;
00156 #endif
00157
00158
00159
00160
00161 DWORD dwTotalSectors;
00162
00163 WORD wSectorSize;
00164 } DRIVE, *LPDRIVE;
00165
00166
00167
00168
00169
00170
00171
00172
00173 static HANDLE hIDEEvent;
00174 static volatile BYTE *pIDE;
00175 static volatile BYTE gbIntStatus = 0;
00176
00177 static DRIVE sDrive[IDE_MAX_SUPPORTED_DEVICE];
00178
00179 static HANDLE hIDESemaphore;
00180 static HANDLE hCFChangeInt;
00181 static BYTE gbCFMountStatus = 0;
00182
00183 static IDE_MOUNT_FUNC *pUserMountFunc = NULL;
00184 static IDE_MOUNT_FUNC *pUserUnMountFunc = NULL;
00185
00186 #if (IDE_SUPPORT_ATAPI == 1)
00187
00188
00189
00190 static BYTE aATAPICmd[12];
00191
00192 #define ATAPI_CMD(_x) { \
00193 memset(aATAPICmd, 0x00, sizeof(aATAPICmd)); \
00194 aATAPICmd[0] = _x; \
00195 }
00196
00197 #define CLEAR_ATAPI_CMD() memset(aATAPICmd, 0x00, sizeof(aATAPICmd));
00198 #endif
00199
00200
00201
00202
00203
00204
00205
00206 static void Wait400ns(void)
00207 {
00208
00209
00210
00211
00212 COMPRESS_DISABLE;
00213 _NOP();
00214 _NOP();
00215 _NOP();
00216 _NOP();
00217 _NOP();
00218 _NOP();
00219 _NOP();
00220 _NOP();
00221 COMPRESS_REENABLE;
00222 }
00223
00224
00225
00226
00227 void IDELock(void)
00228 {
00229 NutEventWait(&hIDESemaphore, 0);
00230 }
00231
00232
00233
00234
00235 void IDEFree(void)
00236 {
00237 NutEventPost(&hIDESemaphore);
00238 }
00239
00240
00241
00242
00243 void IDESemaInit(void)
00244 {
00245 NutEventPost(&hIDESemaphore);
00246 }
00247
00248
00249
00250
00251 static void HardwareReset(DRIVE * pDrive)
00252 {
00253 if (pDrive->bIDEMode == MEM_8BIT_COMPACT_FLASH) {
00254
00255
00256
00257 PORTD |= 0x20;
00258 _NOP();
00259
00260 NutSleep(1000);
00261
00262
00263
00264
00265 PORTD &= ~0x20;
00266 _NOP();
00267
00268 NutSleep(1000);
00269 } else {
00270
00271
00272
00273 PORTD &= ~0x20;
00274 _NOP();
00275
00276 NutSleep(1000);
00277
00278
00279
00280
00281 PORTD |= 0x20;
00282 _NOP();
00283
00284 if (pDrive->bIDEMode == IDE_COMPACT_FLASH) {
00285 NutSleep(1000);
00286 } else {
00287
00288
00289
00290
00291
00292 NutSleep(10000);
00293 }
00294 }
00295 }
00296
00297
00298
00299
00300 static void CFInterrupt(void *p)
00301 {
00302 p = p;
00303
00304 NutEventPostFromIrq(&hCFChangeInt);
00305 }
00306
00307
00308
00309
00310 static void IDEInterrupt(void *p)
00311 {
00312 p = p;
00313
00314 gbIntStatus = IDEIn(STATUS_REG);
00315
00316 NutEventPostFromIrq(&hIDEEvent);
00317 }
00318
00319
00320
00321
00322 static void ClearEvent(HANDLE * pEvent)
00323 {
00324 NutEnterCritical();
00325
00326 *pEvent = 0;
00327
00328 NutExitCritical();
00329 }
00330
00331
00332
00333
00334
00335
00336 static int WaitForInterrupt(DWORD dwTimeout)
00337 {
00338 int nError;
00339 int nTimeout;
00340
00341 nError = IDE_OK;
00342
00343 nTimeout = NutEventWait(&hIDEEvent, dwTimeout);
00344 if (nTimeout == -1) {
00345 nError = IDE_ERROR;
00346 }
00347
00348 return (nError);
00349 }
00350
00351 #if ((IDE_SUPPORT_WRITE == 1) || (IDE_SUPPORT_ATAPI == 1))
00352
00353
00354
00355
00356
00357 static int WaitDRQ(DWORD dwTimeout)
00358 {
00359 int nError;
00360 BYTE bStatus;
00361
00362 nError = IDE_OK;
00363
00364 bStatus = IDEIn(STATUS_REG);
00365 if ((bStatus & (STATUS_BUSY | STATUS_DATA_REQUEST)) != STATUS_DATA_REQUEST) {
00366
00367 dwTimeout = (DWORD) (((dwTimeout * 10UL) / 625UL) + 1UL);
00368 dwTimeout += NutGetTickCount();
00369
00370 bStatus = IDEIn(STATUS_REG);
00371 while ((bStatus & (STATUS_BUSY | STATUS_DATA_REQUEST)) != STATUS_DATA_REQUEST) {
00372 if (NutGetTickCount() > dwTimeout) {
00373 nError = IDE_ERROR;
00374 break;
00375 }
00376 bStatus = IDEIn(STATUS_REG);
00377 }
00378
00379 }
00380
00381 return (nError);
00382 }
00383 #endif
00384
00385
00386
00387
00388
00389
00390 static int WaitNotBusy(DWORD dwTimeout)
00391 {
00392 int nError;
00393 BYTE bStatus;
00394
00395 nError = IDE_OK;
00396
00397 bStatus = IDEIn(STATUS_REG);
00398 if (bStatus & (STATUS_BUSY | STATUS_DATA_REQUEST)) {
00399
00400 dwTimeout = ((dwTimeout * 10) / 625) + 1;
00401 dwTimeout += NutGetTickCount();
00402
00403 bStatus = IDEIn(STATUS_REG);
00404 while (bStatus & (STATUS_BUSY | STATUS_DATA_REQUEST)) {
00405 if (NutGetTickCount() > dwTimeout) {
00406 nError = IDE_BUSY;
00407 break;
00408 }
00409 bStatus = IDEIn(STATUS_REG);
00410 }
00411
00412 }
00413
00414 return (nError);
00415 }
00416
00417
00418
00419
00420
00421
00422 static int SelectDevice(BYTE bDevice)
00423 {
00424 int nError;
00425 int nTimeout;
00426 BYTE bStatus;
00427 BYTE bDummy;
00428
00429 nError = IDE_OK;
00430
00431 if (WaitNotBusy(CONTROLLERTIMEOUT) == IDE_OK) {
00432
00433 IDEOut(DISK_HEAD_REG, 0xA0 + (bDevice << 4));
00434
00435 Wait400ns();
00436
00437 nError = WaitNotBusy(CONTROLLERTIMEOUT);
00438 } else {
00439 nError = IDE_BUSY;
00440 }
00441
00442 if (nError != IDE_OK) {
00443
00444
00445
00446
00447 bStatus = IDEIn(STATUS_REG);
00448 if (bStatus & STATUS_DATA_REQUEST) {
00449
00450 nTimeout = 512;
00451 while ((bStatus & STATUS_DATA_REQUEST) && (nTimeout)) {
00452 bDummy = IDEIn(DATA_READ_REG_LOW);
00453 bDummy = IDEIn(DATA_READ_REG_LOW);
00454 bStatus = IDEIn(STATUS_REG);
00455 nTimeout--;
00456 }
00457 }
00458 }
00459
00460 return (nError);
00461 }
00462
00463 #if (IDE_SUPPORT_ATAPI == 1)
00464
00465
00466
00467
00468
00469 static int ATAPISendCommand(LPDRIVE pDrive, BYTE * pSectorBuffer, WORD * pReadCount)
00470 {
00471 int nError;
00472 BYTE bStatus;
00473 BYTE bDevice;
00474 WORD x, y;
00475 BYTE bDummy;
00476 WORD wSectorSize;
00477
00478 nError = IDE_ERROR;
00479 bDummy = 0;
00480 bDevice = pDrive->bDevice;
00481 wSectorSize = pDrive->wSectorSize;
00482
00483 *pReadCount = 0;
00484
00485 if (SelectDevice(bDevice) == IDE_OK) {
00486
00487 ClearEvent(&hIDEEvent);
00488
00489 if (WaitNotBusy(ATAPITIMEOUT) == IDE_OK) {
00490
00491 IDEOut(FEATURE_REG, 0x00);
00492 IDEOut(SECTOR_COUNT_REG, 0x00);
00493 IDEOut(SECTOR_REG, 0x00);
00494 IDEOut(CYLINDER_LOW_REG, LOBYTE(wSectorSize));
00495 IDEOut(CYLINDER_HIGH_REG, HIBYTE(wSectorSize));
00496 IDEOut(COMMAND_REG, 0xA0);
00497
00498 if (pDrive->wFlags & IDE_SUPPORT_INTRQ_PACKET) {
00499 nError = WaitForInterrupt(ATAPITIMEOUT);
00500 if (nError == IDE_OK) {
00501 ClearEvent(&hIDEEvent);
00502 }
00503 } else {
00504 nError = WaitDRQ(ATAPITIMEOUT);
00505 }
00506
00507 if (nError == IDE_OK) {
00508 for (x = 0; x < 12; x = x + 2) {
00509 IDEOut(DATA_WRITE_REG_HIGH, aATAPICmd[x + 1]);
00510 IDEOut(DATA_WRITE_REG_LOW, aATAPICmd[x]);
00511 }
00512
00513 if (WaitForInterrupt(ATAPITIMEOUT) == IDE_OK) {
00514 if (gbIntStatus & STATUS_ERROR) {
00515 nError = IDE_ERROR;
00516 } else {
00517 nError = IDE_OK;
00518
00519 if (gbIntStatus & STATUS_DATA_REQUEST) {
00520
00521 Wait400ns();
00522
00523 y = IDEIn(CYLINDER_HIGH_REG) << 8;
00524 y |= IDEIn(CYLINDER_LOW_REG);
00525
00526 if (y > wSectorSize) {
00527 y = wSectorSize;
00528 }
00529
00530 if (pSectorBuffer != NULL) {
00531 for (x = 0; x < y; x = x + 2) {
00532 pSectorBuffer[x] = pIDE[DATA_READ_REG_LOW];
00533 pSectorBuffer[x + 1] = pIDE[DATA_READ_REG_HIGH];
00534 }
00535 } else {
00536 for (x = 0; x < y; x = x + 2) {
00537 bDummy += pIDE[DATA_READ_REG_LOW];
00538 bDummy += pIDE[DATA_READ_REG_HIGH];
00539 }
00540 }
00541
00542 *pReadCount = y;
00543
00544 bStatus = IDEIn(STATUS_REG);
00545 }
00546 }
00547 }
00548 }
00549 }
00550 }
00551
00552 return (nError);
00553 }
00554
00555
00556
00557
00558
00559
00560 static int ATAPIGetTotalSectors(LPDRIVE pDrive, BYTE * pSectorBuffer, DWORD * pMaxSectors)
00561 {
00562 int nError;
00563 WORD wReadCount;
00564 WORD wErrorCount;
00565 DWORD dwValue;
00566
00567 nError = IDE_OK;
00568 *pMaxSectors = 0;
00569
00570 wErrorCount = 4;
00571 while (wErrorCount) {
00572
00573 ATAPI_CMD(ATAPI_CMD_READ_CAPACITY);
00574 nError = ATAPISendCommand(pDrive, pSectorBuffer, &wReadCount);
00575 if ((nError == IDE_OK) && (wReadCount == 8)) {
00576 dwValue = pSectorBuffer[0];
00577 dwValue = dwValue << 8;
00578 dwValue |= pSectorBuffer[1];
00579 dwValue = dwValue << 8;
00580 dwValue |= pSectorBuffer[2];
00581 dwValue = dwValue << 8;
00582 dwValue |= pSectorBuffer[3];
00583 *pMaxSectors = dwValue;
00584
00585
00586
00587
00588 dwValue = pSectorBuffer[4];
00589 dwValue = dwValue << 8;
00590 dwValue |= pSectorBuffer[5];
00591 dwValue = dwValue << 8;
00592 dwValue |= pSectorBuffer[6];
00593 dwValue = dwValue << 8;
00594 dwValue |= pSectorBuffer[7];
00595 if (dwValue > ATAPI_SECTOR_SIZE) {
00596 dwValue = ATAPI_SECTOR_SIZE;
00597 }
00598 pDrive->wSectorSize = (WORD) (dwValue & 0x0000FFFF);
00599 break;
00600 }
00601 wErrorCount--;
00602 NutSleep(2000);
00603 }
00604
00605 return (nError);
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615 static int GetDeviceInfoPacket(LPDRIVE pDrive, BYTE * pSectorBuffer)
00616 {
00617 WORD i;
00618 int nError;
00619 BYTE bStatus;
00620 BYTE bErrorReg;
00621 BYTE bDevice;
00622 WORD wConfig;
00623 DWORD dwTotalSectors;
00624
00625 nError = IDE_ERROR;
00626 bDevice = pDrive->bDevice;
00627
00628 if (SelectDevice(bDevice) == IDE_OK) {
00629
00630 ClearEvent(&hIDEEvent);
00631
00632 IDEOut(COMMAND_REG, COMMAND_DEVICE_INFO_P);
00633 if (WaitForInterrupt(DISKTIMEOUT) == IDE_OK) {
00634
00635 if (gbIntStatus & STATUS_DATA_REQUEST) {
00636
00637 for (i = 0; i < IDE_SECTOR_SIZE; i = i + 2) {
00638 pSectorBuffer[i] = pIDE[DATA_READ_REG_LOW];
00639 if (pDrive->bIDEMode == MEM_8BIT_COMPACT_FLASH) {
00640 pSectorBuffer[i + 1] = pIDE[DATA_READ_REG_LOW];
00641 } else {
00642 pSectorBuffer[i + 1] = pIDE[DATA_READ_REG_HIGH];
00643 }
00644 }
00645
00646
00647
00648
00649
00650 bStatus = IDEIn(STATUS_REG);
00651
00652 pDrive->wFlags = 0;
00653
00654 wConfig = *(WORD *) & pSectorBuffer[0];
00655 if ((wConfig & ATAPI_CFG_INTRQ) == ATAPI_USE_INTRQ) {
00656 pDrive->wFlags |= IDE_SUPPORT_INTRQ_PACKET;
00657 }
00658 if ((wConfig & ATAPI_CFG_DEVICE) == ATAPI_IS_DIRECT_ACCESS) {
00659 pDrive->wFlags |= IDE_ZIP_DEVICE;
00660 }
00661 if ((wConfig & ATAPI_CFG_DEVICE) == ATAPI_IS_CDROM) {
00662 pDrive->wFlags |= (IDE_READ_ONLY | IDE_CDROM_DEVICE);
00663 }
00664 if ((wConfig & ATAPI_CFG_ATAPI) == ATAPI_IS_PACKET) {
00665 pDrive->wFlags |= IDE_SUPPORT_PACKET;
00666 }
00667
00668 if ((wConfig & ATAPI_CFG_12_BYTE_MSK) == ATAPI_IS_12_BYTE) {
00669 pDrive->wFlags |= IDE_READY;
00670
00671 nError = ATAPIGetTotalSectors(pDrive, pSectorBuffer, &dwTotalSectors);
00672 if (nError == IDE_OK) {
00673 pDrive->dwTotalSectors = dwTotalSectors;
00674
00675
00676
00677
00678 ATAPI_CMD(0x5A);
00679 aATAPICmd[2] = 0x2A;
00680 aATAPICmd[7] = 0x08;
00681 aATAPICmd[8] = 0x00;
00682 ATAPISendCommand(pDrive, pSectorBuffer, &i);
00683
00684
00685
00686
00687 IDEATAPISetCDSpeed(bDevice, 150);
00688 } else {
00689 pDrive->dwTotalSectors = 0;
00690 }
00691
00692
00693 }
00694 }
00695
00696 if (gbIntStatus & STATUS_ERROR) {
00697 bErrorReg = IDEIn(ERROR_REG);
00698 }
00699 }
00700
00701 }
00702
00703 return (nError);
00704 }
00705 #endif
00706
00707
00708
00709
00710
00711
00712
00713
00714 static int GetDeviceInfo(LPDRIVE pDrive, BYTE * pSectorBuffer)
00715 {
00716 WORD i;
00717 int nError;
00718 BYTE bStatus;
00719 BYTE bErrorReg;
00720 BYTE bDevice;
00721 IDEDEVICEINFO *pInfo;
00722
00723 nError = IDE_ERROR;
00724 bDevice = pDrive->bDevice;
00725
00726 if (SelectDevice(bDevice) == IDE_OK) {
00727
00728 ClearEvent(&hIDEEvent);
00729
00730 #if 0
00731 IDEOut(FEATURE_REG, 0);
00732 IDEOut(SECTOR_COUNT_REG, 1);
00733 IDEOut(SECTOR_REG, 0);
00734 IDEOut(CYLINDER_LOW_REG, 0);
00735 IDEOut(CYLINDER_HIGH_REG, 0);
00736 #endif
00737
00738 IDEOut(COMMAND_REG, COMMAND_DEVICE_INFO);
00739 if (WaitForInterrupt(DISKTIMEOUT) == IDE_OK) {
00740
00741 if (gbIntStatus & STATUS_DATA_REQUEST) {
00742
00743 for (i = 0; i < IDE_SECTOR_SIZE; i = i + 2) {
00744 pSectorBuffer[i] = pIDE[DATA_READ_REG_LOW];
00745 if (pDrive->bIDEMode == MEM_8BIT_COMPACT_FLASH) {
00746 pSectorBuffer[i + 1] = pIDE[DATA_READ_REG_LOW];
00747 } else {
00748 pSectorBuffer[i + 1] = pIDE[DATA_READ_REG_HIGH];
00749 }
00750 }
00751
00752
00753
00754
00755
00756 bStatus = IDEIn(STATUS_REG);
00757
00758 pInfo = (IDEDEVICEINFO *) pSectorBuffer;
00759
00760 #if (IDE_SUPPORT_CHS == 1)
00761 pDrive->wCylinders = (WORD) pInfo->Cylinders;
00762 pDrive->wHeads = (BYTE) pInfo->Heads;
00763 pDrive->wSectorsPerTrack = (BYTE) pInfo->SectorsPerTrack;
00764 pDrive->dwOneSide = pDrive->wCylinders * pDrive->wSectorsPerTrack;
00765 #endif
00766
00767 if (pInfo->LBASectors > 0) {
00768 pDrive->wFlags = IDE_READY | IDE_SUPPORT_LBA;
00769 pDrive->dwTotalSectors = pInfo->LBASectors;
00770 } else {
00771
00772 #if (IDE_SUPPORT_CHS == 1)
00773 pDrive->wFlags = IDE_READY;
00774 pDrive->dwTotalSectors = pInfo->Cylinders;
00775 pDrive->dwTotalSectors *= pInfo->Heads;
00776 pDrive->dwTotalSectors *= pInfo->SectorsPerTrack;
00777 #endif
00778
00779 }
00780
00781 nError = IDE_OK;
00782 }
00783
00784 if (gbIntStatus & STATUS_ERROR) {
00785 bErrorReg = IDEIn(ERROR_REG);
00786 }
00787 }
00788
00789 }
00790
00791 return (nError);
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 #if (IDE_SUPPORT_ATAPI == 1)
00803 static int IsPacketDevice(void)
00804 {
00805 int nPacketDevice;
00806 BYTE bSectorCount;
00807 BYTE bSectorNumber;
00808 BYTE bCylinderLow;
00809 BYTE bCylinderHigh;
00810
00811 nPacketDevice = FALSE;
00812
00813 bSectorCount = IDEIn(SECTOR_COUNT_REG);
00814 bSectorNumber = IDEIn(SECTOR_REG);
00815 bCylinderLow = IDEIn(CYLINDER_LOW_REG);
00816 bCylinderHigh = IDEIn(CYLINDER_HIGH_REG);
00817
00818
00819 if ((bCylinderLow == 0x14) && (bCylinderHigh == 0xEB)) {
00820 nPacketDevice = TRUE;
00821 }
00822
00823 return (nPacketDevice);
00824 }
00825 #else
00826 static int IsPacketDevice(void)
00827 {
00828 return (FALSE);
00829 }
00830 #endif
00831
00832
00833
00834
00835
00836
00837
00838
00839 static int DeviceDiag(LPDRIVE pDrive)
00840 {
00841 int nError;
00842 BYTE bResult;
00843
00844 nError = IDE_ERROR;
00845
00846 if (SelectDevice(0) == IDE_OK) {
00847
00848 #if 0
00849 IDEOut(FEATURE_REG, 0);
00850 IDEOut(SECTOR_COUNT_REG, 1);
00851 IDEOut(SECTOR_REG, 0);
00852 IDEOut(CYLINDER_LOW_REG, 0);
00853 IDEOut(CYLINDER_HIGH_REG, 0);
00854 #endif
00855
00856 ClearEvent(&hIDEEvent);
00857
00858
00859
00860
00861 if (IsPacketDevice() == TRUE) {
00862 nError = IDE_OK;
00863 pDrive->wFlags = IDE_SUPPORT_PACKET;
00864 } else {
00865
00866 IDEOut(COMMAND_REG, COMMAND_DIAG);
00867 if (WaitForInterrupt(INITTIMEOUT) == IDE_OK) {
00868
00869 bResult = IDEIn(ERROR_REG);
00870 if (bResult == 0x01) {
00871 nError = IDE_OK;
00872 }
00873
00874 }
00875 }
00876 }
00877
00878 return (nError);
00879 }
00880
00881
00882
00883
00884
00885
00886
00887
00888 static int ReadSectors(BYTE bDevice, BYTE * pData, DWORD dwStartSector, WORD wSectorCount)
00889 {
00890 WORD i, x;
00891 int nError;
00892 BYTE bValue;
00893 BYTE bErrorReg;
00894 BYTE bStatus;
00895 LPDRIVE pDrive;
00896
00897 #if (IDE_SUPPORT_CHS == 1)
00898 WORD wCHSSector;
00899 WORD wCHSHead;
00900 WORD wCHSCylinder;
00901 #endif
00902
00903 pDrive = &sDrive[bDevice];
00904 nError = SelectDevice(bDevice);
00905
00906 #if (IDE_SUPPORT_CHS == 0)
00907
00908
00909
00910 if ((pDrive->wFlags & IDE_SUPPORT_LBA) == 0) {
00911
00912
00913
00914 nError = IDE_ERROR;
00915 }
00916 #endif
00917
00918 if (nError == IDE_OK) {
00919
00920 ClearEvent(&hIDEEvent);
00921
00922 if (pDrive->wFlags & IDE_SUPPORT_LBA) {
00923
00924
00925
00926 bValue = (BYTE) ((bDevice << 4) | 0xE0 | (dwStartSector >> 24));
00927 IDEOut(DISK_HEAD_REG, bValue);
00928 IDEOut(LBA_16_23, (BYTE) (dwStartSector >> 16));
00929 IDEOut(LBA_8_15, (BYTE) (dwStartSector >> 8));
00930 IDEOut(LBA_0_7, (BYTE) (dwStartSector));
00931
00932 IDEOut(SECTOR_COUNT_REG, (BYTE) (wSectorCount & 0xff));
00933 IDEOut(COMMAND_REG, COMMAND_READ_SECTORS);
00934
00935 #if (IDE_SUPPORT_CHS == 1)
00936 } else {
00937
00938
00939
00940 wCHSSector = (WORD) (dwStartSector % pDrive->wSectorsPerTrack) + 1;
00941 wCHSHead = (WORD) (dwStartSector / pDrive->dwOneSide);
00942 dwStartSector = dwStartSector % pDrive->dwOneSide;
00943 wCHSCylinder = (WORD) (dwStartSector / pDrive->wSectorsPerTrack);
00944
00945 wCHSHead |= (bDevice << 4) | 0xA0;
00946
00947 IDEOut(DISK_HEAD_REG, (BYTE) wCHSHead);
00948 IDEOut(SECTOR_REG, (BYTE) wCHSSector);
00949 IDEOut(CYLINDER_LOW_REG, (BYTE) (wCHSCylinder & 0x00FF));
00950 IDEOut(CYLINDER_HIGH_REG, (BYTE) (wCHSCylinder >> 8));
00951
00952 IDEOut(SECTOR_COUNT_REG, (BYTE) (wSectorCount & 0xff));
00953 IDEOut(COMMAND_REG, COMMAND_READ_SECTORS);
00954 #endif
00955 }
00956
00957 for (i = 0; i < wSectorCount; i++) {
00958 nError = WaitForInterrupt(DISKTIMEOUT);
00959 if (nError == IDE_OK) {
00960 bStatus = gbIntStatus;
00961
00962 if (bStatus & STATUS_ERROR) {
00963 bErrorReg = IDEIn(ERROR_REG);
00964 nError = IDE_ERROR;
00965 break;
00966 }
00967
00968 for (x = 0; x < IDE_SECTOR_SIZE; x = x + 2) {
00969 pData[x] = pIDE[DATA_READ_REG_LOW];
00970 if (pDrive->bIDEMode == MEM_8BIT_COMPACT_FLASH) {
00971 pData[x + 1] = pIDE[DATA_READ_REG_LOW];
00972 } else {
00973 pData[x + 1] = pIDE[DATA_READ_REG_HIGH];
00974 }
00975 }
00976
00977 pData += IDE_SECTOR_SIZE;
00978
00979 } else {
00980 bStatus = IDEIn(STATUS_REG);
00981 bErrorReg = IDEIn(ERROR_REG);
00982 }
00983 }
00984
00985 bStatus = IDEIn(STATUS_REG);
00986
00987 }
00988
00989 return (nError);
00990 }
00991
00992 #if (IDE_SUPPORT_WRITE == 1)
00993
00994
00995
00996
00997
00998
00999
01000 static BYTE WriteSectors(WORD bDevice, BYTE * pData, DWORD dwStartSector, WORD wSectorCount)
01001 {
01002 WORD i;
01003 int x;
01004 int nError;
01005 BYTE bValue;
01006 BYTE bStatus;
01007 BYTE bErrorReg;
01008 LPDRIVE pDrive;
01009
01010 #if (IDE_SUPPORT_CHS == 1)
01011 WORD wCHSSector;
01012 WORD wCHSHead;
01013 WORD wCHSCylinder;
01014 #endif
01015
01016 pDrive = &sDrive[bDevice];
01017 nError = SelectDevice(bDevice);
01018
01019 #if (IDE_SUPPORT_CHS == 0)
01020
01021
01022
01023 if ((pDrive->wFlags & IDE_SUPPORT_LBA) == 0) {
01024
01025
01026
01027 nError = IDE_ERROR;
01028 }
01029 #endif
01030
01031 if (nError == IDE_OK) {
01032
01033 if (pDrive->wFlags & IDE_SUPPORT_LBA) {
01034
01035
01036
01037 bValue = (BYTE) ((bDevice << 4) | 0xE0 | (dwStartSector >> 24));
01038 IDEOut(DISK_HEAD_REG, bValue);
01039 IDEOut(LBA_16_23, (BYTE) (dwStartSector >> 16));
01040 IDEOut(LBA_8_15, (BYTE) (dwStartSector >> 8));
01041 IDEOut(LBA_0_7, (BYTE) (dwStartSector));
01042
01043 IDEOut(SECTOR_COUNT_REG, (BYTE) (wSectorCount & 0xff));
01044 IDEOut(COMMAND_REG, COMMAND_WRITE_SECTORS);
01045
01046 #if (IDE_SUPPORT_CHS == 1)
01047 } else {
01048
01049
01050
01051 wCHSSector = (WORD) (dwStartSector % pDrive->wSectorsPerTrack) + 1;
01052 wCHSHead = (WORD) (dwStartSector / pDrive->dwOneSide);
01053 dwStartSector = dwStartSector % pDrive->dwOneSide;
01054 wCHSCylinder = (WORD) (dwStartSector / pDrive->wSectorsPerTrack);
01055
01056 wCHSHead |= (bDevice << 4) | 0xA0;
01057
01058 IDEOut(DISK_HEAD_REG, (BYTE) wCHSHead);
01059 IDEOut(SECTOR_REG, (BYTE) wCHSSector);
01060 IDEOut(CYLINDER_LOW_REG, (BYTE) (wCHSCylinder & 0x00FF));
01061 IDEOut(CYLINDER_HIGH_REG, (BYTE) (wCHSCylinder >> 8));
01062
01063 IDEOut(SECTOR_COUNT_REG, (BYTE) (wSectorCount & 0xff));
01064 IDEOut(COMMAND_REG, COMMAND_WRITE_SECTORS);
01065 #endif
01066 }
01067
01068 if (WaitDRQ(CONTROLLERTIMEOUT) == IDE_OK) {
01069
01070 bStatus = IDEIn(STATUS_REG);
01071 for (i = 0; i < wSectorCount; i++) {
01072
01073 for (x = 0; x < IDE_SECTOR_SIZE; x = x + 2) {
01074 if (pDrive->bIDEMode == MEM_8BIT_COMPACT_FLASH) {
01075 IDEOut(DATA_WRITE_REG_LOW, pData[x]);
01076 IDEOut(DATA_WRITE_REG_LOW, pData[x + 1]);
01077 } else {
01078 IDEOut(DATA_WRITE_REG_HIGH, pData[x + 1]);
01079 IDEOut(DATA_WRITE_REG_LOW, pData[x]);
01080 }
01081 }
01082
01083 pData += IDE_SECTOR_SIZE;
01084
01085 nError = WaitForInterrupt(DISKTIMEOUT);
01086 if (nError == IDE_OK) {
01087 bStatus = gbIntStatus;
01088
01089 if ((bStatus & STATUS_ERROR) == STATUS_ERROR) {
01090 bErrorReg = IDEIn(ERROR_REG);
01091 nError = IDE_ERROR;
01092 break;
01093 }
01094 } else {
01095
01096
01097
01098 nError = IDE_ERROR;
01099 break;
01100 }
01101 }
01102
01103 } else {
01104
01105
01106
01107 WaitForInterrupt(DISKTIMEOUT);
01108 bErrorReg = IDEIn(ERROR_REG);
01109 }
01110
01111 }
01112
01113 return (nError);
01114 }
01115 #endif
01116
01117
01118
01119
01120 THREAD(CFChange, arg)
01121 {
01122 BYTE bNewStatus;
01123 BYTE *pSectorBuffer;
01124
01125 while (1) {
01126
01127 NutEventWaitNext(&hCFChangeInt, 0);
01128
01129
01130
01131 NutSleep(2000);
01132
01133 bNewStatus = (PINE & BV(CF_IRQ));
01134 if (bNewStatus != gbCFMountStatus) {
01135
01136 if (bNewStatus == CF_AVAILABLE) {
01137 gbCFMountStatus = CF_AVAILABLE;
01138
01139
01140
01141 HardwareReset(&sDrive[0]);
01142
01143 pSectorBuffer = (BYTE *) NutHeapAlloc(IDE_SECTOR_SIZE);
01144 if (pSectorBuffer != NULL) {
01145 IDEMountDevice(IDE_DRIVE_C, pSectorBuffer);
01146 NutHeapFree(pSectorBuffer);
01147
01148 if (pUserMountFunc != NULL) {
01149 pUserMountFunc(IDE_DRIVE_C);
01150 }
01151 }
01152
01153 NutEnterCritical();
01154 EICR &= ~CF_INT_SENS_MASK;
01155 EICR |= CF_INT_RISING_EDGE;
01156 NutExitCritical();
01157
01158 } else {
01159 gbCFMountStatus = CF_NOT_AVAILABLE;
01160
01161
01162
01163
01164 IDEUnMountDevice(IDE_DRIVE_C);
01165
01166 if (pUserUnMountFunc != NULL) {
01167 pUserUnMountFunc(IDE_DRIVE_C);
01168 }
01169
01170 NutEnterCritical();
01171 EICR &= ~CF_INT_SENS_MASK;
01172 EICR |= CF_INT_FALLING_EDGE;
01173 NutExitCritical();
01174 }
01175 }
01176 }
01177 }
01178
01179
01180
01181
01182
01183
01184
01185 int IDEInit(int nBaseAddress, int nIDEMode, IDE_MOUNT_FUNC * pMountFunc, IDE_MOUNT_FUNC * pUnMountFunc)
01186 {
01187 int i;
01188 int nError;
01189 BYTE bValue;
01190
01191 pUserMountFunc = pMountFunc;
01192 pUserUnMountFunc = pUnMountFunc;
01193
01194
01195
01196
01197 if (nBaseAddress == 0) {
01198 nBaseAddress = IDE_BASE_ADDRESS;
01199 }
01200
01201
01202
01203
01204
01205
01206
01207 #ifdef __AVR_ENHANCED__
01208 XMCRA = _BV(SRW11);
01209 #endif
01210
01211
01212
01213
01214 DDRD = 0x20;
01215
01216
01217 for (i = 0; i < IDE_MAX_SUPPORTED_DEVICE; i++) {
01218 memset((BYTE *) & sDrive[i], 0x00, sizeof(DRIVE));
01219
01220 sDrive[i].bDevice = (BYTE) i;
01221 sDrive[i].bIDEMode = (BYTE) nIDEMode;
01222 }
01223
01224 IDESemaInit();
01225
01226 pIDE = (unsigned char *) nBaseAddress;
01227
01228 ClearEvent(&hIDEEvent);
01229
01230 NutEnterCritical();
01231
01232
01233
01234
01235 gbIntStatus = 0;
01236
01237
01238
01239
01240 nError = NutRegisterIrqHandler(&sig_INTERRUPT7, IDEInterrupt, NULL);
01241 if (nError == FALSE) {
01242 EICR |= IDE_INT_RISING_EDGE;
01243 sbi(EIMSK, IDE_IRQ);
01244 }
01245
01246 switch (nIDEMode) {
01247 case IDE_HARDDISK:{
01248 break;
01249 }
01250
01251
01252
01253
01254
01255
01256
01257
01258 case IDE_HARDDISK_7MHZ:{
01259 #if defined(CLKPR)
01260 CLKPR = _BV(CLKPCE);
01261 CLKPR = 2;
01262 #else
01263 XDIV = 0xff;
01264 #endif
01265 break;
01266 }
01267 case IDE_COMPACT_FLASH:{
01268 break;
01269 }
01270 case MEM_8BIT_COMPACT_FLASH:{
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280 EICR &= ~CF_INT_SENS_MASK;
01281
01282
01283
01284
01285 bValue = (PINE & BV(CF_IRQ));
01286 if (bValue == CF_AVAILABLE) {
01287 gbCFMountStatus = CF_AVAILABLE;
01288
01289
01290
01291
01292
01293 EICR |= CF_INT_RISING_EDGE;
01294 } else {
01295 gbCFMountStatus = CF_NOT_AVAILABLE;
01296
01297
01298
01299
01300
01301 EICR |= CF_INT_FALLING_EDGE;
01302 }
01303
01304 nError = NutRegisterIrqHandler(&sig_INTERRUPT6, CFInterrupt, NULL);
01305 if (nError == FALSE) {
01306 NutThreadCreate("cfchange", CFChange, NULL, 640);
01307 sbi(EIMSK, CF_IRQ);
01308 }
01309
01310 break;
01311 }
01312 }
01313 NutExitCritical();
01314
01315 HardwareReset(&sDrive[0]);
01316
01317 nError = IDE_OK;
01318
01319 return (nError);
01320 }
01321
01322
01323
01324
01325 int IDEMountDevice(BYTE bDevice, BYTE * pSectorBuffer)
01326 {
01327 int nError;
01328 LPDRIVE pDrive;
01329
01330 pDrive = NULL;
01331
01332 IDELock();
01333
01334 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01335 nError = IDE_ERROR;
01336 } else {
01337 pDrive = &sDrive[bDevice];
01338
01339 pDrive->wFlags = 0;
01340
01341 #if (IDE_SUPPORT_CHS == 1)
01342
01343
01344
01345 pDrive->wCylinders = 0;
01346 pDrive->wHeads = 0;
01347 pDrive->wSectorsPerTrack = 0;
01348 #endif
01349
01350
01351
01352
01353 pDrive->dwTotalSectors = 0;
01354
01355 nError = DeviceDiag(pDrive);
01356 if (pDrive->wFlags & IDE_SUPPORT_PACKET) {
01357 #if (IDE_SUPPORT_ATAPI == 1)
01358 pDrive->wSectorSize = ATAPI_SECTOR_SIZE;
01359 nError = GetDeviceInfoPacket(pDrive, pSectorBuffer);
01360 if (pDrive->wFlags & IDE_READY) {
01361 nError = IDE_OK;
01362 }
01363 #endif
01364 } else {
01365 if (nError != IDE_OK) {
01366
01367
01368
01369 nError = DeviceDiag(pDrive);
01370 }
01371
01372 if (nError == IDE_OK) {
01373 pDrive->wSectorSize = IDE_SECTOR_SIZE;
01374 nError = GetDeviceInfo(pDrive, pSectorBuffer);
01375 if (pDrive->wFlags & IDE_READY) {
01376 nError = IDE_OK;
01377 }
01378 }
01379 }
01380
01381 }
01382
01383 IDEFree();
01384
01385 return (nError);
01386 }
01387
01388
01389
01390
01391 int IDEGetSectorSize(BYTE bDevice)
01392 {
01393 int nSectorSize;
01394 LPDRIVE pDrive;
01395
01396 nSectorSize = 0;
01397
01398 IDELock();
01399
01400 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01401 nSectorSize = 0;
01402 } else {
01403 pDrive = &sDrive[bDevice];
01404 nSectorSize = pDrive->wSectorSize;
01405 }
01406
01407 IDEFree();
01408
01409 return (nSectorSize);
01410 }
01411
01412
01413
01414
01415 int IDEIsCDROMDevice(BYTE bDevice)
01416 {
01417 int nIsCDROM;
01418 LPDRIVE pDrive;
01419
01420 nIsCDROM = FALSE;
01421
01422 IDELock();
01423
01424 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01425 nIsCDROM = FALSE;
01426 } else {
01427 pDrive = &sDrive[bDevice];
01428 if ((pDrive->wFlags & IDE_READY) && (pDrive->wFlags & IDE_CDROM_DEVICE)) {
01429 nIsCDROM = TRUE;
01430 }
01431 }
01432
01433 IDEFree();
01434
01435 return (nIsCDROM);
01436 }
01437
01438
01439
01440
01441 int IDEIsZIPDevice(BYTE bDevice)
01442 {
01443 int nIsZIP;
01444 LPDRIVE pDrive;
01445
01446 nIsZIP = FALSE;
01447
01448 IDELock();
01449
01450 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01451 nIsZIP = FALSE;
01452 } else {
01453 pDrive = &sDrive[bDevice];
01454 if ((pDrive->wFlags & IDE_READY) && (pDrive->wFlags & IDE_ZIP_DEVICE)) {
01455 nIsZIP = TRUE;
01456 }
01457 }
01458
01459 IDEFree();
01460
01461 return (nIsZIP);
01462 }
01463
01464
01465
01466
01467 int IDEUnMountDevice(BYTE bDevice)
01468 {
01469 int nError = 0;
01470 LPDRIVE pDrive;
01471
01472 pDrive = NULL;
01473
01474 IDELock();
01475
01476 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01477 nError = IDE_ERROR;
01478 } else {
01479 pDrive = &sDrive[bDevice];
01480
01481 pDrive->wFlags = 0;
01482 }
01483
01484 IDEFree();
01485
01486 return (nError);
01487 }
01488
01489
01490
01491
01492 DWORD IDEGetTotalSectors(BYTE bDevice)
01493 {
01494 DWORD dwTotalSectors;
01495 LPDRIVE pDrive;
01496
01497 dwTotalSectors = 0;
01498
01499 IDELock();
01500
01501 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01502 dwTotalSectors = 0;
01503 } else {
01504 pDrive = &sDrive[bDevice];
01505 dwTotalSectors = pDrive->dwTotalSectors;
01506
01507 dwTotalSectors -= 64;
01508 }
01509
01510 IDEFree();
01511
01512 return (dwTotalSectors);
01513 }
01514
01515
01516
01517
01518 int IDEReadSectors(BYTE bDevice, void *pData, DWORD dwStartSector, WORD wSectorCount)
01519 {
01520 WORD i;
01521 int nError;
01522 WORD wReadCount;
01523 LPDRIVE pDrive = 0;
01524 BYTE *pByte;
01525
01526 nError = IDE_OK;
01527
01528 IDELock();
01529
01530 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01531 nError = IDE_DRIVE_NOT_FOUND;
01532 } else {
01533 pDrive = &sDrive[bDevice];
01534 if ((pDrive->wFlags & IDE_READY) == 0) {
01535 nError = IDE_DRIVE_NOT_FOUND;
01536 } else {
01537 if ((dwStartSector + wSectorCount) > pDrive->dwTotalSectors) {
01538 nError = IDE_PARAM_ERROR;
01539 }
01540 }
01541 }
01542
01543 if ((pDrive->wFlags & IDE_SUPPORT_PACKET) && ((wSectorCount > 1))) {
01544
01545
01546
01547
01548 nError = IDE_PARAM_ERROR;
01549 }
01550
01551 if ((pDrive->wFlags & IDE_SUPPORT_PACKET) && (nError == IDE_OK)) {
01552 #if (IDE_SUPPORT_ATAPI == 1)
01553
01554
01555
01556 ATAPI_CMD(ATAPI_CMD_READ12);
01557 i = 5;
01558 while (dwStartSector) {
01559 aATAPICmd[i--] = (BYTE) dwStartSector;
01560 dwStartSector >>= 8;
01561 }
01562
01563
01564
01565 aATAPICmd[9] = 1;
01566 nError = ATAPISendCommand(pDrive, pData, &i);
01567 if ((nError != IDE_OK) || (i != pDrive->wSectorSize)) {
01568 nError = IDE_ERROR;
01569 }
01570 #else
01571 nError = IDE_ERROR;
01572 #endif
01573 } else {
01574 if (nError == IDE_OK) {
01575 pByte = (BYTE *) pData;
01576 while (wSectorCount > 0) {
01577
01578 if (wSectorCount < 256) {
01579 wReadCount = wSectorCount;
01580 } else {
01581 wReadCount = 256;
01582 }
01583
01584 nError = ReadSectors(bDevice, pByte, dwStartSector, wReadCount);
01585 if (nError != IDE_OK) {
01586 break;
01587 }
01588
01589 dwStartSector += wReadCount;
01590 wSectorCount -= wReadCount;
01591 pByte += (wReadCount * pDrive->wSectorSize);
01592 }
01593 }
01594 }
01595
01596 IDEFree();
01597
01598 return (nError);
01599 }
01600
01601 #if (IDE_SUPPORT_WRITE == 1)
01602
01603
01604
01605 int IDEWriteSectors(BYTE bDevice, void *pData, DWORD dwStartSector, WORD wSectorCount)
01606 {
01607 int nError;
01608 WORD wWriteCount;
01609 LPDRIVE pDrive;
01610 BYTE *pByte;
01611
01612 nError = IDE_OK;
01613 pDrive = NULL;
01614
01615 IDELock();
01616
01617 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01618 nError = IDE_DRIVE_NOT_FOUND;
01619 } else {
01620 pDrive = &sDrive[bDevice];
01621
01622 if ((dwStartSector + wSectorCount) > pDrive->dwTotalSectors) {
01623 nError = IDE_PARAM_ERROR;
01624 }
01625 if ((pDrive->wFlags & IDE_READY) == 0) {
01626 nError = IDE_DRIVE_NOT_FOUND;
01627 }
01628 if (pDrive->wFlags & IDE_READ_ONLY) {
01629 nError = IDE_NOT_SUPPORTED;
01630 }
01631 }
01632
01633 if (nError == IDE_OK) {
01634 pByte = (BYTE *) pData;
01635 while (wSectorCount > 0) {
01636
01637 if (wSectorCount < 256) {
01638 wWriteCount = wSectorCount;
01639 } else {
01640 wWriteCount = 256;
01641 }
01642
01643 nError = WriteSectors(bDevice, pByte, dwStartSector, wWriteCount);
01644 if (nError != IDE_OK) {
01645 break;
01646 }
01647
01648 dwStartSector += wWriteCount;
01649 wSectorCount -= wWriteCount;
01650 pByte += (wWriteCount * IDE_SECTOR_SIZE);
01651 }
01652 }
01653
01654 IDEFree();
01655
01656 return (nError);
01657 }
01658 #endif
01659
01660 #if (IDE_SUPPORT_ATAPI == 1)
01661
01662
01663
01664 int IDEATAPISetCDSpeed(BYTE bDevice, WORD wSpeed)
01665 {
01666 WORD i;
01667 int nError;
01668 LPDRIVE pDrive;
01669
01670 nError = IDE_OK;
01671 pDrive = NULL;
01672
01673 if (bDevice >= IDE_MAX_SUPPORTED_DEVICE) {
01674 nError = IDE_DRIVE_NOT_FOUND;
01675 } else {
01676 pDrive = &sDrive[bDevice];
01677 if ((pDrive->wFlags & IDE_READY) == 0) {
01678 nError = IDE_DRIVE_NOT_FOUND;
01679 }
01680 if ((pDrive->wFlags & IDE_SUPPORT_PACKET) == 0) {
01681 nError = IDE_NOT_SUPPORTED;
01682 }
01683 }
01684
01685 if (nError == IDE_OK) {
01686 ATAPI_CMD(0xBB);
01687 aATAPICmd[2] = (BYTE) ((wSpeed >> 8) & 0x00FF);
01688 aATAPICmd[3] = (BYTE) (wSpeed & 0x00FF);
01689 nError = ATAPISendCommand(pDrive, NULL, &i);
01690 }
01691
01692 return (nError);
01693 }
01694 #endif