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