]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[usb] Use non-zero language ID to retrieve strings
authorMichael Brown <mcb30@ipxe.org>
Mon, 3 Jul 2017 12:38:55 +0000 (13:38 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 3 Jul 2017 12:38:55 +0000 (13:38 +0100)
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>
src/drivers/bus/usb.c
src/include/ipxe/usb.h

index bd2a446be0d205ddb8e8883a5f4b3b07d9f2828c..d8db3849acefd384520d2c0dca549d96140292ef 100644 (file)
@@ -843,12 +843,40 @@ int usb_control ( struct usb_device *usb, unsigned int request,
        return rc;
 }
 
+/**
+ * Get default language ID
+ *
+ * @v usb              USB device
+ * @ret language       Language ID
+ */
+static unsigned int usb_get_default_language ( struct usb_device *usb ) {
+       struct {
+               struct usb_descriptor_header header;
+               uint16_t language[1];
+       } __attribute__ (( packed )) desc;
+       unsigned int language;
+       int rc;
+
+       /* Get descriptor */
+       if ( ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, 0, 0,
+                                        &desc.header, sizeof ( desc ) ) ) !=0){
+               DBGC ( usb, "USB %s has no default language: %s\n",
+                      usb->name, strerror ( rc ) );
+               return USB_LANG_ENGLISH;
+       }
+
+       /* Use first language ID */
+       language = le16_to_cpu ( desc.language[0] );
+       DBGC2 ( usb, "USB %s default language %#04x\n", usb->name, language );
+       return language;
+}
+
 /**
  * Get USB string descriptor
  *
  * @v usb              USB device
  * @v index            String index
- * @v language         Language ID
+ * @v language         Language ID, or 0 to use default
  * @v buf              Data buffer
  * @v len              Length of buffer
  * @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,
        unsigned int i;
        int rc;
 
+       /* Use default language ID, if applicable */
+       if ( ( language == 0 ) && ( index != 0 ) ) {
+               if ( ! usb->language )
+                       usb->language = usb_get_default_language ( usb );
+               language = usb->language;
+       }
+
        /* Allocate buffer for string */
        desc = malloc ( sizeof ( *desc ) );
        if ( ! desc ) {
index e7909d300aad2567ccd8669445672eaf1c2ebef9..68289d26d8d816e8d566005f4bd0e13c3cacbc9b 100644 (file)
@@ -223,6 +223,9 @@ struct usb_string_descriptor {
 /** A USB string descriptor */
 #define USB_STRING_DESCRIPTOR 3
 
+/** Language ID for English */
+#define USB_LANG_ENGLISH 0x0409
+
 /** A USB interface descriptor */
 struct usb_interface_descriptor {
        /** Descriptor header */
@@ -728,6 +731,9 @@ struct usb_device {
        struct usb_endpoint control;
        /** Completed control transfers */
        struct list_head complete;
+
+       /** Default language ID (if known) */
+       unsigned int language;
 };
 
 /** USB device host controller operations */