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 /* 29 Copyright (c) 1998 Apple Computer, Inc. All rights reserved. 30 31 HISTORY 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) \ 45 do { \ 46 IOTimeStampStart(IODBG_INTES(t), \ 47 (uintptr_t) this, (uintptr_t) owner); \ 48 } while(0) 49 50 #define IOTimeTypeStampE(t) \ 51 do { \ 52 IOTimeStampEnd(IODBG_INTES(t), \ 53 (uintptr_t) this, (uintptr_t) owner); \ 54 } while(0) 55 56 #define IOTimeStampLatency() \ 57 do { \ 58 IOTimeStampEnd(IODBG_INTES(IOINTES_LAT), \ 59 (uintptr_t) this, (uintptr_t) 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 70 OSDefineMetaClassAndStructors(IOInterruptEventSource, IOEventSource) 71 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 0); 72 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 1); 73 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 2); 74 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 3); 75 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 4); 76 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 5); 77 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 6); 78 OSMetaClassDefineReservedUnused(IOInterruptEventSource, 7); 79 80 bool 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 123 IOInterruptEventSource * 124 IOInterruptEventSource::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 139 void IOInterruptEventSource::free() 140 { 141 if (provider && intIndex != -1) 142 provider->unregisterInterrupt(intIndex); 143 144 super::free(); 145 } 146 147 void IOInterruptEventSource::enable() 148 { 149 if (provider && intIndex != -1) { 150 provider->enableInterrupt(intIndex); 151 explicitDisable = false; 152 enabled = true; 153 } 154 } 155 156 void IOInterruptEventSource::disable() 157 { 158 if (provider && intIndex != -1) { 159 provider->disableInterrupt(intIndex); 160 explicitDisable = true; 161 enabled = false; 162 } 163 } 164 165 const IOService *IOInterruptEventSource::getProvider() const 166 { 167 return provider; 168 } 169 170 int IOInterruptEventSource::getIntIndex() const 171 { 172 return intIndex; 173 } 174 175 bool IOInterruptEventSource::getAutoDisable() const 176 { 177 return autoDisable; 178 } 179 180 bool 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 (uintptr_t) intAction, (uintptr_t) 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 (uintptr_t) intAction, (uintptr_t) 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 215 void IOInterruptEventSource::normalInterruptOccurred 216 (void */*refcon*/, IOService */*prov*/, int /*source*/) 217 { 218 IOTimeTypeStampS(IOINTES_INTCTXT); 219 IOTimeStampLatency(); 220 221 producerCount++; 222 223 IOTimeTypeStampS(IOINTES_SEMA); 224 signalWorkAvailable(); 225 IOTimeTypeStampE(IOINTES_SEMA); 226 227 IOTimeTypeStampE(IOINTES_INTCTXT); 228 } 229 230 void IOInterruptEventSource::disableInterruptOccurred 231 (void */*refcon*/, IOService *prov, int source) 232 { 233 IOTimeTypeStampS(IOINTES_INTCTXT); 234 IOTimeStampLatency(); 235 236 prov->disableInterrupt(source); /* disable the interrupt */ 237 238 producerCount++; 239 240 IOTimeTypeStampS(IOINTES_SEMA); 241 signalWorkAvailable(); 242 IOTimeTypeStampE(IOINTES_SEMA); 243 244 IOTimeTypeStampE(IOINTES_INTCTXT); 245 } 246 247 void 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