Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

# ata.c

Go to the documentation of this file.

    00001 /*! \file ata.c \brief IDE-ATA hard disk interface driver. */
    00002 //*****************************************************************************
    00003 //
    00004 // File Name    : 'ata.c'
    00005 // Title        : IDE-ATA interface driver for hard disks
    00006 // Author       : Pascal Stang
    00007 // Date         : 11/22/2000
    00008 // Revised      : 4/19/2003
    00009 // Version      : 0.3
    00010 // Target MCU   : Atmel AVR Series
    00011 // Editor Tabs  : 4
    00012 //
    00013 // NOTE: This code is currently below version 1.0, and therefore is considered
    00014 // to be lacking in some functionality or documentation, or may not be fully
    00015 // tested.  Nonetheless, you can expect most functions to work.
    00016 //
    00017 // This code is distributed under the GNU Public License
    00018 //      which can be found at http://www.gnu.org/licenses/gpl.txt
    00019 //
    00020 //*****************************************************************************
    00021
    00022 #ifndef WIN32
    00023     #include <avr/io.h>
    00024     #include <avr/interrupt.h>
    00025     #include <avr/pgmspace.h>
    00026 //  #include <stdio.h>
    00027 #endif
    00028 #include "global.h"
    00029 #include "timer.h"
    00030 #include "rprintf.h"
    00031
    00032 #include "ata.h"
    00033
    00034 //#define DEBUG_ATA 1
    00035
    00036 // global variables
    00037
    00038 // drive information
    00039 typeDriveInfo ataDriveInfo;
    00040
    00041
    00042 void ataInit(void)
    00043 {
    00044
    00045 }
    00046
    00047 void ataDriveInit(void)
    00048 {
    00049     u08 i;
    00050     unsigned char* buffer = (unsigned char*) SECTOR_BUFFER_ADDR;
    00051
    00052     // read drive identity
    00053     rprintfProgStrM("\r\nScanning IDE interface...\r\n");
    00054     // Wait for drive to be ready
    00055     ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
    00056     // issue identify command
    00057     ataWriteByte(ATA_REG_CMDSTATUS1, 0xEC);
    00058     // wait for drive to request data transfer
    00059     ataStatusWait(ATA_SR_DRQ, ATA_SR_DRQ);
    00060     timerPause(200);
    00061     // read in the data
    00062     ataReadDataBuffer(buffer, 512);
    00063
    00064     // set local drive info parameters
    00065     ataDriveInfo.cylinders =        *( ((unsigned int*) buffer) + ATA_IDENT_CYLINDERS );
    00066     ataDriveInfo.heads =            *( ((unsigned int*) buffer) + ATA_IDENT_HEADS );
    00067     ataDriveInfo.sectors =          *( ((unsigned int*) buffer) + ATA_IDENT_SECTORS );
    00068     ataDriveInfo.LBAsupport =       *( ((unsigned int*) buffer) + ATA_IDENT_FIELDVALID );
    00069     ataDriveInfo.sizeinsectors =    *( (unsigned long*) (buffer + ATA_IDENT_LBASECTORS*2) );
    00070     // copy model string
    00071     for(i=0; i<40; i+=2)
    00072     {
    00073         // correct for byte order
    00074         ataDriveInfo.model[i  ] = buffer[(ATA_IDENT_MODEL*2) + i + 1];
    00075         ataDriveInfo.model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i    ];
    00076     }
    00077     // terminate string
    00078     ataDriveInfo.model[40] = 0;
    00079
    00080     // process and print info
    00081     if(ataDriveInfo.LBAsupport)
    00082     {
    00083         // LBA support
    00084         rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) );
    00085         rprintf("LBA mode -- MODEL: ");
    00086     }
    00087     else
    00088     {
    00089         // CHS, no LBA support
    00090         // calculate drive size
    00091         ataDriveInfo.sizeinsectors = (unsigned long) ataDriveInfo.cylinders*
    00092                                                 ataDriveInfo.heads*ataDriveInfo.sectors;
    00093         rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) );
    00094         rprintf("CHS mode C=%d H=%d S=%d -- MODEL: ", ataDriveInfo.cylinders, ataDriveInfo.heads, ataDriveInfo.sectors );
    00095     }
    00096     // print model information
    00097     rprintfStr(ataDriveInfo.model); rprintfCRLF();
    00098
    00099     // initialize local disk parameters
    00100     //ataDriveInfo.cylinders = ATA_DISKPARM_CLYS;
    00101     //ataDriveInfo.heads = ATA_DISKPARM_HEADS;
    00102     //ataDriveInfo.sectors = ATA_DISKPARM_SECTORS;
    00103
    00104 }
    00105
    00106 void ataDiskErr(void)
    00107 {
    00108     unsigned char b;
    00109
    00110     b = ataReadByte(ATA_REG_ERROR);
    00111     rprintfProgStrM("ATA Error: ");
    00112     rprintfu08(b);
    00113     rprintfCRLF();
    00114 }
    00115
    00116 void ataSetDrivePowerMode(u08 DriveNo, u08 mode, u08 timeout)
    00117 {
    00118     // select drive
    00119     ataDriveSelect(DriveNo);
    00120     // Wait for drive to be ready
    00121     ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
    00122
    00123     // set mode
    00124     switch(mode)
    00125     {
    00126     case ATA_DISKMODE_SPINDOWN:     ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINDOWN); break;
    00127     case ATA_DISKMODE_SPINUP:       ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINUP); break;
    00128     case ATA_DISKMODE_SETTIMEOUT:
    00129         ataWriteByte(ATA_REG_SECCOUNT, timeout);
    00130         ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_IDLE_5SU);
    00131         break;
    00132     case ATA_DISKMODE_SLEEP:        ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SLEEP); break;
    00133     default:
    00134         break;
    00135     }
    00136 }
    00137
    00138 void ataPrintSector( u08 *Buffer)
    00139 {
    00140     u08 i;
    00141     u16 j;
    00142     u08 *buf;
    00143     u08 s;
    00144
    00145     buf = Buffer;
    00146
    00147     // print the low order address indicies
    00148     rprintfProgStrM("     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F  0123456789ABCDEF\r\n");
    00149     rprintfProgStrM("     -----------------------------------------------  ---- ASCII -----\r\n");
    00150
    00151     // print the data
    00152     for(j=0; j<0x20; j++)
    00153     {
    00154         // print the high order address index for this line
    00155         rprintfu16(j<<4);
    00156         rprintfProgStrM(" ");
    00157
    00158         // print the hex data
    00159         for(i=0; i<0x10; i++)
    00160         {
    00161             rprintfu08(buf[(j<<4)+i]);
    00162             rprintfProgStrM(" ");
    00163         }
    00164
    00165         // leave some space
    00166         rprintfProgStrM(" ");
    00167
    00168         // print the ascii data
    00169         for(i=0; i<0x10; i++)
    00170         {
    00171             s = buf[(j<<4)+i];
    00172             // make sure character is printable
    00173             if(s >= 0x20)
    00174             {
    00175                 rprintfChar(s);
    00176             }
    00177             else
    00178             {
    00179                 rprintfChar(0x20);
    00180             }
    00181
    00182         }
    00183         rprintfCRLF();
    00184     }
    00185 }
    00186
    00187 void ataReadDataBuffer(u08 *Buffer, u16 numBytes)
    00188 {
    00189     unsigned int i;
    00190
    00191     //sbi(MCUCR, SRW);          // enable RAM waitstate
    00192
    00193     // read data from drive
    00194     for (i=0; i<(numBytes/16); i++)
    00195     {
    00196         // optimize by reading 16 bytes in-line before looping
    00197         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00198         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00199         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00200         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00201         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00202         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00203         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00204         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00205         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00206         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00207         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00208         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00209         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00210         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00211         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
    00212         *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
    00213     }
    00214     //cbi(MCUCR, SRW);          // disable RAM waitstate
    00215
    00216 }
    00217
    00218 void ataWriteDataBuffer(u08 *Buffer, u16 numBytes)
    00219 {
    00220     register unsigned char temp;
    00221     unsigned int i;
    00222
    00223     //sbi(MCUCR, SRW);          // enable RAM waitstate
    00224
    00225     // write data to drive
    00226     for (i=0; i<(numBytes/16); i++)
    00227     {
    00228         // optimize by writing 16 bytes in-line before looping
    00229         // keep byte order correct by using temp register
    00230         temp = *Buffer++;
    00231         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00232         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00233         temp = *Buffer++;
    00234         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00235         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00236         temp = *Buffer++;
    00237         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00238         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00239         temp = *Buffer++;
    00240         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00241         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00242         temp = *Buffer++;
    00243         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00244         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00245         temp = *Buffer++;
    00246         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00247         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00248         temp = *Buffer++;
    00249         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00250         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00251         temp = *Buffer++;
    00252         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
    00253         *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
    00254     }
    00255     //cbi(MCUCR, SRW);          // disable RAM waitstate
    00256
    00257 }
    00258
    00259 u08 ataStatusWait(u08 mask, u08 waitStatus)
    00260 {
    00261     register u08 status;
    00262
    00263     delay(100);
    00264
    00265     // wait for desired status
    00266     while( ((status = ataReadByte(ATA_REG_CMDSTATUS1)) & mask) == waitStatus );
    00267
    00268     return status;
    00269 }
    00270
    00271
    00272 unsigned char ataReadSectorsCHS(    unsigned char Drive,
    00273                                             unsigned char Head,
    00274                                             unsigned int Track,
    00275                                             unsigned char Sector,
    00276                                             unsigned int numsectors,
    00277                                             unsigned char *Buffer)
    00278 {
    00279     unsigned char temp;
    00280
    00281     // Wait for drive to be ready
    00282     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
    00283
    00284     // Prepare parameters...
    00285     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head
    00286     ataWriteByte(ATA_REG_CYLHI, Track>>8);          // MSB of track
    00287     ataWriteByte(ATA_REG_CYLLO, Track);             // LSB of track
    00288     ataWriteByte(ATA_REG_STARTSEC, Sector);     // sector
    00289     ataWriteByte(ATA_REG_SECCOUNT, numsectors); // # of sectors
    00290
    00291     // Issue read sector command...
    00292     ataWriteByte(ATA_REG_CMDSTATUS1, 0x21);
    00293
    00294     // Wait for drive to be ready
    00295     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
    00296
    00297     if (temp & ATA_SR_ERR)
    00298     {
    00299         rprintfProgStrM("RD ERR\r\n");
    00300         return 1;
    00301     }
    00302
    00303     // Wait for drive to request data transfer
    00304     ataStatusWait(ATA_SR_DRQ, 0);
    00305
    00306     // read data from drive
    00307     ataReadDataBuffer(Buffer, 512*numsectors);
    00308
    00309     // Return the error bit from the status register...
    00310     temp = ataReadByte(ATA_REG_CMDSTATUS1); // read status register
    00311
    00312     return (temp & ATA_SR_ERR) ? 1:0;
    00313 }
    00314
    00315
    00316 unsigned char ataWriteSectorsCHS(unsigned char Drive,
    00317                                             unsigned char Head,
    00318                                             unsigned int Track,
    00319                                             unsigned char Sector,
    00320                                             unsigned int numsectors,
    00321                                             unsigned char *Buffer)
    00322 {
    00323     unsigned char temp;
    00324
    00325     // Wait for drive to be ready
    00326     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
    00327
    00328     // Prepare parameters...
    00329     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head
    00330     ataWriteByte(ATA_REG_CYLHI, Track>>8);          // MSB of track
    00331     ataWriteByte(ATA_REG_CYLLO, Track);             // LSB of track
    00332     ataWriteByte(ATA_REG_STARTSEC, Sector);     // sector
    00333     ataWriteByte(ATA_REG_SECCOUNT, numsectors); // # of sectors
    00334
    00335     // Issue write sector command
    00336     ataWriteByte(ATA_REG_CMDSTATUS1, 0x31);
    00337
    00338     //delay(100);
    00339
    00340     // Wait for drive to request data transfer
    00341     ataStatusWait(ATA_SR_DRQ, 0);
    00342
    00343     // write data to drive
    00344     ataWriteDataBuffer(Buffer, 512*numsectors);
    00345
    00346     // Wait for drive to finish write
    00347     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
    00348
    00349     // check for errors
    00350     if (temp & ATA_SR_ERR)
    00351     {
    00352         rprintfProgStrM("WR ERR\r\n");
    00353         return 1;
    00354     }
    00355
    00356     // Return the error bit from the status register...
    00357     return (temp & ATA_SR_ERR) ? 1:0;
    00358 }
    00359
    00360 unsigned char ataReadSectorsLBA(    unsigned char Drive,
    00361                                             unsigned long lba,
    00362                                             unsigned int numsectors,
    00363                                     unsigned char *Buffer)
    00364 {
    00365     unsigned int cyl, head, sect;
    00366     unsigned char temp;
    00367
    00368 #ifdef DEBUG_ATA
    00369     rprintfProgStrM("ATA LBA read ");
    00370     rprintfu32(lba); rprintfProgStrM(" ");
    00371     rprintfu16(numsectors); rprintfProgStrM(" ");
    00372     rprintfu16((unsigned int)Buffer);
    00373     rprintfCRLF();
    00374 #endif
    00375
    00376     sect = (int) ( lba & 0x000000ffL );
    00377     lba = lba >> 8;
    00378     cyl = (int) ( lba & 0x0000ffff );
    00379     lba = lba >> 16;
    00380     head = ( (int) ( lba & 0x0fL ) ) | ATA_HEAD_USE_LBA;
    00381
    00382     temp = ataReadSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer );
    00383
    00384     if(temp)
    00385         ataDiskErr();
    00386     return temp;
    00387 }
    00388
    00389 unsigned char ataWriteSectorsLBA(   unsigned char Drive,
    00390                                                 unsigned long lba,
    00391                                                 unsigned int numsectors,
    00392                                         unsigned char *Buffer)
    00393 {
    00394     unsigned int cyl, head, sect;
    00395     unsigned char temp;
    00396
    00397 #ifdef DEBUG_ATA
    00398     rprintfProgStrM("ATA LBA write ");
    00399     rprintfu32(lba); rprintfProgStrM(" ");
    00400     rprintfu16(numsectors); rprintfProgStrM(" ");
    00401     rprintfu16((unsigned int)Buffer);
    00402     rprintfCRLF();
    00403 #endif
    00404
    00405     sect = (int) ( lba & 0x000000ffL );
    00406     lba = lba >> 8;
    00407     cyl = (int) ( lba & 0x0000ffff );
    00408     lba = lba >> 16;
    00409     head = ( (int) ( lba & 0x0fL ) ) | ATA_HEAD_USE_LBA;
    00410
    00411     temp = ataWriteSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer );
    00412
    00413     if(temp)
    00414         ataDiskErr();
    00415     return temp;
    00416 }
    00417
    00418
    00419 unsigned char ataReadSectors(   unsigned char Drive,
    00420                                         unsigned long lba,
    00421                                         unsigned int numsectors,
    00422                                 unsigned char *Buffer)
    00423 {
    00424     unsigned int cyl, head, sect;
    00425     unsigned char temp;
    00426
    00427     // check if drive supports native LBA mode
    00428     if(ataDriveInfo.LBAsupport)
    00429     {
    00430         // drive supports using native LBA
    00431         temp = ataReadSectorsLBA(Drive, lba, numsectors, Buffer);
    00432     }
    00433     else
    00434     {
    00435         // drive required CHS access
    00436         #ifdef DEBUG_ATA
    00437             // do this defore destroying lba
    00438             rprintfProgStrM("ATA LBA for CHS read: ");
    00439             rprintfProgStrM("LBA="); rprintfu32(lba); rprintfProgStrM(" ");
    00440         #endif
    00441
    00442         // convert LBA to pseudo CHS
    00443         // remember to offset the sector count by one
    00444         sect = (u08) (lba % ataDriveInfo.sectors)+1;
    00445         lba = lba / ataDriveInfo.sectors;
    00446         head = (u08) (lba % ataDriveInfo.heads);
    00447         lba = lba / ataDriveInfo.heads;
    00448         cyl = (u16) lba;
    00449
    00450         #ifdef DEBUG_ATA
    00451             rprintfProgStrM("C:H:S=");
    00452             rprintfu16(cyl); rprintfProgStrM(":");
    00453             rprintfu08(head); rprintfProgStrM(":");
    00454             rprintfu08(sect); rprintfCRLF();
    00455         #endif
    00456
    00457         temp = ataReadSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer );
    00458     }
    00459
    00460     if(temp)
    00461         ataDiskErr();
    00462     return temp;
    00463 }
    00464
    00465
    00466 unsigned char ataWriteSectors(unsigned char Drive,
    00467                                         unsigned long lba,
    00468                                         unsigned int numsectors,
    00469                                 unsigned char *Buffer)
    00470 {
    00471     unsigned int cyl, head, sect;
    00472     unsigned char temp;
    00473
    00474     // check if drive supports native LBA mode
    00475     if(ataDriveInfo.LBAsupport)
    00476     {
    00477         // drive supports using native LBA
    00478         temp = ataWriteSectorsLBA(Drive, lba, numsectors, Buffer);
    00479     }
    00480     else
    00481     {
    00482         // drive required CHS access
    00483         #ifdef DEBUG_ATA
    00484             // do this defore destroying lba
    00485             rprintfProgStrM("ATA LBA for CHS write: ");
    00486             rprintfProgStrM("LBA="); rprintfu32(lba); rprintfProgStrM(" ");
    00487         #endif
    00488
    00489         // convert LBA to pseudo CHS
    00490         // remember to offset the sector count by one
    00491         sect = (u08) (lba % ataDriveInfo.sectors)+1;
    00492         lba = lba / ataDriveInfo.sectors;
    00493         head = (u08) (lba % ataDriveInfo.heads);
    00494         lba = lba / ataDriveInfo.heads;
    00495         cyl = (u16) lba;
    00496
    00497         #ifdef DEBUG_ATA
    00498             rprintfProgStrM("C:H:S=");
    00499             rprintfu16(cyl); rprintfProgStrM(":");
    00500             rprintfu08(head); rprintfProgStrM(":");
    00501             rprintfu08(sect); rprintfCRLF();
    00502         #endif
    00503
    00504         temp = ataWriteSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer );
    00505     }
    00506
    00507     if(temp)
    00508         ataDiskErr();
    00509     return temp;
    00510 }
    00511
    00512 void ataDriveSelect(u08 DriveNo)
    00513 {
    00514     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(DriveNo ? 0x10:00)); // Drive selection
    00515 }
    00516
    00517 //----------------------------------------------------------------------------
    00518 // Set drive mode (STANDBY, IDLE)
    00519 //----------------------------------------------------------------------------
    00520 /*#define STANDBY 0
    00521 #define IDLE    1
    00522 #define SLEEP   2
    00523 */
    00524
    00525 /*
    00526 unsigned char SetMode(unsigned char DriveNo, unsigned char Mode, unsigned char PwrDown)
    00527 {
    00528   WriteBYTE(CMD, 6, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive
    00529   WriteBYTE(CMD, 2, (PwrDown ? 0x01:0x00)); // Enable automatic power down
    00530   switch (Mode)
    00531   {
    00532     case STANDBY: WriteBYTE(CMD,7, 0xE2); break;
    00533     case IDLE:    WriteBYTE(CMD,7, 0xE3); break;
    00534     // NOTE: To recover from sleep, either issue a soft or hardware reset !
    00535     // (But not on all drives, f.ex seagate ST3655A it's not nessecary to reset
    00536     // but only to go in Idle mode, But on a Conner CFA170A it's nessecary with
    00537     // a reset)
    00538     case SLEEP:   WriteBYTE(CMD,7, 0xE6); break;
    00539   }
    00540   Timer10mSec=10000;
    00541   while ((ReadBYTE(CMD,7) & 0xC0)!=0x40 && Timer10mSec); // Wait for DRDY & NOT BUSY
    00542   if (Timer10mSec==0) return 0xFF;                       //   or timeout
    00543
    00544   // Return the error register...
    00545   return ReadBYTE(CMD, 1);
    00546 }
    00547
    00548 */
    00549
    00550 u08 ataReadByte(u08 reg)
    00551 {
    00552     register u08 ret;
    00553     //sbi(MCUCR, SRW);          // enable RAM waitstate
    00554     ret = *((volatile unsigned char*) ATA_REG_BASE + reg);
    00555     //cbi(MCUCR, SRW);          // disable RAM waitstate
    00556     return ret;
    00557 }
    00558
    00559 void ataWriteByte(u08 reg, u08 data)
    00560 {
    00561     //sbi(MCUCR, SRW);          // enable RAM waitstate
    00562     *((volatile unsigned char*) ATA_REG_BASE + reg) = data;
    00563     //cbi(MCUCR, SRW);          // disable RAM waitstate
    00564 }
    00565
    00566
    00567 void ataShowRegisters(unsigned char DriveNo)
    00568 {
    00569     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive
    00570
    00571     rprintfProgStrM("R0: DATALOW  = 0x");   rprintfu08(ataReadByte(ATA_REG_DATAL    ));     rprintfProgStrM(" \r\n");
    00572     rprintfProgStrM("R1: ERROR    = 0x");   rprintfu08(ataReadByte(ATA_REG_ERROR    ));     rprintfProgStrM(" \r\n");
    00573     rprintfProgStrM("R2: SECT CNT = 0x");   rprintfu08(ataReadByte(ATA_REG_SECCOUNT));      rprintfProgStrM(" \r\n");
    00574     rprintfProgStrM("R3: SECT NUM = 0x");   rprintfu08(ataReadByte(ATA_REG_STARTSEC));      rprintfProgStrM(" \r\n");
    00575     rprintfProgStrM("R4: CYL LOW  = 0x");   rprintfu08(ataReadByte(ATA_REG_CYLLO    ));     rprintfProgStrM(" \r\n");
    00576     rprintfProgStrM("R5: CYL HIGH = 0x");   rprintfu08(ataReadByte(ATA_REG_CYLHI    ));     rprintfProgStrM(" \r\n");
    00577     rprintfProgStrM("R6: HEAD/DEV = 0x");   rprintfu08(ataReadByte(ATA_REG_HDDEVSEL));      rprintfProgStrM(" \r\n");
    00578     rprintfProgStrM("R7: CMD/STA  = 0x");   rprintfu08(ataReadByte(ATA_REG_CMDSTATUS1));    rprintfProgStrM("\r\n");
    00579 }
    00580
    00581 unsigned char ataSWReset(void)
    00582 {
    00583     ataWriteByte(ATA_REG_HDDEVSEL, 0x06);   // SRST and nIEN bits
    00584     delay(10);  // 10uS delay
    00585     ataWriteByte(ATA_REG_HDDEVSEL, 0x02);   // nIEN bits
    00586     delay(10);  // 10 uS delay
    00587
    00588    while( (ataReadByte(ATA_REG_CMDSTATUS1) & 0xC0) != 0x40 ); // Wait for DRDY and not BSY
    00589
    00590     return ataReadByte(ATA_REG_CMDSTATUS1) + ataReadByte(ATA_REG_ERROR);
    00591 }
    00592
    00593 /*
    00594 unsigned char ATA_Idle(unsigned char Drive)
    00595 {
    00596
    00597   WriteBYTE(CMD, 6, 0xA0 + (Drive ? 0x10:0x00)); // Select drive
    00598   WriteBYTE(CMD,7, 0xE1);
    00599
    00600   while ((ReadBYTE(CMD,7) & 0xC0)!=0x40); // Wait for DRDY & NOT BUSY
    00601
    00602   // Return the error register...
    00603   return ReadBYTE(CMD, 1);
    00604 }
    00605 */