aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/usb/persist.txt8
-rw-r--r--drivers/usb/core/hub.c65
-rw-r--r--drivers/usb/core/message.c2
3 files changed, 55 insertions, 20 deletions
diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt
index bea58dbd30fe..d56cb1a11550 100644
--- a/Documentation/usb/persist.txt
+++ b/Documentation/usb/persist.txt
@@ -136,10 +136,10 @@ aren't guaranteed to be 100% accurate.
136 136
137If you replace one USB device with another of the same type (same 137If you replace one USB device with another of the same type (same
138manufacturer, same IDs, and so on) there's an excellent chance the 138manufacturer, same IDs, and so on) there's an excellent chance the
139kernel won't detect the change. Serial numbers and other strings are 139kernel won't detect the change. The serial number string and other
140not compared. In many cases it wouldn't help if they were, because 140descriptors are compared with the kernel's stored values, but this
141manufacturers frequently omit serial numbers entirely in their 141might not help since manufacturers frequently omit serial numbers
142devices. 142entirely in their devices.
143 143
144Furthermore it's quite possible to leave a USB device exactly the same 144Furthermore it's quite possible to leave a USB device exactly the same
145while changing its media. If you replace the flash memory card in a 145while changing its media. If you replace the flash memory card in a
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 6dc589955d75..9fc5179dfc60 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3010,16 +3010,36 @@ void usb_hub_cleanup(void)
3010 usb_deregister(&hub_driver); 3010 usb_deregister(&hub_driver);
3011} /* usb_hub_cleanup() */ 3011} /* usb_hub_cleanup() */
3012 3012
3013static int config_descriptors_changed(struct usb_device *udev) 3013static int descriptors_changed(struct usb_device *udev,
3014{ 3014 struct usb_device_descriptor *old_device_descriptor)
3015 unsigned index; 3015{
3016 unsigned len = 0; 3016 int changed = 0;
3017 struct usb_config_descriptor *buf; 3017 unsigned index;
3018 unsigned serial_len = 0;
3019 unsigned len;
3020 unsigned old_length;
3021 int length;
3022 char *buf;
3023
3024 if (memcmp(&udev->descriptor, old_device_descriptor,
3025 sizeof(*old_device_descriptor)) != 0)
3026 return 1;
3027
3028 /* Since the idVendor, idProduct, and bcdDevice values in the
3029 * device descriptor haven't changed, we will assume the
3030 * Manufacturer and Product strings haven't changed either.
3031 * But the SerialNumber string could be different (e.g., a
3032 * different flash card of the same brand).
3033 */
3034 if (udev->serial)
3035 serial_len = strlen(udev->serial) + 1;
3018 3036
3037 len = serial_len;
3019 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { 3038 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
3020 if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) 3039 old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
3021 len = le16_to_cpu(udev->config[index].desc.wTotalLength); 3040 len = max(len, old_length);
3022 } 3041 }
3042
3023 buf = kmalloc(len, GFP_NOIO); 3043 buf = kmalloc(len, GFP_NOIO);
3024 if (buf == NULL) { 3044 if (buf == NULL) {
3025 dev_err(&udev->dev, "no mem to re-read configs after reset\n"); 3045 dev_err(&udev->dev, "no mem to re-read configs after reset\n");
@@ -3027,25 +3047,41 @@ static int config_descriptors_changed(struct usb_device *udev)
3027 return 1; 3047 return 1;
3028 } 3048 }
3029 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { 3049 for (index = 0; index < udev->descriptor.bNumConfigurations; index++) {
3030 int length; 3050 old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
3031 int old_length = le16_to_cpu(udev->config[index].desc.wTotalLength);
3032
3033 length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, 3051 length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf,
3034 old_length); 3052 old_length);
3035 if (length < old_length) { 3053 if (length != old_length) {
3036 dev_dbg(&udev->dev, "config index %d, error %d\n", 3054 dev_dbg(&udev->dev, "config index %d, error %d\n",
3037 index, length); 3055 index, length);
3056 changed = 1;
3038 break; 3057 break;
3039 } 3058 }
3040 if (memcmp (buf, udev->rawdescriptors[index], old_length) 3059 if (memcmp (buf, udev->rawdescriptors[index], old_length)
3041 != 0) { 3060 != 0) {
3042 dev_dbg(&udev->dev, "config index %d changed (#%d)\n", 3061 dev_dbg(&udev->dev, "config index %d changed (#%d)\n",
3043 index, buf->bConfigurationValue); 3062 index,
3063 ((struct usb_config_descriptor *) buf)->
3064 bConfigurationValue);
3065 changed = 1;
3044 break; 3066 break;
3045 } 3067 }
3046 } 3068 }
3069
3070 if (!changed && serial_len) {
3071 length = usb_string(udev, udev->descriptor.iSerialNumber,
3072 buf, serial_len);
3073 if (length + 1 != serial_len) {
3074 dev_dbg(&udev->dev, "serial string error %d\n",
3075 length);
3076 changed = 1;
3077 } else if (memcmp(buf, udev->serial, length) != 0) {
3078 dev_dbg(&udev->dev, "serial string changed\n");
3079 changed = 1;
3080 }
3081 }
3082
3047 kfree(buf); 3083 kfree(buf);
3048 return index != udev->descriptor.bNumConfigurations; 3084 return changed;
3049} 3085}
3050 3086
3051/** 3087/**
@@ -3118,8 +3154,7 @@ int usb_reset_device(struct usb_device *udev)
3118 goto re_enumerate; 3154 goto re_enumerate;
3119 3155
3120 /* Device might have changed firmware (DFU or similar) */ 3156 /* Device might have changed firmware (DFU or similar) */
3121 if (memcmp(&udev->descriptor, &descriptor, sizeof descriptor) 3157 if (descriptors_changed(udev, &descriptor)) {
3122 || config_descriptors_changed (udev)) {
3123 dev_info(&udev->dev, "device firmware changed\n"); 3158 dev_info(&udev->dev, "device firmware changed\n");
3124 udev->descriptor = descriptor; /* for disconnect() calls */ 3159 udev->descriptor = descriptor; /* for disconnect() calls */
3125 goto re_enumerate; 3160 goto re_enumerate;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index c311f67b7f08..a3695b5115ff 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -784,7 +784,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
784 if (size <= 0 || !buf || !index) 784 if (size <= 0 || !buf || !index)
785 return -EINVAL; 785 return -EINVAL;
786 buf[0] = 0; 786 buf[0] = 0;
787 tbuf = kmalloc(256, GFP_KERNEL); 787 tbuf = kmalloc(256, GFP_NOIO);
788 if (!tbuf) 788 if (!tbuf)
789 return -ENOMEM; 789 return -ENOMEM;
790 790