diff options
| author | Jared Pan <jared.pan@dell.com> | 2026-06-23 11:43:07 +0800 |
|---|---|---|
| committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2026-06-30 11:47:34 +0000 |
| commit | 8c0dea946f5187016fc79e723275f9c94024d725 (patch) | |
| tree | c9b890a5b807768cc65ecf8196a53982ceb73d1b | |
| parent | 23ebccb46c5c9e594fe777fef9ede4de2e4b584d (diff) | |
| download | edk2-8c0dea946f5187016fc79e723275f9c94024d725.tar.gz edk2-8c0dea946f5187016fc79e723275f9c94024d725.zip | |
MdeModulePkg/UsbBusDxe: Manufacturer String Descriptor Caching
Certain devices require immediate follow-up commands
after reading the LANGID string to fetch Manufacturer,
Product, or SerialNumber strings.
[Suggested Solution]
These strings are now cached after initial retrieval
to allow UsbIoGetStringDescriptor() to return them
directly, improving efficiency and stability.
Signed-off-by: Marlboro Chuang <marlboro.chuang@dell.com>
Signed-off-by: Jared Pan <jared.pan@dell.com>
| -rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h | 2 | ||||
| -rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c | 162 | ||||
| -rw-r--r-- | MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h | 3 |
3 files changed, 142 insertions, 25 deletions
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h index ac0cbab359..bc4f7ceb02 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBus.h @@ -289,7 +289,7 @@ struct _USB_HUB_API { USB_HUB_RELEASE Release;
};
-#define USB_US_LAND_ID 0x0409
+#define USB_US_LANG_ID 0x0409
#define DEVICE_PATH_LIST_ITEM_SIGNATURE SIGNATURE_32('d','p','l','i')
typedef struct _DEVICE_PATH_LIST_ITEM {
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c index f0c3cc7ced..3f55c3a381 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.c @@ -114,6 +114,18 @@ UsbFreeDevDesc ( FreePool (DevDesc->Configs);
}
+ if (DevDesc->StrDescManufacturerUS != NULL) {
+ FreePool (DevDesc->StrDescManufacturerUS);
+ }
+
+ if (DevDesc->StrDescProductUS != NULL) {
+ FreePool (DevDesc->StrDescProductUS);
+ }
+
+ if (DevDesc->StrDescSerialNumberUS != NULL) {
+ FreePool (DevDesc->StrDescSerialNumberUS);
+ }
+
FreePool (DevDesc);
}
@@ -654,41 +666,93 @@ UsbGetOneString ( EFI_USB_STRING_DESCRIPTOR Desc;
EFI_STATUS Status;
UINT8 *Buf;
+ EFI_USB_STRING_DESCRIPTOR *CachedDesc;
+
+ CachedDesc = NULL;
//
- // First get two bytes which contains the string length.
+ // If the String is cached and LangId = US, just return the cached string descriptor
//
- Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);
+ if ((LangId == USB_US_LANG_ID) && (Index > 0)) {
+ Buf = NULL;
+
+ if (Index == UsbDev->DevDesc->Desc.StrManufacturer) {
+ if (UsbDev->DevDesc->StrDescManufacturerUS != NULL) {
+ CachedDesc = (EFI_USB_STRING_DESCRIPTOR *)UsbDev->DevDesc->StrDescManufacturerUS;
+ Buf = AllocateZeroPool (CachedDesc->Length);
+ CopyMem (Buf, (UINT8 *)CachedDesc, CachedDesc->Length);
+ }
+ } else if (Index == UsbDev->DevDesc->Desc.StrProduct) {
+ if (UsbDev->DevDesc->StrDescProductUS != NULL) {
+ CachedDesc = (EFI_USB_STRING_DESCRIPTOR *)UsbDev->DevDesc->StrDescProductUS;
+ Buf = AllocateZeroPool (CachedDesc->Length);
+ CopyMem (Buf, (UINT8 *)CachedDesc, CachedDesc->Length);
+ }
+ } else if (Index == UsbDev->DevDesc->Desc.StrSerialNumber) {
+ if (UsbDev->DevDesc->StrDescSerialNumberUS != NULL) {
+ CachedDesc = (EFI_USB_STRING_DESCRIPTOR *)UsbDev->DevDesc->StrDescSerialNumberUS;
+ Buf = AllocateZeroPool (CachedDesc->Length);
+ CopyMem (Buf, (UINT8 *)CachedDesc, CachedDesc->Length);
+ }
+ } else {
+ Buf = NULL;
+ }
+
+ if (Buf != NULL) {
+ return (EFI_USB_STRING_DESCRIPTOR *)Buf;
+ }
+ }
//
- // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even.
+ // Copy the mechanism from Linux Driver to get the better compatibility. see usb_string_sub.
//
+ Buf = AllocateZeroPool (256);
+ Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, Buf, 255);
if (EFI_ERROR (Status) ||
- (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) ||
- (Desc.Length % 2 != 0)
- )
+ (((EFI_USB_STRING_DESCRIPTOR *)Buf)->Length <
+ OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) +
+ sizeof (((EFI_USB_STRING_DESCRIPTOR *)Buf)->Length)) ||
+ (((EFI_USB_STRING_DESCRIPTOR *)Buf)->Length % 2 != 0))
{
- return NULL;
- }
+ DEBUG ((DEBUG_ERROR, "UsbGetOneString: Get 255 bytes path failed, Status = %r\n", Status));
+ FreePool (Buf);
+ Buf = NULL;
- Buf = AllocateZeroPool (Desc.Length);
+ //
+ // First get two bytes which contains the string length.
+ //
+ Status = UsbCtrlGetDesc (UsbDev, USB_DESC_TYPE_STRING, Index, LangId, &Desc, 2);
- if (Buf == NULL) {
- return NULL;
- }
+ //
+ // Reject if Length even cannot cover itself, or odd because Unicode string byte length should be even.
+ //
+ if (EFI_ERROR (Status) ||
+ (Desc.Length < OFFSET_OF (EFI_USB_STRING_DESCRIPTOR, Length) + sizeof (Desc.Length)) ||
+ (Desc.Length % 2 != 0)
+ )
+ {
+ return NULL;
+ }
- Status = UsbCtrlGetDesc (
- UsbDev,
- USB_DESC_TYPE_STRING,
- Index,
- LangId,
- Buf,
- Desc.Length
- );
+ Buf = AllocateZeroPool (Desc.Length);
- if (EFI_ERROR (Status)) {
- FreePool (Buf);
- return NULL;
+ if (Buf == NULL) {
+ return NULL;
+ }
+
+ Status = UsbCtrlGetDesc (
+ UsbDev,
+ USB_DESC_TYPE_STRING,
+ Index,
+ LangId,
+ Buf,
+ Desc.Length
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buf);
+ return NULL;
+ }
}
return (EFI_USB_STRING_DESCRIPTOR *)Buf;
@@ -740,8 +804,58 @@ UsbBuildLangTable ( UsbDev->TotalLangId = (UINT16)Max;
-ON_EXIT:
+ //
+ // Some SMART Technologies key says that it supports LangId=0 only, but it
+ // responds to USB_US_LANG_ID (English). This is a workaround for all such keys.
+ //
+ if ((UsbDev->TotalLangId == 1) && (UsbDev->LangId[0] == 0)) {
+ UsbDev->LangId[0] = USB_US_LANG_ID;
+ }
+
+ //
+ // Some devices need to get the string immediately after SW get the first String descriptor
+ // for supported language.
+ //
gBS->FreePool (Desc);
+ Desc = NULL;
+ if (UsbDev->DevDesc->Desc.StrManufacturer != 0) {
+ Desc = UsbGetOneString (UsbDev, UsbDev->DevDesc->Desc.StrManufacturer, UsbDev->LangId[0]);
+ if ((Desc != NULL) && (UsbDev->LangId[0] == USB_US_LANG_ID)) {
+ UsbDev->DevDesc->StrDescManufacturerUS = (UINT8 *)Desc;
+ } else if (Desc != NULL) {
+ gBS->FreePool (Desc);
+ }
+
+ Desc = NULL;
+ }
+
+ if (UsbDev->DevDesc->Desc.StrProduct != 0) {
+ Desc = UsbGetOneString (UsbDev, UsbDev->DevDesc->Desc.StrProduct, UsbDev->LangId[0]);
+ if ((Desc != NULL) && (UsbDev->LangId[0] == USB_US_LANG_ID)) {
+ UsbDev->DevDesc->StrDescProductUS = (UINT8 *)Desc;
+ } else if (Desc != NULL) {
+ gBS->FreePool (Desc);
+ }
+
+ Desc = NULL;
+ }
+
+ if (UsbDev->DevDesc->Desc.StrSerialNumber != 0) {
+ Desc = UsbGetOneString (UsbDev, UsbDev->DevDesc->Desc.StrSerialNumber, UsbDev->LangId[0]);
+ if ((Desc != NULL) && (UsbDev->LangId[0] == USB_US_LANG_ID)) {
+ UsbDev->DevDesc->StrDescSerialNumberUS = (UINT8 *)Desc;
+ } else if (Desc != NULL) {
+ gBS->FreePool (Desc);
+ }
+
+ Desc = NULL;
+ }
+
+ON_EXIT:
+ if (Desc != NULL) {
+ gBS->FreePool (Desc);
+ }
+
return Status;
}
diff --git a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h index de11ade8ef..9d4540bff9 100644 --- a/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h +++ b/MdeModulePkg/Bus/Usb/UsbBusDxe/UsbDesc.h @@ -68,6 +68,9 @@ typedef struct { typedef struct {
EFI_USB_DEVICE_DESCRIPTOR Desc;
USB_CONFIG_DESC **Configs;
+ UINT8 *StrDescManufacturerUS;
+ UINT8 *StrDescProductUS;
+ UINT8 *StrDescSerialNumberUS;
} USB_DEVICE_DESC;
/**
|
