aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-06-11 17:29:32 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-06-11 17:29:32 -0700
commit631025b4d87d5a9d7e04a1ed652d247191e223d4 (patch)
tree9d96ac072b1856cb62913113260a90ecd9031823
parentaaef4d6c2ee64d5e4d59b7c4d23c37ce59115211 (diff)
parent5340ba827b6269ccd2dcfd3d966626d9dd75d5d4 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: USB: don't use reset-resume if drivers don't support it USB: isp1760: Assign resource fields before adding hcd isight_firmware: Avoid crash on loading invalid firmware USB: fix build bug in USB_ISIGHTFW
-rw-r--r--drivers/usb/core/hub.c46
-rw-r--r--drivers/usb/host/isp1760-hcd.c8
-rw-r--r--drivers/usb/misc/Kconfig1
-rw-r--r--drivers/usb/misc/isight_firmware.c23
4 files changed, 65 insertions, 13 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 8eb4da332f5..94789be54ca 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -644,6 +644,48 @@ static void hub_stop(struct usb_hub *hub)
#ifdef CONFIG_PM
+/* Try to identify which devices need USB-PERSIST handling */
+static int persistent_device(struct usb_device *udev)
+{
+ int i;
+ int retval;
+ struct usb_host_config *actconfig;
+
+ /* Explicitly not marked persistent? */
+ if (!udev->persist_enabled)
+ return 0;
+
+ /* No active config? */
+ actconfig = udev->actconfig;
+ if (!actconfig)
+ return 0;
+
+ /* FIXME! We should check whether it's open here or not! */
+
+ /*
+ * Check that all the interface drivers have a
+ * 'reset_resume' entrypoint
+ */
+ retval = 0;
+ for (i = 0; i < actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf;
+ struct usb_driver *driver;
+
+ intf = actconfig->interface[i];
+ if (!intf->dev.driver)
+ continue;
+ driver = to_usb_driver(intf->dev.driver);
+ if (!driver->reset_resume)
+ return 0;
+ /*
+ * We have at least one driver, and that one
+ * has a reset_resume method.
+ */
+ retval = 1;
+ }
+ return retval;
+}
+
static void hub_restart(struct usb_hub *hub, int type)
{
struct usb_device *hdev = hub->hdev;
@@ -689,8 +731,8 @@ static void hub_restart(struct usb_hub *hub, int type)
* turn off the various status changes to prevent
* khubd from disconnecting it later.
*/
- if (udev->persist_enabled && status == 0 &&
- !(portstatus & USB_PORT_STAT_ENABLE)) {
+ if (status == 0 && !(portstatus & USB_PORT_STAT_ENABLE) &&
+ persistent_device(udev)) {
if (portchange & USB_PORT_STAT_C_ENABLE)
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE);
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index c9cec873826..65aa5ecf569 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -2207,14 +2207,14 @@ struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
goto err_put;
}
- ret = usb_add_hcd(hcd, irq, irqflags);
- if (ret)
- goto err_unmap;
-
hcd->irq = irq;
hcd->rsrc_start = res_start;
hcd->rsrc_len = res_len;
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+ goto err_unmap;
+
return hcd;
err_unmap:
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index eb6c06979f3..001789c9a11 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -272,6 +272,7 @@ config USB_TEST
config USB_ISIGHTFW
tristate "iSight firmware loading support"
depends on USB
+ select FW_LOADER
help
This driver loads firmware for USB Apple iSight cameras, allowing
them to be driven by the USB video class driver available at
diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c
index 390e0488553..9f30aa1f8a5 100644
--- a/drivers/usb/misc/isight_firmware.c
+++ b/drivers/usb/misc/isight_firmware.c
@@ -39,9 +39,12 @@ static int isight_firmware_load(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
int llen, len, req, ret = 0;
const struct firmware *firmware;
- unsigned char *buf;
+ unsigned char *buf = kmalloc(50, GFP_KERNEL);
unsigned char data[4];
- char *ptr;
+ u8 *ptr;
+
+ if (!buf)
+ return -ENOMEM;
if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) {
printk(KERN_ERR "Unable to load isight firmware\n");
@@ -59,7 +62,7 @@ static int isight_firmware_load(struct usb_interface *intf,
goto out;
}
- while (1) {
+ while (ptr+4 <= firmware->data+firmware->size) {
memcpy(data, ptr, 4);
len = (data[0] << 8 | data[1]);
req = (data[2] << 8 | data[3]);
@@ -71,10 +74,14 @@ static int isight_firmware_load(struct usb_interface *intf,
continue;
for (; len > 0; req += 50) {
- llen = len > 50 ? 50 : len;
+ llen = min(len, 50);
len -= llen;
-
- buf = kmalloc(llen, GFP_KERNEL);
+ if (ptr+llen > firmware->data+firmware->size) {
+ printk(KERN_ERR
+ "Malformed isight firmware");
+ ret = -ENODEV;
+ goto out;
+ }
memcpy(buf, ptr, llen);
ptr += llen;
@@ -89,16 +96,18 @@ static int isight_firmware_load(struct usb_interface *intf,
goto out;
}
- kfree(buf);
}
}
+
if (usb_control_msg
(dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
300) != 1) {
printk(KERN_ERR "isight firmware loading completion failed\n");
ret = -ENODEV;
}
+
out:
+ kfree(buf);
release_firmware(firmware);
return ret;
}