Author: hselasky
Date: Mon May 18 09:46:51 2020
New Revision: 361208
URL: https://svnweb.freebsd.org/changeset/base/361208

Log:
  MFC r360925:
  Refresh the USB device strings when a USB device is re-enumerated.
  
  Submitted by: Horse Ma <shichun...@dell.com>
  Sponsored by: Mellanox Technologies

Modified:
  stable/11/sys/dev/usb/usb_device.c
  stable/11/sys/dev/usb/usb_device.h
  stable/11/sys/dev/usb/usb_hub.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/usb/usb_device.c
==============================================================================
--- stable/11/sys/dev/usb/usb_device.c  Mon May 18 09:45:59 2020        
(r361207)
+++ stable/11/sys/dev/usb/usb_device.c  Mon May 18 09:46:51 2020        
(r361208)
@@ -101,7 +101,6 @@ static void usb_suspend_resume_sub(struct usb_device *
                    uint8_t);
 static usb_proc_callback_t usbd_clear_stall_proc;
 static usb_error_t usb_config_parse(struct usb_device *, uint8_t, uint8_t);
-static void    usbd_set_device_strings(struct usb_device *);
 #if USB_HAVE_DEVCTL
 static void    usb_notify_addq(const char *type, struct usb_device *);
 #endif
@@ -1650,6 +1649,85 @@ usbd_clear_stall_proc(struct usb_proc_msg *_pm)
 }
 
 /*------------------------------------------------------------------------*
+ *      usb_get_langid
+ *
+ * This function tries to figure out the USB string language to use.
+ *------------------------------------------------------------------------*/
+void
+usb_get_langid(struct usb_device *udev)
+{
+       uint8_t *scratch_ptr;
+       uint8_t do_unlock;
+       int err;
+
+       /*
+        * Workaround for buggy USB devices.
+        *
+        * It appears that some string-less USB chips will crash and
+        * disappear if any attempts are made to read any string
+        * descriptors.
+        *
+        * Try to detect such chips by checking the strings in the USB
+        * device descriptor. If no strings are present there we
+        * simply disable all USB strings.
+        */
+
+       /* Protect scratch area */
+       do_unlock = usbd_ctrl_lock(udev);
+
+       scratch_ptr = udev->scratch.data;
+
+       if (udev->flags.no_strings) {
+               err = USB_ERR_INVAL;
+       } else if (udev->ddesc.iManufacturer ||
+           udev->ddesc.iProduct ||
+           udev->ddesc.iSerialNumber) {
+               /* read out the language ID string */
+               err = usbd_req_get_string_desc(udev, NULL,
+                   (char *)scratch_ptr, 4, 0, USB_LANGUAGE_TABLE);
+       } else {
+               err = USB_ERR_INVAL;
+       }
+
+       if (err || (scratch_ptr[0] < 4)) {
+               udev->flags.no_strings = 1;
+       } else {
+               uint16_t langid;
+               uint16_t pref;
+               uint16_t mask;
+               uint8_t x;
+
+               /* load preferred value and mask */
+               pref = usb_lang_id;
+               mask = usb_lang_mask;
+
+               /* align length correctly */
+               scratch_ptr[0] &= ~1U;
+
+               /* fix compiler warning */
+               langid = 0;
+
+               /* search for preferred language */
+               for (x = 2; x < scratch_ptr[0]; x += 2) {
+                       langid = UGETW(scratch_ptr + x);
+                       if ((langid & mask) == pref)
+                               break;
+               }
+               if (x >= scratch_ptr[0]) {
+                       /* pick the first language as the default */
+                       DPRINTFN(1, "Using first language\n");
+                       langid = UGETW(scratch_ptr + 2);
+               }
+
+               DPRINTFN(1, "Language selected: 0x%04x\n", langid);
+               udev->langid = langid;
+       }
+
+       if (do_unlock)
+               usbd_ctrl_unlock(udev);
+}
+
+/*------------------------------------------------------------------------*
  *     usb_alloc_device
  *
  * This function allocates a new USB device. This function is called
@@ -1670,13 +1748,11 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *
        struct usb_device *udev;
        struct usb_device *adev;
        struct usb_device *hub;
-       uint8_t *scratch_ptr;
        usb_error_t err;
        uint8_t device_index;
        uint8_t config_index;
        uint8_t config_quirk;
        uint8_t set_config_failed;
-       uint8_t do_unlock;
 
        DPRINTF("parent_dev=%p, bus=%p, parent_hub=%p, depth=%u, "
            "port_index=%u, port_no=%u, speed=%u, usb_mode=%u\n",
@@ -1886,76 +1962,13 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *
        if (usb_test_quirk(&uaa, UQ_NO_STRINGS)) {
                udev->flags.no_strings = 1;
        }
-       /*
-        * Workaround for buggy USB devices.
-        *
-        * It appears that some string-less USB chips will crash and
-        * disappear if any attempts are made to read any string
-        * descriptors.
-        *
-        * Try to detect such chips by checking the strings in the USB
-        * device descriptor. If no strings are present there we
-        * simply disable all USB strings.
-        */
 
-       /* Protect scratch area */
-       do_unlock = usbd_ctrl_lock(udev);
+       usb_get_langid(udev);
 
-       scratch_ptr = udev->scratch.data;
-
-       if (udev->flags.no_strings) {
-               err = USB_ERR_INVAL;
-       } else if (udev->ddesc.iManufacturer ||
-           udev->ddesc.iProduct ||
-           udev->ddesc.iSerialNumber) {
-               /* read out the language ID string */
-               err = usbd_req_get_string_desc(udev, NULL,
-                   (char *)scratch_ptr, 4, 0, USB_LANGUAGE_TABLE);
-       } else {
-               err = USB_ERR_INVAL;
-       }
-
-       if (err || (scratch_ptr[0] < 4)) {
-               udev->flags.no_strings = 1;
-       } else {
-               uint16_t langid;
-               uint16_t pref;
-               uint16_t mask;
-               uint8_t x;
-
-               /* load preferred value and mask */
-               pref = usb_lang_id;
-               mask = usb_lang_mask;
-
-               /* align length correctly */
-               scratch_ptr[0] &= ~1U;
-
-               /* fix compiler warning */
-               langid = 0;
-
-               /* search for preferred language */
-               for (x = 2; (x < scratch_ptr[0]); x += 2) {
-                       langid = UGETW(scratch_ptr + x);
-                       if ((langid & mask) == pref)
-                               break;
-               }
-               if (x >= scratch_ptr[0]) {
-                       /* pick the first language as the default */
-                       DPRINTFN(1, "Using first language\n");
-                       langid = UGETW(scratch_ptr + 2);
-               }
-
-               DPRINTFN(1, "Language selected: 0x%04x\n", langid);
-               udev->langid = langid;
-       }
-
-       if (do_unlock)
-               usbd_ctrl_unlock(udev);
-
        /* assume 100mA bus powered for now. Changed when configured. */
        udev->power = USB_MIN_POWER;
        /* fetch the vendor and product strings from the device */
-       usbd_set_device_strings(udev);
+       usb_set_device_strings(udev);
 
        if (udev->flags.usb_mode == USB_MODE_DEVICE) {
                /* USB device mode setup is complete */
@@ -2475,8 +2488,8 @@ struct usb_knowndev {
 #include "usbdevs_data.h"
 #endif                                 /* USB_VERBOSE */
 
-static void
-usbd_set_device_strings(struct usb_device *udev)
+void
+usb_set_device_strings(struct usb_device *udev)
 {
        struct usb_device_descriptor *udd = &udev->ddesc;
 #ifdef USB_VERBOSE
@@ -2496,6 +2509,16 @@ usbd_set_device_strings(struct usb_device *udev)
 
        vendor_id = UGETW(udd->idVendor);
        product_id = UGETW(udd->idProduct);
+
+       /* cleanup old strings, if any */
+       free(udev->serial, M_USB);
+       free(udev->manufacturer, M_USB);
+       free(udev->product, M_USB);
+
+       /* zero the string pointers */
+       udev->serial = NULL;
+       udev->manufacturer = NULL;
+       udev->product = NULL;
 
        /* get serial number string */
        usbd_req_get_string_any(udev, NULL, temp_ptr, temp_size,

Modified: stable/11/sys/dev/usb/usb_device.h
==============================================================================
--- stable/11/sys/dev/usb/usb_device.h  Mon May 18 09:45:59 2020        
(r361207)
+++ stable/11/sys/dev/usb/usb_device.h  Mon May 18 09:46:51 2020        
(r361208)
@@ -326,6 +326,9 @@ struct usb_endpoint *usb_endpoint_foreach(struct usb_d
 void   usb_set_device_state(struct usb_device *, enum usb_dev_state);
 enum usb_dev_state usb_get_device_state(struct usb_device *);
 
+void   usb_set_device_strings(struct usb_device *);
+void   usb_get_langid(struct usb_device *);
+
 uint8_t        usbd_enum_lock(struct usb_device *);
 #if USB_HAVE_UGEN
 uint8_t        usbd_enum_lock_sig(struct usb_device *);

Modified: stable/11/sys/dev/usb/usb_hub.c
==============================================================================
--- stable/11/sys/dev/usb/usb_hub.c     Mon May 18 09:45:59 2020        
(r361207)
+++ stable/11/sys/dev/usb/usb_hub.c     Mon May 18 09:46:51 2020        
(r361208)
@@ -470,8 +470,14 @@ uhub_explore_handle_re_enumerate(struct usb_device *ch
                } else {
                        err = usbd_req_re_enumerate(child, NULL);
                }
-               if (err == 0)
+               if (err == 0) {
+                       /* refresh device strings */
+                       usb_get_langid(child);
+                       usb_set_device_strings(child);
+
+                       /* set default configuration */
                        err = usbd_set_config_index(child, 0);
+               }
                if (err == 0) {
                        err = usb_probe_and_attach(child,
                            USB_IFACE_INDEX_ANY);
@@ -1724,6 +1730,7 @@ uhub_child_pnpinfo_string(device_t parent, device_t ch
        struct usb_hub *hub;
        struct usb_interface *iface;
        struct hub_result res;
+       uint8_t do_unlock;
 
        if (!device_is_attached(parent)) {
                if (buflen)
@@ -1745,6 +1752,9 @@ uhub_child_pnpinfo_string(device_t parent, device_t ch
        }
        iface = usbd_get_iface(res.udev, res.iface_index);
        if (iface && iface->idesc) {
+               /* Make sure device information is not changed during the 
print. */
+               do_unlock = usbd_ctrl_lock(res.udev);
+
                snprintf(buf, buflen, "vendor=0x%04x product=0x%04x "
                    "devclass=0x%02x devsubclass=0x%02x "
                    "devproto=0x%02x "
@@ -1766,6 +1776,9 @@ uhub_child_pnpinfo_string(device_t parent, device_t ch
                    iface->idesc->bInterfaceProtocol,
                    iface->pnpinfo ? " " : "",
                    iface->pnpinfo ? iface->pnpinfo : "");
+
+               if (do_unlock)
+                       usbd_ctrl_unlock(res.udev);
        } else {
                if (buflen) {
                        buf[0] = '\0';
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to