Enhance the Usb bus driver to support Star with Remaining device path.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / usbbus.c
index 910ebc5..332871a 100644 (file)
@@ -868,6 +868,192 @@ ON_EXIT:
   return Status;\r
 }\r
 \r
+\r
+/**\r
+  Install Usb Bus Protocol on host controller, and start the Usb bus\r
+\r
+  @param This                    The USB bus driver binding instance\r
+  @param Controller              The controller to check\r
+  @param RemainingDevicePath     The remaining device patch\r
+\r
+  @retval EFI_SUCCESS            The controller is controlled by the usb bus\r
+  @retval EFI_ALREADY_STARTED    The controller is already controlled by the usb bus\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UsbBusBuildProtocol (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+{\r
+  USB_BUS                 *UsbBus;\r
+  USB_DEVICE              *RootHub;\r
+  USB_INTERFACE           *RootIf;\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              Status2;\r
+\r
+  UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
+\r
+  if (UsbBus == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  UsbBus->Signature   = USB_BUS_SIGNATURE;\r
+  UsbBus->HostHandle  = Controller;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &UsbBus->DevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));\r
+\r
+    gBS->FreePool (UsbBus);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
+  // This is for backward compatbility with EFI 1.x. In UEFI\r
+  // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
+  // and USB_HC because EHCI driver will install both protocols\r
+  // (for the same reason). If we don't consume both of them,\r
+  // the unconsumed one may be opened by others.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiUsb2HcProtocolGuid,\r
+                  (VOID **) &(UsbBus->Usb2Hc),\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  Status2 = gBS->OpenProtocol (\r
+                   Controller,\r
+                   &gEfiUsbHcProtocolGuid,\r
+                   (VOID **) &(UsbBus->UsbHc),\r
+                   This->DriverBindingHandle,\r
+                   Controller,\r
+                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                   );\r
+\r
+  if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto CLOSE_HC;\r
+  }\r
+\r
+  UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
+  UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
+\r
+  //\r
+  // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &mUsbBusProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &UsbBus->BusId\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));\r
+    goto CLOSE_HC;\r
+  }\r
+\r
+  //\r
+  // Initial the wanted child device path list, and add first RemainingDevicePath\r
+  //\r
+  InitializeListHead (&UsbBus->WantedUsbIoDPList);\r
+  Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath);\r
+  ASSERT (!EFI_ERROR (Status));\r
+  //\r
+  // Create a fake usb device for root hub\r
+  //\r
+  RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
+\r
+  if (RootHub == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto UNINSTALL_USBBUS;\r
+  }\r
+\r
+  RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
+\r
+  if (RootIf == NULL) {\r
+    gBS->FreePool (RootHub);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto FREE_ROOTHUB;\r
+  }\r
+\r
+  RootHub->Bus            = UsbBus;\r
+  RootHub->NumOfInterface = 1;\r
+  RootHub->Interfaces[0]  = RootIf;\r
+  RootIf->Signature       = USB_INTERFACE_SIGNATURE;\r
+  RootIf->Device          = RootHub;\r
+  RootIf->DevicePath      = UsbBus->DevicePath;\r
+\r
+  Status                  = mUsbRootHubApi.Init (RootIf);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));\r
+    goto FREE_ROOTHUB;\r
+  }\r
+\r
+  UsbBus->Devices[0] = RootHub;\r
+\r
+  DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));\r
+  return EFI_SUCCESS;\r
+\r
+FREE_ROOTHUB:\r
+  if (RootIf != NULL) {\r
+    gBS->FreePool (RootIf);\r
+  }\r
+  if (RootHub != NULL) {\r
+    gBS->FreePool (RootHub);\r
+  }\r
+\r
+UNINSTALL_USBBUS:\r
+  gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &UsbBus->BusId);\r
+\r
+CLOSE_HC:\r
+  if (UsbBus->Usb2Hc != NULL) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiUsb2HcProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+  if (UsbBus->UsbHc != NULL) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiUsbHcProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+  }\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiDevicePathProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+  gBS->FreePool (UsbBus);\r
+\r
+  DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));\r
+  return Status;\r
+}\r
+\r
 EFI_USB_IO_PROTOCOL mUsbIoProtocol = {\r
   UsbIoControlTransfer,\r
   UsbIoBulkTransfer,\r
@@ -952,8 +1138,10 @@ UsbBusControllerDriverSupported (
     DevicePathNode.DevPath = RemainingDevicePath;\r
 \r
     if ((DevicePathNode.DevPath->Type    != MESSAGING_DEVICE_PATH) ||\r
-        (DevicePathNode.DevPath->SubType != MSG_USB_DP) ||\r
-        (DevicePathNodeLength (DevicePathNode.DevPath) != sizeof (USB_DEVICE_PATH))) {\r
+        (DevicePathNode.DevPath->SubType != MSG_USB_DP &&\r
+         DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP\r
+         && DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP\r
+         )) {\r
 \r
       return EFI_UNSUPPORTED;\r
     }\r
@@ -1060,12 +1248,8 @@ UsbBusControllerDriverStart (
   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
   )\r
 {\r
-  USB_BUS                 *UsbBus;\r
-  USB_DEVICE              *RootHub;\r
-  USB_INTERFACE           *RootIf;\r
-  EFI_USB_BUS_PROTOCOL    *UsbBusId;\r
-  EFI_STATUS              Status;\r
-  EFI_STATUS              Status2;\r
+  EFI_USB_BUS_PROTOCOL          *UsbBusId;\r
+  EFI_STATUS                    Status;\r
 \r
   //\r
   // Locate the USB bus protocol, if it is found, USB bus\r
@@ -1080,161 +1264,47 @@ UsbBusControllerDriverStart (
                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                   );\r
 \r
-  if (!EFI_ERROR (Status)) {\r
-    return EFI_ALREADY_STARTED;\r
-  }\r
-\r
-  UsbBus = AllocateZeroPool (sizeof (USB_BUS));\r
-\r
-  if (UsbBus == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  UsbBus->Signature   = USB_BUS_SIGNATURE;\r
-  UsbBus->HostHandle  = Controller;\r
-\r
-  Status = gBS->OpenProtocol (\r
-                  Controller,\r
-                  &gEfiDevicePathProtocolGuid,\r
-                  (VOID **) &UsbBus->DevicePath,\r
-                  This->DriverBindingHandle,\r
-                  Controller,\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
-                  );\r
-\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status));\r
-\r
-    gBS->FreePool (UsbBus);\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI).\r
-  // This is for backward compatbility with EFI 1.x. In UEFI\r
-  // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2\r
-  // and USB_HC because EHCI driver will install both protocols\r
-  // (for the same reason). If we don't consume both of them,\r
-  // the unconsumed one may be opened by others.\r
-  //\r
-  Status = gBS->OpenProtocol (\r
-                  Controller,\r
-                  &gEfiUsb2HcProtocolGuid,\r
-                  (VOID **) &(UsbBus->Usb2Hc),\r
-                  This->DriverBindingHandle,\r
-                  Controller,\r
-                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
-                  );\r
-\r
-  Status2 = gBS->OpenProtocol (\r
-                   Controller,\r
-                   &gEfiUsbHcProtocolGuid,\r
-                   (VOID **) &(UsbBus->UsbHc),\r
-                   This->DriverBindingHandle,\r
-                   Controller,\r
-                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
-                   );\r
-\r
-  if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {\r
-    DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status));\r
-\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto CLOSE_HC;\r
-  }\r
-\r
-  UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
-  UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
-\r
-  //\r
-  // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it.\r
-  //\r
-  Status = gBS->InstallProtocolInterface (\r
-                  &Controller,\r
-                  &mUsbBusProtocolGuid,\r
-                  EFI_NATIVE_INTERFACE,\r
-                  &UsbBus->BusId\r
-                  );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status));\r
-    goto CLOSE_HC;\r
-  }\r
-\r
-  //\r
-  // Create a fake usb device for root hub\r
-  //\r
-  RootHub = AllocateZeroPool (sizeof (USB_DEVICE));\r
-\r
-  if (RootHub == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto UNINSTALL_USBBUS;\r
-  }\r
-\r
-  RootIf = AllocateZeroPool (sizeof (USB_INTERFACE));\r
-\r
-  if (RootIf == NULL) {\r
-    gBS->FreePool (RootHub);\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto FREE_ROOTHUB;\r
-  }\r
-\r
-  RootHub->Bus            = UsbBus;\r
-  RootHub->NumOfInterface = 1;\r
-  RootHub->Interfaces[0]  = RootIf;\r
-  RootIf->Signature       = USB_INTERFACE_SIGNATURE;\r
-  RootIf->Device          = RootHub;\r
-  RootIf->DevicePath      = UsbBus->DevicePath;\r
-  \r
-  Status                  = mUsbRootHubApi.Init (RootIf);\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status));\r
-    goto FREE_ROOTHUB;\r
+    //\r
+    // If first start, build the bus execute enviorment and install bus protocol\r
+    //\r
+    Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Try get the Usb Bus protocol interface again\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &mUsbBusProtocolGuid,\r
+                    (VOID **) &UsbBusId,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    ASSERT (!EFI_ERROR (Status));\r
+  } else {\r
+    //\r
+    // USB Bus driver need to control the recursive connect policy of the bus, only those wanted\r
+    // usb child device will be recursively connected.\r
+    // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time.\r
+    // All wanted usb child devices will be remembered by the usb bus driver itself.\r
+    // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices.\r
+    //\r
+    // Save the passed in RemainingDevicePath this time\r
+    //\r
+    Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath);\r
+    ASSERT (!EFI_ERROR (Status));\r
+    //\r
+    // Ensure all wanted child usb devices are fully recursively connected\r
+    //\r
+    Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId);\r
+    ASSERT (!EFI_ERROR (Status));\r
   }\r
 \r
-  UsbBus->Devices[0] = RootHub;\r
 \r
-  DEBUG (( EFI_D_INFO, "UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));\r
   return EFI_SUCCESS;\r
-  \r
-FREE_ROOTHUB:\r
-  if (RootIf != NULL) {\r
-    gBS->FreePool (RootIf);\r
-  }\r
-  if (RootHub != NULL) {\r
-    gBS->FreePool (RootHub);\r
-  }\r
-  \r
-UNINSTALL_USBBUS:\r
-  gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &UsbBus->BusId);\r
-  \r
-CLOSE_HC:\r
-  if (UsbBus->Usb2Hc != NULL) {\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsb2HcProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-  }\r
-  if (UsbBus->UsbHc != NULL) {\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbHcProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-  }\r
-  gBS->CloseProtocol (\r
-         Controller,\r
-         &gEfiDevicePathProtocolGuid,\r
-         This->DriverBindingHandle,\r
-         Controller\r
-         );\r
-  gBS->FreePool (UsbBus);\r
-\r
-  DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status));\r
-  return Status;\r
 }\r
 \r
 \r
@@ -1274,7 +1344,10 @@ UsbBusControllerDriverStop (
   Status  = EFI_SUCCESS;\r
 \r
   if (NumberOfChildren > 0) {\r
-    OldTpl   = gBS->RaiseTPL (USB_BUS_TPL);\r
+    //\r
+    // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
+    //\r
+    OldTpl   = gBS->RaiseTPL (TPL_CALLBACK);\r
 \r
     for (Index = 0; Index < NumberOfChildren; Index++) {\r
       Status = gBS->OpenProtocol (\r
@@ -1329,7 +1402,9 @@ UsbBusControllerDriverStop (
   //\r
   // Stop the root hub, then free all the devices\r
   //\r
-  OldTpl  = gBS->RaiseTPL (USB_BUS_TPL);\r
+  // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict\r
+  //\r
+  OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
   UsbHcSetState (Bus, EfiUsbHcStateHalt);\r
 \r
   RootHub = Bus->Devices[0];\r
@@ -1347,6 +1422,8 @@ UsbBusControllerDriverStop (
 \r
   gBS->FreePool   (RootIf);\r
   gBS->FreePool   (RootHub);\r
+  Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList);\r
+  ASSERT (!EFI_ERROR (Status));\r
 \r
   //\r
   // Uninstall the bus identifier and close USB_HC/USB2_HC protocols\r