]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOInterruptEventSource.cpp
97d4c595761deb84c70f8a39341cc3b7e76d593b
[apple/xnu.git] / iokit / Kernel / IOInterruptEventSource.cpp
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 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
30
31 HISTORY
32 1998-7-13 Godfrey van der Linden(gvdl)
33 Created.
34 */
35 #include <IOKit/IOInterruptEventSource.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOLib.h>
38 #include <IOKit/IOService.h>
39 #include <IOKit/IOInterrupts.h>
40 #include <IOKit/IOTimeStamp.h>
41 #include <IOKit/IOWorkLoop.h>
42
43 #define super IOEventSource
44
45 OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource)
46 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0);
47 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1);
48 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2);
49 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3);
50 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4);
51 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5);
52 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6);
53 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7);
54
55 bool IOInterruptEventSource::init(OSObject *inOwner,
56 Action inAction,
57 IOService *inProvider,
58 int inIntIndex)
59 {
60 bool res = true;
61
62 if ( !super::init(inOwner, (IOEventSourceAction) inAction) )
63 return false;
64
65 provider = inProvider;
66 producerCount = consumerCount = 0;
67 autoDisable = explicitDisable = false;
68 intIndex = ~inIntIndex;
69
70 // Assumes inOwner holds a reference(retain) on the provider
71 if (inProvider) {
72 res = (kIOReturnSuccess == registerInterruptHandler(inProvider, inIntIndex));
73 if (res)
74 intIndex = inIntIndex;
75 }
76
77 return res;
78 }
79
80 IOReturn IOInterruptEventSource::registerInterruptHandler(IOService *inProvider,
81 int inIntIndex)
82 {
83 IOReturn ret;
84 int intType;
85 IOInterruptAction intHandler;
86
87 ret = inProvider->getInterruptType(inIntIndex, &intType);
88 if (kIOReturnSuccess != ret)
89 return (ret);
90
91 autoDisable = (intType == kIOInterruptTypeLevel);
92 if (autoDisable) {
93 intHandler = OSMemberFunctionCast(IOInterruptAction,
94 this, &IOInterruptEventSource::disableInterruptOccurred);
95 }
96 else
97 intHandler = OSMemberFunctionCast(IOInterruptAction,
98 this, &IOInterruptEventSource::normalInterruptOccurred);
99
100 ret = provider->registerInterrupt(inIntIndex, this, intHandler);
101
102 return (ret);
103 }
104
105 IOInterruptEventSource *
106 IOInterruptEventSource::interruptEventSource(OSObject *inOwner,
107 Action inAction,
108 IOService *inProvider,
109 int inIntIndex)
110 {
111 IOInterruptEventSource *me = new IOInterruptEventSource;
112
113 if (me && !me->init(inOwner, inAction, inProvider, inIntIndex)) {
114 me->release();
115 return 0;
116 }
117
118 return me;
119 }
120
121 void IOInterruptEventSource::free()
122 {
123 if (provider && intIndex >= 0)
124 provider->unregisterInterrupt(intIndex);
125
126 super::free();
127 }
128
129 void IOInterruptEventSource::enable()
130 {
131 if (provider && intIndex >= 0) {
132 provider->enableInterrupt(intIndex);
133 explicitDisable = false;
134 enabled = true;
135 }
136 }
137
138 void IOInterruptEventSource::disable()
139 {
140 if (provider && intIndex >= 0) {
141 provider->disableInterrupt(intIndex);
142 explicitDisable = true;
143 enabled = false;
144 }
145 }
146
147 void IOInterruptEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
148 {
149 super::setWorkLoop(inWorkLoop);
150
151 if (!provider)
152 return;
153
154 if ( !inWorkLoop ) {
155 if (intIndex >= 0) {
156 provider->unregisterInterrupt(intIndex);
157 intIndex = ~intIndex;
158 }
159 } else if ((intIndex < 0) && (kIOReturnSuccess == registerInterruptHandler(provider, ~intIndex))) {
160 intIndex = ~intIndex;
161 }
162 }
163
164 const IOService *IOInterruptEventSource::getProvider() const
165 {
166 return provider;
167 }
168
169 int IOInterruptEventSource::getIntIndex() const
170 {
171 return intIndex;
172 }
173
174 bool IOInterruptEventSource::getAutoDisable() const
175 {
176 return autoDisable;
177 }
178
179 bool IOInterruptEventSource::checkForWork()
180 {
181 unsigned int cacheProdCount = producerCount;
182 int numInts = cacheProdCount - consumerCount;
183 IOInterruptEventAction intAction = (IOInterruptEventAction) action;
184 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
185
186 if ( numInts > 0 )
187 {
188 if (trace)
189 IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION),
190 (uintptr_t) intAction, (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
191
192 // Call the handler
193 (*intAction)(owner, this, numInts);
194
195 if (trace)
196 IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION),
197 (uintptr_t) intAction, (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
198
199 consumerCount = cacheProdCount;
200 if (autoDisable && !explicitDisable)
201 enable();
202 }
203
204 else if ( numInts < 0 )
205 {
206 if (trace)
207 IOTimeStampStartConstant(IODBG_INTES(IOINTES_ACTION),
208 (uintptr_t) intAction, (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
209
210 // Call the handler
211 (*intAction)(owner, this, -numInts);
212
213 if (trace)
214 IOTimeStampEndConstant(IODBG_INTES(IOINTES_ACTION),
215 (uintptr_t) intAction, (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
216
217 consumerCount = cacheProdCount;
218 if (autoDisable && !explicitDisable)
219 enable();
220 }
221
222 return false;
223 }
224
225 void IOInterruptEventSource::normalInterruptOccurred
226 (void */*refcon*/, IOService */*prov*/, int /*source*/)
227 {
228 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
229
230 producerCount++;
231
232 if (trace)
233 IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
234
235 signalWorkAvailable();
236
237 if (trace)
238 IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
239 }
240
241 void IOInterruptEventSource::disableInterruptOccurred
242 (void */*refcon*/, IOService *prov, int source)
243 {
244 bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
245
246 prov->disableInterrupt(source); /* disable the interrupt */
247
248 producerCount++;
249
250 if (trace)
251 IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
252
253 signalWorkAvailable();
254
255 if (trace)
256 IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
257 }
258
259 void IOInterruptEventSource::interruptOccurred
260 (void *refcon, IOService *prov, int source)
261 {
262 if (autoDisable && prov)
263 disableInterruptOccurred(refcon, prov, source);
264 else
265 normalInterruptOccurred(refcon, prov, source);
266 }