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.
1575 lines
38 KiB
1575 lines
38 KiB
/*++
|
|
|
|
Copyright (c) 1999, 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
hydramp.c
|
|
|
|
Abstract:
|
|
|
|
USB 2.0 EHCI driver
|
|
|
|
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:
|
|
|
|
2-19-99 : created, jdunn
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include <initguid.h>
|
|
#include "usbpriv.h"
|
|
|
|
//implements the following miniport functions:
|
|
//EHCI_StartController
|
|
//EHCI_StopController
|
|
//EHCI_DisableInterrupts
|
|
//EHCI_EnableInterrupts
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_InitializeHardware(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the hardware registers for the host controller.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PHC_OPERATIONAL_REGISTER hcOp;
|
|
PHC_CAPABILITIES_REGISTER hcCap;
|
|
USBCMD cmd;
|
|
HCSPARAMS hcSparms;
|
|
LARGE_INTEGER finishTime, currentTime;
|
|
|
|
hcCap = DeviceData->CapabilitiesRegisters;
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
|
|
// reset the controller
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
LOGENTRY(DeviceData, G, '_res', cmd.ul, 0, 0);
|
|
cmd.HostControllerReset = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul);
|
|
|
|
KeQuerySystemTime(&finishTime);
|
|
// no spec'ed time -- we will graciously grant 0.1 sec.
|
|
//
|
|
// figure when we quit (.1 seconds later)
|
|
finishTime.QuadPart += 1000000;
|
|
|
|
// wait for reset bit to got to zero
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
while (cmd.HostControllerReset) {
|
|
|
|
KeQuerySystemTime(¤tTime);
|
|
|
|
if (currentTime.QuadPart >= finishTime.QuadPart) {
|
|
|
|
EHCI_KdPrint((DeviceData, 0,
|
|
"'EHCI controller failed to reset in .1 sec!\n"));
|
|
|
|
return USBMP_STATUS_HARDWARE_FAILURE;
|
|
}
|
|
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
|
|
}
|
|
|
|
hcSparms.ul =
|
|
READ_REGISTER_ULONG(&hcCap->HcStructuralParameters.ul);
|
|
|
|
DeviceData->NumberOfPorts =
|
|
(USHORT) hcSparms.NumberOfPorts;
|
|
|
|
DeviceData->PortPowerControl =
|
|
(USHORT) hcSparms.PortPowerControl;
|
|
|
|
// inialize operational registers
|
|
WRITE_REGISTER_ULONG(&hcOp->AsyncListAddr, 0);
|
|
WRITE_REGISTER_ULONG(&hcOp->PeriodicListBase, 0);
|
|
|
|
// set the enabled interrupts cache, we'll enable
|
|
// these interrupts when asked
|
|
DeviceData->EnabledInterrupts.UsbInterrupt = 1;
|
|
DeviceData->EnabledInterrupts.UsbError = 1;
|
|
DeviceData->EnabledInterrupts.FrameListRollover = 1;
|
|
DeviceData->EnabledInterrupts.HostSystemError = 1;
|
|
DeviceData->EnabledInterrupts.IntOnAsyncAdvance = 1;
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_InitializeSchedule(
|
|
PDEVICE_DATA DeviceData,
|
|
PUCHAR StaticQHs,
|
|
HW_32BIT_PHYSICAL_ADDRESS StaticQHsPhys
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build the schedule of static Eds
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
ULONG length;
|
|
ULONG i;
|
|
PHC_OPERATIONAL_REGISTER hcOp;
|
|
PHCD_QUEUEHEAD_DESCRIPTOR qh;
|
|
HW_LINK_POINTER asyncHwQh;
|
|
PHW_32BIT_PHYSICAL_ADDRESS frameBase;
|
|
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
|
|
// allocate a frame list
|
|
frameBase = DeviceData->FrameListBaseAddress =
|
|
(PHW_32BIT_PHYSICAL_ADDRESS) StaticQHs;
|
|
DeviceData->FrameListBasePhys =
|
|
StaticQHsPhys;
|
|
StaticQHs += USBEHCI_MAX_FRAME*sizeof(HW_32BIT_PHYSICAL_ADDRESS);
|
|
StaticQHsPhys += USBEHCI_MAX_FRAME*sizeof(HW_32BIT_PHYSICAL_ADDRESS);
|
|
|
|
// allocate a 'Dummy' QH for the Async list
|
|
qh = (PHCD_QUEUEHEAD_DESCRIPTOR) StaticQHs;
|
|
|
|
RtlZeroMemory(qh, sizeof(*qh));
|
|
asyncHwQh.HwAddress =
|
|
qh->PhysicalAddress = StaticQHsPhys;
|
|
// no current TD
|
|
// t-bit set on next TD
|
|
SET_T_BIT(qh->HwQH.Overlay.qTD.Next_qTD.HwAddress);
|
|
qh->HwQH.Overlay.qTD.Token.Halted = 1;
|
|
qh->HwQH.EpChars.HeadOfReclimationList = 1;
|
|
qh->Sig = SIG_HCD_AQH;
|
|
SET_QH(asyncHwQh.HwAddress);
|
|
// link to ourselves
|
|
qh->HwQH.HLink.HwAddress = asyncHwQh.HwAddress;
|
|
QH_DESCRIPTOR_PTR(qh->NextQh) = qh;
|
|
QH_DESCRIPTOR_PTR(qh->PrevQh) = qh;
|
|
|
|
DeviceData->AsyncQueueHead = qh;
|
|
|
|
StaticQHs += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
|
|
StaticQHsPhys += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
|
|
|
|
// allocate 64 static interrupt queue heads
|
|
for (i=0; i<64; i++) {
|
|
qh = (PHCD_QUEUEHEAD_DESCRIPTOR) StaticQHs;
|
|
qh->PhysicalAddress = StaticQHsPhys;
|
|
|
|
DeviceData->StaticInterruptQH[i] = qh;
|
|
|
|
StaticQHs += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
|
|
StaticQHsPhys += sizeof(HCD_QUEUEHEAD_DESCRIPTOR);
|
|
}
|
|
|
|
EHCI_InitailizeInterruptSchedule(DeviceData);
|
|
|
|
for (i=0; i<USBEHCI_MAX_FRAME; i++) {
|
|
|
|
PHCD_QUEUEHEAD_DESCRIPTOR qh;
|
|
HW_32BIT_PHYSICAL_ADDRESS qhPhys;
|
|
|
|
qh = EHCI_GetQueueHeadForFrame(DeviceData, i);
|
|
|
|
qhPhys = qh->PhysicalAddress;
|
|
SET_QH(qhPhys);
|
|
|
|
*frameBase = qhPhys;
|
|
frameBase++;
|
|
}
|
|
|
|
DeviceData->DummyQueueHeads = StaticQHs;
|
|
DeviceData->DummyQueueHeadsPhys = StaticQHsPhys;
|
|
|
|
StaticQHs+= sizeof(HCD_QUEUEHEAD_DESCRIPTOR)*USBEHCI_MAX_FRAME;
|
|
StaticQHsPhys+= sizeof(HCD_QUEUEHEAD_DESCRIPTOR)*USBEHCI_MAX_FRAME;
|
|
|
|
EHCI_AddDummyQueueHeads(DeviceData);
|
|
|
|
// program the frame list
|
|
WRITE_REGISTER_ULONG(&hcOp->PeriodicListBase,
|
|
DeviceData->FrameListBasePhys);
|
|
|
|
// write the async qh to the controller
|
|
WRITE_REGISTER_ULONG(&hcOp->AsyncListAddr, asyncHwQh.HwAddress);
|
|
|
|
mpStatus = USBMP_STATUS_SUCCESS;
|
|
|
|
return mpStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_ReadUlongRegFlag(
|
|
PDEVICE_DATA DeviceData,
|
|
PUCHAR DebugString,
|
|
PWCHAR FlagName,
|
|
ULONG FlagNameSize,
|
|
ULONG FlagBit
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
ULONG flag;
|
|
|
|
// get SOF modify value from registry
|
|
mpStatus =
|
|
USBPORT_GET_REGISTRY_KEY_VALUE(DeviceData,
|
|
TRUE, // software branch
|
|
FlagName,
|
|
FlagNameSize,
|
|
&flag,
|
|
sizeof(flag));
|
|
|
|
// if this call fails we just use the default
|
|
|
|
if (mpStatus == USBMP_STATUS_SUCCESS) {
|
|
|
|
if (flag) {
|
|
SET_FLAG(DeviceData->Flags, FlagBit);
|
|
}
|
|
EHCI_KdPrint((DeviceData, 1, "'%s: %d \n",
|
|
DebugString, flag));
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
EHCI_GetRegistryParameters(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
|
|
EHCI_ReadUlongRegFlag(DeviceData,
|
|
"Enable Idle Endpoint Support",
|
|
EN_IDLE_ENDPOINT_SUPPORT,
|
|
sizeof(EN_IDLE_ENDPOINT_SUPPORT),
|
|
EHCI_DD_EN_IDLE_EP_SUPPORT);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
USBMPFN
|
|
EHCI_StopController(
|
|
PDEVICE_DATA DeviceData,
|
|
BOOLEAN HwPresent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
USBCMD cmd;
|
|
PHC_OPERATIONAL_REGISTER hcOp = NULL;
|
|
CONFIGFLAG configFlag;
|
|
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
|
|
// clear the run bit
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
LOGENTRY(DeviceData, G, '_stp', cmd.ul, 0, 0);
|
|
cmd.HostControllerRun = 0;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul);
|
|
|
|
// mask off all interrupts
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul,
|
|
0);
|
|
|
|
// set cc control of the hc ports to the companion
|
|
// controllers
|
|
configFlag.ul = 0;
|
|
configFlag.RoutePortsToEHCI = 0;
|
|
WRITE_REGISTER_ULONG(&hcOp->ConfigFlag.ul, configFlag.ul);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
USBMPFN
|
|
EHCI_TakePortControl(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PHC_OPERATIONAL_REGISTER hcOp = NULL;
|
|
CONFIGFLAG configFlag;
|
|
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
|
|
configFlag.ul = READ_REGISTER_ULONG(&hcOp->ConfigFlag.ul);
|
|
EHCI_KdPrint((DeviceData, 0, "'EHCI - configflag %x\n", configFlag.ul));
|
|
DeviceData->LastConfigFlag.ul = configFlag.ul;
|
|
|
|
// set default port routing
|
|
configFlag.ul = 0;
|
|
configFlag.RoutePortsToEHCI = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->ConfigFlag.ul, configFlag.ul);
|
|
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
USBMPFN
|
|
EHCI_StartController(
|
|
PDEVICE_DATA DeviceData,
|
|
PHC_RESOURCES HcResources
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
PHC_OPERATIONAL_REGISTER hcOp = NULL;
|
|
PHC_CAPABILITIES_REGISTER hcCap = NULL;
|
|
PUCHAR base;
|
|
USBCMD cmd;
|
|
HCLENGTHVERSION hcLengthVersion;
|
|
ULONG capLength;
|
|
ULONG hciVersion;
|
|
CONFIGFLAG configFlag;
|
|
UCHAR fladj; // fBIOS set frame length adjustment
|
|
|
|
DeviceData->Sig = SIG_EHCI_DD;
|
|
DeviceData->ControllerFlavor =
|
|
HcResources->ControllerFlavor;
|
|
DeviceData->DeviceStarted = FALSE;
|
|
|
|
USBPORT_READ_CONFIG_SPACE(
|
|
DeviceData,
|
|
&DeviceData->Vid,
|
|
0,
|
|
sizeof(DeviceData->Vid));
|
|
|
|
USBPORT_READ_CONFIG_SPACE(
|
|
DeviceData,
|
|
&DeviceData->Dev,
|
|
2,
|
|
sizeof(DeviceData->Dev));
|
|
|
|
#if DBG
|
|
if (AGERE(DeviceData)) {
|
|
EHCI_KdPrint((DeviceData, 0, "'EHCI Agere Controller Detected\n"));
|
|
} else if (NEC(DeviceData)) {
|
|
EHCI_KdPrint((DeviceData, 0, "'EHCI NEC Controller Detected\n"));
|
|
} else {
|
|
EHCI_KdPrint((DeviceData, 0, "'EHCI Generic Controller Detected\n"));
|
|
}
|
|
#endif
|
|
|
|
// get the frame length adjustment value set by the BIOS
|
|
USBPORT_READ_CONFIG_SPACE(
|
|
DeviceData,
|
|
&fladj,
|
|
0x61,
|
|
sizeof(fladj));
|
|
|
|
DeviceData->SavedFladj = fladj;
|
|
|
|
DeviceData->IsoEndpointListHead = NULL;
|
|
|
|
if (EHCI_PastExpirationDate(DeviceData)) {
|
|
return USBMP_STATUS_INIT_FAILURE;
|
|
}
|
|
|
|
// assume success
|
|
mpStatus = USBMP_STATUS_SUCCESS;
|
|
|
|
EHCI_ASSERT(DeviceData, HcResources->CommonBufferVa != NULL);
|
|
// validate our resources
|
|
if ((HcResources->Flags & (HCR_MEM_REGS | HCR_IRQ)) !=
|
|
(HCR_MEM_REGS | HCR_IRQ)) {
|
|
mpStatus = USBMP_STATUS_INIT_FAILURE;
|
|
}
|
|
|
|
base = HcResources->DeviceRegisters;
|
|
|
|
hcCap = DeviceData->CapabilitiesRegisters =
|
|
(PHC_CAPABILITIES_REGISTER) base;
|
|
|
|
hcLengthVersion.ul = READ_REGISTER_ULONG(&hcCap->HcLengthVersion.ul);
|
|
|
|
capLength = hcLengthVersion.HcCapLength;
|
|
hciVersion = hcLengthVersion.HcVersion;
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "'EHCI CAPLENGTH = 0x%x\n", capLength));
|
|
EHCI_KdPrint((DeviceData, 1, "'EHCI HCIVERSION = 0x%x\n", hciVersion));
|
|
|
|
// set up or device data structure
|
|
hcOp = DeviceData->OperationalRegisters =
|
|
(PHC_OPERATIONAL_REGISTER) (base + capLength);
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "'EHCI mapped Operational Regs = %x\n", hcOp));
|
|
EHCI_KdPrint((DeviceData, 1, "'EHCI mapped Capabilities Regs = %x\n", hcCap));
|
|
|
|
EHCI_GetRegistryParameters(DeviceData);
|
|
|
|
// if (mpStatus == USBMP_STATUS_SUCCESS) {
|
|
// mpStatus = EHCI_StopBIOS(DeviceData);
|
|
// }
|
|
|
|
if (mpStatus == USBMP_STATUS_SUCCESS) {
|
|
// got resources and schedule
|
|
// init the controller
|
|
mpStatus = EHCI_InitializeHardware(DeviceData);
|
|
}
|
|
|
|
if (mpStatus == USBMP_STATUS_SUCCESS) {
|
|
|
|
// inialize static Queue Heads
|
|
PUCHAR staticQHs;
|
|
HW_32BIT_PHYSICAL_ADDRESS staticQHsPhys;
|
|
|
|
// carve the common buffer block in to
|
|
// static QueueHeads
|
|
//
|
|
// set up the schedule
|
|
|
|
staticQHs = HcResources->CommonBufferVa;
|
|
staticQHsPhys = HcResources->CommonBufferPhys;
|
|
|
|
// set up the schedule
|
|
mpStatus = EHCI_InitializeSchedule(DeviceData,
|
|
staticQHs,
|
|
staticQHsPhys);
|
|
|
|
|
|
}
|
|
|
|
if (mpStatus == USBMP_STATUS_SUCCESS) {
|
|
|
|
USBPORT_READ_CONFIG_SPACE(
|
|
DeviceData,
|
|
&fladj,
|
|
0x61,
|
|
sizeof(fladj));
|
|
|
|
if (fladj != DeviceData->SavedFladj) {
|
|
TEST_TRAP();
|
|
|
|
fladj = DeviceData->SavedFladj;
|
|
USBPORT_WRITE_CONFIG_SPACE(
|
|
DeviceData,
|
|
&fladj,
|
|
0x61,
|
|
sizeof(fladj));
|
|
}
|
|
|
|
// set default port routing
|
|
configFlag.ul = 0;
|
|
configFlag.RoutePortsToEHCI = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->ConfigFlag.ul, configFlag.ul);
|
|
|
|
DeviceData->LastConfigFlag.ul = configFlag.ul;
|
|
|
|
// set the interrupt threshold to maximum
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
cmd.InterruptThreshold = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul);
|
|
|
|
// start the controller
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
LOGENTRY(DeviceData, G, '_run', cmd.ul, 0, 0);
|
|
cmd.HostControllerRun = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul);
|
|
|
|
DeviceData->DeviceStarted = TRUE;
|
|
|
|
if (HcResources->Restart) {
|
|
USHORT p;
|
|
// we have a restart, re-power the ports here so that
|
|
// we can hand of devices that are on the 1.1 bus
|
|
EHCI_KdPrint((DeviceData, 0, "'Restart, power chirpable ports\n"));
|
|
// power the ports
|
|
for (p = 1; p <= DeviceData->NumberOfPorts; p++) {
|
|
EHCI_RH_SetFeaturePortPower(DeviceData, p);
|
|
}
|
|
|
|
// no poweron2powergood for EHCI root ports, wait
|
|
// 100 ms for port power stabilization
|
|
// 100 ms minimum debiunce time
|
|
USBPORT_WAIT(DeviceData, 200);
|
|
|
|
// bugbug this will keep some HS mass storage devices from failing after
|
|
// hibernate, however it will significantly increase resume from hibernate
|
|
// time. see bug #586818
|
|
// USBPORT_WAIT(DeviceData, 500);
|
|
for (p = 1; p <= DeviceData->NumberOfPorts; p++) {
|
|
EHCI_RH_ChirpRootPort(DeviceData, p);
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUG_BREAK(DeviceData);
|
|
}
|
|
|
|
return mpStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_SuspendController(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
{
|
|
USBCMD cmd;
|
|
USBSTS status;
|
|
USBINTR intr;
|
|
PHC_OPERATIONAL_REGISTER hcOp = NULL;
|
|
ULONG i,p;
|
|
USBSTS irqStatus;
|
|
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
// save all volatile regs from the core power well
|
|
|
|
// since we may loose power on the controller chip (not bus)
|
|
// the miniport is resposnible for saving HW state
|
|
DeviceData->PeriodicListBaseSave =
|
|
READ_REGISTER_ULONG(&hcOp->PeriodicListBase);
|
|
DeviceData->AsyncListAddrSave =
|
|
READ_REGISTER_ULONG(&hcOp->AsyncListAddr);
|
|
DeviceData->SegmentSelectorSave =
|
|
READ_REGISTER_ULONG(&hcOp->SegmentSelector);
|
|
// preserve the state of the list enable bits
|
|
DeviceData->CmdSave.ul =
|
|
READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
|
|
// reset the PM chirp state flags for another pass at power
|
|
// management
|
|
DeviceData, DeviceData->PortPMChirp == 0;
|
|
|
|
// Save away the command register
|
|
// DeviceData->SuspendCommandReg.us =
|
|
// command.us = READ_PORT_USHORT(®->UsbCommand.us);
|
|
|
|
// clear the int on async advance doorbell
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
cmd.IntOnAsyncAdvanceDoorbell = 0;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul,
|
|
cmd.ul);
|
|
|
|
|
|
// Stop the controller
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
LOGENTRY(DeviceData, G, '_st1', cmd.ul, 0, 0);
|
|
cmd.HostControllerRun = 0;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul);
|
|
|
|
// ack any interrupts that may be left over from the halt
|
|
// process. The controller should not generate any new
|
|
// interrupts when it is stopped. For some reason the NEC
|
|
// controller generates a doorbel interrupt on halt.
|
|
|
|
// wait 1 microframe
|
|
KeStallExecutionProcessor(125);
|
|
irqStatus.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul);
|
|
// just look at the IRQ status bits
|
|
irqStatus.ul &= HcInterruptStatusMask;
|
|
if (irqStatus.ul != 0) {
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbStatus.ul,
|
|
irqStatus.ul);
|
|
}
|
|
|
|
// mask off all interrupts now
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul,
|
|
0);
|
|
|
|
|
|
// Wait for the HC to halt
|
|
// Note that according to the sepc if we don't halt in ms
|
|
// (16ms) the hardware is busted.
|
|
for (i=0; i<10; i++) {
|
|
status.ul = READ_REGISTER_ULONG(&hcOp->UsbStatus.ul);
|
|
if (status.HcHalted) {
|
|
break;
|
|
}
|
|
USBPORT_WAIT(DeviceData, 1);
|
|
}
|
|
|
|
if (status.HcHalted != 1) {
|
|
// hardware is f'ed up
|
|
TEST_TRAP();
|
|
}
|
|
|
|
//if (!status.HCHalted) {
|
|
//
|
|
// // Can't get the HCHalted bit to stick, so reset the controller.
|
|
// command.GlobalReset = 1;
|
|
// WRITE_PORT_USHORT(®->UsbCommand.us, command.us);
|
|
//
|
|
// USBPORT_WAIT(DeviceData, 10);
|
|
//
|
|
// command.GlobalReset = 0;
|
|
// WRITE_PORT_USHORT(®->UsbCommand.us, command.us);
|
|
|
|
// // Re-enable interrupts, since they are zero'd out on reset.
|
|
// WRITE_PORT_USHORT(®->UsbInterruptEnable.us, DeviceData->EnabledInterrupts.us);
|
|
//
|
|
//}
|
|
|
|
// enable the port chage interrupt, this allows us to wake
|
|
// in the selective suspend case
|
|
intr.ul = READ_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul);
|
|
intr.PortChangeDetect = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul, intr.ul);
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_ResumeController(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
{
|
|
USBCMD cmd;
|
|
PHC_OPERATIONAL_REGISTER hcOp = NULL;
|
|
CONFIGFLAG configFlag;
|
|
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "'>EHCI_ResumeController\n"));
|
|
|
|
// don't mess with handoff regs for now
|
|
//configFlag.ul = 0;
|
|
//configFlag.RoutePortsToEHCI = 1;
|
|
//WRITE_REGISTER_ULONG(&hcOp->ConfigFlag.ul, configFlag.ul);
|
|
|
|
// restore volitile regs
|
|
//configFlag.ul = READ_REGISTER_ULONG(&hcOp->ConfigFlag.ul);
|
|
configFlag.ul = DeviceData->LastConfigFlag.ul;
|
|
if (configFlag.RoutePortsToEHCI == 0) {
|
|
// we have a reset
|
|
EHCI_KdPrint((DeviceData, 1, "'Routing bit has reset to 0\n"));
|
|
|
|
configFlag.RoutePortsToEHCI = 1;
|
|
DeviceData->LastConfigFlag.ul = configFlag.ul;
|
|
WRITE_REGISTER_ULONG(&hcOp->ConfigFlag.ul, configFlag.ul);
|
|
|
|
return USBMP_STATUS_HARDWARE_FAILURE;
|
|
}
|
|
|
|
// restore volitile regs
|
|
WRITE_REGISTER_ULONG(&hcOp->SegmentSelector, DeviceData->SegmentSelectorSave);
|
|
WRITE_REGISTER_ULONG(&hcOp->PeriodicListBase, DeviceData->PeriodicListBaseSave);
|
|
WRITE_REGISTER_ULONG(&hcOp->AsyncListAddr, DeviceData->AsyncListAddrSave);
|
|
|
|
// start the controller
|
|
cmd.ul = READ_REGISTER_ULONG(&hcOp->UsbCommand.ul);
|
|
LOGENTRY(DeviceData, G, '_run', cmd.ul, 0, 0);
|
|
cmd.HostControllerRun = 1;
|
|
|
|
// restore volatile cmd bits
|
|
cmd.AsyncScheduleEnable = DeviceData->CmdSave.AsyncScheduleEnable;
|
|
cmd.PeriodicScheduleEnable = DeviceData->CmdSave.PeriodicScheduleEnable;
|
|
cmd.InterruptThreshold = DeviceData->CmdSave.InterruptThreshold;
|
|
|
|
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbCommand.ul, cmd.ul);
|
|
|
|
WRITE_REGISTER_ULONG(&hcOp->UsbInterruptEnable.ul,
|
|
DeviceData->EnabledInterrupts.ul);
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "'<EHCI_ResumeController\n"));
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_OpenEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_PARAMETERS EndpointParameters,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
EndpointData->Sig = SIG_EP_DATA;
|
|
// save a copy of the parameters
|
|
EndpointData->Parameters = *EndpointParameters;
|
|
EndpointData->Flags = 0;
|
|
EndpointData->PendingTransfers = 0;
|
|
|
|
switch (EndpointParameters->TransferType) {
|
|
|
|
case Control:
|
|
|
|
EndpointData->MaxPendingTransfers = 1;
|
|
mpStatus = EHCI_OpenBulkOrControlEndpoint(
|
|
DeviceData,
|
|
TRUE,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
|
|
break;
|
|
|
|
case Interrupt:
|
|
|
|
mpStatus = EHCI_OpenInterruptEndpoint(
|
|
DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
|
|
break;
|
|
|
|
case Bulk:
|
|
|
|
EndpointData->MaxPendingTransfers = 1;
|
|
mpStatus = EHCI_OpenBulkOrControlEndpoint(
|
|
DeviceData,
|
|
FALSE,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
|
|
break;
|
|
|
|
case Isochronous:
|
|
|
|
if (EndpointParameters->DeviceSpeed == HighSpeed) {
|
|
mpStatus = EHCI_OpenHsIsochronousEndpoint(
|
|
DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
} else {
|
|
mpStatus = EHCI_OpenIsochronousEndpoint(
|
|
DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TEST_TRAP();
|
|
mpStatus = USBMP_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
return mpStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_CloseEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
// nothing to do here
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_PokeEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_PARAMETERS EndpointParameters,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PHCD_QUEUEHEAD_DESCRIPTOR qh;
|
|
ULONG oldBandwidth;
|
|
|
|
LOGENTRY(DeviceData, G, '_Pok', EndpointData,
|
|
EndpointParameters, 0);
|
|
|
|
switch(EndpointData->Parameters.TransferType) {
|
|
case Interrupt:
|
|
case Control:
|
|
case Bulk:
|
|
return EHCI_PokeAsyncEndpoint(DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
case Isochronous:
|
|
return EHCI_PokeIsoEndpoint(DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
}
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_RebalanceEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_PARAMETERS EndpointParameters,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
compute how much common buffer we will need
|
|
for this endpoint
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
switch (EndpointParameters->TransferType) {
|
|
case Interrupt:
|
|
EHCI_RebalanceInterruptEndpoint(DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
break;
|
|
|
|
case Isochronous:
|
|
EHCI_RebalanceIsoEndpoint(DeviceData,
|
|
EndpointParameters,
|
|
EndpointData);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_QueryEndpointRequirements(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_PARAMETERS EndpointParameters,
|
|
OUT PENDPOINT_REQUIREMENTS EndpointRequirements
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
compute how much common buffer we will need
|
|
for this endpoint
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
switch (EndpointParameters->TransferType) {
|
|
|
|
case Control:
|
|
|
|
EndpointRequirements->MinCommonBufferBytes =
|
|
sizeof(HCD_QUEUEHEAD_DESCRIPTOR) +
|
|
TDS_PER_CONTROL_ENDPOINT*sizeof(HCD_TRANSFER_DESCRIPTOR);
|
|
|
|
EndpointRequirements->MaximumTransferSize =
|
|
MAX_CONTROL_TRANSFER_SIZE;
|
|
break;
|
|
|
|
case Interrupt:
|
|
|
|
EndpointRequirements->MinCommonBufferBytes =
|
|
sizeof(HCD_QUEUEHEAD_DESCRIPTOR) +
|
|
TDS_PER_INTERRUPT_ENDPOINT*sizeof(HCD_TRANSFER_DESCRIPTOR);
|
|
|
|
EndpointRequirements->MaximumTransferSize =
|
|
MAX_INTERRUPT_TRANSFER_SIZE;
|
|
|
|
break;
|
|
|
|
case Bulk:
|
|
|
|
//
|
|
// TDS_PER_ENDPOINT limits the largest transfer we
|
|
// can handle.
|
|
//
|
|
|
|
// TDS_PER_ENDPOINT TDs plus an ED
|
|
EndpointRequirements->MinCommonBufferBytes =
|
|
sizeof(HCD_QUEUEHEAD_DESCRIPTOR) +
|
|
TDS_PER_BULK_ENDPOINT*sizeof(HCD_TRANSFER_DESCRIPTOR);
|
|
|
|
EndpointRequirements->MaximumTransferSize =
|
|
MAX_BULK_TRANSFER_SIZE;
|
|
break;
|
|
|
|
case Isochronous:
|
|
|
|
if (EndpointParameters->DeviceSpeed == HighSpeed) {
|
|
EndpointRequirements->MinCommonBufferBytes =
|
|
USBEHCI_MAX_FRAME*sizeof(HCD_HSISO_TRANSFER_DESCRIPTOR);
|
|
|
|
EndpointRequirements->MaximumTransferSize =
|
|
MAX_HSISO_TRANSFER_SIZE;
|
|
} else {
|
|
// TDS_PER_ENDPOINT TDs plus an ED
|
|
EndpointRequirements->MinCommonBufferBytes =
|
|
TDS_PER_ISO_ENDPOINT*sizeof(HCD_SI_TRANSFER_DESCRIPTOR);
|
|
|
|
EndpointRequirements->MaximumTransferSize =
|
|
MAX_ISO_TRANSFER_SIZE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
USBPORT_BUGCHECK(DeviceData);
|
|
}
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_PollEndpoint(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
switch(EndpointData->Parameters.TransferType) {
|
|
|
|
case Control:
|
|
case Bulk:
|
|
case Interrupt:
|
|
EHCI_PollAsyncEndpoint(DeviceData, EndpointData);
|
|
break;
|
|
case Isochronous:
|
|
EHCI_PollIsoEndpoint(DeviceData, EndpointData);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
PHCD_TRANSFER_DESCRIPTOR
|
|
EHCI_AllocTd(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a TD from an endpoints pool
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
PHCD_TRANSFER_DESCRIPTOR td;
|
|
|
|
for (i=0; i<EndpointData->TdCount; i++) {
|
|
td = &EndpointData->TdList->Td[i];
|
|
|
|
if (!TEST_FLAG(td->Flags, TD_FLAG_BUSY)) {
|
|
SET_FLAG(td->Flags, TD_FLAG_BUSY);
|
|
LOGENTRY(DeviceData, G, '_aTD', td, 0, 0);
|
|
EndpointData->FreeTds--;
|
|
return td;
|
|
}
|
|
}
|
|
|
|
// we should always find one
|
|
EHCI_ASSERT(DeviceData, FALSE);
|
|
USBPORT_BUGCHECK(DeviceData);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_SetEndpointStatus(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
MP_ENDPOINT_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
switch (EndpointData->Parameters.TransferType) {
|
|
case Control:
|
|
case Bulk:
|
|
case Interrupt:
|
|
EHCI_SetAsyncEndpointStatus(DeviceData,
|
|
EndpointData,
|
|
Status);
|
|
break;
|
|
case Isochronous:
|
|
// nothing to do for iso
|
|
break;
|
|
|
|
default:
|
|
USBPORT_BUGCHECK(DeviceData);
|
|
}
|
|
}
|
|
|
|
|
|
MP_ENDPOINT_STATUS
|
|
EHCI_GetEndpointStatus(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
switch (EndpointData->Parameters.TransferType) {
|
|
case Control:
|
|
case Bulk:
|
|
case Interrupt:
|
|
return EHCI_GetAsyncEndpointStatus(DeviceData,
|
|
EndpointData);
|
|
break;
|
|
}
|
|
|
|
// return RUNNING for iso
|
|
|
|
return ENDPOINT_STATUS_RUN;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_SetEndpointState(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
MP_ENDPOINT_STATE State
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
|
|
LOGENTRY(DeviceData, G, '_ses', EndpointData, 0, State);
|
|
|
|
switch (EndpointData->Parameters.TransferType) {
|
|
case Control:
|
|
case Bulk:
|
|
case Interrupt:
|
|
EHCI_SetAsyncEndpointState(DeviceData,
|
|
EndpointData,
|
|
State);
|
|
break;
|
|
case Isochronous:
|
|
EHCI_SetIsoEndpointState(DeviceData,
|
|
EndpointData,
|
|
State);
|
|
break;
|
|
default:
|
|
USBPORT_BUGCHECK(DeviceData);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
MP_ENDPOINT_STATE
|
|
EHCI_GetEndpointState(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
MP_ENDPOINT_STATE currentState;
|
|
PHCD_QUEUEHEAD_DESCRIPTOR qh;
|
|
|
|
// assume we are active
|
|
currentState = ENDPOINT_ACTIVE;
|
|
|
|
qh = EndpointData->QueueHead;
|
|
|
|
// removed from schedule?
|
|
if (!TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_IN_SCHEDULE)) {
|
|
// yes
|
|
currentState = TEST_FLAG(qh->QhFlags, EHCI_QH_FLAG_QH_REMOVED) ?
|
|
ENDPOINT_REMOVE : ENDPOINT_PAUSE;
|
|
}
|
|
|
|
LOGENTRY(DeviceData, G, '_ges', EndpointData, 0, currentState);
|
|
|
|
return currentState;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_PollController(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
|
|
USBPORT_INVALIDATE_ROOTHUB(DeviceData);
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_SubmitTransfer(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
PTRANSFER_PARAMETERS TransferParameters,
|
|
PTRANSFER_CONTEXT TransferContext,
|
|
PTRANSFER_SG_LIST TransferSGList
|
|
)
|
|
{
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
// init the context
|
|
RtlZeroMemory(TransferContext, sizeof(*TransferContext));
|
|
TransferContext->Sig = SIG_EHCI_TRANSFER;
|
|
TransferContext->UsbdStatus = USBD_STATUS_SUCCESS;
|
|
TransferContext->EndpointData = EndpointData;
|
|
TransferContext->TransferParameters = TransferParameters;
|
|
|
|
switch (EndpointData->Parameters.TransferType) {
|
|
case Control:
|
|
mpStatus =
|
|
EHCI_ControlTransfer(DeviceData,
|
|
EndpointData,
|
|
TransferParameters,
|
|
TransferContext,
|
|
TransferSGList);
|
|
break;
|
|
case Interrupt:
|
|
mpStatus =
|
|
EHCI_InterruptTransfer(DeviceData,
|
|
EndpointData,
|
|
TransferParameters,
|
|
TransferContext,
|
|
TransferSGList);
|
|
break;
|
|
case Bulk:
|
|
mpStatus =
|
|
EHCI_BulkTransfer(DeviceData,
|
|
EndpointData,
|
|
TransferParameters,
|
|
TransferContext,
|
|
TransferSGList);
|
|
break;
|
|
default:
|
|
TEST_TRAP();
|
|
}
|
|
|
|
return mpStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
EHCI_AbortTransfer(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
PTRANSFER_CONTEXT TransferContext,
|
|
OUT PULONG BytesTransferred
|
|
)
|
|
{
|
|
switch (EndpointData->Parameters.TransferType) {
|
|
case Control:
|
|
case Interrupt:
|
|
case Bulk:
|
|
EHCI_AbortAsyncTransfer(DeviceData,
|
|
EndpointData,
|
|
TransferContext);
|
|
break;
|
|
default:
|
|
EHCI_AbortIsoTransfer(DeviceData,
|
|
EndpointData,
|
|
TransferContext);
|
|
}
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_PassThru (
|
|
PDEVICE_DATA DeviceData,
|
|
GUID *FunctionGuid,
|
|
ULONG ParameterLength,
|
|
OUT PVOID Parameters
|
|
)
|
|
{
|
|
PUCHAR p = Parameters;
|
|
UCHAR pdkApi;
|
|
ULONG portNumber;
|
|
USB_MINIPORT_STATUS mpStatus;
|
|
|
|
mpStatus = USBMP_STATUS_NOT_SUPPORTED;
|
|
if (RtlEqualMemory(FunctionGuid, &GUID_USBPRIV_ROOTPORT_STATUS, sizeof(GUID)))
|
|
{
|
|
mpStatus = EHCI_RH_UsbprivRootPortStatus(DeviceData,
|
|
ParameterLength,
|
|
Parameters);
|
|
}
|
|
|
|
#if 0
|
|
portNumber = *(p+1);
|
|
|
|
mpStatus = USBMP_STATUS_NOT_SUPPORTED;
|
|
|
|
// pdkApi - force full speed
|
|
|
|
pdkApi = *p;
|
|
switch (pdkApi) {
|
|
// obtumtuserate the port as requested
|
|
case 0:
|
|
{
|
|
PHC_OPERATIONAL_REGISTER hcOp;
|
|
USHORT portNumber;
|
|
PORTSC port;
|
|
|
|
portNumber = *(p+1);
|
|
hcOp = DeviceData->OperationalRegisters;
|
|
|
|
// first power the port up
|
|
port.ul = READ_REGISTER_ULONG(&hcOp->PortRegister[portNumber-1].ul);
|
|
port.PortPower = 1;
|
|
WRITE_REGISTER_ULONG(&hcOp->PortRegister[portNumber-1].ul,
|
|
port.ul);
|
|
|
|
KeStallExecutionProcessor(10); //stall for 10 microseconds
|
|
|
|
EHCI_OptumtuseratePort(DeviceData, portNumber);
|
|
|
|
port.ul = READ_REGISTER_ULONG(&hcOp->PortRegister[portNumber-1].ul);
|
|
|
|
SET_BIT(DeviceData->HighSpeedDeviceAttached, portNumber-1);
|
|
|
|
// see if it worked
|
|
if (port.ul == 0x1205) {
|
|
mpStatus = USBMP_STATUS_SUCCESS;
|
|
} else {
|
|
mpStatus = USBMP_STATUS_FAILURE;
|
|
}
|
|
|
|
LOGENTRY(DeviceData, G, '_hsE', portNumber, mpStatus, port.ul);
|
|
TEST_TRAP();
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
// force a connect change
|
|
|
|
// indicate a port change condition to the hub
|
|
SET_BIT(DeviceData->PortConnectChange, portNumber-1);
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return mpStatus;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
EHCI_SetEndpointDataToggle(
|
|
PDEVICE_DATA DeviceData,
|
|
PENDPOINT_DATA EndpointData,
|
|
ULONG Toggle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Toggle is 0 or 1
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PHCD_QUEUEHEAD_DESCRIPTOR qh;
|
|
|
|
if (EndpointData->Parameters.TransferType == Control ||
|
|
EndpointData->Parameters.TransferType == Isochronous) {
|
|
|
|
// nothing to do for control and iso
|
|
return;
|
|
}
|
|
|
|
qh = EndpointData->QueueHead;
|
|
qh->HwQH.Overlay.qTD.Token.DataToggle = Toggle;
|
|
|
|
LOGENTRY(DeviceData, G, '_stg', EndpointData, 0, Toggle);
|
|
}
|
|
|
|
VOID
|
|
EHCI_CheckController(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
{
|
|
if (DeviceData->DeviceStarted) {
|
|
EHCI_HardwarePresent(DeviceData, TRUE);
|
|
}
|
|
}
|
|
|
|
// Beta versions of our miniport driver have a hard coded exp date
|
|
|
|
#ifdef NO_EXP_DATE
|
|
#define EXPIRATION_DATE 0
|
|
#else
|
|
//Sep 1, 2001
|
|
//#define EXPIRATION_DATE 0x01c133406ab2406c
|
|
|
|
//Oct 24, 2001
|
|
//#define EXPIRATION_DATE 0x01c15cd5887bc884
|
|
|
|
//Dec 31, 2001
|
|
//#define EXPIRATION_DATE 0x01c19251a68bfac0
|
|
#endif
|
|
|
|
BOOLEAN
|
|
EHCI_PastExpirationDate(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
{
|
|
LARGE_INTEGER systemTime;
|
|
|
|
KeQuerySystemTime(&systemTime);
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "system time: %x %x\n", systemTime.QuadPart));
|
|
EHCI_KdPrint((DeviceData, 1, "exp system time: %x %x\n", EXPIRATION_DATE));
|
|
|
|
if (EXPIRATION_DATE &&
|
|
systemTime.QuadPart > EXPIRATION_DATE) {
|
|
EHCI_KdPrint((DeviceData, 1, "driver expired"));
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
UCHAR
|
|
EHCI_GetEECP(
|
|
PDEVICE_DATA DeviceData,
|
|
UCHAR CapabilityId
|
|
)
|
|
/*
|
|
returns the offset of a specific EECP in config space
|
|
given a cap id
|
|
|
|
returns 0 if no EECP or Id not found
|
|
|
|
*/
|
|
{
|
|
UCHAR eecpOffset;
|
|
HC_EECP eecp;
|
|
PHC_CAPABILITIES_REGISTER hcCap;
|
|
|
|
hcCap = DeviceData->CapabilitiesRegisters;
|
|
|
|
eecpOffset = (UCHAR) hcCap->HcCapabilityParameters.EECP;
|
|
|
|
if (eecpOffset == 0) {
|
|
return eecpOffset;
|
|
}
|
|
|
|
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "EECP offset found @ 0x%x\n", eecpOffset));
|
|
|
|
do {
|
|
|
|
USBPORT_READ_CONFIG_SPACE(
|
|
DeviceData,
|
|
&eecp,
|
|
eecpOffset,
|
|
sizeof(eecp));
|
|
|
|
EHCI_KdPrint((DeviceData, 1, "EECP cap 0x%x Next 0x%x (%08.8x)\n",
|
|
eecp.CapId, eecp.NextCap, eecp.ul));
|
|
|
|
if (eecp.CapId == CapabilityId) {
|
|
return eecpOffset;
|
|
}
|
|
|
|
eecpOffset = (UCHAR) eecp.NextCap;
|
|
|
|
} while (eecpOffset);
|
|
|
|
return eecpOffset;
|
|
}
|
|
|
|
|
|
USB_MINIPORT_STATUS
|
|
EHCI_StopBIOS(
|
|
PDEVICE_DATA DeviceData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stop Legacy BIOS
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
UCHAR biosOffset;
|
|
USB_LEGACYBIOS_REGISTERS hcLegs;
|
|
|
|
biosOffset = EHCI_GetEECP(DeviceData, EECP_PRE_OS_HANDOFF);
|
|
|
|
// do we have BIOS
|
|
if (biosOffset) {
|
|
// hey! nice Legs.
|
|
EHCI_KdPrint((DeviceData, 1, "EHCI Legacy BIOS EECP registers detected\n"));
|
|
|
|
// read the legacy registers
|
|
USBPORT_READ_CONFIG_SPACE(DeviceData, &hcLegs, biosOffset, sizeof(hcLegs));
|
|
|
|
// see if BIOS is enabled
|
|
if (hcLegs.Caps.HcBIOSowned) {
|
|
USBLEGSUP legSup;
|
|
|
|
EHCI_KdPrint((DeviceData, 0, "EHCI Legacy BIOS detected\n"));
|
|
TEST_TRAP();
|
|
|
|
// take ownership,
|
|
// set OS owned
|
|
legSup.ul = hcLegs.Caps.ul;
|
|
legSup.HcOSowned = 1;
|
|
|
|
USBPORT_WRITE_CONFIG_SPACE(DeviceData, &legSup, biosOffset, sizeof(legSup));
|
|
|
|
// wait on Bios owned to go to zero
|
|
do {
|
|
USBPORT_READ_CONFIG_SPACE(DeviceData, &legSup, biosOffset, sizeof(legSup));
|
|
} while (legSup.HcBIOSowned);
|
|
|
|
}
|
|
}
|
|
|
|
return USBMP_STATUS_SUCCESS;
|
|
}
|
|
|
|
|