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