1 /*
2  * Copyright (c) 1998-2010 Apple 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 #include <IOKit/IOFilterInterruptEventSource.h>
30 #include <IOKit/IOService.h>
31 #include <IOKit/IOKitDebug.h>
32 #include <IOKit/IOTimeStamp.h>
33 #include <IOKit/IOWorkLoop.h>
34 
35 #if IOKITSTATS
36 
37 #define IOStatisticsInitializeCounter() \
38 do { \
39 	IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsFilterInterruptEventSourceCounter); \
40 } while (0)
41 
42 #define IOStatisticsInterrupt() \
43 do { \
44 	IOStatistics::countInterrupt(IOEventSource::reserved->counter); \
45 } while (0)
46 
47 #else
48 
49 #define IOStatisticsInitializeCounter()
50 #define IOStatisticsInterrupt()
51 
52 #endif /* IOKITSTATS */
53 
54 #define super IOInterruptEventSource
55 
56 OSDefineMetaClassAndStructors
57     (IOFilterInterruptEventSource, IOInterruptEventSource)
58 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 0);
59 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 1);
60 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 2);
61 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 3);
62 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 4);
63 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 5);
64 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 6);
65 OSMetaClassDefineReservedUnused(IOFilterInterruptEventSource, 7);
66 
67 /*
68  * Implement the call throughs for the private protection conversion
69  */
70 bool IOFilterInterruptEventSource::init(OSObject *inOwner,
71                                         Action inAction,
72                                         IOService *inProvider,
73                                         int inIntIndex)
74 {
75     return false;
76 }
77 
78 IOInterruptEventSource *
79 IOFilterInterruptEventSource::interruptEventSource(OSObject *inOwner,
80                                                    Action inAction,
81                                                    IOService *inProvider,
82                                                    int inIntIndex)
83 {
84     return 0;
85 }
86 
87 bool
88 IOFilterInterruptEventSource::init(OSObject *inOwner,
89                                    Action inAction,
90                                    Filter inFilterAction,
91                                    IOService *inProvider,
92                                    int inIntIndex)
93 {
94     if ( !super::init(inOwner, inAction, inProvider, inIntIndex) )
95         return false;
96 
97     if (!inFilterAction)
98         return false;
99 
100     filterAction = inFilterAction;
101 
102     IOStatisticsInitializeCounter();
103 
104     return true;
105 }
106 
107 IOFilterInterruptEventSource *IOFilterInterruptEventSource
108 ::filterInterruptEventSource(OSObject *inOwner,
109                              Action inAction,
110                              Filter inFilterAction,
111                              IOService *inProvider,
112                              int inIntIndex)
113 {
114     IOFilterInterruptEventSource *me = new IOFilterInterruptEventSource;
115 
116     if (me
117     && !me->init(inOwner, inAction, inFilterAction, inProvider, inIntIndex)) {
118         me->release();
119         return 0;
120     }
121 
122     return me;
123 }
124 
125 void IOFilterInterruptEventSource::signalInterrupt()
126 {
127 	bool trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
128 
129     IOStatisticsInterrupt();
130     producerCount++;
131 
132 	if (trace)
133 	    IOTimeStampStartConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
134 
135     signalWorkAvailable();
136 
137 	if (trace)
138 	    IOTimeStampEndConstant(IODBG_INTES(IOINTES_SEMA), (uintptr_t) this, (uintptr_t) owner);
139 
140 }
141 
142 
143 IOFilterInterruptEventSource::Filter
144 IOFilterInterruptEventSource::getFilterAction() const
145 {
146     return filterAction;
147 }
148 
149 
150 
151 
152 void IOFilterInterruptEventSource::normalInterruptOccurred
153     (void */*refcon*/, IOService */*prov*/, int /*source*/)
154 {
155     bool 	filterRes;
156 	bool	trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
157 
158 	if (trace)
159 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER),
160 					 VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
161 
162     // Call the filter.
163     filterRes = (*filterAction)(owner, this);
164 
165 	if (trace)
166 		IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER),
167 				       VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
168 
169     if (filterRes)
170         signalInterrupt();
171 }
172 
173 void IOFilterInterruptEventSource::disableInterruptOccurred
174     (void */*refcon*/, IOService *prov, int source)
175 {
176     bool 	filterRes;
177 	bool	trace = (gIOKitTrace & kIOTraceIntEventSource) ? true : false;
178 
179 	if (trace)
180 		IOTimeStampStartConstant(IODBG_INTES(IOINTES_FILTER),
181 					 VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
182 
183     // Call the filter.
184     filterRes = (*filterAction)(owner, this);
185 
186 	if (trace)
187 		IOTimeStampEndConstant(IODBG_INTES(IOINTES_FILTER),
188 				       VM_KERNEL_UNSLIDE(filterAction), (uintptr_t) owner, (uintptr_t) this, (uintptr_t) workLoop);
189 
190     if (filterRes) {
191         prov->disableInterrupt(source);	/* disable the interrupt */
192         signalInterrupt();
193     }
194 }
195