Author: cgutman
Date: Thu Mar 1 18:05:59 2012
New Revision: 55948
URL:
http://svn.reactos.org/svn/reactos?rev=55948&view=rev
Log:
[USBOHCI]
- Add a OHCI reset hack based on Linux code
Modified:
trunk/reactos/drivers/usb/usbohci/hardware.cpp
Modified: trunk/reactos/drivers/usb/usbohci/hardware.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbohci/hardwa…
==============================================================================
--- trunk/reactos/drivers/usb/usbohci/hardware.cpp [iso-8859-1] (original)
+++ trunk/reactos/drivers/usb/usbohci/hardware.cpp [iso-8859-1] Thu Mar 1 18:05:59 2012
@@ -367,18 +367,6 @@
return Status;
}
-
- //
- // Stop the controller before modifying schedules
- //
- Status = StopController();
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Failed to stop the controller \n");
- return Status;
- }
-
-
//
// Start the controller
//
@@ -468,381 +456,18 @@
NTSTATUS
CUSBHardwareDevice::StartController(void)
{
- ULONG Control, Descriptor, FrameInterval, Periodic, Port;
-
- //
- // lets write physical address of dummy control endpoint descriptor
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_HEAD_ED_OFFSET),
m_ControlEndpointDescriptor->PhysicalAddress.LowPart);
-
- //
- // lets write physical address of dummy bulk endpoint descriptor
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_BULK_HEAD_ED_OFFSET),
m_BulkEndpointDescriptor->PhysicalAddress.LowPart);
-
- //
- // read descriptor A
- //
- Descriptor = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_RH_DESCRIPTOR_A_OFFSET));
-
- //
- // get port count
- //
- m_NumberOfPorts = OHCI_RH_GET_PORT_COUNT(Descriptor);
- DPRINT1("NumberOfPorts %lu\n", m_NumberOfPorts);
- ASSERT(m_NumberOfPorts < OHCI_MAX_PORT_COUNT);
-
- //
- // no over current protection
- //
- Descriptor |= OHCI_RH_NO_OVER_CURRENT_PROTECTION;
-
- //
- // power switching on
- //
- Descriptor &= ~OHCI_RH_NO_POWER_SWITCHING;
-
- //
- // control each port power independently
- //
- Descriptor |= OHCI_RH_POWER_SWITCHING_MODE;
-
- //
- // write the configuration back
- //
- DPRINT1("Descriptor A: %x\n", Descriptor);
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_A_OFFSET),
Descriptor);
-
- //
- // read descriptor B
- //
- Descriptor = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_RH_DESCRIPTOR_B_OFFSET));
-
- //
- // set power power control for each port to use PPS
- //
- for (Port = 1; Port <= m_NumberOfPorts; Port++)
- {
- Descriptor |= (1 << (16 + Port));
- }
-
- //
- // write the configuration back
- //
- DPRINT1("Descriptor B: %x\n", Descriptor);
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_B_OFFSET),
Descriptor);
-
- //
- // get frame interval
- //
- FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_FRAME_INTERVAL_OFFSET));
- m_IntervalValue = OHCI_GET_INTERVAL_VALUE(FrameInterval);
-
- FrameInterval = ((FrameInterval & OHCI_FRAME_INTERVAL_TOGGLE) ^
OHCI_FRAME_INTERVAL_TOGGLE);
-
- DPRINT1("FrameInterval %x IntervalValue %x\n", FrameInterval,
m_IntervalValue);
- FrameInterval |= OHCI_FSMPS(m_IntervalValue) | m_IntervalValue;
- DPRINT1("FrameInterval %x\n", FrameInterval);
-
- //
- // write frame interval
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET),
FrameInterval);
-
- //
- // HCCA alignment check
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET), 0xFFFFFFFF);
- KeStallExecutionProcessor(10);
- Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET));
- ASSERT((m_HCCAPhysicalAddress.LowPart & Control) ==
m_HCCAPhysicalAddress.LowPart);
- DPRINT1("HCCA: %x Alignment mask: %x\n", m_HCCAPhysicalAddress.LowPart,
Control);
-
- //
- // write address of HCCA
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET),
m_HCCAPhysicalAddress.LowPart);
-
- //
- // now enable the interrupts
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_ENABLE_OFFSET),
OHCI_NORMAL_INTERRUPTS | OHCI_MASTER_INTERRUPT_ENABLE);
-
- //
- // enable all queues
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET),
OHCI_ENABLE_LIST);
-
- //
- // 90 % periodic
- //
- Periodic = OHCI_PERIODIC(m_IntervalValue);
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_PERIODIC_START_OFFSET),
Periodic);
- DPRINT("Periodic Start %x\n", Periodic);
-
- //
- // start the controller
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_ENABLE_LIST
| OHCI_CONTROL_BULK_RATIO_1_4 | OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL);
-
- //
- // wait a bit
- //
- KeStallExecutionProcessor(100);
-
- //
- // is the controller started
+ ULONG Control, Descriptor, FrameInterval, Periodic, Port, Reset, Index;
+ ULONG NewControl, WaitInMs;
+ LARGE_INTEGER Timeout;
+ BOOLEAN Again = FALSE;
+
+ //
+ // check context
//
Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
- //
- // assert that the controller has been started
- //
- ASSERT((Control & OHCI_HC_FUNCTIONAL_STATE_MASK) ==
OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL);
- ASSERT((Control & OHCI_ENABLE_LIST) == OHCI_ENABLE_LIST);
- DPRINT1("Control %x\n", Control);
-
- //
- // done
- //
- DPRINT1("OHCI controller is operational\n");
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-CUSBHardwareDevice::AllocateEndpointDescriptor(
- OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor)
-{
- POHCI_ENDPOINT_DESCRIPTOR Descriptor;
- PHYSICAL_ADDRESS DescriptorAddress;
- NTSTATUS Status;
-
- //
- // allocate descriptor
- //
- Status = m_MemoryManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR),
(PVOID*)&Descriptor, &DescriptorAddress);
- if (!NT_SUCCESS(Status))
- {
- //
- // failed to allocate descriptor
- //
- return Status;
- }
-
- //
- // intialize descriptor
- //
- Descriptor->Flags = OHCI_ENDPOINT_SKIP;
- Descriptor->HeadPhysicalDescriptor = 0;
- Descriptor->NextPhysicalEndpoint = 0;
- Descriptor->TailPhysicalDescriptor = 0;
- Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
-
- //
- // store result
- //
- *OutDescriptor = Descriptor;
-
- //
- // done
- //
- return STATUS_SUCCESS;
-}
-
-VOID
-STDMETHODCALLTYPE
-CUSBHardwareDevice::GetBulkHeadEndpointDescriptor(
- struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
-{
- *OutDescriptor = m_BulkEndpointDescriptor;
-}
-
-VOID
-STDMETHODCALLTYPE
-CUSBHardwareDevice::GetInterruptEndpointDescriptors(
- struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor)
-{
- *OutDescriptor = m_InterruptEndpoints;
-}
-
-VOID
-STDMETHODCALLTYPE
-CUSBHardwareDevice::GetIsochronousHeadEndpointDescriptor(
- struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
-{
- *OutDescriptor = m_IsoEndpointDescriptor;
-}
-
-VOID
-STDMETHODCALLTYPE
-CUSBHardwareDevice::HeadEndpointDescriptorModified(
- ULONG Type)
-{
- if (Type == USB_ENDPOINT_TYPE_CONTROL)
- {
- //
- // notify controller
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET),
OHCI_CONTROL_LIST_FILLED);
- }
- else if (Type == USB_ENDPOINT_TYPE_BULK)
- {
- //
- // notify controller
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET),
OHCI_BULK_LIST_FILLED);
- }
-}
-
-VOID
-STDMETHODCALLTYPE
-CUSBHardwareDevice::GetControlHeadEndpointDescriptor(
- struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
-{
- *OutDescriptor = m_ControlEndpointDescriptor;
-}
-
-NTSTATUS
-CUSBHardwareDevice::InitializeController()
-{
- NTSTATUS Status;
- ULONG Index, Interval, IntervalIndex, InsertIndex;
- POHCI_ENDPOINT_DESCRIPTOR Descriptor;
-
- //
- // first allocate the hcca area
- //
- Status = m_MemoryManager->Allocate(sizeof(OHCIHCCA), (PVOID*)&m_HCCA,
&m_HCCAPhysicalAddress);
- if (!NT_SUCCESS(Status))
- {
- //
- // no memory
- //
- return Status;
- }
-
- //
- // now allocate an endpoint for control transfers
- // this endpoint will never be removed
- //
- Status = AllocateEndpointDescriptor(&m_ControlEndpointDescriptor);
- if (!NT_SUCCESS(Status))
- {
- //
- // no memory
- //
- return Status;
- }
-
- //
- // now allocate an endpoint for bulk transfers
- // this endpoint will never be removed
- //
- Status = AllocateEndpointDescriptor(&m_BulkEndpointDescriptor);
- if (!NT_SUCCESS(Status))
- {
- //
- // no memory
- //
- return Status;
- }
-
- //
- // now allocate an endpoint for iso transfers
- // this endpoint will never be removed
- //
- Status = AllocateEndpointDescriptor(&m_IsoEndpointDescriptor);
- if (!NT_SUCCESS(Status))
- {
- //
- // no memory
- //
- return Status;
- }
-
- //
- // now allocate endpoint descriptors for iso / interrupt transfers interval is
1,2,4,8,16,32
- //
- for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
- {
- //
- // allocate endpoint descriptor
- //
- Status = AllocateEndpointDescriptor(&Descriptor);
- if (!NT_SUCCESS(Status))
- {
- //
- // no memory
- //
- return Status;
- }
-
- //
- // save in array
- //
- m_InterruptEndpoints[Index] = Descriptor;
- }
-
-
- //
- // now link the descriptors, taken from Haiku
- //
- Interval = OHCI_BIGGEST_INTERVAL;
- IntervalIndex = OHCI_STATIC_ENDPOINT_COUNT - 1;
- while (Interval > 1)
- {
- InsertIndex = Interval / 2;
- while (InsertIndex < OHCI_BIGGEST_INTERVAL)
- {
- //
- // assign endpoint address
- //
- m_HCCA->InterruptTable[InsertIndex] =
m_InterruptEndpoints[IntervalIndex]->PhysicalAddress.LowPart;
- InsertIndex += Interval;
- }
-
- IntervalIndex--;
- Interval /= 2;
- }
-
- //
- // link all endpoint descriptors to first descriptor in array
- //
- m_HCCA->InterruptTable[0] = m_InterruptEndpoints[0]->PhysicalAddress.LowPart;
- for (Index = 1; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
- {
- //
- // link descriptor
- //
- m_InterruptEndpoints[Index]->NextPhysicalEndpoint =
m_InterruptEndpoints[0]->PhysicalAddress.LowPart;
- }
-
- //
- // Now link the first endpoint to the isochronous endpoint
- //
- m_InterruptEndpoints[0]->NextPhysicalEndpoint =
m_IsoEndpointDescriptor->PhysicalAddress.LowPart;
-
- //
- // set iso endpoint type
- //
- m_IsoEndpointDescriptor->Flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
-
- //
- // done
- //
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-CUSBHardwareDevice::StopController(void)
-{
- ULONG Control, Reset;
- ULONG Index, FrameInterval;
-
- //
- // check context
- //
- Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
+ //Save this
+ NewControl = Control & OHCI_REMOTE_WAKEUP_CONNECTED;
if ((Control & OHCI_INTERRUPT_ROUTING))
{
@@ -879,151 +504,495 @@
}
else
{
- DPRINT("SMM has given up ownership\n");
+ DPRINT1("SMM has given up ownership\n");
}
}
- else
- {
- //
- // read contents of control register
- //
- Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET))
& OHCI_HC_FUNCTIONAL_STATE_MASK);
- DPRINT("Controller State %x\n", Control);
-
- if (Control != OHCI_HC_FUNCTIONAL_STATE_RESET)
+
+ //
+ // read contents of control register
+ //
+
+ Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET)) &
OHCI_HC_FUNCTIONAL_STATE_MASK);
+ DPRINT1("Controller State %x\n", Control);
+
+ switch (Control)
+ {
+ case OHCI_HC_FUNCTIONAL_STATE_RESET:
+ NewControl |= OHCI_HC_FUNCTIONAL_STATE_RESET;
+ WaitInMs = 50;
+ break;
+
+ case OHCI_HC_FUNCTIONAL_STATE_SUSPEND:
+ case OHCI_HC_FUNCTIONAL_STATE_RESUME:
+ NewControl |= OHCI_HC_FUNCTIONAL_STATE_RESUME;
+ WaitInMs = 10;
+ break;
+
+ default:
+ WaitInMs = 0;
+ break;
+ }
+
+retry:
+ if (WaitInMs != 0)
+ {
+ // Do the state transition
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET),
NewControl);
+
+ if (!Again)
{
//
- // OHCI 5.1.1.3.4, no SMM, BIOS active
- //
- if (Control != OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL)
- {
- //
- // lets resume
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET),
OHCI_HC_FUNCTIONAL_STATE_RESUME);
- Index = 0;
- do
- {
- //
- // wait untill its resumed
- //
- KeStallExecutionProcessor(10);
-
- //
- // check control register
- //
- Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_CONTROL_OFFSET)) & OHCI_HC_FUNCTIONAL_STATE_MASK);
- if (Control == OHCI_HC_FUNCTIONAL_STATE_RESUME)
- {
- //
- // it has resumed
- //
- break;
- }
-
- //
- // check for time outs
- //
- Index++;
- if(Index > 100)
- {
- DPRINT1("Failed to resume controller\n");
- break;
- }
- }while(TRUE);
- }
+ // delay is 100 ms
+ //
+ Timeout.QuadPart = WaitInMs;
+ DPRINT1("Waiting %d milliseconds for controller to transition
state\n", Timeout.LowPart);
+
+ //
+ // convert to 100 ns units (absolute)
+ //
+ Timeout.QuadPart *= -10000;
+
+ //
+ // perform the wait
+ //
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+ }
+ }
+
+ //
+ // now reset controller
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET),
OHCI_HOST_CONTROLLER_RESET);
+
+ //
+ // reset time is 10ms
+ //
+ for(Index = 0; Index < 100; Index++)
+ {
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(10);
+
+ //
+ // read command status
+ //
+ Reset = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_COMMAND_STATUS_OFFSET));
+
+ //
+ // was reset bit cleared
+ //
+ if ((Reset & OHCI_HOST_CONTROLLER_RESET) == 0)
+ {
+ //
+ // controller completed reset
+ //
+ break;
+ }
+ }
+
+ if ((Reset & OHCI_HOST_CONTROLLER_RESET))
+ {
+ //
+ // failed to reset controller
+ //
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // get frame interval
+ //
+ FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_FRAME_INTERVAL_OFFSET));
+ m_IntervalValue = OHCI_GET_INTERVAL_VALUE(FrameInterval);
+
+ FrameInterval = ((FrameInterval & OHCI_FRAME_INTERVAL_TOGGLE) ^
OHCI_FRAME_INTERVAL_TOGGLE);
+
+ DPRINT1("FrameInterval %x IntervalValue %x\n", FrameInterval,
m_IntervalValue);
+ FrameInterval |= OHCI_FSMPS(m_IntervalValue) | m_IntervalValue;
+ DPRINT1("Computed FrameInterval %x\n", FrameInterval);
+
+ //
+ // write frame interval
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET),
FrameInterval);
+
+ FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_FRAME_INTERVAL_OFFSET));
+ DPRINT1("Read FrameInterval %x\n", FrameInterval);
+
+ //
+ // 90 % periodic
+ //
+ Periodic = OHCI_PERIODIC(m_IntervalValue);
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_PERIODIC_START_OFFSET),
Periodic);
+ DPRINT1("Computed Periodic Start %x\n", Periodic);
+
+ Periodic = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_PERIODIC_START_OFFSET));
+ DPRINT1("Read Periodic Start %x\n", Periodic);
+
+ // Linux does this hack for some bad controllers
+ if (!(FrameInterval & 0x3FFF0000) ||
+ !(Periodic))
+ {
+ if (!Again)
+ {
+ DPRINT1("Trying reset again on faulty controller\n");
+ Again = TRUE;
+ goto retry;
}
else
{
- //
- // 5.1.1.3.5 OHCI, no SMM, no BIOS
- //
- Index = 0;
-
- //
- // some controllers also depend on this
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET),
OHCI_HC_FUNCTIONAL_STATE_RESET);
- do
- {
- //
- // wait untill its reset
- //
- KeStallExecutionProcessor(10);
-
- //
- // check control register
- //
- Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_CONTROL_OFFSET)) & OHCI_HC_FUNCTIONAL_STATE_MASK);
- if (Control == OHCI_HC_FUNCTIONAL_STATE_RESET)
- {
- //
- // it has reset
- //
- break;
- }
-
- //
- // check for time outs
- //
- Index++;
- if(Index > 100)
- {
- DPRINT1("Failed to reset controller\n");
- break;
- }
-
- }while(TRUE);
+ DPRINT1("Second reset didn't solve the problem, failing\n");
+ return STATUS_UNSUCCESSFUL;
}
}
//
- // read from interval
- //
- FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_FRAME_INTERVAL_OFFSET));
-
- //
- // store interval value for later
- //
- m_IntervalValue = OHCI_GET_INTERVAL_VALUE(FrameInterval);
-
- DPRINT1("FrameInterval %x Interval %x\n", FrameInterval, m_IntervalValue);
-
- //
- // now reset controller
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET),
OHCI_HOST_CONTROLLER_RESET);
-
- //
- // reset time is 10ms
- //
- for(Index = 0; Index < 100; Index++)
- {
- //
- // wait a bit
- //
- KeStallExecutionProcessor(10);
-
- //
- // read command status
- //
- Reset = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_COMMAND_STATUS_OFFSET));
-
- //
- // was reset bit cleared
- //
- if ((Reset & OHCI_HOST_CONTROLLER_RESET) == 0)
+ // lets write physical address of dummy control endpoint descriptor
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_HEAD_ED_OFFSET),
m_ControlEndpointDescriptor->PhysicalAddress.LowPart);
+
+ //
+ // lets write physical address of dummy bulk endpoint descriptor
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_BULK_HEAD_ED_OFFSET),
m_BulkEndpointDescriptor->PhysicalAddress.LowPart);
+
+ //
+ // read descriptor A
+ //
+ Descriptor = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_RH_DESCRIPTOR_A_OFFSET));
+
+ //
+ // get port count
+ //
+ m_NumberOfPorts = OHCI_RH_GET_PORT_COUNT(Descriptor);
+ DPRINT1("NumberOfPorts %lu\n", m_NumberOfPorts);
+ ASSERT(m_NumberOfPorts < OHCI_MAX_PORT_COUNT);
+
+ //
+ // no over current protection
+ //
+ Descriptor |= OHCI_RH_NO_OVER_CURRENT_PROTECTION;
+
+ //
+ // power switching on
+ //
+ Descriptor &= ~OHCI_RH_NO_POWER_SWITCHING;
+
+ //
+ // control each port power independently
+ //
+ Descriptor |= OHCI_RH_POWER_SWITCHING_MODE;
+
+ //
+ // write the configuration back
+ //
+ DPRINT1("Descriptor A: %x\n", Descriptor);
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_A_OFFSET),
Descriptor);
+
+ //
+ // read descriptor B
+ //
+ Descriptor = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base +
OHCI_RH_DESCRIPTOR_B_OFFSET));
+
+ //
+ // set power power control for each port to use PPS
+ //
+ for (Port = 1; Port <= m_NumberOfPorts; Port++)
+ {
+ Descriptor |= (1 << (16 + Port));
+ }
+
+ //
+ // write the configuration back
+ //
+ DPRINT1("Descriptor B: %x\n", Descriptor);
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_DESCRIPTOR_B_OFFSET),
Descriptor);
+
+ //
+ // HCCA alignment check
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET), 0xFFFFFFFF);
+ KeStallExecutionProcessor(10);
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET));
+ ASSERT((m_HCCAPhysicalAddress.LowPart & Control) ==
m_HCCAPhysicalAddress.LowPart);
+ DPRINT1("HCCA: %x Alignment mask: %x\n", m_HCCAPhysicalAddress.LowPart,
Control);
+
+ //
+ // write address of HCCA
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET),
m_HCCAPhysicalAddress.LowPart);
+
+ //
+ // now enable the interrupts
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_ENABLE_OFFSET),
OHCI_NORMAL_INTERRUPTS | OHCI_MASTER_INTERRUPT_ENABLE);
+
+ //
+ // enable all queues
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), (NewControl
& OHCI_REMOTE_WAKEUP_CONNECTED) | OHCI_ENABLE_LIST);
+
+ //
+ // start the controller
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_ENABLE_LIST
|
+ (NewControl
& OHCI_REMOTE_WAKEUP_CONNECTED) |
+
OHCI_CONTROL_BULK_RATIO_1_4 |
+
OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL);
+
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(100);
+
+ //
+ // is the controller started
+ //
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
+
+ //
+ // assert that the controller has been started
+ //
+ ASSERT((Control & OHCI_HC_FUNCTIONAL_STATE_MASK) ==
OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL);
+ ASSERT((Control & OHCI_ENABLE_LIST) == OHCI_ENABLE_LIST);
+ DPRINT1("Control %x\n", Control);
+
+ //
+ // done
+ //
+ DPRINT1("OHCI controller is operational\n");
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CUSBHardwareDevice::AllocateEndpointDescriptor(
+ OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor)
+{
+ POHCI_ENDPOINT_DESCRIPTOR Descriptor;
+ PHYSICAL_ADDRESS DescriptorAddress;
+ NTSTATUS Status;
+
+ //
+ // allocate descriptor
+ //
+ Status = m_MemoryManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR),
(PVOID*)&Descriptor, &DescriptorAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed to allocate descriptor
+ //
+ return Status;
+ }
+
+ //
+ // intialize descriptor
+ //
+ Descriptor->Flags = OHCI_ENDPOINT_SKIP;
+ Descriptor->HeadPhysicalDescriptor = 0;
+ Descriptor->NextPhysicalEndpoint = 0;
+ Descriptor->TailPhysicalDescriptor = 0;
+ Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
+
+ //
+ // store result
+ //
+ *OutDescriptor = Descriptor;
+
+ //
+ // done
+ //
+ return STATUS_SUCCESS;
+}
+
+VOID
+STDMETHODCALLTYPE
+CUSBHardwareDevice::GetBulkHeadEndpointDescriptor(
+ struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
+{
+ *OutDescriptor = m_BulkEndpointDescriptor;
+}
+
+VOID
+STDMETHODCALLTYPE
+CUSBHardwareDevice::GetInterruptEndpointDescriptors(
+ struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor)
+{
+ *OutDescriptor = m_InterruptEndpoints;
+}
+
+VOID
+STDMETHODCALLTYPE
+CUSBHardwareDevice::GetIsochronousHeadEndpointDescriptor(
+ struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
+{
+ *OutDescriptor = m_IsoEndpointDescriptor;
+}
+
+VOID
+STDMETHODCALLTYPE
+CUSBHardwareDevice::HeadEndpointDescriptorModified(
+ ULONG Type)
+{
+ if (Type == USB_ENDPOINT_TYPE_CONTROL)
+ {
+ //
+ // notify controller
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET),
OHCI_CONTROL_LIST_FILLED);
+ }
+ else if (Type == USB_ENDPOINT_TYPE_BULK)
+ {
+ //
+ // notify controller
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET),
OHCI_BULK_LIST_FILLED);
+ }
+}
+
+VOID
+STDMETHODCALLTYPE
+CUSBHardwareDevice::GetControlHeadEndpointDescriptor(
+ struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
+{
+ *OutDescriptor = m_ControlEndpointDescriptor;
+}
+
+NTSTATUS
+CUSBHardwareDevice::InitializeController()
+{
+ NTSTATUS Status;
+ ULONG Index, Interval, IntervalIndex, InsertIndex;
+ POHCI_ENDPOINT_DESCRIPTOR Descriptor;
+
+ //
+ // first allocate the hcca area
+ //
+ Status = m_MemoryManager->Allocate(sizeof(OHCIHCCA), (PVOID*)&m_HCCA,
&m_HCCAPhysicalAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // no memory
+ //
+ return Status;
+ }
+
+ //
+ // now allocate an endpoint for control transfers
+ // this endpoint will never be removed
+ //
+ Status = AllocateEndpointDescriptor(&m_ControlEndpointDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // no memory
+ //
+ return Status;
+ }
+
+ //
+ // now allocate an endpoint for bulk transfers
+ // this endpoint will never be removed
+ //
+ Status = AllocateEndpointDescriptor(&m_BulkEndpointDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // no memory
+ //
+ return Status;
+ }
+
+ //
+ // now allocate an endpoint for iso transfers
+ // this endpoint will never be removed
+ //
+ Status = AllocateEndpointDescriptor(&m_IsoEndpointDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // no memory
+ //
+ return Status;
+ }
+
+ //
+ // now allocate endpoint descriptors for iso / interrupt transfers interval is
1,2,4,8,16,32
+ //
+ for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
+ {
+ //
+ // allocate endpoint descriptor
+ //
+ Status = AllocateEndpointDescriptor(&Descriptor);
+ if (!NT_SUCCESS(Status))
{
//
- // controller completed reset
- //
- return STATUS_SUCCESS;
+ // no memory
+ //
+ return Status;
}
- }
-
- //
- // failed to reset controller
- //
+
+ //
+ // save in array
+ //
+ m_InterruptEndpoints[Index] = Descriptor;
+ }
+
+
+ //
+ // now link the descriptors, taken from Haiku
+ //
+ Interval = OHCI_BIGGEST_INTERVAL;
+ IntervalIndex = OHCI_STATIC_ENDPOINT_COUNT - 1;
+ while (Interval > 1)
+ {
+ InsertIndex = Interval / 2;
+ while (InsertIndex < OHCI_BIGGEST_INTERVAL)
+ {
+ //
+ // assign endpoint address
+ //
+ m_HCCA->InterruptTable[InsertIndex] =
m_InterruptEndpoints[IntervalIndex]->PhysicalAddress.LowPart;
+ InsertIndex += Interval;
+ }
+
+ IntervalIndex--;
+ Interval /= 2;
+ }
+
+ //
+ // link all endpoint descriptors to first descriptor in array
+ //
+ m_HCCA->InterruptTable[0] = m_InterruptEndpoints[0]->PhysicalAddress.LowPart;
+ for (Index = 1; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
+ {
+ //
+ // link descriptor
+ //
+ m_InterruptEndpoints[Index]->NextPhysicalEndpoint =
m_InterruptEndpoints[0]->PhysicalAddress.LowPart;
+ }
+
+ //
+ // Now link the first endpoint to the isochronous endpoint
+ //
+ m_InterruptEndpoints[0]->NextPhysicalEndpoint =
m_IsoEndpointDescriptor->PhysicalAddress.LowPart;
+
+ //
+ // set iso endpoint type
+ //
+ m_IsoEndpointDescriptor->Flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
+
+ //
+ // done
+ //
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CUSBHardwareDevice::StopController(void)
+{
+ ASSERT(FALSE);
+
return STATUS_UNSUCCESSFUL;
}