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 #define IOKIT_ENABLE_SHARED_PTR 30 31 #include <IOKit/IODMAEventSource.h> 32 #include <IOKit/IOService.h> 33 34 #include "IOKitKernelInternal.h" 35 36 37 #define super IOEventSource 38 OSDefineMetaClassAndStructors(IODMAEventSource, IOEventSource); 39 40 bool 41 IODMAEventSource::init(OSObject *inOwner, 42 IOService *inProvider, 43 Action inCompletion, 44 Action inNotification, 45 UInt32 inDMAIndex) 46 { 47 IOReturn result; 48 49 if (!super::init(inOwner)) { 50 return false; 51 } 52 53 if (inProvider == NULL) { 54 return false; 55 } 56 57 dmaProvider = inProvider; 58 dmaIndex = 0xFFFFFFFF; 59 dmaCompletionAction = inCompletion; 60 dmaNotificationAction = inNotification; 61 62 dmaController.reset(IODMAController::getController(dmaProvider, inDMAIndex), OSRetain); 63 if (dmaController == NULL) { 64 return false; 65 } 66 67 result = dmaController->initDMAChannel(dmaProvider, this, &dmaIndex, inDMAIndex); 68 if (result != kIOReturnSuccess) { 69 return false; 70 } 71 72 queue_init(&dmaCommandsCompleted); 73 dmaCommandsCompletedLock = IOSimpleLockAlloc(); 74 75 return true; 76 } 77 78 void 79 IODMAEventSource::free() 80 { 81 if (dmaCommandsCompletedLock != NULL) { 82 IOSimpleLockFree(dmaCommandsCompletedLock); 83 } 84 super::free(); 85 } 86 87 OSSharedPtr<IODMAEventSource> 88 IODMAEventSource::dmaEventSource(OSObject *inOwner, 89 IOService *inProvider, 90 Action inCompletion, 91 Action inNotification, 92 UInt32 inDMAIndex) 93 { 94 OSSharedPtr<IODMAEventSource> dmaES = OSMakeShared<IODMAEventSource>(); 95 96 if (dmaES && !dmaES->init(inOwner, inProvider, inCompletion, inNotification, inDMAIndex)) { 97 return nullptr; 98 } 99 100 return dmaES; 101 } 102 103 IOReturn 104 IODMAEventSource::startDMACommand(IODMACommand *dmaCommand, IODirection direction, IOByteCount byteCount, IOByteCount byteOffset) 105 { 106 IOReturn result; 107 108 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 109 return kIOReturnError; 110 } 111 112 if (dmaSynchBusy) { 113 return kIOReturnBusy; 114 } 115 116 if (dmaCompletionAction == NULL) { 117 dmaSynchBusy = true; 118 } 119 120 result = dmaController->startDMACommand(dmaIndex, dmaCommand, direction, byteCount, byteOffset); 121 122 if (result != kIOReturnSuccess) { 123 dmaSynchBusy = false; 124 return result; 125 } 126 127 while (dmaSynchBusy) { 128 sleepGate(&dmaSynchBusy, THREAD_UNINT); 129 } 130 131 return kIOReturnSuccess; 132 } 133 134 IOReturn 135 IODMAEventSource::stopDMACommand(bool flush, uint64_t timeout) 136 { 137 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 138 return kIOReturnError; 139 } 140 141 return dmaController->stopDMACommand(dmaIndex, flush, timeout); 142 } 143 144 145 IOReturn 146 IODMAEventSource::queryDMACommand(IODMACommand **dmaCommand, IOByteCount *transferCount, bool waitForIdle) 147 { 148 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 149 return kIOReturnError; 150 } 151 152 return dmaController->queryDMACommand(dmaIndex, dmaCommand, transferCount, waitForIdle); 153 } 154 155 156 IOByteCount 157 IODMAEventSource::getFIFODepth(IODirection direction) 158 { 159 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 160 return 0; 161 } 162 163 return dmaController->getFIFODepth(dmaIndex, direction); 164 } 165 166 167 IOReturn 168 IODMAEventSource::setFIFODepth(IOByteCount depth) 169 { 170 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 171 return kIOReturnError; 172 } 173 174 return dmaController->setFIFODepth(dmaIndex, depth); 175 } 176 177 178 IOByteCount 179 IODMAEventSource::validFIFODepth(IOByteCount depth, IODirection direction) 180 { 181 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 182 return kIOReturnError; 183 } 184 185 return dmaController->validFIFODepth(dmaIndex, depth, direction); 186 } 187 188 189 IOReturn 190 IODMAEventSource::setFrameSize(UInt8 byteCount) 191 { 192 if ((dmaController == NULL) || (dmaIndex == 0xFFFFFFFF)) { 193 return kIOReturnError; 194 } 195 196 return dmaController->setFrameSize(dmaIndex, byteCount); 197 } 198 199 // protected 200 201 bool 202 IODMAEventSource::checkForWork(void) 203 { 204 IODMACommand *dmaCommand = NULL; 205 bool work, again; 206 207 IOSimpleLockLock(dmaCommandsCompletedLock); 208 work = !queue_empty(&dmaCommandsCompleted); 209 if (work) { 210 queue_remove_first(&dmaCommandsCompleted, dmaCommand, IODMACommand *, fCommandChain); 211 again = !queue_empty(&dmaCommandsCompleted); 212 } else { 213 again = false; 214 } 215 IOSimpleLockUnlock(dmaCommandsCompletedLock); 216 217 if (work) { 218 (*dmaCompletionAction)(owner, this, dmaCommand, dmaCommand->reserved->fStatus, dmaCommand->reserved->fActualByteCount, dmaCommand->reserved->fTimeStamp); 219 } 220 221 return again; 222 } 223 224 void 225 IODMAEventSource::completeDMACommand(IODMACommand *dmaCommand) 226 { 227 if (dmaCompletionAction != NULL) { 228 IOSimpleLockLock(dmaCommandsCompletedLock); 229 queue_enter(&dmaCommandsCompleted, dmaCommand, IODMACommand *, fCommandChain); 230 IOSimpleLockUnlock(dmaCommandsCompletedLock); 231 232 signalWorkAvailable(); 233 } else { 234 dmaSynchBusy = false; 235 wakeupGate(&dmaSynchBusy, true); 236 } 237 } 238 239 void 240 IODMAEventSource::notifyDMACommand(IODMACommand *dmaCommand, IOReturn status, IOByteCount actualByteCount, AbsoluteTime timeStamp) 241 { 242 dmaCommand->reserved->fStatus = status; 243 dmaCommand->reserved->fActualByteCount = actualByteCount; 244 dmaCommand->reserved->fTimeStamp = timeStamp; 245 246 if (dmaNotificationAction != NULL) { 247 (*dmaNotificationAction)(owner, this, dmaCommand, status, actualByteCount, timeStamp); 248 } 249 } 250 251 IOReturn 252 IODMAEventSource::setDMAConfig(UInt32 newReqIndex) 253 { 254 return dmaController->setDMAConfig(dmaIndex, dmaProvider, newReqIndex); 255 } 256 257 bool 258 IODMAEventSource::validDMAConfig(UInt32 newReqIndex) 259 { 260 return dmaController->validDMAConfig(dmaIndex, dmaProvider, newReqIndex); 261 } 262