|
|
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: /* IOStub.m 1.0 01/29/91 (c) 1991 NeXT
25: *
26: * IOStub.m - Implementation for trivial I/O device subclass.
27: *
28: * HISTORY
29: * 29-Jan-91 Doug Mitchell at NeXT
30: * Created.
31: */
32:
33: #import "myDevice.h"
34: #import <kernserv/queue.h>
35: #import <kernserv/prototypes.h>
36: #import <machkit/NXLock.h>
37: #import <architecture/nrw/io.h>
38: #import <architecture/nrw/dma_macros.h>
39: #import <driverkit/generalFuncs.h>
40: #import <driverkit/driverServer.h>
41:
42: static volatile void myDeviceThread(id deviceId);
43:
44: /*
45: * Communication between exported threads and I/O thread via a queue
46: * of these structs.
47: */
48: typedef struct {
49: NXConditionLock *lock; // caller sleeps on this
50: myDeviceOp op; // operation to perform
51: IOReturn status; // status on completion
52: queue_chain_t link;
53: } cmdBuf;
54:
55: /*
56: * States of cmdBuf.lock and of qLock.
57: */
58: typedef enum {
59: LS_IDLE,
60: LS_BUSY
61: } lockState;
62:
63: @implementation myDevice
64:
65: /*
66: * Set device port. devicePort must be a port_t in the IOTask IPC space.
67: * This is called from myHandler, which is NOT in the IOTask context, hence
68: * convertPortToIOTask() was used to generate the devicePort passed in here.
69: */
70: - (void)setDevicePort : (port_t)devicePort
71: {
72: myDevicePort = devicePort;
73: }
74:
75: /*
76: * Initialize. We assume that myDevicePort is valid at this time.
77: * Again, this is called from myHandler's context, so we start up an I/O
78: * thread in the IOTask to enable performing actual I/O using the hardware
79: * represented by myDevicePort.
80: */
81: - init
82: {
83: /*
84: * Initialize resources.
85: */
86: queue_init(&ioQueue);
87: qLock = [NXConditionLock alloc];
88: [qLock initWith:LS_IDLE];
89: IOForkThread((IOThreadFunc)myDeviceThread, self);
90:
91: /*
92: * Send an initialize command to the I/O thread.
93: */
94: [self enqueueCmd:OP_INIT];
95:
96: return self;
97: }
98:
99: /*
100: * Shut down, free resources (but not ourself).
101: */
102: - (void)shutDown
103: {
104: [self enqueueCmd:OP_SHUTDOWN];
105: [qLock free];
106: }
107:
108: /*
109: * Private methods.
110: *
111: * Send a cmdBuf to the I/O thread and wait for completion. This is the
112: * means by which exported methods (-init, -shutDown) pass commands to
113: * the I/O thread.
114: */
115: - (IOReturn)enqueueCmd : (myDeviceOp)op
116: {
117: cmdBuf cmd;
118:
119: /*
120: * Create a cmdBuf.
121: */
122: cmd.lock = [NXConditionLock alloc];
123: [cmd.lock initWith:LS_BUSY];
124: cmd.op = op;
125:
126: /*
127: * Enqueue on ioQueue.
128: */
129: [qLock lock];
130: queue_enter(&ioQueue, &cmd, cmdBuf *, link);
131: [qLock unlockWith:LS_BUSY];
132:
133: /*
134: * Wait for completion.
135: */
136: [cmd.lock lockWhen:LS_IDLE];
137: [cmd.lock free];
138: return cmd.status;
139: }
140:
141: /*
142: * Initialize device, called from within the I/O thread.
143: */
144: - (IOReturn)deviceInit
145: {
146: IODevicePage *devicePage;
147: IOReturn drtn;
148: unsigned intr;
149:
150: /*
151: * Map in device Page.
152: */
153: drtn = _IOMapDevicePage(myDevicePort,
154: task_self(),
155: (vm_offset_t *)&devicePage,
156: YES, // anywhere
157: IO_CacheOff);
158: if(drtn) {
159: IOLog("myDevice: _IOMapDevicePage() returned %s\n",
160: [self stringFromReturn: drtn]);
161: return IO_R_NO_MEMORY;
162: }
163:
164: /*
165: * Make sure we can access device page.
166: */
167: set_chan_intr_set(devicePage, 0, 0x5a);
168: intr = chan_intr_cause(devicePage, 0);
169: IOLog("myDevice: channel interrrupt cause 0x%x\n", intr);
170:
171: /*
172: * This should clear all cause bits.
173: */
174: set_chan_intr_cause(devicePage, 0, 0xffff);
175: intr = chan_intr_cause(devicePage, 0);
176: IOLog("myDevice: channel interrrupt cause 0x%x\n", intr);
177: set_chan_intr_mask(devicePage, 0, 0x55aa);
178: intr = chan_intr_mask(devicePage, 0);
179: IOLog("myDevice: channel interrrupt mask 0x%x\n", intr);
180: return IO_R_SUCCESS;
181: }
182:
183:
184: /*
185: * The I/O thread which performs all of the useful work of this example.
186: */
187: static volatile void myDeviceThread(myDevice *deviceId)
188: {
189: cmdBuf *cmdp;
190: BOOL die = NO;
191: queue_head_t *ioQ = &deviceId->ioQueue;
192:
193: IOLog("myDevice: I/O thread starting\n");
194:
195: while(1) {
196:
197: /*
198: * Wait for something to do.
199: */
200: [deviceId->qLock lockWhen:LS_BUSY];
201: cmdp = (cmdBuf *)queue_first(ioQ);
202: queue_remove(ioQ, cmdp, cmdBuf *, link);
203:
204: /*
205: * Leave qLock in appropriate state, depending on contents
206: * of queue.
207: */
208: if(queue_empty(ioQ)) {
209: [deviceId->qLock unlockWith:LS_IDLE];
210: }
211: else {
212: [deviceId->qLock unlockWith:LS_BUSY];
213: }
214:
215: /*
216: * Execute command.
217: */
218: switch(cmdp->op) {
219: case OP_INIT:
220: cmdp->status = [deviceId deviceInit];
221: break;
222:
223: case OP_SHUTDOWN:
224: /*
225: * Kill this thread, but return good status first.
226: */
227: die = YES;
228: cmdp->status = IO_R_SUCCESS;
229: }
230:
231: /*
232: * Return cmdBuf to caller.
233: */
234: [cmdp->lock lock];
235: [cmdp->lock unlockWith:LS_IDLE];
236:
237: /*
238: * Terminate if necessary.
239: */
240: if(die) {
241: IOLog("myDriver; I/O thread terminating\n");
242: IOExitThread();
243: }
244: }
245:
246: /* Not reached */
247: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.