|
|
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 (c) 1993 NeXT Computer, Inc. ! 26: * ! 27: * ISA/EISA direct device implementation. ! 28: * ! 29: * HISTORY ! 30: * ! 31: * 10Jan93 Brian Pinkerton at NeXT ! 32: * Created. ! 33: * ! 34: * ! 35: * TODO: ! 36: * Implement IOPort reservation ! 37: * Verify that host-master DMA is working with DavidS ! 38: */ ! 39: ! 40: #define KERNEL_PRIVATE 1 ! 41: ! 42: #import <objc/List.h> ! 43: #import <driverkit/i386/directDevice.h> ! 44: #import <driverkit/IODirectDevicePrivate.h> ! 45: #import <driverkit/i386/IOEISADeviceDescription.h> ! 46: #import <driverkit/driverTypes.h> ! 47: #import <driverkit/i386/driverTypesPrivate.h> ! 48: #import <driverkit/generalFuncs.h> ! 49: #import <driverkit/i386/driverTypes.h> ! 50: #import <driverkit/i386/EISAKernBus.h> ! 51: #import <driverkit/KernDevice.h> ! 52: #import <driverkit/KernDeviceDescription.h> ! 53: #import <driverkit/kernelDriver.h> ! 54: #import <driverkit/interruptMsg.h> ! 55: #import <machdep/i386/dma_exported.h> ! 56: #import <machdep/i386/dma.h> ! 57: #import <machdep/i386/xpr.h> ! 58: #import <machkit/NXLock.h> ! 59: #import <kernserv/lock.h> ! 60: #import <kernserv/prototypes.h> ! 61: ! 62: #import <objc/HashTable.h> ! 63: ! 64: extern NXLock *dmaLock; // in autoconf_i386.m ! 65: ! 66: @interface IODirectDevice(EISAPrivate) ! 67: ! 68: - (unsigned int) _localToChannel:(unsigned int) localChannel; ! 69: - initEISA; ! 70: - freeEISA; ! 71: ! 72: @end ! 73: ! 74: struct _eisa_private { ! 75: Arch type; ! 76: }; ! 77: ! 78: @implementation IODirectDevice(IOEISADirectDevice) ! 79: ! 80: - initEISA ! 81: { ! 82: struct _eisa_private *private; ! 83: ! 84: private = _busPrivate = (void *)IOMalloc(sizeof (*private)); ! 85: private->type = EISA; ! 86: ! 87: return self; ! 88: } ! 89: ! 90: - freeEISA ! 91: { ! 92: struct _eisa_private *private = _busPrivate; ! 93: ! 94: IOFree((void *)private, sizeof (*private)); ! 95: ! 96: return self; ! 97: } ! 98: ! 99: /* ! 100: * A bunch of convenient private API: ! 101: * ! 102: * Map from local channel numbers to real ones, and from local IRQ numbers ! 103: * to real ones. ! 104: */ ! 105: - (unsigned int) _localToChannel:(unsigned int) localChannel ! 106: { ! 107: return [(IOEISADeviceDescription *)_deviceDescription channelList][localChannel]; ! 108: } ! 109: ! 110: ! 111: /* ! 112: * Routines for dealing with interrupts start here. ! 113: */ ! 114: ! 115: - (IOReturn) reserveInterrupt : (unsigned int)localInterrupt ! 116: { ! 117: return IO_R_SUCCESS; ! 118: } ! 119: ! 120: - (void) releaseInterrupt : (unsigned int) localInterrupt ! 121: { ! 122: } ! 123: ! 124: ! 125: ! 126: ! 127: /* ! 128: * The subclass overrides this method. In the superclass, we just ! 129: * return NO. ! 130: */ ! 131: - (BOOL) getHandler:(IOEISAInterruptHandler *)handler ! 132: level:(unsigned int *)ipl ! 133: argument:(unsigned int *) arg ! 134: forInterrupt:(unsigned int) localInterrupt ! 135: { ! 136: return NO; ! 137: } ! 138: ! 139: ! 140: - (IOReturn) reserveChannel : (unsigned int) localChannel ! 141: { ! 142: return IO_R_SUCCESS; ! 143: } ! 144: ! 145: - (void) releaseChannel : (unsigned int) localChannel ! 146: { ! 147: } ! 148: ! 149: - (IOReturn) enableChannel:(unsigned int) localChannel ! 150: { ! 151: unsigned int realChannel; ! 152: ! 153: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 154: return IO_R_INVALID_ARG; ! 155: ! 156: realChannel = [self _localToChannel:localChannel]; ! 157: ! 158: dma_unmask_chan(realChannel); ! 159: return IO_R_SUCCESS; ! 160: } ! 161: ! 162: ! 163: - (void) disableChannel:(unsigned int) localChannel ! 164: { ! 165: unsigned int realChannel; ! 166: ! 167: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 168: return; ! 169: ! 170: realChannel = [self _localToChannel:localChannel]; ! 171: ! 172: dma_mask_chan(realChannel); ! 173: } ! 174: ! 175: ! 176: - (IOReturn) setTransferMode : (IODMATransferMode) mode ! 177: forChannel : (unsigned int) localChannel; ! 178: { ! 179: int real_mode; ! 180: unsigned int realChannel; ! 181: ! 182: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 183: return IO_R_INVALID_ARG; ! 184: ! 185: realChannel = [self _localToChannel:localChannel]; ! 186: ! 187: switch(mode) { ! 188: case IO_Demand: ! 189: real_mode = DMA_MODE_DEMAND; ! 190: break; ! 191: case IO_Single: ! 192: real_mode = DMA_MODE_SINGLE; ! 193: break; ! 194: case IO_Block: ! 195: real_mode = DMA_MODE_BLOCK; ! 196: break; ! 197: case IO_Cascade: ! 198: real_mode = DMA_MODE_CASCADE; ! 199: break; ! 200: } ! 201: dma_chan_xfer_mode(realChannel, real_mode); ! 202: return IO_R_SUCCESS; ! 203: } ! 204: ! 205: /* ! 206: * Enable/disable autoinitialize DMA mode. Default is ! 207: * disabled. ! 208: */ ! 209: - (IOReturn)setAutoinitialize : (BOOL)flag ! 210: forChannel : (unsigned)localChannel ! 211: { ! 212: unsigned int realChannel; ! 213: ! 214: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 215: return IO_R_INVALID_ARG; ! 216: ! 217: realChannel = [self _localToChannel:localChannel]; ! 218: ! 219: dma_chan_autoinit(realChannel, (flag ? 1 : 0)); ! 220: return IO_R_SUCCESS; ! 221: } ! 222: ! 223: /* ! 224: * Set DMA address increment/decrement mode. ! 225: * Default is IO_Increment. ! 226: */ ! 227: - (IOReturn)setIncrementMode : (IOIncrementMode)mode ! 228: forChannel : (unsigned)localChannel ! 229: { ! 230: unsigned int realChannel; ! 231: int dir; ! 232: ! 233: if(mode == IO_Decrement) { ! 234: return IO_R_UNSUPPORTED; // nope! ! 235: } ! 236: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 237: return IO_R_INVALID_ARG; ! 238: ! 239: realChannel = [self _localToChannel:localChannel]; ! 240: ! 241: dir = (mode == IO_Decrement ? DMA_ADRS_DECR : DMA_ADRS_INCR); ! 242: dma_chan_adrs_dir(realChannel, dir); ! 243: return IO_R_SUCCESS; ! 244: } ! 245: ! 246: ! 247: /* ! 248: * Returns a DMA buffer for the contents of physical memory starting at ! 249: * addr and continuing for length bytes. If the physical address changed ! 250: * to accommodate the ISA bus, the new physical address is returned in ! 251: * place. The DMABuffer is an opaque type. ! 252: * ! 253: * Warning: this method allocates memory, so it can block! ! 254: */ ! 255: - (IOEISADMABuffer) createDMABufferFor:(unsigned int *) physAddr ! 256: length:(unsigned int) length ! 257: read:(BOOL) isRead ! 258: needsLowMemory:(BOOL) lowerMem ! 259: limitSize:(BOOL) limitSize ! 260: { ! 261: dma_xfer_t *xfer = IOMalloc(sizeof(dma_xfer_t)); ! 262: ! 263: if (xfer == NULL) ! 264: return NULL; ! 265: ! 266: xfer->phys = *physAddr; ! 267: xfer->len = length; ! 268: xfer->read = isRead; ! 269: xfer->lower16 = lowerMem; ! 270: xfer->bound64 = limitSize; ! 271: xfer->buffered = FALSE; ! 272: ! 273: if (!dma_xfer(xfer, physAddr)) { ! 274: xpr_dmabuf("createDMABufferFor: dma_xfer() failed; physAddr" ! 275: "0x%x\n", physAddr, 2,3,4,5); ! 276: IOFree(xfer, sizeof(dma_xfer_t)); ! 277: return NULL; ! 278: } ! 279: ! 280: xpr_dmabuf("createDMABufferFor: xfer 0x%x\n", xfer, 2,3,4,5); ! 281: return (IOEISADMABuffer) xfer; ! 282: } ! 283: ! 284: ! 285: - (void) freeDMABuffer:(IOEISADMABuffer) dmaBuffer ! 286: { ! 287: dma_xfer_t *xfer = (dma_xfer_t *) dmaBuffer; ! 288: ! 289: xpr_dmabuf("freeDMABuffer: dmaBuffer active %d 0x%x\n", ! 290: xfer, xfer->active,3,4,5); ! 291: if (xfer->active) ! 292: dma_xfer_done(xfer); ! 293: IOFree(xfer, sizeof(dma_xfer_t)); ! 294: } ! 295: ! 296: ! 297: - (void) abortDMABuffer:(IOEISADMABuffer) dmaBuffer ! 298: { ! 299: dma_xfer_t *xfer = (dma_xfer_t *) dmaBuffer; ! 300: ! 301: xpr_dmabuf("abortDMABuffer: dmaBuffer active %d 0x%x\n", ! 302: xfer, xfer->active,3,4,5); ! 303: if (xfer->active) ! 304: dma_xfer_abort(xfer); ! 305: IOFree(xfer, sizeof(dma_xfer_t)); ! 306: } ! 307: ! 308: - (IOReturn) startDMAForBuffer:(IOEISADMABuffer) buffer channel:(unsigned int) localChannel ! 309: { ! 310: unsigned int realChannel; ! 311: ! 312: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 313: return IO_R_INVALID_ARG; ! 314: ! 315: realChannel = [self _localToChannel:localChannel]; ! 316: ! 317: if (dma_xfer_chan(realChannel, (dma_xfer_t *) buffer)) ! 318: return IO_R_SUCCESS; ! 319: else ! 320: return IO_R_NO_FRAMES; /* XXX */ ! 321: } ! 322: ! 323: /* ! 324: * Return localChannel's current address and count. ! 325: */ ! 326: - (unsigned)currentAddressForChannel : (unsigned)localChannel ! 327: { ! 328: unsigned int realChannel; ! 329: ! 330: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 331: return 0; ! 332: realChannel = [self _localToChannel:localChannel]; ! 333: return(get_dma_addr(realChannel)); ! 334: } ! 335: ! 336: - (unsigned)currentCountForChannel : (unsigned)localChannel ! 337: { ! 338: unsigned int realChannel; ! 339: ! 340: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 341: return 0; ! 342: realChannel = [self _localToChannel:localChannel]; ! 343: return(get_dma_count(realChannel)); ! 344: } ! 345: ! 346: ! 347: - (BOOL) isDMADone:(unsigned int) localChannel ! 348: { ! 349: if (localChannel >= [(IOEISADeviceDescription *)_deviceDescription numChannels]) ! 350: return NO; ! 351: ! 352: return (is_dma_done([self _localToChannel:localChannel]) ? ! 353: YES : NO); ! 354: } ! 355: ! 356: ! 357: ! 358: ! 359: /* ! 360: * Determine whether or not the aassociated device is connected to an EISA ! 361: * bus. Returns YES if so, else returns NO. ! 362: */ ! 363: extern BOOL is_ISA; // in driverkit/i386/autoconf_i386.m ! 364: ! 365: - (BOOL)isEISAPresent ! 366: { ! 367: return (is_ISA ? NO : YES); ! 368: } ! 369: ! 370: - (BOOL)getEISAId: (unsigned int *)_id forSlot: (int) slot ! 371: { ! 372: return eisa_id(slot, _id); ! 373: } ! 374: ! 375: /* ! 376: * DMA lock package. ! 377: */ ! 378: ! 379: typedef struct _dmaQueueEntry dmaQueueEntry; ! 380: struct _dmaQueueEntry { ! 381: id device; ! 382: int count; ! 383: dmaQueueEntry *next; ! 384: }; ! 385: ! 386: static dmaQueueEntry *dmaQueueHead; ! 387: static dmaQueueEntry *dmaQueueTail; ! 388: static int sleepChannel; // for sleep/wakeup ! 389: static simple_lock_t dmaSpinLock; // ditto ! 390: ! 391: int dmaLockDisable = 0; ! 392: ! 393: extern void thread_wakeup(int x); ! 394: ! 395: /* ! 396: * Init routine, called out from dev_server_init(). ! 397: */ ! 398: void initDmaLock() ! 399: { ! 400: dmaQueueHead = NULL; ! 401: dmaQueueTail = NULL; ! 402: dmaSpinLock = simple_lock_alloc(); ! 403: simple_lock_init(dmaSpinLock); ! 404: } ! 405: ! 406: /* ! 407: * Sleep until specified dmaQueueEntry is at the head of dmaQueue. ! 408: * Note we have to wait for a specific dmaQueueEntry to bubble to the head, ! 409: * not just any dmaQueueEntry for a specific device, since one device can have ! 410: * one entry at the head and another somewhere back in line. ! 411: * ! 412: * dmaSpinLock held on entry and exit. ! 413: */ ! 414: static void waitTilHead(dmaQueueEntry *queueEntry) ! 415: { ! 416: while(queueEntry != dmaQueueHead) { ! 417: thread_sleep((int)&sleepChannel, dmaSpinLock, FALSE); ! 418: simple_lock(dmaSpinLock); ! 419: } ! 420: } ! 421: ! 422: /* ! 423: * Cons up a new dmaQueueEntry, count of 1, for specified device. ! 424: */ ! 425: static inline dmaQueueEntry *queueEntryAlloc(id device) ! 426: { ! 427: dmaQueueEntry *queueEntry = IOMalloc(sizeof(dmaQueueEntry)); ! 428: ! 429: queueEntry->count = 1; ! 430: queueEntry->device = device; ! 431: queueEntry->next = NULL; ! 432: return queueEntry; ! 433: } ! 434: ! 435: /* ! 436: * Free a dmaQueueEntry. ! 437: */ ! 438: static inline void queueEntryFree(dmaQueueEntry *queueEntry) ! 439: { ! 440: ASSERT(queueEntry->count == 0); ! 441: IOFree(queueEntry, sizeof(dmaQueueEntry)); ! 442: } ! 443: ! 444: /* ! 445: * Acquire dma lock. Allows multiple threads associated with one device ! 446: * instance to hold the DMA lock siimultaneously. If calling device ! 447: * owns the lock but other devices are blocked waiting for it, calling ! 448: * thread will block, and will not acquire the lock until all other pending ! 449: * requests are honored. ! 450: */ ! 451: - (void)reserveDMALock ! 452: { ! 453: dmaQueueEntry *queueEntry; ! 454: dmaQueueEntry *newQueueEntry; ! 455: ! 456: if([self isEISAPresent] || dmaLockDisable) { ! 457: return; ! 458: } ! 459: newQueueEntry = queueEntryAlloc(self); ! 460: simple_lock(dmaSpinLock); ! 461: if(dmaQueueHead == NULL) { ! 462: /* ! 463: * Trivial quiescent case. ! 464: */ ! 465: dmaQueueHead = dmaQueueTail = newQueueEntry; ! 466: simple_unlock(dmaSpinLock); ! 467: return; ! 468: } ! 469: queueEntry = dmaQueueHead; ! 470: if((queueEntry->device == self) && (queueEntry->next == NULL)) { ! 471: /* ! 472: * This device owns the lock, and no other requests pending. ! 473: */ ! 474: queueEntry->count++; ! 475: simple_unlock(dmaSpinLock); ! 476: queueEntryFree(newQueueEntry); ! 477: return; ! 478: } ! 479: ! 480: /* ! 481: * See if any subsequent entries (after the first one) match this ! 482: * device. ! 483: */ ! 484: queueEntry = queueEntry->next; ! 485: while(queueEntry) { ! 486: if(queueEntry->device == self) { ! 487: /* ! 488: * Calling device has a request pending, not at head ! 489: * of queue. Lump these together. ! 490: */ ! 491: queueEntry->count++; ! 492: waitTilHead(queueEntry); ! 493: simple_unlock(dmaSpinLock); ! 494: queueEntryFree(newQueueEntry); ! 495: return; ! 496: } ! 497: queueEntry = queueEntry->next; ! 498: } ! 499: ! 500: /* ! 501: * New request for this device. ! 502: */ ! 503: dmaQueueTail->next = newQueueEntry; ! 504: dmaQueueTail = newQueueEntry; ! 505: waitTilHead(newQueueEntry); ! 506: simple_unlock(dmaSpinLock); ! 507: return; ! 508: } ! 509: ! 510: - (void)releaseDMALock ! 511: { ! 512: dmaQueueEntry *queueEntry = dmaQueueHead; ! 513: dmaQueueEntry *freeQueueEntry = NULL; ! 514: boolean_t needWakeup = FALSE; ! 515: ! 516: if([self isEISAPresent] || dmaLockDisable) { ! 517: return; ! 518: } ! 519: simple_lock(dmaSpinLock); ! 520: if(queueEntry->device != self) { ! 521: simple_unlock(dmaSpinLock); ! 522: IOLog("%s: releaseDmaLock when not holding lock\n", ! 523: [self name]); ! 524: panic("releaseDMALock"); ! 525: } ! 526: if(--queueEntry->count == 0) { ! 527: /* ! 528: * This device is done. Wake up others, if any. ! 529: */ ! 530: needWakeup = (queueEntry->next != NULL); ! 531: freeQueueEntry = queueEntry; ! 532: dmaQueueHead = queueEntry->next; ! 533: } ! 534: simple_unlock(dmaSpinLock); ! 535: if(needWakeup) { ! 536: thread_wakeup((int)&sleepChannel); ! 537: } ! 538: if(freeQueueEntry != NULL) { ! 539: queueEntryFree(freeQueueEntry); ! 540: } ! 541: } ! 542: ! 543: /* ! 544: * Support for the extended mode register (EISA only). ! 545: */ ! 546: ! 547: - (IOReturn)setDMATransferWidth : (IOEISADMATransferWidth)width ! 548: forChannel : (unsigned)localChannel ! 549: { ! 550: unsigned int realChannel; ! 551: int dmaWidth; ! 552: ! 553: if((width == IO_16BitWordCount) || is_ISA) { ! 554: return IO_R_UNSUPPORTED; ! 555: } ! 556: if (localChannel >= [[self deviceDescription] numChannels]) { ! 557: return IO_R_INVALID_ARG; ! 558: } ! 559: realChannel = [self _localToChannel:localChannel]; ! 560: ! 561: switch(width) { ! 562: case IO_8Bit: ! 563: dmaWidth = DMA_XFR_8_BIT; ! 564: break; ! 565: case IO_16BitWordCount: ! 566: dmaWidth = DMA_XFR_16_BIT_WORD; ! 567: break; ! 568: case IO_16BitByteCount: ! 569: dmaWidth = DMA_XFR_16_BIT_BYTE; ! 570: break; ! 571: case IO_32Bit: ! 572: dmaWidth = DMA_XFR_32_BIT; ! 573: break; ! 574: default: ! 575: return IO_R_INVALID_ARG; ! 576: } ! 577: dma_xfer_width(realChannel, dmaWidth); ! 578: return IO_R_SUCCESS; ! 579: } ! 580: ! 581: - (IOReturn)getDMATransferWidth : (IOEISADMATransferWidth *)width_p ! 582: forChannel : (unsigned)localChannel ! 583: { ! 584: unsigned int realChannel; ! 585: int width; ! 586: ! 587: if (localChannel >= [[self deviceDescription] numChannels]) { ! 588: return IO_R_INVALID_ARG; ! 589: } ! 590: realChannel = [self _localToChannel:localChannel]; ! 591: ! 592: width = get_dma_xfer_width(realChannel); ! 593: switch(width) { ! 594: case DMA_XFR_8_BIT: ! 595: *width_p = IO_8Bit; ! 596: break; ! 597: case DMA_XFR_16_BIT_WORD: ! 598: *width_p = IO_16BitWordCount; ! 599: break; ! 600: case DMA_XFR_16_BIT_BYTE: ! 601: *width_p = IO_16BitByteCount; ! 602: break; ! 603: case DMA_XFR_32_BIT: ! 604: *width_p = IO_32Bit; ! 605: break; ! 606: default: /* should never be reached */ ! 607: return IO_R_NOT_ATTACHED; ! 608: } ! 609: return IO_R_SUCCESS; ! 610: } ! 611: ! 612: /* ! 613: * Select DMA Timing. ! 614: */ ! 615: - (IOReturn)setDMATiming : (IOEISADMATiming)timing ! 616: forChannel : (unsigned)localChannel ! 617: { ! 618: unsigned int realChannel; ! 619: int dmaTiming; ! 620: ! 621: if(is_ISA) { ! 622: return IO_R_UNSUPPORTED; ! 623: } ! 624: if (localChannel >= [[self deviceDescription] numChannels]) { ! 625: return IO_R_INVALID_ARG; ! 626: } ! 627: realChannel = [self _localToChannel:localChannel]; ! 628: ! 629: switch(timing) { ! 630: case IO_Compatible: ! 631: dmaTiming = DMA_TIMING_COMPAT; ! 632: break; ! 633: case IO_TypeA: ! 634: dmaTiming = DMA_TIMING_A; ! 635: break; ! 636: case IO_TypeB: ! 637: dmaTiming = DMA_TIMING_B; ! 638: break; ! 639: case IO_Burst: ! 640: dmaTiming = DMA_TIMING_BURST; ! 641: break; ! 642: } ! 643: dma_timing(realChannel, dmaTiming); ! 644: return IO_R_SUCCESS; ! 645: } ! 646: ! 647: /* ! 648: * Select whether EOP pin is output (default) or input. ! 649: */ ! 650: - (IOReturn)setEOPAsOutput : (BOOL)flag ! 651: forChannel : (unsigned)localChannel ! 652: { ! 653: unsigned realChannel; ! 654: unsigned dmaFlag; ! 655: ! 656: if(is_ISA) { ! 657: return IO_R_UNSUPPORTED; ! 658: } ! 659: if (localChannel >= [[self deviceDescription] numChannels]) { ! 660: return IO_R_INVALID_ARG; ! 661: } ! 662: realChannel = [self _localToChannel:localChannel]; ! 663: ! 664: dmaFlag = (flag ? DMA_EOP_OUT : DMA_EOP_IN); ! 665: dma_eop_in(realChannel, dmaFlag); ! 666: return IO_R_SUCCESS; ! 667: } ! 668: ! 669: /* ! 670: * Enable Stop register. Default is disabled; enabling this feature ! 671: * is not supported in [PR2]the current release. ! 672: */ ! 673: - (IOReturn)setStopRegisterMode : (IOEISAStopRegisterMode)mode ! 674: forChannel : (unsigned)localChannel ! 675: { ! 676: unsigned realChannel; ! 677: unsigned dmaFlag; ! 678: ! 679: if((mode == IO_StopRegisterEnable) || is_ISA) { ! 680: return IO_R_UNSUPPORTED; ! 681: } ! 682: if (localChannel >= [[self deviceDescription] numChannels]) { ! 683: return IO_R_INVALID_ARG; ! 684: } ! 685: realChannel = [self _localToChannel:localChannel]; ! 686: ! 687: if(mode == IO_StopRegisterEnable) { ! 688: dmaFlag = DMA_STOP_ENABLE; ! 689: } ! 690: else { ! 691: dmaFlag = DMA_STOP_DISABLE; ! 692: } ! 693: dma_stop_enable(realChannel, dmaFlag); ! 694: return IO_R_SUCCESS; ! 695: } ! 696: ! 697: - (IOReturn) reservePortRange : (unsigned int) localPortRange ! 698: { ! 699: return IO_R_SUCCESS; ! 700: } ! 701: ! 702: - (void) releasePortRange : (unsigned int) localPortRange ! 703: { ! 704: } ! 705: ! 706: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.