when fetching USB strings, first try the full descriptor and if it works, use it. if not, fall back to the existing method that fetches the first 2 bytes and then the whole string, using the length from the 2 byte reply. fixes a very strange problem where an axe(4) attaching (either has ugen(4) or axe(4)) would ask for 2 bytes, usb_mem.c would allocate a 2 byte fragment, perform the operation, and sometime shortly afterwards (usually by the time the next allocation is made for this fragment), would become corrupted (usually two bytes were written with 0x0304.) (initial request of 4 bytes also avoids the problem on this device. it really seems like a HC problem -- host should not allow the device to write more than req.wLength!) Index: usb_subr.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v retrieving revision 1.238 diff -p -u -r1.238 usb_subr.c --- usb_subr.c 21 Aug 2019 10:48:37 -0000 1.238 +++ usb_subr.c 24 Aug 2019 13:38:50 -0000 @@ -126,7 +126,27 @@ usbd_get_string_desc(struct usbd_device req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, UDESC_STRING, sindex); USETW(req.wIndex, langid); - USETW(req.wLength, 2); /* only size byte first */ + USETW(req.wLength, sizeof *sdesc); + err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, + &actlen, USBD_DEFAULT_TIMEOUT); + + if (actlen < 2) + return USBD_SHORT_XFER; + + /* Worked on first attempt. */ + if (err == 0) + goto out; + + /* + * Failed. Try again with just the first 2 bytes for length, and + * then fetch the returned length. + */ + + req.bmRequestType = UT_READ_DEVICE; + req.bRequest = UR_GET_DESCRIPTOR; + USETW2(req.wValue, UDESC_STRING, sindex); + USETW(req.wIndex, langid); + USETW(req.wLength, 2); err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); if (err) @@ -143,6 +163,7 @@ usbd_get_string_desc(struct usbd_device if (err) return err; +out: if (actlen != sdesc->bLength) { DPRINTF("expected %jd, got %jd", sdesc->bLength, actlen, 0, 0); } @@ -1380,6 +1401,7 @@ usbd_new_device(device_t parent, struct } err = usbd_reload_device_desc(dev); + if (err) { DPRINTF("addr=%jd, getting full desc failed, err = %jd", addr, err, 0, 0);