diff --git a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c index 5fa7facfca..27df8a4b56 100644 --- a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c +++ b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.c @@ -202,8 +202,7 @@ ConPlatformDriverBindingSupported ( Start this driver on ControllerHandle by opening Simple Text Input Protocol, reading Device Path, and installing Console In Devcice GUID on ControllerHandle. - If this devcie is not one hot-plug devce, append its device path into the - console environment variables ConInDev. + Append its device path into the console environment variables ConInDev. @param This Protocol instance pointer. @param ControllerHandle Handle of device to bind driver to @@ -270,58 +269,32 @@ ConPlatformTextInDriverBindingStart ( } // - // Check the device path, if it is a hot plug device, - // do not put the device path into ConInDev, and install - // gEfiConsoleInDeviceGuid to the device handle directly. - // The policy is, make hot plug device plug in and play immediately. + // Append the device path to the ConInDev environment variable // - if (IsHotPlugDevice (DevicePath)) { + ConPlatformUpdateDeviceVariable ( + L"ConInDev", + DevicePath, + Append + ); + + // + // If the device path is an instance in the ConIn environment variable, + // then install EfiConsoleInDeviceGuid onto ControllerHandle + // + if (IsInConInVariable) { gBS->InstallMultipleProtocolInterfaces ( &ControllerHandle, &gEfiConsoleInDeviceGuid, NULL, NULL ); - // - // Append the device path to ConInDev only if it is in ConIn variable. - // - if (IsInConInVariable) { - ConPlatformUpdateDeviceVariable ( - L"ConInDev", - DevicePath, - Append - ); - } } else { - // - // If it is not a hot-plug device, append the device path to the - // ConInDev environment variable - // - ConPlatformUpdateDeviceVariable ( - L"ConInDev", - DevicePath, - Append - ); - - // - // If the device path is an instance in the ConIn environment variable, - // then install EfiConsoleInDeviceGuid onto ControllerHandle - // - if (IsInConInVariable) { - gBS->InstallMultipleProtocolInterfaces ( - &ControllerHandle, - &gEfiConsoleInDeviceGuid, - NULL, - NULL - ); - } else { - gBS->CloseProtocol ( - ControllerHandle, - &gEfiSimpleTextInProtocolGuid, - This->DriverBindingHandle, - ControllerHandle - ); - } + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleTextInProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); } return EFI_SUCCESS; @@ -334,8 +307,7 @@ ConPlatformTextInDriverBindingStart ( reading Device Path, and installing Console Out Devcic GUID, Standard Error Device GUID on ControllerHandle. - If this devcie is not one hot-plug devce, append its device path into the - console environment variables ConOutDev, ErrOutDev. + Append its device path into the console environment variables ConOutDev, ErrOutDev. @param This Protocol instance pointer. @param ControllerHandle Handle of device to bind driver to @@ -416,95 +388,59 @@ ConPlatformTextOutDriverBindingStart ( } // - // Check the device path, if it is a hot plug device, - // do not put the device path into ConOutDev and ErrOutDev, - // and install gEfiConsoleOutDeviceGuid to the device handle directly. - // The policy is, make hot plug device plug in and play immediately. + // Append the device path to the ConOutDev and ErrOutDev environment variable. + // For GOP device path, append the sibling device path as well. // - if (IsHotPlugDevice (DevicePath)) { + if (!ConPlatformUpdateGopCandidate (DevicePath)) { + ConPlatformUpdateDeviceVariable ( + L"ConOutDev", + DevicePath, + Append + ); + // + // Then append the device path to the ErrOutDev environment variable + // + ConPlatformUpdateDeviceVariable ( + L"ErrOutDev", + DevicePath, + Append + ); + } + + // + // If the device path is an instance in the ConOut environment variable, + // then install EfiConsoleOutDeviceGuid onto ControllerHandle + // + if (IsInConOutVariable) { + NeedClose = FALSE; + Status = gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiConsoleOutDeviceGuid, + NULL, + NULL + ); + } + // + // If the device path is an instance in the ErrOut environment variable, + // then install EfiStandardErrorDeviceGuid onto ControllerHandle + // + if (IsInErrOutVariable) { + NeedClose = FALSE; gBS->InstallMultipleProtocolInterfaces ( &ControllerHandle, - &gEfiConsoleOutDeviceGuid, + &gEfiStandardErrorDeviceGuid, NULL, NULL ); - // - // Append the device path to ConOutDev only if it is in ConOut variable. - // - if (IsInConOutVariable) { - ConPlatformUpdateDeviceVariable ( - L"ConOutDev", - DevicePath, - Append - ); - } - // - // Append the device path to ErrOutDev only if it is in ErrOut variable. - // - if (IsInErrOutVariable) { - ConPlatformUpdateDeviceVariable ( - L"ErrOutDev", - DevicePath, - Append - ); - } - } else { - // - // If it is not a hot-plug device, append the device path to - // the ConOutDev and ErrOutDev environment variable. - // For GOP device path, append the sibling device path as well. - // - if (!ConPlatformUpdateGopCandidate (DevicePath)) { - ConPlatformUpdateDeviceVariable ( - L"ConOutDev", - DevicePath, - Append - ); - // - // Then append the device path to the ErrOutDev environment variable - // - ConPlatformUpdateDeviceVariable ( - L"ErrOutDev", - DevicePath, - Append - ); - } + } - // - // If the device path is an instance in the ConOut environment variable, - // then install EfiConsoleOutDeviceGuid onto ControllerHandle - // - if (IsInConOutVariable) { - NeedClose = FALSE; - Status = gBS->InstallMultipleProtocolInterfaces ( - &ControllerHandle, - &gEfiConsoleOutDeviceGuid, - NULL, - NULL - ); - } - // - // If the device path is an instance in the ErrOut environment variable, - // then install EfiStandardErrorDeviceGuid onto ControllerHandle - // - if (IsInErrOutVariable) { - NeedClose = FALSE; - gBS->InstallMultipleProtocolInterfaces ( - &ControllerHandle, - &gEfiStandardErrorDeviceGuid, - NULL, - NULL - ); - } - - if (NeedClose) { - gBS->CloseProtocol ( - ControllerHandle, - &gEfiSimpleTextOutProtocolGuid, - This->DriverBindingHandle, - ControllerHandle - ); - } + if (NeedClose) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiSimpleTextOutProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); } return EFI_SUCCESS; @@ -822,6 +758,273 @@ IsGopSibling ( return (BOOLEAN) (CompareMem (Left, Right, (UINTN) NodeLeft - (UINTN) Left) == 0); } +/** + Check whether a USB device match the specified USB Class device path. This + function follows "Load Option Processing" behavior in UEFI specification. + + @param UsbIo USB I/O protocol associated with the USB device. + @param UsbClass The USB Class device path to match. + + @retval TRUE The USB device match the USB Class device path. + @retval FALSE The USB device does not match the USB Class device path. + +**/ +BOOLEAN +MatchUsbClass ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN USB_CLASS_DEVICE_PATH *UsbClass + ) +{ + EFI_STATUS Status; + EFI_USB_DEVICE_DESCRIPTOR DevDesc; + EFI_USB_INTERFACE_DESCRIPTOR IfDesc; + UINT8 DeviceClass; + UINT8 DeviceSubClass; + UINT8 DeviceProtocol; + + if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) || + (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){ + return FALSE; + } + + // + // Check Vendor Id and Product Id. + // + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if ((UsbClass->VendorId != 0xffff) && + (UsbClass->VendorId != DevDesc.IdVendor)) { + return FALSE; + } + + if ((UsbClass->ProductId != 0xffff) && + (UsbClass->ProductId != DevDesc.IdProduct)) { + return FALSE; + } + + DeviceClass = DevDesc.DeviceClass; + DeviceSubClass = DevDesc.DeviceSubClass; + DeviceProtocol = DevDesc.DeviceProtocol; + if (DeviceClass == 0) { + // + // If Class in Device Descriptor is set to 0, use the Class, SubClass and + // Protocol in Interface Descriptor instead. + // + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc); + if (EFI_ERROR (Status)) { + return FALSE; + } + + DeviceClass = IfDesc.InterfaceClass; + DeviceSubClass = IfDesc.InterfaceSubClass; + DeviceProtocol = IfDesc.InterfaceProtocol; + } + + // + // Check Class, SubClass and Protocol. + // + if ((UsbClass->DeviceClass != 0xff) && + (UsbClass->DeviceClass != DeviceClass)) { + return FALSE; + } + + if ((UsbClass->DeviceSubClass != 0xff) && + (UsbClass->DeviceSubClass != DeviceSubClass)) { + return FALSE; + } + + if ((UsbClass->DeviceProtocol != 0xff) && + (UsbClass->DeviceProtocol != DeviceProtocol)) { + return FALSE; + } + + return TRUE; +} + +/** + Check whether a USB device match the specified USB WWID device path. This + function follows "Load Option Processing" behavior in UEFI specification. + + @param UsbIo USB I/O protocol associated with the USB device. + @param UsbWwid The USB WWID device path to match. + + @retval TRUE The USB device match the USB WWID device path. + @retval FALSE The USB device does not match the USB WWID device path. + +**/ +BOOLEAN +MatchUsbWwid ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN USB_WWID_DEVICE_PATH *UsbWwid + ) +{ + EFI_STATUS Status; + EFI_USB_DEVICE_DESCRIPTOR DevDesc; + EFI_USB_INTERFACE_DESCRIPTOR IfDesc; + UINT16 *LangIdTable; + UINT16 TableSize; + UINT16 Index; + CHAR16 *CompareStr; + UINTN CompareLen; + CHAR16 *SerialNumberStr; + UINTN Length; + + if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) || + (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP)) { + return FALSE; + } + + // + // Check Vendor Id and Product Id. + // + Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); + if (EFI_ERROR (Status)) { + return FALSE; + } + if ((DevDesc.IdVendor != UsbWwid->VendorId) || + (DevDesc.IdProduct != UsbWwid->ProductId)) { + return FALSE; + } + + // + // Check Interface Number. + // + Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc); + if (EFI_ERROR (Status)) { + return FALSE; + } + if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) { + return FALSE; + } + + // + // Check Serial Number. + // + if (DevDesc.StrSerialNumber == 0) { + return FALSE; + } + + // + // Get all supported languages. + // + TableSize = 0; + LangIdTable = NULL; + Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize); + if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) { + return FALSE; + } + + // + // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters. + // + CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1); + CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16); + if (CompareStr[CompareLen - 1] == L'\0') { + CompareLen--; + } + + // + // Compare serial number in each supported language. + // + for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) { + SerialNumberStr = NULL; + Status = UsbIo->UsbGetStringDescriptor ( + UsbIo, + LangIdTable[Index], + DevDesc.StrSerialNumber, + &SerialNumberStr + ); + if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) { + continue; + } + + Length = StrLen (SerialNumberStr); + if ((Length >= CompareLen) && + (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) { + FreePool (SerialNumberStr); + return TRUE; + } + + FreePool (SerialNumberStr); + } + + return FALSE; +} + +/** + Compare whether a full console device path matches a USB shortform device path. + + @param[in] FullPath Full console device path. + @param[in] ShortformPath Short-form device path. Short-form device node may in the beginning or in the middle. + + @retval TRUE The full console device path matches the short-form device path. + @retval FALSE The full console device path doesn't match the short-form device path. +**/ +BOOLEAN +MatchUsbShortformDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *FullPath, + IN EFI_DEVICE_PATH_PROTOCOL *ShortformPath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ShortformNode; + UINTN ParentDevicePathSize; + EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_HANDLE Handle; + + for ( ShortformNode = ShortformPath + ; !IsDevicePathEnd (ShortformNode) + ; ShortformNode = NextDevicePathNode (ShortformNode) + ) { + if ((DevicePathType (ShortformNode) == MESSAGING_DEVICE_PATH) && + ((DevicePathSubType (ShortformNode) == MSG_USB_CLASS_DP) || + (DevicePathSubType (ShortformNode) == MSG_USB_WWID_DP)) + ) { + break; + } + } + + // + // Skip further compare when it's not a shortform device path. + // + if (IsDevicePathEnd (ShortformNode)) { + return FALSE; + } + + // + // Compare the parent device path when the ShortformPath doesn't start with short-form node. + // + ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) ShortformPath; + RemainingDevicePath = FullPath; + Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &RemainingDevicePath, &Handle); + if (EFI_ERROR (Status)) { + return FALSE; + } + if (ParentDevicePathSize != 0) { + if ((ParentDevicePathSize > (UINTN) RemainingDevicePath - (UINTN) FullPath) || + (CompareMem (FullPath, ShortformPath, ParentDevicePathSize) != 0)) { + return FALSE; + } + } + + // + // Compar the USB layer. + // + Status = gBS->HandleProtocol( + Handle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo + ); + ASSERT_EFI_ERROR (Status); + + return MatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *)ShortformNode) || + MatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *)ShortformNode); +} + /** Function compares a device path data structure to that of all the nodes of a second device path instance. @@ -881,7 +1084,8 @@ ConPlatformMatchDevicePaths ( // Search for the match of 'Single' in 'Multi' // while (DevicePathInst != NULL) { - if ((CompareMem (Single, DevicePathInst, Size) == 0) || IsGopSibling (Single, DevicePathInst)) { + if ((CompareMem (Single, DevicePathInst, Size) == 0) || + IsGopSibling (Single, DevicePathInst) || MatchUsbShortformDevicePath (Single, DevicePathInst)) { if (!Delete) { // // If Delete is FALSE, return EFI_SUCCESS if Single is found in Multi. @@ -1029,53 +1233,6 @@ ConPlatformUpdateDeviceVariable ( return Status; } -/** - Check if the device supports hot-plug through its device path. - - This function could be updated to check more types of Hot Plug devices. - Currently, it checks USB and PCCard device. - - @param DevicePath Pointer to device's device path. - - @retval TRUE The devcie is a hot-plug device - @retval FALSE The devcie is not a hot-plug device. - -**/ -BOOLEAN -IsHotPlugDevice ( - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath - ) -{ - EFI_DEVICE_PATH_PROTOCOL *CheckDevicePath; - - CheckDevicePath = DevicePath; - while (!IsDevicePathEnd (CheckDevicePath)) { - // - // Check device whether is hot plug device or not throught Device Path - // - if ((DevicePathType (CheckDevicePath) == MESSAGING_DEVICE_PATH) && - (DevicePathSubType (CheckDevicePath) == MSG_USB_DP || - DevicePathSubType (CheckDevicePath) == MSG_USB_CLASS_DP || - DevicePathSubType (CheckDevicePath) == MSG_USB_WWID_DP)) { - // - // If Device is USB device - // - return TRUE; - } - if ((DevicePathType (CheckDevicePath) == HARDWARE_DEVICE_PATH) && - (DevicePathSubType (CheckDevicePath) == HW_PCCARD_DP)) { - // - // If Device is PCCard - // - return TRUE; - } - - CheckDevicePath = NextDevicePathNode (CheckDevicePath); - } - - return FALSE; -} - /** Update ConOutDev and ErrOutDev variables to add the device path of GOP controller itself and the sibling controllers. diff --git a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h index 1d5f11e94c..b5465f09f1 100644 --- a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h +++ b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatform.h @@ -21,6 +21,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include #include +#include #include #include @@ -119,8 +120,7 @@ ConPlatformTextOutDriverBindingSupported ( Start this driver on ControllerHandle by opening Simple Text Input Protocol, reading Device Path, and installing Console In Devcice GUID on ControllerHandle. - If this devcie is not one hot-plug devce, append its device path into the - console environment variables ConInDev. + Append its device path into the console environment variables ConInDev. @param This Protocol instance pointer. @param ControllerHandle Handle of device to bind driver to @@ -147,8 +147,7 @@ ConPlatformTextInDriverBindingStart ( reading Device Path, and installing Console Out Devcic GUID, Standard Error Device GUID on ControllerHandle. - If this devcie is not one hot-plug devce, append its device path into the - console environment variables ConOutDev, StdErrDev. + Append its device path into the console environment variables ConOutDev, ErrOutDev. @param This Protocol instance pointer. @param ControllerHandle Handle of device to bind driver to @@ -294,23 +293,6 @@ ConPlatformUpdateDeviceVariable ( IN CONPLATFORM_VAR_OPERATION Operation ); -/** - Check if the device supports hot-plug through its device path. - - This function could be updated to check more types of Hot Plug devices. - Currently, it checks USB and PCCard device. - - @param DevicePath Pointer to device's device path. - - @retval TRUE The devcie is a hot-plug device - @retval FALSE The devcie is not a hot-plug device. - -**/ -BOOLEAN -IsHotPlugDevice ( - IN EFI_DEVICE_PATH_PROTOCOL *DevicePath - ); - // // EFI Component Name Functions // diff --git a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf index 176fd2fa0b..19b3f5c443 100644 --- a/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf +++ b/MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf @@ -94,6 +94,7 @@ gEfiSimpleTextOutProtocolGuid ## TO_START gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES + gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES [UserExtensions.TianoCore."ExtraFiles"] ConPlatformDxeExtra.uni