[USBEHCI]
[reactos.git] / drivers / usb / usbehci_new / hardware.cpp
index c62e81b..804b133 100644 (file)
@@ -114,9 +114,9 @@ protected:
     HD_INIT_CALLBACK* m_SCECallBack;                                                   // status change callback routine
     PVOID m_SCEContext;                                                                // status change callback routine context
     BOOLEAN m_DoorBellRingInProgress;                                                  // door bell ring in progress
-    EHCI_PORT_STATUS m_PortStatus[16];                                                 // port status
     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
 
     // set command
     VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
@@ -438,7 +438,7 @@ CUSBHardwareDevice::PnpStart(
     //
     // Initialize the UsbQueue now that we have an AdapterObject.
     //
-    Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, NULL);
+    Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, &m_Lock);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to Initialize the UsbQueue\n");
@@ -525,39 +525,10 @@ CUSBHardwareDevice::StartController(void)
         StopController();
 
     //
-    // Reset the device. Bit is set to 0 on completion.
-    //
-    GetCommandRegister(&UsbCmd);
-    UsbCmd.HCReset = TRUE;
-    SetCommandRegister(&UsbCmd);
-
-    //
-    // Check that the controller reset
-    //
-    for (FailSafe = 100; FailSafe > 1; FailSafe--)
-    {
-        KeStallExecutionProcessor(10);
-        GetCommandRegister(&UsbCmd);
-        if (!UsbCmd.HCReset)
-        {
-            break;
-        }
-    }
-
-    //
-    // If the controller did not reset then fail
-    //
-    if (UsbCmd.HCReset)
-    {
-        DPRINT1("EHCI ERROR: Controller failed to reset. Hardware problem!\n");
-        return STATUS_UNSUCCESSFUL;
-    }
-
-    //
-    // Disable Interrupts and clear status
+    // Enable Interrupts and start execution
     //
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, 0);
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBSTS, 0x0000001f);
+    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
+        /*| EHCI_USBINTR_FLROVR*/  | EHCI_USBINTR_PC);
 
     //
     // Assign the AsyncList Register
@@ -574,18 +545,10 @@ CUSBHardwareDevice::StartController(void)
     //
     GetCommandRegister(&UsbCmd);
     UsbCmd.PeriodicEnable = TRUE;
-    UsbCmd.AsyncEnable = TRUE;  //FIXME: Need USB Memory Manager
-
     UsbCmd.IntThreshold = 1;
-    // FIXME: Set framelistsize when periodic is implemented.
     SetCommandRegister(&UsbCmd);
 
-    //
-    // Enable Interrupts and start execution
-    //
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
-        /*| EHCI_USBINTR_FLROVR*/  | EHCI_USBINTR_PC);
-
+    GetCommandRegister(&UsbCmd);
     UsbCmd.Run = TRUE;
     SetCommandRegister(&UsbCmd);
 
@@ -614,6 +577,14 @@ CUSBHardwareDevice::StartController(void)
     //
     EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1);
 
+    //
+    // Enable async
+    //
+    GetCommandRegister(&UsbCmd);
+    UsbCmd.AsyncEnable = TRUE;  //FIXME: Need USB Memory Manager
+    // FIXME: Set framelistsize when periodic is implemented.
+    SetCommandRegister(&UsbCmd);
+
     DPRINT1("EHCI Started!\n");
     return STATUS_SUCCESS;
 }
@@ -669,6 +640,9 @@ CUSBHardwareDevice::ResetPort(
         return STATUS_UNSUCCESSFUL;
 
     PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
+    //
+    // check slow speed line before reset
+    //
     if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
     {
         DPRINT1("Non HighSpeed device. Releasing Ownership\n");
@@ -676,6 +650,8 @@ CUSBHardwareDevice::ResetPort(
         return STATUS_DEVICE_NOT_CONNECTED;
     }
 
+    ASSERT(PortStatus & EHCI_PRT_CONNECTED);
+
     //
     // Reset and clean enable
     //
@@ -692,18 +668,36 @@ CUSBHardwareDevice::ResetPort(
     PortStatus &= ~EHCI_PRT_RESET;
     EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), PortStatus);
 
-    KeStallExecutionProcessor(100);
+    do
+    {
+        //
+        // wait
+        //
+        KeStallExecutionProcessor(100);
+
+        //
+        // Check that the port reset
+        //
+        PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
+        if (!(PortStatus & EHCI_PRT_RESET))
+            break;
+    } while (TRUE);
 
     //
-    // Check that the port reset
+    // check slow speed line after reset
     //
-    PortStatus = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex));
-    if (PortStatus & EHCI_PRT_RESET)
+    if (PortStatus & EHCI_PRT_SLOWSPEEDLINE)
     {
-        DPRINT1("Port did not reset\n");
-        return STATUS_RETRY;
+        DPRINT1("Non HighSpeed device. Releasing Ownership\n");
+        EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortIndex), EHCI_PRT_RELEASEOWNERSHIP);
+        return STATUS_DEVICE_NOT_CONNECTED;
     }
 
+    //
+    // this must be enabled now
+    //
+    ASSERT(PortStatus & EHCI_PRT_ENABLED);
+
     return STATUS_SUCCESS;
 }
 
@@ -713,7 +707,6 @@ CUSBHardwareDevice::GetPortStatus(
     OUT USHORT *PortStatus,
     OUT USHORT *PortChange)
 {
-#if 0
     ULONG Value;
     USHORT Status = 0, Change = 0;
 
@@ -740,16 +733,18 @@ CUSBHardwareDevice::GetPortStatus(
         }
     }
 
-    // Get Speed. If SlowSpeedLine flag is there then its a slow speed device
-    if (Value & EHCI_PRT_SLOWSPEEDLINE)
-        Status |= USB_PORT_STATUS_LOW_SPEED;
-    else
-        Status |= USB_PORT_STATUS_HIGH_SPEED;
-
     // Get Connected Status
     if (Value & EHCI_PRT_CONNECTED)
+    {
         Status |= USB_PORT_STATUS_CONNECT;
 
+        // Get Speed. If SlowSpeedLine flag is there then its a slow speed device
+        if (Value & EHCI_PRT_SLOWSPEEDLINE)
+            Status |= USB_PORT_STATUS_LOW_SPEED;
+        else
+            Status |= USB_PORT_STATUS_HIGH_SPEED;
+    }
+
     // Get Enabled Status
     if (Value & EHCI_PRT_ENABLED)
         Status |= USB_PORT_STATUS_ENABLE;
@@ -763,8 +758,11 @@ CUSBHardwareDevice::GetPortStatus(
         Status |= USB_PORT_STATUS_OVER_CURRENT;
 
     // In a reset state?
-    if (Value & EHCI_PRT_RESET)
+    if ((Value & EHCI_PRT_RESET) || m_ResetInProgress[PortId])
+    {
         Status |= USB_PORT_STATUS_RESET;
+        Change |= USB_PORT_STATUS_RESET;
+    }
 
     //
     // FIXME: Is the Change here correct?
@@ -777,10 +775,7 @@ CUSBHardwareDevice::GetPortStatus(
 
     *PortStatus = Status;
     *PortChange = Change;
-#else
-    *PortStatus = m_PortStatus[PortId].PortStatus;
-    *PortChange = m_PortStatus[PortId].PortChange;
-#endif
+
     return STATUS_SUCCESS;
 }
 
@@ -796,38 +791,19 @@ CUSBHardwareDevice::ClearPortStatus(
     if (PortId > m_Capabilities.HCSParams.PortCount)
         return STATUS_UNSUCCESSFUL;
 
-    Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
-
     if (Status == C_PORT_RESET)
     {
-        if (Value & EHCI_PRT_RESET)
-        {
-            Value &= ~EHCI_PRT_RESET;
-            EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
-            KeStallExecutionProcessor(100);
-        }
-
-        Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
         //
         // update port status
         //
-        m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_RESET;
-        if (Value & EHCI_PRT_ENABLED) 
-            m_PortStatus[PortId].PortStatus |= USB_PORT_STATUS_ENABLE;
-        else
-        {
-            DPRINT1("Port is not enabled.\n");
-        }
+        m_ResetInProgress[PortId] = FALSE;
     }
 
     if (Status == C_PORT_CONNECTION)
     {
-        // FIXME: Make sure its the Connection and Enable Change status.
-        Value |= EHCI_PRT_CONNECTSTATUSCHANGE;
-        Value |= EHCI_PRT_ENABLEDSTATUSCHANGE;
+        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);
-
-        m_PortStatus[PortId].PortChange &= ~USB_PORT_STATUS_CONNECT;
     }
 
     return STATUS_SUCCESS;
@@ -858,18 +834,12 @@ CUSBHardwareDevice::SetPortFeature(
 
     if (Feature == PORT_RESET)
     {
-        if (Value & EHCI_PRT_SLOWSPEEDLINE)
-        {
-            DPRINT1("Non HighSpeed device. Releasing Ownership\n");
-        }
-
         ResetPort(PortId);
 
         //
         // update cached settings
         //
-        m_PortStatus[PortId].PortChange |= USB_PORT_STATUS_RESET;
-        m_PortStatus[PortId].PortStatus &= ~USB_PORT_STATUS_ENABLE;
+        m_ResetInProgress[PortId] = TRUE;
 
         //
         // is there a status change callback
@@ -1028,8 +998,10 @@ EhciDefferedRoutine(
                 //
                 // controller reported error
                 //
+                DPRINT1("CStatus %x\n", CStatus);
                 Status = STATUS_UNSUCCESSFUL;
                 PC_ASSERT(FALSE);
+                return;
             }
 
             //
@@ -1098,11 +1070,6 @@ EhciDefferedRoutine(
             //
             if (PortStatus & EHCI_PRT_CONNECTSTATUSCHANGE)
             {
-                //
-                // Clear the port change status
-                //
-                //This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_CONNECTSTATUSCHANGE);
-
                 if (PortStatus & EHCI_PRT_CONNECTED)
                 {
                     DPRINT1("Device connected on port %d\n", i);
@@ -1124,26 +1091,12 @@ EhciDefferedRoutine(
                             continue;
                         }
                     }
-
-                    //
-                    // update port status flags
-                    //
-                    This->m_PortStatus[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED;
-                    This->m_PortStatus[i].PortStatus |= USB_PORT_STATUS_CONNECT;
-                    This->m_PortStatus[i].PortChange |= USB_PORT_STATUS_CONNECT;
                 }
                 else
                 {
                     DPRINT1("Device disconnected on port %d\n", i);
-
-                    //
-                    // update port status flags
-                    //
-                    This->m_PortStatus[i].PortStatus &= ~USB_PORT_STATUS_HIGH_SPEED;
-                    This->m_PortStatus[i].PortStatus &= ~USB_PORT_STATUS_CONNECT;
-                    This->m_PortStatus[i].PortChange |= USB_PORT_STATUS_CONNECT;
                 }
-                
+
                 //
                 // is there a status change callback
                 //