ChangeSet 1.1474.148.18, 2004/01/26 17:12:05-08:00, stern@rowland.harvard.edu [PATCH] USB: Fix DMA coherence when reading device descriptor drivers/usb/core/hub.c | 5 +++-- drivers/usb/core/message.c | 37 ++++++++++++++++++++++++------------- drivers/usb/core/usb.c | 6 +++--- drivers/usb/core/usb.h | 3 +++ include/linux/usb.h | 1 - 5 files changed, 33 insertions(+), 19 deletions(-) diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Tue Jan 27 15:12:40 2004 +++ b/drivers/usb/core/hub.c Tue Jan 27 15:12:40 2004 @@ -31,6 +31,7 @@ #include #include +#include "usb.h" #include "hcd.h" #include "hub.h" @@ -1316,8 +1317,8 @@ kfree(descriptor); usb_destroy_configuration(dev); - ret = usb_get_device_descriptor(dev); - if (ret < sizeof(dev->descriptor)) { + ret = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); + if (ret != sizeof(dev->descriptor)) { if (ret < 0) err("unable to get device %s descriptor " "(error=%d)", dev->devpath, ret); diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Tue Jan 27 15:12:40 2004 +++ b/drivers/usb/core/message.c Tue Jan 27 15:12:40 2004 @@ -546,10 +546,10 @@ * * Gets a USB descriptor. Convenience functions exist to simplify * getting some types of descriptors. Use - * usb_get_device_descriptor() for USB_DT_DEVICE, + * usb_get_device_descriptor() for USB_DT_DEVICE (not exported), * and usb_get_string() or usb_string() for USB_DT_STRING. - * Configuration descriptors (USB_DT_CONFIG) are part of the device - * structure, at least for the current configuration. + * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG) + * are part of the device structure. * In addition to a number of USB-standard descriptors, some * devices also use class-specific or vendor-specific descriptors. * @@ -610,6 +610,7 @@ /** * usb_get_device_descriptor - (re)reads the device descriptor * @dev: the device whose device descriptor is being updated + * @size: how much of the descriptor to read * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, @@ -618,24 +619,35 @@ * vendors product and version fields (idVendor, idProduct, and bcdDevice). * That lets device drivers compare against non-byteswapped constants. * - * There's normally no need to use this call, although some devices - * will change their descriptors after events like updating firmware. + * Not exported, only for use by the core. If drivers really want to read + * the device descriptor directly, they can call usb_get_descriptor() with + * type = USB_DT_DEVICE and index = 0. * * This call is synchronous, and may not be used in an interrupt context. * * Returns the number of bytes received on success, or else the status code * returned by the underlying usb_control_msg() call. */ -int usb_get_device_descriptor(struct usb_device *dev) +int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) { - int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, - sizeof(dev->descriptor)); + struct usb_device_descriptor *desc; + int ret; + + if (size > sizeof(*desc)) + return -EINVAL; + desc = kmalloc(sizeof(*desc), GFP_NOIO); + if (!desc) + return -ENOMEM; + + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); if (ret >= 0) { - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); + le16_to_cpus(&desc->bcdUSB); + le16_to_cpus(&desc->idVendor); + le16_to_cpus(&desc->idProduct); + le16_to_cpus(&desc->bcdDevice); + memcpy(&dev->descriptor, desc, size); } + kfree(desc); return ret; } @@ -1241,7 +1253,6 @@ // synchronous control message convenience routines EXPORT_SYMBOL(usb_get_descriptor); -EXPORT_SYMBOL(usb_get_device_descriptor); EXPORT_SYMBOL(usb_get_status); EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_string); diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Tue Jan 27 15:12:40 2004 +++ b/drivers/usb/core/usb.c Tue Jan 27 15:12:40 2004 @@ -1065,7 +1065,7 @@ wait_ms(10); /* Let the SET_ADDRESS settle */ /* high and low speed devices don't need this... */ - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8); + err = usb_get_device_descriptor(dev, 8); if (err >= 8) break; wait_ms(100); @@ -1085,8 +1085,8 @@ /* USB device state == addressed ... still not usable */ - err = usb_get_device_descriptor(dev); - if (err < (signed)sizeof(dev->descriptor)) { + err = usb_get_device_descriptor(dev, sizeof(dev->descriptor)); + if (err != (signed)sizeof(dev->descriptor)) { dev_err(&dev->dev, "device descriptor read/all, error %d\n", err); goto fail; } diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h --- a/drivers/usb/core/usb.h Tue Jan 27 15:12:40 2004 +++ b/drivers/usb/core/usb.h Tue Jan 27 15:12:40 2004 @@ -14,3 +14,6 @@ struct usb_endpoint_descriptor *epd); extern void usb_enable_interface (struct usb_device *dev, struct usb_interface *intf); + +extern int usb_get_device_descriptor(struct usb_device *dev, + unsigned int size); diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Tue Jan 27 15:12:40 2004 +++ b/include/linux/usb.h Tue Jan 27 15:12:40 2004 @@ -856,7 +856,6 @@ /* wrappers around usb_control_msg() for the most common standard requests */ extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned char descindex, void *buf, int size); -extern int usb_get_device_descriptor(struct usb_device *dev); extern int usb_get_status(struct usb_device *dev, int type, int target, void *data); extern int usb_get_string(struct usb_device *dev,