Leaked source code of windows server 2003
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.
 
 
 
 
 
 

488 lines
12 KiB

/*++
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-26-00 : created, jsenior
--*/
#include "pch.h"
//implements the following miniport functions:
//non paged
//UhciInterruptService
//UhciInterruptDpc
//UhciDisableInterrupts
//UhciEnableInterrupts
//UhciRHDisableIrq
//UhciRHEnableIrq
//UhciInterruptNextSOF
BOOLEAN
UhciInterruptService (
IN PDEVICE_DATA DeviceData
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
BOOLEAN usbInt;
PHC_REGISTER reg;
// USBINTR enabledIrqs;
USBSTS irqStatus;
reg = DeviceData->Registers;
// assume it is not ours
usbInt = FALSE;
// see if we have lost the controller due to
// a surprise remove
if (UhciHardwarePresent(DeviceData) == FALSE) {
return FALSE;
}
// get a mask of possible interrupts
// enabledIrqs.us = READ_PORT_USHORT(&reg->UsbInterruptEnable.us);
irqStatus.us = READ_PORT_USHORT(&reg->UsbStatus.us);
// just look at the IRQ status bits
irqStatus.us &= HcInterruptStatusMask;
// irqStatus now possibly contains bits set for any currently
// enabled interrupts
if (irqStatus.HostSystemError ||
irqStatus.HostControllerProcessError) {
UhciKdPrint((DeviceData, 0, "IrqStatus Error: %x\n", irqStatus.us));
} else if (irqStatus.us) {
DeviceData->HCErrorCount = 0;
}
#if DBG
// this usually means we have a bad TD in the schedule
// we will need to debug this since the controller and/or
// device will not function after this point
if (irqStatus.HostControllerProcessError) {
USHORT fn;
fn = READ_PORT_USHORT(&reg->FrameNumber.us)&0x7ff;
UhciKdPrint((DeviceData, 0, "HostControllerProcessError: %x\n", irqStatus.us));
UhciKdPrint((DeviceData, 0, "frame[]: %x\n", fn&0x7ff));
{
//UhciDumpRegs(DeviceData);
USHORT tmp;
tmp = READ_PORT_USHORT(&reg->UsbCommand.us);
UhciKdPrint((DeviceData, 0, "UsbCommand %x\n", tmp));
tmp = READ_PORT_USHORT(&reg->UsbStatus.us);
UhciKdPrint((DeviceData, 0, "UsbStatus %x\n", tmp));
tmp = READ_PORT_USHORT(&reg->UsbInterruptEnable.us);
UhciKdPrint((DeviceData, 0, "UsbInterruptEnable %x\n", tmp));
tmp = READ_PORT_USHORT(&reg->UsbCommand.us);
UhciKdPrint((DeviceData, 0, "UsbCommand %x\n", tmp));
}
TEST_TRAP();
}
#endif
// the halted bit alone does not indicate the interrupt
// came from the controller
if (irqStatus.UsbInterrupt ||
irqStatus.ResumeDetect ||
irqStatus.UsbError ||
irqStatus.HostSystemError ||
irqStatus.HostControllerProcessError) {
DeviceData->IrqStatus = irqStatus.us;
// Clear the condition
WRITE_PORT_USHORT(&reg->UsbStatus.us, irqStatus.us);
#if DBG
#ifndef _WIN64
if (irqStatus.HostSystemError) {
// something has gone terribly wrong
UhciKdPrint((DeviceData, 0, "HostSystemError: %x\n", irqStatus.us));
TEST_TRAP();
}
#endif
#endif
// indications are that this came from the
// USB controller
usbInt = TRUE;
// disable all interrupts until the DPC for ISR runs
WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us, 0);
}
//
// If bulk bandwidth reclamation is on and there's
// nothing queued, then turn it off.
//
if (irqStatus.UsbInterrupt) {
UhciUpdateCounter(DeviceData);
if (!DeviceData->LastBulkQueueHead->HwQH.HLink.Terminate) {
PHCD_QUEUEHEAD_DESCRIPTOR qh;
BOOLEAN activeBulkTDs = FALSE;
// This loop skips the td that has been inserted for
// the PIIX4 problem, since it starts with the qh
// the bulk queuehead is pointing at.
// If the bulk queuehead is not pointing at anything,
// then we're fine too, since it will have been
// turned off already.
for (qh = DeviceData->BulkQueueHead->NextQh;
qh;
qh = qh->NextQh) {
if (!qh->HwQH.VLink.Terminate) {
activeBulkTDs = TRUE;
break;
}
}
//
// qh is pointing at either the first queuehead
// with transfers pending or the bulk queuehead.
//
if (!activeBulkTDs) {
UHCI_ASSERT(DeviceData, !qh)
DeviceData->LastBulkQueueHead->HwQH.HLink.Terminate = 1;
}
}
}
if (irqStatus.HostControllerProcessError) {
//
// Force the schedule clean.
//
UhciCleanOutIsoch(DeviceData, TRUE);
} else if (irqStatus.UsbInterrupt && DeviceData->IsoPendingTransfers) {
//
// Something completed.
//
UhciCleanOutIsoch(DeviceData, FALSE);
#if 0
} else if (!DeviceData->IsoPendingTransfers) {
//
// Remove the rollover interrupt.
//
*( ((PULONG) (DeviceData->FrameListVA)) ) = DeviceData->RollOverTd->HwTD.LinkPointer.HwAddress;
#endif
}
if (irqStatus.HostControllerProcessError) {
if (DeviceData->HCErrorCount++ < UHCI_HC_MAX_ERRORS) {
USBCMD command;
// Attempt to recover.
// It could just be that we overran. If so,
// the above code that clears the schedule
// should take care of it.
command.us = READ_PORT_USHORT(&reg->UsbCommand.us);
command.RunStop = 1;
WRITE_PORT_USHORT(&reg->UsbCommand.us, command.us);
UhciKdPrint((DeviceData, 0, "Attempted to recover from error\n"));
}
}
return usbInt;
}
VOID
UhciInterruptDpc (
IN PDEVICE_DATA DeviceData,
IN BOOLEAN EnableInterrupts
)
/*++
Routine Description:
process an interrupt
Arguments:
Return Value:
--*/
{
PHC_REGISTER reg;
USBSTS irqStatus, tmp;
PLIST_ENTRY listEntry;
PENDPOINT_DATA endpointData;
reg = DeviceData->Registers;
// ack all status bits asserted now
//tmp.us = READ_PORT_USHORT(&reg->UsbStatus.us);
tmp.us = DeviceData->IrqStatus;
DeviceData->IrqStatus = 0;
LOGENTRY(DeviceData, G, '_idp', tmp.us, 0, 0);
//WRITE_PORT_USHORT(&reg->UsbStatus.us, tmp.us);
// now process status bits aserted,
// just look at the IRQ status bits
irqStatus.us = tmp.us & HcInterruptStatusMask;
if (irqStatus.UsbInterrupt ||
irqStatus.UsbError) {
LOGENTRY(DeviceData, G, '_iEP', irqStatus.us, 0, 0);
USBPORT_INVALIDATE_ENDPOINT(DeviceData, NULL);
}
if (EnableInterrupts) {
LOGENTRY(DeviceData, G, '_iEE', 0, 0, 0);
WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us,
DeviceData->EnabledInterrupts.us);
}
}
VOID
USBMPFN
UhciDisableInterrupts(
IN PDEVICE_DATA DeviceData
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
USHORT legsup;
PHC_REGISTER reg;
UhciKdPrint((DeviceData, 2, "Disable interrupts\n"));
LOGENTRY(DeviceData, G, '_DIn', 0, 0, 0);
reg = DeviceData->Registers;
WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us,
0);
if (DeviceData->ControllerFlavor != UHCI_Ich2_1 &&
DeviceData->ControllerFlavor != UHCI_Ich2_2) {
//
// change the state of the PIRQD routing bit
//
USBPORT_READ_CONFIG_SPACE(
DeviceData,
&legsup,
LEGACY_BIOS_REGISTER,
sizeof(legsup));
LOGENTRY(DeviceData, G, '_leg', 0, legsup, 0);
// clear the PIRQD routing bit
legsup &= ~LEGSUP_USBPIRQD_EN;
USBPORT_WRITE_CONFIG_SPACE(
DeviceData,
&legsup,
LEGACY_BIOS_REGISTER,
sizeof(legsup));
}
}
VOID
UhciFlushInterrupts(
IN PDEVICE_DATA DeviceData
)
/*++
Routine Description:
used to flush rougue interrupts from the controller
after power events
Arguments:
Return Value:
--*/
{
PHC_REGISTER reg;
LOGENTRY(DeviceData, G, '_FIn', 0, 0, 0);
UhciKdPrint((DeviceData, 2, "Enable interrupts\n"));
reg = DeviceData->Registers;
// before writing the PIRQD register ack any eronious interrupts
// the controller may be asserting -- it should not be asserting
// at all but often is
WRITE_PORT_USHORT(&reg->UsbStatus.us, 0xFFFF);
}
VOID
USBMPFN
UhciEnableInterrupts(
IN PDEVICE_DATA DeviceData
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
USHORT legsup;
PHC_REGISTER reg;
LOGENTRY(DeviceData, G, '_EIn', 0, 0, 0);
UhciKdPrint((DeviceData, 2, "Enable interrupts\n"));
reg = DeviceData->Registers;
//
// change the state of the PIrQD routing bit
//
USBPORT_READ_CONFIG_SPACE(
DeviceData,
&legsup,
LEGACY_BIOS_REGISTER,
sizeof(legsup));
LOGENTRY(DeviceData, G, '_leg', 0, legsup, 0);
// clear the PIRQD routing bit
legsup |= LEGSUP_USBPIRQD_EN;
USBPORT_WRITE_CONFIG_SPACE(
DeviceData,
&legsup,
LEGACY_BIOS_REGISTER,
sizeof(legsup));
WRITE_PORT_USHORT(&reg->UsbInterruptEnable.us,
DeviceData->EnabledInterrupts.us);
}
VOID
UhciRHDisableIrq(
IN PDEVICE_DATA DeviceData
)
{
// Uhci doesn't have this IRQ
}
VOID
UhciRHEnableIrq(
IN PDEVICE_DATA DeviceData
)
{
// Uhci doesn't have this IRQ
}
#define UHCI_SOF_LATENCY 2
VOID
UhciInterruptNextSOF(
IN PDEVICE_DATA DeviceData
)
{
ULONG i, frame, offset, cf;
PHCD_TRANSFER_DESCRIPTOR td;
BOOLEAN found = FALSE;
cf = UhciGet32BitFrameNumber(DeviceData);
// find a TD
for (i=0; i<SOF_TD_COUNT; i++) {
td = &DeviceData->SofTdList->Td[i];
UHCI_ASSERT(DeviceData, td->Sig == SIG_HCD_SOFTD);
// use transferconext to hold req frame
frame = td->RequestFrame;
if (frame == cf+UHCI_SOF_LATENCY) {
// There's already one queued
found = TRUE;
break;
}
if (frame < cf) {
td->RequestFrame = (cf+UHCI_SOF_LATENCY);
LOGENTRY(DeviceData, G, '_SOF', td, td->RequestFrame, cf);
// insert TD
td->HwTD.LinkPointer.HwAddress = 0;
INSERT_ISOCH_TD(DeviceData, td, td->RequestFrame);
found = TRUE;
break;
}
}
if (!found) {
TEST_TRAP();
}
// recycle any old SOF interrupt TDs
for (i=0; i<SOF_TD_COUNT; i++) {
td = &DeviceData->SofTdList->Td[i];
UHCI_ASSERT(DeviceData, td->Sig == SIG_HCD_SOFTD);
// use transferconext to hold req frame
frame = td->RequestFrame;
if (frame &&
(frame < cf ||
frame - cf > UHCI_MAX_FRAME)) {
td->RequestFrame = 0;
}
}
}