You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
6.3 KiB
258 lines
6.3 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
|
|
|