]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOInterruptEventSource.cpp
cbdd0aa6a2af71823444b1d67f889db55ad88a0c
[apple/xnu.git] / iokit / Kernel / IOInterruptEventSource.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
27
28 HISTORY
29 1998-7-13 Godfrey van der Linden(gvdl)
30 Created.
31 */
32 #include <IOKit/IOInterruptEventSource.h>
33 #include <IOKit/IOLib.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IOInterrupts.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/IOWorkLoop.h>
38
39 #if KDEBUG
40
41 #define IOTimeTypeStampS(t) \
42 do { \
43 IOTimeStampStart(IODBG_INTES(t), \
44 (unsigned int) this, (unsigned int) owner); \
45 } while(0)
46
47 #define IOTimeTypeStampE(t) \
48 do { \
49 IOTimeStampEnd(IODBG_INTES(t), \
50 (unsigned int) this, (unsigned int) owner); \
51 } while(0)
52
53 #define IOTimeStampLatency() \
54 do { \
55 IOTimeStampEnd(IODBG_INTES(IOINTES_LAT), \
56 (unsigned int) this, (unsigned int) owner); \
57 } while(0)
58
59 #else /* !KDEBUG */
60 #define IOTimeTypeStampS(t)
61 #define IOTimeTypeStampE(t)
62 #define IOTimeStampLatency()
63 #endif /* KDEBUG */
64
65 #define super IOEventSource
66
67 OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource)
68 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0);
69 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1);
70 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2);
71 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3);
72 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4);
73 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5);
74 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6);
75 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7);
76
77 bool IOInterruptEventSource::init(OSObject *inOwner,
78 Action inAction = 0,
79 IOService *inProvider = 0,
80 int inIntIndex = 0)
81 {
82 bool res = true;
83
84 if ( !super::init(inOwner, (IOEventSourceAction) inAction) )
85 return false;
86
87 provider = inProvider;
88 producerCount = consumerCount = 0;
89 autoDisable = explicitDisable = false;
90 intIndex = -1;
91
92 // Assumes inOwner holds a reference(retain) on the provider
93 if (inProvider) {
94 int intType;
95
96 res = (kIOReturnSuccess
97 == inProvider->getInterruptType(inIntIndex, &intType));
98 if (res) {
99 IOInterruptAction intHandler;
100
101 autoDisable = (intType == kIOInterruptTypeLevel);
102 if (autoDisable) {
103 intHandler = (IOInterruptAction)
104 &IOInterruptEventSource::disableInterruptOccurred;
105 }
106 else
107 intHandler = (IOInterruptAction)
108 &IOInterruptEventSource::normalInterruptOccurred;
109
110 res = (kIOReturnSuccess == inProvider->registerInterrupt
111 (inIntIndex, this, intHandler));
112 if (res)
113 intIndex = inIntIndex;
114 }
115 }
116
117 return res;
118 }
119
120 IOInterruptEventSource *
121 IOInterruptEventSource::interruptEventSource(OSObject *inOwner,
122 Action inAction,
123 IOService *inProvider,
124 int inIntIndex)
125 {
126 IOInterruptEventSource *me = new IOInterruptEventSource;
127
128 if (me && !me->init(inOwner, inAction, inProvider, inIntIndex)) {
129 me->free();
130 return 0;
131 }
132
133 return me;
134 }
135
136 void IOInterruptEventSource::free()
137 {
138 if (provider && intIndex != -1)
139 provider->unregisterInterrupt(intIndex);
140
141 super::free();
142 }
143
144 void IOInterruptEventSource::enable()
145 {
146 if (provider && intIndex != -1) {
147 provider->enableInterrupt(intIndex);
148 explicitDisable = false;
149 }
150 }
151
152 void IOInterruptEventSource::disable()
153 {
154 if (provider && intIndex != -1) {
155 provider->disableInterrupt(intIndex);
156 explicitDisable = true;
157 }
158 }
159
160 const IOService *IOInterruptEventSource::getProvider() const
161 {
162 return provider;
163 }
164
165 int IOInterruptEventSource::getIntIndex() const
166 {
167 return intIndex;
168 }
169
170 bool IOInterruptEventSource::getAutoDisable() const
171 {
172 return autoDisable;
173 }
174
175 bool IOInterruptEventSource::checkForWork()
176 {
177 unsigned int cacheProdCount = producerCount;
178 int numInts = cacheProdCount - consumerCount;
179 IOInterruptEventAction intAction = (IOInterruptEventAction) action;
180
181 if (numInts > 0) {
182
183 IOTimeStampLatency();
184 IOTimeTypeStampS(IOINTES_CLIENT);
185 IOTimeStampConstant(IODBG_INTES(IOINTES_ACTION),
186 (unsigned int) intAction, (unsigned int) owner);
187 (*intAction)(owner, this, numInts);
188 IOTimeTypeStampE(IOINTES_CLIENT);
189
190 consumerCount = cacheProdCount;
191 if (autoDisable && !explicitDisable)
192 enable();
193 }
194 else if (numInts < 0) {
195 IOTimeStampLatency();
196 IOTimeTypeStampS(IOINTES_CLIENT);
197 IOTimeStampConstant(IODBG_INTES(IOINTES_ACTION),
198 (unsigned int) intAction, (unsigned int) owner);
199 (*intAction)(owner, this, -numInts);
200 IOTimeTypeStampE(IOINTES_CLIENT);
201
202 consumerCount = cacheProdCount;
203 if (autoDisable && !explicitDisable)
204 enable();
205 }
206
207 return false;
208 }
209
210 void IOInterruptEventSource::normalInterruptOccurred
211 (void */*refcon*/, IOService */*prov*/, int /*source*/)
212 {
213 IOTimeTypeStampS(IOINTES_INTCTXT);
214 IOTimeStampLatency();
215
216 producerCount++;
217
218 IOTimeTypeStampS(IOINTES_SEMA);
219 signalWorkAvailable();
220 IOTimeTypeStampE(IOINTES_SEMA);
221
222 IOTimeTypeStampE(IOINTES_INTCTXT);
223 }
224
225 void IOInterruptEventSource::disableInterruptOccurred
226 (void */*refcon*/, IOService *prov, int source)
227 {
228 IOTimeTypeStampS(IOINTES_INTCTXT);
229 IOTimeStampLatency();
230
231 prov->disableInterrupt(source); /* disable the interrupt */
232
233 producerCount++;
234
235 IOTimeTypeStampS(IOINTES_SEMA);
236 signalWorkAvailable();
237 IOTimeTypeStampE(IOINTES_SEMA);
238
239 IOTimeTypeStampE(IOINTES_INTCTXT);
240 }
241
242 void IOInterruptEventSource::interruptOccurred
243 (void *refcon, IOService *prov, int source)
244 {
245 if (autoDisable && prov)
246 disableInterruptOccurred(refcon, prov, source);
247 else
248 normalInterruptOccurred(refcon, prov, source);
249 }