summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-07-14 14:29:49 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2008-07-14 14:29:49 +1000
commit11c2d8174ed3dc4f1971564732689b4a39129702 (patch)
treeac00daa548ea8ac24ae7a5c8062312e335ab9858 /drivers
parentcde274c0c789404df8ece3f9e7d6506caf0127e2 (diff)
parentbce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff)
downloadlinux-11c2d8174ed3dc4f1971564732689b4a39129702.tar.gz
Merge commit 'origin/HEAD' into test-merge
Manual fixup of include/asm-powerpc/pgtable-ppc64.h
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/sleep/main.c5
-rw-r--r--drivers/acpi/sleep/proc.c5
-rw-r--r--drivers/ata/ahci.c23
-rw-r--r--drivers/ata/libata-acpi.c19
-rw-r--r--drivers/ata/libata-sff.c30
-rw-r--r--drivers/ata/pata_sis.c1
-rw-r--r--drivers/ata/sata_mv.c2
-rw-r--r--drivers/ata/sata_sil24.c1
-rw-r--r--drivers/ata/sata_uli.c1
-rw-r--r--drivers/auxdisplay/Kconfig2
-rw-r--r--drivers/auxdisplay/cfag12864b.c4
-rw-r--r--drivers/auxdisplay/cfag12864bfb.c4
-rw-r--r--drivers/auxdisplay/ks0108.c4
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/block/cciss.c70
-rw-r--r--drivers/char/drm/i915_irq.c4
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c3
-rw-r--r--drivers/char/pcmcia/ipwireless/hardware.c4
-rw-r--r--drivers/char/rtc.c3
-rw-r--r--drivers/char/tpm/tpm_tis.c1
-rw-r--r--drivers/char/tty_io.c2
-rw-r--r--drivers/connector/connector.c40
-rw-r--r--drivers/gpio/Kconfig14
-rw-r--r--drivers/gpio/pca953x.c2
-rw-r--r--drivers/hwmon/hdaps.c6
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c28
-rw-r--r--drivers/ide/Kconfig7
-rw-r--r--drivers/ide/arm/Makefile1
-rw-r--r--drivers/ide/arm/bast-ide.c90
-rw-r--r--drivers/ide/arm/palm_bk3710.c38
-rw-r--r--drivers/ide/ide-probe.c10
-rw-r--r--drivers/ide/ide-proc.c2
-rw-r--r--drivers/ide/ide.c24
-rw-r--r--drivers/ide/pci/it8213.c3
-rw-r--r--drivers/ide/pci/ns87415.c6
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c4
-rw-r--r--drivers/input/ff-core.c18
-rw-r--r--drivers/isdn/i4l/isdn_common.c4
-rw-r--r--drivers/md/dm-crypt.c1
-rw-r--r--drivers/md/md.c6
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/md/raid5.c14
-rw-r--r--drivers/media/video/Kconfig8
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/ov7670.c4
-rw-r--r--drivers/media/video/uvc/Makefile3
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c1256
-rw-r--r--drivers/media/video/uvc/uvc_driver.c1955
-rw-r--r--drivers/media/video/uvc/uvc_isight.c134
-rw-r--r--drivers/media/video/uvc/uvc_queue.c477
-rw-r--r--drivers/media/video/uvc/uvc_status.c207
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c1105
-rw-r--r--drivers/media/video/uvc/uvc_video.c934
-rw-r--r--drivers/media/video/uvc/uvcvideo.h796
-rw-r--r--drivers/message/fusion/mptbase.c11
-rw-r--r--drivers/message/fusion/mptspi.c9
-rw-r--r--drivers/mmc/host/pxamci.c13
-rw-r--r--drivers/mmc/host/sdhci.c34
-rw-r--r--drivers/net/3c59x.c5
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000/e1000_ethtool.c2
-rw-r--r--drivers/net/e1000e/netdev.c3
-rw-r--r--drivers/net/ehea/ehea.h8
-rw-r--r--drivers/net/ehea/ehea_main.c42
-rw-r--r--drivers/net/forcedeth.c15
-rw-r--r--drivers/net/fs_enet/mac-fcc.c3
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/ibm_newemac/core.c8
-rw-r--r--drivers/net/igb/igb_main.c3
-rw-r--r--drivers/net/ipg.c16
-rw-r--r--drivers/net/irda/nsc-ircc.c1
-rw-r--r--drivers/net/irda/via-ircc.c3
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/netxen/netxen_nic_main.c18
-rw-r--r--drivers/net/pasemi_mac.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c3
-rw-r--r--drivers/net/qla3xxx.c2
-rw-r--r--drivers/net/r6040.c2
-rw-r--r--drivers/net/s2io.c35
-rw-r--r--drivers/net/s2io.h4
-rw-r--r--drivers/net/tc35815.c4
-rw-r--r--drivers/net/tun.c6
-rw-r--r--drivers/net/wan/hdlc_fr.c1
-rw-r--r--drivers/net/wan/x25_asy.c3
-rw-r--r--drivers/net/wireless/b43/leds.c3
-rw-r--r--drivers/net/wireless/b43/main.c12
-rw-r--r--drivers/net/wireless/b43legacy/dma.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c8
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c20
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c10
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c36
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c42
-rw-r--r--drivers/net/wireless/libertas/if_usb.c1
-rw-r--r--drivers/net/wireless/libertas/scan.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c11
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c43
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c38
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c45
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1
-rw-r--r--drivers/pci/access.c14
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c17
-rw-r--r--drivers/pci/pci-sysfs.c4
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/quirks.c43
-rw-r--r--drivers/rapidio/rio-driver.c2
-rw-r--r--drivers/rtc/interface.c102
-rw-r--r--drivers/rtc/rtc-fm3130.c2
-rw-r--r--drivers/rtc/rtc-pcf8563.c1
-rw-r--r--drivers/rtc/rtc-sa1100.c4
-rw-r--r--drivers/rtc/rtc-x1205.c111
-rw-r--r--drivers/scsi/esp_scsi.c22
-rw-r--r--drivers/scsi/ipr.c6
-rw-r--r--drivers/scsi/scsi_lib.c9
-rw-r--r--drivers/scsi/ses.c2
-rw-r--r--drivers/serial/8250.c3
-rw-r--r--drivers/serial/serial_core.c4
-rw-r--r--drivers/spi/spidev.c10
-rw-r--r--drivers/ssb/driver_pcicore.c7
-rw-r--r--drivers/usb/class/cdc-acm.c3
-rw-r--r--drivers/usb/core/hcd.c47
-rw-r--r--drivers/usb/core/hcd.h2
-rw-r--r--drivers/usb/core/hub.c24
-rw-r--r--drivers/usb/host/ehci.h19
-rw-r--r--drivers/usb/host/ohci-at91.c1
-rw-r--r--drivers/usb/host/ohci-au1xxx.c3
-rw-r--r--drivers/usb/host/ohci-ep93xx.c1
-rw-r--r--drivers/usb/host/ohci-hcd.c15
-rw-r--r--drivers/usb/host/ohci-hub.c53
-rw-r--r--drivers/usb/host/ohci-lh7a404.c3
-rw-r--r--drivers/usb/host/ohci-omap.c1
-rw-r--r--drivers/usb/host/ohci-pci.c1
-rw-r--r--drivers/usb/host/ohci-pnx4008.c1
-rw-r--r--drivers/usb/host/ohci-pnx8550.c1
-rw-r--r--drivers/usb/host/ohci-ppc-of.c1
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c1
-rw-r--r--drivers/usb/host/ohci-ps3.c1
-rw-r--r--drivers/usb/host/ohci-pxa27x.c1
-rw-r--r--drivers/usb/host/ohci-q.c12
-rw-r--r--drivers/usb/host/ohci-s3c2410.c3
-rw-r--r--drivers/usb/host/ohci-sa1111.c3
-rw-r--r--drivers/usb/host/ohci-sh.c1
-rw-r--r--drivers/usb/host/ohci-sm501.c1
-rw-r--r--drivers/usb/host/ohci-ssb.c1
-rw-r--r--drivers/usb/host/u132-hcd.c11
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio.h3
-rw-r--r--drivers/usb/serial/ipaq.c7
-rw-r--r--drivers/usb/serial/option.c1
-rw-r--r--drivers/usb/serial/pl2303.c1
-rw-r--r--drivers/usb/serial/pl2303.h1
-rw-r--r--drivers/usb/storage/unusual_devs.h8
-rw-r--r--drivers/video/Kconfig3
-rw-r--r--drivers/video/fb_defio.c20
-rw-r--r--drivers/video/fsl-diu-fb.c25
-rw-r--r--drivers/video/pxafb.c52
-rw-r--r--drivers/video/w100fb.c1
169 files changed, 8170 insertions, 522 deletions
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index c3b0cd88d09f..495c63a3e0af 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -36,9 +36,8 @@ static int acpi_sleep_prepare(u32 acpi_state)
 		if (!acpi_wakeup_address) {
 			return -EFAULT;
 		}
-		acpi_set_firmware_waking_vector((acpi_physical_address)
-						virt_to_phys((void *)
-							     acpi_wakeup_address));
+		acpi_set_firmware_waking_vector(
+				(acpi_physical_address)acpi_wakeup_address);
 
 	}
 	ACPI_FLUSH_CPU_CACHE();
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 224c57c03381..4ebbba2b6b19 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -315,8 +315,11 @@ acpi_system_write_alarm(struct file *file,
 		cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control);
 	if (acpi_gbl_FADT.month_alarm)
 		cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control);
-	if (acpi_gbl_FADT.century)
+	if (acpi_gbl_FADT.century) {
+		if (adjust)
+			yr += cmos_bcd_read(acpi_gbl_FADT.century, rtc_control) * 100;
 		cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control);
+	}
 	/* enable the rtc alarm interrupt */
 	rtc_control |= RTC_AIE;
 	CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 6a4a2a25d97a..5e6468a7ca4b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1777,7 +1777,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 	struct ahci_host_priv *hpriv;
 	unsigned int i, handled = 0;
 	void __iomem *mmio;
-	u32 irq_stat, irq_ack = 0;
+	u32 irq_stat, irq_masked;
 
 	VPRINTK("ENTER\n");
 
@@ -1786,16 +1786,17 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 
 	/* sigh.  0xffffffff is a valid return from h/w */
 	irq_stat = readl(mmio + HOST_IRQ_STAT);
-	irq_stat &= hpriv->port_map;
 	if (!irq_stat)
 		return IRQ_NONE;
 
+	irq_masked = irq_stat & hpriv->port_map;
+
 	spin_lock(&host->lock);
 
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap;
 
-		if (!(irq_stat & (1 << i)))
+		if (!(irq_masked & (1 << i)))
 			continue;
 
 		ap = host->ports[i];
@@ -1809,14 +1810,20 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 					"interrupt on disabled port %u\n", i);
 		}
 
-		irq_ack |= (1 << i);
-	}
-
-	if (irq_ack) {
-		writel(irq_ack, mmio + HOST_IRQ_STAT);
 		handled = 1;
 	}
 
+	/* HOST_IRQ_STAT behaves as level triggered latch meaning that
+	 * it should be cleared after all the port events are cleared;
+	 * otherwise, it will raise a spurious interrupt after each
+	 * valid one.  Please read section 10.6.2 of ahci 1.1 for more
+	 * information.
+	 *
+	 * Also, use the unmasked value to clear interrupt as spurious
+	 * pending event on a dummy port might cause screaming IRQ.
+	 */
+	writel(irq_stat, mmio + HOST_IRQ_STAT);
+
 	spin_unlock(&host->lock);
 
 	VPRINTK("EXIT\n");
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 3ff8b14420d9..9330b7922f62 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -29,14 +29,16 @@
 enum {
 	ATA_ACPI_FILTER_SETXFER	= 1 << 0,
 	ATA_ACPI_FILTER_LOCK	= 1 << 1,
+	ATA_ACPI_FILTER_DIPM	= 1 << 2,
 
 	ATA_ACPI_FILTER_DEFAULT	= ATA_ACPI_FILTER_SETXFER |
-				  ATA_ACPI_FILTER_LOCK,
+				  ATA_ACPI_FILTER_LOCK |
+				  ATA_ACPI_FILTER_DIPM,
 };
 
 static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
 module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
-MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock)");
+MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM)");
 
 #define NO_PORT_MULT		0xffff
 #define SATA_ADR(root, pmp)	(((root) << 16) | (pmp))
@@ -195,6 +197,10 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
 		/* This device does not support hotplug */
 		return;
 
+	if (event == ACPI_NOTIFY_BUS_CHECK ||
+	    event == ACPI_NOTIFY_DEVICE_CHECK)
+		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+
 	spin_lock_irqsave(ap->lock, flags);
 
 	switch (event) {
@@ -202,7 +208,6 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		ata_ehi_push_desc(ehi, "ACPI event");
 
-		status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
 		if (ACPI_FAILURE(status)) {
 			ata_port_printk(ap, KERN_ERR,
 				"acpi: failed to determine bay status (0x%x)\n",
@@ -690,6 +695,14 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
 			return 1;
 	}
 
+	if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_DIPM) {
+		/* inhibit enabling DIPM */
+		if (tf->command == ATA_CMD_SET_FEATURES &&
+		    tf->feature == SETFEATURES_SATA_ENABLE &&
+		    tf->nsect == SATA_DIPM)
+			return 1;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 215d18672a5a..c0908c225483 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1094,6 +1094,7 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
 int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
 		     u8 status, int in_wq)
 {
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	unsigned long flags = 0;
 	int poll_next;
 
@@ -1125,9 +1126,12 @@ fsm_start:
 			if (likely(status & (ATA_ERR | ATA_DF)))
 				/* device stops HSM for abort/error */
 				qc->err_mask |= AC_ERR_DEV;
-			else
+			else {
 				/* HSM violation. Let EH handle this */
+				ata_ehi_push_desc(ehi,
+					"ST_FIRST: !(DRQ|ERR|DF)");
 				qc->err_mask |= AC_ERR_HSM;
+			}
 
 			ap->hsm_task_state = HSM_ST_ERR;
 			goto fsm_start;
@@ -1146,9 +1150,9 @@ fsm_start:
 			 * the CDB.
 			 */
 			if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
-				ata_port_printk(ap, KERN_WARNING,
-						"DRQ=1 with device error, "
-						"dev_stat 0x%X\n", status);
+				ata_ehi_push_desc(ehi, "ST_FIRST: "
+					"DRQ=1 with device error, "
+					"dev_stat 0x%X", status);
 				qc->err_mask |= AC_ERR_HSM;
 				ap->hsm_task_state = HSM_ST_ERR;
 				goto fsm_start;
@@ -1205,9 +1209,9 @@ fsm_start:
 			 * let the EH abort the command or reset the device.
 			 */
 			if (unlikely(status & (ATA_ERR | ATA_DF))) {
-				ata_port_printk(ap, KERN_WARNING, "DRQ=1 with "
-						"device error, dev_stat 0x%X\n",
-						status);
+				ata_ehi_push_desc(ehi, "ST-ATAPI: "
+					"DRQ=1 with device error, "
+					"dev_stat 0x%X", status);
 				qc->err_mask |= AC_ERR_HSM;
 				ap->hsm_task_state = HSM_ST_ERR;
 				goto fsm_start;
@@ -1226,13 +1230,17 @@ fsm_start:
 				if (likely(status & (ATA_ERR | ATA_DF)))
 					/* device stops HSM for abort/error */
 					qc->err_mask |= AC_ERR_DEV;
-				else
+				else {
 					/* HSM violation. Let EH handle this.
 					 * Phantom devices also trigger this
 					 * condition.  Mark hint.
 					 */
+					ata_ehi_push_desc(ehi, "ST-ATA: "
+						"DRQ=1 with device error, "
+						"dev_stat 0x%X", status);
 					qc->err_mask |= AC_ERR_HSM |
 							AC_ERR_NODEV_HINT;
+				}
 
 				ap->hsm_task_state = HSM_ST_ERR;
 				goto fsm_start;
@@ -1257,8 +1265,12 @@ fsm_start:
 					status = ata_wait_idle(ap);
 				}
 
-				if (status & (ATA_BUSY | ATA_DRQ))
+				if (status & (ATA_BUSY | ATA_DRQ)) {
+					ata_ehi_push_desc(ehi, "ST-ATA: "
+						"BUSY|DRQ persists on ERR|DF, "
+						"dev_stat 0x%X", status);
 					qc->err_mask |= AC_ERR_HSM;
+				}
 
 				/* ata_pio_sectors() might change the
 				 * state to HSM_ST_LAST. so, the state
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index e82c66e8d31b..26345d7b531c 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -56,6 +56,7 @@ static const struct sis_laptop sis_laptop[] = {
 	{ 0x5513, 0x1043, 0x1107 },	/* ASUS A6K */
 	{ 0x5513, 0x1734, 0x105F },	/* FSC Amilo A1630 */
 	{ 0x5513, 0x1071, 0x8640 },     /* EasyNote K5305 */
+	{ 0x5513, 0x1039, 0x5513 },	/* Targa Visionary 1000 */
 	/* end marker */
 	{ 0, }
 };
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 28092bc50146..ad169ffbc4cb 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -1607,7 +1607,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
 		 * Much of the time, this could just work regardless.
 		 * So for now, just log the incident, and allow the attempt.
 		 */
-		if (limit_warnings && (qc->nbytes / qc->sect_size) > 1) {
+		if (limit_warnings > 0 && (qc->nbytes / qc->sect_size) > 1) {
 			--limit_warnings;
 			ata_link_printk(qc->dev->link, KERN_WARNING, DRV_NAME
 					": attempting PIO w/multiple DRQ: "
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 8ee6b5b4ede7..84ffcc26a74b 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -370,6 +370,7 @@ static const struct pci_device_id sil24_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
 	{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
 	{ PCI_VDEVICE(CMD, 0x0242), BID_SIL3132 },
+	{ PCI_VDEVICE(CMD, 0x0244), BID_SIL3132 },
 	{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
 	{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
 
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index f277cea904ce..db529b849948 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -83,6 +83,7 @@ static struct ata_port_operations uli_ops = {
 	.inherits		= &ata_bmdma_port_ops,
 	.scr_read		= uli_scr_read,
 	.scr_write		= uli_scr_write,
+	.hardreset		= ATA_OP_NULL,
 };
 
 static const struct ata_port_info uli_port_info = {
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 043353bd0600..14b9d5f4c203 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -64,7 +64,7 @@ config KS0108_DELAY
 	  Amount of time the ks0108 should wait between each control write
 	  to the parallel port.
 
-	  If your driver seems to miss random writings, increment this.
+	  If your LCD seems to miss random writings, increment this.
 
 	  If you don't know what I'm talking about, ignore it.
 
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c
index 80bb06105387..683509f013ab 100644
--- a/drivers/auxdisplay/cfag12864b.c
+++ b/drivers/auxdisplay/cfag12864b.c
@@ -5,7 +5,7 @@
  *     License: GPLv2
  *     Depends: ks0108
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -398,5 +398,5 @@ module_init(cfag12864b_init);
 module_exit(cfag12864b_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 MODULE_DESCRIPTION("cfag12864b LCD driver");
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c
index 307c190699e0..fe3a865be4e5 100644
--- a/drivers/auxdisplay/cfag12864bfb.c
+++ b/drivers/auxdisplay/cfag12864bfb.c
@@ -5,7 +5,7 @@
  *     License: GPLv2
  *     Depends: cfag12864b
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -186,5 +186,5 @@ module_init(cfag12864bfb_init);
 module_exit(cfag12864bfb_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver");
diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c
index e6c3646ef18c..5b93852392b8 100644
--- a/drivers/auxdisplay/ks0108.c
+++ b/drivers/auxdisplay/ks0108.c
@@ -5,7 +5,7 @@
  *     License: GPLv2
  *     Depends: parport
  *
- *      Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com>
+ *      Author: Copyright (C) Miguel Ojeda Sandonis
  *        Date: 2006-10-31
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -173,6 +173,6 @@ module_init(ks0108_init);
 module_exit(ks0108_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>");
+MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 MODULE_DESCRIPTION("ks0108 LCD Controller driver");
 
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 39f3d1b3a213..0f867a083338 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -84,8 +84,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
 		       nid, K(i.totalram),
 		       nid, K(i.freeram),
 		       nid, K(i.totalram - i.freeram),
-		       nid, node_page_state(nid, NR_ACTIVE),
-		       nid, node_page_state(nid, NR_INACTIVE),
+		       nid, K(node_page_state(nid, NR_ACTIVE)),
+		       nid, K(node_page_state(nid, NR_INACTIVE)),
 #ifdef CONFIG_HIGHMEM
 		       nid, K(i.totalhigh),
 		       nid, K(i.freehigh),
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 5f1e1cc6165a..d81632cd7d06 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -106,35 +106,34 @@ MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 /*  board_id = Subsystem Device ID & Vendor ID
  *  product = Marketing Name for the board
  *  access = Address of the struct of function pointers
- *  nr_cmds = Number of commands supported by controller
  */
 static struct board_type products[] = {
-	{0x40700E11, "Smart Array 5300", &SA5_access, 512},
-	{0x40800E11, "Smart Array 5i", &SA5B_access, 512},
-	{0x40820E11, "Smart Array 532", &SA5B_access, 512},
-	{0x40830E11, "Smart Array 5312", &SA5B_access, 512},
-	{0x409A0E11, "Smart Array 641", &SA5_access, 512},
-	{0x409B0E11, "Smart Array 642", &SA5_access, 512},
-	{0x409C0E11, "Smart Array 6400", &SA5_access, 512},
-	{0x409D0E11, "Smart Array 6400 EM", &SA5_access, 512},
-	{0x40910E11, "Smart Array 6i", &SA5_access, 512},
-	{0x3225103C, "Smart Array P600", &SA5_access, 512},
-	{0x3223103C, "Smart Array P800", &SA5_access, 512},
-	{0x3234103C, "Smart Array P400", &SA5_access, 512},
-	{0x3235103C, "Smart Array P400i", &SA5_access, 512},
-	{0x3211103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3212103C, "Smart Array E200", &SA5_access, 120},
-	{0x3213103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3214103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3215103C, "Smart Array E200i", &SA5_access, 120},
-	{0x3237103C, "Smart Array E500", &SA5_access, 512},
-	{0x323D103C, "Smart Array P700m", &SA5_access, 512},
-	{0x3241103C, "Smart Array P212", &SA5_access, 384},
-	{0x3243103C, "Smart Array P410", &SA5_access, 384},
-	{0x3245103C, "Smart Array P410i", &SA5_access, 384},
-	{0x3247103C, "Smart Array P411", &SA5_access, 384},
-	{0x3249103C, "Smart Array P812", &SA5_access, 384},
-	{0xFFFF103C, "Unknown Smart Array", &SA5_access, 120},
+	{0x40700E11, "Smart Array 5300", &SA5_access},
+	{0x40800E11, "Smart Array 5i", &SA5B_access},
+	{0x40820E11, "Smart Array 532", &SA5B_access},
+	{0x40830E11, "Smart Array 5312", &SA5B_access},
+	{0x409A0E11, "Smart Array 641", &SA5_access},
+	{0x409B0E11, "Smart Array 642", &SA5_access},
+	{0x409C0E11, "Smart Array 6400", &SA5_access},
+	{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
+	{0x40910E11, "Smart Array 6i", &SA5_access},
+	{0x3225103C, "Smart Array P600", &SA5_access},
+	{0x3223103C, "Smart Array P800", &SA5_access},
+	{0x3234103C, "Smart Array P400", &SA5_access},
+	{0x3235103C, "Smart Array P400i", &SA5_access},
+	{0x3211103C, "Smart Array E200i", &SA5_access},
+	{0x3212103C, "Smart Array E200", &SA5_access},
+	{0x3213103C, "Smart Array E200i", &SA5_access},
+	{0x3214103C, "Smart Array E200i", &SA5_access},
+	{0x3215103C, "Smart Array E200i", &SA5_access},
+	{0x3237103C, "Smart Array E500", &SA5_access},
+	{0x323D103C, "Smart Array P700m", &SA5_access},
+	{0x3241103C, "Smart Array P212", &SA5_access},
+	{0x3243103C, "Smart Array P410", &SA5_access},
+	{0x3245103C, "Smart Array P410i", &SA5_access},
+	{0x3247103C, "Smart Array P411", &SA5_access},
+	{0x3249103C, "Smart Array P812", &SA5_access},
+	{0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
 /* How long to wait (in milliseconds) for board to go into simple mode */
@@ -3086,11 +3085,20 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 	print_cfg_table(c->cfgtable);
 #endif				/* CCISS_DEBUG */
 
+	/* Some controllers support Zero Memory Raid (ZMR).
+	 * When configured in ZMR mode the number of supported
+	 * commands drops to 64. So instead of just setting an
+	 * arbitrary value we make the driver a little smarter.
+	 * We read the config table to tell us how many commands
+	 * are supported on the controller then subtract 4 to
+	 * leave a little room for ioctl calls.
+	 */
+	c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
 	for (i = 0; i < ARRAY_SIZE(products); i++) {
 		if (board_id == products[i].board_id) {
 			c->product_name = products[i].product_name;
 			c->access = *(products[i].access);
-			c->nr_cmds = products[i].nr_cmds;
+			c->nr_cmds = c->max_commands - 4;
 			break;
 		}
 	}
@@ -3110,7 +3118,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
 		if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
 			c->product_name = products[i-1].product_name;
 			c->access = *(products[i-1].access);
-			c->nr_cmds = products[i-1].nr_cmds;
+			c->nr_cmds = c->max_commands - 4;
 			printk(KERN_WARNING "cciss: This is an unknown "
 				"Smart Array controller.\n"
 				"cciss: Please update to the latest driver "
@@ -3546,6 +3554,10 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 	for (j = 0; j <= hba[i]->highest_lun; j++)
 		add_disk(hba[i]->gendisk[j]);
 
+	/* we must register the controller even if no disks exist */
+	if (hba[i]->highest_lun == -1)
+		add_disk(hba[i]->gendisk[0]);
+
 	return 1;
 
       clean4:
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index f7f16e7a8bf3..df036118b8b1 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -62,11 +62,11 @@ static void i915_vblank_tasklet(struct drm_device *dev)
 	u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
 	RING_LOCALS;
 
-	if (sarea_priv->front_tiled) {
+	if (IS_I965G(dev) && sarea_priv->front_tiled) {
 		cmd |= XY_SRC_COPY_BLT_DST_TILED;
 		dst_pitch >>= 2;
 	}
-	if (sarea_priv->back_tiled) {
+	if (IS_I965G(dev) && sarea_priv->back_tiled) {
 		cmd |= XY_SRC_COPY_BLT_SRC_TILED;
 		src_pitch >>= 2;
 	}
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 1b9a87047817..0e6df289cb46 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -755,9 +755,8 @@ static ssize_t ipmi_write(struct file *file,
 		rv = ipmi_heartbeat();
 		if (rv)
 			return rv;
-		return 1;
 	}
-	return 0;
+	return len;
 }
 
 static ssize_t ipmi_read(struct file *file,
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
index ba6340ae98af..929101ecbae2 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.c
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -590,8 +590,10 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw,
 		packet = kmalloc(sizeof(struct ipw_rx_packet) +
 				old_packet->length + minimum_free_space,
 				GFP_ATOMIC);
-		if (!packet)
+		if (!packet) {
+			kfree(old_packet);
 			return NULL;
+		}
 		memcpy(packet, old_packet,
 				sizeof(struct ipw_rx_packet)
 					+ old_packet->length);
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 5f80a9dff573..909cac93fa2a 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -678,12 +678,13 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 		if (arg != (1<<tmp))
 			return -EINVAL;
 
+		rtc_freq = arg;
+
 		spin_lock_irqsave(&rtc_lock, flags);
 		if (hpet_set_periodic_freq(arg)) {
 			spin_unlock_irqrestore(&rtc_lock, flags);
 			return 0;
 		}
-		rtc_freq = arg;
 
 		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
 		val |= (16 - tmp);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 13a4bdd4e4d6..c7a977bc03e8 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -623,6 +623,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
 	{"IFX0102", 0},		/* Infineon */
 	{"BCM0101", 0},		/* Broadcom */
 	{"NSC1200", 0},		/* National */
+	{"ICO0102", 0},		/* Intel */
 	/* Add new here */
 	{"", 0},		/* User Specified */
 	{"", 0}			/* Terminator */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index e94bee032314..750131010af0 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3322,7 +3322,7 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
 		msleep_interruptible(duration);
 	tty->ops->break_ctl(tty, 0);
 	tty_write_unlock(tty);
-	if (!signal_pending(current))
+	if (signal_pending(current))
 		return -EINTR;
 	return 0;
 }
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 85e2ba7fcfba..bf4830082a13 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -27,6 +27,8 @@
 #include <linux/moduleparam.h>
 #include <linux/connector.h>
 #include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 
 #include <net/sock.h>
 
@@ -403,6 +405,40 @@ static void cn_callback(void *data)
 	mutex_unlock(&notify_lock);
 }
 
+static int cn_proc_show(struct seq_file *m, void *v)
+{
+	struct cn_queue_dev *dev = cdev.cbdev;
+	struct cn_callback_entry *cbq;
+
+	seq_printf(m, "Name            ID\n");
+
+	spin_lock_bh(&dev->queue_lock);
+
+	list_for_each_entry(cbq, &dev->queue_list, callback_entry) {
+		seq_printf(m, "%-15s %u:%u\n",
+			   cbq->id.name,
+			   cbq->id.id.idx,
+			   cbq->id.id.val);
+	}
+
+	spin_unlock_bh(&dev->queue_lock);
+
+	return 0;
+}
+
+static int cn_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cn_proc_show, NULL);
+}
+
+static const struct file_operations cn_file_ops = {
+	.owner   = THIS_MODULE,
+	.open    = cn_proc_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release
+};
+
 static int __devinit cn_init(void)
 {
 	struct cn_dev *dev = &cdev;
@@ -434,6 +470,8 @@ static int __devinit cn_init(void)
 		return -EINVAL;
 	}
 
+	proc_net_fops_create(&init_net, "connector", S_IRUGO, &cn_file_ops);
+
 	return 0;
 }
 
@@ -443,6 +481,8 @@ static void __devexit cn_fini(void)
 
 	cn_already_initialized = 0;
 
+	proc_net_remove(&init_net, "connector");
+
 	cn_del_callback(&dev->id);
 	cn_queue_free_dev(dev->cbdev);
 	netlink_kernel_release(dev->nls);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index bbd28342e771..008c38ba774f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -28,12 +28,18 @@ config DEBUG_GPIO
 comment "I2C GPIO expanders:"
 
 config GPIO_PCA953X
-	tristate "PCA953x I/O ports"
+	tristate "PCA953x, PCA955x, and MAX7310 I/O ports"
 	depends on I2C
 	help
-	  Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit),
-	  PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539
-	  (16-bit) I/O ports. These parts are made by NXP and TI.
+	  Say yes here to provide access to several register-oriented
+	  SMBus I/O expanders, made mostly by NXP or TI.  Compatible
+	  models include:
+
+	  4 bits:	pca9536, pca9537
+
+	  8 bits:	max7310, pca9534, pca9538, pca9554, pca9557
+
+	  16 bits:	pca9535, pca9539, pca9555
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called pca953x.
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 7e40e8a55edf..a380730b61ab 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -33,7 +33,7 @@ static const struct i2c_device_id pca953x_id[] = {
 	{ "pca9554", 8, },
 	{ "pca9555", 16, },
 	{ "pca9557", 8, },
-	/* REVISIT several pca955x parts should work here too */
+	{ "max7310", 8, },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 26df06f840eb..50f22690d611 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -516,17 +516,23 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = {
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"),
 	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"),
 	HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"),
 	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"),
 	HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"),
+	HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"),
 	{ .ident = NULL }
 };
 
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 1305ef190fc1..9e8c875437be 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -290,12 +290,12 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 		 * bus, or started a new i2c message
 		 */
 		
-		if (iicstat  & S3C2410_IICSTAT_LASTBIT &&
+		if (iicstat & S3C2410_IICSTAT_LASTBIT &&
 		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
 			/* ack was not received... */
 
 			dev_dbg(i2c->dev, "ack was not received\n");
-			s3c24xx_i2c_stop(i2c, -EREMOTEIO);
+			s3c24xx_i2c_stop(i2c, -ENXIO);
 			goto out_ack;
 		}
 
@@ -305,7 +305,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 			i2c->state = STATE_WRITE;
 
 		/* terminate the transfer if there is nothing to do
-		 * (used by the i2c probe to find devices */
+		 * as this is used by the i2c probe to find devices. */
 
 		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
 			s3c24xx_i2c_stop(i2c, 0);
@@ -323,7 +323,17 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 		 * end of the message, and if so, work out what to do
 		 */
 
+		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+				dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+				s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+				goto out_ack;
+			}
+		}
+
 	retry_write:
+
 		if (!is_msgend(i2c)) {
 			byte = i2c->msg->buf[i2c->msg_ptr++];
 			writeb(byte, i2c->regs + S3C2410_IICDS);
@@ -377,17 +387,6 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
 		 * going to do any more read/write
 		 */
 
-		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
-		    !(is_msglast(i2c) && is_lastmsg(i2c))) {
-
-			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
-				dev_dbg(i2c->dev, "READ: No Ack\n");
-
-				s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
-				goto out_ack;
-			}
-		}
-
 		byte = readb(i2c->regs + S3C2410_IICDS);
 		i2c->msg->buf[i2c->msg_ptr++] = byte;
 
@@ -949,3 +948,4 @@ MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:s3c2410-i2c");
+MODULE_ALIAS("platform:s3c2440-i2c");
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 8e07de23d220..1607536ff5fb 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -823,6 +823,13 @@ config BLK_DEV_IDE_RAPIDE
 	  Say Y here if you want to support the Yellowstone RapIDE controller
 	  manufactured for use with Acorn computers.
 
+config BLK_DEV_IDE_BAST
+	tristate "Simtec BAST / Thorcom VR1000 IDE support"
+	depends on ARM && (ARCH_BAST || MACH_VR1000)
+	help
+	  Say Y here if you want to support the onboard IDE channels on the
+	  Simtec BAST or the Thorcom VR1000
+
 config IDE_H8300
 	tristate "H8300 IDE support"
 	depends on H8300
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
index 5bc26053afa6..936e7b0237f5 100644
--- a/drivers/ide/arm/Makefile
+++ b/drivers/ide/arm/Makefile
@@ -1,6 +1,7 @@
 
 obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
+obj-$(CONFIG_BLK_DEV_IDE_BAST)		+= bast-ide.o
 obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710)	+= palm_bk3710.o
 
 ifeq ($(CONFIG_IDE_ARM), m)
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
new file mode 100644
index 000000000000..8e8c28104b45
--- /dev/null
+++ b/drivers/ide/arm/bast-ide.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2003-2004 Simtec Electronics
+ *  Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/arch/map.h>
+#include <asm/arch/bast-map.h>
+#include <asm/arch/bast-irq.h>
+
+#define DRV_NAME "bast-ide"
+
+static int __init bastide_register(unsigned int base, unsigned int aux, int irq)
+{
+	ide_hwif_t *hwif;
+	hw_regs_t hw;
+	int i;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
+	memset(&hw, 0, sizeof(hw));
+
+	base += BAST_IDE_CS;
+	aux  += BAST_IDE_CS;
+
+	for (i = 0; i <= 7; i++) {
+		hw.io_ports_array[i] = (unsigned long)base;
+		base += 0x20;
+	}
+
+	hw.io_ports.ctl_addr = aux + (6 * 0x20);
+	hw.irq = irq;
+	hw.chipset = ide_generic;
+
+	hwif = ide_find_port();
+	if (hwif == NULL)
+		goto out;
+
+	i = hwif->index;
+
+	ide_init_port_data(hwif, i);
+	ide_init_port_hw(hwif, &hw);
+	hwif->port_ops = NULL;
+
+	idx[0] = i;
+
+	ide_device_add(idx, NULL);
+out:
+	return 0;
+}
+
+static int __init bastide_init(void)
+{
+	unsigned long base = BAST_VA_IDEPRI + BAST_IDE_CS;
+
+	/* we can treat the VR1000 and the BAST the same */
+
+	if (!(machine_is_bast() || machine_is_vr1000()))
+		return 0;
+
+	printk("BAST: IDE driver, (c) 2003-2004 Simtec Electronics\n");
+
+	if (!request_mem_region(base, 0x400000, DRV_NAME)) {
+		printk(KERN_ERR "%s: resources busy\n", DRV_NAME);
+		return -EBUSY;
+	}
+
+	bastide_register(BAST_VA_IDEPRI, BAST_VA_IDEPRIAUX, IRQ_IDE0);
+	bastide_register(BAST_VA_IDESEC, BAST_VA_IDESECAUX, IRQ_IDE1);
+
+	return 0;
+}
+
+module_init(bastide_init);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Simtec BAST / Thorcom VR1000 IDE driver");
diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c
index cc24803fadff..2f2b4f4cf229 100644
--- a/drivers/ide/arm/palm_bk3710.c
+++ b/drivers/ide/arm/palm_bk3710.c
@@ -76,7 +76,7 @@ struct palm_bk3710_udmatiming {
 
 #include "../ide-timing.h"
 
-static long ide_palm_clk;
+static unsigned ideclk_period; /* in nanoseconds */
 
 static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
 	{160, 240},		/* UDMA Mode 0 */
@@ -86,8 +86,6 @@ static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = {
 	{85,  60},		/* UDMA Mode 4 */
 };
 
-static struct clk *ideclkp;
-
 static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
 				    unsigned int mode)
 {
@@ -97,10 +95,10 @@ static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev,
 
 	/* DMA Data Setup */
 	t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime,
-			  ide_palm_clk) - 1;
-	tenv = DIV_ROUND_UP(20, ide_palm_clk) - 1;
+			  ideclk_period) - 1;
+	tenv = DIV_ROUND_UP(20, ideclk_period) - 1;
 	trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime,
-			   ide_palm_clk) - 1;
+			   ideclk_period) - 1;
 
 	/* udmatim Register */
 	val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0);
@@ -141,8 +139,8 @@ static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev,
 	cycletime = max_t(int, t->cycle, min_cycle);
 
 	/* DMA Data Setup */
-	t0 = DIV_ROUND_UP(cycletime, ide_palm_clk);
-	td = DIV_ROUND_UP(t->active, ide_palm_clk);
+	t0 = DIV_ROUND_UP(cycletime, ideclk_period);
+	td = DIV_ROUND_UP(t->active, ideclk_period);
 	tkw = t0 - td - 1;
 	td -= 1;
 
@@ -168,9 +166,9 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
 	struct ide_timing *t;
 
 	/* PIO Data Setup */
-	t0 = DIV_ROUND_UP(cycletime, ide_palm_clk);
+	t0 = DIV_ROUND_UP(cycletime, ideclk_period);
 	t2 = DIV_ROUND_UP(ide_timing_find_mode(XFER_PIO_0 + mode)->active,
-			  ide_palm_clk);
+			  ideclk_period);
 
 	t2i = t0 - t2 - 1;
 	t2 -= 1;
@@ -192,8 +190,8 @@ static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate,
 
 	/* TASKFILE Setup */
 	t = ide_timing_find_mode(XFER_PIO_0 + mode);
-	t0 = DIV_ROUND_UP(t->cyc8b, ide_palm_clk);
-	t2 = DIV_ROUND_UP(t->act8b, ide_palm_clk);
+	t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period);
+	t2 = DIV_ROUND_UP(t->act8b, ideclk_period);
 
 	t2i = t0 - t2 - 1;
 	t2 -= 1;
@@ -350,22 +348,22 @@ static const struct ide_port_info __devinitdata palm_bk3710_port_info = {
 
 static int __devinit palm_bk3710_probe(struct platform_device *pdev)
 {
-	struct clk *clkp;
+	struct clk *clk;
 	struct resource *mem, *irq;
 	ide_hwif_t *hwif;
-	unsigned long base;
+	unsigned long base, rate;
 	int i;
 	hw_regs_t hw;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
-	clkp = clk_get(NULL, "IDECLK");
-	if (IS_ERR(clkp))
+	clk = clk_get(NULL, "IDECLK");
+	if (IS_ERR(clk))
 		return -ENODEV;
 
-	ideclkp = clkp;
-	clk_enable(ideclkp);
-	ide_palm_clk = clk_get_rate(ideclkp)/100000;
-	ide_palm_clk = (10000/ide_palm_clk) + 1;
+	clk_enable(clk);
+	rate = clk_get_rate(clk);
+	ideclk_period = 1000000000UL / rate;
+
 	/* Register the IDE interface with Linux ATA Interface */
 	memset(&hw, 0, sizeof(hw));
 
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 380fa0c8cc84..26e68b65b7cf 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -646,8 +646,6 @@ static int ide_register_port(ide_hwif_t *hwif)
 		goto out;
 	}
 
-	get_device(&hwif->gendev);
-
 	hwif->portdev = device_create_drvdata(ide_port_class, &hwif->gendev,
 					      MKDEV(0, 0), hwif, hwif->name);
 	if (IS_ERR(hwif->portdev)) {
@@ -1220,16 +1218,12 @@ static void drive_release_dev (struct device *dev)
 	complete(&drive->gendev_rel_comp);
 }
 
-#ifndef ide_default_irq
-#define ide_default_irq(irq) 0
-#endif
-
 static int hwif_init(ide_hwif_t *hwif)
 {
 	int old_irq;
 
 	if (!hwif->irq) {
-		hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+		hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
 		if (!hwif->irq) {
 			printk("%s: DISABLED, NO IRQ\n", hwif->name);
 			return 0;
@@ -1259,7 +1253,7 @@ static int hwif_init(ide_hwif_t *hwif)
 	 *	It failed to initialise. Find the default IRQ for 
 	 *	this port and try that.
 	 */
-	hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+	hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
 	if (!hwif->irq) {
 		printk("%s: Disabled unable to get IRQ %d.\n",
 			hwif->name, old_irq);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 55ec7f798772..8af88bf0969b 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -76,7 +76,7 @@ static int proc_ide_read_mate
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
 	int		len;
 
-	if (hwif && hwif->mate && hwif->mate->present)
+	if (hwif && hwif->mate)
 		len = sprintf(page, "%s\n", hwif->mate->name);
 	else
 		len = sprintf(page, "(none)\n");
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index c758dcb13b14..300431d080a9 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -315,13 +315,14 @@ void ide_unregister(ide_hwif_t *hwif)
 
 	BUG_ON(in_interrupt());
 	BUG_ON(irqs_disabled());
+
 	mutex_lock(&ide_cfg_mtx);
-	spin_lock_irq(&ide_lock);
-	if (!hwif->present)
-		goto abort;
-	__ide_port_unregister_devices(hwif);
-	hwif->present = 0;
 
+	spin_lock_irq(&ide_lock);
+	if (hwif->present) {
+		__ide_port_unregister_devices(hwif);
+		hwif->present = 0;
+	}
 	spin_unlock_irq(&ide_lock);
 
 	ide_proc_unregister_port(hwif);
@@ -351,16 +352,15 @@ void ide_unregister(ide_hwif_t *hwif)
 	blk_unregister_region(MKDEV(hwif->major, 0), MAX_DRIVES<<PARTN_BITS);
 	kfree(hwif->sg_table);
 	unregister_blkdev(hwif->major, hwif->name);
-	spin_lock_irq(&ide_lock);
 
 	if (hwif->dma_base)
 		ide_release_dma_engine(hwif);
 
+	spin_lock_irq(&ide_lock);
 	/* restore hwif data to pristine status */
 	ide_init_port_data(hwif, hwif->index);
-
-abort:
 	spin_unlock_irq(&ide_lock);
+
 	mutex_unlock(&ide_cfg_mtx);
 }
 
@@ -1094,13 +1094,6 @@ struct bus_type ide_bus_type = {
 
 EXPORT_SYMBOL_GPL(ide_bus_type);
 
-static void ide_port_class_release(struct device *portdev)
-{
-	ide_hwif_t *hwif = dev_get_drvdata(portdev);
-
-	put_device(&hwif->gendev);
-}
-
 int ide_vlb_clk;
 EXPORT_SYMBOL_GPL(ide_vlb_clk);
 
@@ -1305,7 +1298,6 @@ static int __init ide_init(void)
 		ret = PTR_ERR(ide_port_class);
 		goto out_port_class;
 	}
-	ide_port_class->dev_release = ide_port_class_release;
 
 	init_ide_data();
 
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 9053c8771e6e..2b71bdf74e73 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -184,8 +184,7 @@ static const struct ide_port_info it8213_chipsets[] __devinitdata = {
 
 static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
-	return 0;
+	return ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
 }
 
 static const struct pci_device_id it8213_pci_tbl[] = {
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index fec4955f449b..a7a41bb82778 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -225,10 +225,6 @@ static int ns87415_dma_setup(ide_drive_t *drive)
 	return 1;
 }
 
-#ifndef ide_default_irq
-#define ide_default_irq(irq) 0
-#endif
-
 static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -288,7 +284,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 	}
 
 	if (!using_inta)
-		hwif->irq = ide_default_irq(hwif->io_ports.data_addr);
+		hwif->irq = __ide_default_irq(hwif->io_ports.data_addr);
 	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
 		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
 
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 8934178a23ee..95f82cfb6c54 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1096,7 +1096,9 @@ static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr, ch
 	struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
 
 	PDBG("%s dev 0x%p\n", __func__, dev);
+	rtnl_lock();
 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
+	rtnl_unlock();
 	return sprintf(buf, "%s\n", info.fw_version);
 }
 
@@ -1109,7 +1111,9 @@ static ssize_t show_hca(struct device *dev, struct device_attribute *attr,
 	struct net_device *lldev = iwch_dev->rdev.t3cdev_p->lldev;
 
 	PDBG("%s dev 0x%p\n", __func__, dev);
+	rtnl_lock();
 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
+	rtnl_unlock();
 	return sprintf(buf, "%s\n", info.driver);
 }
 
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index eebc72465fc9..72c63e5dd630 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -28,6 +28,7 @@
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/sched.h>
 
 /*
  * Check that the effect_id is a valid effect and whether the user
@@ -166,8 +167,10 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
 	if (ret)
 		goto out;
 
+	spin_lock_irq(&dev->event_lock);
 	ff->effects[id] = *effect;
 	ff->effect_owners[id] = file;
+	spin_unlock_irq(&dev->event_lock);
 
  out:
 	mutex_unlock(&ff->mutex);
@@ -189,16 +192,22 @@ static int erase_effect(struct input_dev *dev, int effect_id,
 	if (error)
 		return error;
 
+	spin_lock_irq(&dev->event_lock);
 	ff->playback(dev, effect_id, 0);
+	ff->effect_owners[effect_id] = NULL;
+	spin_unlock_irq(&dev->event_lock);
 
 	if (ff->erase) {
 		error = ff->erase(dev, effect_id);
-		if (error)
+		if (error) {
+			spin_lock_irq(&dev->event_lock);
+			ff->effect_owners[effect_id] = file;
+			spin_unlock_irq(&dev->event_lock);
+
 			return error;
+		}
 	}
 
-	ff->effect_owners[effect_id] = NULL;
-
 	return 0;
 }
 
@@ -263,8 +272,6 @@ int input_ff_event(struct input_dev *dev, unsigned int type,
 	if (type != EV_FF)
 		return 0;
 
-	mutex_lock(&ff->mutex);
-
 	switch (code) {
 	case FF_GAIN:
 		if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
@@ -286,7 +293,6 @@ int input_ff_event(struct input_dev *dev, unsigned int type,
 		break;
 	}
 
-	mutex_unlock(&ff->mutex);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(input_ff_event);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 0f3c66de69bc..8d8c6b736167 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1977,8 +1977,10 @@ isdn_writebuf_stub(int drvidx, int chan, const u_char __user * buf, int len)
 	if (!skb)
 		return -ENOMEM;
 	skb_reserve(skb, hl);
-	if (copy_from_user(skb_put(skb, len), buf, len))
+	if (copy_from_user(skb_put(skb, len), buf, len)) {
+		dev_kfree_skb(skb);
 		return -EFAULT;
+	}
 	ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
 	if (ret <= 0)
 		dev_kfree_skb(skb);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 835def11419d..ab6a61db63ce 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -432,6 +432,7 @@ static int crypt_convert(struct crypt_config *cc,
 		case 0:
 			atomic_dec(&ctx->pending);
 			ctx->sector++;
+			cond_resched();
 			continue;
 
 		/* error */
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 7cf512a34ccf..2580ac1b9b0f 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3897,8 +3897,10 @@ static void autorun_devices(int part)
 
 		md_probe(dev, NULL, NULL);
 		mddev = mddev_find(dev);
-		if (!mddev) {
-			printk(KERN_ERR 
+		if (!mddev || !mddev->gendisk) {
+			if (mddev)
+				mddev_put(mddev);
+			printk(KERN_ERR
 				"md: cannot allocate memory for md drive.\n");
 			break;
 		}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1de17da34a95..a71277b640ab 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2137,6 +2137,8 @@ static int run(mddev_t *mddev)
 		    !test_bit(In_sync, &disk->rdev->flags)) {
 			disk->head_position = 0;
 			mddev->degraded++;
+			if (disk->rdev)
+				conf->fullsync = 1;
 		}
 	}
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c37e256b1176..3b27df52456b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2017,12 +2017,7 @@ static int __handle_issuing_new_read_requests5(struct stripe_head *sh,
 			 */
 			s->uptodate++;
 			return 0; /* uptodate + compute == disks */
-		} else if ((s->uptodate < disks - 1) &&
-			test_bit(R5_Insync, &dev->flags)) {
-			/* Note: we hold off compute operations while checks are
-			 * in flight, but we still prefer 'compute' over 'read'
-			 * hence we only read if (uptodate < * disks-1)
-			 */
+		} else if (test_bit(R5_Insync, &dev->flags)) {
 			set_bit(R5_LOCKED, &dev->flags);
 			set_bit(R5_Wantread, &dev->flags);
 			if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
@@ -2898,6 +2893,8 @@ static void handle_stripe5(struct stripe_head *sh)
 
 		for (i = conf->raid_disks; i--; ) {
 			set_bit(R5_Wantwrite, &sh->dev[i].flags);
+			set_bit(R5_LOCKED, &dev->flags);
+			s.locked++;
 			if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
 				sh->ops.count++;
 		}
@@ -2911,6 +2908,7 @@ static void handle_stripe5(struct stripe_head *sh)
 			conf->raid_disks);
 		s.locked += handle_write_operations5(sh, 1, 1);
 	} else if (s.expanded &&
+		   s.locked == 0 &&
 		!test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
 		clear_bit(STRIPE_EXPAND_READY, &sh->state);
 		atomic_dec(&conf->reshape_stripes);
@@ -4305,7 +4303,9 @@ static int run(mddev_t *mddev)
 				" disk %d\n", bdevname(rdev->bdev,b),
 				raid_disk);
 			working_disks++;
-		}
+		} else
+			/* Cannot rely on bitmap to complete recovery */
+			conf->fullsync = 1;
 	}
 
 	/*
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 3b26fbd3e558..5ccb0aeca8cc 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -793,6 +793,14 @@ menuconfig V4L_USB_DRIVERS
 
 if V4L_USB_DRIVERS && USB
 
+config USB_VIDEO_CLASS
+	tristate "USB Video Class (UVC)"
+	---help---
+	  Support for the USB Video Class (UVC).  Currently only video
+	  input devices, such as webcams, are supported.
+
+	  For more information see: <http://linux-uvc.berlios.de/>
+
 source "drivers/media/video/pvrusb2/Kconfig"
 
 source "drivers/media/video/em28xx/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index dff0d6abe917..ecbbfaab24d5 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -136,6 +136,8 @@ obj-$(CONFIG_SOC_CAMERA_MT9V022)	+= mt9v022.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
+obj-$(CONFIG_USB_VIDEO_CLASS)	+= uvc/
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 2bc6bdc9c1f2..d7bfd30f74a9 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -406,8 +406,10 @@ static int ov7670_read(struct i2c_client *c, unsigned char reg,
 	int ret;
 
 	ret = i2c_smbus_read_byte_data(c, reg);
-	if (ret >= 0)
+	if (ret >= 0) {
 		*value = (unsigned char) ret;
+		ret = 0;
+	}
 	return ret;
 }
 
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
new file mode 100644
index 000000000000..968c1994eda0
--- /dev/null
+++ b/drivers/media/video/uvc/Makefile
@@ -0,0 +1,3 @@
+uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
+		  uvc_status.o uvc_isight.o
+obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
new file mode 100644
index 000000000000..f0ee46d15540
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -0,0 +1,1256 @@
+/*
+ *      uvc_ctrl.c  --  USB Video Class driver - Controls
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+#define UVC_CTRL_NDATA		2
+#define UVC_CTRL_DATA_CURRENT	0
+#define UVC_CTRL_DATA_BACKUP	1
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_control_info uvc_ctrls[] = {
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BRIGHTNESS_CONTROL,
+		.index		= 0,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_CONTRAST_CONTROL,
+		.index		= 1,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_CONTROL,
+		.index		= 2,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SATURATION_CONTROL,
+		.index		= 3,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SHARPNESS_CONTROL,
+		.index		= 4,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAMMA_CONTROL,
+		.index		= 5,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BACKLIGHT_COMPENSATION_CONTROL,
+		.index		= 8,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAIN_CONTROL,
+		.index		= 9,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_POWER_LINE_FREQUENCY_CONTROL,
+		.index		= 10,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_AUTO_CONTROL,
+		.index		= 11,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_MODE_CONTROL,
+		.index		= 1,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_PRIORITY_CONTROL,
+		.index		= 2,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+		.index		= 3,
+		.size		= 4,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_ABSOLUTE_CONTROL,
+		.index		= 5,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_AUTO_CONTROL,
+		.index		= 17,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+		.index		= 12,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+		.index		= 6,
+		.size		= 2,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+		.index		= 13,
+		.size		= 1,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+				| UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+	},
+	{
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.index		= 7,
+		.size		= 4,
+		.flags		= UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
+				| UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+	},
+};
+
+static struct uvc_menu_info power_line_frequency_controls[] = {
+	{ 0, "Disabled" },
+	{ 1, "50 Hz" },
+	{ 2, "60 Hz" },
+};
+
+static struct uvc_menu_info exposure_auto_controls[] = {
+	{ 1, "Manual Mode" },
+	{ 2, "Auto Mode" },
+	{ 4, "Shutter Priority Mode" },
+	{ 8, "Aperture Priority Mode" },
+};
+
+static struct uvc_control_mapping uvc_ctrl_mappings[] = {
+	{
+		.id		= V4L2_CID_BRIGHTNESS,
+		.name		= "Brightness",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BRIGHTNESS_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_CONTRAST,
+		.name		= "Contrast",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_CONTRAST_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_HUE,
+		.name		= "Hue",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_SATURATION,
+		.name		= "Saturation",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SATURATION_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_SHARPNESS,
+		.name		= "Sharpness",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_SHARPNESS_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_GAMMA,
+		.name		= "Gamma",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAMMA_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_BACKLIGHT_COMPENSATION,
+		.name		= "Backlight Compensation",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_BACKLIGHT_COMPENSATION_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_GAIN,
+		.name		= "Gain",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_GAIN_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_POWER_LINE_FREQUENCY,
+		.name		= "Power Line Frequency",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_POWER_LINE_FREQUENCY_CONTROL,
+		.size		= 2,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+		.data_type	= UVC_CTRL_DATA_TYPE_ENUM,
+		.menu_info	= power_line_frequency_controls,
+		.menu_count	= ARRAY_SIZE(power_line_frequency_controls),
+	},
+	{
+		.id		= V4L2_CID_HUE_AUTO,
+		.name		= "Hue, Auto",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_HUE_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_EXPOSURE_AUTO,
+		.name		= "Exposure, Auto",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_MODE_CONTROL,
+		.size		= 4,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_MENU,
+		.data_type	= UVC_CTRL_DATA_TYPE_BITMASK,
+		.menu_info	= exposure_auto_controls,
+		.menu_count	= ARRAY_SIZE(exposure_auto_controls),
+	},
+	{
+		.id		= V4L2_CID_EXPOSURE_AUTO_PRIORITY,
+		.name		= "Exposure, Auto Priority",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_AE_PRIORITY_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_EXPOSURE_ABSOLUTE,
+		.name		= "Exposure (Absolute)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
+		.size		= 32,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
+		.name		= "White Balance Temperature, Auto",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+		.name		= "White Balance Temperature",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_AUTO_WHITE_BALANCE,
+		.name		= "White Balance Component, Auto",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+	{
+		.id		= V4L2_CID_BLUE_BALANCE,
+		.name		= "White Balance Blue Component",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_RED_BALANCE,
+		.name		= "White Balance Red Component",
+		.entity		= UVC_GUID_UVC_PROCESSING,
+		.selector	= PU_WHITE_BALANCE_COMPONENT_CONTROL,
+		.size		= 16,
+		.offset		= 16,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,
+	},
+	{
+		.id		= V4L2_CID_FOCUS_ABSOLUTE,
+		.name		= "Focus (absolute)",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_ABSOLUTE_CONTROL,
+		.size		= 16,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
+	{
+		.id		= V4L2_CID_FOCUS_AUTO,
+		.name		= "Focus, Auto",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= CT_FOCUS_AUTO_CONTROL,
+		.size		= 1,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
+		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
+	},
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
+{
+	return ctrl->data + id * ctrl->info->size;
+}
+
+static inline int uvc_get_bit(const __u8 *data, int bit)
+{
+	return (data[bit >> 3] >> (bit & 7)) & 1;
+}
+
+/* Extract the bit string specified by mapping->offset and mapping->size
+ * from the little-endian data stored at 'data' and return the result as
+ * a signed 32bit integer. Sign extension will be performed if the mapping
+ * references a signed data type.
+ */
+static __s32 uvc_get_le_value(const __u8 *data,
+	struct uvc_control_mapping *mapping)
+{
+	int bits = mapping->size;
+	int offset = mapping->offset;
+	__s32 value = 0;
+	__u8 mask;
+
+	data += offset / 8;
+	offset &= 7;
+	mask = ((1LL << bits) - 1) << offset;
+
+	for (; bits > 0; data++) {
+		__u8 byte = *data & mask;
+		value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
+		bits -= 8 - (offset > 0 ? offset : 0);
+		offset -= 8;
+		mask = (1 << bits) - 1;
+	}
+
+	/* Sign-extend the value if needed */
+	if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
+		value |= -(value & (1 << (mapping->size - 1)));
+
+	return value;
+}
+
+/* Set the bit string specified by mapping->offset and mapping->size
+ * in the little-endian data stored at 'data' to the value 'value'.
+ */
+static void uvc_set_le_value(__s32 value, __u8 *data,
+	struct uvc_control_mapping *mapping)
+{
+	int bits = mapping->size;
+	int offset = mapping->offset;
+	__u8 mask;
+
+	data += offset / 8;
+	offset &= 7;
+
+	for (; bits > 0; data++) {
+		mask = ((1LL << bits) - 1) << offset;
+		*data = (*data & ~mask) | ((value << offset) & mask);
+		value >>= offset ? offset : 8;
+		bits -= 8 - offset;
+		offset = 0;
+	}
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
+static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const __u8 uvc_media_transport_input_guid[16] =
+	UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
+
+static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
+{
+	switch (UVC_ENTITY_TYPE(entity)) {
+	case ITT_CAMERA:
+		return memcmp(uvc_camera_guid, guid, 16) == 0;
+
+	case ITT_MEDIA_TRANSPORT_INPUT:
+		return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
+
+	case VC_PROCESSING_UNIT:
+		return memcmp(uvc_processing_guid, guid, 16) == 0;
+
+	case VC_EXTENSION_UNIT:
+		return memcmp(entity->extension.guidExtensionCode,
+			      guid, 16) == 0;
+
+	default:
+		return 0;
+	}
+}
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
+	struct uvc_control_mapping **mapping, struct uvc_control **control,
+	int next)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *map;
+	unsigned int i;
+
+	if (entity == NULL)
+		return;
+
+	for (i = 0; i < entity->ncontrols; ++i) {
+		ctrl = &entity->controls[i];
+		if (ctrl->info == NULL)
+			continue;
+
+		list_for_each_entry(map, &ctrl->info->mappings, list) {
+			if ((map->id == v4l2_id) && !next) {
+				*control = ctrl;
+				*mapping = map;
+				return;
+			}
+
+			if ((*mapping == NULL || (*mapping)->id > map->id) &&
+			    (map->id > v4l2_id) && next) {
+				*control = ctrl;
+				*mapping = map;
+			}
+		}
+	}
+}
+
+struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+	__u32 v4l2_id, struct uvc_control_mapping **mapping)
+{
+	struct uvc_control *ctrl = NULL;
+	struct uvc_entity *entity;
+	int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+
+	*mapping = NULL;
+
+	/* Mask the query flags. */
+	v4l2_id &= V4L2_CTRL_ID_MASK;
+
+	/* Find the control. */
+	__uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);
+	if (ctrl && !next)
+		return ctrl;
+
+	list_for_each_entry(entity, &video->iterms, chain) {
+		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+		if (ctrl && !next)
+			return ctrl;
+	}
+
+	list_for_each_entry(entity, &video->extensions, chain) {
+		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
+		if (ctrl && !next)
+			return ctrl;
+	}
+
+	if (ctrl == NULL && !next)
+		uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",
+				v4l2_id);
+
+	return ctrl;
+}
+
+int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+	struct v4l2_queryctrl *v4l2_ctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	struct uvc_menu_info *menu;
+	unsigned int i;
+	__u8 data[8];
+	int ret;
+
+	ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);
+	if (ctrl == NULL)
+		return -EINVAL;
+
+	v4l2_ctrl->id = mapping->id;
+	v4l2_ctrl->type = mapping->v4l2_type;
+	strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
+	v4l2_ctrl->flags = 0;
+
+	if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+	}
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		v4l2_ctrl->minimum = 0;
+		v4l2_ctrl->maximum = mapping->menu_count - 1;
+		v4l2_ctrl->step = 1;
+
+		menu = mapping->menu_info;
+		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+			if (menu->value == v4l2_ctrl->default_value) {
+				v4l2_ctrl->default_value = i;
+				break;
+			}
+		}
+
+		return 0;
+	}
+
+	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+	}
+	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+	}
+	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+		if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				&data, ctrl->info->size)) < 0)
+			return ret;
+		v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+	}
+
+	return 0;
+}
+
+
+/* --------------------------------------------------------------------------
+ * Control transactions
+ *
+ * To make extended set operations as atomic as the hardware allows, controls
+ * are handled using begin/commit/rollback operations.
+ *
+ * At the beginning of a set request, uvc_ctrl_begin should be called to
+ * initialize the request. This function acquires the control lock.
+ *
+ * When setting a control, the new value is stored in the control data field
+ * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for
+ * later processing. If the UVC and V4L2 control sizes differ, the current
+ * value is loaded from the hardware before storing the new value in the data
+ * field.
+ *
+ * After processing all controls in the transaction, uvc_ctrl_commit or
+ * uvc_ctrl_rollback must be called to apply the pending changes to the
+ * hardware or revert them. When applying changes, all controls marked as
+ * dirty will be modified in the UVC device, and the dirty flag will be
+ * cleared. When reverting controls, the control data field
+ * UVC_CTRL_DATA_CURRENT is reverted to its previous value
+ * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
+ * control lock.
+ */
+int uvc_ctrl_begin(struct uvc_video_device *video)
+{
+	return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;
+}
+
+static int uvc_ctrl_commit_entity(struct uvc_device *dev,
+	struct uvc_entity *entity, int rollback)
+{
+	struct uvc_control *ctrl;
+	unsigned int i;
+	int ret;
+
+	if (entity == NULL)
+		return 0;
+
+	for (i = 0; i < entity->ncontrols; ++i) {
+		ctrl = &entity->controls[i];
+		if (ctrl->info == NULL || !ctrl->dirty)
+			continue;
+
+		if (!rollback)
+			ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,
+				dev->intfnum, ctrl->info->selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info->size);
+		else
+			ret = 0;
+
+		if (rollback || ret < 0)
+			memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+			       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+			       ctrl->info->size);
+
+		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+			ctrl->loaded = 0;
+
+		ctrl->dirty = 0;
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
+{
+	struct uvc_entity *entity;
+	int ret = 0;
+
+	/* Find the control. */
+	ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);
+	if (ret < 0)
+		goto done;
+
+	list_for_each_entry(entity, &video->iterms, chain) {
+		ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+		if (ret < 0)
+			goto done;
+	}
+
+	list_for_each_entry(entity, &video->extensions, chain) {
+		ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);
+		if (ret < 0)
+			goto done;
+	}
+
+done:
+	mutex_unlock(&video->ctrl_mutex);
+	return ret;
+}
+
+int uvc_ctrl_get(struct uvc_video_device *video,
+	struct v4l2_ext_control *xctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	struct uvc_menu_info *menu;
+	unsigned int i;
+	int ret;
+
+	ctrl = uvc_find_control(video, xctrl->id, &mapping);
+	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+		return -EINVAL;
+
+	if (!ctrl->loaded) {
+		ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,
+				video->dev->intfnum, ctrl->info->selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info->size);
+		if (ret < 0)
+			return ret;
+
+		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+			ctrl->loaded = 1;
+	}
+
+	xctrl->value = uvc_get_le_value(
+		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		menu = mapping->menu_info;
+		for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+			if (menu->value == xctrl->value) {
+				xctrl->value = i;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int uvc_ctrl_set(struct uvc_video_device *video,
+	struct v4l2_ext_control *xctrl)
+{
+	struct uvc_control *ctrl;
+	struct uvc_control_mapping *mapping;
+	s32 value = xctrl->value;
+	int ret;
+
+	ctrl = uvc_find_control(video, xctrl->id, &mapping);
+	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
+		return -EINVAL;
+
+	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+		if (value < 0 || value >= mapping->menu_count)
+			return -EINVAL;
+		value = mapping->menu_info[value].value;
+	}
+
+	if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
+		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
+			memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				0, ctrl->info->size);
+		} else {
+			ret = uvc_query_ctrl(video->dev, GET_CUR,
+				ctrl->entity->id, video->dev->intfnum,
+				ctrl->info->selector,
+				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+				ctrl->info->size);
+			if (ret < 0)
+				return ret;
+		}
+
+		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)
+			ctrl->loaded = 1;
+	}
+
+	if (!ctrl->dirty) {
+		memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+		       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+		       ctrl->info->size);
+	}
+
+	uvc_set_le_value(value,
+		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+
+	ctrl->dirty = 1;
+	ctrl->modified = 1;
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Dynamic controls
+ */
+
+int uvc_xu_ctrl_query(struct uvc_video_device *video,
+	struct uvc_xu_control *xctrl, int set)
+{
+	struct uvc_entity *entity;
+	struct uvc_control *ctrl = NULL;
+	unsigned int i, found = 0;
+	__u8 *data;
+	int ret;
+
+	/* Find the extension unit. */
+	list_for_each_entry(entity, &video->extensions, chain) {
+		if (entity->id == xctrl->unit)
+			break;
+	}
+
+	if (entity->id != xctrl->unit) {
+		uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
+			xctrl->unit);
+		return -EINVAL;
+	}
+
+	/* Find the control. */
+	for (i = 0; i < entity->ncontrols; ++i) {
+		ctrl = &entity->controls[i];
+		if (ctrl->info == NULL)
+			continue;
+
+		if (ctrl->info->selector == xctrl->selector) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		uvc_trace(UVC_TRACE_CONTROL,
+			"Control " UVC_GUID_FORMAT "/%u not found.\n",
+			UVC_GUID_ARGS(entity->extension.guidExtensionCode),
+			xctrl->selector);
+		return -EINVAL;
+	}
+
+	/* Validate control data size. */
+	if (ctrl->info->size != xctrl->size)
+		return -EINVAL;
+
+	if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) ||
+	    (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
+		return -EINVAL;
+
+	if (mutex_lock_interruptible(&video->ctrl_mutex))
+		return -ERESTARTSYS;
+
+	memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+	       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+	       xctrl->size);
+	data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
+
+	if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	ret = uvc_query_ctrl(video->dev, set ? SET_CUR : GET_CUR, xctrl->unit,
+			     video->dev->intfnum, xctrl->selector, data,
+			     xctrl->size);
+	if (ret < 0)
+		goto out;
+
+	if (!set && copy_to_user(xctrl->data, data, xctrl->size)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+out:
+	if (ret)
+		memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+		       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
+		       xctrl->size);
+
+	mutex_unlock(&video->ctrl_mutex);
+	return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Restore control values after resume, skipping controls that haven't been
+ * changed.
+ *
+ * TODO
+ * - Don't restore modified controls that are back to their default value.
+ * - Handle restore order (Auto-Exposure Mode should be restored before
+ *   Exposure Time).
+ */
+int uvc_ctrl_resume_device(struct uvc_device *dev)
+{
+	struct uvc_control *ctrl;
+	struct uvc_entity *entity;
+	unsigned int i;
+	int ret;
+
+	/* Walk the entities list and restore controls when possible. */
+	list_for_each_entry(entity, &dev->entities, list) {
+
+		for (i = 0; i < entity->ncontrols; ++i) {
+			ctrl = &entity->controls[i];
+
+			if (ctrl->info == NULL || !ctrl->modified ||
+			    (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
+				continue;
+
+			printk(KERN_INFO "restoring control " UVC_GUID_FORMAT
+				"/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity),
+				ctrl->info->index, ctrl->info->selector);
+			ctrl->dirty = 1;
+		}
+
+		ret = uvc_ctrl_commit_entity(dev, entity, 0);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Control and mapping handling
+ */
+
+static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
+	struct uvc_control_info *info)
+{
+	struct uvc_entity *entity;
+	struct uvc_control *ctrl = NULL;
+	int ret, found = 0;
+	unsigned int i;
+
+	list_for_each_entry(entity, &dev->entities, list) {
+		if (!uvc_entity_match_guid(entity, info->entity))
+			continue;
+
+		for (i = 0; i < entity->ncontrols; ++i) {
+			ctrl = &entity->controls[i];
+			if (ctrl->index == info->index) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (found)
+			break;
+	}
+
+	if (!found)
+		return;
+
+	if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+		/* Check if the device control information and length match
+		 * the user supplied information.
+		 */
+		__u32 flags;
+		__le16 size;
+		__u8 inf;
+
+		if ((ret = uvc_query_ctrl(dev, GET_LEN, ctrl->entity->id,
+			dev->intfnum, info->selector, (__u8 *)&size, 2)) < 0) {
+			uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
+				"control " UVC_GUID_FORMAT "/%u (%d).\n",
+				UVC_GUID_ARGS(info->entity), info->selector,
+				ret);
+			return;
+		}
+
+		if (info->size != le16_to_cpu(size)) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT
+				"/%u size doesn't match user supplied "
+				"value.\n", UVC_GUID_ARGS(info->entity),
+				info->selector);
+			return;
+		}
+
+		if ((ret = uvc_query_ctrl(dev, GET_INFO, ctrl->entity->id,
+			dev->intfnum, info->selector, &inf, 1)) < 0) {
+			uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
+				"control " UVC_GUID_FORMAT "/%u (%d).\n",
+				UVC_GUID_ARGS(info->entity), info->selector,
+				ret);
+			return;
+		}
+
+		flags = info->flags;
+		if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
+		    ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control "
+				UVC_GUID_FORMAT "/%u flags don't match "
+				"supported operations.\n",
+				UVC_GUID_ARGS(info->entity), info->selector);
+			return;
+		}
+	}
+
+	ctrl->info = info;
+	ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
+	uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u "
+		"to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity),
+		ctrl->info->selector, dev->udev->devpath, entity->id);
+}
+
+/*
+ * Add an item to the UVC control information list, and instantiate a control
+ * structure for each device that supports the control.
+ */
+int uvc_ctrl_add_info(struct uvc_control_info *info)
+{
+	struct uvc_control_info *ctrl;
+	struct uvc_device *dev;
+	int ret = 0;
+
+	/* Find matching controls by walking the devices, entities and
+	 * controls list.
+	 */
+	mutex_lock(&uvc_driver.ctrl_mutex);
+
+	/* First check if the list contains a control matching the new one.
+	 * Bail out if it does.
+	 */
+	list_for_each_entry(ctrl, &uvc_driver.controls, list) {
+		if (memcmp(ctrl->entity, info->entity, 16))
+			continue;
+
+		if (ctrl->selector == info->selector) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control "
+				UVC_GUID_FORMAT "/%u is already defined.\n",
+				UVC_GUID_ARGS(info->entity), info->selector);
+			ret = -EEXIST;
+			goto end;
+		}
+		if (ctrl->index == info->index) {
+			uvc_trace(UVC_TRACE_CONTROL, "Control "
+				UVC_GUID_FORMAT "/%u would overwrite index "
+				"%d.\n", UVC_GUID_ARGS(info->entity),
+				info->selector, info->index);
+			ret = -EEXIST;
+			goto end;
+		}
+	}
+
+	list_for_each_entry(dev, &uvc_driver.devices, list)
+		uvc_ctrl_add_ctrl(dev, info);
+
+	INIT_LIST_HEAD(&info->mappings);
+	list_add_tail(&info->list, &uvc_driver.controls);
+end:
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+	return ret;
+}
+
+int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
+{
+	struct uvc_control_info *info;
+	struct uvc_control_mapping *map;
+	int ret = -EINVAL;
+
+	if (mapping->id & ~V4L2_CTRL_ID_MASK) {
+		uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
+			"invalid control id 0x%08x\n", mapping->name,
+			mapping->id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&uvc_driver.ctrl_mutex);
+	list_for_each_entry(info, &uvc_driver.controls, list) {
+		if (memcmp(info->entity, mapping->entity, 16) ||
+			info->selector != mapping->selector)
+			continue;
+
+		if (info->size * 8 < mapping->size + mapping->offset) {
+			uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "
+				"overflow control " UVC_GUID_FORMAT "/%u\n",
+				mapping->name, UVC_GUID_ARGS(info->entity),
+				info->selector);
+			ret = -EOVERFLOW;
+			goto end;
+		}
+
+		/* Check if the list contains a mapping matching the new one.
+		 * Bail out if it does.
+		 */
+		list_for_each_entry(map, &info->mappings, list) {
+			if (map->id == mapping->id) {
+				uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is "
+					"already defined.\n", mapping->name);
+				ret = -EEXIST;
+				goto end;
+			}
+		}
+
+		mapping->ctrl = info;
+		list_add_tail(&mapping->list, &info->mappings);
+		uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "
+			UVC_GUID_FORMAT "/%u.\n", mapping->name,
+			UVC_GUID_ARGS(info->entity), info->selector);
+
+		ret = 0;
+		break;
+	}
+end:
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+	return ret;
+}
+
+/*
+ * Initialize device controls.
+ */
+int uvc_ctrl_init_device(struct uvc_device *dev)
+{
+	struct uvc_control_info *info;
+	struct uvc_control *ctrl;
+	struct uvc_entity *entity;
+	unsigned int i;
+
+	/* Walk the entities list and instantiate controls */
+	list_for_each_entry(entity, &dev->entities, list) {
+		unsigned int bControlSize = 0, ncontrols = 0;
+		__u8 *bmControls = NULL;
+
+		if (UVC_ENTITY_TYPE(entity) == VC_EXTENSION_UNIT) {
+			bmControls = entity->extension.bmControls;
+			bControlSize = entity->extension.bControlSize;
+		} else if (UVC_ENTITY_TYPE(entity) == VC_PROCESSING_UNIT) {
+			bmControls = entity->processing.bmControls;
+			bControlSize = entity->processing.bControlSize;
+		} else if (UVC_ENTITY_TYPE(entity) == ITT_CAMERA) {
+			bmControls = entity->camera.bmControls;
+			bControlSize = entity->camera.bControlSize;
+		}
+
+		for (i = 0; i < bControlSize; ++i)
+			ncontrols += hweight8(bmControls[i]);
+
+		if (ncontrols == 0)
+			continue;
+
+		entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);
+		if (entity->controls == NULL)
+			return -ENOMEM;
+
+		entity->ncontrols = ncontrols;
+
+		ctrl = entity->controls;
+		for (i = 0; i < bControlSize * 8; ++i) {
+			if (uvc_get_bit(bmControls, i) == 0)
+				continue;
+
+			ctrl->entity = entity;
+			ctrl->index = i;
+			ctrl++;
+		}
+	}
+
+	/* Walk the controls info list and associate them with the device
+	 * controls, then add the device to the global device list. This has
+	 * to be done while holding the controls lock, to make sure
+	 * uvc_ctrl_add_info() will not get called in-between.
+	 */
+	mutex_lock(&uvc_driver.ctrl_mutex);
+	list_for_each_entry(info, &uvc_driver.controls, list)
+		uvc_ctrl_add_ctrl(dev, info);
+
+	list_add_tail(&dev->list, &uvc_driver.devices);
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+
+	return 0;
+}
+
+/*
+ * Cleanup device controls.
+ */
+void uvc_ctrl_cleanup_device(struct uvc_device *dev)
+{
+	struct uvc_entity *entity;
+	unsigned int i;
+
+	/* Remove the device from the global devices list */
+	mutex_lock(&uvc_driver.ctrl_mutex);
+	if (dev->list.next != NULL)
+		list_del(&dev->list);
+	mutex_unlock(&uvc_driver.ctrl_mutex);
+
+	list_for_each_entry(entity, &dev->entities, list) {
+		for (i = 0; i < entity->ncontrols; ++i)
+			kfree(entity->controls[i].data);
+
+		kfree(entity->controls);
+	}
+}
+
+void uvc_ctrl_init(void)
+{
+	struct uvc_control_info *ctrl = uvc_ctrls;
+	struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);
+	struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
+	struct uvc_control_mapping *mend =
+		mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+	for (; ctrl < cend; ++ctrl)
+		uvc_ctrl_add_info(ctrl);
+
+	for (; mapping < mend; ++mapping)
+		uvc_ctrl_add_mapping(mapping);
+}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
new file mode 100644
index 000000000000..60ced589f898
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -0,0 +1,1955 @@
+/*
+ *      uvc_driver.c  --  USB Video Class driver
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+/*
+ * This driver aims to support video input devices compliant with the 'USB
+ * Video Class' specification.
+ *
+ * The driver doesn't support the deprecated v4l1 interface. It implements the
+ * mmap capture method only, and doesn't do any image format conversion in
+ * software. If your user-space application doesn't support YUYV or MJPEG, fix
+ * it :-). Please note that the MJPEG data have been stripped from their
+ * Huffman tables (DHT marker), you will need to add it back if your JPEG
+ * codec can't handle MJPEG data.
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+#define DRIVER_AUTHOR		"Laurent Pinchart <laurent.pinchart@skynet.be>"
+#define DRIVER_DESC		"USB Video Class driver"
+#ifndef DRIVER_VERSION
+#define DRIVER_VERSION		"v0.1.0"
+#endif
+
+static unsigned int uvc_quirks_param;
+unsigned int uvc_trace_param;
+
+/* ------------------------------------------------------------------------
+ * Control, formats, ...
+ */
+
+static struct uvc_format_desc uvc_fmts[] = {
+	{
+		.name		= "YUV 4:2:2 (YUYV)",
+		.guid		= UVC_GUID_FORMAT_YUY2,
+		.fcc		= V4L2_PIX_FMT_YUYV,
+	},
+	{
+		.name		= "YUV 4:2:0 (NV12)",
+		.guid		= UVC_GUID_FORMAT_NV12,
+		.fcc		= V4L2_PIX_FMT_NV12,
+	},
+	{
+		.name		= "MJPEG",
+		.guid		= UVC_GUID_FORMAT_MJPEG,
+		.fcc		= V4L2_PIX_FMT_MJPEG,
+	},
+	{
+		.name		= "YVU 4:2:0 (YV12)",
+		.guid		= UVC_GUID_FORMAT_YV12,
+		.fcc		= V4L2_PIX_FMT_YVU420,
+	},
+	{
+		.name		= "YUV 4:2:0 (I420)",
+		.guid		= UVC_GUID_FORMAT_I420,
+		.fcc		= V4L2_PIX_FMT_YUV420,
+	},
+	{
+		.name		= "YUV 4:2:2 (UYVY)",
+		.guid		= UVC_GUID_FORMAT_UYVY,
+		.fcc		= V4L2_PIX_FMT_UYVY,
+	},
+	{
+		.name		= "Greyscale",
+		.guid		= UVC_GUID_FORMAT_Y800,
+		.fcc		= V4L2_PIX_FMT_GREY,
+	},
+	{
+		.name		= "RGB Bayer",
+		.guid		= UVC_GUID_FORMAT_BY8,
+		.fcc		= V4L2_PIX_FMT_SBGGR8,
+	},
+};
+
+/* ------------------------------------------------------------------------
+ * Utility functions
+ */
+
+struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
+		__u8 epaddr)
+{
+	struct usb_host_endpoint *ep;
+	unsigned int i;
+
+	for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+		ep = &alts->endpoint[i];
+		if (ep->desc.bEndpointAddress == epaddr)
+			return ep;
+	}
+
+	return NULL;
+}
+
+static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
+{
+	unsigned int len = ARRAY_SIZE(uvc_fmts);
+	unsigned int i;
+
+	for (i = 0; i < len; ++i) {
+		if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
+			return &uvc_fmts[i];
+	}
+
+	return NULL;
+}
+
+static __u32 uvc_colorspace(const __u8 primaries)
+{
+	static const __u8 colorprimaries[] = {
+		0,
+		V4L2_COLORSPACE_SRGB,
+		V4L2_COLORSPACE_470_SYSTEM_M,
+		V4L2_COLORSPACE_470_SYSTEM_BG,
+		V4L2_COLORSPACE_SMPTE170M,
+		V4L2_COLORSPACE_SMPTE240M,
+	};
+
+	if (primaries < ARRAY_SIZE(colorprimaries))
+		return colorprimaries[primaries];
+
+	return 0;
+}
+
+/* Simplify a fraction using a simple continued fraction decomposition. The
+ * idea here is to convert fractions such as 333333/10000000 to 1/30 using
+ * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
+ * arbitrary parameters to remove non-significative terms from the simple
+ * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
+ * respectively seems to give nice results.
+ */
+void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+		unsigned int n_terms, unsigned int threshold)
+{
+	uint32_t *an;
+	uint32_t x, y, r;
+	unsigned int i, n;
+
+	an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
+	if (an == NULL)
+		return;
+
+	/* Convert the fraction to a simple continued fraction. See
+	 * http://mathforum.org/dr.math/faq/faq.fractions.html
+	 * Stop if the current term is bigger than or equal to the given
+	 * threshold.
+	 */
+	x = *numerator;
+	y = *denominator;
+
+	for (n = 0; n < n_terms && y != 0; ++n) {
+		an[n] = x / y;
+		if (an[n] >= threshold) {
+			if (n < 2)
+				n++;
+			break;
+		}
+
+		r = x - an[n] * y;
+		x = y;
+		y = r;
+	}
+
+	/* Expand the simple continued fraction back to an integer fraction. */
+	x = 0;
+	y = 1;
+
+	for (i = n; i > 0; --i) {
+		r = y;
+		y = an[i-1] * y + x;
+		x = r;
+	}
+
+	*numerator = y;
+	*denominator = x;
+	kfree(an);
+}
+
+/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+ * to compute numerator / denominator * 10000000 using 32 bit fixed point
+ * arithmetic only.
+ */
+uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
+{
+	uint32_t multiplier;
+
+	/* Saturate the result if the operation would overflow. */
+	if (denominator == 0 ||
+	    numerator/denominator >= ((uint32_t)-1)/10000000)
+		return (uint32_t)-1;
+
+	/* Divide both the denominator and the multiplier by two until
+	 * numerator * multiplier doesn't overflow. If anyone knows a better
+	 * algorithm please let me know.
+	 */
+	multiplier = 10000000;
+	while (numerator > ((uint32_t)-1)/multiplier) {
+		multiplier /= 2;
+		denominator /= 2;
+	}
+
+	return denominator ? numerator * multiplier / denominator : 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Terminal and unit management
+ */
+
+static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+{
+	struct uvc_entity *entity;
+
+	list_for_each_entry(entity, &dev->entities, list) {
+		if (entity->id == id)
+			return entity;
+	}
+
+	return NULL;
+}
+
+static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
+	int id, struct uvc_entity *entity)
+{
+	unsigned int i;
+
+	if (entity == NULL)
+		entity = list_entry(&dev->entities, struct uvc_entity, list);
+
+	list_for_each_entry_continue(entity, &dev->entities, list) {
+		switch (UVC_ENTITY_TYPE(entity)) {
+		case TT_STREAMING:
+			if (entity->output.bSourceID == id)
+				return entity;
+			break;
+
+		case VC_PROCESSING_UNIT:
+			if (entity->processing.bSourceID == id)
+				return entity;
+			break;
+
+		case VC_SELECTOR_UNIT:
+			for (i = 0; i < entity->selector.bNrInPins; ++i)
+				if (entity->selector.baSourceID[i] == id)
+					return entity;
+			break;
+
+		case VC_EXTENSION_UNIT:
+			for (i = 0; i < entity->extension.bNrInPins; ++i)
+				if (entity->extension.baSourceID[i] == id)
+					return entity;
+			break;
+		}
+	}
+
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------
+ * Descriptors handling
+ */
+
+static int uvc_parse_format(struct uvc_device *dev,
+	struct uvc_streaming *streaming, struct uvc_format *format,
+	__u32 **intervals, unsigned char *buffer, int buflen)
+{
+	struct usb_interface *intf = streaming->intf;
+	struct usb_host_interface *alts = intf->cur_altsetting;
+	struct uvc_format_desc *fmtdesc;
+	struct uvc_frame *frame;
+	const unsigned char *start = buffer;
+	unsigned int interval;
+	unsigned int i, n;
+	__u8 ftype;
+
+	format->type = buffer[2];
+	format->index = buffer[3];
+
+	switch (buffer[2]) {
+	case VS_FORMAT_UNCOMPRESSED:
+	case VS_FORMAT_FRAME_BASED:
+		if (buflen < 27) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		/* Find the format descriptor from its GUID. */
+		fmtdesc = uvc_format_by_guid(&buffer[5]);
+
+		if (fmtdesc != NULL) {
+			strncpy(format->name, fmtdesc->name,
+				sizeof format->name);
+			format->fcc = fmtdesc->fcc;
+		} else {
+			uvc_printk(KERN_INFO, "Unknown video format "
+				UVC_GUID_FORMAT "\n",
+				UVC_GUID_ARGS(&buffer[5]));
+			snprintf(format->name, sizeof format->name,
+				UVC_GUID_FORMAT, UVC_GUID_ARGS(&buffer[5]));
+			format->fcc = 0;
+		}
+
+		format->bpp = buffer[21];
+		if (buffer[2] == VS_FORMAT_UNCOMPRESSED) {
+			ftype = VS_FRAME_UNCOMPRESSED;
+		} else {
+			ftype = VS_FRAME_FRAME_BASED;
+			if (buffer[27])
+				format->flags = UVC_FMT_FLAG_COMPRESSED;
+		}
+		break;
+
+	case VS_FORMAT_MJPEG:
+		if (buflen < 11) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		strncpy(format->name, "MJPEG", sizeof format->name);
+		format->fcc = V4L2_PIX_FMT_MJPEG;
+		format->flags = UVC_FMT_FLAG_COMPRESSED;
+		format->bpp = 0;
+		ftype = VS_FRAME_MJPEG;
+		break;
+
+	case VS_FORMAT_DV:
+		if (buflen < 9) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		switch (buffer[8] & 0x7f) {
+		case 0:
+			strncpy(format->name, "SD-DV", sizeof format->name);
+			break;
+		case 1:
+			strncpy(format->name, "SDL-DV", sizeof format->name);
+			break;
+		case 2:
+			strncpy(format->name, "HD-DV", sizeof format->name);
+			break;
+		default:
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d: unknown DV format %u\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber, buffer[8]);
+			return -EINVAL;
+		}
+
+		strncat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
+			sizeof format->name);
+
+		format->fcc = V4L2_PIX_FMT_DV;
+		format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
+		format->bpp = 0;
+		ftype = 0;
+
+		/* Create a dummy frame descriptor. */
+		frame = &format->frame[0];
+		memset(&format->frame[0], 0, sizeof format->frame[0]);
+		frame->bFrameIntervalType = 1;
+		frame->dwDefaultFrameInterval = 1;
+		frame->dwFrameInterval = *intervals;
+		*(*intervals)++ = 1;
+		format->nframes = 1;
+		break;
+
+	case VS_FORMAT_MPEG2TS:
+	case VS_FORMAT_STREAM_BASED:
+		/* Not supported yet. */
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+		       "interface %d unsupported format %u\n",
+		       dev->udev->devnum, alts->desc.bInterfaceNumber,
+		       buffer[2]);
+		return -EINVAL;
+	}
+
+	uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
+
+	buflen -= buffer[0];
+	buffer += buffer[0];
+
+	/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+	 * based formats have frame descriptors.
+	 */
+	while (buflen > 2 && buffer[2] == ftype) {
+		frame = &format->frame[format->nframes];
+
+		if (ftype != VS_FRAME_FRAME_BASED)
+			n = buflen > 25 ? buffer[25] : 0;
+		else
+			n = buflen > 21 ? buffer[21] : 0;
+
+		n = n ? n : 3;
+
+		if (buflen < 26 + 4*n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d FRAME error\n", dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		frame->bFrameIndex = buffer[3];
+		frame->bmCapabilities = buffer[4];
+		frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]);
+		frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]);
+		frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]);
+		frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]);
+		if (ftype != VS_FRAME_FRAME_BASED) {
+			frame->dwMaxVideoFrameBufferSize =
+				le32_to_cpup((__le32 *)&buffer[17]);
+			frame->dwDefaultFrameInterval =
+				le32_to_cpup((__le32 *)&buffer[21]);
+			frame->bFrameIntervalType = buffer[25];
+		} else {
+			frame->dwMaxVideoFrameBufferSize = 0;
+			frame->dwDefaultFrameInterval =
+				le32_to_cpup((__le32 *)&buffer[17]);
+			frame->bFrameIntervalType = buffer[21];
+		}
+		frame->dwFrameInterval = *intervals;
+
+		/* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
+		 * completely. Observed behaviours range from setting the
+		 * value to 1.1x the actual frame size of hardwiring the
+		 * 16 low bits to 0. This results in a higher than necessary
+		 * memory usage as well as a wrong image size information. For
+		 * uncompressed formats this can be fixed by computing the
+		 * value from the frame size.
+		 */
+		if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
+			frame->dwMaxVideoFrameBufferSize = format->bpp
+				* frame->wWidth * frame->wHeight / 8;
+
+		/* Some bogus devices report dwMinFrameInterval equal to
+		 * dwMaxFrameInterval and have dwFrameIntervalStep set to
+		 * zero. Setting all null intervals to 1 fixes the problem and
+		 * some other divisions by zero which could happen.
+		 */
+		for (i = 0; i < n; ++i) {
+			interval = le32_to_cpup((__le32 *)&buffer[26+4*i]);
+			*(*intervals)++ = interval ? interval : 1;
+		}
+
+		/* Make sure that the default frame interval stays between
+		 * the boundaries.
+		 */
+		n -= frame->bFrameIntervalType ? 1 : 2;
+		frame->dwDefaultFrameInterval =
+			min(frame->dwFrameInterval[n],
+			    max(frame->dwFrameInterval[0],
+				frame->dwDefaultFrameInterval));
+
+		uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
+			frame->wWidth, frame->wHeight,
+			10000000/frame->dwDefaultFrameInterval,
+			(100000000/frame->dwDefaultFrameInterval)%10);
+
+		format->nframes++;
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
+		if (buflen < 6) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d COLORFORMAT error\n",
+			       dev->udev->devnum,
+			       alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		format->colorspace = uvc_colorspace(buffer[3]);
+
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	return buffer - start;
+}
+
+static int uvc_parse_streaming(struct uvc_device *dev,
+	struct usb_interface *intf)
+{
+	struct uvc_streaming *streaming = NULL;
+	struct uvc_format *format;
+	struct uvc_frame *frame;
+	struct usb_host_interface *alts = &intf->altsetting[0];
+	unsigned char *_buffer, *buffer = alts->extra;
+	int _buflen, buflen = alts->extralen;
+	unsigned int nformats = 0, nframes = 0, nintervals = 0;
+	unsigned int size, i, n, p;
+	__u32 *interval;
+	__u16 psize;
+	int ret = -EINVAL;
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass
+		!= SC_VIDEOSTREAMING) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
+			"video streaming interface\n", dev->udev->devnum,
+			intf->altsetting[0].desc.bInterfaceNumber);
+		return -EINVAL;
+	}
+
+	if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
+			"claimed\n", dev->udev->devnum,
+			intf->altsetting[0].desc.bInterfaceNumber);
+		return -EINVAL;
+	}
+
+	streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
+	if (streaming == NULL) {
+		usb_driver_release_interface(&uvc_driver.driver, intf);
+		return -EINVAL;
+	}
+
+	mutex_init(&streaming->mutex);
+	streaming->intf = usb_get_intf(intf);
+	streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	/* The Pico iMage webcam has its class-specific interface descriptors
+	 * after the endpoint descriptors.
+	 */
+	if (buflen == 0) {
+		for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
+			struct usb_host_endpoint *ep = &alts->endpoint[i];
+
+			if (ep->extralen == 0)
+				continue;
+
+			if (ep->extralen > 2 &&
+			    ep->extra[1] == USB_DT_CS_INTERFACE) {
+				uvc_trace(UVC_TRACE_DESCR, "trying extra data "
+					"from endpoint %u.\n", i);
+				buffer = alts->endpoint[i].extra;
+				buflen = alts->endpoint[i].extralen;
+				break;
+			}
+		}
+	}
+
+	/* Skip the standard interface descriptors. */
+	while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	if (buflen <= 2) {
+		uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
+			"interface descriptors found.\n");
+		goto error;
+	}
+
+	/* Parse the header descriptor. */
+	if (buffer[2] == VS_OUTPUT_HEADER) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d OUTPUT HEADER descriptor is not supported.\n",
+			dev->udev->devnum, alts->desc.bInterfaceNumber);
+		goto error;
+	} else if (buffer[2] == VS_INPUT_HEADER) {
+		p = buflen >= 5 ? buffer[3] : 0;
+		n = buflen >= 12 ? buffer[12] : 0;
+
+		if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+				"interface %d INPUT HEADER descriptor is "
+				"invalid.\n", dev->udev->devnum,
+				alts->desc.bInterfaceNumber);
+			goto error;
+		}
+
+		streaming->header.bNumFormats = p;
+		streaming->header.bEndpointAddress = buffer[6];
+		streaming->header.bmInfo = buffer[7];
+		streaming->header.bTerminalLink = buffer[8];
+		streaming->header.bStillCaptureMethod = buffer[9];
+		streaming->header.bTriggerSupport = buffer[10];
+		streaming->header.bTriggerUsage = buffer[11];
+		streaming->header.bControlSize = n;
+
+		streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+		if (streaming->header.bmaControls == NULL) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		memcpy(streaming->header.bmaControls, &buffer[13], p*n);
+	} else {
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d HEADER descriptor not found.\n", dev->udev->devnum,
+			alts->desc.bInterfaceNumber);
+		goto error;
+	}
+
+	buflen -= buffer[0];
+	buffer += buffer[0];
+
+	_buffer = buffer;
+	_buflen = buflen;
+
+	/* Count the format and frame descriptors. */
+	while (_buflen > 2) {
+		switch (_buffer[2]) {
+		case VS_FORMAT_UNCOMPRESSED:
+		case VS_FORMAT_MJPEG:
+		case VS_FORMAT_FRAME_BASED:
+			nformats++;
+			break;
+
+		case VS_FORMAT_DV:
+			/* DV format has no frame descriptor. We will create a
+			 * dummy frame descriptor with a dummy frame interval.
+			 */
+			nformats++;
+			nframes++;
+			nintervals++;
+			break;
+
+		case VS_FORMAT_MPEG2TS:
+		case VS_FORMAT_STREAM_BASED:
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+				"interface %d FORMAT %u is not supported.\n",
+				dev->udev->devnum,
+				alts->desc.bInterfaceNumber, _buffer[2]);
+			break;
+
+		case VS_FRAME_UNCOMPRESSED:
+		case VS_FRAME_MJPEG:
+			nframes++;
+			if (_buflen > 25)
+				nintervals += _buffer[25] ? _buffer[25] : 3;
+			break;
+
+		case VS_FRAME_FRAME_BASED:
+			nframes++;
+			if (_buflen > 21)
+				nintervals += _buffer[21] ? _buffer[21] : 3;
+			break;
+		}
+
+		_buflen -= _buffer[0];
+		_buffer += _buffer[0];
+	}
+
+	if (nformats == 0) {
+		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
+			"%d has no supported formats defined.\n",
+			dev->udev->devnum, alts->desc.bInterfaceNumber);
+		goto error;
+	}
+
+	size = nformats * sizeof *format + nframes * sizeof *frame
+	     + nintervals * sizeof *interval;
+	format = kzalloc(size, GFP_KERNEL);
+	if (format == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	frame = (struct uvc_frame *)&format[nformats];
+	interval = (__u32 *)&frame[nframes];
+
+	streaming->format = format;
+	streaming->nformats = nformats;
+
+	/* Parse the format descriptors. */
+	while (buflen > 2) {
+		switch (buffer[2]) {
+		case VS_FORMAT_UNCOMPRESSED:
+		case VS_FORMAT_MJPEG:
+		case VS_FORMAT_DV:
+		case VS_FORMAT_FRAME_BASED:
+			format->frame = frame;
+			ret = uvc_parse_format(dev, streaming, format,
+				&interval, buffer, buflen);
+			if (ret < 0)
+				goto error;
+
+			frame += format->nframes;
+			format++;
+
+			buflen -= ret;
+			buffer += ret;
+			continue;
+
+		default:
+			break;
+		}
+
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	/* Parse the alternate settings to find the maximum bandwidth. */
+	for (i = 0; i < intf->num_altsetting; ++i) {
+		struct usb_host_endpoint *ep;
+		alts = &intf->altsetting[i];
+		ep = uvc_find_endpoint(alts,
+				streaming->header.bEndpointAddress);
+		if (ep == NULL)
+			continue;
+
+		psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+		if (psize > streaming->maxpsize)
+			streaming->maxpsize = psize;
+	}
+
+	list_add_tail(&streaming->list, &dev->streaming);
+	return 0;
+
+error:
+	usb_driver_release_interface(&uvc_driver.driver, intf);
+	usb_put_intf(intf);
+	kfree(streaming->format);
+	kfree(streaming->header.bmaControls);
+	kfree(streaming);
+	return ret;
+}
+
+/* Parse vendor-specific extensions. */
+static int uvc_parse_vendor_control(struct uvc_device *dev,
+	const unsigned char *buffer, int buflen)
+{
+	struct usb_device *udev = dev->udev;
+	struct usb_host_interface *alts = dev->intf->cur_altsetting;
+	struct uvc_entity *unit;
+	unsigned int n, p;
+	int handled = 0;
+
+	switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
+	case 0x046d:		/* Logitech */
+		if (buffer[1] != 0x41 || buffer[2] != 0x01)
+			break;
+
+		/* Logitech implements several vendor specific functions
+		 * through vendor specific extension units (LXU).
+		 *
+		 * The LXU descriptors are similar to XU descriptors
+		 * (see "USB Device Video Class for Video Devices", section
+		 * 3.7.2.6 "Extension Unit Descriptor") with the following
+		 * differences:
+		 *
+		 * ----------------------------------------------------------
+		 * 0		bLength		1	 Number
+		 *	Size of this descriptor, in bytes: 24+p+n*2
+		 * ----------------------------------------------------------
+		 * 23+p+n	bmControlsType	N	Bitmap
+		 * 	Individual bits in the set are defined:
+		 * 	0: Absolute
+		 * 	1: Relative
+		 *
+		 * 	This bitset is mapped exactly the same as bmControls.
+		 * ----------------------------------------------------------
+		 * 23+p+n*2	bReserved	1	Boolean
+		 * ----------------------------------------------------------
+		 * 24+p+n*2	iExtension	1	Index
+		 *	Index of a string descriptor that describes this
+		 *	extension unit.
+		 * ----------------------------------------------------------
+		 */
+		p = buflen >= 22 ? buffer[21] : 0;
+		n = buflen >= 25 + p ? buffer[22+p] : 0;
+
+		if (buflen < 25 + p + 2*n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d EXTENSION_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			break;
+		}
+
+		unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = VC_EXTENSION_UNIT;
+		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+		unit->extension.bNumControls = buffer[20];
+		unit->extension.bNrInPins =
+			le16_to_cpup((__le16 *)&buffer[21]);
+		unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->extension.baSourceID, &buffer[22], p);
+		unit->extension.bControlSize = buffer[22+p];
+		unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+		unit->extension.bmControlsType = (__u8 *)unit + sizeof *unit
+					       + p + n;
+		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
+
+		if (buffer[24+p+2*n] != 0)
+			usb_string(udev, buffer[24+p+2*n], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Extension %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		handled = 1;
+		break;
+	}
+
+	return handled;
+}
+
+static int uvc_parse_standard_control(struct uvc_device *dev,
+	const unsigned char *buffer, int buflen)
+{
+	struct usb_device *udev = dev->udev;
+	struct uvc_entity *unit, *term;
+	struct usb_interface *intf;
+	struct usb_host_interface *alts = dev->intf->cur_altsetting;
+	unsigned int i, n, p, len;
+	__u16 type;
+
+	switch (buffer[2]) {
+	case VC_HEADER:
+		n = buflen >= 12 ? buffer[11] : 0;
+
+		if (buflen < 12 || buflen < 12 + n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d HEADER error\n", udev->devnum,
+				alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]);
+		dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]);
+
+		/* Parse all USB Video Streaming interfaces. */
+		for (i = 0; i < n; ++i) {
+			intf = usb_ifnum_to_if(udev, buffer[12+i]);
+			if (intf == NULL) {
+				uvc_trace(UVC_TRACE_DESCR, "device %d "
+					"interface %d doesn't exists\n",
+					udev->devnum, i);
+				continue;
+			}
+
+			uvc_parse_streaming(dev, intf);
+		}
+		break;
+
+	case VC_INPUT_TERMINAL:
+		if (buflen < 8) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d INPUT_TERMINAL error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		/* Make sure the terminal type MSB is not null, otherwise it
+		 * could be confused with a unit.
+		 */
+		type = le16_to_cpup((__le16 *)&buffer[4]);
+		if ((type & 0xff00) == 0) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d INPUT_TERMINAL %d has invalid "
+				"type 0x%04x, skipping\n", udev->devnum,
+				alts->desc.bInterfaceNumber,
+				buffer[3], type);
+			return 0;
+		}
+
+		n = 0;
+		p = 0;
+		len = 8;
+
+		if (type == ITT_CAMERA) {
+			n = buflen >= 15 ? buffer[14] : 0;
+			len = 15;
+
+		} else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+			n = buflen >= 9 ? buffer[8] : 0;
+			p = buflen >= 10 + n ? buffer[9+n] : 0;
+			len = 10;
+		}
+
+		if (buflen < len + n + p) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d INPUT_TERMINAL error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		term = kzalloc(sizeof *term + n + p, GFP_KERNEL);
+		if (term == NULL)
+			return -ENOMEM;
+
+		term->id = buffer[3];
+		term->type = type | UVC_TERM_INPUT;
+
+		if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {
+			term->camera.bControlSize = n;
+			term->camera.bmControls = (__u8 *)term + sizeof *term;
+			term->camera.wObjectiveFocalLengthMin =
+				le16_to_cpup((__le16 *)&buffer[8]);
+			term->camera.wObjectiveFocalLengthMax =
+				le16_to_cpup((__le16 *)&buffer[10]);
+			term->camera.wOcularFocalLength =
+				le16_to_cpup((__le16 *)&buffer[12]);
+			memcpy(term->camera.bmControls, &buffer[15], n);
+		} else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
+			term->media.bControlSize = n;
+			term->media.bmControls = (__u8 *)term + sizeof *term;
+			term->media.bTransportModeSize = p;
+			term->media.bmTransportModes = (__u8 *)term
+						     + sizeof *term + n;
+			memcpy(term->media.bmControls, &buffer[9], n);
+			memcpy(term->media.bmTransportModes, &buffer[10+n], p);
+		}
+
+		if (buffer[7] != 0)
+			usb_string(udev, buffer[7], term->name,
+				   sizeof term->name);
+		else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)
+			sprintf(term->name, "Camera %u", buffer[3]);
+		else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)
+			sprintf(term->name, "Media %u", buffer[3]);
+		else
+			sprintf(term->name, "Input %u", buffer[3]);
+
+		list_add_tail(&term->list, &dev->entities);
+		break;
+
+	case VC_OUTPUT_TERMINAL:
+		if (buflen < 9) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d OUTPUT_TERMINAL error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		/* Make sure the terminal type MSB is not null, otherwise it
+		 * could be confused with a unit.
+		 */
+		type = le16_to_cpup((__le16 *)&buffer[4]);
+		if ((type & 0xff00) == 0) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d OUTPUT_TERMINAL %d has invalid "
+				"type 0x%04x, skipping\n", udev->devnum,
+				alts->desc.bInterfaceNumber, buffer[3], type);
+			return 0;
+		}
+
+		term = kzalloc(sizeof *term, GFP_KERNEL);
+		if (term == NULL)
+			return -ENOMEM;
+
+		term->id = buffer[3];
+		term->type = type | UVC_TERM_OUTPUT;
+		term->output.bSourceID = buffer[7];
+
+		if (buffer[8] != 0)
+			usb_string(udev, buffer[8], term->name,
+				   sizeof term->name);
+		else
+			sprintf(term->name, "Output %u", buffer[3]);
+
+		list_add_tail(&term->list, &dev->entities);
+		break;
+
+	case VC_SELECTOR_UNIT:
+		p = buflen >= 5 ? buffer[4] : 0;
+
+		if (buflen < 5 || buflen < 6 + p) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d SELECTOR_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		unit = kzalloc(sizeof *unit + p, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = buffer[2];
+		unit->selector.bNrInPins = buffer[4];
+		unit->selector.baSourceID = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->selector.baSourceID, &buffer[5], p);
+
+		if (buffer[5+p] != 0)
+			usb_string(udev, buffer[5+p], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Selector %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		break;
+
+	case VC_PROCESSING_UNIT:
+		n = buflen >= 8 ? buffer[7] : 0;
+		p = dev->uvc_version >= 0x0110 ? 10 : 9;
+
+		if (buflen < p + n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d PROCESSING_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		unit = kzalloc(sizeof *unit + n, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = buffer[2];
+		unit->processing.bSourceID = buffer[4];
+		unit->processing.wMaxMultiplier =
+			le16_to_cpup((__le16 *)&buffer[5]);
+		unit->processing.bControlSize = buffer[7];
+		unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->processing.bmControls, &buffer[8], n);
+		if (dev->uvc_version >= 0x0110)
+			unit->processing.bmVideoStandards = buffer[9+n];
+
+		if (buffer[8+n] != 0)
+			usb_string(udev, buffer[8+n], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Processing %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		break;
+
+	case VC_EXTENSION_UNIT:
+		p = buflen >= 22 ? buffer[21] : 0;
+		n = buflen >= 24 + p ? buffer[22+p] : 0;
+
+		if (buflen < 24 + p + n) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				"interface %d EXTENSION_UNIT error\n",
+				udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL);
+		if (unit == NULL)
+			return -ENOMEM;
+
+		unit->id = buffer[3];
+		unit->type = buffer[2];
+		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
+		unit->extension.bNumControls = buffer[20];
+		unit->extension.bNrInPins =
+			le16_to_cpup((__le16 *)&buffer[21]);
+		unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
+		memcpy(unit->extension.baSourceID, &buffer[22], p);
+		unit->extension.bControlSize = buffer[22+p];
+		unit->extension.bmControls = (__u8 *)unit + sizeof *unit + p;
+		memcpy(unit->extension.bmControls, &buffer[23+p], n);
+
+		if (buffer[23+p+n] != 0)
+			usb_string(udev, buffer[23+p+n], unit->name,
+				   sizeof unit->name);
+		else
+			sprintf(unit->name, "Extension %u", buffer[3]);
+
+		list_add_tail(&unit->list, &dev->entities);
+		break;
+
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
+			"descriptor (%u)\n", buffer[2]);
+		break;
+	}
+
+	return 0;
+}
+
+static int uvc_parse_control(struct uvc_device *dev)
+{
+	struct usb_host_interface *alts = dev->intf->cur_altsetting;
+	unsigned char *buffer = alts->extra;
+	int buflen = alts->extralen;
+	int ret;
+
+	/* Parse the default alternate setting only, as the UVC specification
+	 * defines a single alternate setting, the default alternate setting
+	 * zero.
+	 */
+
+	while (buflen > 2) {
+		if (uvc_parse_vendor_control(dev, buffer, buflen) ||
+		    buffer[1] != USB_DT_CS_INTERFACE)
+			goto next_descriptor;
+
+		if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
+			return ret;
+
+next_descriptor:
+		buflen -= buffer[0];
+		buffer += buffer[0];
+	}
+
+	/* Check if the optional status endpoint is present. */
+	if (alts->desc.bNumEndpoints == 1) {
+		struct usb_host_endpoint *ep = &alts->endpoint[0];
+		struct usb_endpoint_descriptor *desc = &ep->desc;
+
+		if (usb_endpoint_is_int_in(desc) &&
+		    le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
+		    desc->bInterval != 0) {
+			uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
+				"(addr %02x).\n", desc->bEndpointAddress);
+			dev->int_ep = ep;
+		}
+	}
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * USB probe and disconnect
+ */
+
+/*
+ * Unregister the video devices.
+ */
+static void uvc_unregister_video(struct uvc_device *dev)
+{
+	if (dev->video.vdev) {
+		if (dev->video.vdev->minor == -1)
+			video_device_release(dev->video.vdev);
+		else
+			video_unregister_device(dev->video.vdev);
+		dev->video.vdev = NULL;
+	}
+}
+
+/*
+ * Scan the UVC descriptors to locate a chain starting at an Output Terminal
+ * and containing the following units:
+ *
+ * - a USB Streaming Output Terminal
+ * - zero or one Processing Unit
+ * - zero, one or mode single-input Selector Units
+ * - zero or one multiple-input Selector Units, provided all inputs are
+ *   connected to input terminals
+ * - zero, one or mode single-input Extension Units
+ * - one Camera Input Terminal, or one or more External terminals.
+ *
+ * A side forward scan is made on each detected entity to check for additional
+ * extension units.
+ */
+static int uvc_scan_chain_entity(struct uvc_video_device *video,
+	struct uvc_entity *entity)
+{
+	switch (UVC_ENTITY_TYPE(entity)) {
+	case VC_EXTENSION_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- XU %d", entity->id);
+
+		if (entity->extension.bNrInPins != 1) {
+			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
+				"than 1 input pin.\n", entity->id);
+			return -1;
+		}
+
+		list_add_tail(&entity->chain, &video->extensions);
+		break;
+
+	case VC_PROCESSING_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- PU %d", entity->id);
+
+		if (video->processing != NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found multiple "
+				"Processing Units in chain.\n");
+			return -1;
+		}
+
+		video->processing = entity;
+		break;
+
+	case VC_SELECTOR_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- SU %d", entity->id);
+
+		/* Single-input selector units are ignored. */
+		if (entity->selector.bNrInPins == 1)
+			break;
+
+		if (video->selector != NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
+				"Units in chain.\n");
+			return -1;
+		}
+
+		video->selector = entity;
+		break;
+
+	case ITT_VENDOR_SPECIFIC:
+	case ITT_CAMERA:
+	case ITT_MEDIA_TRANSPORT_INPUT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- IT %d\n", entity->id);
+
+		list_add_tail(&entity->chain, &video->iterms);
+		break;
+
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
+			"0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int uvc_scan_chain_forward(struct uvc_video_device *video,
+	struct uvc_entity *entity, struct uvc_entity *prev)
+{
+	struct uvc_entity *forward;
+	int found;
+
+	/* Forward scan */
+	forward = NULL;
+	found = 0;
+
+	while (1) {
+		forward = uvc_entity_by_reference(video->dev, entity->id,
+			forward);
+		if (forward == NULL)
+			break;
+
+		if (UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT ||
+		    forward == prev)
+			continue;
+
+		if (forward->extension.bNrInPins != 1) {
+			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+				"more than 1 input pin.\n", entity->id);
+			return -1;
+		}
+
+		list_add_tail(&forward->chain, &video->extensions);
+		if (uvc_trace_param & UVC_TRACE_PROBE) {
+			if (!found)
+				printk(" (-> XU");
+
+			printk(" %d", forward->id);
+			found = 1;
+		}
+	}
+	if (found)
+		printk(")");
+
+	return 0;
+}
+
+static int uvc_scan_chain_backward(struct uvc_video_device *video,
+	struct uvc_entity *entity)
+{
+	struct uvc_entity *term;
+	int id = -1, i;
+
+	switch (UVC_ENTITY_TYPE(entity)) {
+	case VC_EXTENSION_UNIT:
+		id = entity->extension.baSourceID[0];
+		break;
+
+	case VC_PROCESSING_UNIT:
+		id = entity->processing.bSourceID;
+		break;
+
+	case VC_SELECTOR_UNIT:
+		/* Single-input selector units are ignored. */
+		if (entity->selector.bNrInPins == 1) {
+			id = entity->selector.baSourceID[0];
+			break;
+		}
+
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- IT");
+
+		video->selector = entity;
+		for (i = 0; i < entity->selector.bNrInPins; ++i) {
+			id = entity->selector.baSourceID[i];
+			term = uvc_entity_by_id(video->dev, id);
+			if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
+				uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
+					"input %d isn't connected to an "
+					"input terminal\n", entity->id, i);
+				return -1;
+			}
+
+			if (uvc_trace_param & UVC_TRACE_PROBE)
+				printk(" %d", term->id);
+
+			list_add_tail(&term->chain, &video->iterms);
+			uvc_scan_chain_forward(video, term, entity);
+		}
+
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk("\n");
+
+		id = 0;
+		break;
+	}
+
+	return id;
+}
+
+static int uvc_scan_chain(struct uvc_video_device *video)
+{
+	struct uvc_entity *entity, *prev;
+	int id;
+
+	entity = video->oterm;
+	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+	id = entity->output.bSourceID;
+	while (id != 0) {
+		prev = entity;
+		entity = uvc_entity_by_id(video->dev, id);
+		if (entity == NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+				"unknown entity %d.\n", id);
+			return -1;
+		}
+
+		/* Process entity */
+		if (uvc_scan_chain_entity(video, entity) < 0)
+			return -1;
+
+		/* Forward scan */
+		if (uvc_scan_chain_forward(video, entity, prev) < 0)
+			return -1;
+
+		/* Stop when a terminal is found. */
+		if (!UVC_ENTITY_IS_UNIT(entity))
+			break;
+
+		/* Backward scan */
+		id = uvc_scan_chain_backward(video, entity);
+		if (id < 0)
+			return id;
+	}
+
+	/* Initialize the video buffers queue. */
+	uvc_queue_init(&video->queue);
+
+	return 0;
+}
+
+/*
+ * Register the video devices.
+ *
+ * The driver currently supports a single video device per control interface
+ * only. The terminal and units must match the following structure:
+ *
+ * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ *
+ * The Extension Units, if present, must have a single input pin. The
+ * Processing Unit and Extension Units can be in any order. Additional
+ * Extension Units connected to the main chain as single-unit branches are
+ * also supported.
+ */
+static int uvc_register_video(struct uvc_device *dev)
+{
+	struct video_device *vdev;
+	struct uvc_entity *term;
+	int found = 0, ret;
+
+	/* Check if the control interface matches the structure we expect. */
+	list_for_each_entry(term, &dev->entities, list) {
+		struct uvc_streaming *streaming;
+
+		if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+			continue;
+
+		memset(&dev->video, 0, sizeof dev->video);
+		mutex_init(&dev->video.ctrl_mutex);
+		INIT_LIST_HEAD(&dev->video.iterms);
+		INIT_LIST_HEAD(&dev->video.extensions);
+		dev->video.oterm = term;
+		dev->video.dev = dev;
+		if (uvc_scan_chain(&dev->video) < 0)
+			continue;
+
+		list_for_each_entry(streaming, &dev->streaming, list) {
+			if (streaming->header.bTerminalLink == term->id) {
+				dev->video.streaming = streaming;
+				found = 1;
+				break;
+			}
+		}
+
+		if (found)
+			break;
+	}
+
+	if (!found) {
+		uvc_printk(KERN_INFO, "No valid video chain found.\n");
+		return -1;
+	}
+
+	if (uvc_trace_param & UVC_TRACE_PROBE) {
+		uvc_printk(KERN_INFO, "Found a valid video chain (");
+		list_for_each_entry(term, &dev->video.iterms, chain) {
+			printk("%d", term->id);
+			if (term->chain.next != &dev->video.iterms)
+				printk(",");
+		}
+		printk(" -> %d).\n", dev->video.oterm->id);
+	}
+
+	/* Initialize the streaming interface with default streaming
+	 * parameters.
+	 */
+	if ((ret = uvc_video_init(&dev->video)) < 0) {
+		uvc_printk(KERN_ERR, "Failed to initialize the device "
+			"(%d).\n", ret);
+		return ret;
+	}
+
+	/* Register the device with V4L. */
+	vdev = video_device_alloc();
+	if (vdev == NULL)
+		return -1;
+
+	/* We already hold a reference to dev->udev. The video device will be
+	 * unregistered before the reference is released, so we don't need to
+	 * get another one.
+	 */
+	vdev->dev = &dev->intf->dev;
+	vdev->type = 0;
+	vdev->type2 = 0;
+	vdev->minor = -1;
+	vdev->fops = &uvc_fops;
+	vdev->release = video_device_release;
+	strncpy(vdev->name, dev->name, sizeof vdev->name);
+
+	/* Set the driver data before calling video_register_device, otherwise
+	 * uvc_v4l2_open might race us.
+	 *
+	 * FIXME: usb_set_intfdata hasn't been called so far. Is that a
+	 * 	  problem ? Does any function which could be called here get
+	 * 	  a pointer to the usb_interface ?
+	 */
+	dev->video.vdev = vdev;
+	video_set_drvdata(vdev, &dev->video);
+
+	if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {
+		dev->video.vdev = NULL;
+		video_device_release(vdev);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Delete the UVC device.
+ *
+ * Called by the kernel when the last reference to the uvc_device structure
+ * is released.
+ *
+ * Unregistering the video devices is done here because every opened instance
+ * must be closed before the device can be unregistered. An alternative would
+ * have been to use another reference count for uvc_v4l2_open/uvc_release, and
+ * unregister the video devices on disconnect when that reference count drops
+ * to zero.
+ *
+ * As this function is called after or during disconnect(), all URBs have
+ * already been canceled by the USB core. There is no need to kill the
+ * interrupt URB manually.
+ */
+void uvc_delete(struct kref *kref)
+{
+	struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
+	struct list_head *p, *n;
+
+	/* Unregister the video device */
+	uvc_unregister_video(dev);
+	usb_put_intf(dev->intf);
+	usb_put_dev(dev->udev);
+
+	uvc_status_cleanup(dev);
+	uvc_ctrl_cleanup_device(dev);
+
+	list_for_each_safe(p, n, &dev->entities) {
+		struct uvc_entity *entity;
+		entity = list_entry(p, struct uvc_entity, list);
+		kfree(entity);
+	}
+
+	list_for_each_safe(p, n, &dev->streaming) {
+		struct uvc_streaming *streaming;
+		streaming = list_entry(p, struct uvc_streaming, list);
+		usb_driver_release_interface(&uvc_driver.driver,
+			streaming->intf);
+		usb_put_intf(streaming->intf);
+		kfree(streaming->format);
+		kfree(streaming->header.bmaControls);
+		kfree(streaming);
+	}
+
+	kfree(dev);
+}
+
+static int uvc_probe(struct usb_interface *intf,
+		     const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct uvc_device *dev;
+	int ret;
+
+	if (id->idVendor && id->idProduct)
+		uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
+				"(%04x:%04x)\n", udev->devpath, id->idVendor,
+				id->idProduct);
+	else
+		uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
+				udev->devpath);
+
+	/* Allocate memory for the device and initialize it */
+	if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&dev->entities);
+	INIT_LIST_HEAD(&dev->streaming);
+	kref_init(&dev->kref);
+
+	dev->udev = usb_get_dev(udev);
+	dev->intf = usb_get_intf(intf);
+	dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	dev->quirks = id->driver_info | uvc_quirks_param;
+
+	if (udev->product != NULL)
+		strncpy(dev->name, udev->product, sizeof dev->name);
+	else
+		snprintf(dev->name, sizeof dev->name,
+			"UVC Camera (%04x:%04x)",
+			le16_to_cpu(udev->descriptor.idVendor),
+			le16_to_cpu(udev->descriptor.idProduct));
+
+	/* Parse the Video Class control descriptor */
+	if (uvc_parse_control(dev) < 0) {
+		uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
+			"descriptors.\n");
+		goto error;
+	}
+
+	uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n",
+		dev->uvc_version >> 8, dev->uvc_version & 0xff,
+		udev->product ? udev->product : "<unnamed>",
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct));
+
+	if (uvc_quirks_param != 0) {
+		uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
+			"parameter for testing purpose.\n", uvc_quirks_param);
+		uvc_printk(KERN_INFO, "Please report required quirks to the "
+			"linux-uvc-devel mailing list.\n");
+	}
+
+	/* Initialize controls */
+	if (uvc_ctrl_init_device(dev) < 0)
+		goto error;
+
+	/* Register the video devices */
+	if (uvc_register_video(dev) < 0)
+		goto error;
+
+	/* Save our data pointer in the interface data */
+	usb_set_intfdata(intf, dev);
+
+	/* Initialize the interrupt URB */
+	if ((ret = uvc_status_init(dev)) < 0) {
+		uvc_printk(KERN_INFO, "Unable to initialize the status "
+			"endpoint (%d), status interrupt will not be "
+			"supported.\n", ret);
+	}
+
+	uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+	return 0;
+
+error:
+	kref_put(&dev->kref, uvc_delete);
+	return -ENODEV;
+}
+
+static void uvc_disconnect(struct usb_interface *intf)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+
+	/* Set the USB interface data to NULL. This can be done outside the
+	 * lock, as there's no other reader.
+	 */
+	usb_set_intfdata(intf, NULL);
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)
+		return;
+
+	/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide
+	 * lock is needed to prevent uvc_disconnect from releasing its
+	 * reference to the uvc_device instance after uvc_v4l2_open() received
+	 * the pointer to the device (video_devdata) but before it got the
+	 * chance to increase the reference count (kref_get).
+	 */
+	mutex_lock(&uvc_driver.open_mutex);
+
+	dev->state |= UVC_DEV_DISCONNECTED;
+	kref_put(&dev->kref, uvc_delete);
+
+	mutex_unlock(&uvc_driver.open_mutex);
+}
+
+static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	/* Controls are cached on the fly so they don't need to be saved. */
+	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)
+		return uvc_status_suspend(dev);
+
+	if (dev->video.streaming->intf != intf) {
+		uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "
+				"interface mismatch.\n");
+		return -EINVAL;
+	}
+
+	return uvc_video_suspend(&dev->video);
+}
+
+static int uvc_resume(struct usb_interface *intf)
+{
+	struct uvc_device *dev = usb_get_intfdata(intf);
+	int ret;
+
+	uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
+		intf->cur_altsetting->desc.bInterfaceNumber);
+
+	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {
+		if ((ret = uvc_ctrl_resume_device(dev)) < 0)
+			return ret;
+
+		return uvc_status_resume(dev);
+	}
+
+	if (dev->video.streaming->intf != intf) {
+		uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "
+				"interface mismatch.\n");
+		return -EINVAL;
+	}
+
+	return uvc_video_resume(&dev->video);
+}
+
+/* ------------------------------------------------------------------------
+ * Driver initialization and cleanup
+ */
+
+/*
+ * The Logitech cameras listed below have their interface class set to
+ * VENDOR_SPEC because they don't announce themselves as UVC devices, even
+ * though they are compliant.
+ */
+static struct usb_device_id uvc_ids[] = {
+	/* ALi M5606 (Clevo M540SR) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0402,
+	  .idProduct		= 0x5606,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Creative Live! Optia */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x041e,
+	  .idProduct		= 0x4057,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Microsoft Lifecam NX-6000 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x045e,
+	  .idProduct		= 0x00f8,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Microsoft Lifecam VX-7000 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x045e,
+	  .idProduct		= 0x0723,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Logitech Quickcam Fusion */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c1,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam Orbit MP */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c2,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam Pro for Notebook */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c3,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam Pro 5000 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c5,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam OEM Dell Notebook */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c6,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Logitech Quickcam OEM Cisco VT Camera II */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x046d,
+	  .idProduct		= 0x08c7,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
+	/* Apple Built-In iSight */
+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x05ac,
+	  .idProduct		= 0x8501,
+	  .bInterfaceClass      = USB_CLASS_VIDEO,
+	  .bInterfaceSubClass   = 1,
+	  .bInterfaceProtocol   = 0,
+	  .driver_info 		= UVC_QUIRK_PROBE_MINMAX
+				| UVC_QUIRK_BUILTIN_ISIGHT },
+	/* Genesys Logic USB 2.0 PC Camera */
+	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor             = 0x05e3,
+	  .idProduct            = 0x0505,
+	  .bInterfaceClass      = USB_CLASS_VIDEO,
+	  .bInterfaceSubClass   = 1,
+	  .bInterfaceProtocol   = 0,
+	  .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+	/* Silicon Motion SM371 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x090c,
+	  .idProduct		= 0xb371,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* MT6227 */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x0e8d,
+	  .idProduct		= 0x0004,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Syntek (HP Spartan) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x174f,
+	  .idProduct		= 0x5212,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
+	/* Syntek (Asus U3S) */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x174f,
+	  .idProduct		= 0x8a33,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },
+	/* Ecamm Pico iMage */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x18cd,
+	  .idProduct		= 0xcafe,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_EXTRAFIELDS },
+	/* Bodelin ProScopeHR */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_DEV_HI
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x19ab,
+	  .idProduct		= 0x1000,
+	  .bcdDevice_hi		= 0x0126,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_STATUS_INTERVAL },
+	/* SiGma Micro USB Web Camera */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x1c4f,
+	  .idProduct		= 0x3000,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX
+				| UVC_QUIRK_IGNORE_SELECTOR_UNIT},
+	/* Acer OEM Webcam - Unknown vendor */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0100,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Packard Bell OEM Webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0101,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Acer Crystal Eye webcam */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0102,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Acer OrbiCam - Unknown vendor */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x5986,
+	  .idProduct		= 0x0200,
+	  .bInterfaceClass	= USB_CLASS_VIDEO,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0,
+	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },
+	/* Generic USB Video Class */
+	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, uvc_ids);
+
+struct uvc_driver uvc_driver = {
+	.driver = {
+		.name		= "uvcvideo",
+		.probe		= uvc_probe,
+		.disconnect	= uvc_disconnect,
+		.suspend	= uvc_suspend,
+		.resume		= uvc_resume,
+		.id_table	= uvc_ids,
+		.supports_autosuspend = 1,
+	},
+};
+
+static int __init uvc_init(void)
+{
+	int result;
+
+	INIT_LIST_HEAD(&uvc_driver.devices);
+	INIT_LIST_HEAD(&uvc_driver.controls);
+	mutex_init(&uvc_driver.open_mutex);
+	mutex_init(&uvc_driver.ctrl_mutex);
+
+	uvc_ctrl_init();
+
+	result = usb_register(&uvc_driver.driver);
+	if (result == 0)
+		printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+	return result;
+}
+
+static void __exit uvc_cleanup(void)
+{
+	usb_deregister(&uvc_driver.driver);
+}
+
+module_init(uvc_init);
+module_exit(uvc_cleanup);
+
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
new file mode 100644
index 000000000000..37bdefdbead5
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -0,0 +1,134 @@
+/*
+ *      uvc_isight.c  --  USB Video Class driver - iSight support
+ *
+ *	Copyright (C) 2006-2007
+ *		Ivan N. Zlatev <contact@i-nz.net>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include "uvcvideo.h"
+
+/* Built-in iSight webcams implements most of UVC 1.0 except a
+ * different packet format. Instead of sending a header at the
+ * beginning of each isochronous transfer payload, the webcam sends a
+ * single header per image (on its own in a packet), followed by
+ * packets containing data only.
+ *
+ * Offset   Size (bytes)	Description
+ * ------------------------------------------------------------------
+ * 0x00 	1   	Header length
+ * 0x01 	1   	Flags (UVC-compliant)
+ * 0x02 	4   	Always equal to '11223344'
+ * 0x06 	8   	Always equal to 'deadbeefdeadface'
+ * 0x0e 	16  	Unknown
+ *
+ * The header can be prefixed by an optional, unknown-purpose byte.
+ */
+
+static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
+		const __u8 *data, unsigned int len)
+{
+	static const __u8 hdr[] = {
+		0x11, 0x22, 0x33, 0x44,
+		0xde, 0xad, 0xbe, 0xef,
+		0xde, 0xad, 0xfa, 0xce
+	};
+
+	unsigned int maxlen, nbytes;
+	__u8 *mem;
+	int is_header = 0;
+
+	if (buf == NULL)
+		return 0;
+
+	if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) ||
+	    (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) {
+		uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
+		is_header = 1;
+	}
+
+	/* Synchronize to the input stream by waiting for a header packet. */
+	if (buf->state != UVC_BUF_STATE_ACTIVE) {
+		if (!is_header) {
+			uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
+				  "sync).\n");
+			return 0;
+		}
+
+		buf->state = UVC_BUF_STATE_ACTIVE;
+	}
+
+	/* Mark the buffer as done if we're at the beginning of a new frame.
+	 *
+	 * Empty buffers (bytesused == 0) don't trigger end of frame detection
+	 * as it doesn't make sense to return an empty buffer.
+	 */
+	if (is_header && buf->buf.bytesused != 0) {
+		buf->state = UVC_BUF_STATE_DONE;
+		return -EAGAIN;
+	}
+
+	/* Copy the video data to the buffer. Skip header packets, as they
+	 * contain no data.
+	 */
+	if (!is_header) {
+		maxlen = buf->buf.length - buf->buf.bytesused;
+		mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+		nbytes = min(len, maxlen);
+		memcpy(mem, data, nbytes);
+		buf->buf.bytesused += nbytes;
+
+		if (len > maxlen || buf->buf.bytesused == buf->buf.length) {
+			uvc_trace(UVC_TRACE_FRAME, "Frame complete "
+				  "(overflow).\n");
+			buf->state = UVC_BUF_STATE_DONE;
+		}
+	}
+
+	return 0;
+}
+
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+		struct uvc_buffer *buf)
+{
+	int ret, i;
+
+	for (i = 0; i < urb->number_of_packets; ++i) {
+		if (urb->iso_frame_desc[i].status < 0) {
+			uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+				  "lost (%d).\n",
+				  urb->iso_frame_desc[i].status);
+		}
+
+		/* Decode the payload packet.
+		 * uvc_video_decode is entered twice when a frame transition
+		 * has been detected because the end of frame can only be
+		 * reliably detected when the first packet of the new frame
+		 * is processed. The first pass detects the transition and
+		 * closes the previous frame's buffer, the second pass
+		 * processes the data of the first payload of the new frame.
+		 */
+		do {
+			ret = isight_decode(&video->queue, buf,
+					urb->transfer_buffer +
+					urb->iso_frame_desc[i].offset,
+					urb->iso_frame_desc[i].actual_length);
+
+			if (buf == NULL)
+				break;
+
+			if (buf->state == UVC_BUF_STATE_DONE ||
+			    buf->state == UVC_BUF_STATE_ERROR)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		} while (ret == -EAGAIN);
+	}
+}
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
new file mode 100644
index 000000000000..0923f0e3b3d4
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -0,0 +1,477 @@
+/*
+ *      uvc_queue.c  --  USB Video Class driver - Buffers management
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * Video buffers queue management.
+ *
+ * Video queues is initialized by uvc_queue_init(). The function performs
+ * basic initialization of the uvc_video_queue struct and never fails.
+ *
+ * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
+ * uvc_free_buffers respectively. The former acquires the video queue lock,
+ * while the later must be called with the lock held (so that allocation can
+ * free previously allocated buffers). Trying to free buffers that are mapped
+ * to user space will return -EBUSY.
+ *
+ * Video buffers are managed using two queues. However, unlike most USB video
+ * drivers which use an in queue and an out queue, we use a main queue which
+ * holds all queued buffers (both 'empty' and 'done' buffers), and an irq
+ * queue which holds empty buffers. This design (copied from video-buf)
+ * minimizes locking in interrupt, as only one queue is shared between
+ * interrupt and user contexts.
+ *
+ * Use cases
+ * ---------
+ *
+ * Unless stated otherwise, all operations which modify the irq buffers queue
+ * are protected by the irq spinlock.
+ *
+ * 1. The user queues the buffers, starts streaming and dequeues a buffer.
+ *
+ *    The buffers are added to the main and irq queues. Both operations are
+ *    protected by the queue lock, and the latert is protected by the irq
+ *    spinlock as well.
+ *
+ *    The completion handler fetches a buffer from the irq queue and fills it
+ *    with video data. If no buffer is available (irq queue empty), the handler
+ *    returns immediately.
+ *
+ *    When the buffer is full, the completion handler removes it from the irq
+ *    queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue.
+ *    At that point, any process waiting on the buffer will be woken up. If a
+ *    process tries to dequeue a buffer after it has been marked ready, the
+ *    dequeing will succeed immediately.
+ *
+ * 2. Buffers are queued, user is waiting on a buffer and the device gets
+ *    disconnected.
+ *
+ *    When the device is disconnected, the kernel calls the completion handler
+ *    with an appropriate status code. The handler marks all buffers in the
+ *    irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
+ *    that any process waiting on a buffer gets woken up.
+ *
+ *    Waking up up the first buffer on the irq list is not enough, as the
+ *    process waiting on the buffer might restart the dequeue operation
+ *    immediately.
+ *
+ */
+
+void uvc_queue_init(struct uvc_video_queue *queue)
+{
+	mutex_init(&queue->mutex);
+	spin_lock_init(&queue->irqlock);
+	INIT_LIST_HEAD(&queue->mainqueue);
+	INIT_LIST_HEAD(&queue->irqqueue);
+}
+
+/*
+ * Allocate the video buffers.
+ *
+ * Pages are reserved to make sure they will not be swaped, as they will be
+ * filled in URB completion handler.
+ *
+ * Buffers will be individually mapped, so they must all be page aligned.
+ */
+int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
+		unsigned int buflength)
+{
+	unsigned int bufsize = PAGE_ALIGN(buflength);
+	unsigned int i;
+	void *mem = NULL;
+	int ret;
+
+	if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
+		nbuffers = UVC_MAX_VIDEO_BUFFERS;
+
+	mutex_lock(&queue->mutex);
+
+	if ((ret = uvc_free_buffers(queue)) < 0)
+		goto done;
+
+	/* Bail out if no buffers should be allocated. */
+	if (nbuffers == 0)
+		goto done;
+
+	/* Decrement the number of buffers until allocation succeeds. */
+	for (; nbuffers > 0; --nbuffers) {
+		mem = vmalloc_32(nbuffers * bufsize);
+		if (mem != NULL)
+			break;
+	}
+
+	if (mem == NULL) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	for (i = 0; i < nbuffers; ++i) {
+		memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
+		queue->buffer[i].buf.index = i;
+		queue->buffer[i].buf.m.offset = i * bufsize;
+		queue->buffer[i].buf.length = buflength;
+		queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		queue->buffer[i].buf.sequence = 0;
+		queue->buffer[i].buf.field = V4L2_FIELD_NONE;
+		queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
+		queue->buffer[i].buf.flags = 0;
+		init_waitqueue_head(&queue->buffer[i].wait);
+	}
+
+	queue->mem = mem;
+	queue->count = nbuffers;
+	queue->buf_size = bufsize;
+	ret = nbuffers;
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+	unsigned int i;
+
+	for (i = 0; i < queue->count; ++i) {
+		if (queue->buffer[i].vma_use_count != 0)
+			return -EBUSY;
+	}
+
+	if (queue->count) {
+		vfree(queue->mem);
+		queue->count = 0;
+	}
+
+	return 0;
+}
+
+static void __uvc_query_buffer(struct uvc_buffer *buf,
+		struct v4l2_buffer *v4l2_buf)
+{
+	memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
+
+	if (buf->vma_use_count)
+		v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	switch (buf->state) {
+	case UVC_BUF_STATE_ERROR:
+	case UVC_BUF_STATE_DONE:
+		v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
+		break;
+	case UVC_BUF_STATE_QUEUED:
+	case UVC_BUF_STATE_ACTIVE:
+		v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
+		break;
+	case UVC_BUF_STATE_IDLE:
+	default:
+		break;
+	}
+}
+
+int uvc_query_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf)
+{
+	int ret = 0;
+
+	mutex_lock(&queue->mutex);
+	if (v4l2_buf->index >= queue->count) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+
+done:
+       mutex_unlock(&queue->mutex);
+       return ret;
+}
+
+/*
+ * Queue a video buffer. Attempting to queue a buffer that has already been
+ * queued will return -EINVAL.
+ */
+int uvc_queue_buffer(struct uvc_video_queue *queue,
+	struct v4l2_buffer *v4l2_buf)
+{
+	struct uvc_buffer *buf;
+	unsigned long flags;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+			"and/or memory (%u).\n", v4l2_buf->type,
+			v4l2_buf->memory);
+		return -EINVAL;
+	}
+
+	mutex_lock(&queue->mutex);
+	if (v4l2_buf->index >= queue->count)  {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = &queue->buffer[v4l2_buf->index];
+	if (buf->state != UVC_BUF_STATE_IDLE) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
+			"(%u).\n", buf->state);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	if (queue->flags & UVC_QUEUE_DISCONNECTED) {
+		spin_unlock_irqrestore(&queue->irqlock, flags);
+		ret = -ENODEV;
+		goto done;
+	}
+	buf->state = UVC_BUF_STATE_QUEUED;
+	buf->buf.bytesused = 0;
+	list_add_tail(&buf->stream, &queue->mainqueue);
+	list_add_tail(&buf->queue, &queue->irqqueue);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
+{
+	if (nonblocking) {
+		return (buf->state != UVC_BUF_STATE_QUEUED &&
+			buf->state != UVC_BUF_STATE_ACTIVE)
+			? 0 : -EAGAIN;
+	}
+
+	return wait_event_interruptible(buf->wait,
+		buf->state != UVC_BUF_STATE_QUEUED &&
+		buf->state != UVC_BUF_STATE_ACTIVE);
+}
+
+/*
+ * Dequeue a video buffer. If nonblocking is false, block until a buffer is
+ * available.
+ */
+int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf, int nonblocking)
+{
+	struct uvc_buffer *buf;
+	int ret = 0;
+
+	if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+	    v4l2_buf->memory != V4L2_MEMORY_MMAP) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
+			"and/or memory (%u).\n", v4l2_buf->type,
+			v4l2_buf->memory);
+		return -EINVAL;
+	}
+
+	mutex_lock(&queue->mutex);
+	if (list_empty(&queue->mainqueue)) {
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
+		ret = -EINVAL;
+		goto done;
+	}
+
+	buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+	if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
+		goto done;
+
+	uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
+		buf->buf.index, buf->state, buf->buf.bytesused);
+
+	switch (buf->state) {
+	case UVC_BUF_STATE_ERROR:
+		uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
+			"(transmission error).\n");
+		ret = -EIO;
+	case UVC_BUF_STATE_DONE:
+		buf->state = UVC_BUF_STATE_IDLE;
+		break;
+
+	case UVC_BUF_STATE_IDLE:
+	case UVC_BUF_STATE_QUEUED:
+	case UVC_BUF_STATE_ACTIVE:
+	default:
+		uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
+			"(driver bug?).\n", buf->state);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	list_del(&buf->stream);
+	__uvc_query_buffer(buf, v4l2_buf);
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Poll the video queue.
+ *
+ * This function implements video queue polling and is intended to be used by
+ * the device poll handler.
+ */
+unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
+		poll_table *wait)
+{
+	struct uvc_buffer *buf;
+	unsigned int mask = 0;
+
+	mutex_lock(&queue->mutex);
+	if (list_empty(&queue->mainqueue)) {
+		mask |= POLLERR;
+		goto done;
+	}
+	buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
+
+	poll_wait(file, &buf->wait, wait);
+	if (buf->state == UVC_BUF_STATE_DONE ||
+	    buf->state == UVC_BUF_STATE_ERROR)
+		mask |= POLLIN | POLLRDNORM;
+
+done:
+	mutex_unlock(&queue->mutex);
+	return mask;
+}
+
+/*
+ * Enable or disable the video buffers queue.
+ *
+ * The queue must be enabled before starting video acquisition and must be
+ * disabled after stopping it. This ensures that the video buffers queue
+ * state can be properly initialized before buffers are accessed from the
+ * interrupt handler.
+ *
+ * Enabling the video queue initializes parameters (such as sequence number,
+ * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ *
+ * Disabling the video queue cancels the queue and removes all buffers from
+ * the main queue.
+ *
+ * This function can't be called from interrupt context. Use
+ * uvc_queue_cancel() instead.
+ */
+int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
+{
+	unsigned int i;
+	int ret = 0;
+
+	mutex_lock(&queue->mutex);
+	if (enable) {
+		if (uvc_queue_streaming(queue)) {
+			ret = -EBUSY;
+			goto done;
+		}
+		queue->sequence = 0;
+		queue->flags |= UVC_QUEUE_STREAMING;
+	} else {
+		uvc_queue_cancel(queue, 0);
+		INIT_LIST_HEAD(&queue->mainqueue);
+
+		for (i = 0; i < queue->count; ++i)
+			queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+
+		queue->flags &= ~UVC_QUEUE_STREAMING;
+	}
+
+done:
+	mutex_unlock(&queue->mutex);
+	return ret;
+}
+
+/*
+ * Cancel the video buffers queue.
+ *
+ * Cancelling the queue marks all buffers on the irq queue as erroneous,
+ * wakes them up and remove them from the queue.
+ *
+ * If the disconnect parameter is set, further calls to uvc_queue_buffer will
+ * fail with -ENODEV.
+ *
+ * This function acquires the irq spinlock and can be called from interrupt
+ * context.
+ */
+void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
+{
+	struct uvc_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	while (!list_empty(&queue->irqqueue)) {
+		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+				       queue);
+		list_del(&buf->queue);
+		buf->state = UVC_BUF_STATE_ERROR;
+		wake_up(&buf->wait);
+	}
+	/* This must be protected by the irqlock spinlock to avoid race
+	 * conditions between uvc_queue_buffer and the disconnection event that
+	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
+	 * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED
+	 * state outside the queue code.
+	 */
+	if (disconnect)
+		queue->flags |= UVC_QUEUE_DISCONNECTED;
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
+struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+		struct uvc_buffer *buf)
+{
+	struct uvc_buffer *nextbuf;
+	unsigned long flags;
+
+	if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
+	    buf->buf.length != buf->buf.bytesused) {
+		buf->state = UVC_BUF_STATE_QUEUED;
+		buf->buf.bytesused = 0;
+		return buf;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	list_del(&buf->queue);
+	if (!list_empty(&queue->irqqueue))
+		nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+					   queue);
+	else
+		nextbuf = NULL;
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	buf->buf.sequence = queue->sequence++;
+	do_gettimeofday(&buf->buf.timestamp);
+
+	wake_up(&buf->wait);
+	return nextbuf;
+}
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
new file mode 100644
index 000000000000..be9084e5eace
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -0,0 +1,207 @@
+/*
+ *      uvc_status.c  --  USB Video Class driver - Status endpoint
+ *
+ *      Copyright (C) 2007-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+
+#include "uvcvideo.h"
+
+/* --------------------------------------------------------------------------
+ * Input device
+ */
+static int uvc_input_init(struct uvc_device *dev)
+{
+	struct usb_device *udev = dev->udev;
+	struct input_dev *input;
+	char *phys = NULL;
+	int ret;
+
+	input = input_allocate_device();
+	if (input == NULL)
+		return -ENOMEM;
+
+	phys = kmalloc(6 + strlen(udev->bus->bus_name) + strlen(udev->devpath),
+			GFP_KERNEL);
+	if (phys == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	sprintf(phys, "usb-%s-%s", udev->bus->bus_name, udev->devpath);
+
+	input->name = dev->name;
+	input->phys = phys;
+	usb_to_input_id(udev, &input->id);
+	input->dev.parent = &dev->intf->dev;
+
+	set_bit(EV_KEY, input->evbit);
+	set_bit(BTN_0, input->keybit);
+
+	if ((ret = input_register_device(input)) < 0)
+		goto error;
+
+	dev->input = input;
+	return 0;
+
+error:
+	input_free_device(input);
+	kfree(phys);
+	return ret;
+}
+
+static void uvc_input_cleanup(struct uvc_device *dev)
+{
+	if (dev->input)
+		input_unregister_device(dev->input);
+}
+
+/* --------------------------------------------------------------------------
+ * Status interrupt endpoint
+ */
+static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
+{
+	if (len < 3) {
+		uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
+				"received.\n");
+		return;
+	}
+
+	if (data[2] == 0) {
+		if (len < 4)
+			return;
+		uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
+			data[1], data[3] ? "pressed" : "released", len);
+		if (dev->input)
+			input_report_key(dev->input, BTN_0, data[3]);
+	} else {
+		uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
+			"len %d.\n", data[1], data[2], data[3], len);
+	}
+}
+
+static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
+{
+	char *attrs[3] = { "value", "info", "failure" };
+
+	if (len < 6 || data[2] != 0 || data[4] > 2) {
+		uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
+				"received.\n");
+		return;
+	}
+
+	uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
+		data[1], data[3], attrs[data[4]], len);
+}
+
+static void uvc_status_complete(struct urb *urb)
+{
+	struct uvc_device *dev = urb->context;
+	int len, ret;
+
+	switch (urb->status) {
+	case 0:
+		break;
+
+	case -ENOENT:		/* usb_kill_urb() called. */
+	case -ECONNRESET:	/* usb_unlink_urb() called. */
+	case -ESHUTDOWN:	/* The endpoint is being disabled. */
+	case -EPROTO:		/* Device is disconnected (reported by some
+				 * host controller). */
+		return;
+
+	default:
+		uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
+			"completion handler.\n", urb->status);
+		return;
+	}
+
+	len = urb->actual_length;
+	if (len > 0) {
+		switch (dev->status[0] & 0x0f) {
+		case UVC_STATUS_TYPE_CONTROL:
+			uvc_event_control(dev, dev->status, len);
+			break;
+
+		case UVC_STATUS_TYPE_STREAMING:
+			uvc_event_streaming(dev, dev->status, len);
+			break;
+
+		default:
+			uvc_printk(KERN_INFO, "unknown event type %u.\n",
+				dev->status[0]);
+			break;
+		}
+	}
+
+	/* Resubmit the URB. */
+	urb->interval = dev->int_ep->desc.bInterval;
+	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
+			ret);
+	}
+}
+
+int uvc_status_init(struct uvc_device *dev)
+{
+	struct usb_host_endpoint *ep = dev->int_ep;
+	unsigned int pipe;
+	int interval;
+
+	if (ep == NULL)
+		return 0;
+
+	uvc_input_init(dev);
+
+	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (dev->int_urb == NULL)
+		return -ENOMEM;
+
+	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
+
+	/* For high-speed interrupt endpoints, the bInterval value is used as
+	 * an exponent of two. Some developers forgot about it.
+	 */
+	interval = ep->desc.bInterval;
+	if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
+	    (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
+		interval = fls(interval) - 1;
+
+	usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
+		dev->status, sizeof dev->status, uvc_status_complete,
+		dev, interval);
+
+	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_cleanup(struct uvc_device *dev)
+{
+	usb_kill_urb(dev->int_urb);
+	usb_free_urb(dev->int_urb);
+	uvc_input_cleanup(dev);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+	usb_kill_urb(dev->int_urb);
+	return 0;
+}
+
+int uvc_status_resume(struct uvc_device *dev)
+{
+	if (dev->int_urb == NULL)
+		return 0;
+
+	return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
new file mode 100644
index 000000000000..2e0a66575bb4
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -0,0 +1,1105 @@
+/*
+ *      uvc_v4l2.c  --  USB Video Class driver - V4L2 API
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * V4L2 interface
+ */
+
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls which can be mapped directly, and handle the others
+ * manually.
+ */
+static int uvc_v4l2_query_menu(struct uvc_video_device *video,
+	struct v4l2_querymenu *query_menu)
+{
+	struct uvc_menu_info *menu_info;
+	struct uvc_control_mapping *mapping;
+	struct uvc_control *ctrl;
+
+	ctrl = uvc_find_control(video, query_menu->id, &mapping);
+	if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
+		return -EINVAL;
+
+	if (query_menu->index >= mapping->menu_count)
+		return -EINVAL;
+
+	menu_info = &mapping->menu_info[query_menu->index];
+	strncpy(query_menu->name, menu_info->name, 32);
+	return 0;
+}
+
+/*
+ * Find the frame interval closest to the requested frame interval for the
+ * given frame format and size. This should be done by the device as part of
+ * the Video Probe and Commit negotiation, but some hardware don't implement
+ * that feature.
+ */
+static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
+{
+	unsigned int i;
+
+	if (frame->bFrameIntervalType) {
+		__u32 best = -1, dist;
+
+		for (i = 0; i < frame->bFrameIntervalType; ++i) {
+			dist = interval > frame->dwFrameInterval[i]
+			     ? interval - frame->dwFrameInterval[i]
+			     : frame->dwFrameInterval[i] - interval;
+
+			if (dist > best)
+				break;
+
+			best = dist;
+		}
+
+		interval = frame->dwFrameInterval[i-1];
+	} else {
+		const __u32 min = frame->dwFrameInterval[0];
+		const __u32 max = frame->dwFrameInterval[1];
+		const __u32 step = frame->dwFrameInterval[2];
+
+		interval = min + (interval - min + step/2) / step * step;
+		if (interval > max)
+			interval = max;
+	}
+
+	return interval;
+}
+
+static int uvc_v4l2_try_format(struct uvc_video_device *video,
+	struct v4l2_format *fmt, struct uvc_streaming_control *probe,
+	struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
+{
+	struct uvc_format *format = NULL;
+	struct uvc_frame *frame = NULL;
+	__u16 rw, rh;
+	unsigned int d, maxd;
+	unsigned int i;
+	__u32 interval;
+	int ret = 0;
+	__u8 *fcc;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
+	uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n",
+			fmt->fmt.pix.pixelformat,
+			fcc[0], fcc[1], fcc[2], fcc[3],
+			fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+	/* Check if the hardware supports the requested format. */
+	for (i = 0; i < video->streaming->nformats; ++i) {
+		format = &video->streaming->format[i];
+		if (format->fcc == fmt->fmt.pix.pixelformat)
+			break;
+	}
+
+	if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
+		uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n",
+				fmt->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	/* Find the closest image size. The distance between image sizes is
+	 * the size in pixels of the non-overlapping regions between the
+	 * requested size and the frame-specified size.
+	 */
+	rw = fmt->fmt.pix.width;
+	rh = fmt->fmt.pix.height;
+	maxd = (unsigned int)-1;
+
+	for (i = 0; i < format->nframes; ++i) {
+		__u16 w = format->frame[i].wWidth;
+		__u16 h = format->frame[i].wHeight;
+
+		d = min(w, rw) * min(h, rh);
+		d = w*h + rw*rh - 2*d;
+		if (d < maxd) {
+			maxd = d;
+			frame = &format->frame[i];
+		}
+
+		if (maxd == 0)
+			break;
+	}
+
+	if (frame == NULL) {
+		uvc_trace(UVC_TRACE_FORMAT, "Unsupported size %ux%u.\n",
+				fmt->fmt.pix.width, fmt->fmt.pix.height);
+		return -EINVAL;
+	}
+
+	/* Use the default frame interval. */
+	interval = frame->dwDefaultFrameInterval;
+	uvc_trace(UVC_TRACE_FORMAT, "Using default frame interval %u.%u us "
+		"(%u.%u fps).\n", interval/10, interval%10, 10000000/interval,
+		(100000000/interval)%10);
+
+	/* Set the format index, frame index and frame interval. */
+	memset(probe, 0, sizeof *probe);
+	probe->bmHint = 1;	/* dwFrameInterval */
+	probe->bFormatIndex = format->index;
+	probe->bFrameIndex = frame->bFrameIndex;
+	probe->dwFrameInterval = uvc_try_frame_interval(frame, interval);
+	/* Some webcams stall the probe control set request when the
+	 * dwMaxVideoFrameSize field is set to zero. The UVC specification
+	 * clearly states that the field is read-only from the host, so this
+	 * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by
+	 * the webcam to work around the problem.
+	 *
+	 * The workaround could probably be enabled for all webcams, so the
+	 * quirk can be removed if needed. It's currently useful to detect
+	 * webcam bugs and fix them before they hit the market (providing
+	 * developers test their webcams with the Linux driver as well as with
+	 * the Windows driver).
+	 */
+	if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+		probe->dwMaxVideoFrameSize =
+			video->streaming->ctrl.dwMaxVideoFrameSize;
+
+	/* Probe the device */
+	if ((ret = uvc_probe_video(video, probe)) < 0)
+		goto done;
+
+	fmt->fmt.pix.width = frame->wWidth;
+	fmt->fmt.pix.height = frame->wHeight;
+	fmt->fmt.pix.field = V4L2_FIELD_NONE;
+	fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+	fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+	fmt->fmt.pix.colorspace = format->colorspace;
+	fmt->fmt.pix.priv = 0;
+
+	if (uvc_format != NULL)
+		*uvc_format = format;
+	if (uvc_frame != NULL)
+		*uvc_frame = frame;
+
+done:
+	return ret;
+}
+
+static int uvc_v4l2_get_format(struct uvc_video_device *video,
+	struct v4l2_format *fmt)
+{
+	struct uvc_format *format = video->streaming->cur_format;
+	struct uvc_frame *frame = video->streaming->cur_frame;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (format == NULL || frame == NULL)
+		return -EINVAL;
+
+	fmt->fmt.pix.pixelformat = format->fcc;
+	fmt->fmt.pix.width = frame->wWidth;
+	fmt->fmt.pix.height = frame->wHeight;
+	fmt->fmt.pix.field = V4L2_FIELD_NONE;
+	fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
+	fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+	fmt->fmt.pix.colorspace = format->colorspace;
+	fmt->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int uvc_v4l2_set_format(struct uvc_video_device *video,
+	struct v4l2_format *fmt)
+{
+	struct uvc_streaming_control probe;
+	struct uvc_format *format;
+	struct uvc_frame *frame;
+	int ret;
+
+	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (uvc_queue_streaming(&video->queue))
+		return -EBUSY;
+
+	ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+	if (ret < 0)
+		return ret;
+
+	if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+		return ret;
+
+	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+	video->streaming->cur_format = format;
+	video->streaming->cur_frame = frame;
+
+	return 0;
+}
+
+static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+		struct v4l2_streamparm *parm)
+{
+	uint32_t numerator, denominator;
+
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	numerator = video->streaming->ctrl.dwFrameInterval;
+	denominator = 10000000;
+	uvc_simplify_fraction(&numerator, &denominator, 8, 333);
+
+	memset(parm, 0, sizeof *parm);
+	parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+	parm->parm.capture.capturemode = 0;
+	parm->parm.capture.timeperframe.numerator = numerator;
+	parm->parm.capture.timeperframe.denominator = denominator;
+	parm->parm.capture.extendedmode = 0;
+	parm->parm.capture.readbuffers = 0;
+
+	return 0;
+}
+
+static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+		struct v4l2_streamparm *parm)
+{
+	struct uvc_frame *frame = video->streaming->cur_frame;
+	struct uvc_streaming_control probe;
+	uint32_t interval;
+	int ret;
+
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (uvc_queue_streaming(&video->queue))
+		return -EBUSY;
+
+	memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+	interval = uvc_fraction_to_interval(
+			parm->parm.capture.timeperframe.numerator,
+			parm->parm.capture.timeperframe.denominator);
+
+	uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
+			parm->parm.capture.timeperframe.numerator,
+			parm->parm.capture.timeperframe.denominator,
+			interval);
+	probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+	/* Probe the device with the new settings. */
+	if ((ret = uvc_probe_video(video, &probe)) < 0)
+		return ret;
+
+	/* Commit the new settings. */
+	if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
+		return ret;
+
+	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+
+	/* Return the actual frame period. */
+	parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
+	parm->parm.capture.timeperframe.denominator = 10000000;
+	uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
+				&parm->parm.capture.timeperframe.denominator,
+				8, 333);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Privilege management
+ */
+
+/*
+ * Privilege management is the multiple-open implementation basis. The current
+ * implementation is completely transparent for the end-user and doesn't
+ * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
+ * Those ioctls enable finer control on the device (by making possible for a
+ * user to request exclusive access to a device), but are not mature yet.
+ * Switching to the V4L2 priority mechanism might be considered in the future
+ * if this situation changes.
+ *
+ * Each open instance of a UVC device can either be in a privileged or
+ * unprivileged state. Only a single instance can be in a privileged state at
+ * a given time. Trying to perform an operation which requires privileges will
+ * automatically acquire the required privileges if possible, or return -EBUSY
+ * otherwise. Privileges are dismissed when closing the instance.
+ *
+ * Operations which require privileges are:
+ *
+ * - VIDIOC_S_INPUT
+ * - VIDIOC_S_PARM
+ * - VIDIOC_S_FMT
+ * - VIDIOC_TRY_FMT
+ * - VIDIOC_REQBUFS
+ */
+static int uvc_acquire_privileges(struct uvc_fh *handle)
+{
+	int ret = 0;
+
+	/* Always succeed if the handle is already privileged. */
+	if (handle->state == UVC_HANDLE_ACTIVE)
+		return 0;
+
+	/* Check if the device already has a privileged handle. */
+	mutex_lock(&uvc_driver.open_mutex);
+	if (atomic_inc_return(&handle->device->active) != 1) {
+		atomic_dec(&handle->device->active);
+		ret = -EBUSY;
+		goto done;
+	}
+
+	handle->state = UVC_HANDLE_ACTIVE;
+
+done:
+	mutex_unlock(&uvc_driver.open_mutex);
+	return ret;
+}
+
+static void uvc_dismiss_privileges(struct uvc_fh *handle)
+{
+	if (handle->state == UVC_HANDLE_ACTIVE)
+		atomic_dec(&handle->device->active);
+
+	handle->state = UVC_HANDLE_PASSIVE;
+}
+
+static int uvc_has_privileges(struct uvc_fh *handle)
+{
+	return handle->state == UVC_HANDLE_ACTIVE;
+}
+
+/* ------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int uvc_v4l2_open(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev;
+	struct uvc_video_device *video;
+	struct uvc_fh *handle;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
+	mutex_lock(&uvc_driver.open_mutex);
+	vdev = video_devdata(file);
+	video = video_get_drvdata(vdev);
+
+	if (video->dev->state & UVC_DEV_DISCONNECTED) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	ret = usb_autopm_get_interface(video->dev->intf);
+	if (ret < 0)
+		goto done;
+
+	/* Create the device handle. */
+	handle = kzalloc(sizeof *handle, GFP_KERNEL);
+	if (handle == NULL) {
+		usb_autopm_put_interface(video->dev->intf);
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	handle->device = video;
+	handle->state = UVC_HANDLE_PASSIVE;
+	file->private_data = handle;
+
+	kref_get(&video->dev->kref);
+
+done:
+	mutex_unlock(&uvc_driver.open_mutex);
+	return ret;
+}
+
+static int uvc_v4l2_release(struct inode *inode, struct file *file)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
+
+	/* Only free resources if this is a privileged handle. */
+	if (uvc_has_privileges(handle)) {
+		uvc_video_enable(video, 0);
+
+		mutex_lock(&video->queue.mutex);
+		if (uvc_free_buffers(&video->queue) < 0)
+			uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
+					"free buffers.\n");
+		mutex_unlock(&video->queue.mutex);
+	}
+
+	/* Release the file handle. */
+	uvc_dismiss_privileges(handle);
+	kfree(handle);
+	file->private_data = NULL;
+
+	usb_autopm_put_interface(video->dev->intf);
+	kref_put(&video->dev->kref, uvc_delete);
+	return 0;
+}
+
+static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, void *arg)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	int ret = 0;
+
+	if (uvc_trace_param & UVC_TRACE_IOCTL)
+		v4l_printk_ioctl(cmd);
+
+	switch (cmd) {
+	/* Query capabilities */
+	case VIDIOC_QUERYCAP:
+	{
+		struct v4l2_capability *cap = arg;
+
+		memset(cap, 0, sizeof *cap);
+		strncpy(cap->driver, "uvcvideo", sizeof cap->driver);
+		strncpy(cap->card, vdev->name, 32);
+		strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
+			sizeof cap->bus_info);
+		cap->version = DRIVER_VERSION_NUMBER;
+		cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+				  | V4L2_CAP_STREAMING;
+		break;
+	}
+
+	/* Get, Set & Query control */
+	case VIDIOC_QUERYCTRL:
+		return uvc_query_v4l2_ctrl(video, arg);
+
+	case VIDIOC_G_CTRL:
+	{
+		struct v4l2_control *ctrl = arg;
+		struct v4l2_ext_control xctrl;
+
+		memset(&xctrl, 0, sizeof xctrl);
+		xctrl.id = ctrl->id;
+
+		uvc_ctrl_begin(video);
+		ret = uvc_ctrl_get(video, &xctrl);
+		uvc_ctrl_rollback(video);
+		if (ret >= 0)
+			ctrl->value = xctrl.value;
+		break;
+	}
+
+	case VIDIOC_S_CTRL:
+	{
+		struct v4l2_control *ctrl = arg;
+		struct v4l2_ext_control xctrl;
+
+		memset(&xctrl, 0, sizeof xctrl);
+		xctrl.id = ctrl->id;
+		xctrl.value = ctrl->value;
+
+		uvc_ctrl_begin(video);
+		ret = uvc_ctrl_set(video, &xctrl);
+		if (ret < 0) {
+			uvc_ctrl_rollback(video);
+			return ret;
+		}
+		ret = uvc_ctrl_commit(video);
+		break;
+	}
+
+	case VIDIOC_QUERYMENU:
+		return uvc_v4l2_query_menu(video, arg);
+
+	case VIDIOC_G_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *ctrls = arg;
+		struct v4l2_ext_control *ctrl = ctrls->controls;
+		unsigned int i;
+
+		uvc_ctrl_begin(video);
+		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+			ret = uvc_ctrl_get(video, ctrl);
+			if (ret < 0) {
+				uvc_ctrl_rollback(video);
+				ctrls->error_idx = i;
+				return ret;
+			}
+		}
+		ctrls->error_idx = 0;
+		ret = uvc_ctrl_rollback(video);
+		break;
+	}
+
+	case VIDIOC_S_EXT_CTRLS:
+	case VIDIOC_TRY_EXT_CTRLS:
+	{
+		struct v4l2_ext_controls *ctrls = arg;
+		struct v4l2_ext_control *ctrl = ctrls->controls;
+		unsigned int i;
+
+		ret = uvc_ctrl_begin(video);
+		if (ret < 0)
+			return ret;
+
+		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+			ret = uvc_ctrl_set(video, ctrl);
+			if (ret < 0) {
+				uvc_ctrl_rollback(video);
+				ctrls->error_idx = i;
+				return ret;
+			}
+		}
+
+		ctrls->error_idx = 0;
+
+		if (cmd == VIDIOC_S_EXT_CTRLS)
+			ret = uvc_ctrl_commit(video);
+		else
+			ret = uvc_ctrl_rollback(video);
+		break;
+	}
+
+	/* Get, Set & Enum input */
+	case VIDIOC_ENUMINPUT:
+	{
+		const struct uvc_entity *selector = video->selector;
+		struct v4l2_input *input = arg;
+		struct uvc_entity *iterm = NULL;
+		u32 index = input->index;
+		int pin = 0;
+
+		if (selector == NULL ||
+		    (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+			if (index != 0)
+				return -EINVAL;
+			iterm = list_first_entry(&video->iterms,
+					struct uvc_entity, chain);
+			pin = iterm->id;
+		} else if (pin < selector->selector.bNrInPins) {
+			pin = selector->selector.baSourceID[index];
+			list_for_each_entry(iterm, video->iterms.next, chain) {
+				if (iterm->id == pin)
+					break;
+			}
+		}
+
+		if (iterm == NULL || iterm->id != pin)
+			return -EINVAL;
+
+		memset(input, 0, sizeof *input);
+		input->index = index;
+		strncpy(input->name, iterm->name, sizeof input->name);
+		if (UVC_ENTITY_TYPE(iterm) == ITT_CAMERA)
+			input->type = V4L2_INPUT_TYPE_CAMERA;
+		break;
+	}
+
+	case VIDIOC_G_INPUT:
+	{
+		u8 input;
+
+		if (video->selector == NULL ||
+		    (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+			*(int *)arg = 0;
+			break;
+		}
+
+		ret = uvc_query_ctrl(video->dev, GET_CUR, video->selector->id,
+			video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+			&input, 1);
+		if (ret < 0)
+			return ret;
+
+		*(int *)arg = input - 1;
+		break;
+	}
+
+	case VIDIOC_S_INPUT:
+	{
+		u8 input = *(u32 *)arg + 1;
+
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		if (video->selector == NULL ||
+		    (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+			if (input != 1)
+				return -EINVAL;
+			break;
+		}
+
+		if (input > video->selector->selector.bNrInPins)
+			return -EINVAL;
+
+		return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
+			video->dev->intfnum, SU_INPUT_SELECT_CONTROL,
+			&input, 1);
+	}
+
+	/* Try, Get, Set & Enum format */
+	case VIDIOC_ENUM_FMT:
+	{
+		struct v4l2_fmtdesc *fmt = arg;
+		struct uvc_format *format;
+
+		if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		    fmt->index >= video->streaming->nformats)
+			return -EINVAL;
+
+		format = &video->streaming->format[fmt->index];
+		fmt->flags = 0;
+		if (format->flags & UVC_FMT_FLAG_COMPRESSED)
+			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+		strncpy(fmt->description, format->name,
+			sizeof fmt->description);
+		fmt->description[sizeof fmt->description - 1] = 0;
+		fmt->pixelformat = format->fcc;
+		break;
+	}
+
+	case VIDIOC_TRY_FMT:
+	{
+		struct uvc_streaming_control probe;
+
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+	}
+
+	case VIDIOC_S_FMT:
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		return uvc_v4l2_set_format(video, arg);
+
+	case VIDIOC_G_FMT:
+		return uvc_v4l2_get_format(video, arg);
+
+	/* Frame size enumeration */
+	case VIDIOC_ENUM_FRAMESIZES:
+	{
+		struct v4l2_frmsizeenum *fsize = arg;
+		struct uvc_format *format = NULL;
+		struct uvc_frame *frame;
+		int i;
+
+		/* Look for the given pixel format */
+		for (i = 0; i < video->streaming->nformats; i++) {
+			if (video->streaming->format[i].fcc ==
+					fsize->pixel_format) {
+				format = &video->streaming->format[i];
+				break;
+			}
+		}
+		if (format == NULL)
+			return -EINVAL;
+
+		if (fsize->index >= format->nframes)
+			return -EINVAL;
+
+		frame = &format->frame[fsize->index];
+		fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+		fsize->discrete.width = frame->wWidth;
+		fsize->discrete.height = frame->wHeight;
+		break;
+	}
+
+	/* Frame interval enumeration */
+	case VIDIOC_ENUM_FRAMEINTERVALS:
+	{
+		struct v4l2_frmivalenum *fival = arg;
+		struct uvc_format *format = NULL;
+		struct uvc_frame *frame = NULL;
+		int i;
+
+		/* Look for the given pixel format and frame size */
+		for (i = 0; i < video->streaming->nformats; i++) {
+			if (video->streaming->format[i].fcc ==
+					fival->pixel_format) {
+				format = &video->streaming->format[i];
+				break;
+			}
+		}
+		if (format == NULL)
+			return -EINVAL;
+
+		for (i = 0; i < format->nframes; i++) {
+			if (format->frame[i].wWidth == fival->width &&
+			    format->frame[i].wHeight == fival->height) {
+				frame = &format->frame[i];
+				break;
+			}
+		}
+		if (frame == NULL)
+			return -EINVAL;
+
+		if (frame->bFrameIntervalType) {
+			if (fival->index >= frame->bFrameIntervalType)
+				return -EINVAL;
+
+			fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+			fival->discrete.numerator =
+				frame->dwFrameInterval[fival->index];
+			fival->discrete.denominator = 10000000;
+			uvc_simplify_fraction(&fival->discrete.numerator,
+				&fival->discrete.denominator, 8, 333);
+		} else {
+			fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+			fival->stepwise.min.numerator =
+				frame->dwFrameInterval[0];
+			fival->stepwise.min.denominator = 10000000;
+			fival->stepwise.max.numerator =
+				frame->dwFrameInterval[1];
+			fival->stepwise.max.denominator = 10000000;
+			fival->stepwise.step.numerator =
+				frame->dwFrameInterval[2];
+			fival->stepwise.step.denominator = 10000000;
+			uvc_simplify_fraction(&fival->stepwise.min.numerator,
+				&fival->stepwise.min.denominator, 8, 333);
+			uvc_simplify_fraction(&fival->stepwise.max.numerator,
+				&fival->stepwise.max.denominator, 8, 333);
+			uvc_simplify_fraction(&fival->stepwise.step.numerator,
+				&fival->stepwise.step.denominator, 8, 333);
+		}
+		break;
+	}
+
+	/* Get & Set streaming parameters */
+	case VIDIOC_G_PARM:
+		return uvc_v4l2_get_streamparm(video, arg);
+
+	case VIDIOC_S_PARM:
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		return uvc_v4l2_set_streamparm(video, arg);
+
+	/* Cropping and scaling */
+	case VIDIOC_CROPCAP:
+	{
+		struct v4l2_cropcap *ccap = arg;
+		struct uvc_frame *frame = video->streaming->cur_frame;
+
+		if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		ccap->bounds.left = 0;
+		ccap->bounds.top = 0;
+		ccap->bounds.width = frame->wWidth;
+		ccap->bounds.height = frame->wHeight;
+
+		ccap->defrect = ccap->bounds;
+
+		ccap->pixelaspect.numerator = 1;
+		ccap->pixelaspect.denominator = 1;
+		break;
+	}
+
+	case VIDIOC_G_CROP:
+	case VIDIOC_S_CROP:
+		return -EINVAL;
+
+	/* Buffers & streaming */
+	case VIDIOC_REQBUFS:
+	{
+		struct v4l2_requestbuffers *rb = arg;
+		unsigned int bufsize =
+			video->streaming->ctrl.dwMaxVideoFrameSize;
+
+		if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		    rb->memory != V4L2_MEMORY_MMAP)
+			return -EINVAL;
+
+		if ((ret = uvc_acquire_privileges(handle)) < 0)
+			return ret;
+
+		ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+		if (ret < 0)
+			return ret;
+
+		if (!(video->streaming->cur_format->flags &
+		    UVC_FMT_FLAG_COMPRESSED))
+			video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
+
+		rb->count = ret;
+		ret = 0;
+		break;
+	}
+
+	case VIDIOC_QUERYBUF:
+	{
+		struct v4l2_buffer *buf = arg;
+
+		if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_query_buffer(&video->queue, buf);
+	}
+
+	case VIDIOC_QBUF:
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_queue_buffer(&video->queue, arg);
+
+	case VIDIOC_DQBUF:
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_dequeue_buffer(&video->queue, arg,
+			file->f_flags & O_NONBLOCK);
+
+	case VIDIOC_STREAMON:
+	{
+		int *type = arg;
+
+		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		if ((ret = uvc_video_enable(video, 1)) < 0)
+			return ret;
+		break;
+	}
+
+	case VIDIOC_STREAMOFF:
+	{
+		int *type = arg;
+
+		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+			return -EINVAL;
+
+		if (!uvc_has_privileges(handle))
+			return -EBUSY;
+
+		return uvc_video_enable(video, 0);
+	}
+
+	/* Analog video standards make no sense for digital cameras. */
+	case VIDIOC_ENUMSTD:
+	case VIDIOC_QUERYSTD:
+	case VIDIOC_G_STD:
+	case VIDIOC_S_STD:
+
+	case VIDIOC_OVERLAY:
+
+	case VIDIOC_ENUMAUDIO:
+	case VIDIOC_ENUMAUDOUT:
+
+	case VIDIOC_ENUMOUTPUT:
+		uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
+		return -EINVAL;
+
+	/* Dynamic controls. */
+	case UVCIOC_CTRL_ADD:
+	{
+		struct uvc_xu_control_info *xinfo = arg;
+		struct uvc_control_info *info;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		info = kmalloc(sizeof *info, GFP_KERNEL);
+		if (info == NULL)
+			return -ENOMEM;
+
+		memcpy(info->entity, xinfo->entity, sizeof info->entity);
+		info->index = xinfo->index;
+		info->selector = xinfo->selector;
+		info->size = xinfo->size;
+		info->flags = xinfo->flags;
+
+		info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+				UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
+
+		ret = uvc_ctrl_add_info(info);
+		if (ret < 0)
+			kfree(info);
+		break;
+	}
+
+	case UVCIOC_CTRL_MAP:
+	{
+		struct uvc_xu_control_mapping *xmap = arg;
+		struct uvc_control_mapping *map;
+
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
+		map = kmalloc(sizeof *map, GFP_KERNEL);
+		if (map == NULL)
+			return -ENOMEM;
+
+		map->id = xmap->id;
+		memcpy(map->name, xmap->name, sizeof map->name);
+		memcpy(map->entity, xmap->entity, sizeof map->entity);
+		map->selector = xmap->selector;
+		map->size = xmap->size;
+		map->offset = xmap->offset;
+		map->v4l2_type = xmap->v4l2_type;
+		map->data_type = xmap->data_type;
+
+		ret = uvc_ctrl_add_mapping(map);
+		if (ret < 0)
+			kfree(map);
+		break;
+	}
+
+	case UVCIOC_CTRL_GET:
+		return uvc_xu_ctrl_query(video, arg, 0);
+
+	case UVCIOC_CTRL_SET:
+		return uvc_xu_ctrl_query(video, arg, 1);
+
+	default:
+		if ((ret = v4l_compat_translate_ioctl(inode, file, cmd, arg,
+			uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+			uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
+				  cmd);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
+	return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl);
+}
+
+static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
+		    size_t count, loff_t *ppos)
+{
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
+	return -ENODEV;
+}
+
+/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+	struct uvc_buffer *buffer = vma->vm_private_data;
+	buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+	struct uvc_buffer *buffer = vma->vm_private_data;
+	buffer->vma_use_count--;
+}
+
+static struct vm_operations_struct uvc_vm_ops = {
+	.open		= uvc_vm_open,
+	.close		= uvc_vm_close,
+};
+
+static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+	struct uvc_buffer *buffer;
+	struct page *page;
+	unsigned long addr, start, size;
+	unsigned int i;
+	int ret = 0;
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
+
+	start = vma->vm_start;
+	size = vma->vm_end - vma->vm_start;
+
+	mutex_lock(&video->queue.mutex);
+
+	for (i = 0; i < video->queue.count; ++i) {
+		buffer = &video->queue.buffer[i];
+		if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+			break;
+	}
+
+	if (i == video->queue.count || size != video->queue.buf_size) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/*
+	 * VM_IO marks the area as being an mmaped region for I/O to a
+	 * device. It also prevents the region from being core dumped.
+	 */
+	vma->vm_flags |= VM_IO;
+
+	addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+	while (size > 0) {
+		page = vmalloc_to_page((void *)addr);
+		if ((ret = vm_insert_page(vma, start, page)) < 0)
+			goto done;
+
+		start += PAGE_SIZE;
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	vma->vm_ops = &uvc_vm_ops;
+	vma->vm_private_data = buffer;
+	uvc_vm_open(vma);
+
+done:
+	mutex_unlock(&video->queue.mutex);
+	return ret;
+}
+
+static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
+{
+	struct video_device *vdev = video_devdata(file);
+	struct uvc_video_device *video = video_get_drvdata(vdev);
+
+	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
+
+	return uvc_queue_poll(&video->queue, file, wait);
+}
+
+struct file_operations uvc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uvc_v4l2_open,
+	.release	= uvc_v4l2_release,
+	.ioctl		= uvc_v4l2_ioctl,
+	.compat_ioctl	= v4l_compat_ioctl32,
+	.llseek		= no_llseek,
+	.read		= uvc_v4l2_read,
+	.mmap		= uvc_v4l2_mmap,
+	.poll		= uvc_v4l2_poll,
+};
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
new file mode 100644
index 000000000000..6faf1fb21614
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -0,0 +1,934 @@
+/*
+ *      uvc_video.c  --  USB Video Class driver - Video handling
+ *
+ *      Copyright (C) 2005-2008
+ *          Laurent Pinchart (laurent.pinchart@skynet.be)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <asm/atomic.h>
+#include <asm/unaligned.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * UVC Controls
+ */
+
+static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+			__u8 intfnum, __u8 cs, void *data, __u16 size,
+			int timeout)
+{
+	__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	unsigned int pipe;
+	int ret;
+
+	pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
+			      : usb_sndctrlpipe(dev->udev, 0);
+	type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
+
+	ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+			unit << 8 | intfnum, data, size, timeout);
+
+	if (ret != size) {
+		uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
+			"(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
+			size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+			__u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+	return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+				UVC_CTRL_CONTROL_TIMEOUT);
+}
+
+static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+	struct uvc_streaming_control *ctrl)
+{
+	struct uvc_format *format;
+	struct uvc_frame *frame;
+
+	if (ctrl->bFormatIndex <= 0 ||
+	    ctrl->bFormatIndex > video->streaming->nformats)
+		return;
+
+	format = &video->streaming->format[ctrl->bFormatIndex - 1];
+
+	if (ctrl->bFrameIndex <= 0 ||
+	    ctrl->bFrameIndex > format->nframes)
+		return;
+
+	frame = &format->frame[ctrl->bFrameIndex - 1];
+
+	if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+	     (ctrl->dwMaxVideoFrameSize == 0 &&
+	      video->dev->uvc_version < 0x0110))
+		ctrl->dwMaxVideoFrameSize =
+			frame->dwMaxVideoFrameBufferSize;
+}
+
+static int uvc_get_video_ctrl(struct uvc_video_device *video,
+	struct uvc_streaming_control *ctrl, int probe, __u8 query)
+{
+	__u8 data[34];
+	__u8 size;
+	int ret;
+
+	size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+	ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
+		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+		UVC_CTRL_STREAMING_TIMEOUT);
+
+	if (ret < 0)
+		return ret;
+
+	ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
+	ctrl->bFormatIndex = data[2];
+	ctrl->bFrameIndex = data[3];
+	ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
+	ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
+	ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
+	ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
+	ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
+	ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
+	ctrl->dwMaxVideoFrameSize =
+		le32_to_cpu(get_unaligned((__le32 *)&data[18]));
+	ctrl->dwMaxPayloadTransferSize =
+		le32_to_cpu(get_unaligned((__le32 *)&data[22]));
+
+	if (size == 34) {
+		ctrl->dwClockFrequency =
+			le32_to_cpu(get_unaligned((__le32 *)&data[26]));
+		ctrl->bmFramingInfo = data[30];
+		ctrl->bPreferedVersion = data[31];
+		ctrl->bMinVersion = data[32];
+		ctrl->bMaxVersion = data[33];
+	} else {
+		ctrl->dwClockFrequency = video->dev->clock_frequency;
+		ctrl->bmFramingInfo = 0;
+		ctrl->bPreferedVersion = 0;
+		ctrl->bMinVersion = 0;
+		ctrl->bMaxVersion = 0;
+	}
+
+	/* Some broken devices return a null or wrong dwMaxVideoFrameSize.
+	 * Try to get the value from the format and frame descriptor.
+	 */
+	uvc_fixup_buffer_size(video, ctrl);
+
+	return 0;
+}
+
+int uvc_set_video_ctrl(struct uvc_video_device *video,
+	struct uvc_streaming_control *ctrl, int probe)
+{
+	__u8 data[34];
+	__u8 size;
+
+	size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
+	memset(data, 0, sizeof data);
+
+	*(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
+	data[2] = ctrl->bFormatIndex;
+	data[3] = ctrl->bFrameIndex;
+	*(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
+	*(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
+	*(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
+	*(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
+	*(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
+	*(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
+	/* Note: Some of the fields below are not required for IN devices (see
+	 * UVC spec, 4.3.1.1), but we still copy them in case support for OUT
+	 * devices is added in the future. */
+	put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize),
+		(__le32 *)&data[18]);
+	put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize),
+		(__le32 *)&data[22]);
+
+	if (size == 34) {
+		put_unaligned(cpu_to_le32(ctrl->dwClockFrequency),
+			(__le32 *)&data[26]);
+		data[30] = ctrl->bmFramingInfo;
+		data[31] = ctrl->bPreferedVersion;
+		data[32] = ctrl->bMinVersion;
+		data[33] = ctrl->bMaxVersion;
+	}
+
+	return __uvc_query_ctrl(video->dev, SET_CUR, 0,
+		video->streaming->intfnum,
+		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size,
+		UVC_CTRL_STREAMING_TIMEOUT);
+}
+
+int uvc_probe_video(struct uvc_video_device *video,
+	struct uvc_streaming_control *probe)
+{
+	struct uvc_streaming_control probe_min, probe_max;
+	__u16 bandwidth;
+	unsigned int i;
+	int ret;
+
+	mutex_lock(&video->streaming->mutex);
+
+	/* Perform probing. The device should adjust the requested values
+	 * according to its capabilities. However, some devices, namely the
+	 * first generation UVC Logitech webcams, don't implement the Video
+	 * Probe control properly, and just return the needed bandwidth. For
+	 * that reason, if the needed bandwidth exceeds the maximum available
+	 * bandwidth, try to lower the quality.
+	 */
+	if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0)
+		goto done;
+
+	/* Get the minimum and maximum values for compression settings. */
+	if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
+		ret = uvc_get_video_ctrl(video, &probe_min, 1, GET_MIN);
+		if (ret < 0)
+			goto done;
+		ret = uvc_get_video_ctrl(video, &probe_max, 1, GET_MAX);
+		if (ret < 0)
+			goto done;
+
+		probe->wCompQuality = probe_max.wCompQuality;
+	}
+
+	for (i = 0; i < 2; ++i) {
+		if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0 ||
+		    (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+			goto done;
+
+		if (video->streaming->intf->num_altsetting == 1)
+			break;
+
+		bandwidth = probe->dwMaxPayloadTransferSize;
+		if (bandwidth <= video->streaming->maxpsize)
+			break;
+
+		if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
+			ret = -ENOSPC;
+			goto done;
+		}
+
+		/* TODO: negotiate compression parameters */
+		probe->wKeyFrameRate = probe_min.wKeyFrameRate;
+		probe->wPFrameRate = probe_min.wPFrameRate;
+		probe->wCompQuality = probe_max.wCompQuality;
+		probe->wCompWindowSize = probe_min.wCompWindowSize;
+	}
+
+done:
+	mutex_unlock(&video->streaming->mutex);
+	return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video codecs
+ */
+
+/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
+#define UVC_STREAM_EOH	(1 << 7)
+#define UVC_STREAM_ERR	(1 << 6)
+#define UVC_STREAM_STI	(1 << 5)
+#define UVC_STREAM_RES	(1 << 4)
+#define UVC_STREAM_SCR	(1 << 3)
+#define UVC_STREAM_PTS	(1 << 2)
+#define UVC_STREAM_EOF	(1 << 1)
+#define UVC_STREAM_FID	(1 << 0)
+
+/* Video payload decoding is handled by uvc_video_decode_start(),
+ * uvc_video_decode_data() and uvc_video_decode_end().
+ *
+ * uvc_video_decode_start is called with URB data at the start of a bulk or
+ * isochronous payload. It processes header data and returns the header size
+ * in bytes if successful. If an error occurs, it returns a negative error
+ * code. The following error codes have special meanings.
+ *
+ * - EAGAIN informs the caller that the current video buffer should be marked
+ *   as done, and that the function should be called again with the same data
+ *   and a new video buffer. This is used when end of frame conditions can be
+ *   reliably detected at the beginning of the next frame only.
+ *
+ * If an error other than -EAGAIN is returned, the caller will drop the current
+ * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
+ * made until the next payload. -ENODATA can be used to drop the current
+ * payload if no other error code is appropriate.
+ *
+ * uvc_video_decode_data is called for every URB with URB data. It copies the
+ * data to the video buffer.
+ *
+ * uvc_video_decode_end is called with header data at the end of a bulk or
+ * isochronous payload. It performs any additional header data processing and
+ * returns 0 or a negative error code if an error occured. As header data have
+ * already been processed by uvc_video_decode_start, this functions isn't
+ * required to perform sanity checks a second time.
+ *
+ * For isochronous transfers where a payload is always transfered in a single
+ * URB, the three functions will be called in a row.
+ *
+ * To let the decoder process header data and update its internal state even
+ * when no video buffer is available, uvc_video_decode_start must be prepared
+ * to be called with a NULL buf parameter. uvc_video_decode_data and
+ * uvc_video_decode_end will never be called with a NULL buffer.
+ */
+static int uvc_video_decode_start(struct uvc_video_device *video,
+		struct uvc_buffer *buf, const __u8 *data, int len)
+{
+	__u8 fid;
+
+	/* Sanity checks:
+	 * - packet must be at least 2 bytes long
+	 * - bHeaderLength value must be at least 2 bytes (see above)
+	 * - bHeaderLength value can't be larger than the packet size.
+	 */
+	if (len < 2 || data[0] < 2 || data[0] > len)
+		return -EINVAL;
+
+	/* Skip payloads marked with the error bit ("error frames"). */
+	if (data[1] & UVC_STREAM_ERR) {
+		uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
+			  "set).\n");
+		return -ENODATA;
+	}
+
+	fid = data[1] & UVC_STREAM_FID;
+
+	/* Store the payload FID bit and return immediately when the buffer is
+	 * NULL.
+	 */
+	if (buf == NULL) {
+		video->last_fid = fid;
+		return -ENODATA;
+	}
+
+	/* Synchronize to the input stream by waiting for the FID bit to be
+	 * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
+	 * queue->last_fid is initialized to -1, so the first isochronous
+	 * frame will always be in sync.
+	 *
+	 * If the device doesn't toggle the FID bit, invert video->last_fid
+	 * when the EOF bit is set to force synchronisation on the next packet.
+	 */
+	if (buf->state != UVC_BUF_STATE_ACTIVE) {
+		if (fid == video->last_fid) {
+			uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
+				"sync).\n");
+			if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
+			    (data[1] & UVC_STREAM_EOF))
+				video->last_fid ^= UVC_STREAM_FID;
+			return -ENODATA;
+		}
+
+		/* TODO: Handle PTS and SCR. */
+		buf->state = UVC_BUF_STATE_ACTIVE;
+	}
+
+	/* Mark the buffer as done if we're at the beginning of a new frame.
+	 * End of frame detection is better implemented by checking the EOF
+	 * bit (FID bit toggling is delayed by one frame compared to the EOF
+	 * bit), but some devices don't set the bit at end of frame (and the
+	 * last payload can be lost anyway). We thus must check if the FID has
+	 * been toggled.
+	 *
+	 * queue->last_fid is initialized to -1, so the first isochronous
+	 * frame will never trigger an end of frame detection.
+	 *
+	 * Empty buffers (bytesused == 0) don't trigger end of frame detection
+	 * as it doesn't make sense to return an empty buffer. This also
+	 * avoids detecting and of frame conditions at FID toggling if the
+	 * previous payload had the EOF bit set.
+	 */
+	if (fid != video->last_fid && buf->buf.bytesused != 0) {
+		uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
+				"toggled).\n");
+		buf->state = UVC_BUF_STATE_DONE;
+		return -EAGAIN;
+	}
+
+	video->last_fid = fid;
+
+	return data[0];
+}
+
+static void uvc_video_decode_data(struct uvc_video_device *video,
+		struct uvc_buffer *buf, const __u8 *data, int len)
+{
+	struct uvc_video_queue *queue = &video->queue;
+	unsigned int maxlen, nbytes;
+	void *mem;
+
+	if (len <= 0)
+		return;
+
+	/* Copy the video data to the buffer. */
+	maxlen = buf->buf.length - buf->buf.bytesused;
+	mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+	nbytes = min((unsigned int)len, maxlen);
+	memcpy(mem, data, nbytes);
+	buf->buf.bytesused += nbytes;
+
+	/* Complete the current frame if the buffer size was exceeded. */
+	if (len > maxlen) {
+		uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
+		buf->state = UVC_BUF_STATE_DONE;
+	}
+}
+
+static void uvc_video_decode_end(struct uvc_video_device *video,
+		struct uvc_buffer *buf, const __u8 *data, int len)
+{
+	/* Mark the buffer as done if the EOF marker is set. */
+	if (data[1] & UVC_STREAM_EOF && buf->buf.bytesused != 0) {
+		uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
+		if (data[0] == len)
+			uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
+		buf->state = UVC_BUF_STATE_DONE;
+		if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
+			video->last_fid ^= UVC_STREAM_FID;
+	}
+}
+
+/* ------------------------------------------------------------------------
+ * URB handling
+ */
+
+/*
+ * Completion handler for video URBs.
+ */
+static void uvc_video_decode_isoc(struct urb *urb,
+	struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+	u8 *mem;
+	int ret, i;
+
+	for (i = 0; i < urb->number_of_packets; ++i) {
+		if (urb->iso_frame_desc[i].status < 0) {
+			uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
+				"lost (%d).\n", urb->iso_frame_desc[i].status);
+			continue;
+		}
+
+		/* Decode the payload header. */
+		mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+		do {
+			ret = uvc_video_decode_start(video, buf, mem,
+				urb->iso_frame_desc[i].actual_length);
+			if (ret == -EAGAIN)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		} while (ret == -EAGAIN);
+
+		if (ret < 0)
+			continue;
+
+		/* Decode the payload data. */
+		uvc_video_decode_data(video, buf, mem + ret,
+			urb->iso_frame_desc[i].actual_length - ret);
+
+		/* Process the header again. */
+		uvc_video_decode_end(video, buf, mem, ret);
+
+		if (buf->state == UVC_BUF_STATE_DONE ||
+		    buf->state == UVC_BUF_STATE_ERROR)
+			buf = uvc_queue_next_buffer(&video->queue, buf);
+	}
+}
+
+static void uvc_video_decode_bulk(struct urb *urb,
+	struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+	u8 *mem;
+	int len, ret;
+
+	mem = urb->transfer_buffer;
+	len = urb->actual_length;
+	video->bulk.payload_size += len;
+
+	/* If the URB is the first of its payload, decode and save the
+	 * header.
+	 */
+	if (video->bulk.header_size == 0) {
+		do {
+			ret = uvc_video_decode_start(video, buf, mem, len);
+			if (ret == -EAGAIN)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		} while (ret == -EAGAIN);
+
+		/* If an error occured skip the rest of the payload. */
+		if (ret < 0 || buf == NULL) {
+			video->bulk.skip_payload = 1;
+			return;
+		}
+
+		video->bulk.header_size = ret;
+		memcpy(video->bulk.header, mem, video->bulk.header_size);
+
+		mem += ret;
+		len -= ret;
+	}
+
+	/* The buffer queue might have been cancelled while a bulk transfer
+	 * was in progress, so we can reach here with buf equal to NULL. Make
+	 * sure buf is never dereferenced if NULL.
+	 */
+
+	/* Process video data. */
+	if (!video->bulk.skip_payload && buf != NULL)
+		uvc_video_decode_data(video, buf, mem, len);
+
+	/* Detect the payload end by a URB smaller than the maximum size (or
+	 * a payload size equal to the maximum) and process the header again.
+	 */
+	if (urb->actual_length < urb->transfer_buffer_length ||
+	    video->bulk.payload_size >= video->bulk.max_payload_size) {
+		if (!video->bulk.skip_payload && buf != NULL) {
+			uvc_video_decode_end(video, buf, video->bulk.header,
+				video->bulk.header_size);
+			if (buf->state == UVC_BUF_STATE_DONE ||
+			    buf->state == UVC_BUF_STATE_ERROR)
+				buf = uvc_queue_next_buffer(&video->queue, buf);
+		}
+
+		video->bulk.header_size = 0;
+		video->bulk.skip_payload = 0;
+		video->bulk.payload_size = 0;
+	}
+}
+
+static void uvc_video_complete(struct urb *urb)
+{
+	struct uvc_video_device *video = urb->context;
+	struct uvc_video_queue *queue = &video->queue;
+	struct uvc_buffer *buf = NULL;
+	unsigned long flags;
+	int ret;
+
+	switch (urb->status) {
+	case 0:
+		break;
+
+	default:
+		uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
+			"completion handler.\n", urb->status);
+
+	case -ENOENT:		/* usb_kill_urb() called. */
+		if (video->frozen)
+			return;
+
+	case -ECONNRESET:	/* usb_unlink_urb() called. */
+	case -ESHUTDOWN:	/* The endpoint is being disabled. */
+		uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
+		return;
+	}
+
+	spin_lock_irqsave(&queue->irqlock, flags);
+	if (!list_empty(&queue->irqqueue))
+		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
+				       queue);
+	spin_unlock_irqrestore(&queue->irqlock, flags);
+
+	video->decode(urb, video, buf);
+
+	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+		uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
+			ret);
+	}
+}
+
+/*
+ * Uninitialize isochronous/bulk URBs and free transfer buffers.
+ */
+static void uvc_uninit_video(struct uvc_video_device *video)
+{
+	struct urb *urb;
+	unsigned int i;
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		if ((urb = video->urb[i]) == NULL)
+			continue;
+
+		usb_kill_urb(urb);
+		/* urb->transfer_buffer_length is not touched by USB core, so
+		 * we can use it here as the buffer length.
+		 */
+		if (video->urb_buffer[i]) {
+			usb_buffer_free(video->dev->udev,
+				urb->transfer_buffer_length,
+				video->urb_buffer[i], urb->transfer_dma);
+			video->urb_buffer[i] = NULL;
+		}
+
+		usb_free_urb(urb);
+		video->urb[i] = NULL;
+	}
+}
+
+/*
+ * Initialize isochronous URBs and allocate transfer buffers. The packet size
+ * is given by the endpoint.
+ */
+static int uvc_init_video_isoc(struct uvc_video_device *video,
+	struct usb_host_endpoint *ep)
+{
+	struct urb *urb;
+	unsigned int npackets, i, j;
+	__u16 psize;
+	__u32 size;
+
+	/* Compute the number of isochronous packets to allocate by dividing
+	 * the maximum video frame size by the packet size. Limit the result
+	 * to UVC_MAX_ISO_PACKETS.
+	 */
+	psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+	psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+
+	size = video->streaming->ctrl.dwMaxVideoFrameSize;
+	if (size > UVC_MAX_FRAME_SIZE)
+		return -EINVAL;
+
+	npackets = (size + psize - 1) / psize;
+	if (npackets > UVC_MAX_ISO_PACKETS)
+		npackets = UVC_MAX_ISO_PACKETS;
+
+	size = npackets * psize;
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		urb = usb_alloc_urb(npackets, GFP_KERNEL);
+		if (urb == NULL) {
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+			size, GFP_KERNEL, &urb->transfer_dma);
+		if (video->urb_buffer[i] == NULL) {
+			usb_free_urb(urb);
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		urb->dev = video->dev->udev;
+		urb->context = video;
+		urb->pipe = usb_rcvisocpipe(video->dev->udev,
+				ep->desc.bEndpointAddress);
+		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->interval = ep->desc.bInterval;
+		urb->transfer_buffer = video->urb_buffer[i];
+		urb->complete = uvc_video_complete;
+		urb->number_of_packets = npackets;
+		urb->transfer_buffer_length = size;
+
+		for (j = 0; j < npackets; ++j) {
+			urb->iso_frame_desc[j].offset = j * psize;
+			urb->iso_frame_desc[j].length = psize;
+		}
+
+		video->urb[i] = urb;
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize bulk URBs and allocate transfer buffers. The packet size is
+ * given by the endpoint.
+ */
+static int uvc_init_video_bulk(struct uvc_video_device *video,
+	struct usb_host_endpoint *ep)
+{
+	struct urb *urb;
+	unsigned int pipe, i;
+	__u16 psize;
+	__u32 size;
+
+	/* Compute the bulk URB size. Some devices set the maximum payload
+	 * size to a value too high for memory-constrained devices. We must
+	 * then transfer the payload accross multiple URBs. To be consistant
+	 * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
+	 * URB.
+	 */
+	psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
+	size = video->streaming->ctrl.dwMaxPayloadTransferSize;
+	video->bulk.max_payload_size = size;
+	if (size > psize * UVC_MAX_ISO_PACKETS)
+		size = psize * UVC_MAX_ISO_PACKETS;
+
+	pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+
+	for (i = 0; i < UVC_URBS; ++i) {
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (urb == NULL) {
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
+			size, GFP_KERNEL, &urb->transfer_dma);
+		if (video->urb_buffer[i] == NULL) {
+			usb_free_urb(urb);
+			uvc_uninit_video(video);
+			return -ENOMEM;
+		}
+
+		usb_fill_bulk_urb(urb, video->dev->udev, pipe,
+			video->urb_buffer[i], size, uvc_video_complete,
+			video);
+		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+
+		video->urb[i] = urb;
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize isochronous/bulk URBs and allocate transfer buffers.
+ */
+static int uvc_init_video(struct uvc_video_device *video)
+{
+	struct usb_interface *intf = video->streaming->intf;
+	struct usb_host_interface *alts;
+	struct usb_host_endpoint *ep = NULL;
+	int intfnum = video->streaming->intfnum;
+	unsigned int bandwidth, psize, i;
+	int ret;
+
+	video->last_fid = -1;
+	video->bulk.header_size = 0;
+	video->bulk.skip_payload = 0;
+	video->bulk.payload_size = 0;
+
+	if (intf->num_altsetting > 1) {
+		/* Isochronous endpoint, select the alternate setting. */
+		bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize;
+
+		if (bandwidth == 0) {
+			uvc_printk(KERN_WARNING, "device %s requested null "
+				"bandwidth, defaulting to lowest.\n",
+				video->vdev->name);
+			bandwidth = 1;
+		}
+
+		for (i = 0; i < intf->num_altsetting; ++i) {
+			alts = &intf->altsetting[i];
+			ep = uvc_find_endpoint(alts,
+				video->streaming->header.bEndpointAddress);
+			if (ep == NULL)
+				continue;
+
+			/* Check if the bandwidth is high enough. */
+			psize = le16_to_cpu(ep->desc.wMaxPacketSize);
+			psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+			if (psize >= bandwidth)
+				break;
+		}
+
+		if (i >= intf->num_altsetting)
+			return -EIO;
+
+		if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0)
+			return ret;
+
+		ret = uvc_init_video_isoc(video, ep);
+	} else {
+		/* Bulk endpoint, proceed to URB initialization. */
+		ep = uvc_find_endpoint(&intf->altsetting[0],
+				video->streaming->header.bEndpointAddress);
+		if (ep == NULL)
+			return -EIO;
+
+		ret = uvc_init_video_bulk(video, ep);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	/* Submit the URBs. */
+	for (i = 0; i < UVC_URBS; ++i) {
+		if ((ret = usb_submit_urb(video->urb[i], GFP_KERNEL)) < 0) {
+			uvc_printk(KERN_ERR, "Failed to submit URB %u "
+					"(%d).\n", i, ret);
+			uvc_uninit_video(video);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+/*
+ * Stop streaming without disabling the video queue.
+ *
+ * To let userspace applications resume without trouble, we must not touch the
+ * video buffers in any way. We mark the device as frozen to make sure the URB
+ * completion handler won't try to cancel the queue when we kill the URBs.
+ */
+int uvc_video_suspend(struct uvc_video_device *video)
+{
+	if (!uvc_queue_streaming(&video->queue))
+		return 0;
+
+	video->frozen = 1;
+	uvc_uninit_video(video);
+	usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+	return 0;
+}
+
+/*
+ * Reconfigure the video interface and restart streaming if it was enable
+ * before suspend.
+ *
+ * If an error occurs, disable the video queue. This will wake all pending
+ * buffers, making sure userspace applications are notified of the problem
+ * instead of waiting forever.
+ */
+int uvc_video_resume(struct uvc_video_device *video)
+{
+	int ret;
+
+	video->frozen = 0;
+
+	if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) {
+		uvc_queue_enable(&video->queue, 0);
+		return ret;
+	}
+
+	if (!uvc_queue_streaming(&video->queue))
+		return 0;
+
+	if ((ret = uvc_init_video(video)) < 0)
+		uvc_queue_enable(&video->queue, 0);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Video device
+ */
+
+/*
+ * Initialize the UVC video device by retrieving the default format and
+ * committing it.
+ *
+ * Some cameras (namely the Fuji Finepix) set the format and frame
+ * indexes to zero. The UVC standard doesn't clearly make this a spec
+ * violation, so try to silently fix the values if possible.
+ *
+ * This function is called before registering the device with V4L.
+ */
+int uvc_video_init(struct uvc_video_device *video)
+{
+	struct uvc_streaming_control *probe = &video->streaming->ctrl;
+	struct uvc_format *format = NULL;
+	struct uvc_frame *frame = NULL;
+	unsigned int i;
+	int ret;
+
+	if (video->streaming->nformats == 0) {
+		uvc_printk(KERN_INFO, "No supported video formats found.\n");
+		return -EINVAL;
+	}
+
+	/* Alternate setting 0 should be the default, yet the XBox Live Vision
+	 * Cam (and possibly other devices) crash or otherwise misbehave if
+	 * they don't receive a SET_INTERFACE request before any other video
+	 * control request.
+	 */
+	usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
+
+	/* Some webcams don't suport GET_DEF request on the probe control. We
+	 * fall back to GET_CUR if GET_DEF fails.
+	 */
+	if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
+	    (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+		return ret;
+
+	/* Check if the default format descriptor exists. Use the first
+	 * available format otherwise.
+	 */
+	for (i = video->streaming->nformats; i > 0; --i) {
+		format = &video->streaming->format[i-1];
+		if (format->index == probe->bFormatIndex)
+			break;
+	}
+
+	if (format->nframes == 0) {
+		uvc_printk(KERN_INFO, "No frame descriptor found for the "
+			"default format.\n");
+		return -EINVAL;
+	}
+
+	/* Zero bFrameIndex might be correct. Stream-based formats (including
+	 * MPEG-2 TS and DV) do not support frames but have a dummy frame
+	 * descriptor with bFrameIndex set to zero. If the default frame
+	 * descriptor is not found, use the first avalable frame.
+	 */
+	for (i = format->nframes; i > 0; --i) {
+		frame = &format->frame[i-1];
+		if (frame->bFrameIndex == probe->bFrameIndex)
+			break;
+	}
+
+	/* Commit the default settings. */
+	probe->bFormatIndex = format->index;
+	probe->bFrameIndex = frame->bFrameIndex;
+	if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
+		return ret;
+
+	video->streaming->cur_format = format;
+	video->streaming->cur_frame = frame;
+	atomic_set(&video->active, 0);
+
+	/* Select the video decoding function */
+	if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+		video->decode = uvc_video_decode_isight;
+	else if (video->streaming->intf->num_altsetting > 1)
+		video->decode = uvc_video_decode_isoc;
+	else
+		video->decode = uvc_video_decode_bulk;
+
+	return 0;
+}
+
+/*
+ * Enable or disable the video stream.
+ */
+int uvc_video_enable(struct uvc_video_device *video, int enable)
+{
+	int ret;
+
+	if (!enable) {
+		uvc_uninit_video(video);
+		usb_set_interface(video->dev->udev,
+			video->streaming->intfnum, 0);
+		uvc_queue_enable(&video->queue, 0);
+		return 0;
+	}
+
+	if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
+		return ret;
+
+	return uvc_init_video(video);
+}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
new file mode 100644
index 000000000000..a995a780db1c
--- /dev/null
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -0,0 +1,796 @@
+#ifndef _USB_VIDEO_H_
+#define _USB_VIDEO_H_
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+
+/*
+ * Dynamic controls
+ */
+
+/* Data types for UVC control data */
+#define UVC_CTRL_DATA_TYPE_RAW		0
+#define UVC_CTRL_DATA_TYPE_SIGNED	1
+#define UVC_CTRL_DATA_TYPE_UNSIGNED	2
+#define UVC_CTRL_DATA_TYPE_BOOLEAN	3
+#define UVC_CTRL_DATA_TYPE_ENUM		4
+#define UVC_CTRL_DATA_TYPE_BITMASK	5
+
+/* Control flags */
+#define UVC_CONTROL_SET_CUR	(1 << 0)
+#define UVC_CONTROL_GET_CUR	(1 << 1)
+#define UVC_CONTROL_GET_MIN	(1 << 2)
+#define UVC_CONTROL_GET_MAX	(1 << 3)
+#define UVC_CONTROL_GET_RES	(1 << 4)
+#define UVC_CONTROL_GET_DEF	(1 << 5)
+/* Control should be saved at suspend and restored at resume. */
+#define UVC_CONTROL_RESTORE	(1 << 6)
+/* Control can be updated by the camera. */
+#define UVC_CONTROL_AUTO_UPDATE	(1 << 7)
+
+#define UVC_CONTROL_GET_RANGE	(UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
+				 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
+				 UVC_CONTROL_GET_DEF)
+
+struct uvc_xu_control_info {
+	__u8 entity[16];
+	__u8 index;
+	__u8 selector;
+	__u16 size;
+	__u32 flags;
+};
+
+struct uvc_xu_control_mapping {
+	__u32 id;
+	__u8 name[32];
+	__u8 entity[16];
+	__u8 selector;
+
+	__u8 size;
+	__u8 offset;
+	enum v4l2_ctrl_type v4l2_type;
+	__u32 data_type;
+};
+
+struct uvc_xu_control {
+	__u8 unit;
+	__u8 selector;
+	__u16 size;
+	__u8 __user *data;
+};
+
+#define UVCIOC_CTRL_ADD		_IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP		_IOWR('U', 2, struct uvc_xu_control_mapping)
+#define UVCIOC_CTRL_GET		_IOWR('U', 3, struct uvc_xu_control)
+#define UVCIOC_CTRL_SET		_IOW('U', 4, struct uvc_xu_control)
+
+#ifdef __KERNEL__
+
+#include <linux/poll.h>
+
+/* --------------------------------------------------------------------------
+ * UVC constants
+ */
+
+#define SC_UNDEFINED                    0x00
+#define SC_VIDEOCONTROL                 0x01
+#define SC_VIDEOSTREAMING               0x02
+#define SC_VIDEO_INTERFACE_COLLECTION   0x03
+
+#define PC_PROTOCOL_UNDEFINED           0x00
+
+#define CS_UNDEFINED                    0x20
+#define CS_DEVICE                       0x21
+#define CS_CONFIGURATION                0x22
+#define CS_STRING                       0x23
+#define CS_INTERFACE                    0x24
+#define CS_ENDPOINT                     0x25
+
+/* VideoControl class specific interface descriptor */
+#define VC_DESCRIPTOR_UNDEFINED         0x00
+#define VC_HEADER                       0x01
+#define VC_INPUT_TERMINAL               0x02
+#define VC_OUTPUT_TERMINAL              0x03
+#define VC_SELECTOR_UNIT                0x04
+#define VC_PROCESSING_UNIT              0x05
+#define VC_EXTENSION_UNIT               0x06
+
+/* VideoStreaming class specific interface descriptor */
+#define VS_UNDEFINED                    0x00
+#define VS_INPUT_HEADER                 0x01
+#define VS_OUTPUT_HEADER                0x02
+#define VS_STILL_IMAGE_FRAME            0x03
+#define VS_FORMAT_UNCOMPRESSED          0x04
+#define VS_FRAME_UNCOMPRESSED           0x05
+#define VS_FORMAT_MJPEG                 0x06
+#define VS_FRAME_MJPEG                  0x07
+#define VS_FORMAT_MPEG2TS               0x0a
+#define VS_FORMAT_DV                    0x0c
+#define VS_COLORFORMAT                  0x0d
+#define VS_FORMAT_FRAME_BASED           0x10
+#define VS_FRAME_FRAME_BASED            0x11
+#define VS_FORMAT_STREAM_BASED          0x12
+
+/* Endpoint type */
+#define EP_UNDEFINED                    0x00
+#define EP_GENERAL                      0x01
+#define EP_ENDPOINT                     0x02
+#define EP_INTERRUPT                    0x03
+
+/* Request codes */
+#define RC_UNDEFINED                    0x00
+#define SET_CUR                         0x01
+#define GET_CUR                         0x81
+#define GET_MIN                         0x82
+#define GET_MAX                         0x83
+#define GET_RES                         0x84
+#define GET_LEN                         0x85
+#define GET_INFO                        0x86
+#define GET_DEF                         0x87
+
+/* VideoControl interface controls */
+#define VC_CONTROL_UNDEFINED            0x00
+#define VC_VIDEO_POWER_MODE_CONTROL     0x01
+#define VC_REQUEST_ERROR_CODE_CONTROL   0x02
+
+/* Terminal controls */
+#define TE_CONTROL_UNDEFINED            0x00
+
+/* Selector Unit controls */
+#define SU_CONTROL_UNDEFINED            0x00
+#define SU_INPUT_SELECT_CONTROL         0x01
+
+/* Camera Terminal controls */
+#define CT_CONTROL_UNDEFINED            		0x00
+#define CT_SCANNING_MODE_CONTROL        		0x01
+#define CT_AE_MODE_CONTROL              		0x02
+#define CT_AE_PRIORITY_CONTROL          		0x03
+#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL               0x04
+#define CT_EXPOSURE_TIME_RELATIVE_CONTROL               0x05
+#define CT_FOCUS_ABSOLUTE_CONTROL       		0x06
+#define CT_FOCUS_RELATIVE_CONTROL       		0x07
+#define CT_FOCUS_AUTO_CONTROL           		0x08
+#define CT_IRIS_ABSOLUTE_CONTROL        		0x09
+#define CT_IRIS_RELATIVE_CONTROL        		0x0a
+#define CT_ZOOM_ABSOLUTE_CONTROL        		0x0b
+#define CT_ZOOM_RELATIVE_CONTROL        		0x0c
+#define CT_PANTILT_ABSOLUTE_CONTROL     		0x0d
+#define CT_PANTILT_RELATIVE_CONTROL     		0x0e
+#define CT_ROLL_ABSOLUTE_CONTROL        		0x0f
+#define CT_ROLL_RELATIVE_CONTROL        		0x10
+#define CT_PRIVACY_CONTROL              		0x11
+
+/* Processing Unit controls */
+#define PU_CONTROL_UNDEFINED            		0x00
+#define PU_BACKLIGHT_COMPENSATION_CONTROL               0x01
+#define PU_BRIGHTNESS_CONTROL           		0x02
+#define PU_CONTRAST_CONTROL             		0x03
+#define PU_GAIN_CONTROL                 		0x04
+#define PU_POWER_LINE_FREQUENCY_CONTROL 		0x05
+#define PU_HUE_CONTROL                  		0x06
+#define PU_SATURATION_CONTROL           		0x07
+#define PU_SHARPNESS_CONTROL            		0x08
+#define PU_GAMMA_CONTROL                		0x09
+#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL            0x0a
+#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL       0x0b
+#define PU_WHITE_BALANCE_COMPONENT_CONTROL              0x0c
+#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL         0x0d
+#define PU_DIGITAL_MULTIPLIER_CONTROL   		0x0e
+#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL             0x0f
+#define PU_HUE_AUTO_CONTROL             		0x10
+#define PU_ANALOG_VIDEO_STANDARD_CONTROL                0x11
+#define PU_ANALOG_LOCK_STATUS_CONTROL   		0x12
+
+#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL		0x01
+#define LXU_MOTOR_PANTILT_RESET_CONTROL			0x02
+#define LXU_MOTOR_FOCUS_MOTOR_CONTROL			0x03
+
+/* VideoStreaming interface controls */
+#define VS_CONTROL_UNDEFINED            0x00
+#define VS_PROBE_CONTROL                0x01
+#define VS_COMMIT_CONTROL               0x02
+#define VS_STILL_PROBE_CONTROL          0x03
+#define VS_STILL_COMMIT_CONTROL         0x04
+#define VS_STILL_IMAGE_TRIGGER_CONTROL  0x05
+#define VS_STREAM_ERROR_CODE_CONTROL    0x06
+#define VS_GENERATE_KEY_FRAME_CONTROL   0x07
+#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
+#define VS_SYNC_DELAY_CONTROL           0x09
+
+#define TT_VENDOR_SPECIFIC              0x0100
+#define TT_STREAMING                    0x0101
+
+/* Input Terminal types */
+#define ITT_VENDOR_SPECIFIC             0x0200
+#define ITT_CAMERA                      0x0201
+#define ITT_MEDIA_TRANSPORT_INPUT       0x0202
+
+/* Output Terminal types */
+#define OTT_VENDOR_SPECIFIC             0x0300
+#define OTT_DISPLAY                     0x0301
+#define OTT_MEDIA_TRANSPORT_OUTPUT      0x0302
+
+/* External Terminal types */
+#define EXTERNAL_VENDOR_SPECIFIC        0x0400
+#define COMPOSITE_CONNECTOR             0x0401
+#define SVIDEO_CONNECTOR                0x0402
+#define COMPONENT_CONNECTOR             0x0403
+
+#define UVC_TERM_INPUT			0x0000
+#define UVC_TERM_OUTPUT			0x8000
+
+#define UVC_ENTITY_TYPE(entity)		((entity)->type & 0x7fff)
+#define UVC_ENTITY_IS_UNIT(entity)	(((entity)->type & 0xff00) == 0)
+#define UVC_ENTITY_IS_TERM(entity)	(((entity)->type & 0xff00) != 0)
+#define UVC_ENTITY_IS_ITERM(entity) \
+	(((entity)->type & 0x8000) == UVC_TERM_INPUT)
+#define UVC_ENTITY_IS_OTERM(entity) \
+	(((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
+
+#define UVC_STATUS_TYPE_CONTROL		1
+#define UVC_STATUS_TYPE_STREAMING	2
+
+/* ------------------------------------------------------------------------
+ * GUIDs
+ */
+#define UVC_GUID_UVC_CAMERA \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+#define UVC_GUID_UVC_OUTPUT \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+#define UVC_GUID_UVC_PROCESSING \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
+#define UVC_GUID_UVC_SELECTOR \
+	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
+
+#define UVC_GUID_LOGITECH_DEV_INFO \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1e}
+#define UVC_GUID_LOGITECH_USER_HW \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x1f}
+#define UVC_GUID_LOGITECH_VIDEO \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x50}
+#define UVC_GUID_LOGITECH_MOTOR \
+	{0x82, 0x06, 0x61, 0x63, 0x70, 0x50, 0xab, 0x49, \
+	 0xb8, 0xcc, 0xb3, 0x85, 0x5e, 0x8d, 0x22, 0x56}
+
+#define UVC_GUID_FORMAT_MJPEG \
+	{ 'M',  'J',  'P',  'G', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2 \
+	{ 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_NV12 \
+	{ 'N',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12 \
+	{ 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420 \
+	{ 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY \
+	{ 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_Y800 \
+	{ 'Y',  '8',  '0',  '0', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BY8 \
+	{ 'B',  'Y',  '8',  ' ', 0x00, 0x00, 0x10, 0x00, \
+	 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
+
+/* ------------------------------------------------------------------------
+ * Driver specific constants.
+ */
+
+#define DRIVER_VERSION_NUMBER	KERNEL_VERSION(0, 1, 0)
+
+/* Number of isochronous URBs. */
+#define UVC_URBS		5
+/* Maximum number of packets per isochronous URB. */
+#define UVC_MAX_ISO_PACKETS	40
+/* Maximum frame size in bytes, for sanity checking. */
+#define UVC_MAX_FRAME_SIZE	(16*1024*1024)
+/* Maximum number of video buffers. */
+#define UVC_MAX_VIDEO_BUFFERS	32
+
+#define UVC_CTRL_CONTROL_TIMEOUT	300
+#define UVC_CTRL_STREAMING_TIMEOUT	1000
+
+/* Devices quirks */
+#define UVC_QUIRK_STATUS_INTERVAL	0x00000001
+#define UVC_QUIRK_PROBE_MINMAX		0x00000002
+#define UVC_QUIRK_PROBE_EXTRAFIELDS	0x00000004
+#define UVC_QUIRK_BUILTIN_ISIGHT	0x00000008
+#define UVC_QUIRK_STREAM_NO_FID		0x00000010
+#define UVC_QUIRK_IGNORE_SELECTOR_UNIT	0x00000020
+
+/* Format flags */
+#define UVC_FMT_FLAG_COMPRESSED		0x00000001
+#define UVC_FMT_FLAG_STREAM		0x00000002
+
+/* ------------------------------------------------------------------------
+ * Structures.
+ */
+
+struct uvc_device;
+
+/* TODO: Put the most frequently accessed fields at the beginning of
+ * structures to maximize cache efficiency.
+ */
+struct uvc_streaming_control {
+	__u16 bmHint;
+	__u8  bFormatIndex;
+	__u8  bFrameIndex;
+	__u32 dwFrameInterval;
+	__u16 wKeyFrameRate;
+	__u16 wPFrameRate;
+	__u16 wCompQuality;
+	__u16 wCompWindowSize;
+	__u16 wDelay;
+	__u32 dwMaxVideoFrameSize;
+	__u32 dwMaxPayloadTransferSize;
+	__u32 dwClockFrequency;
+	__u8  bmFramingInfo;
+	__u8  bPreferedVersion;
+	__u8  bMinVersion;
+	__u8  bMaxVersion;
+};
+
+struct uvc_menu_info {
+	__u32 value;
+	__u8 name[32];
+};
+
+struct uvc_control_info {
+	struct list_head list;
+	struct list_head mappings;
+
+	__u8 entity[16];
+	__u8 index;
+	__u8 selector;
+
+	__u16 size;
+	__u32 flags;
+};
+
+struct uvc_control_mapping {
+	struct list_head list;
+
+	struct uvc_control_info *ctrl;
+
+	__u32 id;
+	__u8 name[32];
+	__u8 entity[16];
+	__u8 selector;
+
+	__u8 size;
+	__u8 offset;
+	enum v4l2_ctrl_type v4l2_type;
+	__u32 data_type;
+
+	struct uvc_menu_info *menu_info;
+	__u32 menu_count;
+};
+
+struct uvc_control {
+	struct uvc_entity *entity;
+	struct uvc_control_info *info;
+
+	__u8 index;	/* Used to match the uvc_control entry with a
+			   uvc_control_info. */
+	__u8 dirty : 1,
+	     loaded : 1,
+	     modified : 1;
+
+	__u8 *data;
+};
+
+struct uvc_format_desc {
+	char *name;
+	__u8 guid[16];
+	__u32 fcc;
+};
+
+/* The term 'entity' refers to both UVC units and UVC terminals.
+ *
+ * The type field is either the terminal type (wTerminalType in the terminal
+ * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
+ * As the bDescriptorSubtype field is one byte long, the type value will
+ * always have a null MSB for units. All terminal types defined by the UVC
+ * specification have a non-null MSB, so it is safe to use the MSB to
+ * differentiate between units and terminals as long as the descriptor parsing
+ * code makes sure terminal types have a non-null MSB.
+ *
+ * For terminals, the type's most significant bit stores the terminal
+ * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
+ * always be accessed with the UVC_ENTITY_* macros and never directly.
+ */
+
+struct uvc_entity {
+	struct list_head list;		/* Entity as part of a UVC device. */
+	struct list_head chain;		/* Entity as part of a video device
+					 * chain. */
+	__u8 id;
+	__u16 type;
+	char name[64];
+
+	union {
+		struct {
+			__u16 wObjectiveFocalLengthMin;
+			__u16 wObjectiveFocalLengthMax;
+			__u16 wOcularFocalLength;
+			__u8  bControlSize;
+			__u8  *bmControls;
+		} camera;
+
+		struct {
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  bTransportModeSize;
+			__u8  *bmTransportModes;
+		} media;
+
+		struct {
+			__u8  bSourceID;
+		} output;
+
+		struct {
+			__u8  bSourceID;
+			__u16 wMaxMultiplier;
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  bmVideoStandards;
+		} processing;
+
+		struct {
+			__u8  bNrInPins;
+			__u8  *baSourceID;
+		} selector;
+
+		struct {
+			__u8  guidExtensionCode[16];
+			__u8  bNumControls;
+			__u8  bNrInPins;
+			__u8  *baSourceID;
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  *bmControlsType;
+		} extension;
+	};
+
+	unsigned int ncontrols;
+	struct uvc_control *controls;
+};
+
+struct uvc_frame {
+	__u8  bFrameIndex;
+	__u8  bmCapabilities;
+	__u16 wWidth;
+	__u16 wHeight;
+	__u32 dwMinBitRate;
+	__u32 dwMaxBitRate;
+	__u32 dwMaxVideoFrameBufferSize;
+	__u8  bFrameIntervalType;
+	__u32 dwDefaultFrameInterval;
+	__u32 *dwFrameInterval;
+};
+
+struct uvc_format {
+	__u8 type;
+	__u8 index;
+	__u8 bpp;
+	__u8 colorspace;
+	__u32 fcc;
+	__u32 flags;
+
+	char name[32];
+
+	unsigned int nframes;
+	struct uvc_frame *frame;
+};
+
+struct uvc_streaming_header {
+	__u8 bNumFormats;
+	__u8 bEndpointAddress;
+	__u8 bTerminalLink;
+	__u8 bControlSize;
+	__u8 *bmaControls;
+	/* The following fields are used by input headers only. */
+	__u8 bmInfo;
+	__u8 bStillCaptureMethod;
+	__u8 bTriggerSupport;
+	__u8 bTriggerUsage;
+};
+
+struct uvc_streaming {
+	struct list_head list;
+
+	struct usb_interface *intf;
+	int intfnum;
+	__u16 maxpsize;
+
+	struct uvc_streaming_header header;
+
+	unsigned int nformats;
+	struct uvc_format *format;
+
+	struct uvc_streaming_control ctrl;
+	struct uvc_format *cur_format;
+	struct uvc_frame *cur_frame;
+
+	struct mutex mutex;
+};
+
+enum uvc_buffer_state {
+	UVC_BUF_STATE_IDLE       = 0,
+	UVC_BUF_STATE_QUEUED     = 1,
+	UVC_BUF_STATE_ACTIVE     = 2,
+	UVC_BUF_STATE_DONE       = 3,
+	UVC_BUF_STATE_ERROR      = 4,
+};
+
+struct uvc_buffer {
+	unsigned long vma_use_count;
+	struct list_head stream;
+
+	/* Touched by interrupt handler. */
+	struct v4l2_buffer buf;
+	struct list_head queue;
+	wait_queue_head_t wait;
+	enum uvc_buffer_state state;
+};
+
+#define UVC_QUEUE_STREAMING		(1 << 0)
+#define UVC_QUEUE_DISCONNECTED		(1 << 1)
+#define UVC_QUEUE_DROP_INCOMPLETE	(1 << 2)
+
+struct uvc_video_queue {
+	void *mem;
+	unsigned int flags;
+	__u32 sequence;
+
+	unsigned int count;
+	unsigned int buf_size;
+	struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
+	struct mutex mutex;	/* protects buffers and mainqueue */
+	spinlock_t irqlock;	/* protects irqqueue */
+
+	struct list_head mainqueue;
+	struct list_head irqqueue;
+};
+
+struct uvc_video_device {
+	struct uvc_device *dev;
+	struct video_device *vdev;
+	atomic_t active;
+	unsigned int frozen : 1;
+
+	struct list_head iterms;
+	struct uvc_entity *oterm;
+	struct uvc_entity *processing;
+	struct uvc_entity *selector;
+	struct list_head extensions;
+	struct mutex ctrl_mutex;
+
+	struct uvc_video_queue queue;
+
+	/* Video streaming object, must always be non-NULL. */
+	struct uvc_streaming *streaming;
+
+	void (*decode) (struct urb *urb, struct uvc_video_device *video,
+			struct uvc_buffer *buf);
+
+	/* Context data used by the bulk completion handler. */
+	struct {
+		__u8 header[256];
+		unsigned int header_size;
+		int skip_payload;
+		__u32 payload_size;
+		__u32 max_payload_size;
+	} bulk;
+
+	struct urb *urb[UVC_URBS];
+	char *urb_buffer[UVC_URBS];
+
+	__u8 last_fid;
+};
+
+enum uvc_device_state {
+	UVC_DEV_DISCONNECTED = 1,
+};
+
+struct uvc_device {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	__u32 quirks;
+	int intfnum;
+	char name[32];
+
+	enum uvc_device_state state;
+	struct kref kref;
+	struct list_head list;
+
+	/* Video control interface */
+	__u16 uvc_version;
+	__u32 clock_frequency;
+
+	struct list_head entities;
+
+	struct uvc_video_device video;
+
+	/* Status Interrupt Endpoint */
+	struct usb_host_endpoint *int_ep;
+	struct urb *int_urb;
+	__u8 status[16];
+	struct input_dev *input;
+
+	/* Video Streaming interfaces */
+	struct list_head streaming;
+};
+
+enum uvc_handle_state {
+	UVC_HANDLE_PASSIVE	= 0,
+	UVC_HANDLE_ACTIVE	= 1,
+};
+
+struct uvc_fh {
+	struct uvc_video_device *device;
+	enum uvc_handle_state state;
+};
+
+struct uvc_driver {
+	struct usb_driver driver;
+
+	struct mutex open_mutex;	/* protects from open/disconnect race */
+
+	struct list_head devices;	/* struct uvc_device list */
+	struct list_head controls;	/* struct uvc_control_info list */
+	struct mutex ctrl_mutex;	/* protects controls and devices
+					   lists */
+};
+
+/* ------------------------------------------------------------------------
+ * Debugging, printing and logging
+ */
+
+#define UVC_TRACE_PROBE		(1 << 0)
+#define UVC_TRACE_DESCR		(1 << 1)
+#define UVC_TRACE_CONTROL	(1 << 2)
+#define UVC_TRACE_FORMAT	(1 << 3)
+#define UVC_TRACE_CAPTURE	(1 << 4)
+#define UVC_TRACE_CALLS		(1 << 5)
+#define UVC_TRACE_IOCTL		(1 << 6)
+#define UVC_TRACE_FRAME		(1 << 7)
+#define UVC_TRACE_SUSPEND	(1 << 8)
+#define UVC_TRACE_STATUS	(1 << 9)
+
+extern unsigned int uvc_trace_param;
+
+#define uvc_trace(flag, msg...) \
+	do { \
+		if (uvc_trace_param & flag) \
+			printk(KERN_DEBUG "uvcvideo: " msg); \
+	} while (0)
+
+#define uvc_printk(level, msg...) \
+	printk(level "uvcvideo: " msg)
+
+#define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
+			"%02x%02x%02x%02x%02x%02x"
+#define UVC_GUID_ARGS(guid) \
+	(guid)[3],  (guid)[2],  (guid)[1],  (guid)[0], \
+	(guid)[5],  (guid)[4], \
+	(guid)[7],  (guid)[6], \
+	(guid)[8],  (guid)[9], \
+	(guid)[10], (guid)[11], (guid)[12], \
+	(guid)[13], (guid)[14], (guid)[15]
+
+/* --------------------------------------------------------------------------
+ * Internal functions.
+ */
+
+/* Core driver */
+extern struct uvc_driver uvc_driver;
+extern void uvc_delete(struct kref *kref);
+
+/* Video buffers queue management. */
+extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
+		unsigned int nbuffers, unsigned int buflength);
+extern int uvc_free_buffers(struct uvc_video_queue *queue);
+extern int uvc_query_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf);
+extern int uvc_queue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf);
+extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+		struct v4l2_buffer *v4l2_buf, int nonblocking);
+extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
+extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+		struct uvc_buffer *buf);
+extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+		struct file *file, poll_table *wait);
+static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
+{
+	return queue->flags & UVC_QUEUE_STREAMING;
+}
+
+/* V4L2 interface */
+extern struct file_operations uvc_fops;
+
+/* Video */
+extern int uvc_video_init(struct uvc_video_device *video);
+extern int uvc_video_suspend(struct uvc_video_device *video);
+extern int uvc_video_resume(struct uvc_video_device *video);
+extern int uvc_video_enable(struct uvc_video_device *video, int enable);
+extern int uvc_probe_video(struct uvc_video_device *video,
+		struct uvc_streaming_control *probe);
+extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+		__u8 intfnum, __u8 cs, void *data, __u16 size);
+extern int uvc_set_video_ctrl(struct uvc_video_device *video,
+		struct uvc_streaming_control *ctrl, int probe);
+
+/* Status */
+extern int uvc_status_init(struct uvc_device *dev);
+extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_suspend(struct uvc_device *dev);
+extern int uvc_status_resume(struct uvc_device *dev);
+
+/* Controls */
+extern struct uvc_control *uvc_find_control(struct uvc_video_device *video,
+		__u32 v4l2_id, struct uvc_control_mapping **mapping);
+extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
+		struct v4l2_queryctrl *v4l2_ctrl);
+
+extern int uvc_ctrl_add_info(struct uvc_control_info *info);
+extern int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_init_device(struct uvc_device *dev);
+extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
+extern int uvc_ctrl_resume_device(struct uvc_device *dev);
+extern void uvc_ctrl_init(void);
+
+extern int uvc_ctrl_begin(struct uvc_video_device *video);
+extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback);
+static inline int uvc_ctrl_commit(struct uvc_video_device *video)
+{
+	return __uvc_ctrl_commit(video, 0);
+}
+static inline int uvc_ctrl_rollback(struct uvc_video_device *video)
+{
+	return __uvc_ctrl_commit(video, 1);
+}
+
+extern int uvc_ctrl_get(struct uvc_video_device *video,
+		struct v4l2_ext_control *xctrl);
+extern int uvc_ctrl_set(struct uvc_video_device *video,
+		struct v4l2_ext_control *xctrl);
+
+extern int uvc_xu_ctrl_query(struct uvc_video_device *video,
+		struct uvc_xu_control *ctrl, int set);
+
+/* Utility functions */
+extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
+		unsigned int n_terms, unsigned int threshold);
+extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
+		uint32_t denominator);
+extern struct usb_host_endpoint *uvc_find_endpoint(
+		struct usb_host_interface *alts, __u8 epaddr);
+
+/* Quirks support */
+void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video,
+		struct uvc_buffer *buf);
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index db3c892f87fb..d40d6d15ae20 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1686,9 +1686,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 		ioc->bus_type = SAS;
 	}
 
-	if (ioc->bus_type == SAS && mpt_msi_enable == -1)
-		ioc->msi_enable = 1;
-	else
+	if (mpt_msi_enable == -1) {
+		/* Enable on SAS, disable on FC and SPI */
+		if (ioc->bus_type == SAS)
+			ioc->msi_enable = 1;
+		else
+			ioc->msi_enable = 0;
+	} else
+		/* follow flag: 0 - disable; 1 - enable */
 		ioc->msi_enable = mpt_msi_enable;
 
 	if (ioc->errata_flag_1064)
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 25bcfcf36f2e..1effca4e40e1 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -1266,13 +1266,18 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
 static int
 mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
-	struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
 	int rc;
 
 	rc = mptscsih_ioc_reset(ioc, reset_phase);
 
-	if (reset_phase == MPT_IOC_POST_RESET)
+	/* only try to do a renegotiation if we're properly set up
+	 * if we get an ioc fault on bringup, ioc->sh will be NULL */
+	if (reset_phase == MPT_IOC_POST_RESET &&
+	    ioc->sh) {
+		struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+
 		mptspi_dv_renegotiate(hd);
+	}
 
 	return rc;
 }
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 65210fca37ed..d89475d36988 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -114,6 +114,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 	unsigned int nob = data->blocks;
 	unsigned long long clks;
 	unsigned int timeout;
+	bool dalgn = 0;
 	u32 dcmd;
 	int i;
 
@@ -152,6 +153,9 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 		host->sg_cpu[i].dcmd = dcmd | length;
 		if (length & 31 && !(data->flags & MMC_DATA_READ))
 			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
+		/* Not aligned to 8-byte boundary? */
+		if (sg_dma_address(&data->sg[i]) & 0x7)
+			dalgn = 1;
 		if (data->flags & MMC_DATA_READ) {
 			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
 			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -165,6 +169,15 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 	host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
 	wmb();
 
+	/*
+	 * The PXA27x DMA controller encounters overhead when working with
+	 * unaligned (to 8-byte boundaries) data, so switch on byte alignment
+	 * mode only if we have unaligned data.
+	 */
+	if (dalgn)
+		DALGN |= (1 << host->dma);
+	else
+		DALGN &= (1 << host->dma);
 	DDADR(host->dma) = host->sg_dma;
 	DCSR(host->dma) = DCSR_RUN;
 }
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 07c2048b230b..b413aa6c246b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -55,6 +55,10 @@ static unsigned int debug_quirks = 0;
 #define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
 /* Controller needs to be reset after each request to stay stable */
 #define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
+/* Controller has an off-by-one issue with timeout value */
+#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL		(1<<10)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -115,7 +119,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+				  SDHCI_QUIRK_BROKEN_DMA,
 	},
 
 	{
@@ -124,7 +129,17 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 		.subvendor      = PCI_ANY_ID,
 		.subdevice      = PCI_ANY_ID,
 		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor         = PCI_VENDOR_ID_MARVELL,
+		.device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.driver_data    = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+				  SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
 	},
 
 	{
@@ -469,6 +484,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 			break;
 	}
 
+	/*
+	 * Compensate for an off-by-one error in the CaFe hardware; otherwise,
+	 * a too-small count gives us interrupt timeouts.
+	 */
+	if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
+		count++;
+
 	if (count >= 0xF) {
 		printk(KERN_WARNING "%s: Too large timeout requested!\n",
 			mmc_hostname(host->mmc));
@@ -774,6 +796,14 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 		BUG();
 	}
 
+	/*
+	 * At least the CaFe chip gets confused if we set the voltage
+	 * and set turn on power at the same time, so set the voltage first.
+	 */
+	if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
+		writeb(pwr & ~SDHCI_POWER_ON,
+				host->ioaddr + SDHCI_POWER_CONTROL);
+
 	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
 
 out:
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 2edda8cc7f99..aabad8ce7458 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1768,9 +1768,10 @@ vortex_timer(unsigned long data)
 	case XCVR_MII: case XCVR_NWAY:
 		{
 			ok = 1;
-			spin_lock_bh(&vp->lock);
+			/* Interrupts are already disabled */
+			spin_lock(&vp->lock);
 			vortex_check_media(dev, 0);
-			spin_unlock_bh(&vp->lock);
+			spin_unlock(&vp->lock);
 		}
 		break;
 	  default:					/* Other media types handled by Tx timeouts. */
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index f3cba5e24ec5..1037b1332312 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1803,6 +1803,8 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 	if (rx->prev->skb) {
 		struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
 		put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
+		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
+			sizeof(struct rfd), PCI_DMA_TODEVICE);
 	}
 
 	return 0;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 701531e72e7b..a3f6a9c72ec8 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -347,7 +347,7 @@ e1000_set_tso(struct net_device *netdev, u32 data)
 	else
 		netdev->features &= ~NETIF_F_TSO;
 
-	if (data)
+	if (data && (adapter->hw.mac_type > e1000_82547_rev_2))
 		netdev->features |= NETIF_F_TSO6;
 	else
 		netdev->features &= ~NETIF_F_TSO6;
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index cab1835173cd..648a87bbf467 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2535,7 +2535,8 @@ void e1000e_down(struct e1000_adapter *adapter)
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 
-	e1000e_reset(adapter);
+	if (!pci_channel_offline(adapter->pdev))
+		e1000e_reset(adapter);
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
 
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index fe872fbd671e..e01926b7b5b7 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0091"
+#define DRV_VERSION	"EHEA_0092"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
@@ -452,7 +452,7 @@ struct ehea_bcmc_reg_entry {
 struct ehea_bcmc_reg_array {
 	struct ehea_bcmc_reg_entry *arr;
 	int num_entries;
-	struct mutex lock;
+	spinlock_t lock;
 };
 
 #define EHEA_PORT_UP 1
@@ -478,6 +478,7 @@ struct ehea_port {
 	int num_add_tx_qps;
 	int num_mcs;
 	int resets;
+	u64 flags;
 	u64 mac_addr;
 	u32 logical_port_id;
 	u32 port_speed;
@@ -501,7 +502,8 @@ struct port_res_cfg {
 };
 
 enum ehea_flag_bits {
-	__EHEA_STOP_XFER
+	__EHEA_STOP_XFER,
+	__EHEA_DISABLE_PORT_RESET
 };
 
 void ehea_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 075fd547421e..0920b796bd78 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -118,6 +118,7 @@ static struct of_device_id ehea_device_table[] = {
 	},
 	{},
 };
+MODULE_DEVICE_TABLE(of, ehea_device_table);
 
 static struct of_platform_driver ehea_driver = {
 	.name = "ehea",
@@ -137,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg)
 	}
 }
 
+void ehea_schedule_port_reset(struct ehea_port *port)
+{
+	if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
+		schedule_work(&port->reset_task);
+}
+
 static void ehea_update_firmware_handles(void)
 {
 	struct ehea_fw_handle_entry *arr = NULL;
@@ -241,7 +248,7 @@ static void ehea_update_bcmc_registrations(void)
 		}
 
 	if (num_registrations) {
-		arr = kzalloc(num_registrations * sizeof(*arr), GFP_KERNEL);
+		arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
 		if (!arr)
 			return;  /* Keep the existing array */
 	} else
@@ -301,7 +308,7 @@ static struct net_device_stats *ehea_get_stats(struct net_device *dev)
 
 	memset(stats, 0, sizeof(*stats));
 
-	cb2 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	cb2 = kzalloc(PAGE_SIZE, GFP_ATOMIC);
 	if (!cb2) {
 		ehea_error("no mem for cb2");
 		goto out;
@@ -587,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
 				   "Resetting port.", pr->qp->init_attr.qp_nr);
 			ehea_dump(cqe, sizeof(*cqe), "CQE");
 		}
-		schedule_work(&pr->port->reset_task);
+		ehea_schedule_port_reset(pr->port);
 		return 1;
 	}
 
@@ -616,7 +623,7 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
 	*tcph = tcp_hdr(skb);
 
 	/* check if ip header and tcp header are complete */
-	if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+	if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
 		return -1;
 
 	*hdr_flags = LRO_IPV4 | LRO_TCP;
@@ -765,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 			ehea_error("Send Completion Error: Resetting port");
 			if (netif_msg_tx_err(pr->port))
 				ehea_dump(cqe, sizeof(*cqe), "Send CQE");
-			schedule_work(&pr->port->reset_task);
+			ehea_schedule_port_reset(pr->port);
 			break;
 		}
 
@@ -885,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
 		eqe = ehea_poll_eq(port->qp_eq);
 	}
 
-	schedule_work(&port->reset_task);
+	ehea_schedule_port_reset(port);
 
 	return IRQ_HANDLED;
 }
@@ -1763,7 +1770,7 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
 	memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 
 	/* Deregister old MAC in pHYP */
 	if (port->state == EHEA_PORT_UP) {
@@ -1785,7 +1792,7 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
 out_upregs:
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 out_free:
 	kfree(cb0);
 out:
@@ -1947,7 +1954,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
 	}
 	ehea_promiscuous(dev, 0);
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 
 	if (dev->flags & IFF_ALLMULTI) {
 		ehea_allmulti(dev, 1);
@@ -1978,7 +1985,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
 	}
 out:
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 	return;
 }
 
@@ -2497,7 +2504,7 @@ static int ehea_up(struct net_device *dev)
 		}
 	}
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 
 	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
 	if (ret) {
@@ -2520,7 +2527,7 @@ out:
 		ehea_info("Failed starting %s. ret=%i", dev->name, ret);
 
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 
 	ehea_update_firmware_handles();
 	mutex_unlock(&ehea_fw_handles.lock);
@@ -2575,7 +2582,7 @@ static int ehea_down(struct net_device *dev)
 
 	mutex_lock(&ehea_fw_handles.lock);
 
-	mutex_lock(&ehea_bcmc_regs.lock);
+	spin_lock(&ehea_bcmc_regs.lock);
 	ehea_drop_multicast_list(dev);
 	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 
@@ -2584,7 +2591,7 @@ static int ehea_down(struct net_device *dev)
 	port->state = EHEA_PORT_DOWN;
 
 	ehea_update_bcmc_registrations();
-	mutex_unlock(&ehea_bcmc_regs.lock);
+	spin_unlock(&ehea_bcmc_regs.lock);
 
 	ret = ehea_clean_all_portres(port);
 	if (ret)
@@ -2605,13 +2612,14 @@ static int ehea_stop(struct net_device *dev)
 	if (netif_msg_ifdown(port))
 		ehea_info("disabling port %s", dev->name);
 
+	set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
 	cancel_work_sync(&port->reset_task);
-
 	mutex_lock(&port->port_lock);
 	netif_stop_queue(dev);
 	port_napi_disable(port);
 	ret = ehea_down(dev);
 	mutex_unlock(&port->port_lock);
+	clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
 	return ret;
 }
 
@@ -2941,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
 
 	if (netif_carrier_ok(dev) &&
 	    !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
-		schedule_work(&port->reset_task);
+		ehea_schedule_port_reset(port);
 }
 
 int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
@@ -3590,7 +3598,7 @@ int __init ehea_module_init(void)
 	memset(&ehea_bcmc_regs, 0, sizeof(ehea_bcmc_regs));
 
 	mutex_init(&ehea_fw_handles.lock);
-	mutex_init(&ehea_bcmc_regs.lock);
+	spin_lock_init(&ehea_bcmc_regs.lock);
 
 	ret = check_module_parm();
 	if (ret)
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 2cb244763292..20d4fe96a81c 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -4194,12 +4194,23 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 
 	netif_carrier_off(dev);
 	if (netif_running(dev)) {
+		unsigned long flags;
+
 		nv_disable_irq(dev);
 		netif_tx_lock_bh(dev);
-		spin_lock(&np->lock);
+		/* with plain spinlock lockdep complains */
+		spin_lock_irqsave(&np->lock, flags);
 		/* stop engines */
+		/* FIXME:
+		 * this can take some time, and interrupts are disabled
+		 * due to spin_lock_irqsave, but let's hope no daemon
+		 * is going to change the settings very often...
+		 * Worst case:
+		 * NV_RXSTOP_DELAY1MAX + NV_TXSTOP_DELAY1MAX
+		 * + some minor delays, which is up to a second approximately
+		 */
 		nv_stop_rxtx(dev);
-		spin_unlock(&np->lock);
+		spin_unlock_irqrestore(&np->lock, flags);
 		netif_tx_unlock_bh(dev);
 	}
 
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index e36321152d50..8268b3535b30 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -463,6 +463,9 @@ static void restart(struct net_device *dev)
 	else
 		C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
 
+	/* Restore multicast and promiscuous settings */
+	set_multicast_list(dev);
+
 	S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
 }
 
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 0b94833e23f7..e8cfadefa4b6 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -1077,8 +1077,6 @@ static inline void rx_off(struct scc_priv *priv)
 
 static void start_timer(struct scc_priv *priv, int t, int r15)
 {
-	unsigned long flags;
-
 	outb(priv->tmr_mode, priv->tmr_ctrl);
 	if (t == 0) {
 		tm_isr(priv);
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index ed24a1d607dd..61af02b4c9d8 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1643,6 +1643,12 @@ static int emac_poll_rx(void *param, int budget)
 			goto next;
 		}
 
+		if (len < ETH_HLEN) {
+			++dev->estats.rx_dropped_stack;
+			emac_recycle_rx_skb(dev, slot, len);
+			goto next;
+		}
+
 		if (len && len < EMAC_RX_COPY_THRESH) {
 			struct sk_buff *copy_skb =
 			    alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC);
@@ -2738,6 +2744,8 @@ static int __devinit emac_probe(struct of_device *ofdev,
 	/* Clean rings */
 	memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));
 	memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));
+	memset(dev->tx_skb, 0, NUM_TX_BUFF * sizeof(struct sk_buff *));
+	memset(dev->rx_skb, 0, NUM_RX_BUFF * sizeof(struct sk_buff *));
 
 	/* Attach to ZMII, if needed */
 	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index ae398f04c7b4..e79a26a886c8 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -718,7 +718,8 @@ void igb_down(struct igb_adapter *adapter)
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
 
-	igb_reset(adapter);
+	if (!pci_channel_offline(adapter->pdev))
+		igb_reset(adapter);
 	igb_clean_all_tx_rings(adapter);
 	igb_clean_all_rx_rings(adapter);
 }
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 679a0826780e..2c03f4e2ccc4 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -1271,7 +1271,7 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
 
 			framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
 
-			endframeLen = framelen - jumbo->current_size;
+			endframelen = framelen - jumbo->current_size;
 			/*
 			if (framelen > IPG_RXFRAG_SIZE)
 				framelen=IPG_RXFRAG_SIZE;
@@ -1279,8 +1279,8 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
 			if (framelen > IPG_RXSUPPORT_SIZE)
 				dev_kfree_skb_irq(jumbo->skb);
 			else {
-				memcpy(skb_put(jumbo->skb, endframeLen),
-				       skb->data, endframeLen);
+				memcpy(skb_put(jumbo->skb, endframelen),
+				       skb->data, endframelen);
 
 				jumbo->skb->protocol =
 				    eth_type_trans(jumbo->skb, dev);
@@ -1352,16 +1352,16 @@ static int ipg_nic_rx(struct net_device *dev)
 
 		switch (ipg_nic_rx_check_frame_type(dev)) {
 		case FRAME_WITH_START_WITH_END:
-			ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+			ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry);
 			break;
 		case FRAME_WITH_START:
-			ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+			ipg_nic_rx_with_start(dev, sp, rxfd, entry);
 			break;
 		case FRAME_WITH_END:
-			ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+			ipg_nic_rx_with_end(dev, sp, rxfd, entry);
 			break;
 		case FRAME_NO_START_NO_END:
-			ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+			ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry);
 			break;
 		}
 	}
@@ -1808,7 +1808,7 @@ static int ipg_nic_open(struct net_device *dev)
 	/* initialize JUMBO Frame control variable */
 	sp->jumbo.found_start = 0;
 	sp->jumbo.current_size = 0;
-	sp->jumbo.skb = 0;
+	sp->jumbo.skb = NULL;
 	dev->mtu = IPG_TXFRAG_SIZE;
 #endif
 
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index a7714da7c283..effc1ce8179a 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -152,6 +152,7 @@ static chipio_t pnp_info;
 static const struct pnp_device_id nsc_ircc_pnp_table[] = {
 	{ .id = "NSC6001", .driver_data = 0 },
 	{ .id = "IBM0071", .driver_data = 0 },
+	{ .id = "HWPC224", .driver_data = 0 },
 	{ }
 };
 
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 58e128784585..04ad3573b159 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -1546,6 +1546,7 @@ static int via_ircc_net_open(struct net_device *dev)
 			IRDA_WARNING("%s, unable to allocate dma2=%d\n",
 				     driver_name, self->io.dma2);
 			free_irq(self->io.irq, self);
+			free_dma(self->io.dma);
 			return -EAGAIN;
 		}
 	}
@@ -1606,6 +1607,8 @@ static int via_ircc_net_close(struct net_device *dev)
 	EnAllInt(iobase, OFF);
 	free_irq(self->io.irq, dev);
 	free_dma(self->io.dma);
+	if (self->io.dma2 != self->io.dma)
+		free_dma(self->io.dma2);
 
 	return 0;
 }
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 7b859220c255..8f0460901153 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1969,7 +1969,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
-	ixgbe_reset(adapter);
+	if (!pci_channel_offline(adapter->pdev))
+		ixgbe_reset(adapter);
 	ixgbe_clean_all_tx_rings(adapter);
 	ixgbe_clean_all_rx_rings(adapter);
 
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 6797ed069f1f..63cd67b931e7 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -71,14 +71,18 @@ static irqreturn_t netxen_intr(int irq, void *data);
 static irqreturn_t netxen_msi_intr(int irq, void *data);
 
 /*  PCI Device ID Table  */
+#define ENTRY(device) \
+	{PCI_DEVICE(0x4040, (device)), \
+	.class = PCI_CLASS_NETWORK_ETHERNET << 8, .class_mask = ~0}
+
 static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
-	{PCI_DEVICE(0x4040, 0x0001), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0002), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0003), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0004), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0005), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0024), PCI_DEVICE_CLASS(0x020000, ~0)},
-	{PCI_DEVICE(0x4040, 0x0025), PCI_DEVICE_CLASS(0x020000, ~0)},
+	ENTRY(0x0001),
+	ENTRY(0x0002),
+	ENTRY(0x0003),
+	ENTRY(0x0004),
+	ENTRY(0x0005),
+	ENTRY(0x0024),
+	ENTRY(0x0025),
 	{0,}
 };
 
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 3b2a6c598088..993d87c9296f 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -277,7 +277,7 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
 	*tcph = tcp_hdr(skb);
 
 	/* check if ip header and tcp header are complete */
-	if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+	if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
 		return -1;
 
 	*hdr_flags = LRO_IPV4 | LRO_TCP;
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index ce95c5d168fe..70d012e90dcf 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -525,12 +525,14 @@ static int axnet_open(struct net_device *dev)
     int ret;
     axnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
+    unsigned int nic_base = dev->base_addr;
     
     DEBUG(2, "axnet_open('%s')\n", dev->name);
 
     if (!pcmcia_dev_present(link))
 	return -ENODEV;
 
+    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
     if (ret)
 	    return ret;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index fd8158a86f64..2d4c4ad89b8d 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -969,6 +969,7 @@ static int pcnet_open(struct net_device *dev)
     int ret;
     pcnet_dev_t *info = PRIV(dev);
     struct pcmcia_device *link = info->p_dev;
+    unsigned int nic_base = dev->base_addr;
 
     DEBUG(2, "pcnet_open('%s')\n", dev->name);
 
@@ -976,6 +977,8 @@ static int pcnet_open(struct net_device *dev)
 	return -ENODEV;
 
     set_misc_reg(dev);
+
+    outb_p(0xFF, nic_base + EN0_ISR); /* Clear bogus intr. */
     ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
     if (ret)
 	    return ret;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index b7f7b2227d56..bccee68bd48a 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -3701,7 +3701,9 @@ static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
 		printk(KERN_ERR PFX
 				"%s: Driver up/down cycle failed, "
 				"closing device\n",qdev->ndev->name);
+		rtnl_lock();
 		dev_close(qdev->ndev);
+		rtnl_unlock();
 		return -1;
 	}
 	return 0;
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 858b191517b3..504a48ff73c8 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -273,7 +273,7 @@ static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
 	dma_addr_t mapping = desc_dma;
 
 	while (size-- > 0) {
-		mapping += sizeof(sizeof(*desc));
+		mapping += sizeof(*desc);
 		desc->ndesc = cpu_to_le32(mapping);
 		desc->vndescp = desc + 1;
 		desc++;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index b5c1e663417d..ae7b697456b4 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2625,9 +2625,7 @@ static int fill_rx_buffers(struct ring_info *ring)
 			rxdp1->Buffer0_ptr = pci_map_single
 			    (ring->pdev, skb->data, size - NET_IP_ALIGN,
 				PCI_DMA_FROMDEVICE);
-			if( (rxdp1->Buffer0_ptr == 0) ||
-				(rxdp1->Buffer0_ptr ==
-				DMA_ERROR_CODE))
+			if(pci_dma_mapping_error(rxdp1->Buffer0_ptr))
 				goto pci_map_failed;
 
 			rxdp->Control_2 =
@@ -2657,6 +2655,7 @@ static int fill_rx_buffers(struct ring_info *ring)
 			skb->data = (void *) (unsigned long)tmp;
 			skb_reset_tail_pointer(skb);
 
+			/* AK: check is wrong. 0 can be valid dma address */
 			if (!(rxdp3->Buffer0_ptr))
 				rxdp3->Buffer0_ptr =
 				   pci_map_single(ring->pdev, ba->ba_0,
@@ -2665,8 +2664,7 @@ static int fill_rx_buffers(struct ring_info *ring)
 				pci_dma_sync_single_for_device(ring->pdev,
 				(dma_addr_t) rxdp3->Buffer0_ptr,
 				    BUF0_LEN, PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer0_ptr == 0) ||
-				(rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
+			if (pci_dma_mapping_error(rxdp3->Buffer0_ptr))
 				goto pci_map_failed;
 
 			rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
@@ -2681,18 +2679,17 @@ static int fill_rx_buffers(struct ring_info *ring)
 				(ring->pdev, skb->data, ring->mtu + 4,
 						PCI_DMA_FROMDEVICE);
 
-				if( (rxdp3->Buffer2_ptr == 0) ||
-					(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
+				if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
 					goto pci_map_failed;
 
+				/* AK: check is wrong */
 				if (!rxdp3->Buffer1_ptr)
 					rxdp3->Buffer1_ptr =
 						pci_map_single(ring->pdev,
 						ba->ba_1, BUF1_LEN,
 						PCI_DMA_FROMDEVICE);
 
-				if( (rxdp3->Buffer1_ptr == 0) ||
-					(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+				if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
 					pci_unmap_single
 						(ring->pdev,
 						(dma_addr_t)(unsigned long)
@@ -4264,16 +4261,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 		txdp->Buffer_Pointer = pci_map_single(sp->pdev,
 					fifo->ufo_in_band_v,
 					sizeof(u64), PCI_DMA_TODEVICE);
-		if((txdp->Buffer_Pointer == 0) ||
-			(txdp->Buffer_Pointer == DMA_ERROR_CODE))
+		if (pci_dma_mapping_error(txdp->Buffer_Pointer))
 			goto pci_map_failed;
 		txdp++;
 	}
 
 	txdp->Buffer_Pointer = pci_map_single
 	    (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
-	if((txdp->Buffer_Pointer == 0) ||
-		(txdp->Buffer_Pointer == DMA_ERROR_CODE))
+	if (pci_dma_mapping_error(txdp->Buffer_Pointer))
 		goto pci_map_failed;
 
 	txdp->Host_Control = (unsigned long) skb;
@@ -6884,10 +6879,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
 				pci_map_single( sp->pdev, (*skb)->data,
 					size - NET_IP_ALIGN,
 					PCI_DMA_FROMDEVICE);
-			if( (rxdp1->Buffer0_ptr == 0) ||
-				(rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp1->Buffer0_ptr))
 				goto memalloc_failed;
-			}
 			rxdp->Host_Control = (unsigned long) (*skb);
 		}
 	} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
@@ -6913,15 +6906,12 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
 				pci_map_single(sp->pdev, (*skb)->data,
 					       dev->mtu + 4,
 					       PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer2_ptr == 0) ||
-				(rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp3->Buffer2_ptr))
 				goto memalloc_failed;
-			}
 			rxdp3->Buffer0_ptr = *temp0 =
 				pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
 						PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer0_ptr == 0) ||
-				(rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp3->Buffer0_ptr)) {
 				pci_unmap_single (sp->pdev,
 					(dma_addr_t)rxdp3->Buffer2_ptr,
 					dev->mtu + 4, PCI_DMA_FROMDEVICE);
@@ -6933,8 +6923,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
 			rxdp3->Buffer1_ptr = *temp1 =
 				pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
 						PCI_DMA_FROMDEVICE);
-			if( (rxdp3->Buffer1_ptr == 0) ||
-				(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+			if (pci_dma_mapping_error(rxdp3->Buffer1_ptr)) {
 				pci_unmap_single (sp->pdev,
 					(dma_addr_t)rxdp3->Buffer0_ptr,
 					BUF0_LEN, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 4706f7f9acb6..1827b6686c98 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -75,10 +75,6 @@ static int debug_level = ERR_DBG;
 /* DEBUG message print. */
 #define DBG_PRINT(dbg_level, args...)  if(!(debug_level<dbg_level)) printk(args)
 
-#ifndef DMA_ERROR_CODE
-#define DMA_ERROR_CODE          (~(dma_addr_t)0x0)
-#endif
-
 /* Protocol assist features of the NIC */
 #define L3_CKSUM_OK 0xFFFF
 #define L4_CKSUM_OK 0xFFFF
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 10e4e85da3fc..b07b8cbadeaf 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1394,6 +1394,7 @@ tc35815_open(struct net_device *dev)
 	tc35815_chip_init(dev);
 	spin_unlock_irq(&lp->lock);
 
+	netif_carrier_off(dev);
 	/* schedule a link state check */
 	phy_start(lp->phy_dev);
 
@@ -1735,7 +1736,6 @@ tc35815_rx(struct net_device *dev)
 			skb = lp->rx_skbs[cur_bd].skb;
 			prefetch(skb->data);
 			lp->rx_skbs[cur_bd].skb = NULL;
-			lp->fbl_count--;
 			pci_unmap_single(lp->pci_dev,
 					 lp->rx_skbs[cur_bd].skb_dma,
 					 RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -1791,6 +1791,7 @@ tc35815_rx(struct net_device *dev)
 #ifdef TC35815_USE_PACKEDBUFFER
 			while (lp->fbl_curid != id)
 #else
+			lp->fbl_count--;
 			while (lp->fbl_count < RX_BUF_NUM)
 #endif
 			{
@@ -2453,6 +2454,7 @@ static int tc35815_resume(struct pci_dev *pdev)
 		return 0;
 	pci_set_power_state(pdev, PCI_D0);
 	tc35815_restart(dev);
+	netif_carrier_off(dev);
 	if (lp->phy_dev)
 		phy_start(lp->phy_dev);
 	netif_device_attach(dev);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 7ab94c825b57..b9018bfa0a97 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -602,6 +602,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 	tun->attached = 1;
 	get_net(dev_net(tun->dev));
 
+	/* Make sure persistent devices do not get stuck in
+	 * xoff state.
+	 */
+	if (netif_running(tun->dev))
+		netif_wake_queue(tun->dev);
+
 	strcpy(ifr->ifr_name, tun->dev->name);
 	return 0;
 
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 520bb0b1a9a2..6d35155c7145 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1008,6 +1008,7 @@ static int fr_rx(struct sk_buff *skb)
 		stats->rx_bytes += skb->len;
 		if (pvc->state.becn)
 			stats->rx_compressed++;
+		skb->dev = dev;
 		netif_rx(skb);
 		return NET_RX_SUCCESS;
 	} else {
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 249e18053d5f..069f8bb0a99f 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -32,6 +32,7 @@
 #include <linux/x25.h>
 #include <linux/lapb.h>
 #include <linux/init.h>
+#include <linux/rtnetlink.h>
 #include "x25_asy.h"
 
 #include <net/x25device.h>
@@ -601,8 +602,10 @@ static void x25_asy_close_tty(struct tty_struct *tty)
 	if (!sl || sl->magic != X25_ASY_MAGIC)
 		return;
 
+	rtnl_lock();
 	if (sl->dev->flags & IFF_UP)
 		dev_close(sl->dev);
+	rtnl_unlock();
 
 	tty->disc_data = NULL;
 	sl->tty = NULL;
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index 36a9c42df835..76f4c7bad8b8 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -72,6 +72,9 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
 	struct b43_wldev *dev = led->dev;
 	bool radio_enabled;
 
+	if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
+		return;
+
 	/* Checking the radio-enabled status here is slightly racy,
 	 * but we want to avoid the locking overhead and we don't care
 	 * whether the LED has the wrong state for a second. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index fa4b0d8b74a2..a70827793086 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2883,12 +2883,11 @@ static int b43_op_tx(struct ieee80211_hw *hw,
 
 	if (unlikely(skb->len < 2 + 2 + 6)) {
 		/* Too short, this can't be a valid frame. */
-		dev_kfree_skb_any(skb);
-		return NETDEV_TX_OK;
+		goto drop_packet;
 	}
 	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
 	if (unlikely(!dev))
-		return NETDEV_TX_BUSY;
+		goto drop_packet;
 
 	/* Transmissions on seperate queues can run concurrently. */
 	read_lock_irqsave(&wl->tx_lock, flags);
@@ -2904,7 +2903,12 @@ static int b43_op_tx(struct ieee80211_hw *hw,
 	read_unlock_irqrestore(&wl->tx_lock, flags);
 
 	if (unlikely(err))
-		return NETDEV_TX_BUSY;
+		goto drop_packet;
+	return NETDEV_TX_OK;
+
+drop_packet:
+	/* We can not transmit this packet. Drop it. */
+	dev_kfree_skb_any(skb);
 	return NETDEV_TX_OK;
 }
 
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index c990f87b107a..93ddc1cbcc8b 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -876,6 +876,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 	if (!ring)
 		goto out;
 	ring->type = type;
+	ring->dev = dev;
 
 	nr_slots = B43legacy_RXRING_SLOTS;
 	if (for_tx)
@@ -922,7 +923,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
 				 DMA_TO_DEVICE);
 	}
 
-	ring->dev = dev;
 	ring->nr_slots = nr_slots;
 	ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index);
 	ring->index = controller_index;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 204077c13870..3e612d0a13e8 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2378,8 +2378,10 @@ static int b43legacy_op_tx(struct ieee80211_hw *hw,
 	} else
 		err = b43legacy_dma_tx(dev, skb, ctl);
 out:
-	if (unlikely(err))
-		return NETDEV_TX_BUSY;
+	if (unlikely(err)) {
+		/* Drop the packet. */
+		dev_kfree_skb_any(skb);
+	}
 	return NETDEV_TX_OK;
 }
 
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index 4fd73809602e..020f450e9dba 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -64,7 +64,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
 	int hdrlen, phdrlen, head_need, tail_need;
 	u16 fc;
 	int prism_header, ret;
-	struct ieee80211_hdr_4addr *hdr;
+	struct ieee80211_hdr_4addr *fhdr;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -83,8 +83,8 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
 		phdrlen = 0;
 	}
 
-	hdr = (struct ieee80211_hdr_4addr *) skb->data;
-	fc = le16_to_cpu(hdr->frame_ctl);
+	fhdr = (struct ieee80211_hdr_4addr *) skb->data;
+	fc = le16_to_cpu(fhdr->frame_ctl);
 
 	if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
 		printk(KERN_DEBUG "%s: dropped management frame with header "
@@ -551,7 +551,7 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
 	     hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
 	     hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
 		/* RA (or BSSID) is not ours - drop */
-		PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
+		PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
 		       "not own or broadcast %s=%s\n",
 		       local->dev->name,
 		       fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 0acd9589c48c..ab981afd481d 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1930,7 +1930,7 @@ static void handle_pspoll(local_info_t *local,
 		PDEBUG(DEBUG_PS, "   PSPOLL and AID[15:14] not set\n");
 		return;
 	}
-	aid &= ~BIT(15) & ~BIT(14);
+	aid &= ~(BIT(15) | BIT(14));
 	if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
 		PDEBUG(DEBUG_PS, "   invalid aid=%d\n", aid);
 		return;
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index ed4317a17cbb..3b4e55cf33cd 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -533,10 +533,10 @@ static void prism2_detach(struct pcmcia_device *link)
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
 #define CFG_CHECK2(fn, retf) \
-do { int ret = (retf); \
-if (ret != 0) { \
-	PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
-	cs_error(link, fn, ret); \
+do { int _ret = (retf); \
+if (_ret != 0) { \
+	PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", _ret); \
+	cs_error(link, fn, _ret); \
 	goto next_entry; \
 } \
 } while (0)
@@ -777,8 +777,10 @@ static int hostap_cs_suspend(struct pcmcia_device *link)
 	int dev_open = 0;
 	struct hostap_interface *iface = NULL;
 
-	if (dev)
-		iface = netdev_priv(dev);
+	if (!dev)
+		return -ENODEV;
+
+	iface = netdev_priv(dev);
 
 	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
 	if (iface && iface->local)
@@ -798,8 +800,10 @@ static int hostap_cs_resume(struct pcmcia_device *link)
 	int dev_open = 0;
 	struct hostap_interface *iface = NULL;
 
-	if (dev)
-		iface = netdev_priv(dev);
+	if (!dev)
+		return -ENODEV;
+
+	iface = netdev_priv(dev);
 
 	PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
 
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index cdf90c40f11b..936f52e3d95c 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2835,7 +2835,7 @@ static void hostap_passive_scan(unsigned long data)
 {
 	local_info_t *local = (local_info_t *) data;
 	struct net_device *dev = local->dev;
-	u16 channel;
+	u16 chan;
 
 	if (local->passive_scan_interval <= 0)
 		return;
@@ -2872,11 +2872,11 @@ static void hostap_passive_scan(unsigned long data)
 
 		printk(KERN_DEBUG "%s: passive scan channel %d\n",
 		       dev->name, local->passive_scan_channel);
-		channel = local->passive_scan_channel;
+		chan = local->passive_scan_channel;
 		local->passive_scan_state = PASSIVE_SCAN_WAIT;
 		local->passive_scan_timer.expires = jiffies + HZ / 10;
 	} else {
-		channel = local->channel;
+		chan = local->channel;
 		local->passive_scan_state = PASSIVE_SCAN_LISTEN;
 		local->passive_scan_timer.expires = jiffies +
 			local->passive_scan_interval * HZ;
@@ -2884,9 +2884,9 @@ static void hostap_passive_scan(unsigned long data)
 
 	if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
 				 (HFA384X_TEST_CHANGE_CHANNEL << 8),
-				 channel, NULL, 0))
+				 chan, NULL, 0))
 		printk(KERN_ERR "%s: passive scan channel set %d "
-		       "failed\n", dev->name, channel);
+		       "failed\n", dev->name, chan);
 
 	add_timer(&local->passive_scan_timer);
 }
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index f7aec9309d04..a38e85f334df 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -594,7 +594,8 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
 }
 
 
-int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+static int hostap_80211_header_parse(const struct sk_buff *skb,
+				     unsigned char *haddr)
 {
 	struct hostap_interface *iface = netdev_priv(skb->dev);
 	local_info_t *local = iface->local;
@@ -857,7 +858,6 @@ const struct header_ops hostap_80211_ops = {
 	.rebuild	= eth_rebuild_header,
 	.cache		= eth_header_cache,
 	.cache_update	= eth_header_cache_update,
-
 	.parse		= hostap_80211_header_parse,
 };
 EXPORT_SYMBOL(hostap_80211_ops);
@@ -1150,7 +1150,6 @@ EXPORT_SYMBOL(hostap_set_roaming);
 EXPORT_SYMBOL(hostap_set_auth_algs);
 EXPORT_SYMBOL(hostap_dump_rx_header);
 EXPORT_SYMBOL(hostap_dump_tx_header);
-EXPORT_SYMBOL(hostap_80211_header_parse);
 EXPORT_SYMBOL(hostap_80211_get_hdrlen);
 EXPORT_SYMBOL(hostap_get_stats);
 EXPORT_SYMBOL(hostap_setup_dev);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 62a3d8f8563e..55ac850744b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -449,7 +449,7 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
 
 	if (print_summary) {
 		char *title;
-		u32 rate;
+		int rate;
 
 		if (hundred)
 			title = "100Frames";
@@ -487,7 +487,7 @@ static void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
 		 *    but you can hack it to show more, if you'd like to. */
 		if (dataframe)
 			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
-				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+				     "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
 				     title, fc, header->addr1[5],
 				     length, rssi, channel, rate);
 		else {
@@ -588,8 +588,12 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
 
 	if (rate == -1)
 		iwl3945_rt->rt_rate = 0;
-	else
+	else {
+		if (stats->band == IEEE80211_BAND_5GHZ)
+			rate += IWL_FIRST_OFDM_RATE;
+
 		iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
+	}
 
 	/* antenna number */
 	antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index bf19eb8aafd0..de330ae0ca95 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3528,8 +3528,12 @@ static void iwl4965_add_radiotap(struct iwl_priv *priv,
 
 	if (rate == -1)
 		iwl4965_rt->rt_rate = 0;
-	else
+	else {
+		if (stats->band == IEEE80211_BAND_5GHZ)
+			rate += IWL_FIRST_OFDM_RATE;
+
 		iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
+	}
 
 	/*
 	 * "antenna number"
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 13925b627e3b..6027e1119c3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2227,7 +2227,10 @@ static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
 	}
 
 	IWL_DEBUG_INFO("Starting scan...\n");
-	priv->scan_bands = 2;
+	if (priv->cfg->sku & IWL_SKU_G)
+		priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+	if (priv->cfg->sku & IWL_SKU_A)
+		priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
 	set_bit(STATUS_SCANNING, &priv->status);
 	priv->scan_start = jiffies;
 	priv->scan_pass_start = priv->scan_start;
@@ -3352,13 +3355,18 @@ static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv,
 	cancel_delayed_work(&priv->scan_check);
 
 	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-		       (priv->scan_bands == 2) ? "2.4" : "5.2",
+		       (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+							"2.4" : "5.2",
 		       jiffies_to_msecs(elapsed_jiffies
 					(priv->scan_pass_start, jiffies)));
 
-	/* Remove this scanned band from the list
-	 * of pending bands to scan */
-	priv->scan_bands--;
+	/* Remove this scanned band from the list of pending
+	 * bands to scan, band G precedes A in order of scanning
+	 * as seen in iwl3945_bg_request_scan */
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+	else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
 	/* If a request to abort was given, or the scan did not succeed
 	 * then we reset the scan state machine and terminate,
@@ -4972,7 +4980,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv,
 
 		ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel);
 		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
 				       scan_ch->channel);
 			continue;
 		}
@@ -6315,21 +6323,16 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 
 	/* flags + rate selection */
 
-	switch (priv->scan_bands) {
-	case 2:
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
 		scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
 		scan->good_CRC_th = 0;
 		band = IEEE80211_BAND_2GHZ;
-		break;
-
-	case 1:
+	} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
 		scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
 		scan->good_CRC_th = IWL_GOOD_CRC_TH;
 		band = IEEE80211_BAND_5GHZ;
-		break;
-
-	default:
+	} else {
 		IWL_WARNING("Invalid scan band count\n");
 		goto done;
 	}
@@ -6684,7 +6687,8 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
 		IWL_DEBUG_MAC80211("leave - monitor\n");
-		return -1;
+		dev_kfree_skb_any(skb);
+		return 0;
 	}
 
 	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
@@ -6770,7 +6774,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
 	ch_info = iwl3945_get_channel_info(priv, conf->channel->band,
 					   conf->channel->hw_value);
 	if (!is_channel_valid(ch_info)) {
-		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this band.\n",
 			       conf->channel->hw_value, conf->channel->band);
 		IWL_DEBUG_MAC80211("leave - invalid channel\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 883b42f7e998..0bd55bb19739 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -1774,7 +1774,10 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv)
 	}
 
 	IWL_DEBUG_INFO("Starting scan...\n");
-	priv->scan_bands = 2;
+	if (priv->cfg->sku & IWL_SKU_G)
+		priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+	if (priv->cfg->sku & IWL_SKU_A)
+		priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
 	set_bit(STATUS_SCANNING, &priv->status);
 	priv->scan_start = jiffies;
 	priv->scan_pass_start = priv->scan_start;
@@ -3023,8 +3026,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
 
 	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
 	if (index != -1) {
-		int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
 #ifdef CONFIG_IWL4965_HT
+		int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
+
 		if (tid != MAX_TID_COUNT)
 			priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
 		if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
@@ -3276,13 +3280,18 @@ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
 	cancel_delayed_work(&priv->scan_check);
 
 	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-		       (priv->scan_bands == 2) ? "2.4" : "5.2",
+		       (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+						"2.4" : "5.2",
 		       jiffies_to_msecs(elapsed_jiffies
 					(priv->scan_pass_start, jiffies)));
 
-	/* Remove this scanned band from the list
-	 * of pending bands to scan */
-	priv->scan_bands--;
+	/* Remove this scanned band from the list of pending
+	 * bands to scan, band G precedes A in order of scanning
+	 * as seen in iwl_bg_request_scan */
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+	else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+		priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
 	/* If a request to abort was given, or the scan did not succeed
 	 * then we reset the scan state machine and terminate,
@@ -3292,7 +3301,7 @@ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
 		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
 	} else {
 		/* If there are more bands on this scan pass reschedule */
-		if (priv->scan_bands > 0)
+		if (priv->scan_bands)
 			goto reschedule;
 	}
 
@@ -4635,10 +4644,9 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
 
 		scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq);
 
-		ch_info = iwl_get_channel_info(priv, band,
-					 scan_ch->channel);
+		ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
 		if (!is_channel_valid(ch_info)) {
-			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
 				       scan_ch->channel);
 			continue;
 		}
@@ -5830,8 +5838,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
 	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
 
-	switch (priv->scan_bands) {
-	case 2:
+	if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
 		scan->tx_cmd.rate_n_flags =
 				iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
@@ -5839,17 +5846,13 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
 
 		scan->good_CRC_th = 0;
 		band = IEEE80211_BAND_2GHZ;
-		break;
-
-	case 1:
+	} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
 		scan->tx_cmd.rate_n_flags =
 				iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
 				RATE_MCS_ANT_B_MSK);
 		scan->good_CRC_th = IWL_GOOD_CRC_TH;
 		band = IEEE80211_BAND_5GHZ;
-		break;
-
-	default:
+	} else {
 		IWL_WARNING("Invalid scan band count\n");
 		goto done;
 	}
@@ -6234,7 +6237,8 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
 		IWL_DEBUG_MAC80211("leave - monitor\n");
-		return -1;
+		dev_kfree_skb_any(skb);
+		return 0;
 	}
 
 	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 8032df72aaab..36288b29abf7 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -925,6 +925,7 @@ static struct usb_driver if_usb_driver = {
 	.id_table = if_usb_table,
 	.suspend = if_usb_suspend,
 	.resume = if_usb_resume,
+	.reset_resume = if_usb_resume,
 };
 
 static int __init if_usb_init_module(void)
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index d448c9702a0f..387d4878af2f 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -567,11 +567,11 @@ static int lbs_process_bss(struct bss_descriptor *bss,
 	pos += 8;
 
 	/* beacon interval is 2 bytes long */
-	bss->beaconperiod = le16_to_cpup((void *) pos);
+	bss->beaconperiod = get_unaligned_le16(pos);
 	pos += 2;
 
 	/* capability information is 2 bytes long */
-	bss->capability = le16_to_cpup((void *) pos);
+	bss->capability = get_unaligned_le16(pos);
 	lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
 	pos += 2;
 
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 762e85bef55d..e43bae97ed8f 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -290,7 +290,7 @@ islpci_monitor_rx(islpci_private *priv, struct sk_buff **skb)
 
 		avs->version = cpu_to_be32(P80211CAPTURE_VERSION);
 		avs->length = cpu_to_be32(sizeof (struct avs_80211_1_header));
-		avs->mactime = cpu_to_be64(le64_to_cpu(clock));
+		avs->mactime = cpu_to_be64(clock);
 		avs->hosttime = cpu_to_be64(jiffies);
 		avs->phytype = cpu_to_be32(6);	/*OFDM: 6 for (g), 8 for (a) */
 		avs->channel = cpu_to_be32(channel_of_freq(freq));
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 560b9c73c0b9..b36ed1c6c746 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -731,6 +731,17 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
 			   (rt2x00dev->rx->data_size / 128));
 	rt2x00pci_register_write(rt2x00dev, CSR9, reg);
 
+	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+	rt2x00_set_field32(&reg, CSR14_TCFP, 0);
+	rt2x00_set_field32(&reg, CSR14_TATIMW, 0);
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
+	rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
 	rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
 
 	rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index a5ed54b69262..f7731fb82555 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -824,6 +824,17 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
 	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
 
+	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+	rt2x00_set_field32(&reg, CSR14_TCFP, 0);
+	rt2x00_set_field32(&reg, CSR14_TATIMW, 0);
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
+	rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
 	rt2x00pci_register_write(rt2x00dev, CNT3, 0);
 
 	rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index fdbd0ef2be4b..d90512f97b39 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -138,11 +138,8 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the data into the BBP.
@@ -155,6 +152,13 @@ static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
 }
 
 static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -168,10 +172,8 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-		return;
-	}
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the request into the BBP.
@@ -186,17 +188,21 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
-		*value = 0xff;
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+		goto exit_fail;
 
 	rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
 	*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
 
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+	*value = 0xff;
 }
 
 static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -795,6 +801,13 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1_VALID, 0);
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
 
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f);
 	rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 611d98320593..b4bf1e09cf9a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -821,6 +821,7 @@ struct rt2x00_dev {
 	/*
 	 * Scheduled work.
 	 */
+	struct workqueue_struct *workqueue;
 	struct work_struct intf_work;
 	struct work_struct filter_work;
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2673d568bcac..c997d4f28ab3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -75,7 +75,7 @@ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
 
 	rt2x00lib_reset_link_tuner(rt2x00dev);
 
-	queue_delayed_work(rt2x00dev->hw->workqueue,
+	queue_delayed_work(rt2x00dev->workqueue,
 			   &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
@@ -137,14 +137,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
 		return;
 
 	/*
-	 * Stop all scheduled work.
-	 */
-	if (work_pending(&rt2x00dev->intf_work))
-		cancel_work_sync(&rt2x00dev->intf_work);
-	if (work_pending(&rt2x00dev->filter_work))
-		cancel_work_sync(&rt2x00dev->filter_work);
-
-	/*
 	 * Stop the TX queues.
 	 */
 	ieee80211_stop_queues(rt2x00dev->hw);
@@ -398,8 +390,8 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
 	 * Increase tuner counter, and reschedule the next link tuner run.
 	 */
 	rt2x00dev->link.count++;
-	queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
-			   LINK_TUNE_INTERVAL);
+	queue_delayed_work(rt2x00dev->workqueue,
+			   &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
 }
 
 static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
@@ -433,6 +425,15 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 
 	spin_unlock(&intf->lock);
 
+	/*
+	 * It is possible the radio was disabled while the work had been
+	 * scheduled. If that happens we should return here immediately,
+	 * note that in the spinlock protected area above the delayed_flags
+	 * have been cleared correctly.
+	 */
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
 	if (delayed_flags & DELAYED_UPDATE_BEACON) {
 		skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control);
 		if (skb && rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
@@ -441,7 +442,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
 	}
 
 	if (delayed_flags & DELAYED_CONFIG_ERP)
-		rt2x00lib_config_erp(rt2x00dev, intf, &intf->conf);
+		rt2x00lib_config_erp(rt2x00dev, intf, &conf);
 
 	if (delayed_flags & DELAYED_LED_ASSOC)
 		rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated);
@@ -487,7 +488,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
 						   rt2x00lib_beacondone_iter,
 						   rt2x00dev);
 
-	queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+	queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
 
@@ -1130,6 +1131,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Initialize configuration work.
 	 */
+	rt2x00dev->workqueue = create_singlethread_workqueue("rt2x00lib");
+	if (!rt2x00dev->workqueue)
+		goto exit;
+
 	INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
 	INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
 	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
@@ -1190,6 +1195,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
 	rt2x00leds_unregister(rt2x00dev);
 
 	/*
+	 * Stop all queued work. Note that most tasks will already be halted
+	 * during rt2x00lib_disable_radio() and rt2x00lib_uninitialize().
+	 */
+	flush_workqueue(rt2x00dev->workqueue);
+	destroy_workqueue(rt2x00dev->workqueue);
+
+	/*
 	 * Free ieee80211_hw memory.
 	 */
 	rt2x00lib_remove_hw(rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 87e280a21971..9cb023edd2e9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -428,7 +428,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
 	if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
 		rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
 	else
-		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->filter_work);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
 
@@ -509,7 +509,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
 	memcpy(&intf->conf, bss_conf, sizeof(*bss_conf));
 	if (delayed) {
 		intf->delayed_flags |= delayed;
-		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+		queue_work(rt2x00dev->workqueue, &rt2x00dev->intf_work);
 	}
 	spin_unlock(&intf->lock);
 }
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 14bc7b281659..c3afb5cbe807 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1201,6 +1201,15 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
 
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
 
 	rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index fff8386e816b..46e9e081fbf1 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -134,11 +134,8 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the data into the BBP.
@@ -151,6 +148,13 @@ static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 
 	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
 }
 
 static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
@@ -164,11 +168,8 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-		mutex_unlock(&rt2x00dev->usb_cache_mutex);
-		return;
-	}
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+		goto exit_fail;
 
 	/*
 	 * Write the request into the BBP.
@@ -184,14 +185,19 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
-	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
-		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
-		*value = 0xff;
-		return;
-	}
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+		goto exit_fail;
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
 	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return;
+
+exit_fail:
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+	*value = 0xff;
 }
 
 static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
@@ -1000,6 +1006,15 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
 	rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
 
+	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
 	rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
 
 	rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 418606ac1c3b..694e95d35fd4 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -765,6 +765,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 	mac->type = IEEE80211_IF_TYPE_INVALID;
+	zd_set_beacon_interval(&mac->chip, 0);
 	zd_write_mac_addr(&mac->chip, NULL);
 }
 
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 8941f5eb96c2..6cdad9764604 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -64,6 +64,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index ec8f7002b09d..39bb96b413ef 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -178,8 +178,7 @@ static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size,
 	int ret;
 	int begin, end, i;
 
-	if (pos < 0 || pos > PCI_VPD_PCI22_SIZE ||
-	    size > PCI_VPD_PCI22_SIZE  - pos)
+	if (pos < 0 || pos > vpd->base.len || size > vpd->base.len  - pos)
 		return -EINVAL;
 	if (size == 0)
 		return 0;
@@ -223,8 +222,8 @@ static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size,
 	u32 val;
 	int ret;
 
-	if (pos < 0 || pos > PCI_VPD_PCI22_SIZE || pos & 3 ||
-	    size > PCI_VPD_PCI22_SIZE - pos || size < 4)
+	if (pos < 0 || pos > vpd->base.len || pos & 3 ||
+	    size > vpd->base.len - pos || size < 4)
 		return -EINVAL;
 
 	val = (u8) *buf++;
@@ -255,11 +254,6 @@ out:
 	return 4;
 }
 
-static int pci_vpd_pci22_get_size(struct pci_dev *dev)
-{
-	return PCI_VPD_PCI22_SIZE;
-}
-
 static void pci_vpd_pci22_release(struct pci_dev *dev)
 {
 	kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
@@ -268,7 +262,6 @@ static void pci_vpd_pci22_release(struct pci_dev *dev)
 static struct pci_vpd_ops pci_vpd_pci22_ops = {
 	.read = pci_vpd_pci22_read,
 	.write = pci_vpd_pci22_write,
-	.get_size = pci_vpd_pci22_get_size,
 	.release = pci_vpd_pci22_release,
 };
 
@@ -284,6 +277,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
 	if (!vpd)
 		return -ENOMEM;
 
+	vpd->base.len = PCI_VPD_PCI22_SIZE;
 	vpd->base.ops = &pci_vpd_pci22_ops;
 	spin_lock_init(&vpd->lock);
 	vpd->cap = cap;
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 648596d469f6..91156f85a926 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -700,9 +700,10 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
 				cleanup_p2p_bridge, NULL, NULL);
 
-	if (!(bridge = acpiphp_handle_to_bridge(handle)))
-		return AE_OK;
-	cleanup_bridge(bridge);
+	bridge = acpiphp_handle_to_bridge(handle);
+	if (bridge)
+		cleanup_bridge(bridge);
+
 	return AE_OK;
 }
 
@@ -715,9 +716,19 @@ static void remove_bridge(acpi_handle handle)
 	acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
 				(u32)1, cleanup_p2p_bridge, NULL, NULL);
 
+	/*
+	 * On root bridges with hotplug slots directly underneath (ie,
+	 * no p2p bridge inbetween), we call cleanup_bridge(). 
+	 *
+	 * The else clause cleans up root bridges that either had no
+	 * hotplug slots at all, or had a p2p bridge underneath.
+	 */
 	bridge = acpiphp_handle_to_bridge(handle);
 	if (bridge)
 		cleanup_bridge(bridge);
+	else
+		acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+					   handle_hotplug_event_bridge);
 }
 
 static struct pci_dev * get_apic_pci_info(acpi_handle handle)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 6f3c7446c329..9c718583a237 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -736,9 +736,9 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
 		attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
 		if (attr) {
 			pdev->vpd->attr = attr;
-			attr->size = pdev->vpd->ops->get_size(pdev);
+			attr->size = pdev->vpd->len;
 			attr->attr.name = "vpd";
-			attr->attr.mode = S_IRUGO | S_IWUSR;
+			attr->attr.mode = S_IRUSR | S_IWUSR;
 			attr->read = pci_read_vpd;
 			attr->write = pci_write_vpd;
 			retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0a497c1b4227..00408c97e5fc 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -21,11 +21,11 @@ extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
 struct pci_vpd_ops {
 	int (*read)(struct pci_dev *dev, int pos, int size, char *buf);
 	int (*write)(struct pci_dev *dev, int pos, int size, const char *buf);
-	int (*get_size)(struct pci_dev *dev);
 	void (*release)(struct pci_dev *dev);
 };
 
 struct pci_vpd {
+	unsigned int len;
 	struct pci_vpd_ops *ops;
 	struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
 };
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index dabb563f51d9..338a3f94b4d4 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1670,6 +1670,48 @@ static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
 
+/*
+ * For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
+ * VPD end tag will hang the device.  This problem was initially
+ * observed when a vpd entry was created in sysfs
+ * ('/sys/bus/pci/devices/<id>/vpd').   A read to this sysfs entry
+ * will dump 32k of data.  Reading a full 32k will cause an access
+ * beyond the VPD end tag causing the device to hang.  Once the device
+ * is hung, the bnx2 driver will not be able to reset the device.
+ * We believe that it is legal to read beyond the end tag and
+ * therefore the solution is to limit the read/write length.
+ */
+static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev)
+{
+	/*  Only disable the VPD capability for 5706, 5708, and 5709 rev. A */
+	if ((dev->device == PCI_DEVICE_ID_NX2_5706) ||
+	    (dev->device == PCI_DEVICE_ID_NX2_5708) ||
+	    ((dev->device == PCI_DEVICE_ID_NX2_5709) &&
+	     (dev->revision & 0xf0) == 0x0)) {
+		if (dev->vpd)
+			dev->vpd->len = 0x80;
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5706,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5706S,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5708,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5708S,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5709,
+			 quirk_brcm_570x_limit_vpd);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM,
+			 PCI_DEVICE_ID_NX2_5709S,
+			 quirk_brcm_570x_limit_vpd);
+
 #ifdef CONFIG_PCI_MSI
 /* Some chipsets do not support MSI. We cannot easily rely on setting
  * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
@@ -1685,6 +1727,7 @@ static void __init quirk_disable_all_msi(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
 
 /* Disable MSI on chipsets that are known to not support it */
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index 3ce9f3defc12..956d3e79f6aa 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -101,8 +101,8 @@ static int rio_device_probe(struct device *dev)
 		if (error >= 0) {
 			rdev->driver = rdrv;
 			error = 0;
+		} else
 			rio_dev_put(rdev);
-		}
 	}
 	return error;
 }
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 7e3ad4f3b343..58b7336640ff 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -126,12 +126,25 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 	int err;
 	struct rtc_time before, now;
 	int first_time = 1;
+	unsigned long t_now, t_alm;
+	enum { none, day, month, year } missing = none;
+	unsigned days;
 
-	/* The lower level RTC driver may not be capable of filling
-	 * in all fields of the rtc_time struct (eg. rtc-cmos),
-	 * and so might instead return -1 in some fields.
-	 * We deal with that here by grabbing a current RTC timestamp
-	 * and using values from that for any missing (-1) values.
+	/* The lower level RTC driver may return -1 in some fields,
+	 * creating invalid alarm->time values, for reasons like:
+	 *
+	 *   - The hardware may not be capable of filling them in;
+	 *     many alarms match only on time-of-day fields, not
+	 *     day/month/year calendar data.
+	 *
+	 *   - Some hardware uses illegal values as "wildcard" match
+	 *     values, which non-Linux firmware (like a BIOS) may try
+	 *     to set up as e.g. "alarm 15 minutes after each hour".
+	 *     Linux uses only oneshot alarms.
+	 *
+	 * When we see that here, we deal with it by using values from
+	 * a current RTC timestamp for any missing (-1) values.  The
+	 * RTC driver prevents "periodic alarm" modes.
 	 *
 	 * But this can be racey, because some fields of the RTC timestamp
 	 * may have wrapped in the interval since we read the RTC alarm,
@@ -174,6 +187,10 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 		if (!alarm->enabled)
 			return 0;
 
+		/* full-function RTCs won't have such missing fields */
+		if (rtc_valid_tm(&alarm->time) == 0)
+			return 0;
+
 		/* get the "after" timestamp, to detect wrapped fields */
 		err = rtc_read_time(rtc, &now);
 		if (err < 0)
@@ -183,22 +200,85 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 	} while (   before.tm_min   != now.tm_min
 		 || before.tm_hour  != now.tm_hour
 		 || before.tm_mon   != now.tm_mon
-		 || before.tm_year  != now.tm_year
-		 || before.tm_isdst != now.tm_isdst);
+		 || before.tm_year  != now.tm_year);
 
-	/* Fill in any missing alarm fields using the timestamp */
+	/* Fill in the missing alarm fields using the timestamp; we
+	 * know there's at least one since alarm->time is invalid.
+	 */
 	if (alarm->time.tm_sec == -1)
 		alarm->time.tm_sec = now.tm_sec;
 	if (alarm->time.tm_min == -1)
 		alarm->time.tm_min = now.tm_min;
 	if (alarm->time.tm_hour == -1)
 		alarm->time.tm_hour = now.tm_hour;
-	if (alarm->time.tm_mday == -1)
+
+	/* For simplicity, only support date rollover for now */
+	if (alarm->time.tm_mday == -1) {
 		alarm->time.tm_mday = now.tm_mday;
-	if (alarm->time.tm_mon == -1)
+		missing = day;
+	}
+	if (alarm->time.tm_mon == -1) {
 		alarm->time.tm_mon = now.tm_mon;
-	if (alarm->time.tm_year == -1)
+		if (missing == none)
+			missing = month;
+	}
+	if (alarm->time.tm_year == -1) {
 		alarm->time.tm_year = now.tm_year;
+		if (missing == none)
+			missing = year;
+	}
+
+	/* with luck, no rollover is needed */
+	rtc_tm_to_time(&now, &t_now);
+	rtc_tm_to_time(&alarm->time, &t_alm);
+	if (t_now < t_alm)
+		goto done;
+
+	switch (missing) {
+
+	/* 24 hour rollover ... if it's now 10am Monday, an alarm that
+	 * that will trigger at 5am will do so at 5am Tuesday, which
+	 * could also be in the next month or year.  This is a common
+	 * case, especially for PCs.
+	 */
+	case day:
+		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
+		t_alm += 24 * 60 * 60;
+		rtc_time_to_tm(t_alm, &alarm->time);
+		break;
+
+	/* Month rollover ... if it's the 31th, an alarm on the 3rd will
+	 * be next month.  An alarm matching on the 30th, 29th, or 28th
+	 * may end up in the month after that!  Many newer PCs support
+	 * this type of alarm.
+	 */
+	case month:
+		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
+		do {
+			if (alarm->time.tm_mon < 11)
+				alarm->time.tm_mon++;
+			else {
+				alarm->time.tm_mon = 0;
+				alarm->time.tm_year++;
+			}
+			days = rtc_month_days(alarm->time.tm_mon,
+					alarm->time.tm_year);
+		} while (days < alarm->time.tm_mday);
+		break;
+
+	/* Year rollover ... easy except for leap years! */
+	case year:
+		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
+		do {
+			alarm->time.tm_year++;
+		} while (!rtc_valid_tm(&alarm->time));
+		break;
+
+	default:
+		dev_warn(&rtc->dev, "alarm rollover not handled\n");
+	}
+
+done:
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rtc_read_alarm);
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index 11644c8fca82..abfdfcbaa059 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -55,7 +55,7 @@ struct fm3130 {
 	int			alarm;
 };
 static const struct i2c_device_id fm3130_id[] = {
-	{ "fm3130-rtc", 0 },
+	{ "fm3130", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, fm3130_id);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0fc4c3630780..748a502a6355 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -302,6 +302,7 @@ static int pcf8563_remove(struct i2c_client *client)
 
 static const struct i2c_device_id pcf8563_id[] = {
 	{ "pcf8563", 0 },
+	{ "rtc8564", 0 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pcf8563_id);
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 82f62d25f921..67421b0d3a7b 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -331,14 +331,14 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
 		RCNR = 0;
 	}
 
+	device_init_wakeup(&pdev->dev, 1);
+
 	rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
 				THIS_MODULE);
 
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
 
-	device_init_wakeup(&pdev->dev, 1);
-
 	platform_set_drvdata(pdev, rtc);
 
 	return 0;
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index eaf55945f21b..7dcfba1bbfe1 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -71,6 +71,7 @@
 #define X1205_SR_RTCF		0x01	/* Clock failure */
 #define X1205_SR_WEL		0x02	/* Write Enable Latch */
 #define X1205_SR_RWEL		0x04	/* Register Write Enable */
+#define X1205_SR_AL0		0x20	/* Alarm 0 match */
 
 #define X1205_DTR_DTR0		0x01
 #define X1205_DTR_DTR1		0x02
@@ -78,6 +79,8 @@
 
 #define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
 
+#define X1205_INT_AL0E		0x20	/* Alarm 0 enable */
+
 static struct i2c_driver x1205_driver;
 
 /*
@@ -89,8 +92,8 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
 				unsigned char reg_base)
 {
 	unsigned char dt_addr[2] = { 0, reg_base };
-
 	unsigned char buf[8];
+	int i;
 
 	struct i2c_msg msgs[] = {
 		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
@@ -98,7 +101,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
 	};
 
 	/* read date registers */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -110,6 +113,11 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
 		buf[0], buf[1], buf[2], buf[3],
 		buf[4], buf[5], buf[6], buf[7]);
 
+	/* Mask out the enable bits if these are alarm registers */
+	if (reg_base < X1205_CCR_BASE)
+		for (i = 0; i <= 4; i++)
+			buf[i] &= 0x7F;
+
 	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
 	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
 	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
@@ -138,7 +146,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
 	};
 
 	/* read status register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -147,10 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
 }
 
 static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
-				int datetoo, u8 reg_base)
+			int datetoo, u8 reg_base, unsigned char alm_enable)
 {
-	int i, xfer;
+	int i, xfer, nbytes;
 	unsigned char buf[8];
+	unsigned char rdata[10] = { 0, reg_base };
 
 	static const unsigned char wel[3] = { 0, X1205_REG_SR,
 						X1205_SR_WEL };
@@ -189,6 +198,11 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
 		buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
 	}
 
+	/* If writing alarm registers, set compare bits on registers 0-4 */
+	if (reg_base < X1205_CCR_BASE)
+		for (i = 0; i <= 4; i++)
+			buf[i] |= 0x80;
+
 	/* this sequence is required to unlock the chip */
 	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
 		dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
@@ -200,19 +214,57 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
 		return -EIO;
 	}
 
+
 	/* write register's data */
-	for (i = 0; i < (datetoo ? 8 : 3); i++) {
-		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
+	if (datetoo)
+		nbytes = 8;
+	else
+		nbytes = 3;
+	for (i = 0; i < nbytes; i++)
+		rdata[2+i] = buf[i];
+
+	xfer = i2c_master_send(client, rdata, nbytes+2);
+	if (xfer != nbytes+2) {
+		dev_err(&client->dev,
+			"%s: result=%d addr=%02x, data=%02x\n",
+			__func__,
+			 xfer, rdata[1], rdata[2]);
+		return -EIO;
+	}
+
+	/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
+	if (reg_base < X1205_CCR_BASE) {
+		unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };
+
+		msleep(10);
 
-		xfer = i2c_master_send(client, rdata, 3);
+		/* ...and set or clear the AL0E bit in the INT register */
+
+		/* Need to set RWEL again as the write has cleared it */
+		xfer = i2c_master_send(client, rwel, 3);
 		if (xfer != 3) {
 			dev_err(&client->dev,
-				"%s: xfer=%d addr=%02x, data=%02x\n",
+				"%s: aloe rwel - %d\n",
 				__func__,
-				 xfer, rdata[1], rdata[2]);
+				xfer);
+			return -EIO;
+		}
+
+		if (alm_enable)
+			al0e[2] = X1205_INT_AL0E;
+
+		xfer = i2c_master_send(client, al0e, 3);
+		if (xfer != 3) {
+			dev_err(&client->dev,
+				"%s: al0e - %d\n",
+				__func__,
+				xfer);
 			return -EIO;
 		}
-	};
+
+		/* and wait 10msec again for this write to complete */
+		msleep(10);
+	}
 
 	/* disable further writes */
 	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
@@ -230,9 +282,9 @@ static int x1205_fix_osc(struct i2c_client *client)
 
 	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
 
-	if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
-		dev_err(&client->dev,
-			"unable to restart the oscillator\n");
+	err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
+	if (err < 0)
+		dev_err(&client->dev, "unable to restart the oscillator\n");
 
 	return err;
 }
@@ -248,7 +300,7 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim)
 	};
 
 	/* read dtr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -280,7 +332,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
 	};
 
 	/* read atr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
 		dev_err(&client->dev, "%s: read error\n", __func__);
 		return -EIO;
 	}
@@ -403,14 +455,33 @@ static int x1205_validate_client(struct i2c_client *client)
 
 static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
-	return x1205_get_datetime(to_i2c_client(dev),
-		&alrm->time, X1205_ALM0_BASE);
+	int err;
+	unsigned char intreg, status;
+	static unsigned char int_addr[2] = { 0, X1205_REG_INT };
+	struct i2c_client *client = to_i2c_client(dev);
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, int_addr },        /* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, &intreg },  /* read INT register */
+	};
+
+	/* read interrupt register and status register */
+	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __func__);
+		return -EIO;
+	}
+	err = x1205_get_status(client, &status);
+	if (err == 0) {
+		alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
+		alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
+		err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
+	}
+	return err;
 }
 
 static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
 	return x1205_set_datetime(to_i2c_client(dev),
-		&alrm->time, 1, X1205_ALM0_BASE);
+		&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
 }
 
 static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -422,7 +493,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
 	return x1205_set_datetime(to_i2c_client(dev),
-		tm, 1, X1205_CCR_BASE);
+		tm, 1, X1205_CCR_BASE, 0);
 }
 
 static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index a0b6d414953d..59fbef08d690 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2359,6 +2359,24 @@ void scsi_esp_unregister(struct esp *esp)
 }
 EXPORT_SYMBOL(scsi_esp_unregister);
 
+static int esp_target_alloc(struct scsi_target *starget)
+{
+	struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+	struct esp_target_data *tp = &esp->target[starget->id];
+
+	tp->starget = starget;
+
+	return 0;
+}
+
+static void esp_target_destroy(struct scsi_target *starget)
+{
+	struct esp *esp = shost_priv(dev_to_shost(&starget->dev));
+	struct esp_target_data *tp = &esp->target[starget->id];
+
+	tp->starget = NULL;
+}
+
 static int esp_slave_alloc(struct scsi_device *dev)
 {
 	struct esp *esp = shost_priv(dev->host);
@@ -2370,8 +2388,6 @@ static int esp_slave_alloc(struct scsi_device *dev)
 		return -ENOMEM;
 	dev->hostdata = lp;
 
-	tp->starget = dev->sdev_target;
-
 	spi_min_period(tp->starget) = esp->min_period;
 	spi_max_offset(tp->starget) = 15;
 
@@ -2608,6 +2624,8 @@ struct scsi_host_template scsi_esp_template = {
 	.name			= "esp",
 	.info			= esp_info,
 	.queuecommand		= esp_queuecommand,
+	.target_alloc		= esp_target_alloc,
+	.target_destroy		= esp_target_destroy,
 	.slave_alloc		= esp_slave_alloc,
 	.slave_configure	= esp_slave_configure,
 	.slave_destroy		= esp_slave_destroy,
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 999e91ea7451..e7a3a6554425 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -71,6 +71,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/libata.h>
+#include <linux/hdreg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/processor.h>
@@ -4913,8 +4914,11 @@ static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 	struct ipr_resource_entry *res;
 
 	res = (struct ipr_resource_entry *)sdev->hostdata;
-	if (res && ipr_is_gata(res))
+	if (res && ipr_is_gata(res)) {
+		if (cmd == HDIO_GET_IDENTITY)
+			return -ENOTTY;
 		return ata_scsi_ioctl(sdev, cmd, arg);
+	}
 
 	return -EINVAL;
 }
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a82d2fe80fb5..cbf55d59a54c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -207,6 +207,15 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 	 */
 	blk_execute_rq(req->q, NULL, req, 1);
 
+	/*
+	 * Some devices (USB mass-storage in particular) may transfer
+	 * garbage data together with a residue indicating that the data
+	 * is invalid.  Prevent the garbage from being misinterpreted
+	 * and prevent security leaks by zeroing out the excess data.
+	 */
+	if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
+		memset(buffer + (bufflen - req->data_len), 0, req->data_len);
+
 	ret = req->errors;
  out:
 	blk_put_request(req);
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 45df83b9d847..0fe031f003e7 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -61,7 +61,7 @@ static int ses_probe(struct device *dev)
 	return err;
 }
 
-#define SES_TIMEOUT 30
+#define SES_TIMEOUT (30 * HZ)
 #define SES_RETRIES 3
 
 static int ses_recv_diag(struct scsi_device *sdev, int page_code,
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 1bc00b721e9d..be95e55b228b 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2623,6 +2623,9 @@ static struct console serial8250_console = {
 
 static int __init serial8250_console_init(void)
 {
+	if (nr_uarts > UART_NR)
+		nr_uarts = UART_NR;
+
 	serial8250_isa_init_ports();
 	register_console(&serial8250_console);
 	return 0;
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index c9b64e73c987..42d2e108b679 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1991,7 +1991,9 @@ struct uart_match {
 static int serial_match_port(struct device *dev, void *data)
 {
 	struct uart_match *match = data;
-	dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line;
+	struct tty_driver *tty_drv = match->driver->tty_driver;
+	dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
+		match->port->line;
 
 	return dev->devt == devt; /* Actually, only one tty per port */
 }
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 799337f7fde1..f5b60c70389b 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -167,14 +167,14 @@ spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
 
 	mutex_lock(&spidev->buf_lock);
 	status = spidev_sync_read(spidev, count);
-	if (status == 0) {
+	if (status > 0) {
 		unsigned long	missing;
 
-		missing = copy_to_user(buf, spidev->buffer, count);
-		if (count && missing == count)
+		missing = copy_to_user(buf, spidev->buffer, status);
+		if (missing == status)
 			status = -EFAULT;
 		else
-			status = count - missing;
+			status = status - missing;
 	}
 	mutex_unlock(&spidev->buf_lock);
 
@@ -200,8 +200,6 @@ spidev_write(struct file *filp, const char __user *buf,
 	missing = copy_from_user(spidev->buffer, buf, count);
 	if (missing == 0) {
 		status = spidev_sync_write(spidev, count);
-		if (status == 0)
-			status = count;
 	} else
 		status = -EFAULT;
 	mutex_unlock(&spidev->buf_lock);
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index d28c53868093..538c570df337 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -537,6 +537,13 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
 	int err = 0;
 	u32 tmp;
 
+	if (dev->bus->bustype != SSB_BUSTYPE_PCI) {
+		/* This SSB device is not on a PCI host-bus. So the IRQs are
+		 * not routed through the PCI core.
+		 * So we must not enable routing through the PCI core. */
+		goto out;
+	}
+
 	if (!pdev)
 		goto out;
 	bus = pdev->bus;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 63c34043b4d9..c3201affa0b6 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1125,9 +1125,6 @@ static void stop_data_traffic(struct acm *acm)
 	for (i = 0; i < acm->rx_buflimit; i++)
 		usb_kill_urb(acm->ru[i].urb);
 
-	INIT_LIST_HEAD(&acm->filled_read_bufs);
-	INIT_LIST_HEAD(&acm->spare_read_bufs);
-
 	tasklet_enable(&acm->urb_task);
 
 	cancel_work_sync(&acm->work);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 09a53e7f3327..42a436478b78 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -924,6 +924,15 @@ static int register_root_hub(struct usb_hcd *hcd)
 	return retval;
 }
 
+void usb_enable_root_hub_irq (struct usb_bus *bus)
+{
+	struct usb_hcd *hcd;
+
+	hcd = container_of (bus, struct usb_hcd, self);
+	if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
+		hcd->driver->hub_irq_enable (hcd);
+}
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -1684,19 +1693,30 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
 irqreturn_t usb_hcd_irq (int irq, void *__hcd)
 {
 	struct usb_hcd		*hcd = __hcd;
-	int			start = hcd->state;
+	unsigned long		flags;
+	irqreturn_t		rc;
 
-	if (unlikely(start == HC_STATE_HALT ||
-	    !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
-		return IRQ_NONE;
-	if (hcd->driver->irq (hcd) == IRQ_NONE)
-		return IRQ_NONE;
+	/* IRQF_DISABLED doesn't work correctly with shared IRQs
+	 * when the first handler doesn't use it.  So let's just
+	 * assume it's never used.
+	 */
+	local_irq_save(flags);
 
-	set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+	if (unlikely(hcd->state == HC_STATE_HALT ||
+		     !test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
+		rc = IRQ_NONE;
+	} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
+		rc = IRQ_NONE;
+	} else {
+		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+		if (unlikely(hcd->state == HC_STATE_HALT))
+			usb_hc_died(hcd);
+		rc = IRQ_HANDLED;
+	}
 
-	if (unlikely(hcd->state == HC_STATE_HALT))
-		usb_hc_died (hcd);
-	return IRQ_HANDLED;
+	local_irq_restore(flags);
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1860,6 +1880,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
 	/* enable irqs just before we start the controller */
 	if (hcd->driver->irq) {
+
+		/* IRQF_DISABLED doesn't work as advertised when used together
+		 * with IRQF_SHARED. As usb_hcd_irq() will always disable
+		 * interrupts we can remove it here.
+		 */
+		irqflags &= ~IRQF_DISABLED;
+
 		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
 				hcd->driver->description, hcd->self.busnum);
 		if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index a0bf5df6cb6f..b9de1569b39e 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -210,6 +210,8 @@ struct hc_driver {
 	int	(*bus_suspend)(struct usb_hcd *);
 	int	(*bus_resume)(struct usb_hcd *);
 	int	(*start_port_reset)(struct usb_hcd *, unsigned port_num);
+	void	(*hub_irq_enable)(struct usb_hcd *);
+		/* Needed only if port-change IRQs are level-triggered */
 
 		/* force handover of high-speed port to full-speed companion */
 	void	(*relinquish_port)(struct usb_hcd *, int);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 94789be54ca3..4cfe32a16c37 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -713,18 +713,11 @@ static void hub_restart(struct usb_hub *hub, int type)
 		}
 
 		/* Was the power session lost while we were suspended? */
-		switch (type) {
-		case HUB_RESET_RESUME:
-			portstatus = 0;
-			portchange = USB_PORT_STAT_C_CONNECTION;
-			break;
+		status = hub_port_status(hub, port1, &portstatus, &portchange);
 
-		case HUB_RESET:
-		case HUB_RESUME:
-			status = hub_port_status(hub, port1,
-					&portstatus, &portchange);
-			break;
-		}
+		/* If the device is gone, khubd will handle it later */
+		if (status == 0 && !(portstatus & USB_PORT_STAT_CONNECTION))
+			continue;
 
 		/* For "USB_PERSIST"-enabled children we must
 		 * mark the child device for reset-resume and
@@ -2080,6 +2073,8 @@ int usb_port_resume(struct usb_device *udev)
 	}
 
 	clear_bit(port1, hub->busy_bits);
+	if (!hub->hdev->parent && !hub->busy_bits[0])
+		usb_enable_root_hub_irq(hub->hdev->bus);
 
 	if (status == 0)
 		status = finish_port_resume(udev);
@@ -3009,6 +3004,11 @@ static void hub_events(void)
 
 		hub->activating = 0;
 
+		/* If this is a root hub, tell the HCD it's okay to
+		 * re-enable port-change interrupts now. */
+		if (!hdev->parent && !hub->busy_bits[0])
+			usb_enable_root_hub_irq(hdev->bus);
+
 loop_autopm:
 		/* Allow autosuspend if we're not going to run again */
 		if (list_empty(&hub->event_list))
@@ -3234,6 +3234,8 @@ int usb_reset_device(struct usb_device *udev)
 			break;
 	}
 	clear_bit(port1, parent_hub->busy_bits);
+	if (!parent_hdev->parent && !parent_hub->busy_bits[0])
+		usb_enable_root_hub_irq(parent_hdev->bus);
 
 	if (ret < 0)
 		goto re_enumerate;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 35a03095757e..90245fd8bac4 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -177,6 +177,15 @@ timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
 static inline void
 timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
 {
+	/* Don't override timeouts which shrink or (later) disable
+	 * the async ring; just the I/O watchdog.  Note that if a
+	 * SHRINK were pending, OFF would never be requested.
+	 */
+	if (timer_pending(&ehci->watchdog)
+			&& ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF))
+				& ehci->actions))
+		return;
+
 	if (!test_and_set_bit (action, &ehci->actions)) {
 		unsigned long t;
 
@@ -192,15 +201,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
 			t = EHCI_SHRINK_JIFFIES;
 			break;
 		}
-		t += jiffies;
-		// all timings except IAA watchdog can be overridden.
-		// async queue SHRINK often precedes IAA.  while it's ready
-		// to go OFF neither can matter, and afterwards the IO
-		// watchdog stops unless there's still periodic traffic.
-		if (time_before_eq(t, ehci->watchdog.expires)
-				&& timer_pending (&ehci->watchdog))
-			return;
-		mod_timer (&ehci->watchdog, t);
+		mod_timer(&ehci->watchdog, t + jiffies);
 	}
 }
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index c96db1153dcf..e534f9de0f05 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -261,6 +261,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 1b9abdba920b..68c17f5ea8ea 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -8,7 +8,7 @@
  * Bus Glue for AMD Alchemy Au1xxx
  *
  * Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
  *
  * Modified for LH7A404 from ohci-sa1111.c
  *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
@@ -288,6 +288,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 06aadfb0ec29..5adaf36e47d0 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -135,6 +135,7 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
 	.get_frame_number	= ohci_get_frame,
 	.hub_status_data	= ohci_hub_status_data,
 	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
 #ifdef CONFIG_PM
 	.bus_suspend		= ohci_bus_suspend,
 	.bus_resume		= ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 33f1c1c32edf..a8160d65f32b 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1054,7 +1054,7 @@ MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_MFD_SM501
 #include "ohci-sm501.c"
-#define PLATFORM_DRIVER		ohci_hcd_sm501_driver
+#define SM501_OHCI_DRIVER	ohci_hcd_sm501_driver
 #endif
 
 #if	!defined(PCI_DRIVER) &&		\
@@ -1062,6 +1062,7 @@ MODULE_LICENSE ("GPL");
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_DRIVER) &&	\
 	!defined(PS3_SYSTEM_BUS_DRIVER) && \
+	!defined(SM501_OHCI_DRIVER) && \
 	!defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
@@ -1121,9 +1122,18 @@ static int __init ohci_hcd_mod_init(void)
 		goto error_ssb;
 #endif
 
+#ifdef SM501_OHCI_DRIVER
+	retval = platform_driver_register(&SM501_OHCI_DRIVER);
+	if (retval < 0)
+		goto error_sm501;
+#endif
+
 	return retval;
 
 	/* Error path */
+#ifdef SM501_OHCI_DRIVER
+ error_sm501:
+#endif
 #ifdef SSB_OHCI_DRIVER
  error_ssb:
 #endif
@@ -1159,6 +1169,9 @@ module_init(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SM501_OHCI_DRIVER
+	platform_driver_unregister(&SM501_OHCI_DRIVER);
+#endif
 #ifdef SSB_OHCI_DRIVER
 	ssb_driver_unregister(&SSB_OHCI_DRIVER);
 #endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 79a78029f896..b56739221d11 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,6 +36,18 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* hcd->hub_irq_enable() */
+static void ohci_rhsc_enable (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	spin_lock_irq(&ohci->lock);
+	if (!ohci->autostop)
+		del_timer(&hcd->rh_timer);	/* Prevent next poll */
+	ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+	spin_unlock_irq(&ohci->lock);
+}
+
 #define OHCI_SCHED_ENABLES \
 	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
 
@@ -362,28 +374,18 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
 		int any_connected)
 {
 	int	poll_rh = 1;
-	int	rhsc;
 
-	rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
 	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 
 	case OHCI_USB_OPER:
-		/* If no status changes are pending, enable status-change
-		 * interrupts.
-		 */
-		if (!rhsc && !changed) {
-			rhsc = OHCI_INTR_RHSC;
-			ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
-		}
-
-		/* Keep on polling until we know a device is connected
-		 * and RHSC is enabled, or until we autostop.
-		 */
+		/* keep on polling until we know a device is connected
+		 * and RHSC is enabled */
 		if (!ohci->autostop) {
 			if (any_connected ||
 					!device_may_wakeup(&ohci_to_hcd(ohci)
 						->self.root_hub->dev)) {
-				if (rhsc)
+				if (ohci_readl(ohci, &ohci->regs->intrenable) &
+						OHCI_INTR_RHSC)
 					poll_rh = 0;
 			} else {
 				ohci->autostop = 1;
@@ -396,13 +398,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
 				ohci->autostop = 0;
 				ohci->next_statechange = jiffies +
 						STATECHANGE_DELAY;
-			} else if (rhsc && time_after_eq(jiffies,
+			} else if (time_after_eq(jiffies,
 						ohci->next_statechange)
 					&& !ohci->ed_rm_list
 					&& !(ohci->hc_control &
 						OHCI_SCHED_ENABLES)) {
 				ohci_rh_suspend(ohci, 1);
-				poll_rh = 0;
 			}
 		}
 		break;
@@ -416,12 +417,6 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
 			else
 				usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
 		} else {
-			if (!rhsc && (ohci->autostop ||
-					ohci_to_hcd(ohci)->self.root_hub->
-						do_remote_wakeup))
-				ohci_writel(ohci, OHCI_INTR_RHSC,
-						&ohci->regs->intrenable);
-
 			/* everything is idle, no need for polling */
 			poll_rh = 0;
 		}
@@ -443,16 +438,12 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
 static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
 		int any_connected)
 {
-	/* If RHSC is enabled, don't poll */
-	if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
-		return 0;
+	int	poll_rh = 1;
 
-	/* If no status changes are pending, enable status-change interrupts */
-	if (!changed) {
-		ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
-		return 0;
-	}
-	return 1;
+	/* keep on polling until RHSC is enabled */
+	if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
+		poll_rh = 0;
+	return poll_rh;
 }
 
 #endif	/* CONFIG_PM */
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 96d14fa1d833..1ef5d482c145 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -8,7 +8,7 @@
  * Bus Glue for Sharp LH7A404
  *
  * Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
  *
  * Modified for LH7A404 from ohci-sa1111.c
  *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
@@ -193,6 +193,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 6859fb5f1d6f..3a7c24c03671 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -466,6 +466,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 3bf175d95a23..4696cc912e16 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -327,6 +327,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 664f07ee8732..28b458f20cc3 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -280,6 +280,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
 	 */
 	.hub_status_data = ohci_hub_status_data,
 	.hub_control = ohci_hub_control,
+	.hub_irq_enable = ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend = ohci_bus_suspend,
 	.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 28467e288a93..605d59cba28e 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -201,6 +201,7 @@ static const struct hc_driver ohci_pnx8550_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 50e55db13636..a67252791223 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -72,6 +72,7 @@ static const struct hc_driver ohci_ppc_of_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index cd3398b675b2..523c30125577 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -172,6 +172,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index bfdeb0d22d05..c1935ae537f8 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -68,6 +68,7 @@ static const struct hc_driver ps3_ohci_hc_driver = {
 	.get_frame_number	= ohci_get_frame,
 	.hub_status_data	= ohci_hub_status_data,
 	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
 	.start_port_reset	= ohci_start_port_reset,
 #if defined(CONFIG_PM)
 	.bus_suspend 		= ohci_bus_suspend,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 70b0d4b459e7..d4ee27d92be8 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -298,6 +298,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef  CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 9c9f3b59186f..9b547407c934 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -952,6 +952,7 @@ rescan_this:
 			struct urb	*urb;
 			urb_priv_t	*urb_priv;
 			__hc32		savebits;
+			u32		tdINFO;
 
 			td = list_entry (entry, struct td, td_list);
 			urb = td->urb;
@@ -966,6 +967,17 @@ rescan_this:
 			savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK);
 			*prev = td->hwNextTD | savebits;
 
+			/* If this was unlinked, the TD may not have been
+			 * retired ... so manually save the data toggle.
+			 * The controller ignores the value we save for
+			 * control and ISO endpoints.
+			 */
+			tdINFO = hc32_to_cpup(ohci, &td->hwINFO);
+			if ((tdINFO & TD_T) == TD_T_DATA0)
+				ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_C);
+			else if ((tdINFO & TD_T) == TD_T_DATA1)
+				ed->hwHeadP |= cpu_to_hc32(ohci, ED_C);
+
 			/* HC may have partly processed this TD */
 			td_done (ohci, urb, td);
 			urb_priv->td_cnt++;
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index a73d2ff322e2..3c7a740cfe0c 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -8,7 +8,7 @@
  * USB Bus Glue for Samsung S3C2410
  *
  * Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
  *
  * Modified for S3C2410 from ohci-sa1111.c, ohci-omap.c and ohci-lh7a40.c
  *	by Ben Dooks, <ben@simtec.co.uk>
@@ -466,6 +466,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
 	 */
 	.hub_status_data =	ohci_s3c2410_hub_status_data,
 	.hub_control =		ohci_s3c2410_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 99438c65981b..2e9dceb9bb99 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -8,7 +8,7 @@
  * SA1111 Bus Glue
  *
  * Written by Christopher Hoover <ch@hpl.hp.com>
- * Based on fragments of previous driver by Rusell King et al.
+ * Based on fragments of previous driver by Russell King et al.
  *
  * This file is licenced under the GPL.
  */
@@ -231,6 +231,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 60f03cc7ec4f..e7ee607278fe 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -68,6 +68,7 @@ static const struct hc_driver ohci_sh_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index e899a77dfb83..e610698c6b60 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -75,6 +75,7 @@ static const struct hc_driver ohci_sm501_hc_driver = {
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend =		ohci_bus_suspend,
 	.bus_resume =		ohci_bus_resume,
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
index c4265caec780..7275186db315 100644
--- a/drivers/usb/host/ohci-ssb.c
+++ b/drivers/usb/host/ohci-ssb.c
@@ -81,6 +81,7 @@ static const struct hc_driver ssb_ohci_hc_driver = {
 
 	.hub_status_data	= ohci_hub_status_data,
 	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
 #ifdef	CONFIG_PM
 	.bus_suspend		= ohci_bus_suspend,
 	.bus_resume		= ohci_bus_resume,
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index f29307405bb3..9b6323f768b2 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2934,6 +2934,16 @@ static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
 		return 0;
 }
 
+static void u132_hub_irq_enable(struct usb_hcd *hcd)
+{
+	struct u132 *u132 = hcd_to_u132(hcd);
+	if (u132->going > 1) {
+		dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+			, u132->going);
+	} else if (u132->going > 0)
+		dev_err(&u132->platform_dev->dev, "device is being removed\n");
+}
+
 
 #ifdef CONFIG_PM
 static int u132_bus_suspend(struct usb_hcd *hcd)
@@ -2985,6 +2995,7 @@ static struct hc_driver u132_hc_driver = {
 	.bus_suspend = u132_bus_suspend,
 	.bus_resume = u132_bus_resume,
 	.start_port_reset = u132_start_port_reset,
+	.hub_irq_enable = u132_hub_irq_enable,
 };
 
 /*
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index cb7fa0eaf3ae..33182f4c2267 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3264,8 +3264,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
 
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
-
-	dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 5234e7a3bd2c..0ff4a3971e45 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -637,6 +637,7 @@ static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
+	{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 06e0ecabb3eb..8302eca893ea 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -828,6 +828,9 @@
 /* Propox devices */
 #define FTDI_PROPOX_JTAGCABLEII_PID	0xD738
 
+/* Rig Expert Ukraine devices */
+#define FTDI_REU_TINY_PID		0xED22	/* RigExpert Tiny */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index ea924dc48496..d9fb3768a2d7 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -570,7 +570,12 @@ static struct usb_serial_driver ipaq_device = {
 	.description =		"PocketPC PDA",
 	.usb_driver = 		&ipaq_driver,
 	.id_table =		ipaq_id_table,
-	.num_ports =		2,
+	/*
+	 * some devices have an extra endpoint, which
+	 * must be ignored as it would make the core
+	 * create a second port which oopses when used
+	 */
+	.num_ports =		1,
 	.open =			ipaq_open,
 	.close =		ipaq_close,
 	.attach =		ipaq_startup,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 43cfde83a93b..a73420dd052a 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -306,6 +306,7 @@ static struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
 	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
+	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
 	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
 	{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
 	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 103195abd417..2a0dd1b50dc4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -57,6 +57,7 @@ static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
 	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
 	{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
 	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index cff160abb130..6ac3bbcf7a22 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -15,6 +15,7 @@
 #define PL2303_PRODUCT_ID_RSAQ3		0xaaa2
 #define PL2303_PRODUCT_ID_ALDIGA	0x0611
 #define PL2303_PRODUCT_ID_MMX		0x0612
+#define PL2303_PRODUCT_ID_GPRS		0x0609
 
 #define ATEN_VENDOR_ID		0x0557
 #define ATEN_VENDOR_ID2		0x0547
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 45fe3663fa7f..39a7c11795c4 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -402,11 +402,19 @@ UNUSUAL_DEV(  0x04a5, 0x3010, 0x0100, 0x0100,
 		US_FL_IGNORE_RESIDUE ),
 
 #ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
+/* CY7C68300 : support atacb */
 UNUSUAL_DEV(  0x04b4, 0x6830, 0x0000, 0x9999,
 		"Cypress",
 		"Cypress AT2LP",
 		US_SC_CYP_ATACB, US_PR_DEVICE, NULL,
 		0),
+
+/* CY7C68310 : support atacb and atacb2 */
+UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,
+		"Cypress",
+		"Cypress ISD-300LP",
+		US_SC_CYP_ATACB, US_PR_DEVICE, NULL,
+		0),
 #endif
 
 /* Reported by Simon Levitt <simon@whattf.com>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 002b61b4f0f6..e0c5f96b273d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1825,12 +1825,13 @@ config FB_FSL_DIU
 
 config FB_W100
 	tristate "W100 frame buffer support"
-	depends on FB && PXA_SHARPSL
+	depends on FB && ARCH_PXA
  	select FB_CFB_FILLRECT
  	select FB_CFB_COPYAREA
  	select FB_CFB_IMAGEBLIT
 	---help---
 	  Frame buffer driver for the w100 as found on the Sharp SL-Cxx series.
+	  It can also drive the w3220 chip found on iPAQ hx4700.
 
 	  This driver is also available as a module ( = code which can be
 	  inserted and removed from the running kernel whenever you want). The
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 24843fdd5395..59df132cc375 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -74,6 +74,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
 {
 	struct fb_info *info = vma->vm_private_data;
 	struct fb_deferred_io *fbdefio = info->fbdefio;
+	struct page *cur;
 
 	/* this is a callback we get when userspace first tries to
 	write to the page. we schedule a workqueue. that workqueue
@@ -83,7 +84,24 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
 
 	/* protect against the workqueue changing the page list */
 	mutex_lock(&fbdefio->lock);
-	list_add(&page->lru, &fbdefio->pagelist);
+
+	/* we loop through the pagelist before adding in order
+	to keep the pagelist sorted */
+	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+		/* this check is to catch the case where a new
+		process could start writing to the same page
+		through a new pte. this new access can cause the
+		mkwrite even when the original ps's pte is marked
+		writable */
+		if (unlikely(cur == page))
+			goto page_already_added;
+		else if (cur->index > page->index)
+			break;
+	}
+
+	list_add_tail(&page->lru, &cur->lru);
+
+page_already_added:
 	mutex_unlock(&fbdefio->lock);
 
 	/* come back after delay to process the deferred IO */
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 0a2785361ca3..09d7e22c6fef 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -286,7 +286,7 @@ static struct diu_pool pool;
  *	rheap and make the furture large allocation fail.
  */
 
-void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
+static void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
 {
 	void *virt;
 
@@ -311,12 +311,12 @@ void *fsl_diu_alloc(unsigned long size, phys_addr_t *phys)
 		memset(virt, 0, size);
 	}
 
-	pr_debug("rh virt=%p phys=%lx\n", virt, *phys);
+	pr_debug("rh virt=%p phys=%llx\n", virt, (unsigned long long)*phys);
 
 	return virt;
 }
 
-void fsl_diu_free(void *p, unsigned long size)
+static void fsl_diu_free(void *p, unsigned long size)
 {
 	pr_debug("p=%p size=%lu\n", p, size);
 
@@ -770,7 +770,7 @@ static int map_video_memory(struct fb_info *info)
 	info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
 	pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
 	info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
-	if (info->screen_base == 0) {
+	if (info->screen_base == NULL) {
 		printk(KERN_ERR "Unable to allocate fb memory\n");
 		return -ENOMEM;
 	}
@@ -788,7 +788,7 @@ static int map_video_memory(struct fb_info *info)
 static void unmap_video_memory(struct fb_info *info)
 {
 	fsl_diu_free(info->screen_base, info->fix.smem_len);
-	info->screen_base = 0;
+	info->screen_base = NULL;
 	info->fix.smem_start = 0;
 	info->fix.smem_len = 0;
 }
@@ -1158,7 +1158,7 @@ static int init_fbinfo(struct fb_info *info)
 	return 0;
 }
 
-static int install_fb(struct fb_info *info)
+static int __devinit install_fb(struct fb_info *info)
 {
 	int rc;
 	struct mfb_info *mfbi = info->par;
@@ -1233,7 +1233,7 @@ static int install_fb(struct fb_info *info)
 	return 0;
 }
 
-static void __exit uninstall_fb(struct fb_info *info)
+static void uninstall_fb(struct fb_info *info)
 {
 	struct mfb_info *mfbi = info->par;
 
@@ -1287,7 +1287,7 @@ static int request_irq_local(int irq)
 	/* Read to clear the status */
 	status = in_be32(&hw->int_status);
 
-	ret = request_irq(irq, fsl_diu_isr, 0, "diu", 0);
+	ret = request_irq(irq, fsl_diu_isr, 0, "diu", NULL);
 	if (ret)
 		pr_info("Request diu IRQ failed.\n");
 	else {
@@ -1312,7 +1312,7 @@ static void free_irq_local(int irq)
 	/* Disable all LCDC interrupt */
 	out_be32(&hw->int_mask, 0x1f);
 
-	free_irq(irq, 0);
+	free_irq(irq, NULL);
 }
 
 #ifdef CONFIG_PM
@@ -1353,7 +1353,8 @@ static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
 	dma_addr_t paddr = 0;
 
 	ssize = size + bytes_align;
-	buf->vaddr = dma_alloc_coherent(0, ssize, &paddr, GFP_DMA | __GFP_ZERO);
+	buf->vaddr = dma_alloc_coherent(NULL, ssize, &paddr, GFP_DMA |
+							     __GFP_ZERO);
 	if (!buf->vaddr)
 		return -ENOMEM;
 
@@ -1371,7 +1372,7 @@ static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
 
 static void free_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
 {
-	dma_free_coherent(0, size + bytes_align,
+	dma_free_coherent(NULL, size + bytes_align,
 				buf->vaddr, (buf->paddr - buf->offset));
 	return;
 }
@@ -1411,7 +1412,7 @@ static ssize_t show_monitor(struct device *device,
 	return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
 }
 
-static int fsl_diu_probe(struct of_device *ofdev,
+static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->node;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 7dcda187d9ba..fafe7db20d6d 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -1246,7 +1246,7 @@ static int pxafb_resume(struct platform_device *dev)
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
+static int __devinit pxafb_map_video_memory(struct pxafb_info *fbi)
 {
 	/*
 	 * We reserve one page for the palette, plus the size
@@ -1348,7 +1348,7 @@ decode_mode:
 	pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
 }
 
-static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
+static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
 {
 	struct pxafb_info *fbi;
 	void *addr;
@@ -1410,7 +1410,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
 }
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
-static int __init parse_opt_mode(struct device *dev, const char *this_opt)
+static int __devinit parse_opt_mode(struct device *dev, const char *this_opt)
 {
 	struct pxafb_mach_info *inf = dev->platform_data;
 
@@ -1469,7 +1469,7 @@ done:
 	return 0;
 }
 
-static int __init parse_opt(struct device *dev, char *this_opt)
+static int __devinit parse_opt(struct device *dev, char *this_opt)
 {
 	struct pxafb_mach_info *inf = dev->platform_data;
 	struct pxafb_mode_info *mode = &inf->modes[0];
@@ -1567,7 +1567,7 @@ static int __init parse_opt(struct device *dev, char *this_opt)
 	return 0;
 }
 
-static int __init pxafb_parse_options(struct device *dev, char *options)
+static int __devinit pxafb_parse_options(struct device *dev, char *options)
 {
 	char *this_opt;
 	int ret;
@@ -1588,8 +1588,8 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
 
 static char g_options[256] __devinitdata = "";
 
-#ifndef CONFIG_MODULES
-static int __devinit pxafb_setup_options(void)
+#ifndef MODULE
+static int __init pxafb_setup_options(void)
 {
 	char *options = NULL;
 
@@ -1613,7 +1613,7 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
 #define pxafb_setup_options()		(0)
 #endif
 
-static int __init pxafb_probe(struct platform_device *dev)
+static int __devinit pxafb_probe(struct platform_device *dev)
 {
 	struct pxafb_info *fbi;
 	struct pxafb_mach_info *inf;
@@ -1685,14 +1685,14 @@ static int __init pxafb_probe(struct platform_device *dev)
 	if (r == NULL) {
 		dev_err(&dev->dev, "no I/O memory resource defined\n");
 		ret = -ENODEV;
-		goto failed;
+		goto failed_fbi;
 	}
 
 	r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
 	if (r == NULL) {
 		dev_err(&dev->dev, "failed to request I/O memory\n");
 		ret = -EBUSY;
-		goto failed;
+		goto failed_fbi;
 	}
 
 	fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
@@ -1735,8 +1735,17 @@ static int __init pxafb_probe(struct platform_device *dev)
 	 * This makes sure that our colour bitfield
 	 * descriptors are correctly initialised.
 	 */
-	pxafb_check_var(&fbi->fb.var, &fbi->fb);
-	pxafb_set_par(&fbi->fb);
+	ret = pxafb_check_var(&fbi->fb.var, &fbi->fb);
+	if (ret) {
+		dev_err(&dev->dev, "failed to get suitable mode\n");
+		goto failed_free_irq;
+	}
+
+	ret = pxafb_set_par(&fbi->fb);
+	if (ret) {
+		dev_err(&dev->dev, "Failed to set parameters\n");
+		goto failed_free_irq;
+	}
 
 	platform_set_drvdata(dev, fbi);
 
@@ -1744,7 +1753,7 @@ static int __init pxafb_probe(struct platform_device *dev)
 	if (ret < 0) {
 		dev_err(&dev->dev,
 			"Failed to register framebuffer device: %d\n", ret);
-		goto failed_free_irq;
+		goto failed_free_cmap;
 	}
 
 #ifdef CONFIG_CPU_FREQ
@@ -1763,18 +1772,23 @@ static int __init pxafb_probe(struct platform_device *dev)
 
 	return 0;
 
+failed_free_cmap:
+	if (fbi->fb.cmap.len)
+		fb_dealloc_cmap(&fbi->fb.cmap);
 failed_free_irq:
 	free_irq(irq, fbi);
-failed_free_res:
-	release_mem_region(r->start, r->end - r->start + 1);
-failed_free_io:
-	iounmap(fbi->mmio_base);
 failed_free_mem:
 	dma_free_writecombine(&dev->dev, fbi->map_size,
 			fbi->map_cpu, fbi->map_dma);
-failed:
+failed_free_io:
+	iounmap(fbi->mmio_base);
+failed_free_res:
+	release_mem_region(r->start, r->end - r->start + 1);
+failed_fbi:
+	clk_put(fbi->clk);
 	platform_set_drvdata(dev, NULL);
 	kfree(fbi);
+failed:
 	return ret;
 }
 
@@ -1787,7 +1801,7 @@ static struct platform_driver pxafb_driver = {
 	},
 };
 
-static int __devinit pxafb_init(void)
+static int __init pxafb_init(void)
 {
 	if (pxafb_setup_options())
 		return -EINVAL;
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 30469bf906e5..d0674f1e3f10 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -1003,6 +1003,7 @@ static struct w100_pll_info xtal_14318000[] = {
 static struct w100_pll_info xtal_16000000[] = {
 	/*freq     M   N_int    N_fac  tfgoal  lock_time */
 	{ 72,      1,   8,       0,     0xe0,        48}, /* tfgoal guessed */
+	{ 80,      1,   9,       0,     0xe0,        13}, /* tfgoal guessed */
 	{ 95,      1,   10,      7,     0xe0,        38}, /* tfgoal guessed */
 	{ 96,      1,   11,      0,     0xe0,        36}, /* tfgoal guessed */
 	{  0,      0,   0,       0,        0,         0},