[USBEHCI]
[reactos.git] / drivers / usb / usbehci_new / hardware.cpp
index 2a08a5d..804b133 100644 (file)
@@ -114,8 +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);
@@ -437,7 +438,7 @@ CUSBHardwareDevice::PnpStart(
     //
     // Initialize the UsbQueue now that we have an AdapterObject.
     //
-    Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, NULL);
+    Status = m_UsbQueue->Initialize(PUSBHARDWAREDEVICE(this), m_Adapter, m_MemoryManager, &m_Lock);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to Initialize the UsbQueue\n");
@@ -524,62 +525,30 @@ 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
+    // Enable Interrupts and start execution
     //
-    if (UsbCmd.HCReset)
-    {
-        DPRINT1("EHCI ERROR: Controller failed to reset. Hardware problem!\n");
-        return STATUS_UNSUCCESSFUL;
-    }
+    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
+        /*| EHCI_USBINTR_FLROVR*/  | EHCI_USBINTR_PC);
 
     //
-    // Disable Interrupts and clear status
+    // Assign the AsyncList Register
     //
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, 0);
-    EHCI_WRITE_REGISTER_ULONG(EHCI_USBSTS, 0x0000001f);
+    EHCI_WRITE_REGISTER_ULONG(EHCI_ASYNCLISTBASE, AsyncQueueHead->PhysicalAddr);
 
     //
-    // Assign the AsyncList Register
+    // Assign the SyncList Register
     //
-    EHCI_WRITE_REGISTER_ULONG(EHCI_ASYNCLISTBASE, AsyncQueueHead->PhysicalAddr);
+    EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, m_SyncFramePhysAddr);
 
     //
     // Set Schedules to Enable and Interrupt Threshold to 1ms.
     //
     GetCommandRegister(&UsbCmd);
-    UsbCmd.PeriodicEnable = FALSE;
-    UsbCmd.AsyncEnable = TRUE;  //FIXME: Need USB Memory Manager
-
+    UsbCmd.PeriodicEnable = TRUE;
     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);
 
@@ -608,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;
 }
@@ -663,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");
@@ -670,6 +650,8 @@ CUSBHardwareDevice::ResetPort(
         return STATUS_DEVICE_NOT_CONNECTED;
     }
 
+    ASSERT(PortStatus & EHCI_PRT_CONNECTED);
+
     //
     // Reset and clean enable
     //
@@ -686,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;
 }
 
@@ -707,7 +707,6 @@ CUSBHardwareDevice::GetPortStatus(
     OUT USHORT *PortStatus,
     OUT USHORT *PortChange)
 {
-#if 0
     ULONG Value;
     USHORT Status = 0, Change = 0;
 
@@ -734,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;
@@ -757,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?
@@ -771,10 +775,7 @@ CUSBHardwareDevice::GetPortStatus(
 
     *PortStatus = Status;
     *PortChange = Change;
-#else
-    *PortStatus = m_PortStatus[PortId].PortStatus;
-    *PortChange = m_PortStatus[PortId].PortChange;
-#endif
+
     return STATUS_SUCCESS;
 }
 
@@ -790,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;
@@ -852,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
@@ -894,7 +870,10 @@ VOID
 CUSBHardwareDevice::SetPeriodicListRegister(
     ULONG PhysicalAddress)
 {
-    EHCI_WRITE_REGISTER_ULONG(EHCI_PERIODICLISTBASE, PhysicalAddress);
+    //
+    // store physical address
+    //
+    m_SyncFramePhysAddr = PhysicalAddress;
 }
 
 struct _QUEUE_HEAD *
@@ -1019,8 +998,10 @@ EhciDefferedRoutine(
                 //
                 // controller reported error
                 //
+                DPRINT1("CStatus %x\n", CStatus);
                 Status = STATUS_UNSUCCESSFUL;
                 PC_ASSERT(FALSE);
+                return;
             }
 
             //
@@ -1089,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);
@@ -1115,30 +1091,23 @@ 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;
-
-                    //
-                    // is there a status change callback
-                    //
-                    if (This->m_SCECallBack != NULL)
-                    {
-                        //
-                        // queue work item for processing
-                        //
-                        ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
-                    }
                 }
                 else
                 {
                     DPRINT1("Device disconnected on port %d\n", i);
                 }
 
+                //
+                // is there a status change callback
+                //
+                if (This->m_SCECallBack != NULL)
+                {
+                    //
+                    // queue work item for processing
+                    //
+                    ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
+                }
+
                 //
                 // FIXME: This needs to be saved somewhere
                 //