浏览代码

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
Linus Torvalds 17 年之前
父节点
当前提交
631025b4d8
共有 4 个文件被更改,包括 65 次插入13 次删除
  1. 44 2
      drivers/usb/core/hub.c
  2. 4 4
      drivers/usb/host/isp1760-hcd.c
  3. 1 0
      drivers/usb/misc/Kconfig
  4. 16 7
      drivers/usb/misc/isight_firmware.c

+ 44 - 2
drivers/usb/core/hub.c

@@ -644,6 +644,48 @@ static void hub_stop(struct usb_hub *hub)
 
 
 #ifdef CONFIG_PM
 #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)
 static void hub_restart(struct usb_hub *hub, int type)
 {
 {
 	struct usb_device *hdev = hub->hdev;
 	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
 		 * turn off the various status changes to prevent
 		 * khubd from disconnecting it later.
 		 * 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)
 			if (portchange & USB_PORT_STAT_C_ENABLE)
 				clear_port_feature(hub->hdev, port1,
 				clear_port_feature(hub->hdev, port1,
 						USB_PORT_FEAT_C_ENABLE);
 						USB_PORT_FEAT_C_ENABLE);

+ 4 - 4
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;
 		goto err_put;
 	}
 	}
 
 
-	ret = usb_add_hcd(hcd, irq, irqflags);
-	if (ret)
-		goto err_unmap;
-
 	hcd->irq = irq;
 	hcd->irq = irq;
 	hcd->rsrc_start = res_start;
 	hcd->rsrc_start = res_start;
 	hcd->rsrc_len = res_len;
 	hcd->rsrc_len = res_len;
 
 
+	ret = usb_add_hcd(hcd, irq, irqflags);
+	if (ret)
+		goto err_unmap;
+
 	return hcd;
 	return hcd;
 
 
 err_unmap:
 err_unmap:

+ 1 - 0
drivers/usb/misc/Kconfig

@@ -272,6 +272,7 @@ config USB_TEST
 config USB_ISIGHTFW
 config USB_ISIGHTFW
 	tristate "iSight firmware loading support"
 	tristate "iSight firmware loading support"
 	depends on USB
 	depends on USB
+	select FW_LOADER
 	help
 	help
 	  This driver loads firmware for USB Apple iSight cameras, allowing
 	  This driver loads firmware for USB Apple iSight cameras, allowing
 	  them to be driven by the USB video class driver available at
 	  them to be driven by the USB video class driver available at

+ 16 - 7
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);
 	struct usb_device *dev = interface_to_usbdev(intf);
 	int llen, len, req, ret = 0;
 	int llen, len, req, ret = 0;
 	const struct firmware *firmware;
 	const struct firmware *firmware;
-	unsigned char *buf;
+	unsigned char *buf = kmalloc(50, GFP_KERNEL);
 	unsigned char data[4];
 	unsigned char data[4];
-	char *ptr;
+	u8 *ptr;
+
+	if (!buf)
+		return -ENOMEM;
 
 
 	if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) {
 	if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) {
 		printk(KERN_ERR "Unable to load isight firmware\n");
 		printk(KERN_ERR "Unable to load isight firmware\n");
@@ -59,7 +62,7 @@ static int isight_firmware_load(struct usb_interface *intf,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	while (1) {
+	while (ptr+4 <= firmware->data+firmware->size) {
 		memcpy(data, ptr, 4);
 		memcpy(data, ptr, 4);
 		len = (data[0] << 8 | data[1]);
 		len = (data[0] << 8 | data[1]);
 		req = (data[2] << 8 | data[3]);
 		req = (data[2] << 8 | data[3]);
@@ -71,10 +74,14 @@ static int isight_firmware_load(struct usb_interface *intf,
 			continue;
 			continue;
 
 
 		for (; len > 0; req += 50) {
 		for (; len > 0; req += 50) {
-			llen = len > 50 ? 50 : len;
+			llen = min(len, 50);
 			len -= llen;
 			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);
 			memcpy(buf, ptr, llen);
 
 
 			ptr += llen;
 			ptr += llen;
@@ -89,16 +96,18 @@ static int isight_firmware_load(struct usb_interface *intf,
 				goto out;
 				goto out;
 			}
 			}
 
 
-			kfree(buf);
 		}
 		}
 	}
 	}
+
 	if (usb_control_msg
 	if (usb_control_msg
 	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
 	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
 	     300) != 1) {
 	     300) != 1) {
 		printk(KERN_ERR "isight firmware loading completion failed\n");
 		printk(KERN_ERR "isight firmware loading completion failed\n");
 		ret = -ENODEV;
 		ret = -ENODEV;
 	}
 	}
+
 out:
 out:
+	kfree(buf);
 	release_firmware(firmware);
 	release_firmware(firmware);
 	return ret;
 	return ret;
 }
 }