IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/, IOService * nub, int /*source*/) { IOInterruptVectorNumber vectorNumber; IOInterruptVector *vector; for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) { vector = &vectors[vectorNumber]; vector->interruptActive = 1; if (!vector->interruptDisabledSoft) { // Call the handler if it exists. if (vector->interruptRegistered) { bool trace = (gIOKitTrace & kIOTraceInterrupts) ? true : false; if (trace) IOTimeStampStartConstant(IODBG_INTC(IOINTC_HANDLER), (uintptr_t) vectorNumber, (uintptr_t) vector->handler, (uintptr_t)vector->target); // Call handler. vector->handler(vector->target, vector->refCon, vector->nub, vector->source); if (trace) IOTimeStampEndConstant(IODBG_INTC(IOINTC_HANDLER), (uintptr_t) vectorNumber, (uintptr_t) vector->handler, (uintptr_t)vector->target); } } vector->interruptActive = 0; } // if any of the vectors are dissabled, then dissable this controller. IOSimpleLockLock(controllerLock); if (vectorsEnabled != vectorsRegistered) { nub->disableInterrupt(0); controllerDisabled = 1; } IOSimpleLockUnlock(controllerLock); return kIOReturnSuccess; }
static void iopa_free(uintptr_t addr, vm_size_t bytes) { io_pagealloc_t * pa; uint32_t count; uintptr_t chunk; if (!bytes) bytes = 1; chunk = (addr & page_mask); assert(0 == (chunk & (kIOPageAllocChunkBytes - 1))); pa = (typeof(pa)) (addr | (page_size - kIOPageAllocChunkBytes)); assert(kIOPageAllocSignature == pa->signature); count = (bytes + kIOPageAllocChunkBytes - 1) / kIOPageAllocChunkBytes; chunk /= kIOPageAllocChunkBytes; IOSimpleLockLock(gIOPageAllocLock); if (!pa->avail) { assert(!pa->link.next); enqueue_tail(&gIOPageAllocList, &pa->link); } pa->avail |= ((-1ULL << (64 - count)) >> chunk); if (pa->avail != -2ULL) pa = 0; else { remque(&pa->link); pa->link.next = 0; pa->signature = 0; gIOPageAllocCount--; } gIOPageAllocBytes -= bytes; IOSimpleLockUnlock(gIOPageAllocLock); if (pa) iopa_freepage(pa); #if IOALLOCDEBUG debug_iomalloc_size -= bytes; #endif IOStatisticsAlloc(kIOStatisticsFreeAligned, bytes); }
IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/, IOService * nub, int /*source*/) { long vectorNumber; IOInterruptVector *vector; for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) { vector = &vectors[vectorNumber]; vector->interruptActive = 1; #if __ppc__ sync(); isync(); #endif if (!vector->interruptDisabledSoft) { #if __ppc__ isync(); #endif // Call the handler if it exists. if (vector->interruptRegistered) { vector->handler(vector->target, vector->refCon, vector->nub, vector->source); } } vector->interruptActive = 0; } // if any of the vectors are dissabled, then dissable this controller. IOSimpleLockLock(controllerLock); if (vectorsEnabled != vectorsRegistered) { nub->disableInterrupt(0); controllerDisabled = 1; } IOSimpleLockUnlock(controllerLock); return kIOReturnSuccess; }
IOReturn AgereET131x::setMulticastList(IOEthernetAddress * addrs, UInt32 count) { UINT32 PacketFilter = 0; IOSimpleLockLock( adapter.Lock ); /************************************************************************** Before we modify the platform-independent filter flags, store them locally. This allows us to determine if anything's changed and if we even need to bother the hardware *************************************************************************/ PacketFilter = adapter.PacketFilter; /************************************************************************** Clear the 'multicast' flag locally; becuase we only have a single flag to check multicast, and multiple multicast addresses can be set, this is the easiest way to determine if more than one multicast address is being set. *************************************************************************/ PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; /************************************************************************** Check the net_device flags and set the device independent flags accordingly *************************************************************************/ if( count > NIC_MAX_MCAST_LIST ) { adapter.PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; } else if( count < 1 ) { adapter.PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; adapter.PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; } else { /************************************************************************** Set values in the private adapter struct *************************************************************************/ adapter.MCAddressCount = count; for( UInt32 k = 0; k < count; k++ ) { bcopy( addrs[k].bytes, adapter.MCList[k], ETH_ALEN ); } } /************************************************************************** Are the new flags different from the previous ones? If not, then no action is required NOTE - This block will always update the MCList with the hardware, even if the addresses aren't the same. *************************************************************************/ if( PacketFilter != adapter.PacketFilter ) { /********************************************************************** Call the device's filter function *********************************************************************/ set_packet_filter(); } IOSimpleLockUnlock( adapter.Lock ); return kIOReturnSuccess; }
// Called at hardware interrupt time bool AppleUSBUHCI::FilterInterrupt(void) { UInt16 activeInterrupts; Boolean needSignal = false; UInt64 currentFrame; uint64_t timeStamp; // we leave all interrupts enabled, so see which ones are active activeInterrupts = ioRead16(kUHCI_STS) & kUHCI_STS_INTR_MASK; if (activeInterrupts != 0) { USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt , (uintptr_t)this, activeInterrupts, 0, 3 ); if (activeInterrupts & kUHCI_STS_HCPE) { // Host Controller Process Error - usually a bad data structure on the list _hostControllerProcessInterrupt = kUHCI_STS_HCPE; ioWrite16(kUHCI_STS, kUHCI_STS_HCPE); needSignal = true; //USBLog(1, "AppleUSBUHCI[%p]::FilterInterrupt - HCPE error - legacy reg = %p", this, (void*)_device->configRead16(kUHCI_PCI_LEGKEY)); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostControllerProcessInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 1 ); } if (activeInterrupts & kUHCI_STS_HSE) { // Host System Error - usually a PCI issue _hostSystemErrorInterrupt = kUHCI_STS_HSE; ioWrite16(kUHCI_STS, kUHCI_STS_HSE); needSignal = true; //USBLog(1, "AppleUSBUHCI[%p]::FilterInterrupt - HSE error - legacy reg = %p", this, (void*)_device->configRead16(kUHCI_PCI_LEGKEY)); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostSystemErrorInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 2 ); } if (activeInterrupts & kUHCI_STS_RD) { // Resume Detect - remote wakeup _resumeDetectInterrupt = kUHCI_STS_RD; ioWrite16(kUHCI_STS, kUHCI_STS_RD); needSignal = true; } if (activeInterrupts & kUHCI_STS_EI) { // USB Error Interrupt - transaction error (CRC, timeout, etc) _usbErrorInterrupt = kUHCI_STS_EI; ioWrite16(kUHCI_STS, kUHCI_STS_EI); needSignal = true; } if (activeInterrupts & kUHCI_STS_INT) { // Normal IOC interrupt - we need to check out low latency Isoch as well timeStamp = mach_absolute_time(); ioWrite16(kUHCI_STS, kUHCI_STS_INT); needSignal = true; // This function will give us the current frame number and check for rollover at the same time // since we are calling from filterInterrupts we will not be preempted, it will also update the // cached copy of the frame_number_with_time GetFrameNumberInternal(); // we need to check the periodic list to see if there are any Isoch TDs which need to come off // and potentially have their frame lists updated (for Low Latency) we will place them in reverse // order on a "done queue" which will be looked at by the isoch scavanger // only do this if the periodic schedule is enabled if (!_inAbortIsochEP && (_outSlot < kUHCI_NVFRAMES)) { AppleUHCIIsochTransferDescriptor *cachedHead; UInt32 cachedProducer; UInt16 curSlot, testSlot, nextSlot; curSlot = (ReadFrameNumber() & kUHCI_NVFRAMES_MASK); cachedHead = (AppleUHCIIsochTransferDescriptor*)_savedDoneQueueHead; cachedProducer = _producerCount; testSlot = _outSlot; while (testSlot != curSlot) { IOUSBControllerListElement *thing, *nextThing; AppleUHCIIsochTransferDescriptor *isochTD; nextSlot = (testSlot+1) & kUHCI_NVFRAMES_MASK; thing = _logicalFrameList[testSlot]; while (thing != NULL) { nextThing = thing->_logicalNext; isochTD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, thing); if (!isochTD) break; // only care about Isoch in this list - if we get here we are at the interrupt TDs // need to unlink this TD _logicalFrameList[testSlot] = nextThing; _frameList[testSlot] = HostToUSBLong(thing->GetPhysicalLink()); if (isochTD->_lowLatency) isochTD->frStatus = isochTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp); // place this guy on the backward done queue // the reason that we do not use the _logicalNext link is that the done queue is not a null terminated list // and the element linked "last" in the list might not be a true link - trust me isochTD->_doneQueueLink = cachedHead; cachedHead = isochTD; cachedProducer++; if (isochTD->_pEndpoint) { isochTD->_pEndpoint->onProducerQ++; OSDecrementAtomic( &(isochTD->_pEndpoint->scheduledTDs)); } thing = nextThing; } testSlot = nextSlot; _outSlot = testSlot; } IOSimpleLockLock( _wdhLock ); _savedDoneQueueHead = cachedHead; // updates the shadow head _producerCount = cachedProducer; // Validates _producerCount; IOSimpleLockUnlock( _wdhLock ); } // 8394970: Make sure we set the flag AFTER we have incremented our producer count. _usbCompletionInterrupt = kUHCI_STS_INT; } } // We will return false from this filter routine, // but will indicate that there the action routine should be called // by calling _filterInterruptSource->signalInterrupt(). // This is needed because IOKit will disable interrupts for a level interrupt // after the filter interrupt is run, until the action interrupt is called. // We want to be able to have our filter interrupt routine called // before the action routine runs, if needed. That is what will enable // low latency isoch transfers to work, as when the // system is under heavy load, the action routine can be delayed for tens of ms. // if (needSignal) _interruptSource->signalInterrupt(); return false; }
bool AppleGPIO::unregisterClient(void *param1, void *param2, void *param3 = 0) { AppleGPIOCallbackInfo *prevClient, *thisClient; bool found = false; DLOG("AppleGPIO::unregisterClient %08lx %08lx %08lx\n", (UInt32)param1, (UInt32)param2, (UInt32)param3); // grab the client list mutex so nothing changes under our nose IOSimpleLockLock(fClientsLock); if (!areRegisteredClients()) { IOSimpleLockUnlock(fClientsLock); DLOG("AppleGPIO::unregisterClient nobody is registered!!\n"); return(false); } // Search for the calling client and remove if found // check for match against first client if (CLIENT_MATCH(fClients)) { thisClient = fClients; fClients = fClients->next; found = true; } // walk through the list else { thisClient = fClients; while (thisClient->next != 0) { prevClient = thisClient; thisClient = thisClient->next; if (CLIENT_MATCH(thisClient)) { prevClient->next = thisClient->next; found = true; break; } } } // release the client list mutex IOSimpleLockUnlock(fClientsLock); if (found) { IOFree(thisClient, sizeof(AppleGPIOCallbackInfo)); // update notification relationship with parent if (!areEnabledClients() && amEnabled()) { disableWithParent(); } if (!areRegisteredClients()) { unregisterWithParent(); } } return(found); }
// param1 is a GPIOEventHandler // param2, param3, param4 are anything the caller wants to give me, they'll // be passed back exactly as given to me bool AppleGPIO::registerClient(void *param1, void *param2, void *param3 = 0) { AppleGPIOCallbackInfo *newClient, *tmpClient; DLOG("AppleGPIO::registerClient %08lx %08lx %08lx\n", (UInt32)param1, (UInt32)param2, (UInt32)param3); // verify the handler address if (param1 == 0) return(false); // Make sure this isn't a dupe tmpClient = fClients; while (tmpClient) { if (CLIENT_MATCH(tmpClient)) return(false); tmpClient = tmpClient->next; } // Allocate memory for client newClient = (AppleGPIOCallbackInfo *)IOMalloc(sizeof(AppleGPIOCallbackInfo)); if (!newClient) return(false); // store the client's data newClient->handler = (GPIOEventHandler)param1; newClient->param1 = param2; newClient->param2 = param3; newClient->isEnabled = true; // events enabled upon registration newClient->next = 0; // grab the client list mutex IOSimpleLockLock(fClientsLock); // insert him into the list if (!fClients) { fClients = newClient; } else { tmpClient = fClients; while (tmpClient->next != 0) tmpClient = tmpClient->next; tmpClient->next = newClient; } // release the client list mutex IOSimpleLockUnlock(fClientsLock); // If necessary, register with GPIO parent for notification if (!amRegistered()) { if (!registerWithParent()) { // [3332930] If we can't register with the parent... // then return an error and leave the notifications disabled. return false; } } // Make sure parent is sending down events if (areEnabledClients() && !amEnabled()) enableWithParent(); return(true); }
void AppleGPIO::stop(IOService *provider) { UInt32 flags, i; IOPlatformFunction *func; AppleGPIOCallbackInfo *thisClient, *nextClient; // Execute any functions flagged as "on termination" UInt32 count = fPlatformFuncArray->getCount(); for (i = 0; i < count; i++) { if (func = OSDynamicCast(IOPlatformFunction, fPlatformFuncArray->getObject(i))) { flags = func->getCommandFlags(); if (flags & kIOPFFlagOnTerm) performFunction(func, (void *)1, (void *)0, (void *)0, (void *)0); } } // Unregister for interrupts if (fIntGen && amRegistered()) { disableWithParent(); unregisterWithParent(); fIntGen = false; } if (fPFLock) { IOLockFree (fPFLock); fPFLock = NULL; } IOSimpleLockLock(fClientsLock); if (fClients) { thisClient = fClients; while (thisClient) { nextClient = thisClient->next; IOFree(thisClient, sizeof(AppleGPIOCallbackInfo)); thisClient = nextClient; } fClients = 0; } IOSimpleLockUnlock(fClientsLock); IOSimpleLockFree(fClientsLock); fClientsLock = 0; IOLockFree(fAmRegisteredLock); fAmRegisteredLock = 0; IOSimpleLockFree(fAmEnabledLock); fAmEnabledLock = 0; fParent = 0; fGPIOID = kGPIOIDInvalid; if (fSymIntRegister) { fSymIntRegister->release(); fSymIntRegister = 0; } if (fSymIntUnRegister) { fSymIntUnRegister->release(); fSymIntUnRegister = 0; } if (fSymIntEnable) { fSymIntEnable->release(); fSymIntEnable = 0; } if (fSymIntDisable) { fSymIntDisable->release(); fSymIntDisable = 0; } #ifdef OLD_STYLE_COMPAT releaseStrings(); #endif super::stop(provider); }