00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "global.h"
00023 #include "timer.h"
00024 #include "rprintf.h"
00025 #include "debug.h"
00026
00027 #include "atadev.h"
00028 #include "ata.h"
00029
00030
00031 unsigned char AtaBuffer[0x200];
00032
00033
00034 void ataInit(DiskInfo_t* disk, DevBlock_t ataif, unsigned char driveno)
00035 {
00036
00037 disk->ataif = ataif;
00038
00039 disk->driveno = driveno;
00040
00041 disk->ataif.Init();
00042 }
00043
00044 void ataDriveInit(DiskInfo_t* disk)
00045 {
00046 u08 i;
00047
00048 unsigned char* buffer = AtaBuffer;
00049
00050
00051
00052
00053
00054
00055
00056
00057 rprintfProgStrM("\r\nScanning IDE interface...\r\n");
00058
00059 ataStatusWait(disk, ATA_SR_BSY, ATA_SR_BSY);
00060
00061 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, 0xEC);
00062
00063 ataStatusWait(disk, ATA_SR_DRQ, ATA_SR_DRQ);
00064 timerPause(20);
00065
00066 disk->ataif.ReadBlock(buffer, 512);
00067
00068
00069 disk->cylinders = *( ((unsigned short*) buffer) + ATA_IDENT_CYLINDERS );
00070 disk->heads = *( ((unsigned short*) buffer) + ATA_IDENT_HEADS );
00071 disk->sectors = *( ((unsigned short*) buffer) + ATA_IDENT_SECTORS );
00072 disk->LBAsupport = *( ((unsigned short*) buffer) + ATA_IDENT_FIELDVALID );
00073 disk->sizeinsectors = *( ((unsigned long*) (buffer + ATA_IDENT_LBASECTORS*2)) );
00074
00075
00076 for(i=0; i<40; i+=2)
00077 {
00078
00079 disk->model[i ] = buffer[(ATA_IDENT_MODEL*2) + i + 1];
00080 disk->model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i ];
00081 }
00082
00083 disk->model[40] = 0;
00084
00085
00086 if(disk->LBAsupport)
00087 {
00088
00089 rprintf("Drive 0: %dMB ", disk->sizeinsectors/(1000000/512) );
00090 rprintfProgStrM("LBA mode -- MODEL: ");
00091 }
00092 else
00093 {
00094
00095
00096 disk->sizeinsectors = (unsigned long) disk->cylinders*disk->heads*disk->sectors;
00097 rprintf("Drive 0: %dMB ", disk->sizeinsectors/(1000000/512) );
00098 rprintf("CHS mode C=%d H=%d S=%d -- MODEL: ", disk->cylinders, disk->heads, disk->sectors );
00099 }
00100
00101 rprintfStr(disk->model); rprintfCRLF();
00102
00103
00104
00105
00106
00107 }
00108
00109 void ataDiskErr(DiskInfo_t* disk)
00110 {
00111 unsigned char b;
00112
00113 b = disk->ataif.ReadReg(ATA_REG_ERROR);
00114 rprintfProgStrM("ATA Error: ");
00115 rprintfu08(b);
00116 rprintfCRLF();
00117 }
00118
00119 void ataSetDrivePowerMode(DiskInfo_t* disk, u08 mode, u08 timeout)
00120 {
00121
00122 ataDriveSelect(disk);
00123
00124 ataStatusWait(disk, ATA_SR_BSY, ATA_SR_BSY);
00125
00126
00127 switch(mode)
00128 {
00129 case ATA_DISKMODE_SPINDOWN:
00130 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, ATA_CMD_SPINDOWN);
00131 break;
00132 case ATA_DISKMODE_SPINUP:
00133 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, ATA_CMD_SPINUP);
00134 break;
00135 case ATA_DISKMODE_SETTIMEOUT:
00136 disk->ataif.WriteReg(ATA_REG_SECCOUNT, timeout);
00137 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, ATA_CMD_IDLE_5SU);
00138 break;
00139 case ATA_DISKMODE_SLEEP:
00140 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, ATA_CMD_SLEEP);
00141 break;
00142 default:
00143 break;
00144 }
00145 }
00146
00147 u08 ataStatusWait(DiskInfo_t* disk, u08 mask, u08 waitStatus)
00148 {
00149 register u08 status;
00150
00151 delay(100);
00152
00153
00154 while( ((status = disk->ataif.ReadReg(ATA_REG_CMDSTATUS1)) & mask) == waitStatus );
00155
00156 return status;
00157 }
00158
00159
00160 unsigned char ataReadSectorsCHS( DiskInfo_t* disk,
00161 unsigned char Head,
00162 unsigned int Track,
00163 unsigned char Sector,
00164 unsigned int numsectors,
00165 unsigned char *Buffer)
00166 {
00167 unsigned char temp;
00168
00169
00170 temp = ataStatusWait(disk, ATA_SR_BSY, ATA_SR_BSY);
00171
00172
00173 disk->ataif.WriteReg(ATA_REG_HDDEVSEL, 0xA0+(disk->driveno ? 0x10:00)+Head);
00174 disk->ataif.WriteReg(ATA_REG_CYLHI, Track>>8);
00175 disk->ataif.WriteReg(ATA_REG_CYLLO, Track);
00176 disk->ataif.WriteReg(ATA_REG_STARTSEC, Sector);
00177 disk->ataif.WriteReg(ATA_REG_SECCOUNT, numsectors);
00178
00179
00180 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, 0x21);
00181
00182
00183 temp = ataStatusWait(disk, ATA_SR_BSY, ATA_SR_BSY);
00184
00185 if (temp & ATA_SR_ERR)
00186 {
00187 rprintfProgStrM("RD ERR\r\n");
00188 return 1;
00189 }
00190
00191
00192 ataStatusWait(disk, ATA_SR_DRQ, 0);
00193
00194
00195 disk->ataif.ReadBlock(Buffer, 512*numsectors);
00196
00197
00198 temp = disk->ataif.ReadReg(ATA_REG_CMDSTATUS1);
00199
00200 return (temp & ATA_SR_ERR) ? 1:0;
00201 }
00202
00203
00204 unsigned char ataWriteSectorsCHS( DiskInfo_t* disk,
00205 unsigned char Head,
00206 unsigned int Track,
00207 unsigned char Sector,
00208 unsigned int numsectors,
00209 unsigned char *Buffer)
00210 {
00211 unsigned char temp;
00212
00213
00214 temp = ataStatusWait(disk, ATA_SR_BSY, ATA_SR_BSY);
00215
00216
00217 disk->ataif.WriteReg(ATA_REG_HDDEVSEL, 0xA0+(disk->driveno ? 0x10:00)+Head);
00218 disk->ataif.WriteReg(ATA_REG_CYLHI, Track>>8);
00219 disk->ataif.WriteReg(ATA_REG_CYLLO, Track);
00220 disk->ataif.WriteReg(ATA_REG_STARTSEC, Sector);
00221 disk->ataif.WriteReg(ATA_REG_SECCOUNT, numsectors);
00222
00223
00224 disk->ataif.WriteReg(ATA_REG_CMDSTATUS1, 0x31);
00225
00226
00227
00228
00229 ataStatusWait(disk, ATA_SR_DRQ, 0);
00230
00231
00232 disk->ataif.WriteBlock(Buffer, 512*numsectors);
00233
00234
00235 temp = ataStatusWait(disk, ATA_SR_BSY, ATA_SR_BSY);
00236
00237
00238 if (temp & ATA_SR_ERR)
00239 {
00240 rprintfProgStrM("WR ERR\r\n");
00241 return 1;
00242 }
00243
00244
00245 return (temp & ATA_SR_ERR) ? 1:0;
00246 }
00247
00248 unsigned char ataReadSectorsLBA( DiskInfo_t* disk,
00249 unsigned long lba,
00250 unsigned int numsectors,
00251 unsigned char *Buffer)
00252 {
00253 unsigned int cyl, head, sect;
00254 unsigned char temp;
00255
00256 #ifdef DEBUG_ATA
00257 rprintfProgStrM("ATA LBA read ");
00258 rprintfu32(lba); rprintfChar(' ');
00259 rprintfu16(numsectors); rprintfChar(' ');
00260 rprintfu16((unsigned int)Buffer);
00261 rprintfCRLF();
00262 #endif
00263
00264 sect = (int) ( lba & 0x000000ffL );
00265 lba = lba >> 8;
00266 cyl = (int) ( lba & 0x0000ffff );
00267 lba = lba >> 16;
00268 head = ( (int) ( lba & 0x0fL ) ) | ATA_HEAD_USE_LBA;
00269
00270 temp = ataReadSectorsCHS( disk, head, cyl, sect, numsectors, Buffer );
00271
00272 if(temp)
00273 ataDiskErr(disk);
00274 return temp;
00275 }
00276
00277 unsigned char ataWriteSectorsLBA( DiskInfo_t* disk,
00278 unsigned long lba,
00279 unsigned int numsectors,
00280 unsigned char *Buffer)
00281 {
00282 unsigned int cyl, head, sect;
00283 unsigned char temp;
00284
00285 #ifdef DEBUG_ATA
00286 rprintfProgStrM("ATA LBA write ");
00287 rprintfu32(lba); rprintfChar(' ');
00288 rprintfu16(numsectors); rprintfChar(' ');
00289 rprintfu16((unsigned int)Buffer);
00290 rprintfCRLF();
00291 #endif
00292
00293 sect = (int) ( lba & 0x000000ffL );
00294 lba = lba >> 8;
00295 cyl = (int) ( lba & 0x0000ffff );
00296 lba = lba >> 16;
00297 head = ( (int) ( lba & 0x0fL ) ) | ATA_HEAD_USE_LBA;
00298
00299 temp = ataWriteSectorsCHS( disk, head, cyl, sect, numsectors, Buffer );
00300
00301 if(temp)
00302 ataDiskErr(disk);
00303 return temp;
00304 }
00305
00306
00307 unsigned char ataReadSectors( DiskInfo_t* disk,
00308 unsigned long lba,
00309 unsigned int numsectors,
00310 unsigned char *Buffer)
00311 {
00312 unsigned int cyl, head, sect;
00313 unsigned char temp;
00314
00315
00316 if(disk->LBAsupport)
00317 {
00318
00319 temp = ataReadSectorsLBA(disk, lba, numsectors, Buffer);
00320 }
00321 else
00322 {
00323
00324 #ifdef DEBUG_ATA
00325
00326 rprintfProgStrM("ATA LBA for CHS read: ");
00327 rprintfProgStrM("LBA="); rprintfu32(lba); rprintfChar(' ');
00328 #endif
00329
00330
00331
00332 sect = (u08) (lba % disk->sectors)+1;
00333 lba = lba / disk->sectors;
00334 head = (u08) (lba % disk->heads);
00335 lba = lba / disk->heads;
00336 cyl = (u16) lba;
00337
00338 #ifdef DEBUG_ATA
00339 rprintfProgStrM("C:H:S=");
00340 rprintfu16(cyl); rprintfChar(':');
00341 rprintfu08(head); rprintfChar(':');
00342 rprintfu08(sect); rprintfCRLF();
00343 #endif
00344
00345 temp = ataReadSectorsCHS( disk, head, cyl, sect, numsectors, Buffer );
00346 }
00347
00348 if(temp)
00349 ataDiskErr(disk);
00350 return temp;
00351 }
00352
00353
00354 unsigned char ataWriteSectors( DiskInfo_t* disk,
00355 unsigned long lba,
00356 unsigned int numsectors,
00357 unsigned char *Buffer)
00358 {
00359 unsigned int cyl, head, sect;
00360 unsigned char temp;
00361
00362
00363 if(disk->LBAsupport)
00364 {
00365
00366 temp = ataWriteSectorsLBA(disk, lba, numsectors, Buffer);
00367 }
00368 else
00369 {
00370
00371 #ifdef DEBUG_ATA
00372
00373 rprintfProgStrM("ATA LBA for CHS write: ");
00374 rprintfProgStrM("LBA="); rprintfu32(lba); rprintfChar(' ');
00375 #endif
00376
00377
00378
00379 sect = (u08) (lba % disk->sectors)+1;
00380 lba = lba / disk->sectors;
00381 head = (u08) (lba % disk->heads);
00382 lba = lba / disk->heads;
00383 cyl = (u16) lba;
00384
00385 #ifdef DEBUG_ATA
00386 rprintfProgStrM("C:H:S=");
00387 rprintfu16(cyl); rprintfChar(' ');
00388 rprintfu08(head); rprintfChar(' ');
00389 rprintfu08(sect); rprintfCRLF();
00390 #endif
00391
00392 temp = ataWriteSectorsCHS( disk, head, cyl, sect, numsectors, Buffer );
00393 }
00394
00395 if(temp)
00396 ataDiskErr(disk);
00397 return temp;
00398 }
00399
00400 void ataDriveSelect(DiskInfo_t* disk)
00401 {
00402 disk->ataif.WriteReg(ATA_REG_HDDEVSEL, 0xA0+(disk->driveno ? 0x10:00));
00403 }
00404
00405 void ataShowRegisters(DiskInfo_t* disk)
00406 {
00407 disk->ataif.WriteReg(ATA_REG_HDDEVSEL, 0xA0 + (disk->driveno ? 0x10:0x00));
00408
00409 rprintfProgStrM("R0: DATA = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_DATA )); rprintfProgStrM(" \r\n");
00410 rprintfProgStrM("R1: ERROR = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_ERROR )); rprintfProgStrM(" \r\n");
00411 rprintfProgStrM("R2: SECT CNT = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_SECCOUNT)); rprintfProgStrM(" \r\n");
00412 rprintfProgStrM("R3: SECT NUM = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_STARTSEC)); rprintfProgStrM(" \r\n");
00413 rprintfProgStrM("R4: CYL LOW = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_CYLLO )); rprintfProgStrM(" \r\n");
00414 rprintfProgStrM("R5: CYL HIGH = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_CYLHI )); rprintfProgStrM(" \r\n");
00415 rprintfProgStrM("R6: HEAD/DEV = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_HDDEVSEL)); rprintfProgStrM(" \r\n");
00416 rprintfProgStrM("R7: CMD/STA = 0x"); rprintfu08(disk->ataif.ReadReg(ATA_REG_CMDSTATUS1)); rprintfProgStrM("\r\n");
00417 }
00418
00419 unsigned char ataSWReset(DiskInfo_t* disk)
00420 {
00421 disk->ataif.WriteReg(ATA_REG_HDDEVSEL, 0x06);
00422 delay(10);
00423 disk->ataif.WriteReg(ATA_REG_HDDEVSEL, 0x02);
00424 delay(10);
00425
00426 while( (disk->ataif.ReadReg(ATA_REG_CMDSTATUS1) & 0xC0) != 0x40 );
00427
00428 return disk->ataif.ReadReg(ATA_REG_CMDSTATUS1) + disk->ataif.ReadReg(ATA_REG_ERROR);
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475