[ros-diffs] [cgutman] 55948: [USBOHCI] - Add a OHCI reset hack based on Linux code

cgutman at svn.reactos.org cgutman at svn.reactos.org
Thu Mar 1 18:05:59 UTC 2012


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/hardware.cpp?rev=55948&r1=55947&r2=55948&view=diff
==============================================================================
--- 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;
 }
 




More information about the Ros-diffs mailing list