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