]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c
Enhance the Usb bus driver to support Star with Remaining device path.
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBusDxe / usbbus.c
index c5a0604fca71da2f99173229bc5927e9f494ac1e..332871a6851d013a9857fa206e5ad629e63ea00d 100644 (file)
@@ -150,8 +150,7 @@ UsbIoControlTransfer (
 \r
       goto ON_EXIT;\r
     }\r
-\r
-    USB_DEBUG (("UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
+    DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n"));\r
 \r
     if (Dev->ActiveConfig != NULL) {\r
       UsbRemoveConfig (Dev);\r
@@ -645,11 +644,16 @@ UsbIoGetEndpointDescriptor (
 \r
   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
 \r
-  if ((Descriptor == NULL) || (Index >= UsbIf->IfSetting->Desc.NumEndpoints)) {\r
+  if ((Descriptor == NULL) || (Index > 15)) {\r
     gBS->RestoreTPL (OldTpl);\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  if (Index >= UsbIf->IfSetting->Desc.NumEndpoints) {\r
+    gBS->RestoreTPL (OldTpl);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
   CopyMem (\r
     Descriptor,\r
     &(UsbIf->IfSetting->Endpoints[Index]->Desc),\r
@@ -813,11 +817,16 @@ UsbIoPortReset (
   UsbIf  = USB_INTERFACE_FROM_USBIO (This);\r
   Dev    = UsbIf->Device;\r
 \r
+  if (UsbIf->IsHub == TRUE) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto ON_EXIT;\r
+  }\r
+\r
   HubIf  = Dev->ParentIf;\r
   Status = HubIf->HubApi->ResetPort (HubIf, Dev->ParentPort);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbIoPortReset: failed to reset hub port %d@hub  %d, %r \n",\r
+    DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to reset hub port %d@hub  %d, %r \n",\r
                 Dev->ParentPort, Dev->ParentAddr, Status));\r
 \r
     goto ON_EXIT;\r
@@ -833,7 +842,7 @@ UsbIoPortReset (
   Status        = UsbSetAddress (Dev, Address);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    USB_ERROR (("UsbIoPortReset: failed to set address for device %d - %r\n",\r
+    DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set address for device %d - %r\n",\r
                 Address, Status));\r
 \r
     goto ON_EXIT;\r
@@ -849,7 +858,7 @@ UsbIoPortReset (
     Status = UsbSetConfig (Dev, Dev->ActiveConfig->Desc.ConfigurationValue);\r
 \r
     if (EFI_ERROR (Status)) {\r
-      USB_ERROR (("UsbIoPortReset: failed to set configure for device %d - %r\n",\r
+      DEBUG (( EFI_D_ERROR, "UsbIoPortReset: failed to set configure for device %d - %r\n",\r
                   Address, Status));\r
     }\r
   }\r
@@ -859,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
@@ -875,7 +1070,6 @@ EFI_USB_IO_PROTOCOL mUsbIoProtocol = {
   UsbIoPortReset\r
 };\r
 \r
-//@MT: EFI_DRIVER_ENTRY_POINT (UsbBusDriverEntryPoint)\r
 \r
 EFI_STATUS\r
 EFIAPI\r
@@ -901,14 +1095,13 @@ Returns:
 \r
 --*/\r
 {\r
-  return EfiLibInstallAllDriverProtocols (\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
            ImageHandle,\r
            SystemTable,\r
            &mUsbBusDriverBinding,\r
            ImageHandle,\r
            &mUsbBusComponentName,\r
-           NULL,\r
-           NULL\r
+           &mUsbBusComponentName2\r
            );\r
 }\r
 \r
@@ -945,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
@@ -1053,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
@@ -1073,159 +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
-    USB_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
-    USB_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
-  //\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 CLOSE_HC;\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 CLOSE_HC;\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
-    USB_ERROR (("UsbBusStart: Failed to init root hub %r\n", Status));\r
-    goto FREE_ROOTHUB;\r
-  }\r
-\r
-  UsbBus->Devices[0] = RootHub;\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
-    USB_ERROR (("UsbBusStart: Failed to install bus protocol %r\n", Status));\r
-\r
-    mUsbRootHubApi.Release (RootIf);\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
-  UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL);\r
-  UsbHcSetState (UsbBus, EfiUsbHcStateOperational);\r
 \r
-  USB_DEBUG (("UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf));\r
   return EFI_SUCCESS;\r
-\r
-FREE_ROOTHUB:\r
-  gBS->FreePool (RootIf);\r
-  gBS->FreePool (RootHub);\r
-\r
-CLOSE_HC:\r
-  if (UsbBus->Usb2Hc != NULL) {\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsb2HcProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-  }\r
-\r
-  if (UsbBus->UsbHc != NULL) {\r
-    gBS->CloseProtocol (\r
-          Controller,\r
-          &gEfiUsbHcProtocolGuid,\r
-          This->DriverBindingHandle,\r
-          Controller\r
-          );\r
-  }\r
-\r
-  gBS->CloseProtocol (\r
-         Controller,\r
-         &gEfiDevicePathProtocolGuid,\r
-         This->DriverBindingHandle,\r
-         Controller\r
-         );\r
-\r
-  gBS->FreePool (UsbBus);\r
-\r
-  USB_ERROR (("UsbBusStart: Failed to start bus driver %r\n", Status));\r
-  return Status;\r
 }\r
 \r
 \r
@@ -1265,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
@@ -1297,7 +1379,7 @@ UsbBusControllerDriverStop (
     return EFI_SUCCESS;\r
   }\r
 \r
-  USB_DEBUG (("UsbBusStop: usb bus stopped on %x\n", Controller));\r
+  DEBUG (( EFI_D_INFO, "UsbBusStop: usb bus stopped on %x\n", Controller));\r
 \r
   //\r
   // Locate USB_BUS for the current host controller\r
@@ -1320,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
@@ -1338,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