|
|
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.