WORK_QUEUE_ITEM m_StatusChangeWorkItem; // work item for status change callback
ULONG m_SyncFramePhysAddr; // periodic frame list physical address
BOOLEAN m_ResetInProgress[16]; // set when a reset is in progress
-
+ BUS_INTERFACE_STANDARD m_BusInterface; // pci bus interface
// read register
ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
PDEVICE_OBJECT PhysicalDeviceObject,
PDEVICE_OBJECT LowerDeviceObject)
{
- BUS_INTERFACE_STANDARD BusInterface;
PCI_COMMON_CONFIG PciConfig;
NTSTATUS Status;
ULONG BytesRead;
m_VendorID = 0;
m_DeviceID = 0;
- Status = GetBusInterface(PhysicalDeviceObject, &BusInterface);
+ Status = GetBusInterface(PhysicalDeviceObject, &m_BusInterface);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to get BusInteface!\n");
return Status;
}
- BytesRead = (*BusInterface.GetBusData)(BusInterface.Context,
+ BytesRead = (*m_BusInterface.GetBusData)(m_BusInterface.Context,
PCI_WHICHSPACE_CONFIG,
&PciConfig,
0,
DPRINT1("PCI Configuration shows this as a non Bus Mastering device! Enabling...\n");
PciConfig.Command |= PCI_ENABLE_BUS_MASTER;
- BusInterface.SetBusData(BusInterface.Context, PCI_WHICHSPACE_CONFIG, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
+ m_BusInterface.SetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
- BytesRead = (*BusInterface.GetBusData)(BusInterface.Context,
+ BytesRead = (*m_BusInterface.GetBusData)(m_BusInterface.Context,
PCI_WHICHSPACE_CONFIG,
&PciConfig,
0,
PHYSICAL_ADDRESS AsyncPhysicalAddress;
PVOID ResourceBase;
NTSTATUS Status;
+ UCHAR Value;
+ UCHAR PortCount;
DPRINT1("CUSBHardwareDevice::PnpStart\n");
for(Index = 0; Index < TranslatedResources->List[0].PartialResourceList.Count; Index++)
//
// Get controllers capabilities
//
- m_Capabilities.Length = READ_REGISTER_UCHAR((PUCHAR)ResourceBase);
- m_Capabilities.HCIVersion = READ_REGISTER_USHORT((PUSHORT)((ULONG)ResourceBase + 2));
- m_Capabilities.HCSParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 4));
- m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 8));
+ m_Capabilities.Length = READ_REGISTER_UCHAR((PUCHAR)ResourceBase + EHCI_CAPLENGTH);
+ m_Capabilities.HCIVersion = READ_REGISTER_USHORT((PUSHORT)((ULONG)ResourceBase + EHCI_HCIVERSION));
+ m_Capabilities.HCSParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + EHCI_HCSPARAMS));
+ m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + EHCI_HCCPARAMS));
DPRINT1("Controller has %d Length\n", m_Capabilities.Length);
DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount);
DPRINT1("Controller EHCI Version %x\n", m_Capabilities.HCIVersion);
- DPRINT1("Controler EHCI Caps HCSParamsLong %x\n", m_Capabilities.HCSParamsLong);
- DPRINT1("Controler EHCI Caps HCCParamsLong %x\n", m_Capabilities.HCCParamsLong);
+ DPRINT1("Controler EHCI Caps HCSParamsLong %x\n", m_Capabilities.HCSParamsLong);
+ DPRINT1("Controler EHCI Caps HCCParamsLong %x\n", m_Capabilities.HCCParamsLong);
+ DPRINT1("Controler EHCI Caps PowerControl %x\n", m_Capabilities.HCSParams.PortPowerControl);
- DPRINT1("Controler EHCI Caps PowerControl %x\n", m_Capabilities.HCSParams.PortPowerControl);
if (m_Capabilities.HCSParams.PortRouteRules)
{
- for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++)
+ Count = 0;
+ PortCount = max(m_Capabilities.HCSParams.PortCount/2, (m_Capabilities.HCSParams.PortCount+1)/2);
+ do
{
- m_Capabilities.PortRoute[Count] = READ_REGISTER_UCHAR((PUCHAR)(ULONG)ResourceBase + 12 + Count);
- }
+ //
+ // each entry is a 4 bit field EHCI 2.2.5
+ //
+ Value = READ_REGISTER_UCHAR((PUCHAR)(ULONG)ResourceBase + EHCI_HCSP_PORTROUTE + Count);
+ m_Capabilities.PortRoute[Count*2] = (Value & 0xF0);
+
+ if ((Count*2) + 1 < m_Capabilities.HCSParams.PortCount)
+ m_Capabilities.PortRoute[(Count*2)+1] = (Value & 0x0F);
+
+ Count++;
+ }while(Count < PortCount);
}
//
CUSBHardwareDevice::StartController(void)
{
EHCI_USBCMD_CONTENT UsbCmd;
- ULONG UsbSts, FailSafe;
+ ULONG UsbSts, FailSafe, ExtendedCapsSupport, Caps, Index;
+ UCHAR Value;
+ LARGE_INTEGER Timeout;
//
// check caps
EHCI_WRITE_REGISTER_ULONG(EHCI_CTRLDSSEGMENT, 0x0);
}
+ //
+ // are extended caps supported
+ //
+ ExtendedCapsSupport = (m_Capabilities.HCCParamsLong >> EHCI_ECP_SHIFT) & EHCI_ECP_MASK;
+ if (ExtendedCapsSupport)
+ {
+ DPRINT1("[EHCI] Extended Caps Support detected!\n");
+
+ //
+ // sanity check
+ //
+ ASSERT(ExtendedCapsSupport >= PCI_COMMON_HDR_LENGTH);
+ m_BusInterface.GetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &Caps, ExtendedCapsSupport, sizeof(ULONG));
+
+ //
+ // OS Handoff Synchronization support capability. EHCI 5.1
+ //
+ if ((Caps & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID)
+ {
+ //
+ // is it bios owned
+ //
+ if ((Caps & EHCI_LEGSUP_BIOSOWNED))
+ {
+ DPRINT1("[EHCI] Controller is BIOS owned, acquring control\n");
+
+ //
+ // acquire ownership
+ //
+ Value = 1;
+ m_BusInterface.SetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &Value, ExtendedCapsSupport+3, sizeof(UCHAR));
+
+ for(Index = 0; Index < 20; Index++)
+ {
+ //
+ // get status
+ //
+ m_BusInterface.GetBusData(m_BusInterface.Context, PCI_WHICHSPACE_CONFIG, &Caps, ExtendedCapsSupport, sizeof(ULONG));
+ if ((Caps & EHCI_LEGSUP_BIOSOWNED))
+ {
+ //
+ // lets wait a bit
+ //
+ Timeout.QuadPart = 50;
+ DPRINT1("Waiting %d milliseconds for port reset\n", Timeout.LowPart);
+
+ //
+ // convert to 100 ns units (absolute)
+ //
+ Timeout.QuadPart *= -10000;
+
+ //
+ // perform the wait
+ //
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+ }
+ }
+ if ((Caps & EHCI_LEGSUP_BIOSOWNED))
+ {
+ //
+ // failed to aquire ownership
+ //
+ DPRINT1("[EHCI] failed to acquire ownership\n");
+ }
+ else if ((Caps & EHCI_LEGSUP_OSOWNED))
+ {
+ //
+ // HC OS Owned Semaphore EHCI 2.1.8
+ //
+ DPRINT1("[EHCI] acquired ownership\n");
+ }
+ }
+ }
+ }
+
+
#if 1
//
//
EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1);
-
-
-
DPRINT1("EHCI Started!\n");
return STATUS_SUCCESS;
}
IN ULONG PortIndex)
{
ULONG PortStatus;
+ LARGE_INTEGER Timeout;
if (PortIndex > m_Capabilities.HCSParams.PortCount)
return STATUS_UNSUCCESSFUL;
PortStatus &= ~EHCI_PRT_ENABLED;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus);
- KeStallExecutionProcessor(100);
+ //
+ // delay is 20 ms for port reset as per USB 2.0 spec
+ //
+ Timeout.QuadPart = 20;
+ DPRINT1("Waiting %d milliseconds for port reset\n", Timeout.LowPart);
+
+ //
+ // convert to 100 ns units (absolute)
+ //
+ Timeout.QuadPart *= -10000;
+
+ //
+ // perform the wait
+ //
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
//
// Clear reset
break;
} while (TRUE);
+ //
+ // delay is 10 ms
+ //
+ Timeout.QuadPart = 10;
+ DPRINT1("Waiting %d milliseconds for port to recover after reset\n", Timeout.LowPart);
+
+ //
+ // convert to 100 ns units (absolute)
+ //
+ Timeout.QuadPart *= -10000;
+
+ //
+ // perform the wait
+ //
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+
//
// check slow speed line after reset
//
+ PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
{
DPRINT1("Non HighSpeed device. Releasing Ownership\n");
if (Status == C_PORT_CONNECTION)
{
+ LARGE_INTEGER Timeout;
+
+ //
+ // reset status change bits
+ //
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
Value |= EHCI_PRT_CONNECTSTATUSCHANGE | EHCI_PRT_ENABLEDSTATUSCHANGE;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
+
+ //
+ // delay is 100 ms
+ //
+ Timeout.QuadPart = 100;
+ DPRINT1("Waiting %d milliseconds for port to stabilize after connection\n", Timeout.LowPart);
+
+ //
+ // convert to 100 ns units (absolute)
+ //
+ Timeout.QuadPart *= -10000;
+
+ //
+ // perform the wait
+ //
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
}
return STATUS_SUCCESS;
{
if (m_Capabilities.HCSParams.PortPowerControl)
{
+ ULONG Value;
+ LARGE_INTEGER Timeout;
+
//
// enable port power
//
- ULONG Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId)) | EHCI_PRT_POWER;
+ Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId)) | EHCI_PRT_POWER;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC, Value);
+
+ //
+ // delay is 20 ms
+ //
+ Timeout.QuadPart = 20;
+ DPRINT1("Waiting %d milliseconds for port power up\n", Timeout.LowPart);
+
+ //
+ // convert to 100 ns units (absolute)
+ //
+ Timeout.QuadPart *= -10000;
+
+ //
+ // perform the wait
+ //
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
}
}
return STATUS_SUCCESS;
This = (CUSBHardwareDevice*) SystemArgument1;
CStatus = (ULONG) SystemArgument2;
- DPRINT1("CStatus %x\n", CStatus);
+ DPRINT("CStatus %x\n", CStatus);
//
// check for completion of async schedule