From: vanjeff Date: Wed, 26 Dec 2007 06:38:15 +0000 (+0000) Subject: Enhance the Usb bus driver to support Star with Remaining device path. X-Git-Tag: edk2-stable201903~21640 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=ecb575d9e65c9d52c17866eebba5f798f178effe;hp=be0187bbbad2039b83b15aebf9352de27a9d3c00 Enhance the Usb bus driver to support Star with Remaining device path. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4437 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c index 65eb2dd77f..6b46e5c3ce 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.c @@ -288,18 +288,24 @@ UsbConnectDriver ( // twisted TPL used. It should be no problem for us to connect // or disconnect at CALLBACK. // - OldTpl = UsbGetCurrentTpl (); - DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d\n", OldTpl)); + + // + // Only recursively wanted usb child device + // + if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) { + OldTpl = UsbGetCurrentTpl (); + DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d\n", OldTpl)); - gBS->RestoreTPL (TPL_CALLBACK); + gBS->RestoreTPL (TPL_CALLBACK); - Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE); - UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status); + Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE); + UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status); - DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl())); - ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK); + DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl())); + ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK); - gBS->RaiseTPL (OldTpl); + gBS->RaiseTPL (OldTpl); + } } return Status; diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h index 23bcdf93fc..54f4dd2ca0 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbEnumer.h @@ -140,6 +140,7 @@ UsbRemoveDevice ( ); VOID +EFIAPI UsbHubEnumeration ( IN EFI_EVENT Event, IN VOID *Context diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c index d4184fe1a2..37e6c05a2f 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbUtility.c @@ -25,6 +25,34 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "UsbBus.h" +// +// if RemainingDevicePath== NULL, then all Usb child devices in this bus are wanted. +// Use a shor form Usb class Device Path, which could match any usb device, in WantedUsbIoDPList to indicate all Usb devices +// are wanted Usb devices +// +STATIC USB_CLASS_FORMAT_DEVICE_PATH mAllUsbClassDevicePath = { + { + { + MESSAGING_DEVICE_PATH, + MSG_USB_CLASS_DP, + (UINT8) (sizeof (USB_CLASS_DEVICE_PATH)), + (UINT8) ((sizeof (USB_CLASS_DEVICE_PATH)) >> 8) + }, + 0xffff, // VendorId + 0xffff, // ProductId + 0xff, // DeviceClass + 0xff, // DeviceSubClass + 0xff // DeviceProtocol + }, + + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + END_DEVICE_PATH_LENGTH, + 0 + } +}; + /** Get the capability of the host controller @@ -711,3 +739,612 @@ UsbGetCurrentTpl ( return Tpl; } +/** + Create a new device path which only contain the first Usb part of the DevicePath + + @param DevicePath A full device path which contain the usb nodes + + @return A new device path which only contain the Usb part of the DevicePath + +**/ +EFI_DEVICE_PATH_PROTOCOL * +EFIAPI +GetUsbDPFromFullDP ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathPtr; + EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathBeginPtr; + EFI_DEVICE_PATH_PROTOCOL *UsbDevicePathEndPtr; + UINTN Size; + + // + // Get the Usb part first Begin node in full device path + // + UsbDevicePathBeginPtr = DevicePath; + while ( (!EfiIsDevicePathEnd (UsbDevicePathBeginPtr))&& + ((UsbDevicePathBeginPtr->Type != MESSAGING_DEVICE_PATH) || + (UsbDevicePathBeginPtr->SubType != MSG_USB_DP && + UsbDevicePathBeginPtr->SubType != MSG_USB_CLASS_DP + && UsbDevicePathBeginPtr->SubType != MSG_USB_WWID_DP + ))) { + + UsbDevicePathBeginPtr = NextDevicePathNode(UsbDevicePathBeginPtr); + } + + // + // Get the Usb part first End node in full device path + // + UsbDevicePathEndPtr = UsbDevicePathBeginPtr; + while ((!EfiIsDevicePathEnd (UsbDevicePathEndPtr))&& + (UsbDevicePathEndPtr->Type == MESSAGING_DEVICE_PATH) && + (UsbDevicePathEndPtr->SubType == MSG_USB_DP || + UsbDevicePathEndPtr->SubType == MSG_USB_CLASS_DP + || UsbDevicePathEndPtr->SubType == MSG_USB_WWID_DP + )) { + + UsbDevicePathEndPtr = NextDevicePathNode(UsbDevicePathEndPtr); + } + + Size = GetDevicePathSize (UsbDevicePathBeginPtr); + Size -= GetDevicePathSize (UsbDevicePathEndPtr); + if (Size ==0){ + // + // The passed in DevicePath does not contain the usb nodes + // + return NULL; + } + + // + // Create a new device path which only contain the above Usb part + // + UsbDevicePathPtr = AllocateZeroPool (Size + sizeof (EFI_DEVICE_PATH_PROTOCOL)); + ASSERT (UsbDevicePathPtr != NULL); + CopyMem (UsbDevicePathPtr, UsbDevicePathBeginPtr, Size); + // + // Append end device path node + // + UsbDevicePathEndPtr = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) UsbDevicePathPtr + Size); + SetDevicePathEndNode (UsbDevicePathEndPtr); + return UsbDevicePathPtr; +} + +/** + Check whether a usb device path is in a DEVICE_PATH_LIST_ITEM list. + + @param UsbDP a usb device path of DEVICE_PATH_LIST_ITEM + @parem UsbIoDPList a DEVICE_PATH_LIST_ITEM list + + @retval TRUE there is a DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP + @retval FALSE there is no DEVICE_PATH_LIST_ITEM in UsbIoDPList which contains the passed in UsbDP + +**/ +BOOLEAN +EFIAPI +SearchUsbDPInList ( + IN EFI_DEVICE_PATH_PROTOCOL *UsbDP, + IN LIST_ENTRY *UsbIoDPList + ) +{ + LIST_ENTRY *ListIndex; + DEVICE_PATH_LIST_ITEM *ListItem; + BOOLEAN Found; + UINTN UsbDpDevicePathSize; + + // + // Check that UsbDP and UsbIoDPList are valid + // + if ((UsbIoDPList == NULL) || (UsbDP == NULL)) { + return FALSE; + } + + Found = FALSE; + ListIndex = UsbIoDPList->ForwardLink; + while (ListIndex != UsbIoDPList){ + ListItem = CR(ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE); + // + // Compare DEVICE_PATH_LIST_ITEM.DevicePath[] + // + ASSERT (ListItem->DevicePath != NULL); + + UsbDpDevicePathSize = GetDevicePathSize (UsbDP); + if (UsbDpDevicePathSize == GetDevicePathSize (ListItem->DevicePath)) { + if ((CompareMem (UsbDP, ListItem->DevicePath, UsbDpDevicePathSize)) == 0) { + Found = TRUE; + break; + } + } + ListIndex = ListIndex->ForwardLink; + } + + return Found; +} + +/** + Add a usb device path into the DEVICE_PATH_LIST_ITEM list. + + @param UsbDP a usb device path of DEVICE_PATH_LIST_ITEM + @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list + + @retval EFI_INVALID_PARAMETER + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EFIAPI +AddUsbDPToList ( + IN EFI_DEVICE_PATH_PROTOCOL *UsbDP, + IN LIST_ENTRY *UsbIoDPList + ) +{ + DEVICE_PATH_LIST_ITEM *ListItem; + + // + // Check that UsbDP and UsbIoDPList are valid + // + if ((UsbIoDPList == NULL) || (UsbDP == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (SearchUsbDPInList (UsbDP, UsbIoDPList)){ + return EFI_SUCCESS; + } + + // + // Prepare the usbio device path DEVICE_PATH_LIST_ITEM structure. + // + ListItem = AllocateZeroPool (sizeof (DEVICE_PATH_LIST_ITEM)); + ASSERT (ListItem != NULL); + ListItem->Signature = DEVICE_PATH_LIST_ITEM_SIGNATURE; + ListItem->DevicePath = DuplicateDevicePath (UsbDP); + + InsertTailList (UsbIoDPList, &ListItem->Link); + + return EFI_SUCCESS; +} + +/** + Check whether usb device, whose interface is UsbIf, matches the usb class which indicated by + UsbClassDevicePathPtr whose is a short form usb class device path + + @param UsbClassDevicePathPtr a short form usb class device path + @param UsbIf a usb device interface + + @retval TRUE the usb device match the usb class + @retval FALSE the usb device does not match the usb class + +**/ +BOOLEAN +EFIAPI +MatchUsbClass ( + IN USB_CLASS_DEVICE_PATH *UsbClassDevicePathPtr, + IN USB_INTERFACE *UsbIf + ) +{ + USB_INTERFACE_DESC *IfDesc; + EFI_USB_INTERFACE_DESCRIPTOR *ActIfDesc; + EFI_USB_DEVICE_DESCRIPTOR *DevDesc; + + + if ((UsbClassDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) || + (UsbClassDevicePathPtr->Header.SubType != MSG_USB_CLASS_DP)){ + ASSERT (0); + return FALSE; + } + + IfDesc = UsbIf->IfDesc; + ActIfDesc = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc); + DevDesc = &(UsbIf->Device->DevDesc->Desc); + + // + // If connect class policy, determine whether to create device handle by the five fields + // in class device path node. + // + // In addtion, hub interface is always matched for this policy. + // + if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) && + (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) { + return TRUE; + } + + // + // If vendor id or product id is 0xffff, they will be ignored. + // + if ((UsbClassDevicePathPtr->VendorId == 0xffff || UsbClassDevicePathPtr->VendorId == DevDesc->IdVendor) && + (UsbClassDevicePathPtr->ProductId == 0xffff || UsbClassDevicePathPtr->ProductId == DevDesc->IdProduct)) { + + // + // If class or subclass or protocol is 0, the counterparts in interface should be checked. + // + if (DevDesc->DeviceClass == 0 && + DevDesc->DeviceSubClass == 0 && + DevDesc->DeviceProtocol == 0) { + + if ((UsbClassDevicePathPtr->DeviceClass == ActIfDesc->InterfaceClass || + UsbClassDevicePathPtr->DeviceClass == 0xff) && + (UsbClassDevicePathPtr->DeviceSubClass == ActIfDesc->InterfaceSubClass || + UsbClassDevicePathPtr->DeviceSubClass == 0xff) && + (UsbClassDevicePathPtr->DeviceProtocol == ActIfDesc->InterfaceProtocol) || + UsbClassDevicePathPtr->DeviceProtocol == 0xff) { + return TRUE; + } + + } else if ((UsbClassDevicePathPtr->DeviceClass != DevDesc->DeviceClass || + UsbClassDevicePathPtr->DeviceClass == 0xff) && + (UsbClassDevicePathPtr->DeviceSubClass == DevDesc->DeviceSubClass || + UsbClassDevicePathPtr->DeviceSubClass == 0xff) && + (UsbClassDevicePathPtr->DeviceProtocol == DevDesc->DeviceProtocol) || + UsbClassDevicePathPtr->DeviceProtocol == 0xff) { + + return TRUE; + } + } + + return FALSE; +} + +/** + Check whether usb device, whose interface is UsbIf, matches the usb WWID requirement which indicated by + UsbWWIDDevicePathPtr whose is a short form usb WWID device path + + @param UsbClassDevicePathPtr a short form usb WWID device path + @param UsbIf a usb device interface + + @retval TRUE the usb device match the usb WWID requirement + @retval FALSE the usb device does not match the usb WWID requirement + +**/ +STATIC +BOOLEAN +MatchUsbWwid ( + IN USB_WWID_DEVICE_PATH *UsbWWIDDevicePathPtr, + IN USB_INTERFACE *UsbIf + ) +{ + USB_INTERFACE_DESC *IfDesc; + EFI_USB_INTERFACE_DESCRIPTOR *ActIfDesc; + EFI_USB_DEVICE_DESCRIPTOR *DevDesc; + EFI_USB_STRING_DESCRIPTOR *StrDesc; + UINT16 *SnString; + + if ((UsbWWIDDevicePathPtr->Header.Type != MESSAGING_DEVICE_PATH) || + (UsbWWIDDevicePathPtr->Header.SubType != MSG_USB_WWID_DP )){ + ASSERT (0); + return FALSE; + } + + IfDesc = UsbIf->IfDesc; + ActIfDesc = &(IfDesc->Settings[IfDesc->ActiveIndex]->Desc); + DevDesc = &(UsbIf->Device->DevDesc->Desc); + StrDesc = UsbGetOneString (UsbIf->Device, DevDesc->StrSerialNumber, USB_US_LAND_ID); + SnString = (UINT16 *) ((UINT8 *)UsbWWIDDevicePathPtr + 10); + + // + //In addtion, hub interface is always matched for this policy. + // + if ((ActIfDesc->InterfaceClass == USB_HUB_CLASS_CODE) && + (ActIfDesc->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) { + return TRUE; + } + // + // If connect wwid policy, determine the objective device by the serial number of + // device descriptor. + // Get serial number index from device descriptor, then get serial number by index + // and land id, compare the serial number with wwid device path node at last + // + // BugBug: only check serial number here, should check Interface Number, Device Vendor Id, Device Product Id in later version + // + if (StrDesc != NULL && !StrnCmp (StrDesc->String, SnString, StrDesc->Length)) { + + return TRUE; + } + + return FALSE; +} + +/** + Free a DEVICE_PATH_LIST_ITEM list + + @param UsbIoDPList a DEVICE_PATH_LIST_ITEM list pointer + + @retval EFI_INVALID_PARAMETER + @retval EFI_SUCCESS + +**/ +EFI_STATUS +EFIAPI +UsbBusFreeUsbDPList ( + IN LIST_ENTRY *UsbIoDPList + ) +{ + LIST_ENTRY *ListIndex; + DEVICE_PATH_LIST_ITEM *ListItem; + + // + // Check that ControllerHandle is a valid handle + // + if (UsbIoDPList == NULL) { + return EFI_INVALID_PARAMETER; + } + + ListIndex = UsbIoDPList->ForwardLink; + while (ListIndex != UsbIoDPList){ + ListItem = CR(ListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE); + // + // Free DEVICE_PATH_LIST_ITEM.DevicePath[] + // + if (ListItem->DevicePath != NULL){ + FreePool(ListItem->DevicePath); + } + // + // Free DEVICE_PATH_LIST_ITEM itself + // + ListIndex = ListIndex->ForwardLink; + RemoveEntryList (&ListItem->Link); + FreePool (ListItem); + } + + InitializeListHead (UsbIoDPList); + return EFI_SUCCESS; +} + +/** + Store a wanted usb child device info (its Usb part of device path) which is indicated by + RemainingDevicePath in a Usb bus which is indicated by UsbBusId + + @param UsbBusId Point to EFI_USB_BUS_PROTOCOL interface + @param RemainingDevicePath The remaining device patch + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + +**/ +EFI_STATUS +EFIAPI +UsbBusAddWantedUsbIoDP ( + IN EFI_USB_BUS_PROTOCOL *UsbBusId, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + USB_BUS *Bus; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePathPtr; + + // + // Check whether remaining device path is valid + // + if (RemainingDevicePath != NULL) { + if ((RemainingDevicePath->Type != MESSAGING_DEVICE_PATH) || + (RemainingDevicePath->SubType != MSG_USB_DP && + RemainingDevicePath->SubType != MSG_USB_CLASS_DP + && RemainingDevicePath->SubType != MSG_USB_WWID_DP + )) { + return EFI_INVALID_PARAMETER; + } + } + + if (UsbBusId == NULL){ + return EFI_INVALID_PARAMETER; + } + + Bus = USB_BUS_FROM_THIS (UsbBusId); + + if (RemainingDevicePath == NULL) { + // + // RemainingDevicePath== NULL means all Usb devices in this bus are wanted. + // Here use a Usb class Device Path in WantedUsbIoDPList to indicate all Usb devices + // are wanted Usb devices + // + Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList); + ASSERT (!EFI_ERROR (Status)); + DevicePathPtr = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) &mAllUsbClassDevicePath); + } else { + // + // Create new Usb device path according to the usb part in remaining device path + // + DevicePathPtr = GetUsbDPFromFullDP (RemainingDevicePath); + } + + ASSERT (DevicePathPtr != NULL); + Status = AddUsbDPToList (DevicePathPtr, &Bus->WantedUsbIoDPList); + ASSERT (!EFI_ERROR (Status)); + gBS->FreePool (DevicePathPtr); + return EFI_SUCCESS; +} + +/** + Check whether a usb child device is the wanted device in a bus + + @param Bus The Usb bus's private data pointer + @param UsbIf The usb child device inferface + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + +**/ +BOOLEAN +EFIAPI +UsbBusIsWantedUsbIO ( + IN USB_BUS *Bus, + IN USB_INTERFACE *UsbIf + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathPtr; + LIST_ENTRY *WantedUsbIoDPListPtr; + LIST_ENTRY *WantedListIndex; + DEVICE_PATH_LIST_ITEM *WantedListItem; + BOOLEAN DoConvert; + UINTN FirstDevicePathSize; + + // + // Check whether passed in parameters are valid + // + if ((UsbIf == NULL) || (Bus == NULL)) { + return FALSE; + } + // + // Check whether UsbIf is Hub + // + if (UsbIf->IsHub) { + return TRUE; + } + + // + // Check whether all Usb devices in this bus are wanted + // + if (SearchUsbDPInList ((EFI_DEVICE_PATH_PROTOCOL *)&mAllUsbClassDevicePath, &Bus->WantedUsbIoDPList)){ + return TRUE; + } + + // + // Check whether the Usb device match any item in WantedUsbIoDPList + // + WantedUsbIoDPListPtr = &Bus->WantedUsbIoDPList; + // + // Create new Usb device path according to the usb part in UsbIo full device path + // + DevicePathPtr = GetUsbDPFromFullDP (UsbIf->DevicePath); + ASSERT (DevicePathPtr != NULL); + + DoConvert = FALSE; + WantedListIndex = WantedUsbIoDPListPtr->ForwardLink; + while (WantedListIndex != WantedUsbIoDPListPtr){ + WantedListItem = CR(WantedListIndex, DEVICE_PATH_LIST_ITEM, Link, DEVICE_PATH_LIST_ITEM_SIGNATURE); + ASSERT (WantedListItem->DevicePath->Type == MESSAGING_DEVICE_PATH); + switch (WantedListItem->DevicePath->SubType) { + case MSG_USB_DP: + FirstDevicePathSize = GetDevicePathSize (WantedListItem->DevicePath); + if (FirstDevicePathSize == GetDevicePathSize (DevicePathPtr)) { + if (CompareMem ( + WantedListItem->DevicePath, + DevicePathPtr, + GetDevicePathSize (DevicePathPtr)) == 0 + ) { + DoConvert = TRUE; + } + } + break; + case MSG_USB_CLASS_DP: + if (MatchUsbClass((USB_CLASS_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) { + DoConvert = TRUE; + } + break; + case MSG_USB_WWID_DP: + if (MatchUsbWwid((USB_WWID_DEVICE_PATH *)WantedListItem->DevicePath, UsbIf)) { + DoConvert = TRUE; + } + break; + default: + ASSERT (0); + break; + } + + if (DoConvert) { + break; + } + + WantedListIndex = WantedListIndex->ForwardLink; + } + gBS->FreePool (DevicePathPtr); + + // + // Check whether the new Usb device path is wanted + // + if (DoConvert){ + return TRUE; + } else { + return FALSE; + } +} + +/** + Recursively connnect every wanted usb child device to ensure they all fully connected. + Check all the child Usb IO handles in this bus, recursively connecte if it is wanted usb child device + + @param UsbBusId point to EFI_USB_BUS_PROTOCOL interface + + @retval EFI_SUCCESS + @retval EFI_INVALID_PARAMETER + @retval EFI_OUT_OF_RESOURCES + +**/ +EFI_STATUS +EFIAPI +UsbBusRecursivelyConnectWantedUsbIo ( + IN EFI_USB_BUS_PROTOCOL *UsbBusId + ) +{ + USB_BUS *Bus; + EFI_STATUS Status; + UINTN Index; + EFI_USB_IO_PROTOCOL *UsbIo; + USB_INTERFACE *UsbIf; + UINTN UsbIoHandleCount; + EFI_HANDLE *UsbIoBuffer; + EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath; + + if (UsbBusId == NULL){ + return EFI_INVALID_PARAMETER; + } + + Bus = USB_BUS_FROM_THIS (UsbBusId); + + // + // Get all Usb IO handles in system + // + UsbIoHandleCount = 0; + Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &UsbIoHandleCount, &UsbIoBuffer); + if (Status == EFI_NOT_FOUND || UsbIoHandleCount == 0) { + return EFI_SUCCESS; + } + ASSERT (!EFI_ERROR (Status)); + + for (Index = 0; Index < UsbIoHandleCount; Index++) { + // + // Check whether the USB IO handle is a child of this bus + // Note: The usb child handle maybe invalid because of hot plugged out during the loop + // + UsbIoDevicePath = NULL; + Status = gBS->HandleProtocol (UsbIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &UsbIoDevicePath); + if (EFI_ERROR (Status) || UsbIoDevicePath == NULL) { + continue; + } + if (CompareMem ( + UsbIoDevicePath, + Bus->DevicePath, + (GetDevicePathSize (Bus->DevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL)) + ) != 0) { + continue; + } + + // + // Get the child Usb IO interface + // + Status = gBS->HandleProtocol( + UsbIoBuffer[Index], + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo + ); + if (EFI_ERROR (Status)) { + continue; + } + UsbIf = USB_INTERFACE_FROM_USBIO (UsbIo); + + if (UsbBusIsWantedUsbIO (Bus, UsbIf)) { + if (!UsbIf->IsManaged) { + // + // Recursively connect the wanted Usb Io handle + // + DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL before connect is %d\n", UsbGetCurrentTpl ())); + Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE); + UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl())); + } + } + } + + return EFI_SUCCESS; +} + diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c index 910ebc5d23..332871a685 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.c @@ -868,6 +868,192 @@ ON_EXIT: return Status; } + +/** + Install Usb Bus Protocol on host controller, and start the Usb bus + + @param This The USB bus driver binding instance + @param Controller The controller to check + @param RemainingDevicePath The remaining device patch + + @retval EFI_SUCCESS The controller is controlled by the usb bus + @retval EFI_ALREADY_STARTED The controller is already controlled by the usb bus + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources + +**/ +EFI_STATUS +EFIAPI +UsbBusBuildProtocol ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + USB_BUS *UsbBus; + USB_DEVICE *RootHub; + USB_INTERFACE *RootIf; + EFI_STATUS Status; + EFI_STATUS Status2; + + UsbBus = AllocateZeroPool (sizeof (USB_BUS)); + + if (UsbBus == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UsbBus->Signature = USB_BUS_SIGNATURE; + UsbBus->HostHandle = Controller; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbBus->DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status)); + + gBS->FreePool (UsbBus); + return Status; + } + + // + // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI). + // This is for backward compatbility with EFI 1.x. In UEFI + // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2 + // and USB_HC because EHCI driver will install both protocols + // (for the same reason). If we don't consume both of them, + // the unconsumed one may be opened by others. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsb2HcProtocolGuid, + (VOID **) &(UsbBus->Usb2Hc), + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + Status2 = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + (VOID **) &(UsbBus->UsbHc), + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status) && EFI_ERROR (Status2)) { + DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status)); + + Status = EFI_DEVICE_ERROR; + goto CLOSE_HC; + } + + UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL); + UsbHcSetState (UsbBus, EfiUsbHcStateOperational); + + // + // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it. + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &mUsbBusProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbBus->BusId + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status)); + goto CLOSE_HC; + } + + // + // Initial the wanted child device path list, and add first RemainingDevicePath + // + InitializeListHead (&UsbBus->WantedUsbIoDPList); + Status = UsbBusAddWantedUsbIoDP (&UsbBus->BusId, RemainingDevicePath); + ASSERT (!EFI_ERROR (Status)); + // + // Create a fake usb device for root hub + // + RootHub = AllocateZeroPool (sizeof (USB_DEVICE)); + + if (RootHub == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto UNINSTALL_USBBUS; + } + + RootIf = AllocateZeroPool (sizeof (USB_INTERFACE)); + + if (RootIf == NULL) { + gBS->FreePool (RootHub); + Status = EFI_OUT_OF_RESOURCES; + goto FREE_ROOTHUB; + } + + RootHub->Bus = UsbBus; + RootHub->NumOfInterface = 1; + RootHub->Interfaces[0] = RootIf; + RootIf->Signature = USB_INTERFACE_SIGNATURE; + RootIf->Device = RootHub; + RootIf->DevicePath = UsbBus->DevicePath; + + Status = mUsbRootHubApi.Init (RootIf); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status)); + goto FREE_ROOTHUB; + } + + UsbBus->Devices[0] = RootHub; + + DEBUG ((EFI_D_INFO, "UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf)); + return EFI_SUCCESS; + +FREE_ROOTHUB: + if (RootIf != NULL) { + gBS->FreePool (RootIf); + } + if (RootHub != NULL) { + gBS->FreePool (RootHub); + } + +UNINSTALL_USBBUS: + gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &UsbBus->BusId); + +CLOSE_HC: + if (UsbBus->Usb2Hc != NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiUsb2HcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + if (UsbBus->UsbHc != NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBus); + + DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status)); + return Status; +} + EFI_USB_IO_PROTOCOL mUsbIoProtocol = { UsbIoControlTransfer, UsbIoBulkTransfer, @@ -952,8 +1138,10 @@ UsbBusControllerDriverSupported ( DevicePathNode.DevPath = RemainingDevicePath; if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) || - (DevicePathNode.DevPath->SubType != MSG_USB_DP) || - (DevicePathNodeLength (DevicePathNode.DevPath) != sizeof (USB_DEVICE_PATH))) { + (DevicePathNode.DevPath->SubType != MSG_USB_DP && + DevicePathNode.DevPath->SubType != MSG_USB_CLASS_DP + && DevicePathNode.DevPath->SubType != MSG_USB_WWID_DP + )) { return EFI_UNSUPPORTED; } @@ -1060,12 +1248,8 @@ UsbBusControllerDriverStart ( IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { - USB_BUS *UsbBus; - USB_DEVICE *RootHub; - USB_INTERFACE *RootIf; - EFI_USB_BUS_PROTOCOL *UsbBusId; - EFI_STATUS Status; - EFI_STATUS Status2; + EFI_USB_BUS_PROTOCOL *UsbBusId; + EFI_STATUS Status; // // Locate the USB bus protocol, if it is found, USB bus @@ -1080,161 +1264,47 @@ UsbBusControllerDriverStart ( EFI_OPEN_PROTOCOL_GET_PROTOCOL ); - if (!EFI_ERROR (Status)) { - return EFI_ALREADY_STARTED; - } - - UsbBus = AllocateZeroPool (sizeof (USB_BUS)); - - if (UsbBus == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - UsbBus->Signature = USB_BUS_SIGNATURE; - UsbBus->HostHandle = Controller; - - Status = gBS->OpenProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - (VOID **) &UsbBus->DevicePath, - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - if (EFI_ERROR (Status)) { - DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to open device path %r\n", Status)); - - gBS->FreePool (UsbBus); - return Status; - } - - // - // Get USB_HC2/USB_HC host controller protocol (EHCI/UHCI). - // This is for backward compatbility with EFI 1.x. In UEFI - // 2.x, USB_HC2 replaces USB_HC. We will open both USB_HC2 - // and USB_HC because EHCI driver will install both protocols - // (for the same reason). If we don't consume both of them, - // the unconsumed one may be opened by others. - // - Status = gBS->OpenProtocol ( - Controller, - &gEfiUsb2HcProtocolGuid, - (VOID **) &(UsbBus->Usb2Hc), - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - Status2 = gBS->OpenProtocol ( - Controller, - &gEfiUsbHcProtocolGuid, - (VOID **) &(UsbBus->UsbHc), - This->DriverBindingHandle, - Controller, - EFI_OPEN_PROTOCOL_BY_DRIVER - ); - - if (EFI_ERROR (Status) && EFI_ERROR (Status2)) { - DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to open USB_HC/USB2_HC %r\n", Status)); - - Status = EFI_DEVICE_ERROR; - goto CLOSE_HC; - } - - UsbHcReset (UsbBus, EFI_USB_HC_RESET_GLOBAL); - UsbHcSetState (UsbBus, EfiUsbHcStateOperational); - - // - // Install an EFI_USB_BUS_PROTOCOL to host controler to identify it. - // - Status = gBS->InstallProtocolInterface ( - &Controller, - &mUsbBusProtocolGuid, - EFI_NATIVE_INTERFACE, - &UsbBus->BusId - ); - - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBusStart: Failed to install bus protocol %r\n", Status)); - goto CLOSE_HC; - } - - // - // Create a fake usb device for root hub - // - RootHub = AllocateZeroPool (sizeof (USB_DEVICE)); - - if (RootHub == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto UNINSTALL_USBBUS; - } - - RootIf = AllocateZeroPool (sizeof (USB_INTERFACE)); - - if (RootIf == NULL) { - gBS->FreePool (RootHub); - Status = EFI_OUT_OF_RESOURCES; - goto FREE_ROOTHUB; - } - - RootHub->Bus = UsbBus; - RootHub->NumOfInterface = 1; - RootHub->Interfaces[0] = RootIf; - RootIf->Signature = USB_INTERFACE_SIGNATURE; - RootIf->Device = RootHub; - RootIf->DevicePath = UsbBus->DevicePath; - - Status = mUsbRootHubApi.Init (RootIf); - - if (EFI_ERROR (Status)) { - DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to init root hub %r\n", Status)); - goto FREE_ROOTHUB; + // + // If first start, build the bus execute enviorment and install bus protocol + // + Status = UsbBusBuildProtocol (This, Controller, RemainingDevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Try get the Usb Bus protocol interface again + // + Status = gBS->OpenProtocol ( + Controller, + &mUsbBusProtocolGuid, + (VOID **) &UsbBusId, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT (!EFI_ERROR (Status)); + } else { + // + // USB Bus driver need to control the recursive connect policy of the bus, only those wanted + // usb child device will be recursively connected. + // The RemainingDevicePath indicate the child usb device which user want to fully recursively connecte this time. + // All wanted usb child devices will be remembered by the usb bus driver itself. + // If RemainingDevicePath == NULL, all the usb child devices in the usb bus are wanted devices. + // + // Save the passed in RemainingDevicePath this time + // + Status = UsbBusAddWantedUsbIoDP (UsbBusId, RemainingDevicePath); + ASSERT (!EFI_ERROR (Status)); + // + // Ensure all wanted child usb devices are fully recursively connected + // + Status = UsbBusRecursivelyConnectWantedUsbIo (UsbBusId); + ASSERT (!EFI_ERROR (Status)); } - UsbBus->Devices[0] = RootHub; - DEBUG (( EFI_D_INFO, "UsbBusStart: usb bus started on %x, root hub %x\n", Controller, RootIf)); return EFI_SUCCESS; - -FREE_ROOTHUB: - if (RootIf != NULL) { - gBS->FreePool (RootIf); - } - if (RootHub != NULL) { - gBS->FreePool (RootHub); - } - -UNINSTALL_USBBUS: - gBS->UninstallProtocolInterface (Controller, &mUsbBusProtocolGuid, &UsbBus->BusId); - -CLOSE_HC: - if (UsbBus->Usb2Hc != NULL) { - gBS->CloseProtocol ( - Controller, - &gEfiUsb2HcProtocolGuid, - This->DriverBindingHandle, - Controller - ); - } - if (UsbBus->UsbHc != NULL) { - gBS->CloseProtocol ( - Controller, - &gEfiUsbHcProtocolGuid, - This->DriverBindingHandle, - Controller - ); - } - gBS->CloseProtocol ( - Controller, - &gEfiDevicePathProtocolGuid, - This->DriverBindingHandle, - Controller - ); - gBS->FreePool (UsbBus); - - DEBUG (( EFI_D_ERROR, "UsbBusStart: Failed to start bus driver %r\n", Status)); - return Status; } @@ -1274,7 +1344,10 @@ UsbBusControllerDriverStop ( Status = EFI_SUCCESS; if (NumberOfChildren > 0) { - OldTpl = gBS->RaiseTPL (USB_BUS_TPL); + // + // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict + // + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); for (Index = 0; Index < NumberOfChildren; Index++) { Status = gBS->OpenProtocol ( @@ -1329,7 +1402,9 @@ UsbBusControllerDriverStop ( // // Stop the root hub, then free all the devices // - OldTpl = gBS->RaiseTPL (USB_BUS_TPL); + // BugBug: Raise TPL to callback level instead of USB_BUS_TPL to avoid TPL conflict + // + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); UsbHcSetState (Bus, EfiUsbHcStateHalt); RootHub = Bus->Devices[0]; @@ -1347,6 +1422,8 @@ UsbBusControllerDriverStop ( gBS->FreePool (RootIf); gBS->FreePool (RootHub); + Status = UsbBusFreeUsbDPList (&Bus->WantedUsbIoDPList); + ASSERT (!EFI_ERROR (Status)); // // Uninstall the bus identifier and close USB_HC/USB2_HC protocols diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h index 971e01b47a..e85fc84fe8 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/usbbus.h @@ -32,6 +32,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include #include #include #include @@ -75,7 +76,7 @@ enum { // USB_WAIT_PORT_STABLE_STALL = 100 * USB_BUS_1_MILLISECOND, - // + // // Wait for port statue reg change, set by experience // USB_WAIT_PORT_STS_CHANGE_STALL = 5 * USB_BUS_1_MILLISECOND, @@ -98,8 +99,8 @@ enum { USB_SET_PORT_POWER_STALL = 2 * USB_BUS_1_MILLISECOND, // - // Wait for port reset, refers to specification - // [USB20-7.1.7.5, it says 10ms for hub and 50ms for + // Wait for port reset, refers to specification + // [USB20-7.1.7.5, it says 10ms for hub and 50ms for // root hub] // USB_SET_PORT_RESET_STALL = 20 * USB_BUS_1_MILLISECOND, @@ -112,11 +113,11 @@ enum { // // Wait for set roothub port enable, set by experience - // + // USB_SET_ROOT_PORT_ENABLE_STALL = 20 * USB_BUS_1_MILLISECOND, // - // Send general device request timeout, refers to + // Send general device request timeout, refers to // specification[USB20-11.24.1] // USB_GENERAL_DEVICE_REQUEST_TIMEOUT = 50 * USB_BUS_1_MILLISECOND, @@ -125,7 +126,7 @@ enum { // Send clear feature request timeout, set by experience // USB_CLEAR_FEATURE_REQUEST_TIMEOUT = 10 * USB_BUS_1_MILLISECOND, - + // // Bus raises TPL to TPL_NOTIFY to serialize all its operations // to protect shared data structures. @@ -251,8 +252,59 @@ struct _USB_BUS { // for root hub. Device with address i is at Devices[i]. // USB_DEVICE *Devices[USB_MAX_DEVICES]; + + // + // USB Bus driver need to control the recursive connect policy of the bus, only those wanted + // usb child device will be recursively connected. + // + // WantedUsbIoDPList tracks the Usb child devices which user want to recursivly fully connecte, + // every wanted child device is stored in a item of the WantedUsbIoDPList, whose structrure is + // DEVICE_PATH_LIST_ITEM + // + LIST_ENTRY WantedUsbIoDPList; + }; +#define USB_US_LAND_ID 0x0409 + +#define DEVICE_PATH_LIST_ITEM_SIGNATURE EFI_SIGNATURE_32('d','p','l','i') +typedef struct _DEVICE_PATH_LIST_ITEM{ + UINTN Signature; + LIST_ENTRY Link; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; +} DEVICE_PATH_LIST_ITEM; + +typedef struct { + USB_CLASS_DEVICE_PATH UsbClass; + EFI_DEVICE_PATH_PROTOCOL End; +} USB_CLASS_FORMAT_DEVICE_PATH; + +EFI_STATUS +EFIAPI +UsbBusFreeUsbDPList ( + IN LIST_ENTRY *UsbIoDPList + ); + +EFI_STATUS +EFIAPI +UsbBusAddWantedUsbIoDP ( + IN EFI_USB_BUS_PROTOCOL *UsbBusId, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +BOOLEAN +EFIAPI +UsbBusIsWantedUsbIO ( + IN USB_BUS *Bus, + IN USB_INTERFACE *UsbIf + ); + +EFI_STATUS +EFIAPI +UsbBusRecursivelyConnectWantedUsbIo ( + IN EFI_USB_BUS_PROTOCOL *UsbBusId + ); + extern EFI_USB_IO_PROTOCOL mUsbIoProtocol; extern EFI_DRIVER_BINDING_PROTOCOL mUsbBusDriverBinding; extern EFI_COMPONENT_NAME_PROTOCOL mUsbBusComponentName;