Commit 962fd332 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

[PATCH] USB: Fix DMA coherence when reading device descriptor

parent 6e8339b9
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "usb.h"
#include "hcd.h" #include "hcd.h"
#include "hub.h" #include "hub.h"
...@@ -1316,8 +1317,8 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1316,8 +1317,8 @@ int usb_physical_reset_device(struct usb_device *dev)
kfree(descriptor); kfree(descriptor);
usb_destroy_configuration(dev); usb_destroy_configuration(dev);
ret = usb_get_device_descriptor(dev); ret = usb_get_device_descriptor(dev, sizeof(dev->descriptor));
if (ret < sizeof(dev->descriptor)) { if (ret != sizeof(dev->descriptor)) {
if (ret < 0) if (ret < 0)
err("unable to get device %s descriptor " err("unable to get device %s descriptor "
"(error=%d)", dev->devpath, ret); "(error=%d)", dev->devpath, ret);
......
...@@ -546,10 +546,10 @@ void usb_sg_cancel (struct usb_sg_request *io) ...@@ -546,10 +546,10 @@ void usb_sg_cancel (struct usb_sg_request *io)
* *
* Gets a USB descriptor. Convenience functions exist to simplify * Gets a USB descriptor. Convenience functions exist to simplify
* getting some types of descriptors. Use * 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. * and usb_get_string() or usb_string() for USB_DT_STRING.
* Configuration descriptors (USB_DT_CONFIG) are part of the device * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG)
* structure, at least for the current configuration. * are part of the device structure.
* In addition to a number of USB-standard descriptors, some * In addition to a number of USB-standard descriptors, some
* devices also use class-specific or vendor-specific descriptors. * devices also use class-specific or vendor-specific descriptors.
* *
...@@ -610,6 +610,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char ...@@ -610,6 +610,7 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char
/** /**
* usb_get_device_descriptor - (re)reads the device descriptor * usb_get_device_descriptor - (re)reads the device descriptor
* @dev: the device whose device descriptor is being updated * @dev: the device whose device descriptor is being updated
* @size: how much of the descriptor to read
* Context: !in_interrupt () * Context: !in_interrupt ()
* *
* Updates the copy of the device descriptor stored in the device structure, * Updates the copy of the device descriptor stored in the device structure,
...@@ -618,24 +619,35 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char ...@@ -618,24 +619,35 @@ int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char
* vendors product and version fields (idVendor, idProduct, and bcdDevice). * vendors product and version fields (idVendor, idProduct, and bcdDevice).
* That lets device drivers compare against non-byteswapped constants. * That lets device drivers compare against non-byteswapped constants.
* *
* There's normally no need to use this call, although some devices * Not exported, only for use by the core. If drivers really want to read
* will change their descriptors after events like updating firmware. * 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. * 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 * Returns the number of bytes received on success, or else the status code
* returned by the underlying usb_control_msg() call. * 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, struct usb_device_descriptor *desc;
sizeof(dev->descriptor)); 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) { if (ret >= 0) {
le16_to_cpus(&dev->descriptor.bcdUSB); le16_to_cpus(&desc->bcdUSB);
le16_to_cpus(&dev->descriptor.idVendor); le16_to_cpus(&desc->idVendor);
le16_to_cpus(&dev->descriptor.idProduct); le16_to_cpus(&desc->idProduct);
le16_to_cpus(&dev->descriptor.bcdDevice); le16_to_cpus(&desc->bcdDevice);
memcpy(&dev->descriptor, desc, size);
} }
kfree(desc);
return ret; return ret;
} }
...@@ -1241,7 +1253,6 @@ EXPORT_SYMBOL(usb_sg_wait); ...@@ -1241,7 +1253,6 @@ EXPORT_SYMBOL(usb_sg_wait);
// synchronous control message convenience routines // synchronous control message convenience routines
EXPORT_SYMBOL(usb_get_descriptor); EXPORT_SYMBOL(usb_get_descriptor);
EXPORT_SYMBOL(usb_get_device_descriptor);
EXPORT_SYMBOL(usb_get_status); EXPORT_SYMBOL(usb_get_status);
EXPORT_SYMBOL(usb_get_string); EXPORT_SYMBOL(usb_get_string);
EXPORT_SYMBOL(usb_string); EXPORT_SYMBOL(usb_string);
......
...@@ -1065,7 +1065,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1065,7 +1065,7 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
wait_ms(10); /* Let the SET_ADDRESS settle */ wait_ms(10); /* Let the SET_ADDRESS settle */
/* high and low speed devices don't need this... */ /* 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) if (err >= 8)
break; break;
wait_ms(100); wait_ms(100);
...@@ -1085,8 +1085,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent) ...@@ -1085,8 +1085,8 @@ int usb_new_device(struct usb_device *dev, struct device *parent)
/* USB device state == addressed ... still not usable */ /* USB device state == addressed ... still not usable */
err = usb_get_device_descriptor(dev); err = usb_get_device_descriptor(dev, sizeof(dev->descriptor));
if (err < (signed)sizeof(dev->descriptor)) { if (err != (signed)sizeof(dev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/all, error %d\n", err); dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
goto fail; goto fail;
} }
......
...@@ -14,3 +14,6 @@ extern void usb_enable_endpoint (struct usb_device *dev, ...@@ -14,3 +14,6 @@ extern void usb_enable_endpoint (struct usb_device *dev,
struct usb_endpoint_descriptor *epd); struct usb_endpoint_descriptor *epd);
extern void usb_enable_interface (struct usb_device *dev, extern void usb_enable_interface (struct usb_device *dev,
struct usb_interface *intf); struct usb_interface *intf);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
...@@ -856,7 +856,6 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, ...@@ -856,7 +856,6 @@ extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
/* wrappers around usb_control_msg() for the most common standard requests */ /* wrappers around usb_control_msg() for the most common standard requests */
extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
unsigned char descindex, void *buf, int size); 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, extern int usb_get_status(struct usb_device *dev,
int type, int target, void *data); int type, int target, void *data);
extern int usb_get_string(struct usb_device *dev, extern int usb_get_string(struct usb_device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment