1 /* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #include <IOKit/IODMAEventSource.h> 30 #include <IOKit/IOService.h> 31 32 #include "IOKitKernelInternal.h" 33 34 35 #define super IOEventSource 36 OSDefineMetaClassAndStructors(IODMAEventSource, IOEventSource); 37 38 bool IODMAEventSource::init(OSObject *inOwner, 39 IOService *inProvider, 40 Action inCompletion, 41 Action inNotification, 42 UInt32 inDMAIndex) 43 { 44 IOReturn result; 45 46 if (!super::init(inOwner)) return false; 47 48 if (inProvider == 0) return false; 49 50 dmaProvider = inProvider; 51 dmaIndex = 0xFFFFFFFF; 52 dmaCompletionAction = inCompletion; 53 dmaNotificationAction = inNotification; 54 55 dmaController = IODMAController::getController(dmaProvider, inDMAIndex); 56 if (dmaController == 0) return false; 57 dmaController->retain(); 58 59 result = dmaController->initDMAChannel(dmaProvider, this, &dmaIndex, inDMAIndex); 60 if (result != kIOReturnSuccess) return false; 61 62 queue_init(&dmaCommandsCompleted); 63 dmaCommandsCompletedLock = IOSimpleLockAlloc(); 64 65 return true; 66 } 67 68 void IODMAEventSource::free() 69 { 70 if (dmaCommandsCompletedLock != NULL) IOSimpleLockFree(dmaCommandsCompletedLock); 71 super::free(); 72 } 73 74 IODMAEventSource *IODMAEventSource::dmaEventSource(OSObject *inOwner, 75 IOService *inProvider, 76 Action inCompletion, 77 Action inNotification, 78 UInt32 inDMAIndex) 79 { 80 IODMAEventSource *dmaES = new IODMAEventSource; 81 82 if (dmaES && !dmaES->init(inOwner, inProvider, inCompletion, inNotification, inDMAIndex)) { 83 dmaES->release(); 84 return 0; 85 } 86 87 return dmaES; 88 } 89 90 IOReturn IODMAEventSource::startDMACommand(IODMACommand *dmaCommand, IODirection direction, IOByteCount byteCount, IOByteCount byteOffset) 91 { 92 IOReturn result; 93 94 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return kIOReturnError; 95 96 if (dmaSynchBusy) return kIOReturnBusy; 97 98 if (dmaCompletionAction == 0) dmaSynchBusy = true; 99 100 result = dmaController->startDMACommand(dmaIndex, dmaCommand, direction, byteCount, byteOffset); 101 102 if (result != kIOReturnSuccess) { 103 dmaSynchBusy = false; 104 return result; 105 } 106 107 while (dmaSynchBusy) sleepGate(&dmaSynchBusy, THREAD_UNINT); 108 109 return kIOReturnSuccess; 110 } 111 112 IOReturn IODMAEventSource::stopDMACommand(bool flush, uint64_t timeout) 113 { 114 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return kIOReturnError; 115 116 return dmaController->stopDMACommand(dmaIndex, flush, timeout); 117 } 118 119 120 IOReturn IODMAEventSource::queryDMACommand(IODMACommand **dmaCommand, IOByteCount *transferCount, bool waitForIdle) 121 { 122 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return kIOReturnError; 123 124 return dmaController->queryDMACommand(dmaIndex, dmaCommand, transferCount, waitForIdle); 125 } 126 127 128 IOByteCount IODMAEventSource::getFIFODepth(IODirection direction) 129 { 130 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return 0; 131 132 return dmaController->getFIFODepth(dmaIndex, direction); 133 } 134 135 136 IOReturn IODMAEventSource::setFIFODepth(IOByteCount depth) 137 { 138 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return kIOReturnError; 139 140 return dmaController->setFIFODepth(dmaIndex, depth); 141 } 142 143 144 IOByteCount IODMAEventSource::validFIFODepth(IOByteCount depth, IODirection direction) 145 { 146 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return kIOReturnError; 147 148 return dmaController->validFIFODepth(dmaIndex, depth, direction); 149 } 150 151 152 IOReturn IODMAEventSource::setFrameSize(UInt8 byteCount) 153 { 154 if ((dmaController == 0) || (dmaIndex == 0xFFFFFFFF)) return kIOReturnError; 155 156 return dmaController->setFrameSize(dmaIndex, byteCount); 157 } 158 159 // protected 160 161 bool IODMAEventSource::checkForWork(void) 162 { 163 IODMACommand *dmaCommand = NULL; 164 bool work, again; 165 166 IOSimpleLockLock(dmaCommandsCompletedLock); 167 work = !queue_empty(&dmaCommandsCompleted); 168 if (work) { 169 queue_remove_first(&dmaCommandsCompleted, dmaCommand, IODMACommand *, fCommandChain); 170 again = !queue_empty(&dmaCommandsCompleted); 171 } else { 172 again = false; 173 } 174 IOSimpleLockUnlock(dmaCommandsCompletedLock); 175 176 if (work) { 177 (*dmaCompletionAction)(owner, this, dmaCommand, dmaCommand->reserved->fStatus, dmaCommand->reserved->fActualByteCount, dmaCommand->reserved->fTimeStamp); 178 } 179 180 return again; 181 } 182 183 void IODMAEventSource::completeDMACommand(IODMACommand *dmaCommand) 184 { 185 if (dmaCompletionAction != 0) { 186 IOSimpleLockLock(dmaCommandsCompletedLock); 187 queue_enter(&dmaCommandsCompleted, dmaCommand, IODMACommand *, fCommandChain); 188 IOSimpleLockUnlock(dmaCommandsCompletedLock); 189 190 signalWorkAvailable(); 191 } else { 192 dmaSynchBusy = false; 193 wakeupGate(&dmaSynchBusy, true); 194 } 195 } 196 197 void IODMAEventSource::notifyDMACommand(IODMACommand *dmaCommand, IOReturn status, IOByteCount actualByteCount, AbsoluteTime timeStamp) 198 { 199 dmaCommand->reserved->fStatus = status; 200 dmaCommand->reserved->fActualByteCount = actualByteCount; 201 dmaCommand->reserved->fTimeStamp = timeStamp; 202 203 if (dmaNotificationAction != 0) (*dmaNotificationAction)(owner, this, dmaCommand, status, actualByteCount, timeStamp); 204 } 205 206 IOReturn IODMAEventSource::setDMAConfig(UInt32 newReqIndex) 207 { 208 return dmaController->setDMAConfig(dmaIndex, dmaProvider, newReqIndex); 209 } 210 211 bool IODMAEventSource::validDMAConfig(UInt32 newReqIndex) 212 { 213 return dmaController->validDMAConfig(dmaIndex, dmaProvider, newReqIndex); 214 } 215