/*++ Copyright (c) 1999 Microsoft Corporation Module Name: int.c Abstract: interrupt service routine Environment: kernel mode only Notes: THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright (c) 1999 Microsoft Corporation. All Rights Reserved. Revision History: 7-19-99 : created, jdunn --*/ #include "common.h" BOOLEAN OHCI_InterruptService ( PDEVICE_DATA DeviceData ) /*++ Routine Description: Arguments: Return Value: --*/ { BOOLEAN usbInt; PHC_OPERATIONAL_REGISTER hc; ULONG irqStatus, enabledIrqs, tmp; hc = DeviceData->HC; // assume it is not ours usbInt = FALSE; // see if we have lost the controller due to // a surprise remove if (OHCI_HardwarePresent(DeviceData, FALSE) == FALSE) { return FALSE; } // get a mask of possible interrupts enabledIrqs = READ_REGISTER_ULONG (&hc->HcInterruptEnable); irqStatus = READ_REGISTER_ULONG(&hc->HcInterruptStatus); // mask off non-enabled irqs irqStatus &= enabledIrqs; // irqStatus now possibly contains bits set for any currently // enabled interrupts if ((irqStatus != 0) && (enabledIrqs & HcInt_MasterInterruptEnable)) { // check for frame number overflow if (irqStatus & HcInt_FrameNumberOverflow) { DeviceData->FrameHighPart += 0x10000 - (0x8000 & (DeviceData->HcHCCA->HccaFrameNumber ^ DeviceData->FrameHighPart)); } #if DBG if (irqStatus & HcInt_UnrecoverableError) { // something has gone terribly wrong OHCI_KdPrint((DeviceData, 0, "'HcInt_UnrecoverableError! DD(%x)\n", DeviceData)); //DbgBreakPoint(); } #endif // indications are that this came from the USB controller usbInt = TRUE; // disable interrupts until the DPC for ISR runs WRITE_REGISTER_ULONG(&hc->HcInterruptDisable, HcInt_MasterInterruptEnable); } return usbInt; } VOID OHCI_InterruptDpc ( PDEVICE_DATA DeviceData, BOOLEAN EnableInterrupts ) /*++ Routine Description: process an interrupt Arguments: Return Value: --*/ { ULONG irqStatus; PHC_OPERATIONAL_REGISTER hc; ULONG doneQueue, cf; hc = DeviceData->HC; irqStatus = READ_REGISTER_ULONG(&hc->HcInterruptStatus); cf = OHCI_Get32BitFrameNumber(DeviceData); // what was the reason for the interrupt? if (irqStatus & HcInt_RootHubStatusChange) { LOGENTRY(DeviceData, G, '_rhS', DeviceData, 0, 0); USBPORT_INVALIDATE_ROOTHUB(DeviceData); } if (irqStatus & HcInt_WritebackDoneHead) { // controller indicates some done TDs doneQueue = DeviceData->HcHCCA->HccaDoneHead; LOGENTRY(DeviceData, G, '_dnQ', DeviceData, doneQueue, cf); // we will have a problem if we ever actually use the doneQ. // Currently we do not use it so the hydra bug where the doneQ // is wriiten back as zero won't hurt us. //if (doneQueue == 0) { //} // write the done head back to zero DeviceData->HcHCCA->HccaDoneHead = 0; LOGENTRY(DeviceData, G, '_dQZ', DeviceData, doneQueue, 0); // if (DoneQueue) { // OpenHCI_ProcessDoneQueue(deviceData, (DoneQueue & 0xFFFFfffe)); // // // // BUGBUG (?) No interrupts can come in while processing // // the done queue. Is this bad? This might take a while. // // // } // check all endpoints USBPORT_INVALIDATE_ENDPOINT(DeviceData, NULL); } if (irqStatus & HcInt_StartOfFrame) { // got the SOF we requested, disable it WRITE_REGISTER_ULONG(&hc->HcInterruptDisable, HcInt_StartOfFrame); } if (irqStatus & HcInt_ResumeDetected) { // got the resume, disable it WRITE_REGISTER_ULONG(&hc->HcInterruptDisable, HcInt_ResumeDetected); } if (irqStatus & HcInt_UnrecoverableError) { // host controller is dead, try to recover... USBPORT_INVALIDATE_CONTROLLER(DeviceData, UsbMpControllerNeedsHwReset); } // acknowlege the interrupts we processed -- // we should have proceesed them all WRITE_REGISTER_ULONG(&hc->HcInterruptStatus, irqStatus); // see if we need to re-enable ints if (EnableInterrupts) { // throw the master irq enable to allow more interupts WRITE_REGISTER_ULONG(&hc->HcInterruptEnable, HcInt_MasterInterruptEnable); } } VOID OHCI_RH_DisableIrq( PDEVICE_DATA DeviceData ) { PHC_OPERATIONAL_REGISTER hc; hc = DeviceData->HC; WRITE_REGISTER_ULONG(&hc->HcInterruptDisable, HcInt_RootHubStatusChange); } VOID OHCI_RH_EnableIrq( PDEVICE_DATA DeviceData ) { PHC_OPERATIONAL_REGISTER hc; hc = DeviceData->HC; WRITE_REGISTER_ULONG(&hc->HcInterruptEnable, HcInt_RootHubStatusChange); } ULONG OHCI_Get32BitFrameNumber( PDEVICE_DATA DeviceData ) { ULONG hp, fn, n; /* * This code accounts for the fact that HccaFrameNumber is updated by the * HC before the HCD gets an interrupt that will adjust FrameHighPart. No * synchronization is nescisary due to great cleaverness. */ hp = DeviceData->FrameHighPart; fn = DeviceData->HcHCCA->HccaFrameNumber; n = ((fn & 0x7FFF) | hp) + ((fn ^ hp) & 0x8000); return n; } VOID OHCI_InterruptNextSOF( PDEVICE_DATA DeviceData ) { PHC_OPERATIONAL_REGISTER hc; hc = DeviceData->HC; WRITE_REGISTER_ULONG(&hc->HcInterruptEnable, HcInt_StartOfFrame); }