diff options
| -rw-r--r-- | drivers/usb/core/driver.c | 38 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 10 | ||||
| -rw-r--r-- | drivers/usb/core/quirks.c | 93 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 4 |
4 files changed, 106 insertions, 39 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 69781016a266..445455a4429b 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
| @@ -607,22 +607,10 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) | |||
| 607 | } | 607 | } |
| 608 | 608 | ||
| 609 | /* returns 0 if no match, 1 if match */ | 609 | /* returns 0 if no match, 1 if match */ |
| 610 | int usb_match_one_id(struct usb_interface *interface, | 610 | int usb_match_one_id_intf(struct usb_device *dev, |
| 611 | const struct usb_device_id *id) | 611 | struct usb_host_interface *intf, |
| 612 | const struct usb_device_id *id) | ||
| 612 | { | 613 | { |
| 613 | struct usb_host_interface *intf; | ||
| 614 | struct usb_device *dev; | ||
| 615 | |||
| 616 | /* proc_connectinfo in devio.c may call us with id == NULL. */ | ||
| 617 | if (id == NULL) | ||
| 618 | return 0; | ||
| 619 | |||
| 620 | intf = interface->cur_altsetting; | ||
| 621 | dev = interface_to_usbdev(interface); | ||
| 622 | |||
| 623 | if (!usb_match_device(dev, id)) | ||
| 624 | return 0; | ||
| 625 | |||
| 626 | /* The interface class, subclass, protocol and number should never be | 614 | /* The interface class, subclass, protocol and number should never be |
| 627 | * checked for a match if the device class is Vendor Specific, | 615 | * checked for a match if the device class is Vendor Specific, |
| 628 | * unless the match record specifies the Vendor ID. */ | 616 | * unless the match record specifies the Vendor ID. */ |
| @@ -652,6 +640,26 @@ int usb_match_one_id(struct usb_interface *interface, | |||
| 652 | 640 | ||
| 653 | return 1; | 641 | return 1; |
| 654 | } | 642 | } |
| 643 | |||
| 644 | /* returns 0 if no match, 1 if match */ | ||
| 645 | int usb_match_one_id(struct usb_interface *interface, | ||
| 646 | const struct usb_device_id *id) | ||
| 647 | { | ||
| 648 | struct usb_host_interface *intf; | ||
| 649 | struct usb_device *dev; | ||
| 650 | |||
| 651 | /* proc_connectinfo in devio.c may call us with id == NULL. */ | ||
| 652 | if (id == NULL) | ||
| 653 | return 0; | ||
| 654 | |||
| 655 | intf = interface->cur_altsetting; | ||
| 656 | dev = interface_to_usbdev(interface); | ||
| 657 | |||
| 658 | if (!usb_match_device(dev, id)) | ||
| 659 | return 0; | ||
| 660 | |||
| 661 | return usb_match_one_id_intf(dev, intf, id); | ||
| 662 | } | ||
| 655 | EXPORT_SYMBOL_GPL(usb_match_one_id); | 663 | EXPORT_SYMBOL_GPL(usb_match_one_id); |
| 656 | 664 | ||
| 657 | /** | 665 | /** |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 540f20bf9e22..821126eb8176 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -2069,7 +2069,7 @@ static int usb_enumerate_device(struct usb_device *udev) | |||
| 2069 | if (err < 0) { | 2069 | if (err < 0) { |
| 2070 | dev_err(&udev->dev, "can't read configurations, error %d\n", | 2070 | dev_err(&udev->dev, "can't read configurations, error %d\n", |
| 2071 | err); | 2071 | err); |
| 2072 | goto fail; | 2072 | return err; |
| 2073 | } | 2073 | } |
| 2074 | } | 2074 | } |
| 2075 | if (udev->wusb == 1 && udev->authorized == 0) { | 2075 | if (udev->wusb == 1 && udev->authorized == 0) { |
| @@ -2085,8 +2085,12 @@ static int usb_enumerate_device(struct usb_device *udev) | |||
| 2085 | udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); | 2085 | udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); |
| 2086 | } | 2086 | } |
| 2087 | err = usb_enumerate_device_otg(udev); | 2087 | err = usb_enumerate_device_otg(udev); |
| 2088 | fail: | 2088 | if (err < 0) |
| 2089 | return err; | 2089 | return err; |
| 2090 | |||
| 2091 | usb_detect_interface_quirks(udev); | ||
| 2092 | |||
| 2093 | return 0; | ||
| 2090 | } | 2094 | } |
| 2091 | 2095 | ||
| 2092 | static void set_usb_port_removable(struct usb_device *udev) | 2096 | static void set_usb_port_removable(struct usb_device *udev) |
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 32d3adc315f5..cbd15d1d25d3 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
| @@ -15,17 +15,22 @@ | |||
| 15 | #include <linux/usb/quirks.h> | 15 | #include <linux/usb/quirks.h> |
| 16 | #include "usb.h" | 16 | #include "usb.h" |
| 17 | 17 | ||
| 18 | /* List of quirky USB devices. Please keep this list ordered by: | 18 | /* Lists of quirky USB devices, split in device quirks and interface quirks. |
| 19 | * Device quirks are applied at the very beginning of the enumeration process, | ||
| 20 | * right after reading the device descriptor. They can thus only match on device | ||
| 21 | * information. | ||
| 22 | * | ||
| 23 | * Interface quirks are applied after reading all the configuration descriptors. | ||
| 24 | * They can match on both device and interface information. | ||
| 25 | * | ||
| 26 | * Note that the DELAY_INIT and HONOR_BNUMINTERFACES quirks do not make sense as | ||
| 27 | * interface quirks, as they only influence the enumeration process which is run | ||
| 28 | * before processing the interface quirks. | ||
| 29 | * | ||
| 30 | * Please keep the lists ordered by: | ||
| 19 | * 1) Vendor ID | 31 | * 1) Vendor ID |
| 20 | * 2) Product ID | 32 | * 2) Product ID |
| 21 | * 3) Class ID | 33 | * 3) Class ID |
| 22 | * | ||
| 23 | * as we want specific devices to be overridden first, and only after that, any | ||
| 24 | * class specific quirks. | ||
| 25 | * | ||
| 26 | * Right now the logic aborts if it finds a valid device in the table, we might | ||
| 27 | * want to change that in the future if it turns out that a whole class of | ||
| 28 | * devices is broken... | ||
| 29 | */ | 34 | */ |
| 30 | static const struct usb_device_id usb_quirk_list[] = { | 35 | static const struct usb_device_id usb_quirk_list[] = { |
| 31 | /* CBM - Flash disk */ | 36 | /* CBM - Flash disk */ |
| @@ -156,16 +161,53 @@ static const struct usb_device_id usb_quirk_list[] = { | |||
| 156 | { } /* terminating entry must be last */ | 161 | { } /* terminating entry must be last */ |
| 157 | }; | 162 | }; |
| 158 | 163 | ||
| 159 | static const struct usb_device_id *find_id(struct usb_device *udev) | 164 | static const struct usb_device_id usb_interface_quirk_list[] = { |
| 165 | { } /* terminating entry must be last */ | ||
| 166 | }; | ||
| 167 | |||
| 168 | static bool usb_match_any_interface(struct usb_device *udev, | ||
| 169 | const struct usb_device_id *id) | ||
| 170 | { | ||
| 171 | unsigned int i; | ||
| 172 | |||
| 173 | for (i = 0; i < udev->descriptor.bNumConfigurations; ++i) { | ||
| 174 | struct usb_host_config *cfg = &udev->config[i]; | ||
| 175 | unsigned int j; | ||
| 176 | |||
| 177 | for (j = 0; j < cfg->desc.bNumInterfaces; ++j) { | ||
| 178 | struct usb_interface_cache *cache; | ||
| 179 | struct usb_host_interface *intf; | ||
| 180 | |||
| 181 | cache = cfg->intf_cache[j]; | ||
| 182 | if (cache->num_altsetting == 0) | ||
| 183 | continue; | ||
| 184 | |||
| 185 | intf = &cache->altsetting[0]; | ||
| 186 | if (usb_match_one_id_intf(udev, intf, id)) | ||
| 187 | return true; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | return false; | ||
| 192 | } | ||
| 193 | |||
| 194 | static u32 __usb_detect_quirks(struct usb_device *udev, | ||
| 195 | const struct usb_device_id *id) | ||
| 160 | { | 196 | { |
| 161 | const struct usb_device_id *id = usb_quirk_list; | 197 | u32 quirks = 0; |
| 162 | 198 | ||
| 163 | for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || | 199 | for (; id->match_flags; id++) { |
| 164 | id->driver_info; id++) { | 200 | if (!usb_match_device(udev, id)) |
| 165 | if (usb_match_device(udev, id)) | 201 | continue; |
| 166 | return id; | 202 | |
| 203 | if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO) && | ||
| 204 | !usb_match_any_interface(udev, id)) | ||
| 205 | continue; | ||
| 206 | |||
| 207 | quirks |= (u32)(id->driver_info); | ||
| 167 | } | 208 | } |
| 168 | return NULL; | 209 | |
| 210 | return quirks; | ||
| 169 | } | 211 | } |
| 170 | 212 | ||
| 171 | /* | 213 | /* |
| @@ -173,14 +215,10 @@ static const struct usb_device_id *find_id(struct usb_device *udev) | |||
| 173 | */ | 215 | */ |
| 174 | void usb_detect_quirks(struct usb_device *udev) | 216 | void usb_detect_quirks(struct usb_device *udev) |
| 175 | { | 217 | { |
| 176 | const struct usb_device_id *id = usb_quirk_list; | 218 | udev->quirks = __usb_detect_quirks(udev, usb_quirk_list); |
| 177 | |||
| 178 | id = find_id(udev); | ||
| 179 | if (id) | ||
| 180 | udev->quirks = (u32)(id->driver_info); | ||
| 181 | if (udev->quirks) | 219 | if (udev->quirks) |
| 182 | dev_dbg(&udev->dev, "USB quirks for this device: %x\n", | 220 | dev_dbg(&udev->dev, "USB quirks for this device: %x\n", |
| 183 | udev->quirks); | 221 | udev->quirks); |
| 184 | 222 | ||
| 185 | /* For the present, all devices default to USB-PERSIST enabled */ | 223 | /* For the present, all devices default to USB-PERSIST enabled */ |
| 186 | #if 0 /* was: #ifdef CONFIG_PM */ | 224 | #if 0 /* was: #ifdef CONFIG_PM */ |
| @@ -197,3 +235,16 @@ void usb_detect_quirks(struct usb_device *udev) | |||
| 197 | udev->persist_enabled = 1; | 235 | udev->persist_enabled = 1; |
| 198 | #endif /* CONFIG_PM */ | 236 | #endif /* CONFIG_PM */ |
| 199 | } | 237 | } |
| 238 | |||
| 239 | void usb_detect_interface_quirks(struct usb_device *udev) | ||
| 240 | { | ||
| 241 | u32 quirks; | ||
| 242 | |||
| 243 | quirks = __usb_detect_quirks(udev, usb_interface_quirk_list); | ||
| 244 | if (quirks == 0) | ||
| 245 | return; | ||
| 246 | |||
| 247 | dev_dbg(&udev->dev, "USB interface quirks for this device: %x\n", | ||
| 248 | quirks); | ||
| 249 | udev->quirks |= quirks; | ||
| 250 | } | ||
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 67875a89cfa1..acb103c5c391 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
| @@ -26,6 +26,7 @@ extern void usb_disable_device(struct usb_device *dev, int skip_ep0); | |||
| 26 | extern int usb_deauthorize_device(struct usb_device *); | 26 | extern int usb_deauthorize_device(struct usb_device *); |
| 27 | extern int usb_authorize_device(struct usb_device *); | 27 | extern int usb_authorize_device(struct usb_device *); |
| 28 | extern void usb_detect_quirks(struct usb_device *udev); | 28 | extern void usb_detect_quirks(struct usb_device *udev); |
| 29 | extern void usb_detect_interface_quirks(struct usb_device *udev); | ||
| 29 | extern int usb_remove_device(struct usb_device *udev); | 30 | extern int usb_remove_device(struct usb_device *udev); |
| 30 | 31 | ||
| 31 | extern int usb_get_device_descriptor(struct usb_device *dev, | 32 | extern int usb_get_device_descriptor(struct usb_device *dev, |
| @@ -37,6 +38,9 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration); | |||
| 37 | extern int usb_choose_configuration(struct usb_device *udev); | 38 | extern int usb_choose_configuration(struct usb_device *udev); |
| 38 | 39 | ||
| 39 | extern void usb_kick_khubd(struct usb_device *dev); | 40 | extern void usb_kick_khubd(struct usb_device *dev); |
| 41 | extern int usb_match_one_id_intf(struct usb_device *dev, | ||
| 42 | struct usb_host_interface *intf, | ||
| 43 | const struct usb_device_id *id); | ||
| 40 | extern int usb_match_device(struct usb_device *dev, | 44 | extern int usb_match_device(struct usb_device *dev, |
| 41 | const struct usb_device_id *id); | 45 | const struct usb_device_id *id); |
| 42 | extern void usb_forced_unbind_intf(struct usb_interface *intf); | 46 | extern void usb_forced_unbind_intf(struct usb_interface *intf); |
