diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-09 20:20:09 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-09 20:20:09 -0800 |
commit | 9a2e19cf4c9de67bfd135d1a00fc4626e9bafed2 (patch) | |
tree | a7453ad853fc1ecc3f15060a4794af8e7accf283 /usb | |
parent | 6bda7dc4404f8d79ce7b2586717fea2407db20cc (diff) | |
download | patches-9a2e19cf4c9de67bfd135d1a00fc4626e9bafed2.tar.gz |
Loads of usb patches added
Diffstat (limited to 'usb')
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 0000000000000..060b91e5e094c --- /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 0000000000000..37ce8f5395013 --- /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 0000000000000..c855a6b41be6e --- /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 0000000000000..00bf6be599036 --- /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, ¶m_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 0000000000000..7e9c818b066de --- /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 0000000000000..5a6ac81508743 --- /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 0000000000000..9c69948c560d9 --- /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 0000000000000..75905663f9713 --- /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 0000000000000..639e8464025c3 --- /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 0000000000000..135bda27e1d8e --- /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 0000000000000..e68e2afe52e2e --- /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 0000000000000..efadd4a6518c1 --- /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 0000000000000..c3480eb7aa171 --- /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 0000000000000..e76ea15893469 --- /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 0000000000000..25dc0086c8fbd --- /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 0000000000000..7b6c99c05ccf4 --- /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 0000000000000..35a312e1f07f5 --- /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 0000000000000..395355e1b333f --- /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 0000000000000..8d15096d746b2 --- /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 0000000000000..5ee011ed54a46 --- /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 0000000000000..384200e4cbf74 --- /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 0000000000000..90afc0de6b16b --- /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 0000000000000..4a5bd654f4920 --- /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 0000000000000..f7585a6bc75fa --- /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 0000000000000..050a656ee35e1 --- /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 0000000000000..eb1c9f6b732cd --- /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 0000000000000..00effb34fd441 --- /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 0000000000000..10ed8f8929104 --- /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 0000000000000..1e541ef9c515c --- /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 0000000000000..9b946aac0d52d --- /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 0000000000000..2fdb4cb75b9da --- /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 0000000000000..444a8426bf4a1 --- /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 0000000000000..63d75ba42d325 --- /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 0000000000000..f2be9baf8e386 --- /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; |