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,
79 				  IOService *inProvider,
80 				  int inIntIndex)
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->release();
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 }
250