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