summaryrefslogtreecommitdiffstats
path: root/src/drivers
diff options
context:
space:
mode:
authorMichael Brown2017-07-03 14:38:55 +0200
committerMichael Brown2017-07-03 14:38:55 +0200
commit8e48d0df6b5a249e4f9f0759cc55a45af186b564 (patch)
tree70929b5441de37f12002fd110475cf18bd6b122e /src/drivers
parent[exanic] Add driver for Exablaze ExaNIC cards (diff)
downloadipxe-8e48d0df6b5a249e4f9f0759cc55a45af186b564.tar.gz
ipxe-8e48d0df6b5a249e4f9f0759cc55a45af186b564.tar.xz
ipxe-8e48d0df6b5a249e4f9f0759cc55a45af186b564.zip
[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>
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/bus/usb.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c
index bd2a446b..d8db3849 100644
--- a/src/drivers/bus/usb.c
+++ b/src/drivers/bus/usb.c
@@ -844,11 +844,39 @@ int usb_control ( struct usb_device *usb, unsigned int request,
}
/**
+ * 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 ) {