[USBOHCI]
[reactos.git] / drivers / usb / usbohci / hardware.cpp
index 32da72c..8d8de64 100644 (file)
@@ -884,16 +884,18 @@ CUSBHardwareDevice::StopController(void)
     ULONG Index, FrameInterval;
 
     //
-    // first turn off all interrupts
+    // alignment check
     //
-    WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_DISABLE_OFFSET), OHCI_ALL_INTERRUPTS);
+    WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET, 0xFFFFFFFF);
+    Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET));
+    DPRINT1("HcHCCA Alignment %x\n", Control);
+    ASSERT((Control & 0xFFFFFFF0) == 0xFFFFFFF0);
 
     //
     // check context
     //
     Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
 
-
     if ((Control & OHCI_INTERRUPT_ROUTING))
     {
         //
@@ -931,34 +933,107 @@ CUSBHardwareDevice::StopController(void)
         if (Control & OHCI_INTERRUPT_ROUTING)
         {
             DPRINT1("SMM not responding\n");
+        }
+        else
+        {
+            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);
+        DPRINT1("Controller State %x\n", Control);
+
+        if (Control != OHCI_HC_FUNCTIONAL_STATE_RESET)
+        {
             //
-            // some controllers also depend on this
+            // OHCI 5.1.1.3.4, no SMM, BIOS active
             //
-            WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
+            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);
+            }
+        }
+        else
+        {
             //
-            // wait a bit
+            // 5.1.1.3.5 OHCI, no SMM, no BIOS
             //
-            KeStallExecutionProcessor(100);
+            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);
         }
     }
 
-
-    //
-    // have a break
-    //
-    KeStallExecutionProcessor(100);
-
-    //
-    // some controllers also depend on this
-    //
-    WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
-
-    //
-    // wait a bit
-    //
-    KeStallExecutionProcessor(100);
-
     //
     // read from interval
     //
@@ -996,6 +1071,11 @@ CUSBHardwareDevice::StopController(void)
         //
         if ((Reset & OHCI_HOST_CONTROLLER_RESET) == 0)
         {
+            //
+            // restore the frame interval register
+            //
+            WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET), FrameInterval);
+
             //
             // controller completed reset
             //
@@ -1031,11 +1111,54 @@ CUSBHardwareDevice::GetPortStatus(
     OUT USHORT *PortStatus,
     OUT USHORT *PortChange)
 {
+    ULONG Value;
+
+    if (PortId > m_NumberOfPorts)
+        return STATUS_UNSUCCESSFUL;
+
+    // init result variables
+    *PortStatus = 0;
+    *PortChange = 0;
+
     //
-    // FIXME: should read status from hardware
+    // read port status
     //
-    *PortStatus = m_PortStatus[PortId].PortStatus;
-    *PortChange = m_PortStatus[PortId].PortChange;
+    Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
+    DPRINT("GetPortStatus PortId %x Value %x\n", PortId, Value);
+
+
+    // connected
+    if (Value & OHCI_RH_PORTSTATUS_CCS)
+        *PortStatus |= USB_PORT_STATUS_CONNECT;
+
+    // did a device connect?
+    if (Value & OHCI_RH_PORTSTATUS_CSC)
+        *PortChange |= USB_PORT_STATUS_CONNECT;
+
+    // port enabled
+    if (Value & OHCI_RH_PORTSTATUS_PES)
+        *PortStatus |= USB_PORT_STATUS_ENABLE;
+
+    // port enabled
+    if (Value & OHCI_RH_PORTSTATUS_PESC)
+        *PortChange |= USB_PORT_STATUS_ENABLE;
+
+    // port suspend
+    if (Value & OHCI_RH_PORTSTATUS_PSS)
+        *PortStatus |= USB_PORT_STATUS_SUSPEND;
+
+    // port suspend
+    if (Value & OHCI_RH_PORTSTATUS_PSSC)
+        *PortChange |= USB_PORT_STATUS_ENABLE;
+
+    // port reset
+    if (Value & OHCI_RH_PORTSTATUS_PSS)
+        *PortStatus |= USB_PORT_STATUS_RESET;
+
+    // port reset
+    if (Value & OHCI_RH_PORTSTATUS_PRSC)
+        *PortChange |= USB_PORT_STATUS_RESET;
+
     return STATUS_SUCCESS;
 }