00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 #ifndef WIN32
00023     #include <avr/io.h>
00024     #include <avr/interrupt.h>
00025     #include <avr/pgmspace.h>
00026 
00027 #endif
00028 #include "global.h"
00029 #include "timer.h"
00030 #include "rprintf.h"
00031 
00032 #include "ata.h"
00033 
00034 
00035 
00036 
00037 
00038 
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     
00053     rprintfProgStrM("\r\nScanning IDE interface...\r\n");
00054     
00055     ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
00056     
00057     ataWriteByte(ATA_REG_CMDSTATUS1, 0xEC);
00058     
00059     ataStatusWait(ATA_SR_DRQ, ATA_SR_DRQ);
00060     timerPause(200);
00061     
00062     ataReadDataBuffer(buffer, 512);
00063 
00064     
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     
00071     for(i=0; i<40; i+=2)
00072     {
00073         
00074         ataDriveInfo.model[i  ] = buffer[(ATA_IDENT_MODEL*2) + i + 1];
00075         ataDriveInfo.model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i    ];
00076     }
00077     
00078     ataDriveInfo.model[40] = 0;
00079 
00080     
00081     if(ataDriveInfo.LBAsupport)
00082     {
00083         
00084         rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) );
00085         rprintf("LBA mode -- MODEL: ");
00086     }
00087     else
00088     {
00089         
00090         
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     
00097     rprintfStr(ataDriveInfo.model); rprintfCRLF();
00098 
00099     
00100     
00101     
00102     
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     
00119     ataDriveSelect(DriveNo);
00120     
00121     ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
00122 
00123     
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     
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     
00152     for(j=0; j<0x20; j++)
00153     {
00154         
00155         rprintfu16(j<<4);
00156         rprintfProgStrM(" ");
00157 
00158         
00159         for(i=0; i<0x10; i++)
00160         {
00161             rprintfu08(buf[(j<<4)+i]);
00162             rprintfProgStrM(" ");
00163         }
00164         
00165         
00166         rprintfProgStrM(" ");
00167 
00168         
00169         for(i=0; i<0x10; i++)
00170         {
00171             s = buf[(j<<4)+i]; 
00172             
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     
00192 
00193     
00194     for (i=0; i<(numBytes/16); i++)
00195     {
00196         
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     
00215     
00216 }
00217 
00218 void ataWriteDataBuffer(u08 *Buffer, u16 numBytes)
00219 {
00220     register unsigned char temp;
00221     unsigned int i;
00222 
00223     
00224 
00225     
00226     for (i=0; i<(numBytes/16); i++)     
00227     {
00228         
00229         
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     
00256 
00257 }
00258 
00259 u08 ataStatusWait(u08 mask, u08 waitStatus)
00260 {
00261     register u08 status;
00262 
00263     delay(100);
00264 
00265     
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     
00282     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
00283 
00284     
00285     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); 
00286     ataWriteByte(ATA_REG_CYLHI, Track>>8);          
00287     ataWriteByte(ATA_REG_CYLLO, Track);             
00288     ataWriteByte(ATA_REG_STARTSEC, Sector);     
00289     ataWriteByte(ATA_REG_SECCOUNT, numsectors); 
00290 
00291     
00292     ataWriteByte(ATA_REG_CMDSTATUS1, 0x21);
00293 
00294     
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     
00304     ataStatusWait(ATA_SR_DRQ, 0);
00305 
00306     
00307     ataReadDataBuffer(Buffer, 512*numsectors);
00308 
00309     
00310     temp = ataReadByte(ATA_REG_CMDSTATUS1); 
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     
00326     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
00327 
00328     
00329     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); 
00330     ataWriteByte(ATA_REG_CYLHI, Track>>8);          
00331     ataWriteByte(ATA_REG_CYLLO, Track);             
00332     ataWriteByte(ATA_REG_STARTSEC, Sector);     
00333     ataWriteByte(ATA_REG_SECCOUNT, numsectors); 
00334 
00335     
00336     ataWriteByte(ATA_REG_CMDSTATUS1, 0x31);
00337 
00338     
00339 
00340     
00341     ataStatusWait(ATA_SR_DRQ, 0);
00342 
00343     
00344     ataWriteDataBuffer(Buffer, 512*numsectors);
00345     
00346     
00347     temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
00348 
00349     
00350     if (temp & ATA_SR_ERR)
00351     {
00352         rprintfProgStrM("WR ERR\r\n");
00353         return 1;
00354     }
00355 
00356     
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     
00428     if(ataDriveInfo.LBAsupport)
00429     {
00430         
00431         temp = ataReadSectorsLBA(Drive, lba, numsectors, Buffer);
00432     }
00433     else
00434     {
00435         
00436         #ifdef DEBUG_ATA
00437             
00438             rprintfProgStrM("ATA LBA for CHS read: ");
00439             rprintfProgStrM("LBA="); rprintfu32(lba); rprintfProgStrM(" ");
00440         #endif
00441 
00442         
00443         
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     
00475     if(ataDriveInfo.LBAsupport)
00476     {
00477         
00478         temp = ataWriteSectorsLBA(Drive, lba, numsectors, Buffer);
00479     }
00480     else
00481     {
00482         
00483         #ifdef DEBUG_ATA
00484             
00485             rprintfProgStrM("ATA LBA for CHS write: ");
00486             rprintfProgStrM("LBA="); rprintfu32(lba); rprintfProgStrM(" ");
00487         #endif
00488 
00489         
00490         
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)); 
00515 }
00516  
00517 
00518 
00519 
00520 
00521 
00522 
00523  
00524 
00525 
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 
00535 
00536 
00537 
00538 
00539 
00540 
00541 
00542 
00543 
00544 
00545 
00546 
00547 
00548 
00549 
00550 u08 ataReadByte(u08 reg)
00551 {
00552     register u08 ret;
00553     
00554     ret = *((volatile unsigned char*) ATA_REG_BASE + reg);
00555     
00556     return ret;
00557 }
00558 
00559 void ataWriteByte(u08 reg, u08 data)
00560 {
00561     
00562     *((volatile unsigned char*) ATA_REG_BASE + reg) = data;
00563     
00564 }
00565 
00566  
00567 void ataShowRegisters(unsigned char DriveNo) 
00568 { 
00569     ataWriteByte(ATA_REG_HDDEVSEL, 0xA0 + (DriveNo ? 0x10:0x00)); 
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);   
00584     delay(10);  
00585     ataWriteByte(ATA_REG_HDDEVSEL, 0x02);   
00586     delay(10);  
00587    
00588    while( (ataReadByte(ATA_REG_CMDSTATUS1) & 0xC0) != 0x40 ); 
00589     
00590     return ataReadByte(ATA_REG_CMDSTATUS1) + ataReadByte(ATA_REG_ERROR);
00591 }
00592 
00593 
00594 
00595 
00596 
00597 
00598 
00599 
00600 
00601 
00602 
00603 
00604 
00605