aboutsummaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2006-01-09 20:20:09 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-09 20:20:09 -0800
commit9a2e19cf4c9de67bfd135d1a00fc4626e9bafed2 (patch)
treea7453ad853fc1ecc3f15060a4794af8e7accf283 /usb
parent6bda7dc4404f8d79ce7b2586717fea2407db20cc (diff)
downloadpatches-9a2e19cf4c9de67bfd135d1a00fc4626e9bafed2.tar.gz
Loads of usb patches added
Diffstat (limited to 'usb')
-rw-r--r--usb/usb-asix-add-device-ids-for-0g0-cable-ethernet.patch32
-rw-r--r--usb/usb-cleanup-of-usblp.patch177
-rw-r--r--usb/usb-drivers-usb-media-ov511.c-remove-hooks-for-the-decomp-module.patch276
-rw-r--r--usb/usb-drivers-usb-media-w9968cf.c-remove-hooks-for-the-vpp-module.patch285
-rw-r--r--usb/usb-ehci-fix-gfp_t-sparse-warning.patch34
-rw-r--r--usb/usb-fix-oops-in-acm-disconnect.patch43
-rw-r--r--usb/usb-ftdi_sio-new-ids-for-westrex-devices.patch48
-rw-r--r--usb/usb-gadgetfs-set-zero-flag-for-short-control-in-response.patch63
-rw-r--r--usb/usb-isp116x-hcd-replace-mdelay-by-msleep.patch77
-rw-r--r--usb/usb-kzalloc-for-hid.patch150
-rw-r--r--usb/usb-kzalloc-for-storage.patch112
-rw-r--r--usb/usb-kzalloc-in-cytherm.patch34
-rw-r--r--usb/usb-kzalloc-in-dabusb.patch34
-rw-r--r--usb/usb-kzalloc-in-idmouse.patch32
-rw-r--r--usb/usb-kzalloc-in-ldusb.patch34
-rw-r--r--usb/usb-kzalloc-in-phidgetinterfacekit.patch68
-rw-r--r--usb/usb-kzalloc-in-phidgetservo.patch33
-rw-r--r--usb/usb-kzalloc-in-sisusbvga.patch44
-rw-r--r--usb/usb-kzalloc-in-usbled.patch33
-rw-r--r--usb/usb-kzalloc-in-usbvideo.patch35
-rw-r--r--usb/usb-kzalloc-in-w9968cf.patch73
-rw-r--r--usb/usb-mdc800.c-to-kzalloc.patch35
-rw-r--r--usb/usb-new-id-for-ftdi_sio.c-and-ftdi_sio.h.patch47
-rw-r--r--usb/usb-optimise-devio.c-usbdev_read.patch56
-rw-r--r--usb/usb-remove-extra-newline-in-hid_init_reports.patch30
-rw-r--r--usb/usb-remove-linux_version_code-check-in-pwc-pwc-ctrl.c.patch490
-rw-r--r--usb/usb-sn9c10x-driver-updates-and-bugfixes.patch2912
-rw-r--r--usb/usb-ub-03-oops-with-cfq.patch226
-rw-r--r--usb/usb-ub-04-loss-of-timer-and-a-hang.patch56
-rw-r--r--usb/usb-ub-05-bulk-reset.patch151
-rw-r--r--usb/usb-uhci-no-fsbr-until-device-is-configured.patch39
-rw-r--r--usb/usb-usb-storage-add-support-for-rio-karma.patch131
-rw-r--r--usb/usb-usb-storage-support-for-sony-dsc-t5-still-camera.patch40
-rw-r--r--usb/usb-yealink.c-cleanup-device-matching-code.patch124
34 files changed, 6054 insertions, 0 deletions
diff --git a/usb/usb-asix-add-device-ids-for-0g0-cable-ethernet.patch b/usb/usb-asix-add-device-ids-for-0g0-cable-ethernet.patch
new file mode 100644
index 00000000000000..060b91e5e094c4
--- /dev/null
+++ b/usb/usb-asix-add-device-ids-for-0g0-cable-ethernet.patch
@@ -0,0 +1,32 @@
+From linux-usb-devel-admin@lists.sourceforge.net Thu Jan 5 11:46:21 2006
+From: David Hollis <dhollis@davehollis.com>
+To: Greg KH <gregkh@suse.de>
+Cc: Charles Lepple <clepple@gmail.com>
+Message-Id: <1136489989.2509.12.camel@dhollis-lnx.sunera.com>
+Subject: USB: asix - Add device IDs for 0G0 Cable Ethernet
+Date: Thu, 05 Jan 2006 14:39:49 -0500
+
+
+Add device IDs for the 0G0 Cable Ethernet device as reported by
+Charles Lepple <clepple@gmail.com>.
+
+Signed-off-by: David Hollis <dhollis@davehollis.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/net/asix.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- gregkh-2.6.orig/drivers/usb/net/asix.c
++++ gregkh-2.6/drivers/usb/net/asix.c
+@@ -916,6 +916,10 @@ static const struct usb_device_id produc
+ // Linksys USB200M Rev 2
+ USB_DEVICE (0x13b1, 0x0018),
+ .driver_info = (unsigned long) &ax88772_info,
++}, {
++ // 0Q0 cable ethernet
++ USB_DEVICE (0x1557, 0x7720),
++ .driver_info = (unsigned long) &ax88772_info,
+ },
+ { }, // END
+ };
diff --git a/usb/usb-cleanup-of-usblp.patch b/usb/usb-cleanup-of-usblp.patch
new file mode 100644
index 00000000000000..37ce8f53950138
--- /dev/null
+++ b/usb/usb-cleanup-of-usblp.patch
@@ -0,0 +1,177 @@
+From neukum@fachschaft.cup.uni-muenchen.de Sat Jan 7 13:22:02 2006
+Date: Sat, 7 Jan 2006 21:35:20 +0100 (CET)
+From: Oliver Neukum <neukum@fachschaft.cup.uni-muenchen.de>
+To: vojtech@suse.cz
+Cc: greg@kroah.com, oliver@neukum.name
+Subject: USB: cleanup of usblp
+Message-ID: <Pine.LNX.4.58.0601072131370.2861@fachschaft.cup.uni-muenchen.de>
+
+this fixes
+-potential hang by disconnecting through usbfs
+-kzalloc
+-general cleanup
+-micro optimisation in interrupt handlers
+
+It compiles and I am printing.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/usblp.c | 71 +++++++++++++++-------------------------------
+ 1 file changed, 24 insertions(+), 47 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/class/usblp.c
++++ gregkh-2.6/drivers/usb/class/usblp.c
+@@ -7,6 +7,7 @@
+ * Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
+ # Copyright (c) 2001 Pete Zaitcev <zaitcev@redhat.com>
+ # Copyright (c) 2001 David Paschal <paschal@rcsis.com>
++ * Copyright (c) 2006 Oliver Neukum <oliver@neukum.name>
+ *
+ * USB Printer Device Class driver for USB printers and printer cables
+ *
+@@ -273,13 +274,16 @@ static void usblp_bulk_read(struct urb *
+ {
+ struct usblp *usblp = urb->context;
+
+- if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
++ if (unlikely(!usblp || !usblp->dev || !usblp->used))
+ return;
+
++ if (unlikely(!usblp->present))
++ goto unplug;
+ if (unlikely(urb->status))
+ warn("usblp%d: nonzero read/write bulk status received: %d",
+ usblp->minor, urb->status);
+ usblp->rcomplete = 1;
++unplug:
+ wake_up_interruptible(&usblp->wait);
+ }
+
+@@ -287,13 +291,15 @@ static void usblp_bulk_write(struct urb
+ {
+ struct usblp *usblp = urb->context;
+
+- if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
++ if (unlikely(!usblp || !usblp->dev || !usblp->used))
+ return;
+-
++ if (unlikely(!usblp->present))
++ goto unplug;
+ if (unlikely(urb->status))
+ warn("usblp%d: nonzero read/write bulk status received: %d",
+ usblp->minor, urb->status);
+ usblp->wcomplete = 1;
++unplug:
+ wake_up_interruptible(&usblp->wait);
+ }
+
+@@ -627,9 +633,8 @@ done:
+
+ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+ {
+- DECLARE_WAITQUEUE(wait, current);
+ struct usblp *usblp = file->private_data;
+- int timeout, err = 0, transfer_length = 0;
++ int timeout, rv, err = 0, transfer_length = 0;
+ size_t writecount = 0;
+
+ while (writecount < count) {
+@@ -641,24 +646,11 @@ static ssize_t usblp_write(struct file *
+ }
+
+ timeout = USBLP_WRITE_TIMEOUT;
+- add_wait_queue(&usblp->wait, &wait);
+- while ( 1==1 ) {
+
+- if (signal_pending(current)) {
+- remove_wait_queue(&usblp->wait, &wait);
+- return writecount ? writecount : -EINTR;
+- }
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (timeout && !usblp->wcomplete) {
+- timeout = schedule_timeout(timeout);
+- } else {
+- set_current_state(TASK_RUNNING);
+- break;
+- }
+- }
+- remove_wait_queue(&usblp->wait, &wait);
++ rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
++ if (rv < 0)
++ return writecount ? writecount : -EINTR;
+ }
+-
+ down (&usblp->sem);
+ if (!usblp->present) {
+ up (&usblp->sem);
+@@ -724,7 +716,7 @@ static ssize_t usblp_write(struct file *
+ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+ {
+ struct usblp *usblp = file->private_data;
+- DECLARE_WAITQUEUE(wait, current);
++ int rv;
+
+ if (!usblp->bidir)
+ return -EINVAL;
+@@ -742,26 +734,13 @@ static ssize_t usblp_read(struct file *f
+ count = -EAGAIN;
+ goto done;
+ }
+-
+- add_wait_queue(&usblp->wait, &wait);
+- while (1==1) {
+- if (signal_pending(current)) {
+- count = -EINTR;
+- remove_wait_queue(&usblp->wait, &wait);
+- goto done;
+- }
+- up (&usblp->sem);
+- set_current_state(TASK_INTERRUPTIBLE);
+- if (!usblp->rcomplete) {
+- schedule();
+- } else {
+- set_current_state(TASK_RUNNING);
+- down(&usblp->sem);
+- break;
+- }
+- down (&usblp->sem);
++ up(&usblp->sem);
++ rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
++ down(&usblp->sem);
++ if (rv < 0) {
++ count = -EINTR;
++ goto done;
+ }
+- remove_wait_queue(&usblp->wait, &wait);
+ }
+
+ if (!usblp->present) {
+@@ -874,11 +853,10 @@ static int usblp_probe(struct usb_interf
+
+ /* Malloc and start initializing usblp structure so we can use it
+ * directly. */
+- if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
++ if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
+ err("out of memory for usblp");
+ goto abort;
+ }
+- memset(usblp, 0, sizeof(struct usblp));
+ usblp->dev = dev;
+ init_MUTEX (&usblp->sem);
+ init_waitqueue_head(&usblp->wait);
+@@ -1214,10 +1192,9 @@ static int __init usblp_init(void)
+ {
+ int retval;
+ retval = usb_register(&usblp_driver);
+- if (retval)
+- goto out;
+- info(DRIVER_VERSION ": " DRIVER_DESC);
+-out:
++ if (!retval)
++ info(DRIVER_VERSION ": " DRIVER_DESC);
++
+ return retval;
+ }
+
diff --git a/usb/usb-drivers-usb-media-ov511.c-remove-hooks-for-the-decomp-module.patch b/usb/usb-drivers-usb-media-ov511.c-remove-hooks-for-the-decomp-module.patch
new file mode 100644
index 00000000000000..c855a6b41be6eb
--- /dev/null
+++ b/usb/usb-drivers-usb-media-ov511.c-remove-hooks-for-the-decomp-module.patch
@@ -0,0 +1,276 @@
+From linux-kernel-owner+greg=40kroah.com-S932605AbWAFC2y@vger.kernel.org Thu Jan 5 19:16:06 2006
+Date: Fri, 6 Jan 2006 03:28:52 +0100
+From: Adrian Bunk <bunk@stusta.de>
+To: mmcclell@bigfoot.com
+Cc: gregkh@suse.de
+Subject: USB: drivers/usb/media/ov511.c: remove hooks for the decomp module
+Message-ID: <20060106022852.GW12313@stusta.de>
+Content-Disposition: inline
+
+- the decomp module is not intended for inclusion into the kernel
+- people using the decomp module from upstream will usually simply use
+ the complete upstream 2.xx driver
+
+Therefore, there seems to be no good reason spending some bytes of
+kernel memory for hooks for this module.
+
+
+Signed-off-by: Adrian Bunk <bunk@stusta.de>
+Signed-off-by: Mark McClelland <mark@ovcam.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/media/ov511.c | 196 ----------------------------------------------
+ 1 file changed, 2 insertions(+), 194 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/media/ov511.c
++++ gregkh-2.6/drivers/usb/media/ov511.c
+@@ -204,22 +204,10 @@ MODULE_LICENSE("GPL");
+
+ static struct usb_driver ov511_driver;
+
+-static struct ov51x_decomp_ops *ov511_decomp_ops;
+-static struct ov51x_decomp_ops *ov511_mmx_decomp_ops;
+-static struct ov51x_decomp_ops *ov518_decomp_ops;
+-static struct ov51x_decomp_ops *ov518_mmx_decomp_ops;
+-
+ /* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+ static const int i2c_detect_tries = 5;
+
+-/* MMX support is present in kernel and CPU. Checked upon decomp module load. */
+-#if defined(__i386__) || defined(__x86_64__)
+-#define ov51x_mmx_available (cpu_has_mmx)
+-#else
+-#define ov51x_mmx_available (0)
+-#endif
+-
+ static struct usb_device_id device_table [] = {
+ { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
+ { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
+@@ -3012,93 +3000,18 @@ yuv420raw_to_yuv420p(struct ov511_frame
+ *
+ **********************************************************************/
+
+-/* Chooses a decompression module, locks it, and sets ov->decomp_ops
+- * accordingly. Returns -ENXIO if decompressor is not available, otherwise
+- * returns 0 if no other error.
+- */
+ static int
+ request_decompressor(struct usb_ov511 *ov)
+ {
+- if (!ov)
+- return -ENODEV;
+-
+- if (ov->decomp_ops) {
+- err("ERROR: Decompressor already requested!");
+- return -EINVAL;
+- }
+-
+- lock_kernel();
+-
+- /* Try to get MMX, and fall back on no-MMX if necessary */
+- if (ov->bclass == BCL_OV511) {
+- if (ov511_mmx_decomp_ops) {
+- PDEBUG(3, "Using OV511 MMX decompressor");
+- ov->decomp_ops = ov511_mmx_decomp_ops;
+- } else if (ov511_decomp_ops) {
+- PDEBUG(3, "Using OV511 decompressor");
+- ov->decomp_ops = ov511_decomp_ops;
+- } else {
+- err("No decompressor available");
+- }
+- } else if (ov->bclass == BCL_OV518) {
+- if (ov518_mmx_decomp_ops) {
+- PDEBUG(3, "Using OV518 MMX decompressor");
+- ov->decomp_ops = ov518_mmx_decomp_ops;
+- } else if (ov518_decomp_ops) {
+- PDEBUG(3, "Using OV518 decompressor");
+- ov->decomp_ops = ov518_decomp_ops;
+- } else {
+- err("No decompressor available");
+- }
++ if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
++ err("No decompressor available");
+ } else {
+ err("Unknown bridge");
+ }
+
+- if (!ov->decomp_ops)
+- goto nosys;
+-
+- if (!ov->decomp_ops->owner) {
+- ov->decomp_ops = NULL;
+- goto nosys;
+- }
+-
+- if (!try_module_get(ov->decomp_ops->owner))
+- goto nosys;
+-
+- unlock_kernel();
+- return 0;
+-
+- nosys:
+- unlock_kernel();
+ return -ENOSYS;
+ }
+
+-/* Unlocks decompression module and nulls ov->decomp_ops. Safe to call even
+- * if ov->decomp_ops is NULL.
+- */
+-static void
+-release_decompressor(struct usb_ov511 *ov)
+-{
+- int released = 0; /* Did we actually do anything? */
+-
+- if (!ov)
+- return;
+-
+- lock_kernel();
+-
+- if (ov->decomp_ops) {
+- module_put(ov->decomp_ops->owner);
+- released = 1;
+- }
+-
+- ov->decomp_ops = NULL;
+-
+- unlock_kernel();
+-
+- if (released)
+- PDEBUG(3, "Decompressor released");
+-}
+-
+ static void
+ decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
+ unsigned char *pIn0, unsigned char *pOut0)
+@@ -3107,31 +3020,6 @@ decompress(struct usb_ov511 *ov, struct
+ if (request_decompressor(ov))
+ return;
+
+- PDEBUG(4, "Decompressing %d bytes", frame->bytes_recvd);
+-
+- if (frame->format == VIDEO_PALETTE_GREY
+- && ov->decomp_ops->decomp_400) {
+- int ret = ov->decomp_ops->decomp_400(
+- pIn0,
+- pOut0,
+- frame->compbuf,
+- frame->rawwidth,
+- frame->rawheight,
+- frame->bytes_recvd);
+- PDEBUG(4, "DEBUG: decomp_400 returned %d", ret);
+- } else if (frame->format != VIDEO_PALETTE_GREY
+- && ov->decomp_ops->decomp_420) {
+- int ret = ov->decomp_ops->decomp_420(
+- pIn0,
+- pOut0,
+- frame->compbuf,
+- frame->rawwidth,
+- frame->rawheight,
+- frame->bytes_recvd);
+- PDEBUG(4, "DEBUG: decomp_420 returned %d", ret);
+- } else {
+- err("Decompressor does not support this format");
+- }
+ }
+
+ /**********************************************************************
+@@ -4087,8 +3975,6 @@ ov51x_v4l1_close(struct inode *inode, st
+ ov->user--;
+ ov51x_stop_isoc(ov);
+
+- release_decompressor(ov);
+-
+ if (ov->led_policy == LED_AUTO)
+ ov51x_led_control(ov, 0);
+
+@@ -6020,82 +5906,6 @@ static struct usb_driver ov511_driver =
+ *
+ ***************************************************************************/
+
+-/* Returns 0 for success */
+-int
+-ov511_register_decomp_module(int ver, struct ov51x_decomp_ops *ops, int ov518,
+- int mmx)
+-{
+- if (ver != DECOMP_INTERFACE_VER) {
+- err("Decompression module has incompatible");
+- err("interface version %d", ver);
+- err("Interface version %d is required", DECOMP_INTERFACE_VER);
+- return -EINVAL;
+- }
+-
+- if (!ops)
+- return -EFAULT;
+-
+- if (mmx && !ov51x_mmx_available) {
+- err("MMX not available on this system or kernel");
+- return -EINVAL;
+- }
+-
+- lock_kernel();
+-
+- if (ov518) {
+- if (mmx) {
+- if (ov518_mmx_decomp_ops)
+- goto err_in_use;
+- else
+- ov518_mmx_decomp_ops = ops;
+- } else {
+- if (ov518_decomp_ops)
+- goto err_in_use;
+- else
+- ov518_decomp_ops = ops;
+- }
+- } else {
+- if (mmx) {
+- if (ov511_mmx_decomp_ops)
+- goto err_in_use;
+- else
+- ov511_mmx_decomp_ops = ops;
+- } else {
+- if (ov511_decomp_ops)
+- goto err_in_use;
+- else
+- ov511_decomp_ops = ops;
+- }
+- }
+-
+- unlock_kernel();
+- return 0;
+-
+-err_in_use:
+- unlock_kernel();
+- return -EBUSY;
+-}
+-
+-void
+-ov511_deregister_decomp_module(int ov518, int mmx)
+-{
+- lock_kernel();
+-
+- if (ov518) {
+- if (mmx)
+- ov518_mmx_decomp_ops = NULL;
+- else
+- ov518_decomp_ops = NULL;
+- } else {
+- if (mmx)
+- ov511_mmx_decomp_ops = NULL;
+- else
+- ov511_decomp_ops = NULL;
+- }
+-
+- unlock_kernel();
+-}
+-
+ static int __init
+ usb_ov511_init(void)
+ {
+@@ -6122,5 +5932,3 @@ usb_ov511_exit(void)
+ module_init(usb_ov511_init);
+ module_exit(usb_ov511_exit);
+
+-EXPORT_SYMBOL(ov511_register_decomp_module);
+-EXPORT_SYMBOL(ov511_deregister_decomp_module);
diff --git a/usb/usb-drivers-usb-media-w9968cf.c-remove-hooks-for-the-vpp-module.patch b/usb/usb-drivers-usb-media-w9968cf.c-remove-hooks-for-the-vpp-module.patch
new file mode 100644
index 00000000000000..00bf6be599036c
--- /dev/null
+++ b/usb/usb-drivers-usb-media-w9968cf.c-remove-hooks-for-the-vpp-module.patch
@@ -0,0 +1,285 @@
+From linux-kernel-owner+greg=40kroah.com-S1161251AbWAHXnl@vger.kernel.org Sun Jan 8 15:46:55 2006
+Date: Mon, 9 Jan 2006 00:43:39 +0100
+From: Adrian Bunk <bunk@stusta.de>
+To: gregkh@suse.de
+Subject: USB: drivers/usb/media/w9968cf.c: remove hooks for the vpp module
+Message-ID: <20060108234339.GQ3774@stusta.de>
+Content-Disposition: inline
+
+- the w9968cf-vpp module is not intended for inclusion into the kernel
+- the upstream w9968cf package shipping the w9968cf-vpp module suggests
+ to simply replace the w9968cf module shipped with the kernel
+
+Therefore, there seems to be no good reason spending some bytes of
+kernel memory for hooks for the w9968cf-vpp module.
+
+
+Signed-off-by: Adrian Bunk <bunk@stusta.de>
+Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ Documentation/usb/w9968cf.txt | 32 +---------
+ drivers/usb/media/w9968cf.c | 128 ----------------------------------------
+ drivers/usb/media/w9968cf.h | 1
+ drivers/usb/media/w9968cf_vpp.h | 3
+ 4 files changed, 7 insertions(+), 157 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/media/w9968cf_vpp.h
++++ gregkh-2.6/drivers/usb/media/w9968cf_vpp.h
+@@ -37,7 +37,4 @@ struct w9968cf_vpp_t {
+ u8 busy; /* read-only flag: module is/is not in use */
+ };
+
+-extern int w9968cf_vppmod_register(struct w9968cf_vpp_t*);
+-extern int w9968cf_vppmod_deregister(struct w9968cf_vpp_t*);
+-
+ #endif /* _W9968CF_VPP_H_ */
+--- gregkh-2.6.orig/drivers/usb/media/w9968cf.h
++++ gregkh-2.6/drivers/usb/media/w9968cf.h
+@@ -195,7 +195,6 @@ enum w9968cf_vpp_flag {
+ };
+
+ static struct w9968cf_vpp_t* w9968cf_vpp;
+-static DECLARE_MUTEX(w9968cf_vppmod_lock);
+ static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
+
+ static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
+--- gregkh-2.6.orig/drivers/usb/media/w9968cf.c
++++ gregkh-2.6/drivers/usb/media/w9968cf.c
+@@ -62,7 +62,6 @@ MODULE_LICENSE(W9968CF_MODULE_LICENSE);
+ MODULE_SUPPORTED_DEVICE("Video");
+
+ static int ovmod_load = W9968CF_OVMOD_LOAD;
+-static int vppmod_load = W9968CF_VPPMOD_LOAD;
+ static unsigned short simcams = W9968CF_SIMCAMS;
+ static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
+ static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
+@@ -107,7 +106,6 @@ static unsigned int param_nv[24]; /* num
+
+ #ifdef CONFIG_KMOD
+ module_param(ovmod_load, bool, 0644);
+-module_param(vppmod_load, bool, 0444);
+ #endif
+ module_param(simcams, ushort, 0644);
+ module_param_array(video_nr, short, &param_nv[0], 0444);
+@@ -150,18 +148,6 @@ MODULE_PARM_DESC(ovmod_load,
+ "\ninto memory."
+ "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
+ "\n");
+-MODULE_PARM_DESC(vppmod_load,
+- "\n<0|1> Automatic 'w9968cf-vpp' module loading."
+- "\n0 disabled, 1 enabled."
+- "\nIf enabled, every time an application attempts to open a"
+- "\ncamera, 'insmod' searches for the video post-processing"
+- "\nmodule in the system and loads it automatically (if"
+- "\npresent). The optional 'w9968cf-vpp' module adds extra"
+- "\n image manipulation functions to the 'w9968cf' module,like"
+- "\nsoftware up-scaling,colour conversions and video decoding"
+- "\nfor very high frame rates."
+- "\nDefault value is "__MODULE_STRING(W9968CF_VPPMOD_LOAD)"."
+- "\n");
+ #endif
+ MODULE_PARM_DESC(simcams,
+ "\n<n> Number of cameras allowed to stream simultaneously."
+@@ -492,10 +478,6 @@ static void w9968cf_push_frame(struct w9
+ static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
+ static void w9968cf_release_resources(struct w9968cf_device*);
+
+-/* Intermodule communication */
+-static int w9968cf_vppmod_detect(struct w9968cf_device*);
+-static void w9968cf_vppmod_release(struct w9968cf_device*);
+-
+
+
+ /****************************************************************************
+@@ -2737,9 +2719,7 @@ static int w9968cf_open(struct inode* in
+ cam->streaming = 0;
+ cam->misconfigured = 0;
+
+- if (!w9968cf_vpp)
+- if ((err = w9968cf_vppmod_detect(cam)))
+- goto out;
++ w9968cf_adjust_configuration(cam);
+
+ if ((err = w9968cf_allocate_memory(cam)))
+ goto deallocate_memory;
+@@ -2766,7 +2746,6 @@ static int w9968cf_open(struct inode* in
+
+ deallocate_memory:
+ w9968cf_deallocate_memory(cam);
+-out:
+ DBG(2, "Failed to open the video device")
+ up(&cam->dev_sem);
+ up_read(&w9968cf_disconnect);
+@@ -2784,8 +2763,6 @@ static int w9968cf_release(struct inode*
+
+ w9968cf_stop_transfer(cam);
+
+- w9968cf_vppmod_release(cam);
+-
+ if (cam->disconnected) {
+ w9968cf_release_resources(cam);
+ up(&cam->dev_sem);
+@@ -3680,106 +3657,6 @@ static struct usb_driver w9968cf_usb_dri
+ * Module init, exit and intermodule communication *
+ ****************************************************************************/
+
+-static int w9968cf_vppmod_detect(struct w9968cf_device* cam)
+-{
+- if (!w9968cf_vpp)
+- if (vppmod_load)
+- request_module("w9968cf-vpp");
+-
+- down(&w9968cf_vppmod_lock);
+-
+- if (!w9968cf_vpp) {
+- DBG(4, "Video post-processing module not detected")
+- w9968cf_adjust_configuration(cam);
+- goto out;
+- }
+-
+- if (!try_module_get(w9968cf_vpp->owner)) {
+- DBG(1, "Couldn't increment the reference count of "
+- "the video post-processing module")
+- up(&w9968cf_vppmod_lock);
+- return -ENOSYS;
+- }
+-
+- w9968cf_vpp->busy++;
+-
+- DBG(5, "Video post-processing module detected")
+-
+-out:
+- up(&w9968cf_vppmod_lock);
+- return 0;
+-}
+-
+-
+-static void w9968cf_vppmod_release(struct w9968cf_device* cam)
+-{
+- down(&w9968cf_vppmod_lock);
+-
+- if (w9968cf_vpp && w9968cf_vpp->busy) {
+- module_put(w9968cf_vpp->owner);
+- w9968cf_vpp->busy--;
+- wake_up(&w9968cf_vppmod_wait);
+- DBG(5, "Video post-processing module released")
+- }
+-
+- up(&w9968cf_vppmod_lock);
+-}
+-
+-
+-int w9968cf_vppmod_register(struct w9968cf_vpp_t* vpp)
+-{
+- down(&w9968cf_vppmod_lock);
+-
+- if (w9968cf_vpp) {
+- KDBG(1, "Video post-processing module already registered")
+- up(&w9968cf_vppmod_lock);
+- return -EINVAL;
+- }
+-
+- w9968cf_vpp = vpp;
+- w9968cf_vpp->busy = 0;
+-
+- KDBG(2, "Video post-processing module registered")
+- up(&w9968cf_vppmod_lock);
+- return 0;
+-}
+-
+-
+-int w9968cf_vppmod_deregister(struct w9968cf_vpp_t* vpp)
+-{
+- down(&w9968cf_vppmod_lock);
+-
+- if (!w9968cf_vpp) {
+- up(&w9968cf_vppmod_lock);
+- return -EINVAL;
+- }
+-
+- if (w9968cf_vpp != vpp) {
+- KDBG(1, "Only the owner can unregister the video "
+- "post-processing module")
+- up(&w9968cf_vppmod_lock);
+- return -EINVAL;
+- }
+-
+- if (w9968cf_vpp->busy) {
+- KDBG(2, "Video post-processing module busy. Wait for it to be "
+- "released...")
+- up(&w9968cf_vppmod_lock);
+- wait_event(w9968cf_vppmod_wait, !w9968cf_vpp->busy);
+- w9968cf_vpp = NULL;
+- goto out;
+- }
+-
+- w9968cf_vpp = NULL;
+-
+- up(&w9968cf_vppmod_lock);
+-
+-out:
+- KDBG(2, "Video post-processing module unregistered")
+- return 0;
+-}
+-
+-
+ static int __init w9968cf_module_init(void)
+ {
+ int err;
+@@ -3809,6 +3686,3 @@ static void __exit w9968cf_module_exit(v
+ module_init(w9968cf_module_init);
+ module_exit(w9968cf_module_exit);
+
+-
+-EXPORT_SYMBOL(w9968cf_vppmod_register);
+-EXPORT_SYMBOL(w9968cf_vppmod_deregister);
+--- gregkh-2.6.orig/Documentation/usb/w9968cf.txt
++++ gregkh-2.6/Documentation/usb/w9968cf.txt
+@@ -57,16 +57,12 @@ based cameras should be supported as wel
+ The driver is divided into two modules: the basic one, "w9968cf", is needed for
+ the supported devices to work; the second one, "w9968cf-vpp", is an optional
+ module, which provides some useful video post-processing functions like video
+-decoding, up-scaling and colour conversions. Once the driver is installed,
+-every time an application tries to open a recognized device, "w9968cf" checks
+-the presence of the "w9968cf-vpp" module and loads it automatically by default.
+-
+-Please keep in mind that official kernels do not include the second module for
+-performance purposes. However it is always recommended to download and install
+-the latest and complete release of the driver, replacing the existing one, if
+-present: it will be still even possible not to load the "w9968cf-vpp" module at
+-all, if you ever want to. Another important missing feature of the version in
+-the official Linux 2.4 kernels is the writeable /proc filesystem interface.
++decoding, up-scaling and colour conversions.
++
++Note that the official kernels do neither include nor support the second
++module for performance purposes. Therefore, it is always recommended to
++download and install the latest and complete release of the driver,
++replacing the existing one, if present.
+
+ The latest and full-featured version of the W996[87]CF driver can be found at:
+ http://www.linux-projects.org. Please refer to the documentation included in
+@@ -201,22 +197,6 @@ Note: The kernel must be comp
+ enabled for the 'ovcamchip' module to be loaded and for
+ this parameter to be present.
+ -------------------------------------------------------------------------------
+-Name: vppmod_load
+-Type: bool
+-Syntax: <0|1>
+-Description: Automatic 'w9968cf-vpp' module loading: 0 disabled, 1 enabled.
+- If enabled, every time an application attempts to open a
+- camera, 'insmod' searches for the video post-processing module
+- in the system and loads it automatically (if present).
+- The optional 'w9968cf-vpp' module adds extra image manipulation
+- capabilities to the 'w9968cf' module,like software up-scaling,
+- colour conversions and video decompression for very high frame
+- rates.
+-Default: 1
+-Note: The kernel must be compiled with the CONFIG_KMOD option
+- enabled for the 'w9968cf-vpp' module to be loaded and for
+- this parameter to be present.
+--------------------------------------------------------------------------------
+ Name: simcams
+ Type: int
+ Syntax: <n>
diff --git a/usb/usb-ehci-fix-gfp_t-sparse-warning.patch b/usb/usb-ehci-fix-gfp_t-sparse-warning.patch
new file mode 100644
index 00000000000000..7e9c818b066dea
--- /dev/null
+++ b/usb/usb-ehci-fix-gfp_t-sparse-warning.patch
@@ -0,0 +1,34 @@
+From rdunlap@xenotime.net Sun Dec 25 19:30:06 2005
+Date: Sun, 25 Dec 2005 19:27:18 -0800
+From: "Randy.Dunlap" <rdunlap@xenotime.net>
+Cc: gregkh <greg@kroah.com>, david-b@pacbell.net
+Subject: USB EHCI: fix gfp_t sparse warning
+Message-Id: <20051225192718.0ca15ef5.rdunlap@xenotime.net>
+
+From: Randy Dunlap <rdunlap@xenotime.net>
+
+Fix sparse warning:
+drivers/usb/host/ehci-hcd.c:719:35: warning: incorrect type in argument 3 (different base types)
+drivers/usb/host/ehci-hcd.c:719:35: expected unsigned int [unsigned] mem_flags
+drivers/usb/host/ehci-hcd.c:719:35: got restricted unsigned int [usertype] mem_flags
+
+Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/ehci-sched.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/ehci-sched.c
++++ gregkh-2.6/drivers/usb/host/ehci-sched.c
+@@ -1843,8 +1843,7 @@ done:
+ #else
+
+ static inline int
+-sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
+- unsigned mem_flags)
++sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
+ {
+ ehci_dbg (ehci, "split iso support is disabled\n");
+ return -ENOSYS;
diff --git a/usb/usb-fix-oops-in-acm-disconnect.patch b/usb/usb-fix-oops-in-acm-disconnect.patch
new file mode 100644
index 00000000000000..5a6ac815087436
--- /dev/null
+++ b/usb/usb-fix-oops-in-acm-disconnect.patch
@@ -0,0 +1,43 @@
+From oliver@neukum.org Sun Jan 8 03:39:31 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Greg KH <gregkh@suse.de>
+Subject: USB: fix oops in acm disconnect
+Date: Sun, 8 Jan 2006 12:39:13 +0100
+Content-Disposition: inline
+Message-Id: <200601081239.13589.oliver@neukum.org>
+
+this fixes an oops with disconnection in acm.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/class/cdc-acm.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/class/cdc-acm.c
++++ gregkh-2.6/drivers/usb/class/cdc-acm.c
+@@ -1019,8 +1019,13 @@ static void acm_disconnect(struct usb_in
+ }
+
+ down(&open_sem);
++ if (!usb_get_intfdata(intf)) {
++ up(&open_sem);
++ return;
++ }
+ acm->dev = NULL;
+- usb_set_intfdata (intf, NULL);
++ usb_set_intfdata(acm->control, NULL);
++ usb_set_intfdata(acm->data, NULL);
+
+ tasklet_disable(&acm->urb_task);
+
+@@ -1041,7 +1046,7 @@ static void acm_disconnect(struct usb_in
+ for (i = 0; i < ACM_NRB; i++)
+ usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
+
+- usb_driver_release_interface(&acm_driver, acm->data);
++ usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);
+
+ if (!acm->used) {
+ acm_tty_unregister(acm);
diff --git a/usb/usb-ftdi_sio-new-ids-for-westrex-devices.patch b/usb/usb-ftdi_sio-new-ids-for-westrex-devices.patch
new file mode 100644
index 00000000000000..9c69948c560d98
--- /dev/null
+++ b/usb/usb-ftdi_sio-new-ids-for-westrex-devices.patch
@@ -0,0 +1,48 @@
+From ian.abbott@mev.co.uk Mon Jan 9 09:18:11 2006
+Message-ID: <43C2994C.1080009@mev.co.uk>
+Date: Mon, 09 Jan 2006 17:11:40 +0000
+From: Ian Abbott <abbotti@mev.co.uk>
+To: Greg KH <greg@kroah.com>, Cory Lee <coryclee_1@yahoo.com>
+Subject: USB: ftdi_sio: new IDs for Westrex devices
+
+From: Ian Abbott <abbotti@mev.co.uk>
+
+This patch adds two new devices to the ftdi_sio driver's device ID
+table. The device IDs were supplied by Cory Lee to support two POS
+printers made by Westrex International (Model 777 and Model 8900F).
+
+Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/serial/ftdi_sio.c | 2 ++
+ drivers/usb/serial/ftdi_sio.h | 6 ++++++
+ 2 files changed, 8 insertions(+)
+
+--- gregkh-2.6.orig/drivers/usb/serial/ftdi_sio.c
++++ gregkh-2.6/drivers/usb/serial/ftdi_sio.c
+@@ -481,6 +481,8 @@ static struct usb_device_id id_table_com
+ { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
+ { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
+ { }, /* Optional parameter entry */
+ { } /* Terminating entry */
+ };
+--- gregkh-2.6.orig/drivers/usb/serial/ftdi_sio.h
++++ gregkh-2.6/drivers/usb/serial/ftdi_sio.h
+@@ -370,6 +370,12 @@
+ #define POSIFLEX_VID 0x0d3a /* Vendor ID */
+ #define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */
+
++/*
++ * Westrex International devices submitted by Cory Lee
++ */
++#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */
++#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */
++
+ /* Commands */
+ #define FTDI_SIO_RESET 0 /* Reset the port */
+ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/usb/usb-gadgetfs-set-zero-flag-for-short-control-in-response.patch b/usb/usb-gadgetfs-set-zero-flag-for-short-control-in-response.patch
new file mode 100644
index 00000000000000..75905663f97130
--- /dev/null
+++ b/usb/usb-gadgetfs-set-zero-flag-for-short-control-in-response.patch
@@ -0,0 +1,63 @@
+From stern@rowland.harvard.edu Tue Jan 3 07:35:07 2006
+Date: Tue, 3 Jan 2006 10:30:31 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+cc: David Brownell <david-b@pacbell.net>
+Subject: USB: gadgetfs: set "zero" flag for short control-IN response
+Message-ID: <Pine.LNX.4.44L0.0601031022330.5297-100000@iolanthe.rowland.org>
+
+
+This patch (as622) makes gadgetfs set the "zero" flag for control-IN
+responses, when the length of the response is shorter than the length of
+the request.
+
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Acked-by: David Brownell <david-b@pacbell.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/gadget/inode.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/drivers/usb/gadget/inode.c
++++ gregkh-2.6/drivers/usb/gadget/inode.c
+@@ -135,6 +135,7 @@ struct dev_data {
+ setup_out_ready : 1,
+ setup_out_error : 1,
+ setup_abort : 1;
++ unsigned setup_wLength;
+
+ /* the rest is basically write-once */
+ struct usb_config_descriptor *config, *hs_config;
+@@ -942,6 +943,7 @@ static int setup_req (struct usb_ep *ep,
+ }
+ req->complete = ep0_complete;
+ req->length = len;
++ req->zero = 0;
+ return 0;
+ }
+
+@@ -1161,10 +1163,13 @@ ep0_write (struct file *fd, const char _
+ spin_unlock_irq (&dev->lock);
+ if (copy_from_user (dev->req->buf, buf, len))
+ retval = -EFAULT;
+- else
++ else {
++ if (len < dev->setup_wLength)
++ dev->req->zero = 1;
+ retval = usb_ep_queue (
+ dev->gadget->ep0, dev->req,
+ GFP_KERNEL);
++ }
+ if (retval < 0) {
+ spin_lock_irq (&dev->lock);
+ clean_req (dev->gadget->ep0, dev->req);
+@@ -1483,6 +1488,7 @@ unrecognized:
+ delegate:
+ dev->setup_in = (ctrl->bRequestType & USB_DIR_IN)
+ ? 1 : 0;
++ dev->setup_wLength = w_length;
+ dev->setup_out_ready = 0;
+ dev->setup_out_error = 0;
+ value = 0;
diff --git a/usb/usb-isp116x-hcd-replace-mdelay-by-msleep.patch b/usb/usb-isp116x-hcd-replace-mdelay-by-msleep.patch
new file mode 100644
index 00000000000000..639e8464025c33
--- /dev/null
+++ b/usb/usb-isp116x-hcd-replace-mdelay-by-msleep.patch
@@ -0,0 +1,77 @@
+From ok@artecdesign.ee Tue Dec 27 06:04:38 2005
+Date: Tue, 27 Dec 2005 16:04:02 +0200 (EET)
+From: Olav Kongas <ok@artecdesign.ee>
+To: Greg KH <greg@kroah.com>
+Subject: USB: isp116x-hcd: replace mdelay() by msleep()
+Message-ID: <Pine.LNX.4.63.0512271553090.5088@pcy.artec.ee>
+
+Replace mdelay() by msleep() in bus_suspend(); the rest of the system will
+gain 7ms. The related code is reorganized to minimize the number of
+locking/unlocking calls.
+
+The last hunk of the patch is the formatting change by Lindent.
+
+Signed-off-by: Olav Kongas <ok@artecdesign.ee>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/isp116x-hcd.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/isp116x-hcd.c
++++ gregkh-2.6/drivers/usb/host/isp116x-hcd.c
+@@ -1420,20 +1420,22 @@ static int isp116x_bus_suspend(struct us
+ int ret = 0;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+-
+ val = isp116x_read_reg32(isp116x, HCCONTROL);
++
+ switch (val & HCCONTROL_HCFS) {
+ case HCCONTROL_USB_OPER:
++ spin_unlock_irqrestore(&isp116x->lock, flags);
+ val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
+ val |= HCCONTROL_USB_SUSPEND;
+ if (device_may_wakeup(&hcd->self.root_hub->dev))
+ val |= HCCONTROL_RWE;
+ /* Wait for usb transfers to finish */
+- mdelay(2);
++ msleep(2);
++ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg32(isp116x, HCCONTROL, val);
++ spin_unlock_irqrestore(&isp116x->lock, flags);
+ /* Wait for devices to suspend */
+- mdelay(5);
+- case HCCONTROL_USB_SUSPEND:
++ msleep(5);
+ break;
+ case HCCONTROL_USB_RESUME:
+ isp116x_write_reg32(isp116x, HCCONTROL,
+@@ -1441,12 +1443,11 @@ static int isp116x_bus_suspend(struct us
+ HCCONTROL_USB_RESET);
+ case HCCONTROL_USB_RESET:
+ ret = -EBUSY;
++ default: /* HCCONTROL_USB_SUSPEND */
++ spin_unlock_irqrestore(&isp116x->lock, flags);
+ break;
+- default:
+- ret = -EINVAL;
+ }
+
+- spin_unlock_irqrestore(&isp116x->lock, flags);
+ return ret;
+ }
+
+@@ -1715,9 +1716,9 @@ static struct platform_driver isp116x_dr
+ .remove = isp116x_remove,
+ .suspend = isp116x_suspend,
+ .resume = isp116x_resume,
+- .driver = {
+- .name = (char *)hcd_name,
+- },
++ .driver = {
++ .name = (char *)hcd_name,
++ },
+ };
+
+ /*-----------------------------------------------------------------*/
diff --git a/usb/usb-kzalloc-for-hid.patch b/usb/usb-kzalloc-for-hid.patch
new file mode 100644
index 00000000000000..135bda27e1d8ed
--- /dev/null
+++ b/usb/usb-kzalloc-for-hid.patch
@@ -0,0 +1,150 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 12:50:01 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Michael Haboustak <mike-@cinci.rr.com>, Greg KH <gregkh@suse.de>, Vojtech Pavlik <vojtech@suse.cz>, dtor_core@ameritech.net
+Content-Disposition: inline
+Message-Id: <200601062054.30226.oliver@neukum.org>
+Subject: USB: kzalloc for hid
+Date: Fri, 6 Jan 2006 20:54:29 +0100
+
+this uses kzalloc in hid.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/input/hid-core.c | 18 +++++-------------
+ drivers/usb/input/hid-lgff.c | 6 ++----
+ drivers/usb/input/hid-tmff.c | 3 +--
+ drivers/usb/input/hiddev.c | 6 ++----
+ 4 files changed, 10 insertions(+), 23 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/input/hid-core.c
++++ gregkh-2.6/drivers/usb/input/hid-core.c
+@@ -66,9 +66,8 @@ static struct hid_report *hid_register_r
+ if (report_enum->report_id_hash[id])
+ return report_enum->report_id_hash[id];
+
+- if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
++ if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+ return NULL;
+- memset(report, 0, sizeof(struct hid_report));
+
+ if (id != 0)
+ report_enum->numbered = 1;
+@@ -97,12 +96,9 @@ static struct hid_field *hid_register_fi
+ return NULL;
+ }
+
+- if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
++ if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+ + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+
+- memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+- + values * sizeof(unsigned));
+-
+ field->index = report->maxfield++;
+ report->field[field->index] = field;
+ field->usage = (struct hid_usage *)(field + 1);
+@@ -651,17 +647,14 @@ static struct hid_device *hid_parse_repo
+ hid_parser_reserved
+ };
+
+- if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
++ if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
+ return NULL;
+- memset(device, 0, sizeof(struct hid_device));
+
+- if (!(device->collection = kmalloc(sizeof(struct hid_collection) *
++ if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
+ HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
+ kfree(device);
+ return NULL;
+ }
+- memset(device->collection, 0, sizeof(struct hid_collection) *
+- HID_DEFAULT_NUM_COLLECTIONS);
+ device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
+ for (i = 0; i < HID_REPORT_TYPES; i++)
+@@ -675,13 +668,12 @@ static struct hid_device *hid_parse_repo
+ memcpy(device->rdesc, start, size);
+ device->rsize = size;
+
+- if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
++ if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+ kfree(device->rdesc);
+ kfree(device->collection);
+ kfree(device);
+ return NULL;
+ }
+- memset(parser, 0, sizeof(struct hid_parser));
+ parser->device = device;
+
+ end = start + size;
+--- gregkh-2.6.orig/drivers/usb/input/hid-tmff.c
++++ gregkh-2.6/drivers/usb/input/hid-tmff.c
+@@ -113,11 +113,10 @@ int hid_tmff_init(struct hid_device *hid
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+ struct input_dev *input_dev = hidinput->input;
+
+- private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
++ private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
+ if (!private)
+ return -ENOMEM;
+
+- memset(private, 0, sizeof(struct tmff_device));
+ hid->ff_private = private;
+
+ /* Find the report to use */
+--- gregkh-2.6.orig/drivers/usb/input/hid-lgff.c
++++ gregkh-2.6/drivers/usb/input/hid-lgff.c
+@@ -154,10 +154,9 @@ int hid_lgff_init(struct hid_device* hid
+ return -1;
+ }
+
+- private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
++ private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
+ if (!private)
+ return -1;
+- memset(private, 0, sizeof(struct lgff_device));
+ hid->ff_private = private;
+
+ /* Input init */
+@@ -228,13 +227,12 @@ static struct hid_report* hid_lgff_dupli
+ }
+ *ret->field[0] = *report->field[0];
+
+- ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL);
++ ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
+ if (!ret->field[0]->value) {
+ kfree(ret->field[0]);
+ kfree(ret);
+ return NULL;
+ }
+- memset(ret->field[0]->value, 0, sizeof(s32[8]));
+
+ return ret;
+ }
+--- gregkh-2.6.orig/drivers/usb/input/hiddev.c
++++ gregkh-2.6/drivers/usb/input/hiddev.c
+@@ -258,9 +258,8 @@ static int hiddev_open(struct inode * in
+ if (i >= HIDDEV_MINORS || !hiddev_table[i])
+ return -ENODEV;
+
+- if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
++ if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+ return -ENOMEM;
+- memset(list, 0, sizeof(struct hiddev_list));
+
+ list->hiddev = hiddev_table[i];
+ list->next = hiddev_table[i]->list;
+@@ -755,9 +754,8 @@ int hiddev_connect(struct hid_device *hi
+ if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
+ return -1;
+
+- if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
++ if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
+ return -1;
+- memset(hiddev, 0, sizeof(struct hiddev));
+
+ retval = usb_register_dev(hid->intf, &hiddev_class);
+ if (retval) {
diff --git a/usb/usb-kzalloc-for-storage.patch b/usb/usb-kzalloc-for-storage.patch
new file mode 100644
index 00000000000000..e68e2afe52e2e0
--- /dev/null
+++ b/usb/usb-kzalloc-for-storage.patch
@@ -0,0 +1,112 @@
+From oliver@neukum.org Sun Jan 8 03:34:01 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: mdharm-usb@one-eyed-alien.net, usb-storage@lists.one-eyed-alien.net, Greg KH <gregkh@suse.de>
+Subject: USB: kzalloc for storage
+Content-Disposition: inline
+Date: Sun, 8 Jan 2006 12:33:45 +0100
+Message-Id: <200601081233.45552.oliver@neukum.org>
+
+another one for kzalloc. This covers the storage subdirectory.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/storage/datafab.c | 3 +--
+ drivers/usb/storage/isd200.c | 8 +++-----
+ drivers/usb/storage/jumpshot.c | 3 +--
+ drivers/usb/storage/sddr55.c | 3 +--
+ drivers/usb/storage/shuttle_usbat.c | 3 +--
+ 5 files changed, 7 insertions(+), 13 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/storage/datafab.c
++++ gregkh-2.6/drivers/usb/storage/datafab.c
+@@ -512,13 +512,12 @@ int datafab_transport(struct scsi_cmnd *
+ };
+
+ if (!us->extra) {
+- us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
++ us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
+ if (!us->extra) {
+ US_DEBUGP("datafab_transport: Gah! "
+ "Can't allocate storage for Datafab info struct!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+- memset(us->extra, 0, sizeof(struct datafab_info));
+ us->extra_destructor = datafab_info_destructor;
+ ((struct datafab_info *)us->extra)->lun = -1;
+ }
+--- gregkh-2.6.orig/drivers/usb/storage/isd200.c
++++ gregkh-2.6/drivers/usb/storage/isd200.c
+@@ -1361,21 +1361,19 @@ static int isd200_init_info(struct us_da
+ struct isd200_info *info;
+
+ info = (struct isd200_info *)
+- kmalloc(sizeof(struct isd200_info), GFP_KERNEL);
++ kzalloc(sizeof(struct isd200_info), GFP_KERNEL);
+ if (!info)
+ retStatus = ISD200_ERROR;
+ else {
+- memset(info, 0, sizeof(struct isd200_info));
+ info->id = (struct hd_driveid *)
+- kmalloc(sizeof(struct hd_driveid), GFP_KERNEL);
++ kzalloc(sizeof(struct hd_driveid), GFP_KERNEL);
+ info->RegsBuf = (unsigned char *)
+ kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
+ if (!info->id || !info->RegsBuf) {
+ isd200_free_info_ptrs(info);
+ kfree(info);
+ retStatus = ISD200_ERROR;
+- } else
+- memset(info->id, 0, sizeof(struct hd_driveid));
++ }
+ }
+
+ if (retStatus == ISD200_GOOD) {
+--- gregkh-2.6.orig/drivers/usb/storage/jumpshot.c
++++ gregkh-2.6/drivers/usb/storage/jumpshot.c
+@@ -441,12 +441,11 @@ int jumpshot_transport(struct scsi_cmnd
+ };
+
+ if (!us->extra) {
+- us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
++ us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+ if (!us->extra) {
+ US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+- memset(us->extra, 0, sizeof(struct jumpshot_info));
+ us->extra_destructor = jumpshot_info_destructor;
+ }
+
+--- gregkh-2.6.orig/drivers/usb/storage/sddr55.c
++++ gregkh-2.6/drivers/usb/storage/sddr55.c
+@@ -751,11 +751,10 @@ int sddr55_transport(struct scsi_cmnd *s
+ struct sddr55_card_info *info;
+
+ if (!us->extra) {
+- us->extra = kmalloc(
++ us->extra = kzalloc(
+ sizeof(struct sddr55_card_info), GFP_NOIO);
+ if (!us->extra)
+ return USB_STOR_TRANSPORT_ERROR;
+- memset(us->extra, 0, sizeof(struct sddr55_card_info));
+ us->extra_destructor = sddr55_card_info_destructor;
+ }
+
+--- gregkh-2.6.orig/drivers/usb/storage/shuttle_usbat.c
++++ gregkh-2.6/drivers/usb/storage/shuttle_usbat.c
+@@ -1318,12 +1318,11 @@ int init_usbat(struct us_data *us)
+ unsigned char subcountL = USBAT_ATA_LBA_ME;
+ unsigned char *status = us->iobuf;
+
+- us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
++ us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
+ if (!us->extra) {
+ US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
+ return 1;
+ }
+- memset(us->extra, 0, sizeof(struct usbat_info));
+ info = (struct usbat_info *) (us->extra);
+
+ /* Enable peripheral control signals */
diff --git a/usb/usb-kzalloc-in-cytherm.patch b/usb/usb-kzalloc-in-cytherm.patch
new file mode 100644
index 00000000000000..efadd4a6518c1a
--- /dev/null
+++ b/usb/usb-kzalloc-in-cytherm.patch
@@ -0,0 +1,34 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 13:28:33 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Erik Rigtorp <erkki@linux.nu>
+Content-Disposition: inline
+Message-Id: <200601062224.56945.oliver@neukum.org>
+Subject: USB: kzalloc in cytherm
+Date: Fri, 6 Jan 2006 22:24:56 +0100
+
+
+another one for kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/cytherm.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/cytherm.c
++++ gregkh-2.6/drivers/usb/misc/cytherm.c
+@@ -351,12 +351,11 @@ static int cytherm_probe(struct usb_inte
+ struct usb_cytherm *dev = NULL;
+ int retval = -ENOMEM;
+
+- dev = kmalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
++ dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err (&interface->dev, "Out of memory\n");
+ goto error;
+ }
+- memset (dev, 0x00, sizeof (*dev));
+
+ dev->udev = usb_get_dev(udev);
+
diff --git a/usb/usb-kzalloc-in-dabusb.patch b/usb/usb-kzalloc-in-dabusb.patch
new file mode 100644
index 00000000000000..c3480eb7aa171b
--- /dev/null
+++ b/usb/usb-kzalloc-in-dabusb.patch
@@ -0,0 +1,34 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 12:50:10 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: deti@fliegl.de
+Content-Disposition: inline
+Message-Id: <200601062101.47610.oliver@neukum.org>
+Subject: USB: kzalloc in dabusb
+Date: Fri, 6 Jan 2006 21:01:47 +0100
+
+kzalloc in dabusb.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/media/dabusb.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/media/dabusb.c
++++ gregkh-2.6/drivers/usb/media/dabusb.c
+@@ -217,12 +217,11 @@ static int dabusb_alloc_buffers (pdabusb
+ pipesize, packets, transfer_buffer_length);
+
+ while (buffers < (s->total_buffer_size << 10)) {
+- b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL);
++ b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
+ if (!b) {
+- err("kmalloc(sizeof(buff_t))==NULL");
++ err("kzalloc(sizeof(buff_t))==NULL");
+ goto err;
+ }
+- memset (b, 0, sizeof (buff_t));
+ b->s = s;
+ b->purb = usb_alloc_urb(packets, GFP_KERNEL);
+ if (!b->purb) {
diff --git a/usb/usb-kzalloc-in-idmouse.patch b/usb/usb-kzalloc-in-idmouse.patch
new file mode 100644
index 00000000000000..e76ea15893469f
--- /dev/null
+++ b/usb/usb-kzalloc-in-idmouse.patch
@@ -0,0 +1,32 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 13:39:07 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: echtler@fs.tum.de, aderesch@fs.tum.de
+Content-Disposition: inline
+Message-Id: <200601062236.27991.oliver@neukum.org>
+Subject: USB: kzalloc in idmouse
+Date: Fri, 6 Jan 2006 22:36:27 +0100
+
+
+another for kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/idmouse.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/idmouse.c
++++ gregkh-2.6/drivers/usb/misc/idmouse.c
+@@ -340,10 +340,9 @@ static int idmouse_probe(struct usb_inte
+ return -ENODEV;
+
+ /* allocate memory for our device state and initialize it */
+- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL)
+ return -ENOMEM;
+- memset(dev, 0x00, sizeof(*dev));
+
+ init_MUTEX(&dev->sem);
+ dev->udev = udev;
diff --git a/usb/usb-kzalloc-in-ldusb.patch b/usb/usb-kzalloc-in-ldusb.patch
new file mode 100644
index 00000000000000..25dc0086c8fbd8
--- /dev/null
+++ b/usb/usb-kzalloc-in-ldusb.patch
@@ -0,0 +1,34 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 13:44:37 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Michael Hund <mhund@ld-didactic.de>
+Content-Disposition: inline
+Message-Id: <200601062240.02686.oliver@neukum.org>
+Subject: USB: kzalloc in ldusb
+Date: Fri, 6 Jan 2006 22:40:02 +0100
+
+
+another one for kzalloc
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/ldusb.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/ldusb.c
++++ gregkh-2.6/drivers/usb/misc/ldusb.c
+@@ -619,12 +619,11 @@ static int ld_usb_probe(struct usb_inter
+
+ /* allocate memory for our device state and intialize it */
+
+- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&intf->dev, "Out of memory\n");
+ goto exit;
+ }
+- memset(dev, 0x00, sizeof(*dev));
+ init_MUTEX(&dev->sem);
+ dev->intf = intf;
+ init_waitqueue_head(&dev->read_wait);
diff --git a/usb/usb-kzalloc-in-phidgetinterfacekit.patch b/usb/usb-kzalloc-in-phidgetinterfacekit.patch
new file mode 100644
index 00000000000000..7b6c99c05ccf40
--- /dev/null
+++ b/usb/usb-kzalloc-in-phidgetinterfacekit.patch
@@ -0,0 +1,68 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 13:44:40 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Sean Young <sean@mess.org>
+Content-Disposition: inline
+Message-Id: <200601062241.51664.oliver@neukum.org>
+Subject: USB: kzalloc in PhidgetInterfaceKit
+Date: Fri, 6 Jan 2006 22:41:51 +0100
+
+
+another for kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/phidgetkit.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/phidgetkit.c
++++ gregkh-2.6/drivers/usb/misc/phidgetkit.c
+@@ -88,7 +88,7 @@ static int change_outputs(struct phidget
+ int retval;
+ int n;
+
+- buffer = kmalloc(4, GFP_KERNEL);
++ buffer = kzalloc(4, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&kit->udev->dev, "%s - out of memory\n",
+ __FUNCTION__);
+@@ -96,7 +96,6 @@ static int change_outputs(struct phidget
+ }
+
+ kit->outputs[output_num] = enable;
+- memset(buffer, 0, 4);
+ for (n=0; n<8; n++) {
+ if (kit->outputs[n]) {
+ buffer[0] |= 1 << n;
+@@ -192,7 +191,7 @@ static ssize_t set_backlight(struct devi
+ unsigned char *buffer;
+ int retval = -ENOMEM;
+
+- buffer = kmalloc(8, GFP_KERNEL);
++ buffer = kzalloc(8, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
+ goto exit;
+@@ -202,7 +201,6 @@ static ssize_t set_backlight(struct devi
+ retval = -EINVAL;
+ goto exit;
+ }
+- memset(buffer, 0x00, 8);
+ if (enabled)
+ buffer[0] = 0x01;
+ buffer[7] = 0x11;
+@@ -406,12 +404,11 @@ static int interfacekit_probe(struct usb
+ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+- kit = kmalloc(sizeof(*kit), GFP_KERNEL);
++ kit = kzalloc(sizeof(*kit), GFP_KERNEL);
+ if (kit == NULL) {
+ dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+- memset(kit, 0, sizeof(*kit));
+ kit->ifkit = ifkit;
+
+ kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma);
diff --git a/usb/usb-kzalloc-in-phidgetservo.patch b/usb/usb-kzalloc-in-phidgetservo.patch
new file mode 100644
index 00000000000000..35a312e1f07f5d
--- /dev/null
+++ b/usb/usb-kzalloc-in-phidgetservo.patch
@@ -0,0 +1,33 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 13:44:48 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Sean Young <sean@mess.org>
+Content-Disposition: inline
+Message-Id: <200601062243.33015.oliver@neukum.org>
+Subject: USB: kzalloc in PhidgetServo
+Date: Fri, 6 Jan 2006 22:43:32 +0100
+
+another for kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/phidgetservo.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/phidgetservo.c
++++ gregkh-2.6/drivers/usb/misc/phidgetservo.c
+@@ -252,12 +252,11 @@ servo_probe(struct usb_interface *interf
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct phidget_servo *dev;
+
+- dev = kmalloc(sizeof (struct phidget_servo), GFP_KERNEL);
++ dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+- memset(dev, 0x00, sizeof (*dev));
+
+ dev->udev = usb_get_dev(udev);
+ dev->type = id->driver_info;
diff --git a/usb/usb-kzalloc-in-sisusbvga.patch b/usb/usb-kzalloc-in-sisusbvga.patch
new file mode 100644
index 00000000000000..395355e1b333ff
--- /dev/null
+++ b/usb/usb-kzalloc-in-sisusbvga.patch
@@ -0,0 +1,44 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 14:32:41 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Thomas Winischhofer <thomas@winischhofer.net>
+Content-Disposition: inline
+Message-Id: <200601062327.17654.oliver@neukum.org>
+Subject: USB: kzalloc in sisusbvga
+Date: Fri, 6 Jan 2006 23:27:17 +0100
+
+this does two things:
+- use kzalloc where appropriate
+- correct error return codes in ioctl
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/sisusbvga/sisusb.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/sisusbvga/sisusb.c
++++ gregkh-2.6/drivers/usb/misc/sisusbvga/sisusb.c
+@@ -3188,7 +3188,7 @@ sisusb_ioctl(struct inode *inode, struct
+ break;
+
+ default:
+- retval = -EINVAL;
++ retval = -ENOTTY;
+ break;
+ }
+
+@@ -3251,12 +3251,11 @@ static int sisusb_probe(struct usb_inter
+ dev->devnum);
+
+ /* Allocate memory for our private */
+- if (!(sisusb = kmalloc(sizeof(*sisusb), GFP_KERNEL))) {
++ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
+ printk(KERN_ERR
+ "sisusb: Failed to allocate memory for private data\n");
+ return -ENOMEM;
+ }
+- memset(sisusb, 0, sizeof(*sisusb));
+ kref_init(&sisusb->kref);
+
+ init_MUTEX(&(sisusb->lock));
diff --git a/usb/usb-kzalloc-in-usbled.patch b/usb/usb-kzalloc-in-usbled.patch
new file mode 100644
index 00000000000000..8d15096d746b21
--- /dev/null
+++ b/usb/usb-kzalloc-in-usbled.patch
@@ -0,0 +1,33 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 13:49:54 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Greg KH <gregkh@suse.de>
+Content-Disposition: inline
+Message-Id: <200601062244.52481.oliver@neukum.org>
+Subject: USB: kzalloc in usbled
+Date: Fri, 6 Jan 2006 22:44:52 +0100
+
+another one for kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/misc/usbled.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/misc/usbled.c
++++ gregkh-2.6/drivers/usb/misc/usbled.c
+@@ -106,12 +106,11 @@ static int led_probe(struct usb_interfac
+ struct usb_led *dev = NULL;
+ int retval = -ENOMEM;
+
+- dev = kmalloc(sizeof(struct usb_led), GFP_KERNEL);
++ dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ goto error;
+ }
+- memset (dev, 0x00, sizeof (*dev));
+
+ dev->udev = usb_get_dev(udev);
+
diff --git a/usb/usb-kzalloc-in-usbvideo.patch b/usb/usb-kzalloc-in-usbvideo.patch
new file mode 100644
index 00000000000000..5ee011ed54a465
--- /dev/null
+++ b/usb/usb-kzalloc-in-usbvideo.patch
@@ -0,0 +1,35 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 12:52:07 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Greg KH <gregkh@suse.de>
+Content-Disposition: inline
+Message-Id: <200601062135.09101.oliver@neukum.org>
+Subject: USB: kzalloc in usbvideo
+Date: Fri, 6 Jan 2006 21:35:08 +0100
+
+another for kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/media/usbvideo.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/media/usbvideo.c
++++ gregkh-2.6/drivers/usb/media/usbvideo.c
+@@ -690,14 +690,13 @@ int usbvideo_register(
+ }
+
+ base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
+- cams = (struct usbvideo *) kmalloc(base_size, GFP_KERNEL);
++ cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
+ if (cams == NULL) {
+ err("Failed to allocate %d. bytes for usbvideo struct", base_size);
+ return -ENOMEM;
+ }
+ dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
+ __FUNCTION__, cams, base_size, num_cams);
+- memset(cams, 0, base_size);
+
+ /* Copy callbacks, apply defaults for those that are not set */
+ memmove(&cams->cb, cbTbl, sizeof(cams->cb));
diff --git a/usb/usb-kzalloc-in-w9968cf.patch b/usb/usb-kzalloc-in-w9968cf.patch
new file mode 100644
index 00000000000000..384200e4cbf740
--- /dev/null
+++ b/usb/usb-kzalloc-in-w9968cf.patch
@@ -0,0 +1,73 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 12:51:54 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Luca Risolia <luca.risolia@studio.unibo.it>, Greg KH <gregkh@suse.de>
+Content-Disposition: inline
+Message-Id: <200601062128.41016.oliver@neukum.org>
+Subject: USB: kzalloc in w9968cf
+Date: Fri, 6 Jan 2006 21:28:40 +0100
+
+another one for kzalloc.
+
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/media/w9968cf.c | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/media/w9968cf.c
++++ gregkh-2.6/drivers/usb/media/w9968cf.c
+@@ -695,13 +695,12 @@ static int w9968cf_allocate_memory(struc
+ /* Allocate memory for the isochronous transfer buffers */
+ for (i = 0; i < W9968CF_URBS; i++) {
+ if (!(cam->transfer_buffer[i] =
+- kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
++ kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
+ DBG(1, "Couldn't allocate memory for the isochronous "
+ "transfer buffers (%u bytes)",
+ p_size * W9968CF_ISO_PACKETS)
+ return -ENOMEM;
+ }
+- memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size);
+ }
+
+ /* Allocate memory for the temporary frame buffer */
+@@ -3498,12 +3497,10 @@ w9968cf_usb_probe(struct usb_interface*
+ return -ENODEV;
+
+ cam = (struct w9968cf_device*)
+- kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
++ kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
+ if (!cam)
+ return -ENOMEM;
+
+- memset(cam, 0, sizeof(*cam));
+-
+ init_MUTEX(&cam->dev_sem);
+ down(&cam->dev_sem);
+
+@@ -3531,21 +3528,19 @@ w9968cf_usb_probe(struct usb_interface*
+
+
+ /* Allocate 2 bytes of memory for camera control USB transfers */
+- if (!(cam->control_buffer = kmalloc(2, GFP_KERNEL))) {
++ if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
+ DBG(1,"Couldn't allocate memory for camera control transfers")
+ err = -ENOMEM;
+ goto fail;
+ }
+- memset(cam->control_buffer, 0, 2);
+
+ /* Allocate 8 bytes of memory for USB data transfers to the FSB */
+- if (!(cam->data_buffer = kmalloc(8, GFP_KERNEL))) {
++ if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
+ DBG(1, "Couldn't allocate memory for data "
+ "transfers to the FSB")
+ err = -ENOMEM;
+ goto fail;
+ }
+- memset(cam->data_buffer, 0, 8);
+
+ /* Register the V4L device */
+ cam->v4ldev = video_device_alloc();
diff --git a/usb/usb-mdc800.c-to-kzalloc.patch b/usb/usb-mdc800.c-to-kzalloc.patch
new file mode 100644
index 00000000000000..90afc0de6b16b1
--- /dev/null
+++ b/usb/usb-mdc800.c-to-kzalloc.patch
@@ -0,0 +1,35 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 12:49:49 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Henning Zabel <henning@uni-paderborn.de>
+Content-Disposition: inline
+Message-Id: <200601062045.11939.oliver@neukum.org>
+Subject: USB: mdc800.c to kzalloc
+Date: Fri, 6 Jan 2006 20:45:11 +0100
+
+
+one more conversion to kzalloc.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/image/mdc800.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/image/mdc800.c
++++ gregkh-2.6/drivers/usb/image/mdc800.c
+@@ -978,13 +978,11 @@ static int __init usb_mdc800_init (void)
+ {
+ int retval = -ENODEV;
+ /* Allocate Memory */
+- mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
++ mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL);
+ if (!mdc800)
+ goto cleanup_on_fail;
+
+- memset(mdc800, 0, sizeof(struct mdc800_data));
+ mdc800->dev = NULL;
+- mdc800->open=0;
+ mdc800->state=NOT_CONNECTED;
+ init_MUTEX (&mdc800->io_lock);
+
diff --git a/usb/usb-new-id-for-ftdi_sio.c-and-ftdi_sio.h.patch b/usb/usb-new-id-for-ftdi_sio.c-and-ftdi_sio.h.patch
new file mode 100644
index 00000000000000..4a5bd654f49204
--- /dev/null
+++ b/usb/usb-new-id-for-ftdi_sio.c-and-ftdi_sio.h.patch
@@ -0,0 +1,47 @@
+From louis.nyffenegger@gmail.com Thu Jan 5 08:53:35 2006
+Message-ID: <43BD4755.3020902@gmail.com>
+Date: Thu, 05 Jan 2006 17:20:37 +0100
+From: Louis Nyffenegger <louis.nyffenegger@gmail.com>
+To: greg@kroah.com
+Subject: USB: new id for ftdi_sio.c and ftdi_sio.h
+
+this patch includes the Vendor Id for a optic fiber to USB device named
+TTUSB from thought Technology. It's just add the vendor Id to
+ftdi_sio.h and add the Vendor ID and model Id to table_combined.
+
+Signed-off-by: Louis Nyffenegger <louis.nyffenegger@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/serial/ftdi_sio.c | 1 +
+ drivers/usb/serial/ftdi_sio.h | 5 +++++
+ 2 files changed, 6 insertions(+)
+
+--- gregkh-2.6.orig/drivers/usb/serial/ftdi_sio.h
++++ gregkh-2.6/drivers/usb/serial/ftdi_sio.h
+@@ -31,9 +31,14 @@
+ #define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
+ #define FTDI_NF_RIC_PID 0x0001 /* Product Id */
+
++
+ /* www.irtrans.de device */
+ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
+
++
++/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */
++#define FTDI_TTUSB_PID 0xFF20 /* Product Id */
++
+ /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
+ /* they use the ftdi chipset for the USB interface and the vendor id is the same */
+ #define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
+--- gregkh-2.6.orig/drivers/usb/serial/ftdi_sio.c
++++ gregkh-2.6/drivers/usb/serial/ftdi_sio.c
+@@ -480,6 +480,7 @@ static struct usb_device_id id_table_com
+ { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
+ { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
+ { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
++ { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
+ { }, /* Optional parameter entry */
+ { } /* Terminating entry */
+ };
diff --git a/usb/usb-optimise-devio.c-usbdev_read.patch b/usb/usb-optimise-devio.c-usbdev_read.patch
new file mode 100644
index 00000000000000..f7585a6bc75fa9
--- /dev/null
+++ b/usb/usb-optimise-devio.c-usbdev_read.patch
@@ -0,0 +1,56 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 12:51:44 2006
+From: Oliver Neukum <oliver@neukum.org>
+To: Pete Zaitcev <zaitcev@redhat.com>
+Subject: USB: optimise devio.c::usbdev_read
+Cc: gregkh@suse.de
+Content-Disposition: inline
+Message-Id: <200601062124.25970.oliver@neukum.org>
+Date: Fri, 6 Jan 2006 21:24:25 +0100
+
+this is a small optimisation. It is ridiculous to do a kmalloc for
+18 bytes. This puts it onto the stack.
+
+Signed-off-by: Oliver Neukum <oliver@neukum.name>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/core/devio.c | 21 ++++++++-------------
+ 1 file changed, 8 insertions(+), 13 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/core/devio.c
++++ gregkh-2.6/drivers/usb/core/devio.c
+@@ -134,26 +134,21 @@ static ssize_t usbdev_read(struct file *
+ }
+
+ if (pos < sizeof(struct usb_device_descriptor)) {
+- struct usb_device_descriptor *desc = kmalloc(sizeof(*desc), GFP_KERNEL);
+- if (!desc) {
+- ret = -ENOMEM;
+- goto err;
+- }
+- memcpy(desc, &dev->descriptor, sizeof(dev->descriptor));
+- le16_to_cpus(&desc->bcdUSB);
+- le16_to_cpus(&desc->idVendor);
+- le16_to_cpus(&desc->idProduct);
+- le16_to_cpus(&desc->bcdDevice);
++ struct usb_device_descriptor temp_desc ; /* 18 bytes - fits on the stack */
++
++ memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor));
++ le16_to_cpus(&temp_desc->bcdUSB);
++ le16_to_cpus(&temp_desc->idVendor);
++ le16_to_cpus(&temp_desc->idProduct);
++ le16_to_cpus(&temp_desc->bcdDevice);
+
+ len = sizeof(struct usb_device_descriptor) - pos;
+ if (len > nbytes)
+ len = nbytes;
+- if (copy_to_user(buf, ((char *)desc) + pos, len)) {
+- kfree(desc);
++ if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) {
+ ret = -EFAULT;
+ goto err;
+ }
+- kfree(desc);
+
+ *ppos += len;
+ buf += len;
diff --git a/usb/usb-remove-extra-newline-in-hid_init_reports.patch b/usb/usb-remove-extra-newline-in-hid_init_reports.patch
new file mode 100644
index 00000000000000..050a656ee35e1d
--- /dev/null
+++ b/usb/usb-remove-extra-newline-in-hid_init_reports.patch
@@ -0,0 +1,30 @@
+From linux-usb-devel-admin@lists.sourceforge.net Fri Jan 6 03:48:03 2006
+From: Olaf Hering <olh@suse.de>
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Message-ID: <20060106114528.GA9640@suse.de>
+Content-Disposition: inline
+Subject: USB: remove extra newline in hid_init_reports
+Date: Fri, 6 Jan 2006 12:45:28 +0100
+
+
+The warn() macro in include/linux/usb.h adds a newline.
+
+Signed-off-by: Olaf Hering <olh@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/input/hid-core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- gregkh-2.6.orig/drivers/usb/input/hid-core.c
++++ gregkh-2.6/drivers/usb/input/hid-core.c
+@@ -1307,7 +1307,7 @@ void hid_init_reports(struct hid_device
+ }
+
+ if (err)
+- warn("timeout initializing reports\n");
++ warn("timeout initializing reports");
+ }
+
+ #define USB_VENDOR_ID_WACOM 0x056a
diff --git a/usb/usb-remove-linux_version_code-check-in-pwc-pwc-ctrl.c.patch b/usb/usb-remove-linux_version_code-check-in-pwc-pwc-ctrl.c.patch
new file mode 100644
index 00000000000000..eb1c9f6b732cd3
--- /dev/null
+++ b/usb/usb-remove-linux_version_code-check-in-pwc-pwc-ctrl.c.patch
@@ -0,0 +1,490 @@
+From kernel-janitors-bounces@lists.osdl.org Wed Jan 4 09:16:27 2006
+From: Eric Sesterhenn / snakebyte <snakebyte@gmx.de>
+Date: Wed, 04 Jan 2006 18:10:44 +0100
+Message-Id: <1136394645.4692.3.camel@localhost>
+Subject: USB: Remove LINUX_VERSION_CODE check in pwc/pwc-ctrl.c
+
+this patch removes compatibility with 2.4 kernel, which makes
+the code much easier to read.
+
+Signed-off-by: Eric Sesterhenn <snakebyte@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/media/pwc/pwc-ctrl.c | 264 +++++++++++++--------------------------
+ 1 file changed, 89 insertions(+), 175 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/media/pwc/pwc-ctrl.c
++++ gregkh-2.6/drivers/usb/media/pwc/pwc-ctrl.c
+@@ -1152,45 +1152,6 @@ int pwc_get_cmos_sensor(struct pwc_devic
+ /* End of Add-Ons */
+ /* ************************************************* */
+
+-/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+- ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+- and copy_to_user() calls. With these macros we circumvent this,
+- and let me maintain only one source file. The functionality is
+- exactly the same otherwise.
+- */
+-
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+-
+-/* define local variable for arg */
+-#define ARG_DEF(ARG_type, ARG_name)\
+- ARG_type *ARG_name = arg;
+-/* copy arg to local variable */
+-#define ARG_IN(ARG_name) /* nothing */
+-/* argument itself (referenced) */
+-#define ARGR(ARG_name) (*ARG_name)
+-/* argument address */
+-#define ARGA(ARG_name) ARG_name
+-/* copy local variable to arg */
+-#define ARG_OUT(ARG_name) /* nothing */
+-
+-#else
+-
+-#define ARG_DEF(ARG_type, ARG_name)\
+- ARG_type ARG_name;
+-#define ARG_IN(ARG_name)\
+- if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\
+- ret = -EFAULT;\
+- break;\
+- }
+-#define ARGR(ARG_name) ARG_name
+-#define ARGA(ARG_name) &ARG_name
+-#define ARG_OUT(ARG_name)\
+- if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\
+- ret = -EFAULT;\
+- break;\
+- }
+-
+-#endif
+
+ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
+ {
+@@ -1220,243 +1181,206 @@ int pwc_ioctl(struct pwc_device *pdev, u
+
+ case VIDIOCPWCSCQUAL:
+ {
+- ARG_DEF(int, qual)
++ int *qual = arg;
+
+- ARG_IN(qual)
+- if (ARGR(qual) < 0 || ARGR(qual) > 3)
++ if (*qual < 0 || *qual > 3)
+ ret = -EINVAL;
+ else
+- ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
++ ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+ if (ret >= 0)
+- pdev->vcompression = ARGR(qual);
++ pdev->vcompression = *qual;
+ break;
+ }
+
+ case VIDIOCPWCGCQUAL:
+ {
+- ARG_DEF(int, qual)
+-
+- ARGR(qual) = pdev->vcompression;
+- ARG_OUT(qual)
++ int *qual = arg;
++ *qual = pdev->vcompression;
+ break;
+ }
+
+ case VIDIOCPWCPROBE:
+ {
+- ARG_DEF(struct pwc_probe, probe)
+-
+- strcpy(ARGR(probe).name, pdev->vdev->name);
+- ARGR(probe).type = pdev->type;
+- ARG_OUT(probe)
++ struct pwc_probe *probe = arg;
++ strcpy(probe->name, pdev->vdev->name);
++ probe->type = pdev->type;
+ break;
+ }
+
+ case VIDIOCPWCGSERIAL:
+ {
+- ARG_DEF(struct pwc_serial, serial)
+-
+- strcpy(ARGR(serial).serial, pdev->serial);
+- ARG_OUT(serial)
++ struct pwc_serial *serial = arg;
++ strcpy(serial->serial, pdev->serial);
+ break;
+ }
+
+ case VIDIOCPWCSAGC:
+ {
+- ARG_DEF(int, agc)
+-
+- ARG_IN(agc)
+- if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
++ int *agc = arg;
++ if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+ ret = -EINVAL;
+ break;
+ }
+
+ case VIDIOCPWCGAGC:
+ {
+- ARG_DEF(int, agc)
++ int *agc = arg;
+
+- if (pwc_get_agc(pdev, ARGA(agc)))
++ if (pwc_get_agc(pdev, agc))
+ ret = -EINVAL;
+- ARG_OUT(agc)
+ break;
+ }
+
+ case VIDIOCPWCSSHUTTER:
+ {
+- ARG_DEF(int, shutter_speed)
+-
+- ARG_IN(shutter_speed)
+- ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
++ int *shutter_speed = arg;
++ ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+ break;
+ }
+
+ case VIDIOCPWCSAWB:
+ {
+- ARG_DEF(struct pwc_whitebalance, wb)
++ struct pwc_whitebalance *wb = arg;
+
+- ARG_IN(wb)
+- ret = pwc_set_awb(pdev, ARGR(wb).mode);
+- if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+- pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+- pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
++ ret = pwc_set_awb(pdev, wb->mode);
++ if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
++ pwc_set_red_gain(pdev, wb->manual_red);
++ pwc_set_blue_gain(pdev, wb->manual_blue);
+ }
+ break;
+ }
+
+ case VIDIOCPWCGAWB:
+ {
+- ARG_DEF(struct pwc_whitebalance, wb)
++ struct pwc_whitebalance *wb = arg;
+
+- memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+- ARGR(wb).mode = pwc_get_awb(pdev);
+- if (ARGR(wb).mode < 0)
++ memset(wb, 0, sizeof(struct pwc_whitebalance));
++ wb->mode = pwc_get_awb(pdev);
++ if (wb->mode < 0)
+ ret = -EINVAL;
+ else {
+- if (ARGR(wb).mode == PWC_WB_MANUAL) {
+- ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
++ if (wb->mode == PWC_WB_MANUAL) {
++ ret = pwc_get_red_gain(pdev, &wb->manual_red);
+ if (ret < 0)
+ break;
+- ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
++ ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+ if (ret < 0)
+ break;
+ }
+- if (ARGR(wb).mode == PWC_WB_AUTO) {
+- ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
++ if (wb->mode == PWC_WB_AUTO) {
++ ret = pwc_read_red_gain(pdev, &wb->read_red);
+ if (ret < 0)
+ break;
+- ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
++ ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+ if (ret < 0)
+ break;
+ }
+ }
+- ARG_OUT(wb)
+ break;
+ }
+
+ case VIDIOCPWCSAWBSPEED:
+ {
+- ARG_DEF(struct pwc_wb_speed, wbs)
++ struct pwc_wb_speed *wbs = arg;
+
+- if (ARGR(wbs).control_speed > 0) {
+- ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
++ if (wbs->control_speed > 0) {
++ ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+ }
+- if (ARGR(wbs).control_delay > 0) {
+- ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
++ if (wbs->control_delay > 0) {
++ ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+ }
+ break;
+ }
+
+ case VIDIOCPWCGAWBSPEED:
+ {
+- ARG_DEF(struct pwc_wb_speed, wbs)
++ struct pwc_wb_speed *wbs = arg;
+
+- ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
++ ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+ if (ret < 0)
+ break;
+- ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
++ ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+ if (ret < 0)
+ break;
+- ARG_OUT(wbs)
+ break;
+ }
+
+ case VIDIOCPWCSLED:
+ {
+- ARG_DEF(struct pwc_leds, leds)
+-
+- ARG_IN(leds)
+- ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
++ struct pwc_leds *leds = arg;
++ ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
+ break;
+ }
+
+
+ case VIDIOCPWCGLED:
+ {
+- ARG_DEF(struct pwc_leds, leds)
+-
+- ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+- ARG_OUT(leds)
++ struct pwc_leds *leds = arg;
++ ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+ break;
+ }
+
+ case VIDIOCPWCSCONTOUR:
+ {
+- ARG_DEF(int, contour)
+-
+- ARG_IN(contour)
+- ret = pwc_set_contour(pdev, ARGR(contour));
++ int *contour = arg;
++ ret = pwc_set_contour(pdev, *contour);
+ break;
+ }
+
+ case VIDIOCPWCGCONTOUR:
+ {
+- ARG_DEF(int, contour)
+-
+- ret = pwc_get_contour(pdev, ARGA(contour));
+- ARG_OUT(contour)
++ int *contour = arg;
++ ret = pwc_get_contour(pdev, contour);
+ break;
+ }
+
+ case VIDIOCPWCSBACKLIGHT:
+ {
+- ARG_DEF(int, backlight)
+-
+- ARG_IN(backlight)
+- ret = pwc_set_backlight(pdev, ARGR(backlight));
++ int *backlight = arg;
++ ret = pwc_set_backlight(pdev, *backlight);
+ break;
+ }
+
+ case VIDIOCPWCGBACKLIGHT:
+ {
+- ARG_DEF(int, backlight)
+-
+- ret = pwc_get_backlight(pdev, ARGA(backlight));
+- ARG_OUT(backlight)
++ int *backlight = arg;
++ ret = pwc_get_backlight(pdev, backlight);
+ break;
+ }
+
+ case VIDIOCPWCSFLICKER:
+ {
+- ARG_DEF(int, flicker)
+-
+- ARG_IN(flicker)
+- ret = pwc_set_flicker(pdev, ARGR(flicker));
++ int *flicker = arg;
++ ret = pwc_set_flicker(pdev, *flicker);
+ break;
+ }
+
+ case VIDIOCPWCGFLICKER:
+ {
+- ARG_DEF(int, flicker)
+-
+- ret = pwc_get_flicker(pdev, ARGA(flicker));
+- ARG_OUT(flicker)
++ int *flicker = arg;
++ ret = pwc_get_flicker(pdev, flicker);
+ break;
+ }
+
+ case VIDIOCPWCSDYNNOISE:
+ {
+- ARG_DEF(int, dynnoise)
+-
+- ARG_IN(dynnoise)
+- ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
++ int *dynnoise = arg;
++ ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+ break;
+ }
+
+ case VIDIOCPWCGDYNNOISE:
+ {
+- ARG_DEF(int, dynnoise)
+-
+- ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+- ARG_OUT(dynnoise);
++ int *dynnoise = arg;
++ ret = pwc_get_dynamic_noise(pdev, dynnoise);
+ break;
+ }
+
+ case VIDIOCPWCGREALSIZE:
+ {
+- ARG_DEF(struct pwc_imagesize, size)
+-
+- ARGR(size).width = pdev->image.x;
+- ARGR(size).height = pdev->image.y;
+- ARG_OUT(size)
++ struct pwc_imagesize *size = arg;
++ size->width = pdev->image.x;
++ size->height = pdev->image.y;
+ break;
+ }
+
+@@ -1464,10 +1388,9 @@ int pwc_ioctl(struct pwc_device *pdev, u
+ {
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ {
+- ARG_DEF(int, flags)
++ int *flags = arg;
+
+- ARG_IN(flags)
+- ret = pwc_mpt_reset(pdev, ARGR(flags));
++ ret = pwc_mpt_reset(pdev, *flags);
+ if (ret >= 0)
+ {
+ pdev->pan_angle = 0;
+@@ -1485,10 +1408,8 @@ int pwc_ioctl(struct pwc_device *pdev, u
+ {
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ {
+- ARG_DEF(struct pwc_mpt_range, range)
+-
+- ARGR(range) = pdev->angle_range;
+- ARG_OUT(range)
++ struct pwc_mpt_range *range = arg;
++ *range = pdev->angle_range;
+ }
+ else
+ {
+@@ -1503,21 +1424,19 @@ int pwc_ioctl(struct pwc_device *pdev, u
+
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ {
+- ARG_DEF(struct pwc_mpt_angles, angles)
+-
+- ARG_IN(angles)
++ struct pwc_mpt_angles *angles = arg;
+ /* The camera can only set relative angles, so
+ do some calculations when getting an absolute angle .
+ */
+- if (ARGR(angles).absolute)
++ if (angles->absolute)
+ {
+- new_pan = ARGR(angles).pan;
+- new_tilt = ARGR(angles).tilt;
++ new_pan = angles->pan;
++ new_tilt = angles->tilt;
+ }
+ else
+ {
+- new_pan = pdev->pan_angle + ARGR(angles).pan;
+- new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
++ new_pan = pdev->pan_angle + angles->pan;
++ new_tilt = pdev->tilt_angle + angles->tilt;
+ }
+ /* check absolute ranges */
+ if (new_pan < pdev->angle_range.pan_min ||
+@@ -1560,12 +1479,11 @@ int pwc_ioctl(struct pwc_device *pdev, u
+
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ {
+- ARG_DEF(struct pwc_mpt_angles, angles)
++ struct pwc_mpt_angles *angles = arg;
+
+- ARGR(angles).absolute = 1;
+- ARGR(angles).pan = pdev->pan_angle;
+- ARGR(angles).tilt = pdev->tilt_angle;
+- ARG_OUT(angles)
++ angles->absolute = 1;
++ angles->pan = pdev->pan_angle;
++ angles->tilt = pdev->tilt_angle;
+ }
+ else
+ {
+@@ -1578,10 +1496,8 @@ int pwc_ioctl(struct pwc_device *pdev, u
+ {
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ {
+- ARG_DEF(struct pwc_mpt_status, status)
+-
+- ret = pwc_mpt_get_status(pdev, ARGA(status));
+- ARG_OUT(status)
++ struct pwc_mpt_status *status = arg;
++ ret = pwc_mpt_get_status(pdev, status);
+ }
+ else
+ {
+@@ -1592,24 +1508,22 @@ int pwc_ioctl(struct pwc_device *pdev, u
+
+ case VIDIOCPWCGVIDCMD:
+ {
+- ARG_DEF(struct pwc_video_command, cmd);
++ struct pwc_video_command *cmd = arg;
+
+- ARGR(cmd).type = pdev->type;
+- ARGR(cmd).release = pdev->release;
+- ARGR(cmd).command_len = pdev->cmd_len;
+- memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+- ARGR(cmd).bandlength = pdev->vbandlength;
+- ARGR(cmd).frame_size = pdev->frame_size;
+- ARG_OUT(cmd)
++ cmd->type = pdev->type;
++ cmd->release = pdev->release;
++ cmd->command_len = pdev->cmd_len;
++ memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
++ cmd->bandlength = pdev->vbandlength;
++ cmd->frame_size = pdev->frame_size;
+ break;
+ }
+ /*
+ case VIDIOCPWCGVIDTABLE:
+ {
+- ARG_DEF(struct pwc_table_init_buffer, table);
+- ARGR(table).len = pdev->cmd_len;
+- memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+- ARG_OUT(table)
++ struct pwc_table_init_buffer *table = arg;
++ table->len = pdev->cmd_len;
++ memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ break;
+ }
+ */
diff --git a/usb/usb-sn9c10x-driver-updates-and-bugfixes.patch b/usb/usb-sn9c10x-driver-updates-and-bugfixes.patch
new file mode 100644
index 00000000000000..00effb34fd441a
--- /dev/null
+++ b/usb/usb-sn9c10x-driver-updates-and-bugfixes.patch
@@ -0,0 +1,2912 @@
+From linux-usb-devel-admin@lists.sourceforge.net Thu Jan 5 09:10:41 2006
+From: Luca Risolia <luca.risolia@studio.unibo.it>
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Message-ID: <20060105181404.GA9389@studio.unibo.it>
+Content-Disposition: inline
+Subject: USB: SN9C10x driver updates and bugfixes
+Date: Thu, 5 Jan 2006 18:14:04 +0000
+
+SN9C10x driver updates and bugfixes.
+
+Changes: + new, - removed, * cleanup, @ bugfix:
+
+@ fix poll()
+@ Remove bad get_ctrl()'s
+* Reduce ioctl stack usage
+* Remove final ";" from some macro definitions
+* Better support for SN9C103
++ Add sn9c102_write_regs()
++ Add 0x0c45/0x602d to the list of SN9C10x based devices
++ Add support for OV7630 image sensors
++ Provide support for the built-in microphone interface of the SN9C103
++ Documentation updates
++ Add 0x0c45/0x602e to the list of SN9C10x based devices
+
+Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ Documentation/usb/sn9c102.txt | 86 +
+ drivers/usb/media/sn9c102.h | 31
+ drivers/usb/media/sn9c102_core.c | 1605 ++++++++++++++++++---------------
+ drivers/usb/media/sn9c102_hv7131d.c | 2
+ drivers/usb/media/sn9c102_mi0343.c | 2
+ drivers/usb/media/sn9c102_ov7630.c | 8
+ drivers/usb/media/sn9c102_pas106b.c | 2
+ drivers/usb/media/sn9c102_sensor.h | 69 -
+ drivers/usb/media/sn9c102_tas5110c1b.c | 2
+ drivers/usb/media/sn9c102_tas5130d1b.c | 2
+ 10 files changed, 1012 insertions(+), 797 deletions(-)
+
+--- gregkh-2.6.orig/Documentation/usb/sn9c102.txt
++++ gregkh-2.6/Documentation/usb/sn9c102.txt
+@@ -17,16 +17,15 @@ Index
+ 7. Module parameters
+ 8. Optional device control through "sysfs"
+ 9. Supported devices
+-10. How to add plug-in's for new image sensors
+-11. Notes for V4L2 application developers
+-12. Video frame formats
+-13. Contact information
+-14. Credits
++10. Notes for V4L2 application developers
++11. Video frame formats
++12. Contact information
++13. Credits
+
+
+ 1. Copyright
+ ============
+-Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it>
++Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>
+
+
+ 2. Disclaimer
+@@ -54,9 +53,8 @@ Foundation, Inc., 675 Mass Ave, Cambridg
+
+ 4. Overview and features
+ ========================
+-This driver attempts to support the video and audio streaming capabilities of
+-the devices mounting the SONiX SN9C101, SN9C102 and SN9C103 PC Camera
+-Controllers.
++This driver attempts to support the video interface of the devices mounting the
++SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers.
+
+ It's worth to note that SONiX has never collaborated with the author during the
+ development of this project, despite several requests for enough detailed
+@@ -78,6 +76,7 @@ Some of the features of the driver are:
+ - available mmap or read/poll methods for video streaming through isochronous
+ data transfers;
+ - automatic detection of image sensor;
++- support for built-in microphone interface;
+ - support for any window resolutions and optional panning within the maximum
+ pixel area of image sensor;
+ - image downscaling with arbitrary scaling factors from 1, 2 and 4 in both
+@@ -96,7 +95,7 @@ Some of the features of the driver are:
+ parameters" paragraph);
+ - up to 64 cameras can be handled at the same time; they can be connected and
+ disconnected from the host many times without turning off the computer, if
+- your system supports hotplugging;
++ the system supports hotplugging;
+ - no known bugs.
+
+
+@@ -125,6 +124,21 @@ necessary:
+ CONFIG_USB_UHCI_HCD=m
+ CONFIG_USB_OHCI_HCD=m
+
++The SN9C103 controller also provides a built-in microphone interface. It is
++supported by the USB Audio driver thanks to the ALSA API:
++
++ # Sound
++ #
++ CONFIG_SOUND=y
++
++ # Advanced Linux Sound Architecture
++ #
++ CONFIG_SND=m
++
++ # USB devices
++ #
++ CONFIG_SND_USB_AUDIO=m
++
+ And finally:
+
+ # USB Multimedia devices
+@@ -153,7 +167,7 @@ analyze kernel messages and verify that
+ Module parameters are listed below:
+ -------------------------------------------------------------------------------
+ Name: video_nr
+-Type: int array (min = 0, max = 64)
++Type: short array (min = 0, max = 64)
+ Syntax: <-1|n[,...]>
+ Description: Specify V4L2 minor mode number:
+ -1 = use next available
+@@ -165,19 +179,19 @@ Description: Specify V4L2 minor mode
+ other camera.
+ Default: -1
+ -------------------------------------------------------------------------------
+-Name: force_munmap;
++Name: force_munmap
+ Type: bool array (min = 0, max = 64)
+ Syntax: <0|1[,...]>
+ Description: Force the application to unmap previously mapped buffer memory
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+- 0 = do not force memory unmapping"
+- 1 = force memory unmapping (save memory)"
++ 0 = do not force memory unmapping
++ 1 = force memory unmapping (save memory)
+ Default: 0
+ -------------------------------------------------------------------------------
+ Name: debug
+-Type: int
++Type: ushort
+ Syntax: <n>
+ Description: Debugging information level, from 0 to 3:
+ 0 = none (use carefully)
+@@ -187,7 +201,7 @@ Description: Debugging information le
+ Level 3 is useful for testing only, when only one device
+ is used. It also shows some more informations about the
+ hardware being detected. This parameter can be changed at
+- runtime thanks to the /sys filesystem.
++ runtime thanks to the /sys filesystem interface.
+ Default: 2
+ -------------------------------------------------------------------------------
+
+@@ -236,7 +250,7 @@ serialized.
+
+ The sysfs interface also provides the "frame_header" entry, which exports the
+ frame header of the most recent requested and captured video frame. The header
+-is 12-bytes long and is appended to every video frame by the SN9C10x
++is always 18-bytes long and is appended to every video frame by the SN9C10x
+ controllers. As an example, this additional information can be used by the user
+ application for implementing auto-exposure features via software.
+
+@@ -250,7 +264,8 @@ Byte # Value Description
+ 0x03 0xC4 Frame synchronisation pattern.
+ 0x04 0xC4 Frame synchronisation pattern.
+ 0x05 0x96 Frame synchronisation pattern.
+-0x06 0x00 or 0x01 Unknown meaning. The exact value depends on the chip.
++0x06 0xXX Unknown meaning. The exact value depends on the chip;
++ possible values are 0x00, 0x01 and 0x20.
+ 0x07 0xXX Variable value, whose bits are ff00uzzc, where ff is a
+ frame counter, u is unknown, zz is a size indicator
+ (00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
+@@ -267,12 +282,23 @@ Byte # Value Description
+ times the area outside of the specified AE area. For
+ images that are not pure white, the value scales down
+ according to relative whiteness.
++ according to relative whiteness.
++
++The following bytes are used by the SN9C103 bridge only:
++
++0x0C 0xXX Unknown meaning
++0x0D 0xXX Unknown meaning
++0x0E 0xXX Unknown meaning
++0x0F 0xXX Unknown meaning
++0x10 0xXX Unknown meaning
++0x11 0xXX Unknown meaning
+
+ The AE area (sx, sy, ex, ey) in the active window can be set by programming the
+ registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C10x controllers, where one unit
+ corresponds to 32 pixels.
+
+-[1] The frame header has been documented by Bertrik Sikken.
++[1] Part of the meaning of the frame header has been documented by Bertrik
++ Sikken.
+
+
+ 9. Supported devices
+@@ -298,6 +324,7 @@ Vendor ID Product ID
+ 0x0c45 0x602b
+ 0x0c45 0x602c
+ 0x0c45 0x602d
++0x0c45 0x602e
+ 0x0c45 0x6030
+ 0x0c45 0x6080
+ 0x0c45 0x6082
+@@ -348,18 +375,7 @@ appreciated. Non-available hardware will
+ driver.
+
+
+-10. How to add plug-in's for new image sensors
+-==============================================
+-It should be easy to write plug-in's for new sensors by using the small API
+-that has been created for this purpose, which is present in "sn9c102_sensor.h"
+-(documentation is included there). As an example, have a look at the code in
+-"sn9c102_pas106b.c", which uses the mentioned interface.
+-
+-At the moment, possible unsupported image sensors are: CIS-VF10 (VGA),
+-OV7620 (VGA), OV7630 (VGA).
+-
+-
+-11. Notes for V4L2 application developers
++10. Notes for V4L2 application developers
+ =========================================
+ This driver follows the V4L2 API specifications. In particular, it enforces two
+ rules:
+@@ -394,7 +410,7 @@ initialized (as described in the documen
+ supplied by this driver).
+
+
+-12. Video frame formats [1]
++11. Video frame formats [1]
+ =======================
+ The SN9C10x PC Camera Controllers can send images in two possible video
+ formats over the USB: either native "Sequential RGB Bayer" or Huffman
+@@ -455,7 +471,7 @@ The following Huffman codes have been fo
+ documented by Bertrik Sikken.
+
+
+-13. Contact information
++12. Contact information
+ =======================
+ The author may be contacted by e-mail at <luca.risolia@studio.unibo.it>.
+
+@@ -464,7 +480,7 @@ GPG/PGP encrypted e-mail's are accepted.
+ the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'.
+
+
+-14. Credits
++13. Credits
+ ===========
+ Many thanks to following persons for their contribute (listed in alphabetical
+ order):
+@@ -480,5 +496,5 @@ order):
+ - Bertrik Sikken, who reverse-engineered and documented the Huffman compression
+ algorithm used in the SN9C10x controllers and implemented the first decoder;
+ - Mizuno Takafumi for the donation of a webcam;
+-- An "anonymous" donator (who didn't want his name to be revealed) for the
++- an "anonymous" donator (who didn't want his name to be revealed) for the
+ donation of a webcam.
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_core.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_core.c
+@@ -1,7 +1,7 @@
+ /***************************************************************************
+ * V4L2 driver for SN9C10x PC Camera Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+@@ -70,10 +70,10 @@ static short force_munmap[] = {[0 ... SN
+ SN9C102_FORCE_MUNMAP};
+ module_param_array(force_munmap, bool, NULL, 0444);
+ MODULE_PARM_DESC(force_munmap,
+- "\n<0|1[,...]> Force the application to unmap previously "
+- "\nmapped buffer memory before calling any VIDIOC_S_CROP or "
+- "\nVIDIOC_S_FMT ioctl's. Not all the applications support "
+- "\nthis feature. This parameter is specific for each "
++ "\n<0|1[,...]> Force the application to unmap previously"
++ "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
++ "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
++ "\nthis feature. This parameter is specific for each"
+ "\ndetected camera."
+ "\n 0 = do not force memory unmapping"
+ "\n 1 = force memory unmapping (save memory)"
+@@ -102,6 +102,9 @@ static sn9c102_sof_header_t sn9c102_sof_
+ {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
+ };
+
++static sn9c103_sof_header_t sn9c103_sof_header[] = {
++ {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
++};
+
+ static sn9c102_eof_header_t sn9c102_eof_header[] = {
+ {0x00, 0x00, 0x00, 0x00},
+@@ -202,6 +205,7 @@ static void sn9c102_release_buffers(stru
+ cam->nbuffers * PAGE_ALIGN(cam->frame[0].buf.length));
+ cam->nbuffers = 0;
+ }
++ cam->frame_current = NULL;
+ }
+
+
+@@ -219,6 +223,19 @@ static void sn9c102_empty_framequeues(st
+ }
+
+
++static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
++{
++ struct sn9c102_frame_t *i;
++
++ list_for_each_entry(i, &cam->outqueue, frame) {
++ i->state = F_QUEUED;
++ list_add(&i->frame, &cam->inqueue);
++ }
++
++ INIT_LIST_HEAD(&cam->outqueue);
++}
++
++
+ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
+ {
+ unsigned long lock_flags;
+@@ -235,19 +252,46 @@ static void sn9c102_queue_unusedframes(s
+
+ /*****************************************************************************/
+
++int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
++{
++ struct usb_device* udev = cam->usbdev;
++ int i, res;
++
++ if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
++ return -1;
++
++ res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
++ index, 0, buff, sizeof(buff),
++ SN9C102_CTRL_TIMEOUT*sizeof(buff));
++ if (res < 0) {
++ DBG(3, "Failed to write registers (index 0x%02X, error %d)",
++ index, res);
++ return -1;
++ }
++
++ for (i = 0; i < sizeof(buff); i++)
++ cam->reg[index+i] = buff[i];
++
++ return 0;
++}
++
++
+ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
+ {
+ struct usb_device* udev = cam->usbdev;
+ u8* buff = cam->control_buffer;
+ int res;
+
++ if (index >= ARRAY_SIZE(cam->reg))
++ return -1;
++
+ *buff = value;
+
+ res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+ index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+ if (res < 0) {
+ DBG(3, "Failed to write a register (value 0x%02X, index "
+- "0x%02X, error %d)", value, index, res)
++ "0x%02X, error %d)", value, index, res);
+ return -1;
+ }
+
+@@ -268,7 +312,7 @@ static int sn9c102_read_reg(struct sn9c1
+ index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+ if (res < 0)
+ DBG(3, "Failed to read a register (index 0x%02X, error %d)",
+- index, res)
++ index, res);
+
+ return (res >= 0) ? (int)(*buff) : -1;
+ }
+@@ -276,8 +320,8 @@ static int sn9c102_read_reg(struct sn9c1
+
+ int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
+ {
+- if (index > 0x1f)
+- return -EINVAL;
++ if (index >= ARRAY_SIZE(cam->reg))
++ return -1;
+
+ return cam->reg[index];
+ }
+@@ -367,10 +411,10 @@ sn9c102_i2c_try_raw_read(struct sn9c102_
+ err += sn9c102_i2c_detect_read_error(cam, sensor);
+
+ PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
+- data[4])
++ data[4]);
+
+ if (err) {
+- DBG(3, "I2C read failed for %s image sensor", sensor->name)
++ DBG(3, "I2C read failed for %s image sensor", sensor->name);
+ return -1;
+ }
+
+@@ -410,11 +454,11 @@ sn9c102_i2c_try_raw_write(struct sn9c102
+ err += sn9c102_i2c_detect_write_error(cam, sensor);
+
+ if (err)
+- DBG(3, "I2C write failed for %s image sensor", sensor->name)
++ DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+ PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
+ "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
+- n, data0, data1, data2, data3, data4, data5)
++ n, data0, data1, data2, data3, data4, data5);
+
+ return err ? -1 : 0;
+ }
+@@ -461,13 +505,27 @@ int sn9c102_i2c_write(struct sn9c102_dev
+ static void*
+ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+ {
+- size_t soflen = sizeof(sn9c102_sof_header_t), i;
+- u8 j, n = sizeof(sn9c102_sof_header) / soflen;
++ size_t soflen = 0, i;
++ u8 j, n = 0;
++
++ switch (cam->bridge) {
++ case BRIDGE_SN9C101:
++ case BRIDGE_SN9C102:
++ soflen = sizeof(sn9c102_sof_header_t);
++ n = sizeof(sn9c102_sof_header) / soflen;
++ break;
++ case BRIDGE_SN9C103:
++ soflen = sizeof(sn9c103_sof_header_t);
++ n = sizeof(sn9c103_sof_header) / soflen;
++ }
+
+- for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
++ for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
+ for (j = 0; j < n; j++)
+- /* It's enough to compare 7 bytes */
+- if (!memcmp(mem + i, sn9c102_sof_header[j], 7)) {
++ /* The invariable part of the header is 6 bytes long */
++ if ((cam->bridge != BRIDGE_SN9C103 &&
++ !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
++ (cam->bridge == BRIDGE_SN9C103 &&
++ !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
+ memcpy(cam->sof_header, mem + i, soflen);
+ /* Skip the header */
+ return mem + i + soflen;
+@@ -499,8 +557,7 @@ static void sn9c102_urb_complete(struct
+ {
+ struct sn9c102_device* cam = urb->context;
+ struct sn9c102_frame_t** f;
+- size_t imagesize;
+- unsigned long lock_flags;
++ size_t imagesize, soflen;
+ u8 i;
+ int err = 0;
+
+@@ -513,7 +570,7 @@ static void sn9c102_urb_complete(struct
+ cam->stream = STREAM_OFF;
+ if ((*f))
+ (*f)->state = F_QUEUED;
+- DBG(3, "Stream interrupted")
++ DBG(3, "Stream interrupted");
+ wake_up_interruptible(&cam->wait_stream);
+ }
+
+@@ -536,6 +593,10 @@ static void sn9c102_urb_complete(struct
+ cam->sensor->pix_format.height *
+ cam->sensor->pix_format.priv) / 8;
+
++ soflen = (cam->bridge) == BRIDGE_SN9C103 ?
++ sizeof(sn9c103_sof_header_t) :
++ sizeof(sn9c102_sof_header_t);
++
+ for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned int img, len, status;
+ void *pos, *sof, *eof;
+@@ -545,19 +606,12 @@ static void sn9c102_urb_complete(struct
+ pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+ if (status) {
+- DBG(3, "Error in isochronous frame")
++ DBG(3, "Error in isochronous frame");
+ (*f)->state = F_ERROR;
+ continue;
+ }
+
+- PDBGG("Isochrnous frame: length %u, #%u i", len, i)
+-
+- /*
+- NOTE: It is probably correct to assume that SOF and EOF
+- headers do not occur between two consecutive packets,
+- but who knows..Whatever is the truth, this assumption
+- doesn't introduce bugs.
+- */
++ PDBGG("Isochrnous frame: length %u, #%u i", len, i);
+
+ redo:
+ sof = sn9c102_find_sof_header(cam, pos, len);
+@@ -575,10 +629,10 @@ end_of_frame:
+ imagesize;
+ img = imagesize - (*f)->buf.bytesused;
+ DBG(3, "Expected EOF not found: "
+- "video frame cut")
++ "video frame cut");
+ if (eof)
+ DBG(3, "Exceeded limit: +%u "
+- "bytes", (unsigned)(b))
++ "bytes", (unsigned)(b));
+ }
+
+ memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
+@@ -595,8 +649,7 @@ end_of_frame:
+ u32 b = (*f)->buf.bytesused;
+ (*f)->state = F_DONE;
+ (*f)->buf.sequence= ++cam->frame_count;
+- spin_lock_irqsave(&cam->queue_lock,
+- lock_flags);
++ spin_lock(&cam->queue_lock);
+ list_move_tail(&(*f)->frame,
+ &cam->outqueue);
+ if (!list_empty(&cam->inqueue))
+@@ -606,13 +659,11 @@ end_of_frame:
+ frame );
+ else
+ (*f) = NULL;
+- spin_unlock_irqrestore(&cam->queue_lock
+- , lock_flags);
++ spin_unlock(&cam->queue_lock);
+ memcpy(cam->sysfs.frame_header,
+- cam->sof_header,
+- sizeof(sn9c102_sof_header_t));
+- DBG(3, "Video frame captured: "
+- "%lu bytes", (unsigned long)(b))
++ cam->sof_header, soflen);
++ DBG(3, "Video frame captured: %lu "
++ "bytes", (unsigned long)(b));
+
+ if (!(*f))
+ goto resubmit_urb;
+@@ -621,18 +672,19 @@ end_of_frame:
+ (*f)->state = F_ERROR;
+ DBG(3, "Not expected EOF after %lu "
+ "bytes of image data",
+- (unsigned long)((*f)->buf.bytesused))
++ (unsigned long)
++ ((*f)->buf.bytesused));
+ }
+
+ if (sof) /* (1) */
+ goto start_of_frame;
+
+ } else if (eof) {
+- DBG(3, "EOF without SOF")
++ DBG(3, "EOF without SOF");
+ continue;
+
+ } else {
+- PDBGG("Ignoring pointless isochronous frame")
++ PDBGG("Ignoring pointless isochronous frame");
+ continue;
+ }
+
+@@ -642,7 +694,7 @@ start_of_frame:
+ (*f)->buf.bytesused = 0;
+ len -= (sof - pos);
+ pos = sof;
+- DBG(3, "SOF detected: new video frame")
++ DBG(3, "SOF detected: new video frame");
+ if (len)
+ goto redo;
+
+@@ -653,12 +705,13 @@ start_of_frame:
+ else {
+ if (cam->sensor->pix_format.pixelformat ==
+ V4L2_PIX_FMT_SN9C10X) {
+- eof = sof-sizeof(sn9c102_sof_header_t);
++ eof = sof - soflen;
+ goto end_of_frame;
+ } else {
+ DBG(3, "SOF before expected EOF after "
+ "%lu bytes of image data",
+- (unsigned long)((*f)->buf.bytesused))
++ (unsigned long)
++ ((*f)->buf.bytesused));
+ goto start_of_frame;
+ }
+ }
+@@ -670,7 +723,7 @@ resubmit_urb:
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0 && err != -EPERM) {
+ cam->state |= DEV_MISCONFIGURED;
+- DBG(1, "usb_submit_urb() failed")
++ DBG(1, "usb_submit_urb() failed");
+ }
+
+ wake_up_interruptible(&cam->wait_frame);
+@@ -681,9 +734,13 @@ static int sn9c102_start_transfer(struct
+ {
+ struct usb_device *udev = cam->usbdev;
+ struct urb* urb;
+- const unsigned int wMaxPacketSize[] = {0, 128, 256, 384, 512,
+- 680, 800, 900, 1023};
+- const unsigned int psz = wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
++ const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
++ 680, 800, 900, 1023};
++ const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
++ 680, 800, 900, 1003};
++ const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
++ sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
++ sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+ s8 i, j;
+ int err = 0;
+
+@@ -692,7 +749,7 @@ static int sn9c102_start_transfer(struct
+ GFP_KERNEL);
+ if (!cam->transfer_buffer[i]) {
+ err = -ENOMEM;
+- DBG(1, "Not enough memory")
++ DBG(1, "Not enough memory");
+ goto free_buffers;
+ }
+ }
+@@ -702,7 +759,7 @@ static int sn9c102_start_transfer(struct
+ cam->urb[i] = urb;
+ if (!urb) {
+ err = -ENOMEM;
+- DBG(1, "usb_alloc_urb() failed")
++ DBG(1, "usb_alloc_urb() failed");
+ goto free_urbs;
+ }
+ urb->dev = udev;
+@@ -725,14 +782,14 @@ static int sn9c102_start_transfer(struct
+ err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
+ if (err) {
+ err = -EIO;
+- DBG(1, "I/O hardware error")
++ DBG(1, "I/O hardware error");
+ goto free_urbs;
+ }
+ }
+
+ err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
+ if (err) {
+- DBG(1, "usb_set_interface() failed")
++ DBG(1, "usb_set_interface() failed");
+ goto free_urbs;
+ }
+
+@@ -743,7 +800,7 @@ static int sn9c102_start_transfer(struct
+ if (err) {
+ for (j = i-1; j >= 0; j--)
+ usb_kill_urb(cam->urb[j]);
+- DBG(1, "usb_submit_urb() failed, error %d", err)
++ DBG(1, "usb_submit_urb() failed, error %d", err);
+ goto free_urbs;
+ }
+ }
+@@ -779,7 +836,7 @@ static int sn9c102_stop_transfer(struct
+
+ err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+ if (err)
+- DBG(3, "usb_set_interface() failed")
++ DBG(3, "usb_set_interface() failed");
+
+ return err;
+ }
+@@ -799,7 +856,7 @@ static int sn9c102_stream_interrupt(stru
+ else if (err) {
+ cam->state |= DEV_MISCONFIGURED;
+ DBG(1, "The camera is misconfigured. To use it, close and "
+- "open /dev/video%d again.", cam->v4ldev->minor)
++ "open /dev/video%d again.", cam->v4ldev->minor);
+ return err;
+ }
+
+@@ -885,8 +942,8 @@ sn9c102_store_reg(struct class_device* c
+
+ cam->sysfs.reg = index;
+
+- DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg)
+- DBG(3, "Written bytes: %zd", count)
++ DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
++ DBG(3, "Written bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -916,7 +973,7 @@ static ssize_t sn9c102_show_val(struct c
+
+ count = sprintf(buf, "%d\n", val);
+
+- DBG(3, "Read bytes: %zd", count)
++ DBG(3, "Read bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -954,8 +1011,8 @@ sn9c102_store_val(struct class_device* c
+ }
+
+ DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
+- cam->sysfs.reg, value)
+- DBG(3, "Written bytes: %zd", count)
++ cam->sysfs.reg, value);
++ DBG(3, "Written bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -979,7 +1036,7 @@ static ssize_t sn9c102_show_i2c_reg(stru
+
+ count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
+
+- DBG(3, "Read bytes: %zd", count)
++ DBG(3, "Read bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -1011,8 +1068,8 @@ sn9c102_store_i2c_reg(struct class_devic
+
+ cam->sysfs.i2c_reg = index;
+
+- DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg)
+- DBG(3, "Written bytes: %zd", count)
++ DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
++ DBG(3, "Written bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -1047,7 +1104,7 @@ static ssize_t sn9c102_show_i2c_val(stru
+
+ count = sprintf(buf, "%d\n", val);
+
+- DBG(3, "Read bytes: %zd", count)
++ DBG(3, "Read bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -1090,8 +1147,8 @@ sn9c102_store_i2c_val(struct class_devic
+ }
+
+ DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
+- cam->sysfs.i2c_reg, value)
+- DBG(3, "Written bytes: %zd", count)
++ cam->sysfs.i2c_reg, value);
++ DBG(3, "Written bytes: %zd", count);
+
+ up(&sn9c102_sysfs_lock);
+
+@@ -1193,7 +1250,7 @@ static ssize_t sn9c102_show_frame_header
+ count = sizeof(cam->sysfs.frame_header);
+ memcpy(buf, cam->sysfs.frame_header, count);
+
+- DBG(3, "Frame header, read bytes: %zd", count)
++ DBG(3, "Frame header, read bytes: %zd", count);
+
+ return count;
+ }
+@@ -1227,7 +1284,7 @@ static void sn9c102_create_sysfs(struct
+ video_device_create_file(v4ldev, &class_device_attr_blue);
+ video_device_create_file(v4ldev, &class_device_attr_red);
+ }
+- if (cam->sensor->sysfs_ops) {
++ if (cam->sensor && cam->sensor->sysfs_ops) {
+ video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+ video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+ }
+@@ -1281,7 +1338,7 @@ static int sn9c102_set_scale(struct sn9c
+ if (err)
+ return -EIO;
+
+- PDBGG("Scaling factor: %u", scale)
++ PDBGG("Scaling factor: %u", scale);
+
+ return 0;
+ }
+@@ -1304,7 +1361,7 @@ static int sn9c102_set_crop(struct sn9c1
+ return -EIO;
+
+ PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
+- "%u %u %u %u", h_start, v_start, h_size, v_size)
++ "%u %u %u %u", h_start, v_start, h_size, v_size);
+
+ return 0;
+ }
+@@ -1336,7 +1393,7 @@ static int sn9c102_init(struct sn9c102_d
+ if (s->init) {
+ err = s->init(cam);
+ if (err) {
+- DBG(3, "Sensor initialization failed")
++ DBG(3, "Sensor initialization failed");
+ return err;
+ }
+ }
+@@ -1353,13 +1410,13 @@ static int sn9c102_init(struct sn9c102_d
+
+ if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+ DBG(3, "Compressed video format is active, quality %d",
+- cam->compression.quality)
++ cam->compression.quality);
+ else
+- DBG(3, "Uncompressed video format is active")
++ DBG(3, "Uncompressed video format is active");
+
+ if (s->set_crop)
+ if ((err = s->set_crop(cam, rect))) {
+- DBG(3, "set_crop() failed")
++ DBG(3, "set_crop() failed");
+ return err;
+ }
+
+@@ -1372,11 +1429,11 @@ static int sn9c102_init(struct sn9c102_d
+ err = s->set_ctrl(cam, &ctrl);
+ if (err) {
+ DBG(3, "Set %s control failed",
+- s->qctrl[i].name)
++ s->qctrl[i].name);
+ return err;
+ }
+ DBG(3, "Image sensor supports '%s' control",
+- s->qctrl[i].name)
++ s->qctrl[i].name);
+ }
+ }
+
+@@ -1392,7 +1449,7 @@ static int sn9c102_init(struct sn9c102_d
+ cam->state |= DEV_INITIALIZED;
+ }
+
+- DBG(2, "Initialization succeeded")
++ DBG(2, "Initialization succeeded");
+ return 0;
+ }
+
+@@ -1401,7 +1458,7 @@ static void sn9c102_release_resources(st
+ {
+ down(&sn9c102_sysfs_lock);
+
+- DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor)
++ DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+ video_set_drvdata(cam->v4ldev, NULL);
+ video_unregister_device(cam->v4ldev);
+
+@@ -1432,7 +1489,7 @@ static int sn9c102_open(struct inode* in
+ }
+
+ if (cam->users) {
+- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor)
++ DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (filp->f_flags & O_NDELAY)) {
+ err = -EWOULDBLOCK;
+@@ -1458,7 +1515,7 @@ static int sn9c102_open(struct inode* in
+ err = sn9c102_init(cam);
+ if (err) {
+ DBG(1, "Initialization failed again. "
+- "I will retry on next open().")
++ "I will retry on next open().");
+ goto out;
+ }
+ cam->state &= ~DEV_MISCONFIGURED;
+@@ -1475,7 +1532,7 @@ static int sn9c102_open(struct inode* in
+ cam->frame_count = 0;
+ sn9c102_empty_framequeues(cam);
+
+- DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor)
++ DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+ out:
+ up(&cam->dev_sem);
+@@ -1504,7 +1561,7 @@ static int sn9c102_release(struct inode*
+ cam->users--;
+ wake_up_interruptible_nr(&cam->open, 1);
+
+- DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor)
++ DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+ up(&cam->dev_sem);
+
+@@ -1524,32 +1581,38 @@ sn9c102_read(struct file* filp, char __u
+ return -ERESTARTSYS;
+
+ if (cam->state & DEV_DISCONNECTED) {
+- DBG(1, "Device not present")
++ DBG(1, "Device not present");
+ up(&cam->fileop_sem);
+ return -ENODEV;
+ }
+
+ if (cam->state & DEV_MISCONFIGURED) {
+- DBG(1, "The camera is misconfigured. Close and open it again.")
++ DBG(1, "The camera is misconfigured. Close and open it "
++ "again.");
+ up(&cam->fileop_sem);
+ return -EIO;
+ }
+
+ if (cam->io == IO_MMAP) {
+ DBG(3, "Close and open the device again to choose "
+- "the read method")
++ "the read method");
+ up(&cam->fileop_sem);
+ return -EINVAL;
+ }
+
+ if (cam->io == IO_NONE) {
+ if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
+- DBG(1, "read() failed, not enough memory")
++ DBG(1, "read() failed, not enough memory");
+ up(&cam->fileop_sem);
+ return -ENOMEM;
+ }
+ cam->io = IO_READ;
+ cam->stream = STREAM_ON;
++ }
++
++ if (list_empty(&cam->inqueue)) {
++ if (!list_empty(&cam->outqueue))
++ sn9c102_empty_framequeues(cam);
+ sn9c102_queue_unusedframes(cam);
+ }
+
+@@ -1584,6 +1647,16 @@ sn9c102_read(struct file* filp, char __u
+
+ f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
+
++ if (count > f->buf.bytesused)
++ count = f->buf.bytesused;
++
++ if (copy_to_user(buf, f->bufmem, count)) {
++ err = -EFAULT;
++ goto exit;
++ }
++ *f_pos += count;
++
++exit:
+ spin_lock_irqsave(&cam->queue_lock, lock_flags);
+ list_for_each_entry(i, &cam->outqueue, frame)
+ i->state = F_UNUSED;
+@@ -1592,16 +1665,8 @@ sn9c102_read(struct file* filp, char __u
+
+ sn9c102_queue_unusedframes(cam);
+
+- if (count > f->buf.bytesused)
+- count = f->buf.bytesused;
+-
+- if (copy_to_user(buf, f->bufmem, count)) {
+- up(&cam->fileop_sem);
+- return -EFAULT;
+- }
+- *f_pos += count;
+-
+- PDBGG("Frame #%lu, bytes read: %zu", (unsigned long)f->buf.index,count)
++ PDBGG("Frame #%lu, bytes read: %zu",
++ (unsigned long)f->buf.index, count);
+
+ up(&cam->fileop_sem);
+
+@@ -1612,33 +1677,42 @@ sn9c102_read(struct file* filp, char __u
+ static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
+ {
+ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
++ struct sn9c102_frame_t* f;
++ unsigned long lock_flags;
+ unsigned int mask = 0;
+
+ if (down_interruptible(&cam->fileop_sem))
+ return POLLERR;
+
+ if (cam->state & DEV_DISCONNECTED) {
+- DBG(1, "Device not present")
++ DBG(1, "Device not present");
+ goto error;
+ }
+
+ if (cam->state & DEV_MISCONFIGURED) {
+- DBG(1, "The camera is misconfigured. Close and open it again.")
++ DBG(1, "The camera is misconfigured. Close and open it "
++ "again.");
+ goto error;
+ }
+
+ if (cam->io == IO_NONE) {
+ if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
+ IO_READ)) {
+- DBG(1, "poll() failed, not enough memory")
++ DBG(1, "poll() failed, not enough memory");
+ goto error;
+ }
+ cam->io = IO_READ;
+ cam->stream = STREAM_ON;
+ }
+
+- if (cam->io == IO_READ)
++ if (cam->io == IO_READ) {
++ spin_lock_irqsave(&cam->queue_lock, lock_flags);
++ list_for_each_entry(f, &cam->outqueue, frame)
++ f->state = F_UNUSED;
++ INIT_LIST_HEAD(&cam->outqueue);
++ spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+ sn9c102_queue_unusedframes(cam);
++ }
+
+ poll_wait(filp, &cam->wait_frame, wait);
+
+@@ -1689,13 +1763,14 @@ static int sn9c102_mmap(struct file* fil
+ return -ERESTARTSYS;
+
+ if (cam->state & DEV_DISCONNECTED) {
+- DBG(1, "Device not present")
++ DBG(1, "Device not present");
+ up(&cam->fileop_sem);
+ return -ENODEV;
+ }
+
+ if (cam->state & DEV_MISCONFIGURED) {
+- DBG(1, "The camera is misconfigured. Close and open it again.")
++ DBG(1, "The camera is misconfigured. Close and open it "
++ "again.");
+ up(&cam->fileop_sem);
+ return -EIO;
+ }
+@@ -1742,738 +1817,860 @@ static int sn9c102_mmap(struct file* fil
+ return 0;
+ }
+
++/*****************************************************************************/
+
+-static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
+- unsigned int cmd, void __user * arg)
++static int
++sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
+ {
+- struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+-
+- switch (cmd) {
+-
+- case VIDIOC_QUERYCAP:
+- {
+- struct v4l2_capability cap = {
+- .driver = "sn9c102",
+- .version = SN9C102_MODULE_VERSION_CODE,
+- .capabilities = V4L2_CAP_VIDEO_CAPTURE |
+- V4L2_CAP_READWRITE |
+- V4L2_CAP_STREAMING,
+- };
+-
+- strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+- if (usb_make_path(cam->usbdev, cap.bus_info,
+- sizeof(cap.bus_info)) < 0)
+- strlcpy(cap.bus_info, cam->dev.bus_id,
+- sizeof(cap.bus_info));
+-
+- if (copy_to_user(arg, &cap, sizeof(cap)))
+- return -EFAULT;
+-
+- return 0;
+- }
++ struct v4l2_capability cap = {
++ .driver = "sn9c102",
++ .version = SN9C102_MODULE_VERSION_CODE,
++ .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
++ V4L2_CAP_STREAMING,
++ };
++
++ strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
++ if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
++ strlcpy(cap.bus_info, cam->dev.bus_id, sizeof(cap.bus_info));
+
+- case VIDIOC_ENUMINPUT:
+- {
+- struct v4l2_input i;
+-
+- if (copy_from_user(&i, arg, sizeof(i)))
+- return -EFAULT;
++ if (copy_to_user(arg, &cap, sizeof(cap)))
++ return -EFAULT;
+
+- if (i.index)
+- return -EINVAL;
++ return 0;
++}
+
+- memset(&i, 0, sizeof(i));
+- strcpy(i.name, "USB");
+
+- if (copy_to_user(arg, &i, sizeof(i)))
+- return -EFAULT;
++static int
++sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_input i;
+
+- return 0;
+- }
++ if (copy_from_user(&i, arg, sizeof(i)))
++ return -EFAULT;
+
+- case VIDIOC_G_INPUT:
+- case VIDIOC_S_INPUT:
+- {
+- int index;
++ if (i.index)
++ return -EINVAL;
+
+- if (copy_from_user(&index, arg, sizeof(index)))
+- return -EFAULT;
++ memset(&i, 0, sizeof(i));
++ strcpy(i.name, "USB");
+
+- if (index != 0)
+- return -EINVAL;
++ if (copy_to_user(arg, &i, sizeof(i)))
++ return -EFAULT;
+
+- return 0;
+- }
++ return 0;
++}
+
+- case VIDIOC_QUERYCTRL:
+- {
+- struct sn9c102_sensor* s = cam->sensor;
+- struct v4l2_queryctrl qc;
+- u8 i;
+
+- if (copy_from_user(&qc, arg, sizeof(qc)))
+- return -EFAULT;
++static int
++sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
++{
++ int index;
+
+- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+- if (qc.id && qc.id == s->qctrl[i].id) {
+- memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+- if (copy_to_user(arg, &qc, sizeof(qc)))
+- return -EFAULT;
+- return 0;
+- }
++ if (copy_from_user(&index, arg, sizeof(index)))
++ return -EFAULT;
+
++ if (index != 0)
+ return -EINVAL;
+- }
+
+- case VIDIOC_G_CTRL:
+- {
+- struct sn9c102_sensor* s = cam->sensor;
+- struct v4l2_control ctrl;
+- int err = 0;
++ return 0;
++}
+
+- if (!s->get_ctrl)
+- return -EINVAL;
+
+- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+- return -EFAULT;
++static int
++sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
++{
++ struct sn9c102_sensor* s = cam->sensor;
++ struct v4l2_queryctrl qc;
++ u8 i;
+
+- err = s->get_ctrl(cam, &ctrl);
++ if (copy_from_user(&qc, arg, sizeof(qc)))
++ return -EFAULT;
+
+- if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+- return -EFAULT;
++ for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
++ if (qc.id && qc.id == s->qctrl[i].id) {
++ memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
++ if (copy_to_user(arg, &qc, sizeof(qc)))
++ return -EFAULT;
++ return 0;
++ }
+
+- return err;
+- }
++ return -EINVAL;
++}
+
+- case VIDIOC_S_CTRL_OLD:
+- case VIDIOC_S_CTRL:
+- {
+- struct sn9c102_sensor* s = cam->sensor;
+- struct v4l2_control ctrl;
+- u8 i;
+- int err = 0;
+
+- if (!s->set_ctrl)
+- return -EINVAL;
++static int
++sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
++{
++ struct sn9c102_sensor* s = cam->sensor;
++ struct v4l2_control ctrl;
++ int err = 0;
++ u8 i;
+
+- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+- return -EFAULT;
++ if (!s->get_ctrl && !s->set_ctrl)
++ return -EINVAL;
+
++ if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
++ return -EFAULT;
++
++ if (!s->get_ctrl) {
+ for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+- if (ctrl.id == s->qctrl[i].id) {
+- if (ctrl.value < s->qctrl[i].minimum ||
+- ctrl.value > s->qctrl[i].maximum)
+- return -ERANGE;
+- ctrl.value -= ctrl.value % s->qctrl[i].step;
+- break;
++ if (ctrl.id && ctrl.id == s->qctrl[i].id) {
++ ctrl.value = s->_qctrl[i].default_value;
++ goto exit;
+ }
++ return -EINVAL;
++ } else
++ err = s->get_ctrl(cam, &ctrl);
+
+- if ((err = s->set_ctrl(cam, &ctrl)))
+- return err;
++exit:
++ if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
++ return -EFAULT;
+
+- s->_qctrl[i].default_value = ctrl.value;
++ return err;
++}
+
+- PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+- (unsigned long)ctrl.id, (unsigned long)ctrl.value)
+
+- return 0;
+- }
++static int
++sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
++{
++ struct sn9c102_sensor* s = cam->sensor;
++ struct v4l2_control ctrl;
++ u8 i;
++ int err = 0;
+
+- case VIDIOC_CROPCAP:
+- {
+- struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
++ if (!s->set_ctrl)
++ return -EINVAL;
+
+- cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- cc->pixelaspect.numerator = 1;
+- cc->pixelaspect.denominator = 1;
++ if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
++ return -EFAULT;
+
+- if (copy_to_user(arg, cc, sizeof(*cc)))
+- return -EFAULT;
++ for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
++ if (ctrl.id == s->qctrl[i].id) {
++ if (ctrl.value < s->qctrl[i].minimum ||
++ ctrl.value > s->qctrl[i].maximum)
++ return -ERANGE;
++ ctrl.value -= ctrl.value % s->qctrl[i].step;
++ break;
++ }
+
+- return 0;
+- }
++ if ((err = s->set_ctrl(cam, &ctrl)))
++ return err;
+
+- case VIDIOC_G_CROP:
+- {
+- struct sn9c102_sensor* s = cam->sensor;
+- struct v4l2_crop crop = {
+- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+- };
++ s->_qctrl[i].default_value = ctrl.value;
+
+- memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
++ PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
++ (unsigned long)ctrl.id, (unsigned long)ctrl.value);
+
+- if (copy_to_user(arg, &crop, sizeof(crop)))
+- return -EFAULT;
++ return 0;
++}
+
+- return 0;
+- }
+
+- case VIDIOC_S_CROP:
+- {
+- struct sn9c102_sensor* s = cam->sensor;
+- struct v4l2_crop crop;
+- struct v4l2_rect* rect;
+- struct v4l2_rect* bounds = &(s->cropcap.bounds);
+- struct v4l2_pix_format* pix_format = &(s->pix_format);
+- u8 scale;
+- const enum sn9c102_stream_state stream = cam->stream;
+- const u32 nbuffers = cam->nbuffers;
+- u32 i;
+- int err = 0;
++static int
++sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
+
+- if (copy_from_user(&crop, arg, sizeof(crop)))
+- return -EFAULT;
++ cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ cc->pixelaspect.numerator = 1;
++ cc->pixelaspect.denominator = 1;
+
+- rect = &(crop.c);
++ if (copy_to_user(arg, cc, sizeof(*cc)))
++ return -EFAULT;
+
+- if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
++ return 0;
++}
+
+- if (cam->module_param.force_munmap)
+- for (i = 0; i < cam->nbuffers; i++)
+- if (cam->frame[i].vma_use_count) {
+- DBG(3, "VIDIOC_S_CROP failed. "
+- "Unmap the buffers first.")
+- return -EINVAL;
+- }
+
+- /* Preserve R,G or B origin */
+- rect->left = (s->_rect.left & 1L) ?
+- rect->left | 1L : rect->left & ~1L;
+- rect->top = (s->_rect.top & 1L) ?
+- rect->top | 1L : rect->top & ~1L;
+-
+- if (rect->width < 16)
+- rect->width = 16;
+- if (rect->height < 16)
+- rect->height = 16;
+- if (rect->width > bounds->width)
+- rect->width = bounds->width;
+- if (rect->height > bounds->height)
+- rect->height = bounds->height;
+- if (rect->left < bounds->left)
+- rect->left = bounds->left;
+- if (rect->top < bounds->top)
+- rect->top = bounds->top;
+- if (rect->left + rect->width > bounds->left + bounds->width)
+- rect->left = bounds->left+bounds->width - rect->width;
+- if (rect->top + rect->height > bounds->top + bounds->height)
+- rect->top = bounds->top+bounds->height - rect->height;
+-
+- rect->width &= ~15L;
+- rect->height &= ~15L;
+-
+- if (SN9C102_PRESERVE_IMGSCALE) {
+- /* Calculate the actual scaling factor */
+- u32 a, b;
+- a = rect->width * rect->height;
+- b = pix_format->width * pix_format->height;
+- scale = b ? (u8)((a / b) < 4 ? 1 :
+- ((a / b) < 16 ? 2 : 4)) : 1;
+- } else
+- scale = 1;
+-
+- if (cam->stream == STREAM_ON)
+- if ((err = sn9c102_stream_interrupt(cam)))
+- return err;
++static int
++sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
++{
++ struct sn9c102_sensor* s = cam->sensor;
++ struct v4l2_crop crop = {
++ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
++ };
+
+- if (copy_to_user(arg, &crop, sizeof(crop))) {
+- cam->stream = stream;
+- return -EFAULT;
+- }
++ memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+- if (cam->module_param.force_munmap || cam->io == IO_READ)
+- sn9c102_release_buffers(cam);
++ if (copy_to_user(arg, &crop, sizeof(crop)))
++ return -EFAULT;
+
+- err = sn9c102_set_crop(cam, rect);
+- if (s->set_crop)
+- err += s->set_crop(cam, rect);
+- err += sn9c102_set_scale(cam, scale);
+-
+- if (err) { /* atomic, no rollback in ioctl() */
+- cam->state |= DEV_MISCONFIGURED;
+- DBG(1, "VIDIOC_S_CROP failed because of hardware "
+- "problems. To use the camera, close and open "
+- "/dev/video%d again.", cam->v4ldev->minor)
+- return -EIO;
+- }
++ return 0;
++}
+
+- s->pix_format.width = rect->width/scale;
+- s->pix_format.height = rect->height/scale;
+- memcpy(&(s->_rect), rect, sizeof(*rect));
+-
+- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
+- nbuffers != sn9c102_request_buffers(cam, nbuffers,
+- cam->io)) {
+- cam->state |= DEV_MISCONFIGURED;
+- DBG(1, "VIDIOC_S_CROP failed because of not enough "
+- "memory. To use the camera, close and open "
+- "/dev/video%d again.", cam->v4ldev->minor)
+- return -ENOMEM;
+- }
+
+- cam->stream = stream;
++static int
++sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
++{
++ struct sn9c102_sensor* s = cam->sensor;
++ struct v4l2_crop crop;
++ struct v4l2_rect* rect;
++ struct v4l2_rect* bounds = &(s->cropcap.bounds);
++ struct v4l2_pix_format* pix_format = &(s->pix_format);
++ u8 scale;
++ const enum sn9c102_stream_state stream = cam->stream;
++ const u32 nbuffers = cam->nbuffers;
++ u32 i;
++ int err = 0;
+
+- return 0;
+- }
++ if (copy_from_user(&crop, arg, sizeof(crop)))
++ return -EFAULT;
+
+- case VIDIOC_ENUM_FMT:
+- {
+- struct v4l2_fmtdesc fmtd;
++ rect = &(crop.c);
+
+- if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+- return -EFAULT;
++ if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
+
+- if (fmtd.index == 0) {
+- strcpy(fmtd.description, "bayer rgb");
+- fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+- } else if (fmtd.index == 1) {
+- strcpy(fmtd.description, "compressed");
+- fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+- fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+- } else
+- return -EINVAL;
++ if (cam->module_param.force_munmap)
++ for (i = 0; i < cam->nbuffers; i++)
++ if (cam->frame[i].vma_use_count) {
++ DBG(3, "VIDIOC_S_CROP failed. "
++ "Unmap the buffers first.");
++ return -EINVAL;
++ }
+
+- fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+- memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
++ /* Preserve R,G or B origin */
++ rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
++ rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
++
++ if (rect->width < 16)
++ rect->width = 16;
++ if (rect->height < 16)
++ rect->height = 16;
++ if (rect->width > bounds->width)
++ rect->width = bounds->width;
++ if (rect->height > bounds->height)
++ rect->height = bounds->height;
++ if (rect->left < bounds->left)
++ rect->left = bounds->left;
++ if (rect->top < bounds->top)
++ rect->top = bounds->top;
++ if (rect->left + rect->width > bounds->left + bounds->width)
++ rect->left = bounds->left+bounds->width - rect->width;
++ if (rect->top + rect->height > bounds->top + bounds->height)
++ rect->top = bounds->top+bounds->height - rect->height;
++
++ rect->width &= ~15L;
++ rect->height &= ~15L;
++
++ if (SN9C102_PRESERVE_IMGSCALE) {
++ /* Calculate the actual scaling factor */
++ u32 a, b;
++ a = rect->width * rect->height;
++ b = pix_format->width * pix_format->height;
++ scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
++ } else
++ scale = 1;
+
+- if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+- return -EFAULT;
++ if (cam->stream == STREAM_ON)
++ if ((err = sn9c102_stream_interrupt(cam)))
++ return err;
+
+- return 0;
++ if (copy_to_user(arg, &crop, sizeof(crop))) {
++ cam->stream = stream;
++ return -EFAULT;
+ }
+
+- case VIDIOC_G_FMT:
+- {
+- struct v4l2_format format;
+- struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+-
+- if (copy_from_user(&format, arg, sizeof(format)))
+- return -EFAULT;
++ if (cam->module_param.force_munmap || cam->io == IO_READ)
++ sn9c102_release_buffers(cam);
+
+- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
++ err = sn9c102_set_crop(cam, rect);
++ if (s->set_crop)
++ err += s->set_crop(cam, rect);
++ err += sn9c102_set_scale(cam, scale);
+
+- pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+- ? 0 : (pfmt->width * pfmt->priv) / 8;
+- pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+- pfmt->field = V4L2_FIELD_NONE;
+- memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
++ if (err) { /* atomic, no rollback in ioctl() */
++ cam->state |= DEV_MISCONFIGURED;
++ DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
++ "use the camera, close and open /dev/video%d again.",
++ cam->v4ldev->minor);
++ return -EIO;
++ }
+
+- if (copy_to_user(arg, &format, sizeof(format)))
+- return -EFAULT;
++ s->pix_format.width = rect->width/scale;
++ s->pix_format.height = rect->height/scale;
++ memcpy(&(s->_rect), rect, sizeof(*rect));
+
+- return 0;
++ if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
++ nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
++ cam->state |= DEV_MISCONFIGURED;
++ DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
++ "use the camera, close and open /dev/video%d again.",
++ cam->v4ldev->minor);
++ return -ENOMEM;
+ }
+
+- case VIDIOC_TRY_FMT:
+- case VIDIOC_S_FMT:
+- {
+- struct sn9c102_sensor* s = cam->sensor;
+- struct v4l2_format format;
+- struct v4l2_pix_format* pix;
+- struct v4l2_pix_format* pfmt = &(s->pix_format);
+- struct v4l2_rect* bounds = &(s->cropcap.bounds);
+- struct v4l2_rect rect;
+- u8 scale;
+- const enum sn9c102_stream_state stream = cam->stream;
+- const u32 nbuffers = cam->nbuffers;
+- u32 i;
+- int err = 0;
++ if (cam->io == IO_READ)
++ sn9c102_empty_framequeues(cam);
++ else if (cam->module_param.force_munmap)
++ sn9c102_requeue_outqueue(cam);
+
+- if (copy_from_user(&format, arg, sizeof(format)))
+- return -EFAULT;
++ cam->stream = stream;
+
+- pix = &(format.fmt.pix);
++ return 0;
++}
+
+- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+
+- memcpy(&rect, &(s->_rect), sizeof(rect));
++static int
++sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_fmtdesc fmtd;
+
+- { /* calculate the actual scaling factor */
+- u32 a, b;
+- a = rect.width * rect.height;
+- b = pix->width * pix->height;
+- scale = b ? (u8)((a / b) < 4 ? 1 :
+- ((a / b) < 16 ? 2 : 4)) : 1;
+- }
+-
+- rect.width = scale * pix->width;
+- rect.height = scale * pix->height;
+-
+- if (rect.width < 16)
+- rect.width = 16;
+- if (rect.height < 16)
+- rect.height = 16;
+- if (rect.width > bounds->left + bounds->width - rect.left)
+- rect.width = bounds->left + bounds->width - rect.left;
+- if (rect.height > bounds->top + bounds->height - rect.top)
+- rect.height = bounds->top + bounds->height - rect.top;
+-
+- rect.width &= ~15L;
+- rect.height &= ~15L;
+-
+- { /* adjust the scaling factor */
+- u32 a, b;
+- a = rect.width * rect.height;
+- b = pix->width * pix->height;
+- scale = b ? (u8)((a / b) < 4 ? 1 :
+- ((a / b) < 16 ? 2 : 4)) : 1;
+- }
+-
+- pix->width = rect.width / scale;
+- pix->height = rect.height / scale;
+-
+- if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+- pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+- pix->pixelformat = pfmt->pixelformat;
+- pix->priv = pfmt->priv; /* bpp */
+- pix->colorspace = pfmt->colorspace;
+- pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+- ? 0 : (pix->width * pix->priv) / 8;
+- pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+- pix->field = V4L2_FIELD_NONE;
++ if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
++ return -EFAULT;
+
+- if (cmd == VIDIOC_TRY_FMT) {
+- if (copy_to_user(arg, &format, sizeof(format)))
+- return -EFAULT;
+- return 0;
+- }
++ if (fmtd.index == 0) {
++ strcpy(fmtd.description, "bayer rgb");
++ fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
++ } else if (fmtd.index == 1) {
++ strcpy(fmtd.description, "compressed");
++ fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
++ fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
++ } else
++ return -EINVAL;
+
+- if (cam->module_param.force_munmap)
+- for (i = 0; i < cam->nbuffers; i++)
+- if (cam->frame[i].vma_use_count) {
+- DBG(3, "VIDIOC_S_FMT failed. "
+- "Unmap the buffers first.")
+- return -EINVAL;
+- }
++ fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++ memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+- if (cam->stream == STREAM_ON)
+- if ((err = sn9c102_stream_interrupt(cam)))
+- return err;
++ if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
++ return -EFAULT;
+
+- if (copy_to_user(arg, &format, sizeof(format))) {
+- cam->stream = stream;
+- return -EFAULT;
+- }
++ return 0;
++}
+
+- if (cam->module_param.force_munmap || cam->io == IO_READ)
+- sn9c102_release_buffers(cam);
+
+- err += sn9c102_set_pix_format(cam, pix);
+- err += sn9c102_set_crop(cam, &rect);
+- if (s->set_pix_format)
+- err += s->set_pix_format(cam, pix);
+- if (s->set_crop)
+- err += s->set_crop(cam, &rect);
+- err += sn9c102_set_scale(cam, scale);
+-
+- if (err) { /* atomic, no rollback in ioctl() */
+- cam->state |= DEV_MISCONFIGURED;
+- DBG(1, "VIDIOC_S_FMT failed because of hardware "
+- "problems. To use the camera, close and open "
+- "/dev/video%d again.", cam->v4ldev->minor)
+- return -EIO;
+- }
++static int
++sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_format format;
++ struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
+
+- memcpy(pfmt, pix, sizeof(*pix));
+- memcpy(&(s->_rect), &rect, sizeof(rect));
++ if (copy_from_user(&format, arg, sizeof(format)))
++ return -EFAULT;
+
+- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
+- nbuffers != sn9c102_request_buffers(cam, nbuffers,
+- cam->io)) {
+- cam->state |= DEV_MISCONFIGURED;
+- DBG(1, "VIDIOC_S_FMT failed because of not enough "
+- "memory. To use the camera, close and open "
+- "/dev/video%d again.", cam->v4ldev->minor)
+- return -ENOMEM;
+- }
++ if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
+
+- cam->stream = stream;
++ pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
++ ? 0 : (pfmt->width * pfmt->priv) / 8;
++ pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
++ pfmt->field = V4L2_FIELD_NONE;
++ memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+- return 0;
+- }
++ if (copy_to_user(arg, &format, sizeof(format)))
++ return -EFAULT;
+
+- case VIDIOC_G_JPEGCOMP:
+- {
+- if (copy_to_user(arg, &cam->compression,
+- sizeof(cam->compression)))
+- return -EFAULT;
++ return 0;
++}
+
+- return 0;
+- }
+
+- case VIDIOC_S_JPEGCOMP:
+- {
+- struct v4l2_jpegcompression jc;
+- const enum sn9c102_stream_state stream = cam->stream;
+- int err = 0;
++static int
++sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
++ void __user * arg)
++{
++ struct sn9c102_sensor* s = cam->sensor;
++ struct v4l2_format format;
++ struct v4l2_pix_format* pix;
++ struct v4l2_pix_format* pfmt = &(s->pix_format);
++ struct v4l2_rect* bounds = &(s->cropcap.bounds);
++ struct v4l2_rect rect;
++ u8 scale;
++ const enum sn9c102_stream_state stream = cam->stream;
++ const u32 nbuffers = cam->nbuffers;
++ u32 i;
++ int err = 0;
+
+- if (copy_from_user(&jc, arg, sizeof(jc)))
+- return -EFAULT;
++ if (copy_from_user(&format, arg, sizeof(format)))
++ return -EFAULT;
+
+- if (jc.quality != 0 && jc.quality != 1)
+- return -EINVAL;
++ pix = &(format.fmt.pix);
+
+- if (cam->stream == STREAM_ON)
+- if ((err = sn9c102_stream_interrupt(cam)))
+- return err;
+-
+- err += sn9c102_set_compression(cam, &jc);
+- if (err) { /* atomic, no rollback in ioctl() */
+- cam->state |= DEV_MISCONFIGURED;
+- DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+- "problems. To use the camera, close and open "
+- "/dev/video%d again.", cam->v4ldev->minor)
+- return -EIO;
+- }
++ if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
+
+- cam->compression.quality = jc.quality;
++ memcpy(&rect, &(s->_rect), sizeof(rect));
+
+- cam->stream = stream;
++ { /* calculate the actual scaling factor */
++ u32 a, b;
++ a = rect.width * rect.height;
++ b = pix->width * pix->height;
++ scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
++ }
++
++ rect.width = scale * pix->width;
++ rect.height = scale * pix->height;
++
++ if (rect.width < 16)
++ rect.width = 16;
++ if (rect.height < 16)
++ rect.height = 16;
++ if (rect.width > bounds->left + bounds->width - rect.left)
++ rect.width = bounds->left + bounds->width - rect.left;
++ if (rect.height > bounds->top + bounds->height - rect.top)
++ rect.height = bounds->top + bounds->height - rect.top;
++
++ rect.width &= ~15L;
++ rect.height &= ~15L;
++
++ { /* adjust the scaling factor */
++ u32 a, b;
++ a = rect.width * rect.height;
++ b = pix->width * pix->height;
++ scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
++ }
++
++ pix->width = rect.width / scale;
++ pix->height = rect.height / scale;
++
++ if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
++ pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
++ pix->pixelformat = pfmt->pixelformat;
++ pix->priv = pfmt->priv; /* bpp */
++ pix->colorspace = pfmt->colorspace;
++ pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
++ ? 0 : (pix->width * pix->priv) / 8;
++ pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
++ pix->field = V4L2_FIELD_NONE;
+
++ if (cmd == VIDIOC_TRY_FMT) {
++ if (copy_to_user(arg, &format, sizeof(format)))
++ return -EFAULT;
+ return 0;
+ }
+
+- case VIDIOC_REQBUFS:
+- {
+- struct v4l2_requestbuffers rb;
+- u32 i;
+- int err;
+-
+- if (copy_from_user(&rb, arg, sizeof(rb)))
+- return -EFAULT;
+-
+- if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+- rb.memory != V4L2_MEMORY_MMAP)
+- return -EINVAL;
+-
+- if (cam->io == IO_READ) {
+- DBG(3, "Close and open the device again to choose "
+- "the mmap I/O method")
+- return -EINVAL;
+- }
+-
++ if (cam->module_param.force_munmap)
+ for (i = 0; i < cam->nbuffers; i++)
+ if (cam->frame[i].vma_use_count) {
+- DBG(3, "VIDIOC_REQBUFS failed. "
+- "Previous buffers are still mapped.")
++ DBG(3, "VIDIOC_S_FMT failed. Unmap the "
++ "buffers first.");
+ return -EINVAL;
+ }
+
+- if (cam->stream == STREAM_ON)
+- if ((err = sn9c102_stream_interrupt(cam)))
+- return err;
++ if (cam->stream == STREAM_ON)
++ if ((err = sn9c102_stream_interrupt(cam)))
++ return err;
+
+- sn9c102_empty_framequeues(cam);
++ if (copy_to_user(arg, &format, sizeof(format))) {
++ cam->stream = stream;
++ return -EFAULT;
++ }
+
++ if (cam->module_param.force_munmap || cam->io == IO_READ)
+ sn9c102_release_buffers(cam);
+- if (rb.count)
+- rb.count = sn9c102_request_buffers(cam, rb.count,
+- IO_MMAP);
+-
+- if (copy_to_user(arg, &rb, sizeof(rb))) {
+- sn9c102_release_buffers(cam);
+- cam->io = IO_NONE;
+- return -EFAULT;
+- }
+
+- cam->io = rb.count ? IO_MMAP : IO_NONE;
++ err += sn9c102_set_pix_format(cam, pix);
++ err += sn9c102_set_crop(cam, &rect);
++ if (s->set_pix_format)
++ err += s->set_pix_format(cam, pix);
++ if (s->set_crop)
++ err += s->set_crop(cam, &rect);
++ err += sn9c102_set_scale(cam, scale);
+
+- return 0;
++ if (err) { /* atomic, no rollback in ioctl() */
++ cam->state |= DEV_MISCONFIGURED;
++ DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
++ "use the camera, close and open /dev/video%d again.",
++ cam->v4ldev->minor);
++ return -EIO;
+ }
+
+- case VIDIOC_QUERYBUF:
+- {
+- struct v4l2_buffer b;
++ memcpy(pfmt, pix, sizeof(*pix));
++ memcpy(&(s->_rect), &rect, sizeof(rect));
+
+- if (copy_from_user(&b, arg, sizeof(b)))
+- return -EFAULT;
++ if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
++ nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
++ cam->state |= DEV_MISCONFIGURED;
++ DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
++ "use the camera, close and open /dev/video%d again.",
++ cam->v4ldev->minor);
++ return -ENOMEM;
++ }
+
+- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+- b.index >= cam->nbuffers || cam->io != IO_MMAP)
+- return -EINVAL;
++ if (cam->io == IO_READ)
++ sn9c102_empty_framequeues(cam);
++ else if (cam->module_param.force_munmap)
++ sn9c102_requeue_outqueue(cam);
+
+- memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
++ cam->stream = stream;
+
+- if (cam->frame[b.index].vma_use_count)
+- b.flags |= V4L2_BUF_FLAG_MAPPED;
++ return 0;
++}
+
+- if (cam->frame[b.index].state == F_DONE)
+- b.flags |= V4L2_BUF_FLAG_DONE;
+- else if (cam->frame[b.index].state != F_UNUSED)
+- b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+- if (copy_to_user(arg, &b, sizeof(b)))
+- return -EFAULT;
++static int
++sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
++{
++ if (copy_to_user(arg, &cam->compression,
++ sizeof(cam->compression)))
++ return -EFAULT;
+
+- return 0;
++ return 0;
++}
++
++
++static int
++sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_jpegcompression jc;
++ const enum sn9c102_stream_state stream = cam->stream;
++ int err = 0;
++
++ if (copy_from_user(&jc, arg, sizeof(jc)))
++ return -EFAULT;
++
++ if (jc.quality != 0 && jc.quality != 1)
++ return -EINVAL;
++
++ if (cam->stream == STREAM_ON)
++ if ((err = sn9c102_stream_interrupt(cam)))
++ return err;
++
++ err += sn9c102_set_compression(cam, &jc);
++ if (err) { /* atomic, no rollback in ioctl() */
++ cam->state |= DEV_MISCONFIGURED;
++ DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
++ "problems. To use the camera, close and open "
++ "/dev/video%d again.", cam->v4ldev->minor);
++ return -EIO;
+ }
+
+- case VIDIOC_QBUF:
+- {
+- struct v4l2_buffer b;
+- unsigned long lock_flags;
++ cam->compression.quality = jc.quality;
+
+- if (copy_from_user(&b, arg, sizeof(b)))
+- return -EFAULT;
++ cam->stream = stream;
++
++ return 0;
++}
+
+- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+- b.index >= cam->nbuffers || cam->io != IO_MMAP)
+- return -EINVAL;
+
+- if (cam->frame[b.index].state != F_UNUSED)
++static int
++sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_requestbuffers rb;
++ u32 i;
++ int err;
++
++ if (copy_from_user(&rb, arg, sizeof(rb)))
++ return -EFAULT;
++
++ if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
++ rb.memory != V4L2_MEMORY_MMAP)
++ return -EINVAL;
++
++ if (cam->io == IO_READ) {
++ DBG(3, "Close and open the device again to choose the mmap "
++ "I/O method");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < cam->nbuffers; i++)
++ if (cam->frame[i].vma_use_count) {
++ DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
++ "still mapped.");
+ return -EINVAL;
++ }
+
+- cam->frame[b.index].state = F_QUEUED;
++ if (cam->stream == STREAM_ON)
++ if ((err = sn9c102_stream_interrupt(cam)))
++ return err;
+
+- spin_lock_irqsave(&cam->queue_lock, lock_flags);
+- list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
++ sn9c102_empty_framequeues(cam);
+
+- PDBGG("Frame #%lu queued", (unsigned long)b.index)
++ sn9c102_release_buffers(cam);
++ if (rb.count)
++ rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
+
+- return 0;
++ if (copy_to_user(arg, &rb, sizeof(rb))) {
++ sn9c102_release_buffers(cam);
++ cam->io = IO_NONE;
++ return -EFAULT;
+ }
+
+- case VIDIOC_DQBUF:
+- {
+- struct v4l2_buffer b;
+- struct sn9c102_frame_t *f;
+- unsigned long lock_flags;
+- int err = 0;
++ cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+- if (copy_from_user(&b, arg, sizeof(b)))
+- return -EFAULT;
++ return 0;
++}
+
+- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+- return -EINVAL;
+
+- if (list_empty(&cam->outqueue)) {
+- if (cam->stream == STREAM_OFF)
+- return -EINVAL;
+- if (filp->f_flags & O_NONBLOCK)
+- return -EAGAIN;
+- err = wait_event_interruptible
+- ( cam->wait_frame,
+- (!list_empty(&cam->outqueue)) ||
+- (cam->state & DEV_DISCONNECTED) ||
+- (cam->state & DEV_MISCONFIGURED) );
+- if (err)
+- return err;
+- if (cam->state & DEV_DISCONNECTED)
+- return -ENODEV;
+- if (cam->state & DEV_MISCONFIGURED)
+- return -EIO;
+- }
++static int
++sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_buffer b;
+
+- spin_lock_irqsave(&cam->queue_lock, lock_flags);
+- f = list_entry(cam->outqueue.next, struct sn9c102_frame_t,
+- frame);
+- list_del(cam->outqueue.next);
+- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
++ if (copy_from_user(&b, arg, sizeof(b)))
++ return -EFAULT;
+
+- f->state = F_UNUSED;
++ if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
++ b.index >= cam->nbuffers || cam->io != IO_MMAP)
++ return -EINVAL;
+
+- memcpy(&b, &f->buf, sizeof(b));
+- if (f->vma_use_count)
+- b.flags |= V4L2_BUF_FLAG_MAPPED;
++ memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+- if (copy_to_user(arg, &b, sizeof(b)))
+- return -EFAULT;
++ if (cam->frame[b.index].vma_use_count)
++ b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+- PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index)
++ if (cam->frame[b.index].state == F_DONE)
++ b.flags |= V4L2_BUF_FLAG_DONE;
++ else if (cam->frame[b.index].state != F_UNUSED)
++ b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+- return 0;
+- }
++ if (copy_to_user(arg, &b, sizeof(b)))
++ return -EFAULT;
+
+- case VIDIOC_STREAMON:
+- {
+- int type;
++ return 0;
++}
+
+- if (copy_from_user(&type, arg, sizeof(type)))
+- return -EFAULT;
+
+- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+- return -EINVAL;
++static int
++sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_buffer b;
++ unsigned long lock_flags;
+
+- if (list_empty(&cam->inqueue))
+- return -EINVAL;
++ if (copy_from_user(&b, arg, sizeof(b)))
++ return -EFAULT;
+
+- cam->stream = STREAM_ON;
++ if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
++ b.index >= cam->nbuffers || cam->io != IO_MMAP)
++ return -EINVAL;
+
+- DBG(3, "Stream on")
++ if (cam->frame[b.index].state != F_UNUSED)
++ return -EINVAL;
+
+- return 0;
+- }
++ cam->frame[b.index].state = F_QUEUED;
+
+- case VIDIOC_STREAMOFF:
+- {
+- int type, err;
++ spin_lock_irqsave(&cam->queue_lock, lock_flags);
++ list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
++ spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+- if (copy_from_user(&type, arg, sizeof(type)))
+- return -EFAULT;
++ PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+- return -EINVAL;
++ return 0;
++}
+
+- if (cam->stream == STREAM_ON)
+- if ((err = sn9c102_stream_interrupt(cam)))
+- return err;
+
+- sn9c102_empty_framequeues(cam);
++static int
++sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
++ void __user * arg)
++{
++ struct v4l2_buffer b;
++ struct sn9c102_frame_t *f;
++ unsigned long lock_flags;
++ int err = 0;
+
+- DBG(3, "Stream off")
++ if (copy_from_user(&b, arg, sizeof(b)))
++ return -EFAULT;
+
+- return 0;
++ if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
++ return -EINVAL;
++
++ if (list_empty(&cam->outqueue)) {
++ if (cam->stream == STREAM_OFF)
++ return -EINVAL;
++ if (filp->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ err = wait_event_interruptible
++ ( cam->wait_frame,
++ (!list_empty(&cam->outqueue)) ||
++ (cam->state & DEV_DISCONNECTED) ||
++ (cam->state & DEV_MISCONFIGURED) );
++ if (err)
++ return err;
++ if (cam->state & DEV_DISCONNECTED)
++ return -ENODEV;
++ if (cam->state & DEV_MISCONFIGURED)
++ return -EIO;
+ }
+
+- case VIDIOC_G_PARM:
+- {
+- struct v4l2_streamparm sp;
++ spin_lock_irqsave(&cam->queue_lock, lock_flags);
++ f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
++ list_del(cam->outqueue.next);
++ spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+- if (copy_from_user(&sp, arg, sizeof(sp)))
+- return -EFAULT;
++ f->state = F_UNUSED;
+
+- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
++ memcpy(&b, &f->buf, sizeof(b));
++ if (f->vma_use_count)
++ b.flags |= V4L2_BUF_FLAG_MAPPED;
++
++ if (copy_to_user(arg, &b, sizeof(b)))
++ return -EFAULT;
++
++ PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
++
++ return 0;
++}
++
++
++static int
++sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
++{
++ int type;
++
++ if (copy_from_user(&type, arg, sizeof(type)))
++ return -EFAULT;
++
++ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
++ return -EINVAL;
++
++ if (list_empty(&cam->inqueue))
++ return -EINVAL;
++
++ cam->stream = STREAM_ON;
++
++ DBG(3, "Stream on");
++
++ return 0;
++}
++
++
++static int
++sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
++{
++ int type, err;
++
++ if (copy_from_user(&type, arg, sizeof(type)))
++ return -EFAULT;
++
++ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
++ return -EINVAL;
++
++ if (cam->stream == STREAM_ON)
++ if ((err = sn9c102_stream_interrupt(cam)))
++ return err;
++
++ sn9c102_empty_framequeues(cam);
++
++ DBG(3, "Stream off");
++
++ return 0;
++}
++
++
++static int
++sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_streamparm sp;
++
++ if (copy_from_user(&sp, arg, sizeof(sp)))
++ return -EFAULT;
++
++ if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
++
++ sp.parm.capture.extendedmode = 0;
++ sp.parm.capture.readbuffers = cam->nreadbuffers;
++
++ if (copy_to_user(arg, &sp, sizeof(sp)))
++ return -EFAULT;
++
++ return 0;
++}
++
++
++static int
++sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
++{
++ struct v4l2_streamparm sp;
++
++ if (copy_from_user(&sp, arg, sizeof(sp)))
++ return -EFAULT;
++
++ if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
++ return -EINVAL;
+
+- sp.parm.capture.extendedmode = 0;
++ sp.parm.capture.extendedmode = 0;
++
++ if (sp.parm.capture.readbuffers == 0)
+ sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+- if (copy_to_user(arg, &sp, sizeof(sp)))
+- return -EFAULT;
++ if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
++ sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+
+- return 0;
+- }
++ if (copy_to_user(arg, &sp, sizeof(sp)))
++ return -EFAULT;
+
+- case VIDIOC_S_PARM_OLD:
+- case VIDIOC_S_PARM:
+- {
+- struct v4l2_streamparm sp;
++ cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+- if (copy_from_user(&sp, arg, sizeof(sp)))
+- return -EFAULT;
++ return 0;
++}
+
+- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+- return -EINVAL;
+
+- sp.parm.capture.extendedmode = 0;
++static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
++ unsigned int cmd, void __user * arg)
++{
++ struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+
+- if (sp.parm.capture.readbuffers == 0)
+- sp.parm.capture.readbuffers = cam->nreadbuffers;
++ switch (cmd) {
+
+- if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+- sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
++ case VIDIOC_QUERYCAP:
++ return sn9c102_vidioc_querycap(cam, arg);
+
+- if (copy_to_user(arg, &sp, sizeof(sp)))
+- return -EFAULT;
++ case VIDIOC_ENUMINPUT:
++ return sn9c102_vidioc_enuminput(cam, arg);
+
+- cam->nreadbuffers = sp.parm.capture.readbuffers;
++ case VIDIOC_G_INPUT:
++ case VIDIOC_S_INPUT:
++ return sn9c102_vidioc_gs_input(cam, arg);
+
+- return 0;
+- }
++ case VIDIOC_QUERYCTRL:
++ return sn9c102_vidioc_query_ctrl(cam, arg);
++
++ case VIDIOC_G_CTRL:
++ return sn9c102_vidioc_g_ctrl(cam, arg);
++
++ case VIDIOC_S_CTRL_OLD:
++ case VIDIOC_S_CTRL:
++ return sn9c102_vidioc_s_ctrl(cam, arg);
++
++ case VIDIOC_CROPCAP_OLD:
++ case VIDIOC_CROPCAP:
++ return sn9c102_vidioc_cropcap(cam, arg);
++
++ case VIDIOC_G_CROP:
++ return sn9c102_vidioc_g_crop(cam, arg);
++
++ case VIDIOC_S_CROP:
++ return sn9c102_vidioc_s_crop(cam, arg);
++
++ case VIDIOC_ENUM_FMT:
++ return sn9c102_vidioc_enum_fmt(cam, arg);
++
++ case VIDIOC_G_FMT:
++ return sn9c102_vidioc_g_fmt(cam, arg);
++
++ case VIDIOC_TRY_FMT:
++ case VIDIOC_S_FMT:
++ return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
++
++ case VIDIOC_G_JPEGCOMP:
++ return sn9c102_vidioc_g_jpegcomp(cam, arg);
++
++ case VIDIOC_S_JPEGCOMP:
++ return sn9c102_vidioc_s_jpegcomp(cam, arg);
++
++ case VIDIOC_REQBUFS:
++ return sn9c102_vidioc_reqbufs(cam, arg);
++
++ case VIDIOC_QUERYBUF:
++ return sn9c102_vidioc_querybuf(cam, arg);
++
++ case VIDIOC_QBUF:
++ return sn9c102_vidioc_qbuf(cam, arg);
++
++ case VIDIOC_DQBUF:
++ return sn9c102_vidioc_dqbuf(cam, filp, arg);
++
++ case VIDIOC_STREAMON:
++ return sn9c102_vidioc_streamon(cam, arg);
++
++ case VIDIOC_STREAMOFF:
++ return sn9c102_vidioc_streamoff(cam, arg);
++
++ case VIDIOC_G_PARM:
++ return sn9c102_vidioc_g_parm(cam, arg);
++
++ case VIDIOC_S_PARM_OLD:
++ case VIDIOC_S_PARM:
++ return sn9c102_vidioc_s_parm(cam, arg);
+
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+@@ -2499,13 +2696,14 @@ static int sn9c102_ioctl(struct inode* i
+ return -ERESTARTSYS;
+
+ if (cam->state & DEV_DISCONNECTED) {
+- DBG(1, "Device not present")
++ DBG(1, "Device not present");
+ up(&cam->fileop_sem);
+ return -ENODEV;
+ }
+
+ if (cam->state & DEV_MISCONFIGURED) {
+- DBG(1, "The camera is misconfigured. Close and open it again.")
++ DBG(1, "The camera is misconfigured. Close and open it "
++ "again.");
+ up(&cam->fileop_sem);
+ return -EIO;
+ }
+@@ -2517,9 +2715,10 @@ static int sn9c102_ioctl(struct inode* i
+ return err;
+ }
+
++/*****************************************************************************/
+
+ static struct file_operations sn9c102_fops = {
+- .owner = THIS_MODULE,
++ .owner = THIS_MODULE,
+ .open = sn9c102_open,
+ .release = sn9c102_release,
+ .ioctl = sn9c102_ioctl,
+@@ -2538,36 +2737,23 @@ sn9c102_usb_probe(struct usb_interface*
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct sn9c102_device* cam;
+ static unsigned int dev_nr = 0;
+- unsigned int i, n;
++ unsigned int i;
+ int err = 0, r;
+
+- n = ARRAY_SIZE(sn9c102_id_table);
+- for (i = 0; i < n-1; i++)
+- if (le16_to_cpu(udev->descriptor.idVendor) ==
+- sn9c102_id_table[i].idVendor &&
+- le16_to_cpu(udev->descriptor.idProduct) ==
+- sn9c102_id_table[i].idProduct)
+- break;
+- if (i == n-1)
+- return -ENODEV;
+-
+ if (!(cam = kmalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
+ return -ENOMEM;
+- memset(cam, 0, sizeof(*cam));
+
+ cam->usbdev = udev;
+-
+ memcpy(&cam->dev, &udev->dev, sizeof(struct device));
+
+ if (!(cam->control_buffer = kmalloc(8, GFP_KERNEL))) {
+- DBG(1, "kmalloc() failed")
++ DBG(1, "kmalloc() failed");
+ err = -ENOMEM;
+ goto fail;
+ }
+- memset(cam->control_buffer, 0, 8);
+
+ if (!(cam->v4ldev = video_device_alloc())) {
+- DBG(1, "video_device_alloc() failed")
++ DBG(1, "video_device_alloc() failed");
+ err = -ENOMEM;
+ goto fail;
+ }
+@@ -2577,25 +2763,22 @@ sn9c102_usb_probe(struct usb_interface*
+ r = sn9c102_read_reg(cam, 0x00);
+ if (r < 0 || r != 0x10) {
+ DBG(1, "Sorry, this is not a SN9C10x based camera "
+- "(vid/pid 0x%04X/0x%04X)",
+- sn9c102_id_table[i].idVendor,sn9c102_id_table[i].idProduct)
++ "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ err = -ENODEV;
+ goto fail;
+ }
+
+- cam->bridge = (sn9c102_id_table[i].idProduct & 0xffc0) == 0x6080 ?
++ cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
+ BRIDGE_SN9C103 : BRIDGE_SN9C102;
+ switch (cam->bridge) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ DBG(2, "SN9C10[12] PC Camera Controller detected "
+- "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
+- sn9c102_id_table[i].idProduct)
++ "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ break;
+ case BRIDGE_SN9C103:
+ DBG(2, "SN9C103 PC Camera Controller detected "
+- "(vid/pid 0x%04X/0x%04X)", sn9c102_id_table[i].idVendor,
+- sn9c102_id_table[i].idProduct)
++ "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+ break;
+ }
+
+@@ -2606,17 +2789,17 @@ sn9c102_usb_probe(struct usb_interface*
+ }
+
+ if (!err && cam->sensor) {
+- DBG(2, "%s image sensor detected", cam->sensor->name)
++ DBG(2, "%s image sensor detected", cam->sensor->name);
+ DBG(3, "Support for %s maintained by %s",
+- cam->sensor->name, cam->sensor->maintainer)
++ cam->sensor->name, cam->sensor->maintainer);
+ } else {
+- DBG(1, "No supported image sensor detected")
++ DBG(1, "No supported image sensor detected");
+ err = -ENODEV;
+ goto fail;
+ }
+
+ if (sn9c102_init(cam)) {
+- DBG(1, "Initialization failed. I will retry on open().")
++ DBG(1, "Initialization failed. I will retry on open().");
+ cam->state |= DEV_MISCONFIGURED;
+ }
+
+@@ -2634,23 +2817,23 @@ sn9c102_usb_probe(struct usb_interface*
+ err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+ video_nr[dev_nr]);
+ if (err) {
+- DBG(1, "V4L2 device registration failed")
++ DBG(1, "V4L2 device registration failed");
+ if (err == -ENFILE && video_nr[dev_nr] == -1)
+- DBG(1, "Free /dev/videoX node not found")
++ DBG(1, "Free /dev/videoX node not found");
+ video_nr[dev_nr] = -1;
+ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+ up(&cam->dev_sem);
+ goto fail;
+ }
+
+- DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor)
++ DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+ cam->module_param.force_munmap = force_munmap[dev_nr];
+
+ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+ sn9c102_create_sysfs(cam);
+- DBG(2, "Optional device control through 'sysfs' interface ready")
++ DBG(2, "Optional device control through 'sysfs' interface ready");
+
+ usb_set_intfdata(intf, cam);
+
+@@ -2680,14 +2863,14 @@ static void sn9c102_usb_disconnect(struc
+
+ down(&cam->dev_sem);
+
+- DBG(2, "Disconnecting %s...", cam->v4ldev->name)
++ DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+ wake_up_interruptible_all(&cam->open);
+
+ if (cam->users) {
+ DBG(2, "Device /dev/video%d is open! Deregistration and "
+ "memory deallocation are deferred on close.",
+- cam->v4ldev->minor)
++ cam->v4ldev->minor);
+ cam->state |= DEV_MISCONFIGURED;
+ sn9c102_stop_transfer(cam);
+ cam->state |= DEV_DISCONNECTED;
+@@ -2720,11 +2903,11 @@ static int __init sn9c102_module_init(vo
+ {
+ int err = 0;
+
+- KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION)
+- KDBG(3, SN9C102_MODULE_AUTHOR)
++ KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
++ KDBG(3, SN9C102_MODULE_AUTHOR);
+
+ if ((err = usb_register(&sn9c102_usb_driver)))
+- KDBG(1, "usb_register() failed")
++ KDBG(1, "usb_register() failed");
+
+ return err;
+ }
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102.h
++++ gregkh-2.6/drivers/usb/media/sn9c102.h
+@@ -1,7 +1,7 @@
+ /***************************************************************************
+ * V4L2 driver for SN9C10x PC Camera Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+@@ -53,11 +53,11 @@
+ /*****************************************************************************/
+
+ #define SN9C102_MODULE_NAME "V4L2 driver for SN9C10x PC Camera Controllers"
+-#define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia"
++#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia"
+ #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
+ #define SN9C102_MODULE_LICENSE "GPL"
+-#define SN9C102_MODULE_VERSION "1:1.24a"
+-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24)
++#define SN9C102_MODULE_VERSION "1:1.25"
++#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 25)
+
+ enum sn9c102_bridge {
+ BRIDGE_SN9C101 = 0x01,
+@@ -102,12 +102,13 @@ enum sn9c102_stream_state {
+ STREAM_ON,
+ };
+
++typedef char sn9c103_sof_header_t[18];
+ typedef char sn9c102_sof_header_t[12];
+ typedef char sn9c102_eof_header_t[4];
+
+ struct sn9c102_sysfs_attr {
+ u8 reg, i2c_reg;
+- sn9c102_sof_header_t frame_header;
++ sn9c103_sof_header_t frame_header;
+ };
+
+ struct sn9c102_module_param {
+@@ -140,8 +141,8 @@ struct sn9c102_device {
+ struct v4l2_jpegcompression compression;
+
+ struct sn9c102_sysfs_attr sysfs;
+- sn9c102_sof_header_t sof_header;
+- u16 reg[32];
++ sn9c103_sof_header_t sof_header;
++ u16 reg[63];
+
+ struct sn9c102_module_param module_param;
+
+@@ -170,7 +171,7 @@ sn9c102_attach_sensor(struct sn9c102_dev
+ #undef KDBG
+ #ifdef SN9C102_DEBUG
+ # define DBG(level, fmt, args...) \
+-{ \
++do { \
+ if (debug >= (level)) { \
+ if ((level) == 1) \
+ dev_err(&cam->dev, fmt "\n", ## args); \
+@@ -180,9 +181,9 @@ sn9c102_attach_sensor(struct sn9c102_dev
+ dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
+ __FUNCTION__, __LINE__ , ## args); \
+ } \
+-}
++} while (0)
+ # define KDBG(level, fmt, args...) \
+-{ \
++do { \
+ if (debug >= (level)) { \
+ if ((level) == 1 || (level) == 2) \
+ pr_info("sn9c102: " fmt "\n", ## args); \
+@@ -190,17 +191,17 @@ sn9c102_attach_sensor(struct sn9c102_dev
+ pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \
+ __LINE__ , ## args); \
+ } \
+-}
++} while (0)
+ #else
+-# define KDBG(level, fmt, args...) do {;} while(0);
+-# define DBG(level, fmt, args...) do {;} while(0);
++# define KDBG(level, fmt, args...) do {;} while(0)
++# define DBG(level, fmt, args...) do {;} while(0)
+ #endif
+
+ #undef PDBG
+ #define PDBG(fmt, args...) \
+-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
++dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args)
+
+ #undef PDBGG
+-#define PDBGG(fmt, args...) do {;} while(0); /* placeholder */
++#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+ #endif /* _SN9C102_H_ */
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_hv7131d.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_hv7131d.c
+@@ -2,7 +2,7 @@
+ * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_mi0343.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_mi0343.c
+@@ -2,7 +2,7 @@
+ * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_ov7630.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_ov7630.c
+@@ -2,7 +2,7 @@
+ * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+- * Copyright (C) 2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+@@ -375,8 +375,10 @@ int sn9c102_probe_ov7630(struct sn9c102_
+
+ sn9c102_attach_sensor(cam, &ov7630);
+
+- if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
+- le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c)
++ if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
++ le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
++ le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
++ le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
+ return -ENODEV;
+
+ err += sn9c102_write_reg(cam, 0x01, 0x01);
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_pas106b.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_pas106b.c
+@@ -2,7 +2,7 @@
+ * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_sensor.h
++++ gregkh-2.6/drivers/usb/media/sn9c102_sensor.h
+@@ -1,7 +1,7 @@
+ /***************************************************************************
+ * API for image sensors connected to the SN9C10x PC Camera Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+@@ -92,7 +92,18 @@ extern void
+ sn9c102_attach_sensor(struct sn9c102_device* cam,
+ struct sn9c102_sensor* sensor);
+
+-/* Each SN9C10X camera has proper PID/VID identifiers. Add them here in case.*/
++/*
++ Each SN9C10x camera has proper PID/VID identifiers.
++ SN9C103 supports multiple interfaces, but we only handle the video class
++ interface.
++*/
++#define SN9C102_USB_DEVICE(vend, prod, intclass) \
++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
++ USB_DEVICE_ID_MATCH_INT_CLASS, \
++ .idVendor = (vend), \
++ .idProduct = (prod), \
++ .bInterfaceClass = (intclass)
++
+ #define SN9C102_ID_TABLE \
+ static const struct usb_device_id sn9c102_id_table[] = { \
+ { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
+@@ -107,33 +118,34 @@ static const struct usb_device_id sn9c10
+ { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \
+ { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \
+ { USB_DEVICE(0x0c45, 0x602d), }, \
++ { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \
+ { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
+- { USB_DEVICE(0x0c45, 0x6080), }, \
+- { USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \
+- { USB_DEVICE(0x0c45, 0x6083), }, /* HV7131[D|E1] */ \
+- { USB_DEVICE(0x0c45, 0x6088), }, \
+- { USB_DEVICE(0x0c45, 0x608a), }, \
+- { USB_DEVICE(0x0c45, 0x608b), }, \
+- { USB_DEVICE(0x0c45, 0x608c), }, /* HV7131x */ \
+- { USB_DEVICE(0x0c45, 0x608e), }, /* CIS-VF10 */ \
+- { USB_DEVICE(0x0c45, 0x608f), }, /* OV7630 */ \
+- { USB_DEVICE(0x0c45, 0x60a0), }, \
+- { USB_DEVICE(0x0c45, 0x60a2), }, \
+- { USB_DEVICE(0x0c45, 0x60a3), }, \
+- { USB_DEVICE(0x0c45, 0x60a8), }, /* PAS106B */ \
+- { USB_DEVICE(0x0c45, 0x60aa), }, /* TAS5130D1B */ \
+- { USB_DEVICE(0x0c45, 0x60ab), }, /* TAS5110C1B */ \
+- { USB_DEVICE(0x0c45, 0x60ac), }, \
+- { USB_DEVICE(0x0c45, 0x60ae), }, \
+- { USB_DEVICE(0x0c45, 0x60af), }, /* PAS202BCB */ \
+- { USB_DEVICE(0x0c45, 0x60b0), }, \
+- { USB_DEVICE(0x0c45, 0x60b2), }, \
+- { USB_DEVICE(0x0c45, 0x60b3), }, \
+- { USB_DEVICE(0x0c45, 0x60b8), }, \
+- { USB_DEVICE(0x0c45, 0x60ba), }, \
+- { USB_DEVICE(0x0c45, 0x60bb), }, \
+- { USB_DEVICE(0x0c45, 0x60bc), }, \
+- { USB_DEVICE(0x0c45, 0x60be), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \
++ { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \
+ { } \
+ };
+
+@@ -177,6 +189,7 @@ extern int sn9c102_i2c_write(struct sn9c
+ extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
+
+ /* I/O on registers in the bridge. Could be used by the sensor methods too */
++extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
+ extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
+ extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
+
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_tas5110c1b.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_tas5110c1b.c
+@@ -2,7 +2,7 @@
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
+--- gregkh-2.6.orig/drivers/usb/media/sn9c102_tas5130d1b.c
++++ gregkh-2.6/drivers/usb/media/sn9c102_tas5130d1b.c
+@@ -2,7 +2,7 @@
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+- * Copyright (C) 2004-2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
++ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 *
diff --git a/usb/usb-ub-03-oops-with-cfq.patch b/usb/usb-ub-03-oops-with-cfq.patch
new file mode 100644
index 00000000000000..10ed8f8929104c
--- /dev/null
+++ b/usb/usb-ub-03-oops-with-cfq.patch
@@ -0,0 +1,226 @@
+From zaitcev@redhat.com Thu Dec 29 19:00:14 2005
+Date: Wed, 28 Dec 2005 14:22:17 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Subject: USB: ub 03 Oops with CFQ
+Message-Id: <20051228142217.54a8c3d2.zaitcev@redhat.com>
+
+The blk_cleanup_queue does not necesserily destroy the queue. When we
+destroy the corresponding ub_dev, it may leave the queue spinlock pointer
+dangling.
+
+This patch moves spinlocks from ub_dev to static memory. The locking
+scheme is not changed. These spinlocks are still separate from the ub_lock.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/ub.c | 68 +++++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 45 insertions(+), 23 deletions(-)
+
+--- gregkh-2.6.orig/drivers/block/ub.c
++++ gregkh-2.6/drivers/block/ub.c
+@@ -355,7 +355,7 @@ struct ub_lun {
+ * The USB device instance.
+ */
+ struct ub_dev {
+- spinlock_t lock;
++ spinlock_t *lock;
+ atomic_t poison; /* The USB device is disconnected */
+ int openc; /* protected by ub_lock! */
+ /* kref is too implicit for our taste */
+@@ -452,6 +452,10 @@ MODULE_DEVICE_TABLE(usb, ub_usb_ids);
+ #define UB_MAX_HOSTS 26
+ static char ub_hostv[UB_MAX_HOSTS];
+
++#define UB_QLOCK_NUM 5
++static spinlock_t ub_qlockv[UB_QLOCK_NUM];
++static int ub_qlock_next = 0;
++
+ static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */
+
+ /*
+@@ -531,7 +535,7 @@ static ssize_t ub_diag_show(struct devic
+ return 0;
+
+ cnt = 0;
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+
+ cnt += sprintf(page + cnt,
+ "poison %d reset %d\n",
+@@ -579,7 +583,7 @@ static ssize_t ub_diag_show(struct devic
+ if (++nc == SCMD_TRACE_SZ) nc = 0;
+ }
+
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+ return cnt;
+ }
+
+@@ -627,6 +631,24 @@ static void ub_id_put(int id)
+ }
+
+ /*
++ * This is necessitated by the fact that blk_cleanup_queue does not
++ * necesserily destroy the queue. Instead, it may merely decrease q->refcnt.
++ * Since our blk_init_queue() passes a spinlock common with ub_dev,
++ * we have life time issues when ub_cleanup frees ub_dev.
++ */
++static spinlock_t *ub_next_lock(void)
++{
++ unsigned long flags;
++ spinlock_t *ret;
++
++ spin_lock_irqsave(&ub_lock, flags);
++ ret = &ub_qlockv[ub_qlock_next];
++ ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM;
++ spin_unlock_irqrestore(&ub_lock, flags);
++ return ret;
++}
++
++/*
+ * Downcount for deallocation. This rides on two assumptions:
+ * - once something is poisoned, its refcount cannot grow
+ * - opens cannot happen at this time (del_gendisk was done)
+@@ -1083,9 +1105,9 @@ static void ub_urb_timeout(unsigned long
+ struct ub_dev *sc = (struct ub_dev *) arg;
+ unsigned long flags;
+
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ usb_unlink_urb(&sc->work_urb);
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+ }
+
+ /*
+@@ -1108,10 +1130,10 @@ static void ub_scsi_action(unsigned long
+ struct ub_dev *sc = (struct ub_dev *) _dev;
+ unsigned long flags;
+
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ del_timer(&sc->work_timer);
+ ub_scsi_dispatch(sc);
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+ }
+
+ static void ub_scsi_dispatch(struct ub_dev *sc)
+@@ -1754,7 +1776,7 @@ static void ub_reset_task(void *arg)
+ * queues of resets or anything. We do need a spinlock though,
+ * to interact with block layer.
+ */
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ sc->reset = 0;
+ tasklet_schedule(&sc->tasklet);
+ list_for_each(p, &sc->luns) {
+@@ -1762,7 +1784,7 @@ static void ub_reset_task(void *arg)
+ blk_start_queue(lun->disk->queue);
+ }
+ wake_up(&sc->reset_wait);
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+ }
+
+ /*
+@@ -1990,11 +2012,11 @@ static int ub_sync_tur(struct ub_dev *sc
+ cmd->done = ub_probe_done;
+ cmd->back = &compl;
+
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ cmd->tag = sc->tagcnt++;
+
+ rc = ub_submit_scsi(sc, cmd);
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+
+ if (rc != 0) {
+ printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */
+@@ -2052,11 +2074,11 @@ static int ub_sync_read_cap(struct ub_de
+ cmd->done = ub_probe_done;
+ cmd->back = &compl;
+
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ cmd->tag = sc->tagcnt++;
+
+ rc = ub_submit_scsi(sc, cmd);
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+
+ if (rc != 0) {
+ printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */
+@@ -2333,7 +2355,7 @@ static int ub_probe(struct usb_interface
+ if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
+ goto err_core;
+ memset(sc, 0, sizeof(struct ub_dev));
+- spin_lock_init(&sc->lock);
++ sc->lock = ub_next_lock();
+ INIT_LIST_HEAD(&sc->luns);
+ usb_init_urb(&sc->work_urb);
+ tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
+@@ -2483,7 +2505,7 @@ static int ub_probe_lun(struct ub_dev *s
+ disk->driverfs_dev = &sc->intf->dev;
+
+ rc = -ENOMEM;
+- if ((q = blk_init_queue(ub_request_fn, &sc->lock)) == NULL)
++ if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
+ goto err_blkqinit;
+
+ disk->queue = q;
+@@ -2554,7 +2576,7 @@ static void ub_disconnect(struct usb_int
+ * and the whole queue drains. So, we just use this code to
+ * print warnings.
+ */
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ {
+ struct ub_scsi_cmd *cmd;
+ int cnt = 0;
+@@ -2571,7 +2593,7 @@ static void ub_disconnect(struct usb_int
+ "%d was queued after shutdown\n", sc->name, cnt);
+ }
+ }
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+
+ /*
+ * Unregister the upper layer.
+@@ -2590,19 +2612,15 @@ static void ub_disconnect(struct usb_int
+ }
+
+ /*
+- * Taking a lock on a structure which is about to be freed
+- * is very nonsensual. Here it is largely a way to do a debug freeze,
+- * and a bracket which shows where the nonsensual code segment ends.
+- *
+ * Testing for -EINPROGRESS is always a bug, so we are bending
+ * the rules a little.
+ */
+- spin_lock_irqsave(&sc->lock, flags);
++ spin_lock_irqsave(sc->lock, flags);
+ if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */
+ printk(KERN_WARNING "%s: "
+ "URB is active after disconnect\n", sc->name);
+ }
+- spin_unlock_irqrestore(&sc->lock, flags);
++ spin_unlock_irqrestore(sc->lock, flags);
+
+ /*
+ * There is virtually no chance that other CPU runs times so long
+@@ -2636,6 +2654,10 @@ static struct usb_driver ub_driver = {
+ static int __init ub_init(void)
+ {
+ int rc;
++ int i;
++
++ for (i = 0; i < UB_QLOCK_NUM; i++)
++ spin_lock_init(&ub_qlockv[i]);
+
+ if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
+ goto err_regblkdev;
diff --git a/usb/usb-ub-04-loss-of-timer-and-a-hang.patch b/usb/usb-ub-04-loss-of-timer-and-a-hang.patch
new file mode 100644
index 00000000000000..1e541ef9c515c4
--- /dev/null
+++ b/usb/usb-ub-04-loss-of-timer-and-a-hang.patch
@@ -0,0 +1,56 @@
+From zaitcev@redhat.com Thu Jan 5 00:17:16 2006
+Date: Thu, 5 Jan 2006 00:14:02 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Subject: USB: ub 04 Loss of timer and a hang
+Message-Id: <20060105001402.0a1f019d.zaitcev@redhat.com>
+
+If SCSI commands are submitted while other commands are still processed,
+the dispatch loop turns, and we stop the work_timer. Then, if URB fails
+to complete, ub hangs until the device is unplugged.
+
+This does not happen often, becase we only allow one SCSI command per
+block device, but does happen (on multi-LUN devices, for example).
+
+The fix is to stop timer only when we actually going to change the state.
+
+The nicest code would be to have the timer stopped in URB callback, but
+this is impossible, because it can be called from inside a timer, through
+the urb_unlink. Then we get BUG in timer.c:cascade(). So, we do it a
+little dirtier.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/ub.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/block/ub.c
++++ gregkh-2.6/drivers/block/ub.c
+@@ -1106,7 +1106,8 @@ static void ub_urb_timeout(unsigned long
+ unsigned long flags;
+
+ spin_lock_irqsave(sc->lock, flags);
+- usb_unlink_urb(&sc->work_urb);
++ if (!ub_is_completed(&sc->work_done))
++ usb_unlink_urb(&sc->work_urb);
+ spin_unlock_irqrestore(sc->lock, flags);
+ }
+
+@@ -1131,7 +1132,6 @@ static void ub_scsi_action(unsigned long
+ unsigned long flags;
+
+ spin_lock_irqsave(sc->lock, flags);
+- del_timer(&sc->work_timer);
+ ub_scsi_dispatch(sc);
+ spin_unlock_irqrestore(sc->lock, flags);
+ }
+@@ -1155,6 +1155,7 @@ static void ub_scsi_dispatch(struct ub_d
+ } else {
+ if (!ub_is_completed(&sc->work_done))
+ break;
++ del_timer(&sc->work_timer);
+ ub_scsi_urb_compl(sc, cmd);
+ }
+ }
diff --git a/usb/usb-ub-05-bulk-reset.patch b/usb/usb-ub-05-bulk-reset.patch
new file mode 100644
index 00000000000000..9b946aac0d52de
--- /dev/null
+++ b/usb/usb-ub-05-bulk-reset.patch
@@ -0,0 +1,151 @@
+From zaitcev@redhat.com Thu Jan 5 00:28:11 2006
+Date: Thu, 5 Jan 2006 00:26:30 -0800
+From: Pete Zaitcev <zaitcev@redhat.com>
+To: greg@kroah.com
+Subject: USB: ub 05 Bulk reset
+Message-Id: <20060105002630.412b74f2.zaitcev@redhat.com>
+
+For crying out loud, they have devices which do not like port resets.
+So, do what usb-storage does and try both bulk and port resets.
+We start with a port reset (which usb-storage does at the end of transport),
+then do a Bulk reset, then a port reset again. This seems to work for me.
+
+The code is getting dirtier and dirtier here, but I swear that I'll
+do something about it (see those two new XXX). Honest.
+
+Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/block/ub.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 59 insertions(+), 7 deletions(-)
+
+--- gregkh-2.6.orig/drivers/block/ub.c
++++ gregkh-2.6/drivers/block/ub.c
+@@ -14,7 +14,6 @@
+ * -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
+ * -- verify the 13 conditions and do bulk resets
+ * -- kill last_pipe and simply do two-state clearing on both pipes
+- * -- verify protocol (bulk) from USB descriptors (maybe...)
+ * -- highmem
+ * -- move top_sense and work_bcs into separate allocations (if they survive)
+ * for cache purists and esoteric architectures.
+@@ -420,11 +419,13 @@ static void ub_state_sense(struct ub_dev
+ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
+ int stalled_pipe);
+ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
+-static void ub_reset_enter(struct ub_dev *sc);
++static void ub_reset_enter(struct ub_dev *sc, int try);
+ static void ub_reset_task(void *arg);
+ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
+ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
+ struct ub_capacity *ret);
++static int ub_sync_reset(struct ub_dev *sc);
++static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe);
+ static int ub_probe_lun(struct ub_dev *sc, int lnum);
+
+ /*
+@@ -983,7 +984,7 @@ static int ub_rw_cmd_retry(struct ub_dev
+ if (atomic_read(&sc->poison))
+ return -ENXIO;
+
+- ub_reset_enter(sc);
++ ub_reset_enter(sc, urq->current_try);
+
+ if (urq->current_try >= 3)
+ return -EIO;
+@@ -1019,8 +1020,6 @@ static int ub_rw_cmd_retry(struct ub_dev
+ * No exceptions.
+ *
+ * Host is assumed locked.
+- *
+- * XXX We only support Bulk for the moment.
+ */
+ static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+ {
+@@ -1703,16 +1702,18 @@ static void ub_top_sense_done(struct ub_
+
+ /*
+ * Reset management
++ * XXX Move usb_reset_device to khubd. Hogging kevent is not a good thing.
++ * XXX Make usb_sync_reset asynchronous.
+ */
+
+-static void ub_reset_enter(struct ub_dev *sc)
++static void ub_reset_enter(struct ub_dev *sc, int try)
+ {
+
+ if (sc->reset) {
+ /* This happens often on multi-LUN devices. */
+ return;
+ }
+- sc->reset = 1;
++ sc->reset = try + 1;
+
+ #if 0 /* Not needed because the disconnect waits for us. */
+ unsigned long flags;
+@@ -1750,6 +1751,11 @@ static void ub_reset_task(void *arg)
+ if (atomic_read(&sc->poison)) {
+ printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
+ sc->name); /* P3 This floods. Remove soon. XXX */
++ } else if ((sc->reset & 1) == 0) {
++ ub_sync_reset(sc);
++ msleep(700); /* usb-storage sleeps 6s (!) */
++ ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
++ ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+ } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
+ printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
+ sc->name); /* P3 This floods. Remove soon. XXX */
+@@ -2141,6 +2147,52 @@ static void ub_probe_timeout(unsigned lo
+ }
+
+ /*
++ * Reset with a Bulk reset.
++ */
++static int ub_sync_reset(struct ub_dev *sc)
++{
++ int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
++ struct usb_ctrlrequest *cr;
++ struct completion compl;
++ struct timer_list timer;
++ int rc;
++
++ init_completion(&compl);
++
++ cr = &sc->work_cr;
++ cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
++ cr->bRequest = US_BULK_RESET_REQUEST;
++ cr->wValue = cpu_to_le16(0);
++ cr->wIndex = cpu_to_le16(ifnum);
++ cr->wLength = cpu_to_le16(0);
++
++ usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
++ (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
++ sc->work_urb.actual_length = 0;
++ sc->work_urb.error_count = 0;
++ sc->work_urb.status = 0;
++
++ if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
++ printk(KERN_WARNING
++ "%s: Unable to submit a bulk reset (%d)\n", sc->name, rc);
++ return rc;
++ }
++
++ init_timer(&timer);
++ timer.function = ub_probe_timeout;
++ timer.data = (unsigned long) &compl;
++ timer.expires = jiffies + UB_CTRL_TIMEOUT;
++ add_timer(&timer);
++
++ wait_for_completion(&compl);
++
++ del_timer_sync(&timer);
++ usb_kill_urb(&sc->work_urb);
++
++ return sc->work_urb.status;
++}
++
++/*
+ * Get number of LUNs by the way of Bulk GetMaxLUN command.
+ */
+ static int ub_sync_getmaxlun(struct ub_dev *sc)
diff --git a/usb/usb-uhci-no-fsbr-until-device-is-configured.patch b/usb/usb-uhci-no-fsbr-until-device-is-configured.patch
new file mode 100644
index 00000000000000..2fdb4cb75b9da9
--- /dev/null
+++ b/usb/usb-uhci-no-fsbr-until-device-is-configured.patch
@@ -0,0 +1,39 @@
+From stern@rowland.harvard.edu Fri Jan 6 12:51:08 2006
+Date: Fri, 6 Jan 2006 15:13:18 -0500 (EST)
+From: Alan Stern <stern@rowland.harvard.edu>
+To: Greg KH <greg@kroah.com>
+cc: Jeff Lange <jlange6648@gmail.com>
+Subject: USB: UHCI: No FSBR until device is configured
+Message-ID: <Pine.LNX.4.44L0.0601061418070.4973-100000@iolanthe.rowland.org>
+
+There are a few USB devices that don't enumerate properly when FSBR is
+turned on. Currently uhci-hcd has started using FSBR as soon as a
+device receives its address, but now we've found a device that won't
+provide its descriptors when FSBR is on.
+
+Accordingly, this patch (as629) leaves FSBR off for any device that
+isn't in the CONFIGURED state. This will slow down the configuration
+process a tiny bit, but not enough to matter. Furthermore it imitates
+the way Windows behaves -- often a good thing to do.
+
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/usb/host/uhci-q.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/host/uhci-q.c
++++ gregkh-2.6/drivers/usb/host/uhci-q.c
+@@ -602,9 +602,9 @@ static int uhci_submit_control(struct uh
+ /* Low-speed transfers get a different queue, and won't hog the bus.
+ * Also, some devices enumerate better without FSBR; the easiest way
+ * to do that is to put URBs on the low-speed queue while the device
+- * is in the DEFAULT state. */
++ * isn't in the CONFIGURED state. */
+ if (urb->dev->speed == USB_SPEED_LOW ||
+- urb->dev->state == USB_STATE_DEFAULT)
++ urb->dev->state != USB_STATE_CONFIGURED)
+ qh->skel = uhci->skel_ls_control_qh;
+ else {
+ qh->skel = uhci->skel_fs_control_qh;
diff --git a/usb/usb-usb-storage-add-support-for-rio-karma.patch b/usb/usb-usb-storage-add-support-for-rio-karma.patch
new file mode 100644
index 00000000000000..444a8426bf4a1e
--- /dev/null
+++ b/usb/usb-usb-storage-add-support-for-rio-karma.patch
@@ -0,0 +1,131 @@
+From mdharm@multivac.one-eyed-alien.net Fri Dec 30 19:09:06 2005
+Date: Fri, 30 Dec 2005 19:06:53 -0800
+From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+To: Greg KH <greg@kroah.com>
+Subject: USB: usb-storage: Add support for Rio Karma
+Message-ID: <20051231030653.GA31722@one-eyed-alien.net>
+Content-Disposition: inline
+
+This patch from Bob Copeland adds support for the Rio Karma portable
+digital audio player to the usb-storage driver. The only thing needed to
+support this device is a one-time (per plugin) init command which is sent
+to the device.
+
+Signed-off-by: Bob Copeland <me@bobcopeland.com>
+Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/storage/initializers.c | 73 +++++++++++++++++++++++++++++++++++++
+ drivers/usb/storage/initializers.h | 1
+ drivers/usb/storage/unusual_devs.h | 5 ++
+ 3 files changed, 79 insertions(+)
+
+--- gregkh-2.6.orig/drivers/usb/storage/initializers.c
++++ gregkh-2.6/drivers/usb/storage/initializers.c
+@@ -45,6 +45,12 @@
+ #include "debug.h"
+ #include "transport.h"
+
++#define RIO_MSC 0x08
++#define RIOP_INIT "RIOP\x00\x01\x08"
++#define RIOP_INIT_LEN 7
++#define RIO_SEND_LEN 40
++#define RIO_RECV_LEN 0x200
++
+ /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
+ * mode */
+ int usb_stor_euscsi_init(struct us_data *us)
+@@ -91,3 +97,70 @@ int usb_stor_ucr61s2b_init(struct us_dat
+
+ return (res ? -1 : 0);
+ }
++
++/* Place the Rio Karma into mass storage mode.
++ *
++ * The initialization begins by sending 40 bytes starting
++ * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte
++ * packet with the high four bits set and everything else null.
++ *
++ * Next, we send RIOP\x80\x00\x08\x00. Each time, a 512 byte response
++ * must be read, but we must loop until byte 5 in the response is 0x08,
++ * indicating success. */
++int rio_karma_init(struct us_data *us)
++{
++ int result, partial;
++ char *recv;
++ unsigned long timeout;
++
++ // us->iobuf is big enough to hold cmd but not receive
++ if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL)))
++ goto die_nomem;
++
++ US_DEBUGP("Initializing Karma...\n");
++
++ memset(us->iobuf, 0, RIO_SEND_LEN);
++ memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN);
++
++ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ us->iobuf, RIO_SEND_LEN, &partial);
++ if (result != USB_STOR_XFER_GOOD)
++ goto die;
++
++ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ recv, RIO_RECV_LEN, &partial);
++ if (result != USB_STOR_XFER_GOOD)
++ goto die;
++
++ us->iobuf[4] = 0x80;
++ us->iobuf[5] = 0;
++ timeout = jiffies + msecs_to_jiffies(3000);
++ for (;;) {
++ US_DEBUGP("Sending init command\n");
++ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
++ us->iobuf, RIO_SEND_LEN, &partial);
++ if (result != USB_STOR_XFER_GOOD)
++ goto die;
++
++ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
++ recv, RIO_RECV_LEN, &partial);
++ if (result != USB_STOR_XFER_GOOD)
++ goto die;
++
++ if (recv[5] == RIO_MSC)
++ break;
++ if (time_after(jiffies, timeout))
++ goto die;
++ msleep(10);
++ }
++ US_DEBUGP("Karma initialized.\n");
++ kfree(recv);
++ return 0;
++
++die:
++ kfree(recv);
++die_nomem:
++ US_DEBUGP("Could not initialize karma.\n");
++ return USB_STOR_TRANSPORT_FAILED;
++}
++
+--- gregkh-2.6.orig/drivers/usb/storage/initializers.h
++++ gregkh-2.6/drivers/usb/storage/initializers.h
+@@ -48,3 +48,4 @@ int usb_stor_euscsi_init(struct us_data
+ /* This function is required to activate all four slots on the UCR-61S2B
+ * flash reader */
+ int usb_stor_ucr61s2b_init(struct us_data *us);
++int rio_karma_init(struct us_data *us);
+--- gregkh-2.6.orig/drivers/usb/storage/unusual_devs.h
++++ gregkh-2.6/drivers/usb/storage/unusual_devs.h
+@@ -145,6 +145,11 @@ UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x
+ US_SC_DEVICE, US_PR_BULK, NULL,
+ US_FL_NEED_OVERRIDE ),
+
++UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
++ "Rio",
++ "Rio Karma",
++ US_SC_SCSI, US_PR_BULK, rio_karma_init, 0),
++
+ /* Patch submitted by Philipp Friedrich <philipp@void.at> */
+ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
+ "Kyocera",
diff --git a/usb/usb-usb-storage-support-for-sony-dsc-t5-still-camera.patch b/usb/usb-usb-storage-support-for-sony-dsc-t5-still-camera.patch
new file mode 100644
index 00000000000000..63d75ba42d3259
--- /dev/null
+++ b/usb/usb-usb-storage-support-for-sony-dsc-t5-still-camera.patch
@@ -0,0 +1,40 @@
+From phil@ipom.com Mon Dec 26 23:09:34 2005
+Message-ID: <43B0E778.6000508@ipom.com>
+Date: Mon, 26 Dec 2005 23:04:24 -0800
+From: Phil Dibowitz <phil@ipom.com>
+To: Greg KH <greg@kroah.com>, Alexandre Duret-Lutz <adl@gnu.org>
+Subject: USB: usb-storage support for SONY DSC-T5 still camera
+
+
+From: Alexandre Duret-Lutz <adl@gnu.org>
+
+I've been offered a nice Sony DSC-T5 digital camera, with a USB connection.
+Unfortunately it is not recognized by Linux 2.6.14.4's usb-storage.
+
+With the following change I'm able to mount and read my pictures:
+
+Signed-off-by: Phil Dibowitz <phil@ipom.com>
+
+---
+ drivers/usb/storage/unusual_devs.h | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/storage/unusual_devs.h
++++ gregkh-2.6/drivers/usb/storage/unusual_devs.h
+@@ -429,11 +429,11 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x
+ US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
+
+ /* This entry is needed because the device reports Sub=ff */
+-UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0500,
+- "Sony",
+- "DSC-T1",
+- US_SC_8070, US_PR_DEVICE, NULL,
+- US_FL_SINGLE_LUN ),
++UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0600,
++ "Sony",
++ "DSC-T1/T5",
++ US_SC_8070, US_PR_DEVICE, NULL,
++ US_FL_SINGLE_LUN ),
+
+
+ /* Reported by wim@geeks.nl */
diff --git a/usb/usb-yealink.c-cleanup-device-matching-code.patch b/usb/usb-yealink.c-cleanup-device-matching-code.patch
new file mode 100644
index 00000000000000..f2be9baf8e3866
--- /dev/null
+++ b/usb/usb-yealink.c-cleanup-device-matching-code.patch
@@ -0,0 +1,124 @@
+From spam@god.dyndns.org Fri Dec 30 10:41:23 2005
+Date: Fri, 30 Dec 2005 19:41:11 +0100
+From: Henk <Henk.Vergonet@gmail.com>
+To: gregkh@suse.de
+Subject: USB: yealink.c: Cleanup device matching code
+Message-ID: <20051230184111.GA4223@god.dyndns.org>
+Content-Disposition: inline
+
+[PATCH] drivers/usb/input/yealink.c: Cleanup device matching code
+This should fix things mentioned below:
+
+ "I was curious why my firewall was loading a 'phone driver'.
+ It turns out that the probing in the yealink driver is
+ a little too assuming..
+
+ static struct usb_device_id usb_table [] = {
+ { USB_INTERFACE_INFO(USB_CLASS_HID, 0, 0) },
+ { }
+ };
+
+ So it picked up my UPS, and loaded the driver.
+ Whilst no harm came, because it later checks the vendor/product IDs,
+ this driver should probably be rewritten to only probe
+ for the device IDs it actually knows about.
+
+ Dave"
+
+
+Signed-off-by: Henk Vergonet <henk.vergonet@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ drivers/usb/input/yealink.c | 46 ++++++++++++++++++--------------------------
+ 1 file changed, 19 insertions(+), 27 deletions(-)
+
+--- gregkh-2.6.orig/drivers/usb/input/yealink.c
++++ gregkh-2.6/drivers/usb/input/yealink.c
+@@ -59,7 +59,7 @@
+ #include "map_to_7segment.h"
+ #include "yealink.h"
+
+-#define DRIVER_VERSION "yld-20050816"
++#define DRIVER_VERSION "yld-20051230"
+ #define DRIVER_AUTHOR "Henk Vergonet"
+ #define DRIVER_DESC "Yealink phone driver"
+
+@@ -786,16 +786,25 @@ static struct attribute_group yld_attr_g
+ * Linux interface and usb initialisation
+ ******************************************************************************/
+
+-static const struct yld_device {
+- u16 idVendor;
+- u16 idProduct;
++struct driver_info {
+ char *name;
+-} yld_device[] = {
+- { 0x6993, 0xb001, "Yealink usb-p1k" },
+ };
+
+-static struct usb_device_id usb_table [] = {
+- { USB_INTERFACE_INFO(USB_CLASS_HID, 0, 0) },
++static const struct driver_info info_P1K = {
++ .name = "Yealink usb-p1k",
++};
++
++static const struct usb_device_id usb_table [] = {
++ {
++ .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
++ USB_DEVICE_ID_MATCH_INT_INFO,
++ .idVendor = 0x6993,
++ .idProduct = 0xb001,
++ .bInterfaceClass = USB_CLASS_HID,
++ .bInterfaceSubClass = 0,
++ .bInterfaceProtocol = 0,
++ .driver_info = (kernel_ulong_t)&info_P1K
++ },
+ { }
+ };
+
+@@ -842,33 +851,16 @@ static void usb_disconnect(struct usb_in
+ usb_cleanup(yld, 0);
+ }
+
+-static int usb_match(struct usb_device *udev)
+-{
+- int i;
+- u16 idVendor = le16_to_cpu(udev->descriptor.idVendor);
+- u16 idProduct = le16_to_cpu(udev->descriptor.idProduct);
+-
+- for (i = 0; i < ARRAY_SIZE(yld_device); i++) {
+- if ((idVendor == yld_device[i].idVendor) &&
+- (idProduct == yld_device[i].idProduct))
+- return i;
+- }
+- return -ENODEV;
+-}
+-
+ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ struct usb_device *udev = interface_to_usbdev (intf);
++ struct driver_info *nfo = (struct driver_info *)id->driver_info;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct yealink_dev *yld;
+ struct input_dev *input_dev;
+ int ret, pipe, i;
+
+- i = usb_match(udev);
+- if (i < 0)
+- return -ENODEV;
+-
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+ if (!(endpoint->bEndpointAddress & USB_DIR_IN))
+@@ -948,7 +940,7 @@ static int usb_probe(struct usb_interfac
+ strlcat(yld->phys, "/input0", sizeof(yld->phys));
+
+ /* register settings for the input device */
+- input_dev->name = yld_device[i].name;
++ input_dev->name = nfo->name;
+ input_dev->phys = yld->phys;
+ usb_to_input_id(udev, &input_dev->id);
+ input_dev->cdev.dev = &intf->dev;