|
|
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: /* Copyright (c) 1993 NeXT Computer, Inc. All rights reserved. ! 25: * ! 26: * IODirectDevice class implementation. ! 27: * ! 28: * HISTORY ! 29: * 08-Jan-93 Doug Mitchell at NeXT ! 30: * Created. ! 31: */ ! 32: ! 33: #ifdef KERNEL ! 34: #define MACH_USER_API 1 ! 35: #endif KERNEL ! 36: ! 37: #import <objc/List.h> ! 38: #import <driverkit/IODirectDevice.h> ! 39: #import <driverkit/IODirectDevicePrivate.h> ! 40: #import <driverkit/IODeviceDescriptionPrivate.h> ! 41: #import <driverkit/generalFuncs.h> ! 42: #import <driverkit/KernDeviceDescription.h> ! 43: #import <driverkit/KernDevice.h> ! 44: #import <driverkit/KernBusMemory.h> ! 45: #import <driverkit/interruptMsg.h> ! 46: #import <mach/mach_types.h> ! 47: #import <mach/mach_interface.h> ! 48: ! 49: @interface IODirectDevice(EISAPrivate) ! 50: - initEISA; ! 51: - freeEISA; ! 52: @end ! 53: @interface IODirectDevice(HPPAPrivate) ! 54: - initHPPA; ! 55: - freeHPPA; ! 56: @end ! 57: @interface IODirectDevice(SPARCPrivate) ! 58: - initSPARC; ! 59: - freeSPARC; ! 60: @end ! 61: @interface IODirectDevice(PPCPrivate) ! 62: - initPPC; ! 63: - freePPC; ! 64: @end ! 65: ! 66: @interface IODirectDevice(InterruptPrivate) ! 67: - (IOReturn) _changeInterrupt:(unsigned int) localInterrupt to:(BOOL) enable; ! 68: @end ! 69: ! 70: #define NUM_LOCAL_INTS 4 ! 71: ! 72: typedef struct _IODirectDevicePrivate { ! 73: id memory_mappings; ! 74: id device_interrupts; ! 75: id local_device_interrupts[ NUM_LOCAL_INTS ]; ! 76: } IODirectDevicePrivate; ! 77: ! 78: #define IO_EXIT_THREAD_MSG IO_FIRST_UNRESERVED_INTERRUPT_MSG ! 79: ! 80: @implementation IODirectDevice ! 81: ! 82: /* ! 83: * By defintion, all subclasses of this class are of style IO_DirectDevice. ! 84: * Subclasses need not implement this method. ! 85: */ ! 86: + (IODeviceStyle)deviceStyle ! 87: { ! 88: return IO_DirectDevice; ! 89: } ! 90: ! 91: - initFromDeviceDescription: deviceDescription ! 92: { ! 93: IODirectDevicePrivate *private; ! 94: [super init]; ! 95: ! 96: [self setDeviceDescription:deviceDescription]; ! 97: ! 98: #if i386 ! 99: [self initEISA]; ! 100: #elif ppc ! 101: [self initPPC]; ! 102: #elif hppa ! 103: [self initHPPA]; ! 104: #elif sparc ! 105: [self initSPARC]; ! 106: #endif ! 107: private = _private = (void *)IOMalloc(sizeof (*private)); ! 108: bzero( private, sizeof (*private)); ! 109: ! 110: return self; ! 111: } ! 112: ! 113: - init ! 114: { ! 115: return [self free]; ! 116: } ! 117: ! 118: - free ! 119: { ! 120: IODirectDevicePrivate *private = _private; ! 121: struct _private *busPrivate = _busPrivate; ! 122: msg_header_t msg = { 0 }; ! 123: ! 124: if (_interruptPort) { ! 125: if (_ioThread) { ! 126: msg.msg_size = sizeof (msg); ! 127: msg.msg_id = IO_EXIT_THREAD_MSG; ! 128: #ifdef KERNEL ! 129: msg.msg_remote_port = IOGetKernPort(_interruptPort); ! 130: msg_send_from_kernel(&msg, MSG_OPTION_NONE, 0); ! 131: #else ! 132: msg.msg_remote_port = _interruptPort; ! 133: msg_send(&msg, MSG_OPTION_NONE, 0); ! 134: #endif KERNEL ! 135: } ! 136: ! 137: [[_deviceDescriptionDelegate device] detachInterruptPort]; ! 138: (void) port_deallocate(task_self(), _interruptPort); ! 139: _interruptPort = PORT_NULL; ! 140: } ! 141: ! 142: if (busPrivate) { ! 143: if (busPrivate->type == EISA) ! 144: [self freeEISA]; ! 145: else if (busPrivate->type == ArchPPC) ! 146: [self freePPC]; ! 147: else if (busPrivate->type == HPPA) ! 148: [self freeHPPA]; ! 149: else if (busPrivate->type == SPARC) ! 150: [self freeSPARC]; ! 151: } ! 152: ! 153: if (private) { ! 154: if (private->memory_mappings) ! 155: [private->memory_mappings free]; ! 156: if (private->device_interrupts) ! 157: [private->device_interrupts free]; ! 158: IOFree((void *)private, sizeof (*private)); ! 159: } ! 160: ! 161: return [super free]; ! 162: } ! 163: ! 164: - (void)setDeviceDescription : deviceDescription ! 165: { ! 166: [super setDeviceDescription:deviceDescription]; ! 167: _deviceDescription = deviceDescription; ! 168: _deviceDescriptionDelegate = [deviceDescription _delegate]; ! 169: } ! 170: ! 171: - (port_t)interruptPort ! 172: { ! 173: return _interruptPort; ! 174: } ! 175: ! 176: - (IOReturn) attachInterruptPort ! 177: { ! 178: if (_interruptPort == PORT_NULL) { ! 179: if (port_allocate(task_self(), &_interruptPort)) ! 180: return IO_R_NOT_ATTACHED; ! 181: ! 182: /* ! 183: * Don't attach unless interrupts have been configured. ! 184: */ ! 185: if ([[_deviceDescriptionDelegate device] ! 186: attachInterruptPort:_interruptPort] == nil) { ! 187: (void) port_deallocate(task_self(), _interruptPort); ! 188: _interruptPort = PORT_NULL; ! 189: ! 190: return IO_R_NOT_ATTACHED; ! 191: } ! 192: } ! 193: ! 194: return IO_R_SUCCESS; ! 195: } ! 196: ! 197: static void ! 198: IODirectDeviceThread(id device); ! 199: ! 200: - (IOReturn)startIOThreadWithPriority:(int)priority ! 201: { ! 202: IOReturn result = IO_R_SUCCESS; ! 203: ! 204: if (_ioThread == NULL) { ! 205: result = [self attachInterruptPort]; ! 206: ! 207: if (result == IO_R_SUCCESS) { ! 208: _ioThread = IOForkThread((IOThreadFunc)IODirectDeviceThread, self); ! 209: if (priority >= 0) ! 210: (void) IOSetThreadPriority(_ioThread, priority); ! 211: } ! 212: } ! 213: ! 214: return (result); ! 215: } ! 216: ! 217: - (IOReturn)startIOThreadWithFixedPriority:(int)priority ! 218: { ! 219: IOReturn result = IO_R_SUCCESS; ! 220: ! 221: if (_ioThread == NULL) { ! 222: result = [self startIOThreadWithPriority:priority]; ! 223: if (result == IO_R_SUCCESS) ! 224: (void) IOSetThreadPolicy(_ioThread, POLICY_FIXEDPRI); ! 225: } ! 226: ! 227: return (result); ! 228: } ! 229: ! 230: - (IOReturn)startIOThread ! 231: { ! 232: return [self startIOThreadWithPriority:-1]; ! 233: } ! 234: ! 235: - (IOReturn)waitForInterrupt:(int *)id ! 236: { ! 237: IOInterruptMsg interruptMsg; ! 238: kern_return_t result; ! 239: msg_option_t option = RCV_TIMEOUT | RCV_LARGE; ! 240: ! 241: if (_interruptPort == PORT_NULL) ! 242: return (IO_R_NO_INTERRUPT); ! 243: ! 244: do { ! 245: interruptMsg.header.msg_size = sizeof (interruptMsg); ! 246: interruptMsg.header.msg_local_port = _interruptPort; ! 247: ! 248: result = msg_receive(&interruptMsg.header, option, 0); ! 249: if (result == RCV_TOO_LARGE) ! 250: return (IO_R_MSG_TOO_LARGE); ! 251: ! 252: if (result != RCV_SUCCESS && result != RCV_TIMED_OUT) { ! 253: IOLog("%s: %s waitForInterrupt: msg_receive returns %d\n", ! 254: [self name], [self deviceKind], result); ! 255: return (IO_R_IPC_FAILURE); ! 256: } ! 257: ! 258: if (option & RCV_TIMEOUT) { ! 259: if (result == RCV_TIMED_OUT) ! 260: option = RCV_LARGE; ! 261: else /* if (result == RCV_SUCCESS) */ ! 262: (void) thread_block(); ! 263: } ! 264: } while (result != RCV_SUCCESS); ! 265: ! 266: *id = interruptMsg.header.msg_id; ! 267: ! 268: return (IO_R_SUCCESS); ! 269: } ! 270: ! 271: - (void)receiveMsg ! 272: { ! 273: IOInterruptMsg interruptMsg; ! 274: ! 275: if (_interruptPort == PORT_NULL) ! 276: return; ! 277: ! 278: interruptMsg.header.msg_size = sizeof (interruptMsg); ! 279: interruptMsg.header.msg_local_port = _interruptPort; ! 280: ! 281: (void) msg_receive(&interruptMsg.header, MSG_OPTION_NONE, 0); ! 282: } ! 283: ! 284: - (void)timeoutOccurred ! 285: { ! 286: } ! 287: ! 288: - (void)interruptOccurred ! 289: { ! 290: [self interruptOccurredAt:0]; ! 291: } ! 292: ! 293: - (void)interruptOccurredAt:(int)localNum ! 294: { ! 295: } ! 296: ! 297: - (void)commandRequestOccurred ! 298: { ! 299: } ! 300: ! 301: - (void)otherOccurred:(int)id ! 302: { ! 303: } ! 304: ! 305: @end /* IODirectDevice */ ! 306: ! 307: @implementation IODirectDevice(IOInterrupts) ! 308: ! 309: - (IOReturn) enableAllInterrupts ! 310: { ! 311: unsigned int i, max = [_deviceDescription numInterrupts]; ! 312: ! 313: for (i=0; i < max; i++) { ! 314: if ([self enableInterrupt:i] != IO_R_SUCCESS) { ! 315: [self disableAllInterrupts]; ! 316: return IO_R_NOT_ATTACHED; ! 317: } ! 318: } ! 319: return IO_R_SUCCESS; ! 320: } ! 321: ! 322: ! 323: - (void) disableAllInterrupts ! 324: { ! 325: unsigned int i, max = [_deviceDescription numInterrupts]; ! 326: ! 327: for (i=0; i < max; i++) ! 328: [self disableInterrupt:i]; ! 329: } ! 330: ! 331: - (IOReturn) enableInterrupt:(unsigned int) localInterrupt ! 332: { ! 333: IODirectDevicePrivate *private = _private; ! 334: ! 335: if( (localInterrupt < NUM_LOCAL_INTS) && private->local_device_interrupts[ localInterrupt ]) { ! 336: [private->local_device_interrupts[ localInterrupt ] resume]; ! 337: return IO_R_SUCCESS; ! 338: } ! 339: ! 340: if ([self attachInterruptPort] != IO_R_SUCCESS) ! 341: return IO_R_NOT_ATTACHED; ! 342: return [self _changeInterrupt:localInterrupt to:YES]; ! 343: } ! 344: ! 345: ! 346: - (void) disableInterrupt:(unsigned int) localInterrupt ! 347: { ! 348: IODirectDevicePrivate *private = _private; ! 349: ! 350: if( (localInterrupt < NUM_LOCAL_INTS) && private->local_device_interrupts[ localInterrupt ]) { ! 351: [private->local_device_interrupts[ localInterrupt ] suspend]; ! 352: return; ! 353: } ! 354: [self _changeInterrupt:localInterrupt to:NO]; ! 355: } ! 356: ! 357: /* ! 358: * The subclass overrides this method. In the superclass, we just ! 359: * return NO. ! 360: */ ! 361: - (BOOL) getHandler:(IOInterruptHandler *)handler ! 362: level:(unsigned int *)ipl ! 363: argument:(unsigned int *) arg ! 364: forInterrupt:(unsigned int) localInterrupt ! 365: { ! 366: return NO; ! 367: } ! 368: ! 369: @end ! 370: ! 371: @implementation IODirectDevice(InterruptPrivate) ! 372: ! 373: - (IOReturn) _changeInterrupt:(unsigned int) localInterrupt to:(BOOL) enable ! 374: { ! 375: IODirectDevicePrivate *private = _private; ! 376: id interrupt; ! 377: ! 378: if (localInterrupt >= [_deviceDescription numInterrupts]) ! 379: return IO_R_INVALID_ARG; ! 380: ! 381: if (private->device_interrupts == nil) ! 382: private->device_interrupts = ! 383: [[HashTable alloc] initKeyDesc:"i"]; ! 384: interrupt = [private->device_interrupts ! 385: valueForKey:(void *)localInterrupt]; ! 386: if (interrupt == nil) { ! 387: IOInterruptHandler handler; ! 388: unsigned int ipl = 3; /* XXX */ ! 389: unsigned int arg = 0; ! 390: id busInterrupt; ! 391: ! 392: interrupt = [[_deviceDescriptionDelegate device] ! 393: interrupt:localInterrupt]; ! 394: [private->device_interrupts ! 395: insertKey:(void *)localInterrupt ! 396: value:interrupt]; ! 397: if( localInterrupt < NUM_LOCAL_INTS) ! 398: private->local_device_interrupts[ localInterrupt ] = interrupt; ! 399: busInterrupt = [[_deviceDescriptionDelegate ! 400: resourcesForKey:IRQ_LEVELS_KEY] ! 401: objectAt:localInterrupt]; ! 402: if ([self getHandler:&handler ! 403: level:&ipl ! 404: argument:&arg ! 405: forInterrupt:localInterrupt]) ! 406: [interrupt attachToBusInterrupt:busInterrupt ! 407: withSpecialHandler:handler ! 408: argument:(void *)arg ! 409: atLevel:ipl]; ! 410: else ! 411: [interrupt attachToBusInterrupt:busInterrupt ! 412: withArgument:(void *) ! 413: (IO_DEVICE_INTERRUPT_MSG + ! 414: localInterrupt)]; ! 415: } ! 416: ! 417: if (enable) ! 418: [interrupt resume]; ! 419: else ! 420: [interrupt suspend]; ! 421: ! 422: return IO_R_SUCCESS; ! 423: } ! 424: ! 425: ! 426: @end ! 427: ! 428: @implementation IODirectDevice(IOMemory) ! 429: /* ! 430: * Methods to map device memory into the calling task's address space. ! 431: */ ! 432: - (IOReturn) mapMemoryRange:(unsigned int) localRange ! 433: to:(vm_address_t *) destAddr ! 434: findSpace:(BOOL) findSpace ! 435: cache:(IOCache) cache ! 436: { ! 437: IODirectDevicePrivate *private = _private; ! 438: id mapping; ! 439: id resource; ! 440: ! 441: if (localRange >= [_deviceDescription numMemoryRanges]) ! 442: return IO_R_INVALID_ARG; ! 443: ! 444: resource = [[_deviceDescriptionDelegate resourcesForKey:MEM_MAPS_KEY] ! 445: objectAt:localRange]; ! 446: if (findSpace) ! 447: mapping = ! 448: [resource mapInTarget:current_task_EXTERNAL() ! 449: cache:cache]; ! 450: else ! 451: mapping = ! 452: [resource mapToAddress:*destAddr ! 453: inTarget:current_task_EXTERNAL() ! 454: cache:cache]; ! 455: ! 456: if (mapping == nil) ! 457: return IO_R_NO_MEMORY; ! 458: ! 459: *destAddr = [mapping address]; ! 460: ! 461: if (private->memory_mappings == nil) ! 462: private->memory_mappings = [[HashTable alloc] initKeyDesc:"i"]; ! 463: ! 464: [private->memory_mappings insertKey:(void *)*destAddr value:mapping]; ! 465: ! 466: return IO_R_SUCCESS; ! 467: } ! 468: ! 469: - (void) unmapMemoryRange:(unsigned int) localRange ! 470: from:(vm_address_t) virtAddr; ! 471: { ! 472: IODirectDevicePrivate *private = _private; ! 473: id mapping; ! 474: ! 475: if (localRange >= [_deviceDescription numMemoryRanges]) ! 476: return; ! 477: ! 478: mapping = [private->memory_mappings valueForKey:(void *)virtAddr]; ! 479: if (mapping == nil) ! 480: return; ! 481: ! 482: [private->memory_mappings removeKey:(void *)virtAddr]; ! 483: ! 484: [mapping free]; ! 485: } ! 486: ! 487: ! 488: @end ! 489: ! 490: static void ! 491: IODirectDeviceThread( ! 492: id device ! 493: ) ! 494: { ! 495: IOReturn result; ! 496: int id; ! 497: ! 498: while (TRUE) { ! 499: result = [device waitForInterrupt:&id]; ! 500: if (result == IO_R_MSG_TOO_LARGE) ! 501: [device receiveMsg]; ! 502: else if (result != IO_R_SUCCESS) ! 503: IOLog("%s: %s thread: waitForInterrupt: returns %d\n", ! 504: [device name], [device deviceKind], result); ! 505: else { ! 506: switch (id) { ! 507: ! 508: case IO_TIMEOUT_MSG: ! 509: [device timeoutOccurred]; ! 510: break; ! 511: ! 512: case IO_COMMAND_MSG: ! 513: [device commandRequestOccurred]; ! 514: break; ! 515: ! 516: case IO_DEVICE_INTERRUPT_MSG: ! 517: [device interruptOccurred]; ! 518: break; ! 519: ! 520: case IO_EXIT_THREAD_MSG: ! 521: IOExitThread(); ! 522: break; ! 523: ! 524: default: ! 525: if ( id >= IO_DEVICE_INTERRUPT_MSG_FIRST ! 526: && id <= IO_DEVICE_INTERRUPT_MSG_LAST) { ! 527: int localNum = id - IO_DEVICE_INTERRUPT_MSG_FIRST; ! 528: ! 529: [device interruptOccurredAt:localNum]; ! 530: } ! 531: else ! 532: [device otherOccurred:id]; ! 533: } ! 534: } ! 535: } ! 536: } ! 537: ! 538: @implementation IODirectDevice(Private) ! 539: ! 540: - _deviceDescriptionDelegate ! 541: { ! 542: return _deviceDescriptionDelegate; ! 543: } ! 544: ! 545: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.