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