|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: // Copyright 1997 by Apple Computer, Inc., all rights reserved. ! 26: /* ! 27: * Copyright (c) 1994-1997 NeXT Software, Inc. All rights reserved. ! 28: * ! 29: * IdeCntInit.m - ATA controller initialization module. ! 30: * ! 31: */ ! 32: ! 33: #import <driverkit/kernelDriver.h> ! 34: #import <driverkit/interruptMsg.h> ! 35: #import <mach/mach_interface.h> ! 36: #import <driverkit/IODevice.h> ! 37: #import <driverkit/ppc/IOTreeDevice.h> ! 38: #import <driverkit/ppc/IODBDMA.h> ! 39: #import <driverkit/align.h> ! 40: #import <machkit/NXLock.h> ! 41: #import "IdeDDM.h" ! 42: #import "io_inline.h" ! 43: #import <driverkit/return.h> ! 44: #import <mach/port.h> ! 45: #import <machdep/ppc/powermac.h> ! 46: #import <bsd/sys/systm.h> ! 47: ! 48: #import "IdeCnt.h" ! 49: #import "IdeCntInit.h" ! 50: #import "IdeCntCmds.h" ! 51: #import "IdeCntDma.h" ! 52: #import "AtapiCntCmds.h" ! 53: ! 54: ! 55: #define IDE_SYSCLK_NS 30 ! 56: ! 57: typedef struct ! 58: { ! 59: int accessTime; ! 60: int cycleTime; ! 61: } ideModes_t; ! 62: ! 63: static ideModes_t pioModes[] = ! 64: { ! 65: { 165, 600 }, /* Mode 0 */ ! 66: { 125, 383 }, /* 1 */ ! 67: { 100, 240 }, /* 2 */ ! 68: { 80, 180 }, /* 3 */ ! 69: { 70, 120 } /* 4 */ ! 70: }; ! 71: #define MAX_PIO_MODES (sizeof(pioModes) / sizeof(ideModes_t)) ! 72: ! 73: static ideModes_t singleWordModes[] = ! 74: { ! 75: { 480, 960 }, /* Mode 0 */ ! 76: { 100, 480 }, /* 1 */ ! 77: { 120, 240 } /* 2 */ ! 78: }; ! 79: #define MAX_SINGLEWORD_MODES (sizeof(singleWordModes) / sizeof(ideModes_t)) ! 80: ! 81: static ideModes_t multiWordModes[] = ! 82: { ! 83: { 215, 480 }, /* Mode 0 */ ! 84: { 80, 150 }, /* 1 */ ! 85: { 70, 120 } /* 2 */ ! 86: }; ! 87: #define MAX_MULTIWORD_MODES (sizeof(multiWordModes) / sizeof(ideModes_t)) ! 88: ! 89: ! 90: static ideModes_t ultraModes[] = ! 91: { ! 92: { 0, 114 }, /* Mode 0 */ ! 93: { 0, 75 }, /* 1 */ ! 94: { 0, 55 } /* 2 */ ! 95: }; ! 96: ! 97: #define MAX_ULTRA_MODES (sizeof(ultraModes) / sizeof(ideModes_t)) ! 98: ! 99: ! 100: static void endianSwap16Bit( volatile u_int16_t *p16 ) ! 101: { ! 102: u_int16_t tmp16; ! 103: ! 104: tmp16 = *p16; ! 105: tmp16 = (tmp16 >> 8) | (tmp16 << 8); ! 106: *p16 = tmp16; ! 107: } ! 108: ! 109: static void endianSwap32Bit( volatile u_int32_t *p32 ) ! 110: { ! 111: u_int32_t tmp32; ! 112: ! 113: tmp32 = *p32; ! 114: ! 115: tmp32 = ( ((tmp32 & 0x000000ff) << 24) ! 116: | ((tmp32 & 0x0000ff00) << 8) ! 117: | ((tmp32 & 0x00ff0000) >> 8) ! 118: | ((tmp32 & 0xff000000) >> 24) ); ! 119: ! 120: *p32 = tmp32; ! 121: } ! 122: ! 123: static int rnddiv( int x, int y ) ! 124: { ! 125: if ( x < 0 ) ! 126: return 0; ! 127: else ! 128: return ( (x / y) + (( x % y ) ? 1 : 0) ); ! 129: } ! 130: ! 131: @implementation IdeController(Initialize) ! 132: ! 133: ! 134: /* ! 135: * Check for MediaBay ! 136: * ! 137: * Returns: NO - MediaBay implementation with non-ATA/ATAPI option installed ! 138: * YES - Non-MediaBay implementation or MediaBay with ATA/ATAPI option ! 139: */ ! 140: - (BOOL) checkMediaBayOption: (IOTreeDevice *)deviceDescription ! 141: { ! 142: int n; ! 143: u_int32_t *heathrowIdReg; ! 144: u_int32_t heathrowIds; ! 145: IOTreeDevice *devDescParent; ! 146: char *nodeNameParent; ! 147: ! 148: /* ! 149: * Check for MediaBay implementation ! 150: */ ! 151: devDescParent = [[deviceDescription parent] deviceDescription]; ! 152: nodeNameParent = [devDescParent nodeName]; ! 153: ! 154: if ( strcmp( nodeNameParent, "media-bay" ) ) ! 155: { ! 156: return YES; /* Non-MediaBay implementation */ ! 157: } ! 158: if ( (n = [devDescParent numMemoryRanges]) < 1 ) ! 159: { ! 160: return YES; /* Misc OF Device Tree problem */ ! 161: } ! 162: ! 163: /* ! 164: * Check for ATA/ATAPI MediaBay option installed ! 165: */ ! 166: heathrowIdReg = (u_int32_t *)[devDescParent memoryRangeList][0].start; ! 167: heathrowIds = *heathrowIdReg; ! 168: endianSwap32Bit( &heathrowIds ); ! 169: ! 170: if ( (heathrowIds & MEDIA_BAY_ID_MASK) == MEDIA_BAY_ID_CDROM ) ! 171: { ! 172: return YES; /* Media Bay with ATA/ATAPI option */ ! 173: } ! 174: ! 175: return NO; ! 176: } ! 177: ! 178: #define ATAPI_SIGNATURE_LOW 0x14 ! 179: #define ATAPI_SIGNATURE_HIGH 0xeb ! 180: ! 181: #define ATA_SIGNATURE_LOW 0x00 ! 182: #define ATA_SIGNATURE_HIGH 0x00 ! 183: ! 184: /* ! 185: * This is called just after resetting the drives connected to this ! 186: * controller. We read the drive registers to figure out if it is an ATAPI ! 187: * drive. If it is then we make a note of it and return YES. ! 188: */ ! 189: - (BOOL)controllerPresent ! 190: { ! 191: unsigned char dh; ! 192: unsigned char unit; ! 193: ! 194: unit = 0; ! 195: ! 196: dh = _addressMode[unit]; ! 197: ! 198: dh |= (unit ? SEL_DRIVE1 : SEL_DRIVE0); ! 199: outb(_ideRegsAddrs.drHead, dh); ! 200: ! 201: /* ! 202: * Test with some data. ! 203: */ ! 204: ! 205: if (unit == 0) ! 206: { ! 207: outb(_ideRegsAddrs.cylLow, 0xaa); ! 208: outb(_ideRegsAddrs.cylHigh, 0xbb); ! 209: } ! 210: else ! 211: { ! 212: outb(_ideRegsAddrs.cylLow, 0xba); ! 213: outb(_ideRegsAddrs.cylHigh, 0xbe); ! 214: } ! 215: ! 216: if (unit == 0) ! 217: { ! 218: if ((inb(_ideRegsAddrs.cylLow) != 0xaa) || ! 219: (inb(_ideRegsAddrs.cylHigh) != 0xbb)) ! 220: { ! 221: return NO; ! 222: } ! 223: } ! 224: else ! 225: { ! 226: if ((inb(_ideRegsAddrs.cylLow) != 0xba) || ! 227: (inb(_ideRegsAddrs.cylHigh) != 0xbe)) ! 228: { ! 229: return NO; ! 230: } ! 231: } ! 232: ! 233: return YES; ! 234: } ! 235: ! 236: ! 237: /* ! 238: * One-time only init. Returns NO on failure. ! 239: */ ! 240: - (BOOL)ideControllerInit:(IOTreeDevice *)deviceDescription ! 241: { ! 242: int unit; ! 243: int drivesPresent = 0; ! 244: ns_time_t time, startTime; ! 245: ! 246: if ([self enableInterrupt:0]) { ! 247: IOLog("ideControllerInit: failed enableAllInterrupts\n"); ! 248: return NO; ! 249: } ! 250: ! 251: ! 252: if ((_ideCmdLock = [NXLock new]) == NULL) { ! 253: IOLog("ideControllerInit: failed _ideCmdLock\n"); ! 254: return NO; ! 255: } ! 256: ! 257: /* ! 258: * We don't want to execute any IDE commands from Disk until ! 259: * initialization is complete. ! 260: */ ! 261: [self ideCntrlrLock]; ! 262: ! 263: /* ! 264: * Initialize the register address values. ! 265: */ ! 266: [self assignRegisterAddresses: deviceDescription]; ! 267: ! 268: for (unit = 0; unit < MAX_IDE_DRIVES; unit++) { ! 269: _atapiDevice[unit] = NO; ! 270: } ! 271: ! 272: /* ! 273: * We have to test here if the controller is present or else we will ! 274: * block looking for a drive (in ideReset). ! 275: */ ! 276: ! 277: if ([self controllerPresent] == NO) ! 278: { ! 279: IOLog("%s: no devices detected at port 0x%0x\n", [self name], ! 280: _ideRegsAddrs.data); ! 281: [self ideCntrlrUnLock]; ! 282: return NO; ! 283: } ! 284: else ! 285: { ! 286: IOLog("%s: device detected at port 0x%x irq %d\n", [self name], ! 287: _ideRegsAddrs.data, [deviceDescription interrupt]); ! 288: } ! 289: ! 290: _ideInterruptPort = [self interruptPort]; ! 291: _ideDevicePort = [deviceDescription devicePort]; ! 292: ! 293: [self setInterruptTimeOut:IDE_INTR_TIMEOUT]; ! 294: ! 295: _multiSectorRequested = YES; ! 296: ! 297: for (unit = 0; unit < MAX_IDE_DRIVES; unit++) ! 298: { ! 299: _addressMode[unit] = ADDRESS_MODE_LBA; ! 300: } ! 301: ! 302: _driveNum = unit; ! 303: ! 304: for (unit = 0; unit < MAX_IDE_DRIVES; unit++) ! 305: { ! 306: ! 307: bzero(&_ideInfo[unit], sizeof(ideDriveInfo_t)); ! 308: ! 309: [self ideReset]; ! 310: ! 311: IOGetTimestamp(&startTime); ! 312: if ([self ideDetectDrive:unit] == YES) ! 313: { ! 314: _ideInfo[unit].type = 255; ! 315: } ! 316: IOGetTimestamp(&time); ! 317: time = (time - startTime) / (1000*1000); ! 318: kprintf( "Disk(ata) - ideDetectDrive:%d - %d ms\n\r", unit, (u_int32_t)time ); ! 319: ! 320: /* ! 321: * If we didn't find ATA drive then look for ATAPI device. ! 322: */ ! 323: if ((_ideInfo[unit].type == 0) && ([self ideDetectATAPIDevice:unit] == YES)) ! 324: { ! 325: _ideInfo[unit].type = 127; ! 326: } ! 327: ! 328: if (_ideInfo[unit].type != 0) ! 329: drivesPresent += 1 ; ! 330: } ! 331: ! 332: if (drivesPresent == 0) ! 333: { ! 334: [self ideCntrlrUnLock]; ! 335: IOLog("ideControllerInit: failed drivesPresent\n"); ! 336: return NO; ! 337: } ! 338: ! 339: /* ! 340: * Initialization was successful. We should release the lock so that the ! 341: * controller can now execute commands from disk objects. ! 342: */ ! 343: ! 344: [self resetAndInit]; ! 345: ! 346: /* ! 347: * Set drive power state to active. ! 348: */ ! 349: for (unit = 0; unit < MAX_IDE_DRIVES; unit++) ! 350: { ! 351: if (_ideInfo[unit].type != 0) ! 352: [self setDrivePowerState:IDE_PM_ACTIVE]; ! 353: } ! 354: ! 355: _driveSleepRequest = NO; ! 356: ! 357: [self enableInterrupts]; ! 358: ! 359: [self ideCntrlrUnLock]; ! 360: ! 361: return YES; ! 362: } ! 363: ! 364: #define ATA_RESET_DELAY (30 * 1000) /* milliseconds */ ! 365: ! 366: /* ! 367: * Determine the presence and type of drive (IDE/ATAPI) attached to this ! 368: * controller. ! 369: * ! 370: */ ! 371: ! 372: -(BOOL)ideDetectDrive:(unsigned int)unit ! 373: { ! 374: unsigned char dh = _addressMode[unit]; ! 375: int i; ! 376: unsigned char status; ! 377: BOOL found = NO; ! 378: ! 379: [self disableInterrupts]; ! 380: ! 381: dh |= (unit ? SEL_DRIVE1 : SEL_DRIVE0); ! 382: outb(_ideRegsAddrs.drHead, dh); ! 383: IODelay(10); ! 384: ! 385: status = inb(_ideRegsAddrs.status); ! 386: if ( !(status & READY) ) ! 387: { ! 388: return found; ! 389: } ! 390: ! 391: outb(_ideRegsAddrs.command, IDE_IDENTIFY_DRIVE); ! 392: ! 393: for (i = 0; i < (ATA_RESET_DELAY * 5); i++) ! 394: { ! 395: IODelay(200); ! 396: status = inb(_ideRegsAddrs.status); ! 397: ! 398: if ((!(status & BUSY)) && (status & (ERROR | WRITE_FAULT | ERROR_CORRECTED)) ) ! 399: { ! 400: break; /* certain failure */ ! 401: } ! 402: ! 403: if ((!(status & BUSY)) && (status & DREQUEST)) ! 404: { ! 405: found = YES; /* success */ ! 406: break; ! 407: } ! 408: } ! 409: ! 410: return found; ! 411: } ! 412: ! 413: /* ! 414: * We send the device ATAPI soft reset command and check for signature. This ! 415: * is the first command that ATAPI devices need. ! 416: */ ! 417: -(BOOL)ideDetectATAPIDevice:(unsigned int)unit ! 418: { ! 419: unsigned char low, high; ! 420: BOOL found = NO; ! 421: ! 422: [self atapiSoftReset:unit]; ! 423: ! 424: low = inb(_ideRegsAddrs.cylLow); ! 425: high = inb(_ideRegsAddrs.cylHigh); ! 426: ! 427: if ((low == ATAPI_SIGNATURE_LOW) && (high == ATAPI_SIGNATURE_HIGH)) ! 428: { ! 429: _atapiDevice[unit] = YES; ! 430: IOLog("%s: ATAPI device %d detected.\n", [self name], unit); ! 431: found = YES; ! 432: } ! 433: /* ! 434: * Clear ATAPI signature ! 435: */ ! 436: outb(_ideRegsAddrs.cylLow, 0 ); ! 437: outb(_ideRegsAddrs.cylHigh, 0 ); ! 438: ! 439: return found; ! 440: } ! 441: ! 442: ! 443: -(ideDriveInfo_t *)getIdeDriveInfo:(unsigned int)unit ! 444: { ! 445: return &_ideInfo[unit]; ! 446: } ! 447: ! 448: #define MAX_RESET_ATTEMPTS 2 ! 449: ! 450: - (void)ideReset ! 451: { ! 452: int count; ! 453: int delay; ! 454: unsigned char status; ! 455: ! 456: for ( count = 0; count < MAX_IDE_DRIVES; count++ ) ! 457: { ! 458: _driveReset[count] = YES; ! 459: } ! 460: ! 461: for (count = 0; count < MAX_RESET_ATTEMPTS; count++) ! 462: { ! 463: outb(_ideRegsAddrs.deviceControl, DISK_RESET_ENABLE); ! 464: IODelay(100); /* spec >= 25 us */ ! 465: outb(_ideRegsAddrs.deviceControl, 0x0); ! 466: ! 467: [self enableInterrupts]; ! 468: ! 469: delay = 31 * 1000 * 1000; /* thirty one seconds */ ! 470: ! 471: IOSleep(1000); /* Enough time to assert busy */ ! 472: ! 473: while (delay > 0) ! 474: { ! 475: status = inb(_ideRegsAddrs.status); ! 476: if (!(status & BUSY)) ! 477: { ! 478: return; ! 479: } ! 480: ! 481: IOSleep(1); ! 482: delay -= 1000; ! 483: } ! 484: ! 485: IOLog("%s: Reset failed, retrying..\n", [self name]); ! 486: IOSleep(2000); ! 487: } ! 488: } ! 489: ! 490: ! 491: /* ! 492: * Initialize the IDE interface. Find about drive capabilities (by ! 493: * IDE_IDENTIFY_DRIVE command) and configure drive. ! 494: * ! 495: * By the time we enter this routine we know about all devices connected to this controller. ! 496: */ ! 497: - (void)resetAndInit ! 498: { ! 499: int i; ! 500: unsigned char unit; ! 501: ide_return_t rtn; ! 502: atapi_return_t atapi_rtn; ! 503: BOOL ataDevicePresent; ! 504: ! 505: /* ! 506: * If there is at least one ATA drive connected to this controller then ! 507: * is is not necessary to (ATA style) reset them. We use the ATAPI reset ! 508: * instead. ! 509: */ ! 510: ataDevicePresent = NO; ! 511: for (i = 0; i < MAX_IDE_DRIVES; i++) ! 512: { ! 513: if ((_ideInfo[i].type != 0) && ([self isAtapiDevice:i] == NO)) ! 514: { ! 515: ataDevicePresent = YES; ! 516: break; ! 517: } ! 518: } ! 519: ! 520: if (ataDevicePresent == YES) ! 521: { ! 522: [self ideReset]; ! 523: } ! 524: ! 525: /* ! 526: * Send the controller necessary commands to set capabilities and then ! 527: * set drive parameters. It is necessary to set drive parameters before ! 528: * any data I/O can be done from the disk. ! 529: */ ! 530: for (unit = 0; unit < MAX_IDE_DRIVES; unit++) ! 531: { ! 532: if (_ideInfo[unit].type == 0) ! 533: { ! 534: continue; ! 535: } ! 536: ! 537: _driveNum = unit; ! 538: ! 539: _cycleTimes[unit].pioMode = 0; ! 540: _cycleTimes[unit].pioAccessTime = pioModes[0].accessTime; ! 541: _cycleTimes[unit].pioCycleTime = pioModes[0].cycleTime; ! 542: ! 543: [self calcIdeConfig: unit]; ! 544: ! 545: if ( [self isAtapiDevice:unit] == YES ) ! 546: { ! 547: [self atapiSoftReset:unit]; ! 548: ! 549: /* ! 550: * We have to do this test because of "task file shadow" bug ! 551: * present in many ATAPI CD-ROMs. ! 552: */ ! 553: atapi_rtn = ! 554: [self atapiIdentifyDevice:(struct vm_map *)IOVmTaskSelf() ! 555: addr:(unsigned char *)&_ideIdentifyInfo[unit] unit:unit]; ! 556: ! 557: /* Too bad.. */ ! 558: if (atapi_rtn != IDER_SUCCESS) ! 559: { ! 560: _atapiDevice[unit] = NO; ! 561: _ideInfo[unit].type = 0; ! 562: continue; ! 563: } ! 564: ! 565: [self endianSwapIdentifyData: &_ideIdentifyInfo[unit]]; ! 566: ! 567: [self printAtapiInfo:&_ideIdentifyInfo[unit] Device:unit]; ! 568: [self atapiInitParameters:&_ideIdentifyInfo[unit] Device:unit]; ! 569: continue; ! 570: } ! 571: ! 572: rtn = [self setATADriveCapabilities:unit]; ! 573: if (rtn != IDER_SUCCESS) ! 574: { ! 575: _ideInfo[unit].type = 0; ! 576: continue; ! 577: } ! 578: } ! 579: } ! 580: ! 581: /* ! 582: * FIXME: Need to figure out multi-word DMA. ! 583: */ ! 584: - (ide_return_t)getTransferModes:(ideIdentifyInfo_t *)infoPtr Unit: (int)unit ! 585: { ! 586: int i, n; ! 587: ! 588: int pioMode = 0; ! 589: int pioCycleTime = 0; ! 590: int dmaMode = 0; ! 591: int dmaType = IDE_DMA_NONE; ! 592: int dmaCycleTime = 0; ! 593: ! 594: /* ! 595: * PIO Cycle timing...... ! 596: * ! 597: * 1. Try to match Word 51 (pioCycleTime) with cycle timings ! 598: * in our pioModes table to get mode/CycleTime. (Valid for Modes 0-2) ! 599: * 2. If Words 64-68 are supported and Mode 3 or 4 supported check, ! 600: * update CycleTime with Word 68 (CycleTimeWithIORDY). ! 601: */ ! 602: ! 603: pioCycleTime = infoPtr->pioDataTransferCyleTimingMode; ! 604: ! 605: if ( pioCycleTime > 2 ) ! 606: { ! 607: for ( i=MAX_PIO_MODES-1; i != -1; i-- ) ! 608: { ! 609: if ( pioCycleTime <= pioModes[i].cycleTime ) ! 610: { ! 611: pioMode = i; ! 612: break; ! 613: } ! 614: } ! 615: ! 616: if ( i == -1 ) ! 617: { ! 618: pioCycleTime = pioModes[pioMode].cycleTime; ! 619: } ! 620: } ! 621: else ! 622: { ! 623: pioMode = pioCycleTime; ! 624: pioCycleTime = pioModes[pioMode].cycleTime; ! 625: } ! 626: ! 627: if (infoPtr->fieldValidity & IDE_WORDS64_TO_68_SUPPORTED) ! 628: { ! 629: if (infoPtr->fcPioDataTransferCyleTimingMode & IDE_FC_PIO_MODE_4_SUPPORTED) ! 630: pioMode = 4; ! 631: else if (infoPtr->fcPioDataTransferCyleTimingMode & IDE_FC_PIO_MODE_3_SUPPORTED) ! 632: pioMode = 3; ! 633: ! 634: if ( (pioMode >= 3) && infoPtr->MinPIOTransferCycleTimeWithIORDY ) ! 635: { ! 636: pioCycleTime = infoPtr->MinPIOTransferCycleTimeWithIORDY; ! 637: } ! 638: } ! 639: ! 640: /* ! 641: * Ultra DMA timing..... ! 642: * ! 643: */ ! 644: if ( (_controllerType == kControllerTypeCmd646X) && (infoPtr->fieldValidity & IDE_WORD_88_SUPPORTED) ) ! 645: { ! 646: n = infoPtr->ultraDma & IDE_ULTRA_DMA_SUPPORTED; ! 647: if ( n ) ! 648: { ! 649: dmaType = IDE_DMA_ULTRA; ! 650: for ( i=0; n; i++, n>>=1 ) ! 651: ; ! 652: ! 653: dmaMode = i - 1; ! 654: if ( dmaMode > MAX_ULTRA_MODES-1 ) ! 655: { ! 656: dmaMode = MAX_ULTRA_MODES-1; ! 657: } ! 658: dmaCycleTime = ultraModes[dmaMode].cycleTime; ! 659: ! 660: goto getCycleTimes_exit; ! 661: } ! 662: } ! 663: ! 664: /* ! 665: * Multiword DMA timing..... ! 666: * ! 667: * 1. Check Word 63(7:0) (Multiword DMA Modes Supported). Lookup ! 668: * CycleTime for highest mode we support. ! 669: * 2. If Words 64-68 supported, update CycleTime from Word 66 ! 670: * (RecommendedMultiWordCycleTime) if specified. ! 671: */ ! 672: ! 673: n = infoPtr->mwDma & IDE_MW_DMA_SUPPORTED; ! 674: if ( n ) ! 675: { ! 676: dmaType = IDE_DMA_MULTIWORD; ! 677: for ( i=0; n; i++, n>>=1 ) ! 678: ; ! 679: ! 680: dmaMode = i - 1; ! 681: if ( dmaMode > MAX_MULTIWORD_MODES-1 ) ! 682: { ! 683: dmaMode = MAX_MULTIWORD_MODES-1; ! 684: } ! 685: dmaCycleTime = multiWordModes[dmaMode].cycleTime; ! 686: ! 687: if (infoPtr->fieldValidity & IDE_WORDS64_TO_68_SUPPORTED) ! 688: { ! 689: if ( infoPtr->RecommendedMwDMACycleTime ) ! 690: { ! 691: dmaCycleTime = infoPtr->RecommendedMwDMACycleTime; ! 692: } ! 693: } ! 694: goto getCycleTimes_exit; ! 695: } ! 696: ! 697: /* ! 698: * Single Word DMA timing..... ! 699: * ! 700: * 1. If Word 64(7:0) (SingleWord DMA Modes supported) is non-zero, ! 701: * find highest supported mode and get CycleTime from table. ! 702: * 2. If Word 64(7:0) (SingleWord DMA Modes supported) is zero, ! 703: * then match Word 52 (Single Word DMA Cycle Time) against ! 704: * cycle times in singleWordModes table. ! 705: */ ! 706: ! 707: n = infoPtr->swDma & IDE_SW_DMA_SUPPORTED; ! 708: if ( n ) ! 709: { ! 710: dmaType = IDE_DMA_SINGLEWORD; ! 711: for ( i=0; n; i++, n>>=1 ) ! 712: ; ! 713: ! 714: dmaMode = i - 1; ! 715: if ( dmaMode > MAX_SINGLEWORD_MODES-1 ) ! 716: { ! 717: dmaMode = MAX_SINGLEWORD_MODES-1; ! 718: } ! 719: dmaCycleTime = singleWordModes[dmaMode].cycleTime; ! 720: } ! 721: else ! 722: { ! 723: dmaCycleTime = infoPtr->dmaDataTransferCyleTimingMode; ! 724: for ( i=MAX_SINGLEWORD_MODES-1; i != -1; i-- ) ! 725: { ! 726: if ( dmaCycleTime <= singleWordModes[i].cycleTime ) ! 727: { ! 728: dmaType = IDE_DMA_SINGLEWORD; ! 729: dmaMode = i; ! 730: dmaCycleTime = singleWordModes[i].cycleTime; ! 731: break; ! 732: } ! 733: } ! 734: } ! 735: ! 736: ! 737: getCycleTimes_exit: ; ! 738: ! 739: _cycleTimes[unit].pioCycleTime = pioCycleTime; ! 740: _cycleTimes[unit].pioAccessTime = pioModes[pioMode].accessTime; ! 741: _cycleTimes[unit].pioMode = pioMode; ! 742: ! 743: if ( dmaType != IDE_DMA_NONE ) ! 744: { ! 745: _cycleTimes[unit].dmaType = dmaType; ! 746: _cycleTimes[unit].dmaMode = dmaMode; ! 747: _cycleTimes[unit].dmaCycleTime = dmaCycleTime; ! 748: switch ( dmaMode ) ! 749: { ! 750: case IDE_DMA_SINGLEWORD: ! 751: _cycleTimes[unit].dmaAccessTime = singleWordModes[dmaMode].accessTime; ! 752: break; ! 753: case IDE_DMA_MULTIWORD: ! 754: _cycleTimes[unit].dmaAccessTime = multiWordModes[dmaMode].accessTime; ! 755: break; ! 756: case IDE_DMA_ULTRA: ! 757: _cycleTimes[unit].dmaAccessTime = ultraModes[dmaMode].accessTime; ! 758: break; ! 759: } ! 760: } ! 761: ! 762: [self calcIdeConfig: (int)unit]; ! 763: ! 764: ! 765: return IDER_SUCCESS; ! 766: } ! 767: ! 768: -(void) calcIdeConfig:(int)unit ! 769: { ! 770: _cycleTimes[unit].fChanged = YES; ! 771: ! 772: if ( _controllerType == kControllerTypeCmd646X ) ! 773: { ! 774: [self calcIdeTimingsCmd646X:unit]; ! 775: } ! 776: else ! 777: { ! 778: [self calcIdeTimingsDBDMA:unit]; ! 779: } ! 780: } ! 781: ! 782: -(void) calcIdeTimingsCmd646X:(int) unit ! 783: { ! 784: u_int32_t cycleClks; ! 785: u_int32_t cycleTime, accessTime; ! 786: u_int32_t drwActClks, drwRecClks; ! 787: u_int32_t drwActTime, drwRecTime; ! 788: ! 789: _cycleTimes[unit].ideConfig.cmd646XConfig.arttimReg = 0x40; ! 790: _cycleTimes[unit].ideConfig.cmd646XConfig.cmdtimReg = 0xA9; ! 791: ! 792: accessTime = pioModes[_cycleTimes[unit].pioMode].accessTime; ! 793: ! 794: drwActClks = accessTime / IDE_SYSCLK_NS; ! 795: drwActClks += (accessTime % IDE_SYSCLK_NS) ? 1 : 0; ! 796: drwActTime = drwActClks * IDE_SYSCLK_NS; ! 797: ! 798: drwRecTime = pioModes[_cycleTimes[unit].pioMode].cycleTime - drwActTime; ! 799: drwRecClks = drwRecTime / IDE_SYSCLK_NS; ! 800: drwRecClks += (drwRecTime % IDE_SYSCLK_NS) ? 1 : 0; ! 801: ! 802: if ( drwRecClks >= 16 ) ! 803: drwRecClks = 1; ! 804: else if ( drwRecClks <= 1 ) ! 805: drwRecClks = 16; ! 806: ! 807: _cycleTimes[unit].ideConfig.cmd646XConfig.drwtimRegPIO = ((drwActClks & 0x0f) << 4) | ((drwRecClks-1) & 0x0f); ! 808: ! 809: ! 810: _cycleTimes[unit].ideConfig.cmd646XConfig.udidetcrReg = 0; ! 811: ! 812: if ( _cycleTimes[unit].dmaType == IDE_DMA_ULTRA ) ! 813: { ! 814: cycleTime = _cycleTimes[unit].dmaCycleTime; ! 815: ! 816: cycleClks = cycleTime / IDE_SYSCLK_NS; ! 817: cycleClks += (cycleTime % IDE_SYSCLK_NS) ? 1 : 0; ! 818: ! 819: _cycleTimes[unit].ideConfig.cmd646XConfig.udidetcrReg = (0x01 << unit) | ((cycleClks-1) << ((!unit) ? 4 : 6)) ; ! 820: } ! 821: else if ( _cycleTimes[unit].dmaType != IDE_DMA_NONE ) ! 822: { ! 823: accessTime = _cycleTimes[unit].dmaAccessTime; ! 824: ! 825: drwActClks = accessTime / IDE_SYSCLK_NS; ! 826: drwActClks += (accessTime % IDE_SYSCLK_NS) ? 1 : 0; ! 827: drwActTime = drwActClks * IDE_SYSCLK_NS; ! 828: ! 829: drwRecTime = _cycleTimes[unit].dmaCycleTime - drwActTime; ! 830: drwRecClks = drwRecTime / IDE_SYSCLK_NS; ! 831: drwRecClks += (drwRecTime % IDE_SYSCLK_NS) ? 1 : 0; ! 832: ! 833: if ( drwRecClks >= 16 ) ! 834: drwRecClks = 1; ! 835: else if ( drwRecClks <= 1 ) ! 836: drwRecClks = 16; ! 837: ! 838: _cycleTimes[0].ideConfig.cmd646XConfig.drwtimRegDMA = ((drwActClks & 0x0f) << 4) | ((drwRecClks-1) & 0x0f); ! 839: } ! 840: } ! 841: ! 842: ! 843: ! 844: -(void) calcIdeTimingsDBDMA:(int) unit ! 845: { ! 846: int accessTime; ! 847: int accessTicks; ! 848: int recTime; ! 849: int recTicks; ! 850: int cycleTime; ! 851: int cycleTimeOrig; ! 852: int halfTick = 0; ! 853: uint ideConfigWord = 0; ! 854: ! 855: /* ! 856: * Calc PIO access time >= pioAccessTime in SYSCLK increments ! 857: */ ! 858: accessTicks = rnddiv(_cycleTimes[unit].pioAccessTime, IDE_SYSCLK_NS); ! 859: /* ! 860: * Hardware limits access times to >= 120 ns ! 861: */ ! 862: accessTicks -= IDE_PIO_ACCESS_BASE; ! 863: if (accessTicks < IDE_PIO_ACCESS_MIN ) ! 864: { ! 865: accessTicks = IDE_PIO_ACCESS_MIN; ! 866: } ! 867: accessTime = (accessTicks + IDE_PIO_ACCESS_BASE) * IDE_SYSCLK_NS; ! 868: ! 869: /* ! 870: * Calc recovery time in SYSCLK increments based on time remaining in cycle ! 871: */ ! 872: recTime = _cycleTimes[unit].pioCycleTime - accessTime; ! 873: recTicks = rnddiv( recTime, IDE_SYSCLK_NS ); ! 874: /* ! 875: * Hardware limits recovery time to >= 150ns ! 876: */ ! 877: recTicks -= IDE_PIO_RECOVERY_BASE; ! 878: if ( recTicks < IDE_PIO_RECOVERY_MIN ) ! 879: { ! 880: recTicks = IDE_PIO_RECOVERY_MIN; ! 881: } ! 882: ! 883: cycleTime = (recTicks + IDE_PIO_RECOVERY_BASE + accessTicks + IDE_PIO_ACCESS_BASE) * IDE_SYSCLK_NS; ! 884: ! 885: ideConfigWord = accessTicks | (recTicks << 5); ! 886: ! 887: kprintf("Disk(ata): Controller Base = %08x\n\r", _ideRegsAddrs.data ); ! 888: kprintf("Disk(ata): Unit %1d: PIO Requested Timings: Access: %3dns Cycle: %3dns \n\r", ! 889: unit, _cycleTimes[unit].pioAccessTime, _cycleTimes[unit].pioCycleTime); ! 890: kprintf("Disk(ata): PIO Actual Timings: Access: %3dns Cycle: %3dns\n\r", ! 891: accessTime, cycleTime ); ! 892: ! 893: if ( _cycleTimes[unit].dmaType == IDE_DMA_NONE ) ! 894: { ! 895: goto calcConfigWordDone; ! 896: } ! 897: ! 898: /* ! 899: * Calc DMA access time >= dmaAccessTime in SYSCLK increments ! 900: */ ! 901: ! 902: /* ! 903: * OHare II erata - Cant handle write cycle times below 150ns ! 904: */ ! 905: cycleTimeOrig = _cycleTimes[unit].dmaCycleTime; ! 906: if ( IsPowerStar() ) ! 907: { ! 908: if ( cycleTimeOrig < 150 ) _cycleTimes[unit].dmaCycleTime = 150; ! 909: } ! 910: ! 911: accessTicks = rnddiv(_cycleTimes[unit].dmaAccessTime, IDE_SYSCLK_NS); ! 912: ! 913: accessTicks -= IDE_DMA_ACCESS_BASE; ! 914: if ( accessTicks < IDE_DMA_ACCESS_MIN ) ! 915: { ! 916: accessTicks = IDE_DMA_ACCESS_MIN; ! 917: } ! 918: accessTime = (accessTicks + IDE_DMA_ACCESS_BASE) * IDE_SYSCLK_NS; ! 919: ! 920: /* ! 921: * Calc recovery time in SYSCLK increments based on time remaining in cycle ! 922: */ ! 923: recTime = _cycleTimes[unit].dmaCycleTime - accessTime; ! 924: recTicks = rnddiv( recTime, IDE_SYSCLK_NS ); ! 925: ! 926: recTicks -= IDE_DMA_RECOVERY_BASE; ! 927: if ( recTicks < IDE_DMA_RECOVERY_MIN ) ! 928: { ! 929: recTicks = IDE_DMA_RECOVERY_MIN; ! 930: } ! 931: cycleTime = (recTicks + IDE_DMA_RECOVERY_BASE + accessTicks + IDE_DMA_ACCESS_BASE) * IDE_SYSCLK_NS; ! 932: ! 933: /* ! 934: * If our calculated access time is at least SYSCLK/2 > than what the disk requires, ! 935: * see if selecting the 1/2 Clock option will help. This adds SYSCLK/2 to ! 936: * the access time and subtracts SYSCLK/2 from the recovery time. ! 937: * ! 938: * By setting the H-bit and subtracting one from the current access tick count, ! 939: * we are reducing the current access time by SYSCLK/2 and the current recovery ! 940: * time by SYSCLK/2. Now, check if the new cycle time still meets the disk's requirements. ! 941: */ ! 942: if ( (accessTicks > IDE_DMA_ACCESS_MIN) && ((accessTime - IDE_SYSCLK_NS/2) >= _cycleTimes[unit].dmaAccessTime) ) ! 943: { ! 944: if ( (cycleTime - IDE_SYSCLK_NS) >= _cycleTimes[unit].dmaCycleTime ) ! 945: { ! 946: halfTick = 1; ! 947: accessTicks--; ! 948: accessTime -= IDE_SYSCLK_NS/2; ! 949: cycleTime -= IDE_SYSCLK_NS; ! 950: } ! 951: } ! 952: ! 953: ideConfigWord |= (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; ! 954: ! 955: kprintf("Disk(ata): DMA Requested Timings: Access: %3dns Cycle: %3dns \n\r", ! 956: _cycleTimes[unit].dmaAccessTime, cycleTimeOrig); ! 957: kprintf("Disk(ata): DMA Actual Timings: Access: %3dns Cycle: %3dns\n\r", ! 958: accessTime, cycleTime ); ! 959: ! 960: calcConfigWordDone: ; ! 961: endianSwap32Bit( &ideConfigWord ); ! 962: _cycleTimes[unit].ideConfig.dbdmaConfig = ideConfigWord; ! 963: ! 964: } ! 965: ! 966: ! 967: /* ! 968: * Send the Set Parameters command to the drive and set multi-sector mode ! 969: * etc. if the drive supports them. If biosInfo is YES, then we are using ! 970: * drive geometry information from the BIOS else we use Identify command to ! 971: * get this. ! 972: */ ! 973: - (ide_return_t)setATADriveCapabilities:(unsigned int)unit ! 974: { ! 975: ideRegsVal_t ideRegs; ! 976: unsigned char nSectors; ! 977: char *buf; ! 978: ! 979: ideIdentifyInfo_t *infoPtr = &_ideIdentifyInfo[unit]; ! 980: ! 981: ! 982: _multiSector[unit] = 0; ! 983: _dmaSupported[unit] = NO; ! 984: ! 985: _ideIdentifyInfoSupported[unit] = YES; ! 986: bzero(infoPtr, sizeof(ideIdentifyInfo_t)); ! 987: ! 988: /* ! 989: * Remember this command is optional. Failure means that either this ! 990: * command is not supported or the drive is not present. ! 991: */ ! 992: _driveNum = unit; ! 993: ! 994: [self setTransferRate: _driveNum UseDMA:NO]; ! 995: ! 996: if ([self ideReadGetInfoCommon:&ideRegs ! 997: client:(struct vm_map *)IOVmTaskSelf() ! 998: addr:(unsigned char *)infoPtr ! 999: command:IDE_IDENTIFY_DRIVE] != IDER_SUCCESS) ! 1000: { ! 1001: _ideIdentifyInfoSupported[unit] = NO; ! 1002: [self ideReset]; /* necessary */ ! 1003: return IDER_CMD_ERROR; ! 1004: } ! 1005: ! 1006: [self endianSwapIdentifyData: infoPtr]; ! 1007: ! 1008: /* ! 1009: * Fill in this struct similar to which we would have gotten from CMOS. ! 1010: */ ! 1011: _ideInfo[unit].cylinders = _ideIdentifyInfo[unit].cylinders; ! 1012: _ideInfo[unit].heads = _ideIdentifyInfo[unit].heads; ! 1013: _ideInfo[unit].control_byte = 0; ! 1014: _ideInfo[unit].landing_zone = 0; ! 1015: _ideInfo[unit].sectors_per_trk = _ideIdentifyInfo[unit].sectorsPerTrack; ! 1016: _ideInfo[unit].bytes_per_sector = IDE_SECTOR_SIZE; ! 1017: ! 1018: if ( infoPtr->capabilities & IDE_CAP_LBA_SUPPORTED) ! 1019: { ! 1020: _ideInfo[unit].total_sectors = infoPtr->userAddressableSectors; ! 1021: } ! 1022: else ! 1023: { ! 1024: _ideInfo[unit].total_sectors = _ideInfo[unit].sectors_per_trk ! 1025: * _ideInfo[unit].heads ! 1026: * _ideInfo[unit].cylinders; ! 1027: } ! 1028: ! 1029: /* ! 1030: * Set address mode. The only case in which we need to override user ! 1031: * selection if the user chooses LBA and the drive supports only CHS. ! 1032: */ ! 1033: if ((infoPtr->capabilities & IDE_CAP_LBA_SUPPORTED) == 0x0) ! 1034: { ! 1035: _addressMode[unit] = ADDRESS_MODE_CHS; ! 1036: } ! 1037: ! 1038: /* ! 1039: * Set disk parameters. ! 1040: */ ! 1041: [self ideSetParams:_ideInfo[unit].sectors_per_trk ! 1042: numHeads:_ideInfo[unit].heads ForDrive:unit]; ! 1043: ! 1044: /* ! 1045: * Decide how are we going to do data transfers. Is DMA supported? ! 1046: * Multisector support? Verify that the data transfer mode really works ! 1047: * by doing a read operation in that mode. ! 1048: */ ! 1049: [self getTransferModes:infoPtr Unit:unit]; ! 1050: ! 1051: /* ! 1052: * Set the Disk/CDROM transfer mode (Set Features SC=3) ! 1053: */ ! 1054: [self setTransferMode: unit]; ! 1055: ! 1056: if (infoPtr->capabilities & IDE_CAP_DMA_SUPPORTED) ! 1057: { ! 1058: if ( [self allocDmaMemory] == IDER_SUCCESS ) ! 1059: { ! 1060: _dmaSupported[unit] = YES; ! 1061: [self initIdeDma: unit]; ! 1062: } ! 1063: } ! 1064: ! 1065: /* ! 1066: * We don't expect errors here since the drive claims that it can do ! 1067: * multiple sector transfers. ! 1068: */ ! 1069: nSectors = infoPtr->multipleSectors & IDE_MULTI_SECTOR_MASK; ! 1070: ! 1071: if ( nSectors ) ! 1072: { ! 1073: if ([self ideSetMultiSectorMode:&ideRegs ! 1074: numSectors:nSectors] == IDER_SUCCESS) ! 1075: { ! 1076: ! 1077: [self setTransferRate: unit UseDMA: NO]; ! 1078: ! 1079: _multiSector[unit] = nSectors; ! 1080: ideRegs = [self logToPhys:0 numOfBlocks:nSectors]; ! 1081: ! 1082: buf = IOMalloc(nSectors * IDE_SECTOR_SIZE); ! 1083: if ([self ideReadMultiple:&ideRegs ! 1084: client:(struct vm_map *)IOVmTaskSelf() ! 1085: addr:buf] != IDER_SUCCESS) ! 1086: { ! 1087: IOLog("%s: Read Multiple does not work!\n", [self name]); ! 1088: _multiSector[unit] = 0; ! 1089: } ! 1090: IOFree(buf, nSectors * IDE_SECTOR_SIZE); ! 1091: } ! 1092: } ! 1093: /* ! 1094: * A drive may not support set features command. Do we need to do ! 1095: * anything special if this command fails? ! 1096: */ ! 1097: ! 1098: return IDER_SUCCESS; ! 1099: } ! 1100: ! 1101: -(ideIdentifyInfo_t *)getIdeIdentifyInfo:(unsigned int)unit ! 1102: { ! 1103: return _ideIdentifyInfoSupported[unit] ? &_ideIdentifyInfo[unit] : NULL; ! 1104: } ! 1105: ! 1106: -(void)endianSwapIdentifyData:(ideIdentifyInfo_t *)pID ! 1107: { ! 1108: endianSwap16Bit(&pID->genConfig); ! 1109: endianSwap16Bit(&pID->cylinders); ! 1110: endianSwap16Bit(&pID->heads); ! 1111: endianSwap16Bit(&pID->unformattedBytesPerTrack); ! 1112: endianSwap16Bit(&pID->unformattedBytesPerSector); ! 1113: endianSwap16Bit(&pID->sectorsPerTrack); ! 1114: endianSwap16Bit(&pID->bufferType); ! 1115: endianSwap16Bit(&pID->bufferSize); ! 1116: endianSwap16Bit(&pID->eccBytes); ! 1117: endianSwap16Bit(&pID->multipleSectors); ! 1118: endianSwap16Bit(&pID->doubleWordIO); ! 1119: endianSwap16Bit(&pID->capabilities); ! 1120: endianSwap16Bit(&pID->pioDataTransferCyleTimingMode); ! 1121: endianSwap16Bit(&pID->dmaDataTransferCyleTimingMode); ! 1122: endianSwap16Bit(&pID->fieldValidity); ! 1123: endianSwap16Bit(&pID->currentCylinders); ! 1124: endianSwap16Bit(&pID->currentHeads); ! 1125: endianSwap16Bit(&pID->currentSectorsPerTrack); ! 1126: endianSwap16Bit(&pID->capacity[0]); ! 1127: endianSwap16Bit(&pID->capacity[1]); ! 1128: endianSwap16Bit(&pID->multiSectorInfo); ! 1129: endianSwap32Bit(&pID->userAddressableSectors); ! 1130: endianSwap16Bit(&pID->swDma); ! 1131: endianSwap16Bit(&pID->mwDma); ! 1132: endianSwap16Bit(&pID->ultraDma); ! 1133: endianSwap16Bit(&pID->fcPioDataTransferCyleTimingMode); ! 1134: endianSwap16Bit(&pID->minMwDMATransferCycleTimePerWord); ! 1135: endianSwap16Bit(&pID->RecommendedMwDMACycleTime); ! 1136: endianSwap16Bit(&pID->MinPIOTransferCycleTimeWithoutFlowControl); ! 1137: endianSwap16Bit(&pID->MinPIOTransferCycleTimeWithIORDY); ! 1138: } ! 1139: ! 1140: -(void) assignRegisterAddresses: (IOTreeDevice *) deviceDescription ! 1141: { ! 1142: ! 1143: if ( _controllerType == kControllerTypeCmd646X ) ! 1144: { ! 1145: u_int32_t pciRange1, pciRange2; ! 1146: ! 1147: [self mapMemoryRange: 0 to:(vm_address_t *)&pciRange1 findSpace:YES cache:IO_CacheOff]; ! 1148: [self mapMemoryRange: 1 to:(vm_address_t *)&pciRange2 findSpace:YES cache:IO_CacheOff]; ! 1149: ! 1150: _ideRegsAddrs.data = pciRange1; ! 1151: _ideRegsAddrs.error = pciRange1 + 0x1; ! 1152: _ideRegsAddrs.features = pciRange1 + 0x1; ! 1153: _ideRegsAddrs.sectCnt = pciRange1 + 0x2; ! 1154: _ideRegsAddrs.sectNum = pciRange1 + 0x3; ! 1155: _ideRegsAddrs.cylLow = pciRange1 + 0x4; ! 1156: _ideRegsAddrs.cylHigh = pciRange1 + 0x5; ! 1157: _ideRegsAddrs.drHead = pciRange1 + 0x6; ! 1158: _ideRegsAddrs.status = pciRange1 + 0x7; ! 1159: _ideRegsAddrs.command = pciRange1 + 0x7; ! 1160: ! 1161: _ideRegsAddrs.deviceControl = pciRange2 + 0x2; ! 1162: _ideRegsAddrs.altStatus = pciRange2 + 0x2; ! 1163: ! 1164: [(IOPCIDevice *)deviceDescription configWriteLong:0x04 value:0x05]; ! 1165: ! 1166: } ! 1167: else ! 1168: { ! 1169: IORange *IORanges; ! 1170: ! 1171: IORanges = [deviceDescription memoryRangeList]; ! 1172: ! 1173: _ideRegsAddrs.data = IORanges[0].start; ! 1174: _ideRegsAddrs.error = IORanges[0].start + 0x10; ! 1175: _ideRegsAddrs.features = IORanges[0].start + 0x10; ! 1176: _ideRegsAddrs.sectCnt = IORanges[0].start + 0x20; ! 1177: _ideRegsAddrs.sectNum = IORanges[0].start + 0x30; ! 1178: _ideRegsAddrs.cylLow = IORanges[0].start + 0x40; ! 1179: _ideRegsAddrs.cylHigh = IORanges[0].start + 0x50; ! 1180: _ideRegsAddrs.drHead = IORanges[0].start + 0x60; ! 1181: _ideRegsAddrs.status = IORanges[0].start + 0x70; ! 1182: _ideRegsAddrs.command = IORanges[0].start + 0x70; ! 1183: ! 1184: _ideRegsAddrs.deviceControl = IORanges[0].start + 0x160; ! 1185: _ideRegsAddrs.altStatus = IORanges[0].start + 0x160; ! 1186: ! 1187: _ideRegsAddrs.channelConfig = IORanges[0].start + 0x200; ! 1188: ! 1189: _ideDMARegs = (IODBDMAChannelRegisters *)IORanges[1].start; ! 1190: } ! 1191: } ! 1192: ! 1193: ! 1194: @end ! 1195:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.