/*++ Copyright (c) 1999, 2000 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, 2000 Microsoft Corporation. All Rights Reserved. Revision History: 7-19-99 : created, jdunn --*/ #include "common.h" BOOLEAN EHCI_InterruptService ( PDEVICE_DATA DeviceData ) /*++ Routine Description: Arguments: Return Value: --*/ { BOOLEAN usbInt; PHC_OPERATIONAL_REGISTER hcOp; ULONG enabledIrqs, frameNumber; USBSTS irqStatus; FRINDEX frameIndex; hcOp = DeviceData->OperationalRegisters; // assume it is not ours usbInt = FALSE; if (EHCI_HardwarePresent(DeviceData, FALSE) == FALSE) { return FALSE; } // get a mask of possible interrupts enabledIrqs = READ_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul); irqStatus.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul); // just look at the IRQ status bits irqStatus.ul &= HcInterruptStatusMask; // AND with the enabled IRQs irqStatus.ul &= enabledIrqs; // irqStatus now possibly contains bits set for any currently // enabled interrupts if (irqStatus.ul != 0) { DeviceData->IrqStatus = irqStatus.ul; WRITE_REGISTER_ULONG(&hcOp->UsbStatus.ul, irqStatus.ul); #if DBG if (irqStatus.HostSystemError) { // something has gone terribly wrong EHCI_ASSERT(DeviceData, FALSE); } #endif // This code maintains the 32-bit 1 ms frame counter // bugbug this code does not handle varaible frame list // sizes frameIndex.ul = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul); frameNumber = (ULONG) frameIndex.FrameListCurrentIndex; // shut off the microframes frameNumber >>= 3; // did the sign bit change ? if ((DeviceData->LastFrame ^ frameNumber) & 0x0400) { // Yes DeviceData->FrameNumberHighPart += 0x0800 - ((frameNumber ^ DeviceData->FrameNumberHighPart) & 0x0400); } // remember the last frame number DeviceData->LastFrame = frameNumber; // inications are that this came from the // USB controller usbInt = TRUE; // disable all interrupts until the DPC for ISR runs //WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, // 0); } return usbInt; } VOID EHCI_InterruptDpc ( PDEVICE_DATA DeviceData, BOOLEAN EnableInterrupts ) /*++ Routine Description: process an interrupt Arguments: Return Value: --*/ { PHC_OPERATIONAL_REGISTER hcOp; USBSTS irqStatus, tmp; FRINDEX frameIndex; hcOp = DeviceData->OperationalRegisters; // ack all status bits asserted now //tmp.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul); tmp.ul = DeviceData->IrqStatus; DeviceData->IrqStatus = 0; frameIndex.ul = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul); LOGENTRY(DeviceData, G, '_idp', tmp.ul, 0, frameIndex.ul); //WRITE_REGISTER_ULONG(&hcOp->UsbStatus.ul, // tmp.ul); // now process status bits aserted, // just look at the IRQ status bits irqStatus.ul = tmp.ul & HcInterruptStatusMask; // AND with the enabled IRQs, these are the interrupts // we are interested in irqStatus.ul &= DeviceData->EnabledInterrupts.ul; if (irqStatus.UsbInterrupt || irqStatus.UsbError || irqStatus.IntOnAsyncAdvance) { LOGENTRY(DeviceData, G, '_iEP', irqStatus.ul, 0, 0); USBPORT_INVALIDATE_ENDPOINT(DeviceData, NULL); } if (irqStatus.PortChangeDetect) { USBPORT_INVALIDATE_ROOTHUB(DeviceData); } // since ehci does not provide a way to globally mask // interrupts we must mask off all interrupts in our ISR. // When the ISR DPC completes we re-enable the set of // currently enabled interrupts. if (EnableInterrupts) { LOGENTRY(DeviceData, G, '_iEE', 0, 0, 0); WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, DeviceData->EnabledInterrupts.ul); } } VOID USBMPFN EHCI_DisableInterrupts( PDEVICE_DATA DeviceData ) /*++ Routine Description: Arguments: Return Value: --*/ { PHC_OPERATIONAL_REGISTER hcOp = NULL; hcOp = DeviceData->OperationalRegisters; // mask off all interrupts WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, 0); } VOID USBMPFN EHCI_FlushInterrupts( PDEVICE_DATA DeviceData ) /*++ Routine Description: Arguments: Return Value: --*/ { PHC_OPERATIONAL_REGISTER hcOp = NULL; USBSTS irqStatus; hcOp = DeviceData->OperationalRegisters; // flush any outstanding interrupts irqStatus.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul); WRITE_REGISTER_ULONG(&hcOp->UsbStatus.ul, irqStatus.ul); } VOID USBMPFN EHCI_EnableInterrupts( PDEVICE_DATA DeviceData ) /*++ Routine Description: Arguments: Return Value: --*/ { PHC_OPERATIONAL_REGISTER hcOp = NULL; hcOp = DeviceData->OperationalRegisters; // activate the controllers interrupt WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, DeviceData->EnabledInterrupts.ul); } VOID EHCI_RH_DisableIrq( PDEVICE_DATA DeviceData ) { PHC_OPERATIONAL_REGISTER hcOp = NULL; USBINTR enabledIrqs; hcOp = DeviceData->OperationalRegisters; // clear the port change interrupt enabledIrqs.ul = READ_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul); enabledIrqs.PortChangeDetect = DeviceData->EnabledInterrupts.PortChangeDetect = 0; if (enabledIrqs.UsbInterrupt) { WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, enabledIrqs.ul); } } VOID EHCI_RH_EnableIrq( PDEVICE_DATA DeviceData ) { PHC_OPERATIONAL_REGISTER hcOp = NULL; USBINTR enabledIrqs; hcOp = DeviceData->OperationalRegisters; // enable the port change interrupt enabledIrqs.ul = READ_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul); enabledIrqs.PortChangeDetect = DeviceData->EnabledInterrupts.PortChangeDetect = 1; if (enabledIrqs.UsbInterrupt) { WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, enabledIrqs.ul); } } VOID EHCI_InterruptNextSOF( PDEVICE_DATA DeviceData ) { PHC_OPERATIONAL_REGISTER hcOp = NULL; USBCMD cmd; hcOp = DeviceData->OperationalRegisters; // before we use the doorbell enable the async list EHCI_EnableAsyncList(DeviceData); cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul); cmd.IntOnAsyncAdvanceDoorbell = 1; WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul); // TEST_TRAP(); } ULONG EHCI_Get32BitFrameNumber( PDEVICE_DATA DeviceData ) { ULONG highPart, currentFrame, frameNumber; PHC_OPERATIONAL_REGISTER hcOp = NULL; FRINDEX frameIndex; hcOp = DeviceData->OperationalRegisters; // get Hcd's high part of frame number highPart = DeviceData->FrameNumberHighPart; // bugbug this code does not handle varaible frame list // sizes frameIndex.ul = READ_REGISTER_ULONG(&hcOp->UsbFrameIndex.ul); frameNumber = (ULONG) frameIndex.FrameListCurrentIndex; // shift off the microframes frameNumber >>= 3; currentFrame = ((frameNumber & 0x0bff) | highPart) + ((frameNumber ^ highPart) & 0x0400); return currentFrame; } BOOLEAN EHCI_HardwarePresent( PDEVICE_DATA DeviceData, BOOLEAN Notify ) { ULONG tmp; PHC_OPERATIONAL_REGISTER hcOp; hcOp = DeviceData->OperationalRegisters; tmp = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul); if (tmp == 0xffffffff) { if (Notify) { USBPORT_INVALIDATE_CONTROLLER(DeviceData, UsbMpControllerRemoved); } return FALSE; } return TRUE; }