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
init(OSObject * inOwner,IOService * inProvider,Action inCompletion,Action inNotification,UInt32 inDMAIndex)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
free()79 IODMAEventSource::free()
80 {
81 	if (dmaCommandsCompletedLock != NULL) {
82 		IOSimpleLockFree(dmaCommandsCompletedLock);
83 	}
84 	super::free();
85 }
86 
87 OSSharedPtr<IODMAEventSource>
dmaEventSource(OSObject * inOwner,IOService * inProvider,Action inCompletion,Action inNotification,UInt32 inDMAIndex)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
startDMACommand(IODMACommand * dmaCommand,IODirection direction,IOByteCount byteCount,IOByteCount byteOffset)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
stopDMACommand(bool flush,uint64_t timeout)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
queryDMACommand(IODMACommand ** dmaCommand,IOByteCount * transferCount,bool waitForIdle)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
getFIFODepth(IODirection direction)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
setFIFODepth(IOByteCount depth)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
validFIFODepth(IOByteCount depth,IODirection direction)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
setFrameSize(UInt8 byteCount)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
checkForWork(void)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
completeDMACommand(IODMACommand * dmaCommand)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
notifyDMACommand(IODMACommand * dmaCommand,IOReturn status,IOByteCount actualByteCount,AbsoluteTime timeStamp)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
setDMAConfig(UInt32 newReqIndex)252 IODMAEventSource::setDMAConfig(UInt32 newReqIndex)
253 {
254 	return dmaController->setDMAConfig(dmaIndex, dmaProvider, newReqIndex);
255 }
256 
257 bool
validDMAConfig(UInt32 newReqIndex)258 IODMAEventSource::validDMAConfig(UInt32 newReqIndex)
259 {
260 	return dmaController->validDMAConfig(dmaIndex, dmaProvider, newReqIndex);
261 }
262