| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 6 | kaklik | /*! \file ata.c \brief IDE-ATA hard disk interface driver. */ |
| 2 | //***************************************************************************** |
||
| 3 | // |
||
| 4 | // File Name : 'ata.c' |
||
| 5 | // Title : IDE-ATA interface driver for hard disks |
||
| 6 | // Author : Pascal Stang |
||
| 7 | // Date : 11/22/2000 |
||
| 8 | // Revised : 4/19/2003 |
||
| 9 | // Version : 0.3 |
||
| 10 | // Target MCU : Atmel AVR Series |
||
| 11 | // Editor Tabs : 4 |
||
| 12 | // |
||
| 13 | // NOTE: This code is currently below version 1.0, and therefore is considered |
||
| 14 | // to be lacking in some functionality or documentation, or may not be fully |
||
| 15 | // tested. Nonetheless, you can expect most functions to work. |
||
| 16 | // |
||
| 17 | // This code is distributed under the GNU Public License |
||
| 18 | // which can be found at http://www.gnu.org/licenses/gpl.txt |
||
| 19 | // |
||
| 20 | //***************************************************************************** |
||
| 21 | |||
| 22 | #ifndef WIN32 |
||
| 23 | #include <avr/io.h> |
||
| 24 | #include <avr/interrupt.h> |
||
| 25 | #include <avr/pgmspace.h> |
||
| 26 | // #include <stdio.h> |
||
| 27 | #endif |
||
| 28 | #include "global.h" |
||
| 29 | #include "timer.h" |
||
| 30 | #include "rprintf.h" |
||
| 31 | |||
| 32 | #include "ata.h" |
||
| 33 | |||
| 34 | //#define DEBUG_ATA 1 |
||
| 35 | |||
| 36 | // global variables |
||
| 37 | |||
| 38 | // drive information |
||
| 39 | typeDriveInfo ataDriveInfo; |
||
| 40 | |||
| 41 | |||
| 42 | void ataInit(void) |
||
| 43 | { |
||
| 44 | |||
| 45 | } |
||
| 46 | |||
| 47 | void ataDriveInit(void) |
||
| 48 | { |
||
| 49 | u08 i; |
||
| 50 | unsigned char* buffer = (unsigned char*) SECTOR_BUFFER_ADDR; |
||
| 51 | |||
| 52 | // read drive identity |
||
| 53 | rprintfProgStrM("\r\nScanning IDE interface...\r\n"); |
||
| 54 | // Wait for drive to be ready |
||
| 55 | ataStatusWait(ATA_SR_BSY, ATA_SR_BSY); |
||
| 56 | // issue identify command |
||
| 57 | ataWriteByte(ATA_REG_CMDSTATUS1, 0xEC); |
||
| 58 | // wait for drive to request data transfer |
||
| 59 | ataStatusWait(ATA_SR_DRQ, ATA_SR_DRQ); |
||
| 60 | timerPause(200); |
||
| 61 | // read in the data |
||
| 62 | ataReadDataBuffer(buffer, 512); |
||
| 63 | |||
| 64 | // set local drive info parameters |
||
| 65 | ataDriveInfo.cylinders = *( ((unsigned int*) buffer) + ATA_IDENT_CYLINDERS ); |
||
| 66 | ataDriveInfo.heads = *( ((unsigned int*) buffer) + ATA_IDENT_HEADS ); |
||
| 67 | ataDriveInfo.sectors = *( ((unsigned int*) buffer) + ATA_IDENT_SECTORS ); |
||
| 68 | ataDriveInfo.LBAsupport = *( ((unsigned int*) buffer) + ATA_IDENT_FIELDVALID ); |
||
| 69 | ataDriveInfo.sizeinsectors = *( (unsigned long*) (buffer + ATA_IDENT_LBASECTORS*2) ); |
||
| 70 | // copy model string |
||
| 71 | for(i=0; i<40; i+=2) |
||
| 72 | { |
||
| 73 | // correct for byte order |
||
| 74 | ataDriveInfo.model[i ] = buffer[(ATA_IDENT_MODEL*2) + i + 1]; |
||
| 75 | ataDriveInfo.model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i ]; |
||
| 76 | } |
||
| 77 | // terminate string |
||
| 78 | ataDriveInfo.model[40] = 0; |
||
| 79 | |||
| 80 | // process and print info |
||
| 81 | if(ataDriveInfo.LBAsupport) |
||
| 82 | { |
||
| 83 | // LBA support |
||
| 84 | rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) ); |
||
| 85 | rprintf("LBA mode -- MODEL: "); |
||
| 86 | } |
||
| 87 | else |
||
| 88 | { |
||
| 89 | // CHS, no LBA support |
||
| 90 | // calculate drive size |
||
| 91 | ataDriveInfo.sizeinsectors = (unsigned long) ataDriveInfo.cylinders* |
||
| 92 | ataDriveInfo.heads*ataDriveInfo.sectors; |
||
| 93 | rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) ); |
||
| 94 | rprintf("CHS mode C=%d H=%d S=%d -- MODEL: ", ataDriveInfo.cylinders, ataDriveInfo.heads, ataDriveInfo.sectors ); |
||
| 95 | } |
||
| 96 | // print model information |
||
| 97 | rprintfStr(ataDriveInfo.model); rprintfCRLF(); |
||
| 98 | |||
| 99 | // initialize local disk parameters |
||
| 100 | //ataDriveInfo.cylinders = ATA_DISKPARM_CLYS; |
||
| 101 | //ataDriveInfo.heads = ATA_DISKPARM_HEADS; |
||
| 102 | //ataDriveInfo.sectors = ATA_DISKPARM_SECTORS; |
||
| 103 | |||
| 104 | } |
||
| 105 | |||
| 106 | void ataDiskErr(void) |
||
| 107 | { |
||
| 108 | unsigned char b; |
||
| 109 | |||
| 110 | b = ataReadByte(ATA_REG_ERROR); |
||
| 111 | rprintfProgStrM("ATA Error: "); |
||
| 112 | rprintfu08(b); |
||
| 113 | rprintfCRLF(); |
||
| 114 | } |
||
| 115 | |||
| 116 | void ataSetDrivePowerMode(u08 DriveNo, u08 mode, u08 timeout) |
||
| 117 | { |
||
| 118 | // select drive |
||
| 119 | ataDriveSelect(DriveNo); |
||
| 120 | // Wait for drive to be ready |
||
| 121 | ataStatusWait(ATA_SR_BSY, ATA_SR_BSY); |
||
| 122 | |||
| 123 | // set mode |
||
| 124 | switch(mode) |
||
| 125 | { |
||
| 126 | case ATA_DISKMODE_SPINDOWN: ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINDOWN); break; |
||
| 127 | case ATA_DISKMODE_SPINUP: ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINUP); break; |
||
| 128 | case ATA_DISKMODE_SETTIMEOUT: |
||
| 129 | ataWriteByte(ATA_REG_SECCOUNT, timeout); |
||
| 130 | ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_IDLE_5SU); |
||
| 131 | break; |
||
| 132 | case ATA_DISKMODE_SLEEP: ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SLEEP); break; |
||
| 133 | default: |
||
| 134 | break; |
||
| 135 | } |
||
| 136 | } |
||
| 137 | |||
| 138 | void ataPrintSector( u08 *Buffer) |
||
| 139 | { |
||
| 140 | u08 i; |
||
| 141 | u16 j; |
||
| 142 | u08 *buf; |
||
| 143 | u08 s; |
||
| 144 | |||
| 145 | buf = Buffer; |
||
| 146 | |||
| 147 | // print the low order address indicies |
||
| 148 | rprintfProgStrM(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF\r\n"); |
||
| 149 | rprintfProgStrM(" ----------------------------------------------- ---- ASCII -----\r\n"); |
||
| 150 | |||
| 151 | // print the data |
||
| 152 | for(j=0; j<0x20; j++) |
||
| 153 | { |
||
| 154 | // print the high order address index for this line |
||
| 155 | rprintfu16(j<<4); |
||
| 156 | rprintfProgStrM(" "); |
||
| 157 | |||
| 158 | // print the hex data |
||
| 159 | for(i=0; i<0x10; i++) |
||
| 160 | { |
||
| 161 | rprintfu08(buf[(j<<4)+i]); |
||
| 162 | rprintfProgStrM(" "); |
||
| 163 | } |
||
| 164 | |||
| 165 | // leave some space |
||
| 166 | rprintfProgStrM(" "); |
||
| 167 | |||
| 168 | // print the ascii data |
||
| 169 | for(i=0; i<0x10; i++) |
||
| 170 | { |
||
| 171 | s = buf[(j<<4)+i]; |
||
| 172 | // make sure character is printable |
||
| 173 | if(s >= 0x20) |
||
| 174 | { |
||
| 175 | rprintfChar(s); |
||
| 176 | } |
||
| 177 | else |
||
| 178 | { |
||
| 179 | rprintfChar(0x20); |
||
| 180 | } |
||
| 181 | |||
| 182 | } |
||
| 183 | rprintfCRLF(); |
||
| 184 | } |
||
| 185 | } |
||
| 186 | |||
| 187 | void ataReadDataBuffer(u08 *Buffer, u16 numBytes) |
||
| 188 | { |
||
| 189 | unsigned int i; |
||
| 190 | |||
| 191 | //sbi(MCUCR, SRW); // enable RAM waitstate |
||
| 192 | |||
| 193 | // read data from drive |
||
| 194 | for (i=0; i<(numBytes/16); i++) |
||
| 195 | { |
||
| 196 | // optimize by reading 16 bytes in-line before looping |
||
| 197 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 198 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 199 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 200 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 201 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 202 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 203 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 204 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 205 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 206 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 207 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 208 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 209 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 210 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 211 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL); |
||
| 212 | *Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH); |
||
| 213 | } |
||
| 214 | //cbi(MCUCR, SRW); // disable RAM waitstate |
||
| 215 | |||
| 216 | } |
||
| 217 | |||
| 218 | void ataWriteDataBuffer(u08 *Buffer, u16 numBytes) |
||
| 219 | { |
||
| 220 | register unsigned char temp; |
||
| 221 | unsigned int i; |
||
| 222 | |||
| 223 | //sbi(MCUCR, SRW); // enable RAM waitstate |
||
| 224 | |||
| 225 | // write data to drive |
||
| 226 | for (i=0; i<(numBytes/16); i++) |
||
| 227 | { |
||
| 228 | // optimize by writing 16 bytes in-line before looping |
||
| 229 | // keep byte order correct by using temp register |
||
| 230 | temp = *Buffer++; |
||
| 231 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 232 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 233 | temp = *Buffer++; |
||
| 234 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 235 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 236 | temp = *Buffer++; |
||
| 237 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 238 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 239 | temp = *Buffer++; |
||
| 240 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 241 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 242 | temp = *Buffer++; |
||
| 243 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 244 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 245 | temp = *Buffer++; |
||
| 246 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 247 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 248 | temp = *Buffer++; |
||
| 249 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 250 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 251 | temp = *Buffer++; |
||
| 252 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++; |
||
| 253 | *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp; |
||
| 254 | } |
||
| 255 | //cbi(MCUCR, SRW); // disable RAM waitstate |
||
| 256 | |||
| 257 | } |
||
| 258 | |||
| 259 | u08 ataStatusWait(u08 mask, u08 waitStatus) |
||
| 260 | { |
||
| 261 | register u08 status; |
||
| 262 | |||
| 263 | delay(100); |
||
| 264 | |||
| 265 | // wait for desired status |
||
| 266 | while( ((status = ataReadByte(ATA_REG_CMDSTATUS1)) & mask) == waitStatus ); |
||
| 267 | |||
| 268 | return status; |
||
| 269 | } |
||
| 270 | |||
| 271 | |||
| 272 | unsigned char ataReadSectorsCHS( unsigned char Drive, |
||
| 273 | unsigned char Head, |
||
| 274 | unsigned int Track, |
||
| 275 | unsigned char Sector, |
||
| 276 | unsigned int numsectors, |
||
| 277 | unsigned char *Buffer) |
||
| 278 | { |
||
| 279 | unsigned char temp; |
||
| 280 | |||
| 281 | // Wait for drive to be ready |
||
| 282 | temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY); |
||
| 283 | |||
| 284 | // Prepare parameters... |
||
| 285 | ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head |
||
| 286 | ataWriteByte(ATA_REG_CYLHI, Track>>8); // MSB of track |
||
| 287 | ataWriteByte(ATA_REG_CYLLO, Track); // LSB of track |
||
| 288 | ataWriteByte(ATA_REG_STARTSEC, Sector); // sector |
||
| 289 | ataWriteByte(ATA_REG_SECCOUNT, numsectors); // # of sectors |
||
| 290 | |||
| 291 | // Issue read sector command... |
||
| 292 | ataWriteByte(ATA_REG_CMDSTATUS1, 0x21); |
||
| 293 | |||
| 294 | // Wait for drive to be ready |
||
| 295 | temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY); |
||
| 296 | |||
| 297 | if (temp & ATA_SR_ERR) |
||
| 298 | { |
||
| 299 | rprintfProgStrM("RD ERR\r\n"); |
||
| 300 | return 1; |
||
| 301 | } |
||
| 302 | |||
| 303 | // Wait for drive to request data transfer |
||
| 304 | ataStatusWait(ATA_SR_DRQ, 0); |
||
| 305 | |||
| 306 | // read data from drive |
||
| 307 | ataReadDataBuffer(Buffer, 512*numsectors); |
||
| 308 | |||
| 309 | // Return the error bit from the status register... |
||
| 310 | temp = ataReadByte(ATA_REG_CMDSTATUS1); // read status register |
||
| 311 | |||
| 312 | return (temp & ATA_SR_ERR) ? 1:0; |
||
| 313 | } |
||
| 314 | |||
| 315 | |||
| 316 | unsigned char ataWriteSectorsCHS(unsigned char Drive, |
||
| 317 | unsigned char Head, |
||
| 318 | unsigned int Track, |
||
| 319 | unsigned char Sector, |
||
| 320 | unsigned int numsectors, |
||
| 321 | unsigned char *Buffer) |
||
| 322 | { |
||
| 323 | unsigned char temp; |
||
| 324 | |||
| 325 | // Wait for drive to be ready |
||
| 326 | temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY); |
||
| 327 | |||
| 328 | // Prepare parameters... |
||
| 329 | ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head |
||
| 330 | ataWriteByte(ATA_REG_CYLHI, Track>>8); // MSB of track |
||
| 331 | ataWriteByte(ATA_REG_CYLLO, Track); // LSB of track |
||
| 332 | ataWriteByte(ATA_REG_STARTSEC, Sector); // sector |
||
| 333 | ataWriteByte(ATA_REG_SECCOUNT, numsectors); // # of sectors |
||
| 334 | |||
| 335 | // Issue write sector command |
||
| 336 | ataWriteByte(ATA_REG_CMDSTATUS1, 0x31); |
||
| 337 | |||
| 338 | //delay(100); |
||
| 339 | |||
| 340 | // Wait for drive to request data transfer |
||
| 341 | ataStatusWait(ATA_SR_DRQ, 0); |
||
| 342 | |||
| 343 | // write data to drive |
||
| 344 | ataWriteDataBuffer(Buffer, 512*numsectors); |
||
| 345 | |||
| 346 | // Wait for drive to finish write |
||
| 347 | temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY); |
||
| 348 | |||
| 349 | // check for errors |
||
| 350 | if (temp & ATA_SR_ERR) |
||
| 351 | { |
||
| 352 | rprintfProgStrM("WR ERR\r\n"); |
||
| 353 | return 1; |
||
| 354 | } |
||
| 355 | |||
| 356 | // Return the error bit from the status register... |
||
| 357 | return (temp & ATA_SR_ERR) ? 1:0; |
||
| 358 | } |
||
| 359 | |||
| 360 | unsigned char ataReadSectorsLBA( unsigned char Drive, |
||
| 361 | unsigned long lba, |
||
| 362 | unsigned int numsectors, |
||
| 363 | unsigned char *Buffer) |
||
| 364 | { |
||
| 365 | unsigned int cyl, head, sect; |
||
| 366 | unsigned char temp; |
||
| 367 | |||
| 368 | #ifdef DEBUG_ATA |
||
| 369 | rprintfProgStrM("ATA LBA read "); |
||
| 370 | rprintfu32(lba); rprintfProgStrM(" "); |
||
| 371 | rprintfu16(numsectors); rprintfProgStrM(" "); |
||
| 372 | rprintfu16((unsigned int)Buffer); |
||
| 373 | rprintfCRLF(); |
||
| 374 | #endif |
||
| 375 | |||
| 376 | sect = (int) ( lba & 0x000000ffL ); |
||
| 377 | lba = lba >> 8; |
||
| 378 | cyl = (int) ( lba & 0x0000ffff ); |
||
| 379 | lba = lba >> 16; |
||
| 380 | head = ( (int) ( lba & 0x0fL ) ) | ATA_HEAD_USE_LBA; |
||
| 381 | |||
| 382 | temp = ataReadSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer ); |
||
| 383 | |||
| 384 | if(temp) |
||
| 385 | ataDiskErr(); |
||
| 386 | return temp; |
||
| 387 | } |
||
| 388 | |||
| 389 | unsigned char ataWriteSectorsLBA( unsigned char Drive, |
||
| 390 | unsigned long lba, |
||
| 391 | unsigned int numsectors, |
||
| 392 | unsigned char *Buffer) |
||
| 393 | { |
||
| 394 | unsigned int cyl, head, sect; |
||
| 395 | unsigned char temp; |
||
| 396 | |||
| 397 | #ifdef DEBUG_ATA |
||
| 398 | rprintfProgStrM("ATA LBA write "); |
||
| 399 | rprintfu32(lba); rprintfProgStrM(" "); |
||
| 400 | rprintfu16(numsectors); rprintfProgStrM(" "); |
||
| 401 | rprintfu16((unsigned int)Buffer); |
||
| 402 | rprintfCRLF(); |
||
| 403 | #endif |
||
| 404 | |||
| 405 | sect = (int) ( lba & 0x000000ffL ); |
||
| 406 | lba = lba >> 8; |
||
| 407 | cyl = (int) ( lba & 0x0000ffff ); |
||
| 408 | lba = lba >> 16; |
||
| 409 | head = ( (int) ( lba & 0x0fL ) ) | ATA_HEAD_USE_LBA; |
||
| 410 | |||
| 411 | temp = ataWriteSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer ); |
||
| 412 | |||
| 413 | if(temp) |
||
| 414 | ataDiskErr(); |
||
| 415 | return temp; |
||
| 416 | } |
||
| 417 | |||
| 418 | |||
| 419 | unsigned char ataReadSectors( unsigned char Drive, |
||
| 420 | unsigned long lba, |
||
| 421 | unsigned int numsectors, |
||
| 422 | unsigned char *Buffer) |
||
| 423 | { |
||
| 424 | unsigned int cyl, head, sect; |
||
| 425 | unsigned char temp; |
||
| 426 | |||
| 427 | // check if drive supports native LBA mode |
||
| 428 | if(ataDriveInfo.LBAsupport) |
||
| 429 | { |
||
| 430 | // drive supports using native LBA |
||
| 431 | temp = ataReadSectorsLBA(Drive, lba, numsectors, Buffer); |
||
| 432 | } |
||
| 433 | else |
||
| 434 | { |
||
| 435 | // drive required CHS access |
||
| 436 | #ifdef DEBUG_ATA |
||
| 437 | // do this defore destroying lba |
||
| 438 | rprintfProgStrM("ATA LBA for CHS read: "); |
||
| 439 | rprintfProgStrM("LBA="); rprintfu32(lba); rprintfProgStrM(" "); |
||
| 440 | #endif |
||
| 441 | |||
| 442 | // convert LBA to pseudo CHS |
||
| 443 | // remember to offset the sector count by one |
||
| 444 | sect = (u08) (lba % ataDriveInfo.sectors)+1; |
||
| 445 | lba = lba / ataDriveInfo.sectors; |
||
| 446 | head = (u08) (lba % ataDriveInfo.heads); |
||
| 447 | lba = lba / ataDriveInfo.heads; |
||
| 448 | cyl = (u16) lba; |
||
| 449 | |||
| 450 | #ifdef DEBUG_ATA |
||
| 451 | rprintfProgStrM("C:H:S="); |
||
| 452 | rprintfu16(cyl); rprintfProgStrM(":"); |
||
| 453 | rprintfu08(head); rprintfProgStrM(":"); |
||
| 454 | rprintfu08(sect); rprintfCRLF(); |
||
| 455 | #endif |
||
| 456 | |||
| 457 | temp = ataReadSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer ); |
||
| 458 | } |
||
| 459 | |||
| 460 | if(temp) |
||
| 461 | ataDiskErr(); |
||
| 462 | return temp; |
||
| 463 | } |
||
| 464 | |||
| 465 | |||
| 466 | unsigned char ataWriteSectors(unsigned char Drive, |
||
| 467 | unsigned long lba, |
||
| 468 | unsigned int numsectors, |
||
| 469 | unsigned char *Buffer) |
||
| 470 | { |
||
| 471 | unsigned int cyl, head, sect; |
||
| 472 | unsigned char temp; |
||
| 473 | |||
| 474 | // check if drive supports native LBA mode |
||
| 475 | if(ataDriveInfo.LBAsupport) |
||
| 476 | { |
||
| 477 | // drive supports using native LBA |
||
| 478 | temp = ataWriteSectorsLBA(Drive, lba, numsectors, Buffer); |
||
| 479 | } |
||
| 480 | else |
||
| 481 | { |
||
| 482 | // drive required CHS access |
||
| 483 | #ifdef DEBUG_ATA |
||
| 484 | // do this defore destroying lba |
||
| 485 | rprintfProgStrM("ATA LBA for CHS write: "); |
||
| 486 | rprintfProgStrM("LBA="); rprintfu32(lba); rprintfProgStrM(" "); |
||
| 487 | #endif |
||
| 488 | |||
| 489 | // convert LBA to pseudo CHS |
||
| 490 | // remember to offset the sector count by one |
||
| 491 | sect = (u08) (lba % ataDriveInfo.sectors)+1; |
||
| 492 | lba = lba / ataDriveInfo.sectors; |
||
| 493 | head = (u08) (lba % ataDriveInfo.heads); |
||
| 494 | lba = lba / ataDriveInfo.heads; |
||
| 495 | cyl = (u16) lba; |
||
| 496 | |||
| 497 | #ifdef DEBUG_ATA |
||
| 498 | rprintfProgStrM("C:H:S="); |
||
| 499 | rprintfu16(cyl); rprintfProgStrM(":"); |
||
| 500 | rprintfu08(head); rprintfProgStrM(":"); |
||
| 501 | rprintfu08(sect); rprintfCRLF(); |
||
| 502 | #endif |
||
| 503 | |||
| 504 | temp = ataWriteSectorsCHS( Drive, head, cyl, sect, numsectors, Buffer ); |
||
| 505 | } |
||
| 506 | |||
| 507 | if(temp) |
||
| 508 | ataDiskErr(); |
||
| 509 | return temp; |
||
| 510 | } |
||
| 511 | |||
| 512 | void ataDriveSelect(u08 DriveNo) |
||
| 513 | { |
||
| 514 | ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(DriveNo ? 0x10:00)); // Drive selection |
||
| 515 | } |
||
| 516 | |||
| 517 | //---------------------------------------------------------------------------- |
||
| 518 | // Set drive mode (STANDBY, IDLE) |
||
| 519 | //---------------------------------------------------------------------------- |
||
| 520 | /*#define STANDBY 0 |
||
| 521 | #define IDLE 1 |
||
| 522 | #define SLEEP 2 |
||
| 523 | */ |
||
| 524 | |||
| 525 | /* |
||
| 526 | unsigned char SetMode(unsigned char DriveNo, unsigned char Mode, unsigned char PwrDown) |
||
| 527 | { |
||
| 528 | WriteBYTE(CMD, 6, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive |
||
| 529 | WriteBYTE(CMD, 2, (PwrDown ? 0x01:0x00)); // Enable automatic power down |
||
| 530 | switch (Mode) |
||
| 531 | { |
||
| 532 | case STANDBY: WriteBYTE(CMD,7, 0xE2); break; |
||
| 533 | case IDLE: WriteBYTE(CMD,7, 0xE3); break; |
||
| 534 | // NOTE: To recover from sleep, either issue a soft or hardware reset ! |
||
| 535 | // (But not on all drives, f.ex seagate ST3655A it's not nessecary to reset |
||
| 536 | // but only to go in Idle mode, But on a Conner CFA170A it's nessecary with |
||
| 537 | // a reset) |
||
| 538 | case SLEEP: WriteBYTE(CMD,7, 0xE6); break; |
||
| 539 | } |
||
| 540 | Timer10mSec=10000; |
||
| 541 | while ((ReadBYTE(CMD,7) & 0xC0)!=0x40 && Timer10mSec); // Wait for DRDY & NOT BUSY |
||
| 542 | if (Timer10mSec==0) return 0xFF; // or timeout |
||
| 543 | |||
| 544 | // Return the error register... |
||
| 545 | return ReadBYTE(CMD, 1); |
||
| 546 | } |
||
| 547 | |||
| 548 | */ |
||
| 549 | |||
| 550 | u08 ataReadByte(u08 reg) |
||
| 551 | { |
||
| 552 | register u08 ret; |
||
| 553 | //sbi(MCUCR, SRW); // enable RAM waitstate |
||
| 554 | ret = *((volatile unsigned char*) ATA_REG_BASE + reg); |
||
| 555 | //cbi(MCUCR, SRW); // disable RAM waitstate |
||
| 556 | return ret; |
||
| 557 | } |
||
| 558 | |||
| 559 | void ataWriteByte(u08 reg, u08 data) |
||
| 560 | { |
||
| 561 | //sbi(MCUCR, SRW); // enable RAM waitstate |
||
| 562 | *((volatile unsigned char*) ATA_REG_BASE + reg) = data; |
||
| 563 | //cbi(MCUCR, SRW); // disable RAM waitstate |
||
| 564 | } |
||
| 565 | |||
| 566 | |||
| 567 | void ataShowRegisters(unsigned char DriveNo) |
||
| 568 | { |
||
| 569 | ataWriteByte(ATA_REG_HDDEVSEL, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive |
||
| 570 | |||
| 571 | rprintfProgStrM("R0: DATALOW = 0x"); rprintfu08(ataReadByte(ATA_REG_DATAL )); rprintfProgStrM(" \r\n"); |
||
| 572 | rprintfProgStrM("R1: ERROR = 0x"); rprintfu08(ataReadByte(ATA_REG_ERROR )); rprintfProgStrM(" \r\n"); |
||
| 573 | rprintfProgStrM("R2: SECT CNT = 0x"); rprintfu08(ataReadByte(ATA_REG_SECCOUNT)); rprintfProgStrM(" \r\n"); |
||
| 574 | rprintfProgStrM("R3: SECT NUM = 0x"); rprintfu08(ataReadByte(ATA_REG_STARTSEC)); rprintfProgStrM(" \r\n"); |
||
| 575 | rprintfProgStrM("R4: CYL LOW = 0x"); rprintfu08(ataReadByte(ATA_REG_CYLLO )); rprintfProgStrM(" \r\n"); |
||
| 576 | rprintfProgStrM("R5: CYL HIGH = 0x"); rprintfu08(ataReadByte(ATA_REG_CYLHI )); rprintfProgStrM(" \r\n"); |
||
| 577 | rprintfProgStrM("R6: HEAD/DEV = 0x"); rprintfu08(ataReadByte(ATA_REG_HDDEVSEL)); rprintfProgStrM(" \r\n"); |
||
| 578 | rprintfProgStrM("R7: CMD/STA = 0x"); rprintfu08(ataReadByte(ATA_REG_CMDSTATUS1)); rprintfProgStrM("\r\n"); |
||
| 579 | } |
||
| 580 | |||
| 581 | unsigned char ataSWReset(void) |
||
| 582 | { |
||
| 583 | ataWriteByte(ATA_REG_HDDEVSEL, 0x06); // SRST and nIEN bits |
||
| 584 | delay(10); // 10uS delay |
||
| 585 | ataWriteByte(ATA_REG_HDDEVSEL, 0x02); // nIEN bits |
||
| 586 | delay(10); // 10 uS delay |
||
| 587 | |||
| 588 | while( (ataReadByte(ATA_REG_CMDSTATUS1) & 0xC0) != 0x40 ); // Wait for DRDY and not BSY |
||
| 589 | |||
| 590 | return ataReadByte(ATA_REG_CMDSTATUS1) + ataReadByte(ATA_REG_ERROR); |
||
| 591 | } |
||
| 592 | |||
| 593 | /* |
||
| 594 | unsigned char ATA_Idle(unsigned char Drive) |
||
| 595 | { |
||
| 596 | |||
| 597 | WriteBYTE(CMD, 6, 0xA0 + (Drive ? 0x10:0x00)); // Select drive |
||
| 598 | WriteBYTE(CMD,7, 0xE1); |
||
| 599 | |||
| 600 | while ((ReadBYTE(CMD,7) & 0xC0)!=0x40); // Wait for DRDY & NOT BUSY |
||
| 601 | |||
| 602 | // Return the error register... |
||
| 603 | return ReadBYTE(CMD, 1); |
||
| 604 | } |
||
| 605 | */ |
Powered by WebSVN v2.8.3