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