Browse Source

[usb] Use non-zero language ID to retrieve strings

We currently use a zero language ID to retrieve strings such as the
ECM/NCM MAC address.  This works on most hardware devices, but is
known to fail on some software emulated CDC-NCM devices.

Fix by using the first supported language ID, falling back to English
(0x0409) if any error occurs when fetching the list of supported
languages.  This matches the behaviour of the Linux kernel.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 6 years ago
parent
commit
8e48d0df6b
2 changed files with 42 additions and 1 deletions
  1. 36
    1
      src/drivers/bus/usb.c
  2. 6
    0
      src/include/ipxe/usb.h

+ 36
- 1
src/drivers/bus/usb.c View File

@@ -843,12 +843,40 @@ int usb_control ( struct usb_device *usb, unsigned int request,
843 843
 	return rc;
844 844
 }
845 845
 
846
+/**
847
+ * Get default language ID
848
+ *
849
+ * @v usb		USB device
850
+ * @ret language	Language ID
851
+ */
852
+static unsigned int usb_get_default_language ( struct usb_device *usb ) {
853
+	struct {
854
+		struct usb_descriptor_header header;
855
+		uint16_t language[1];
856
+	} __attribute__ (( packed )) desc;
857
+	unsigned int language;
858
+	int rc;
859
+
860
+	/* Get descriptor */
861
+	if ( ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, 0, 0,
862
+					 &desc.header, sizeof ( desc ) ) ) !=0){
863
+		DBGC ( usb, "USB %s has no default language: %s\n",
864
+		       usb->name, strerror ( rc ) );
865
+		return USB_LANG_ENGLISH;
866
+	}
867
+
868
+	/* Use first language ID */
869
+	language = le16_to_cpu ( desc.language[0] );
870
+	DBGC2 ( usb, "USB %s default language %#04x\n", usb->name, language );
871
+	return language;
872
+}
873
+
846 874
 /**
847 875
  * Get USB string descriptor
848 876
  *
849 877
  * @v usb		USB device
850 878
  * @v index		String index
851
- * @v language		Language ID
879
+ * @v language		Language ID, or 0 to use default
852 880
  * @v buf		Data buffer
853 881
  * @v len		Length of buffer
854 882
  * @ret len		String length (excluding NUL), or negative error
@@ -864,6 +892,13 @@ int usb_get_string_descriptor ( struct usb_device *usb, unsigned int index,
864 892
 	unsigned int i;
865 893
 	int rc;
866 894
 
895
+	/* Use default language ID, if applicable */
896
+	if ( ( language == 0 ) && ( index != 0 ) ) {
897
+		if ( ! usb->language )
898
+			usb->language = usb_get_default_language ( usb );
899
+		language = usb->language;
900
+	}
901
+
867 902
 	/* Allocate buffer for string */
868 903
 	desc = malloc ( sizeof ( *desc ) );
869 904
 	if ( ! desc ) {

+ 6
- 0
src/include/ipxe/usb.h View File

@@ -223,6 +223,9 @@ struct usb_string_descriptor {
223 223
 /** A USB string descriptor */
224 224
 #define USB_STRING_DESCRIPTOR 3
225 225
 
226
+/** Language ID for English */
227
+#define USB_LANG_ENGLISH 0x0409
228
+
226 229
 /** A USB interface descriptor */
227 230
 struct usb_interface_descriptor {
228 231
 	/** Descriptor header */
@@ -728,6 +731,9 @@ struct usb_device {
728 731
 	struct usb_endpoint control;
729 732
 	/** Completed control transfers */
730 733
 	struct list_head complete;
734
+
735
+	/** Default language ID (if known) */
736
+	unsigned int language;
731 737
 };
732 738
 
733 739
 /** USB device host controller operations */

Loading…
Cancel
Save