commit 3df74894a778e5c638e91d1d93d72960d07760b8
parent afb1b4a19c0aeb4d21352bc0a7ddb8541901d0c5
Author: alex <alex@022568fa-442e-4ef8-a3e8-54dcafdb011a>
Date:   Wed, 16 Jan 2008 23:51:34 +0000
* Remove these two. They accidentally didn't get removed as my local filesystem was out of sync.
git-svn-id: http://svn.mediati.org/svn/r5u870/trunk@37 022568fa-442e-4ef8-a3e8-54dcafdb011a
Diffstat:
| D | usbcam.c | | | 3477 | ------------------------------------------------------------------------------- | 
| D | usbcam.h | | | 721 | ------------------------------------------------------------------------------- | 
2 files changed, 0 insertions(+), 4198 deletions(-)
diff --git a/usbcam.c b/usbcam.c
@@ -1,3477 +0,0 @@
-/*
- * USBCAM abstraction library for USB webcam drivers
- * Version 0.10.2
- *
- * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
- * Copyright (c) 2008 Alexander Hixon <hixon.alexander@mediati.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * TODO LIST:
- * - Add debug tracing to more ioctl paths
- * - Provide a cleaner mechanism for alerting minidrvers of URB
- *   underflows in the isostream component.
- */
-
-#define CONFIG_USBCAM_DEBUG
-
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/videodev.h>
-
-#include "usbcam.h"
-
-/* If building integrated with a minidriver, don't export symbols */
-#undef EXPORT_SYMBOL
-#define EXPORT_SYMBOL(X)
-
-#define assert usbcam_assert
-
-#define usbcam_drvname(MDP) ((MDP)->um_owner->name)
-
-#if defined(CONFIG_USBCAM_DEBUG)
-#define usbcam_dbgm(MD, SUBSYS, FMT, ARG...) do {			\
-	if ((MD)->um_debug &&						\
-	    *(MD)->um_debug & (1UL << USBCAM_DBG_ ## SUBSYS))		\
-		printk(KERN_INFO "%s: " FMT "\n",			\
-		       (MD)->um_modname, ## ARG);			\
-} while (0)
-#else
-#define usbcam_dbgm(MD, SUBSYS, FMT, ARG...)
-#endif  /* defined(CONFIG_USBCAM_DEBUG) */
-
-#define usbcam_minidrv_op_present(UDP, CB) 				\
-	((UDP)->ud_minidrv->um_ops->CB ? 1 : 0)
-#define usbcam_minidrv_op(UDP, CB, ARGS...)				\
-	((UDP)->ud_minidrv->um_ops->CB((UDP), ## ARGS))
-
-
-/*
- * Private data structure definitions
- */
-
-/*
- * This structure represents a registered minidriver
- */
-struct usbcam_minidrv {
-	struct kref			um_kref;
-	struct module			*um_owner;
-	const char			*um_modname;
-	int				*um_debug;
-	int				um_version;
-	int				um_dev_count;
-	struct list_head		um_dev_list;
-	int				um_dev_privsize;
-	struct usb_driver		um_usbdrv;
-	struct mutex			um_lock;
-	const struct usbcam_dev_ops	*um_ops;
-	struct video_device		um_videodev_template;
-	struct file_operations		um_v4l_fops;
-	const int			*um_video_nr_array;
-	int				um_video_nr_array_len;
-};
-
-/*
- * The frame structure is generally managed by the video-buf module
- * and represents some chunk of memory that the video4linux client
- * requested as a frame buffer.  It might be vmalloc()'d, or it might
- * be mapped from a user address space.  In either case, usbcam
- * guarantees a contiguous kernel mapping accessible to the minidriver.
- *
- * The primary reason to use video-buf in usbcam is for its
- * implementation of buffer mapping methods and "zero-copy" kernel-user
- * data movement.  The V4L2 API is quite rich, and it's much easier to
- * use video-buf than to create a private full-featured implementation,
- * and much more desirable to use video-buf than to limp along with a
- * substandard implementation.  The video-buf module isn't specifically
- * used for DMA functionality, as most USB devices, with the possible
- * exception of those employing bulk transfers, are unsuitable for
- * direct frame buffer DMA.
- *
- * Minidrivers can access details of the current frame using
- * usbcam_curframe_get(), and can signal completion of the current
- * frame with usbcam_curframe_complete().  It is up to the minidriver
- * to fill in the frame buffer.
- */
-struct usbcam_frame {
-	struct videobuf_buffer	vbb;
-	struct list_head	cap_links;
-	void			*vmap_base;
-	void			*vmap_sof;
-};
-
-/*
- * This structure represents an open file handle and the frame
- * buffers associated with that client
- */
-struct usbcam_fh {
-	struct usbcam_dev		*uf_dev;
-	int				uf_flags;
-	struct videobuf_queue		uf_vbq;
-};
-
-#define USBCAM_FH_USE_FIXED_FB		0x00000001
-
-
-/*
- * APPBUG: Some applications expect VIDIOCGMBUF to provide a buffer
- * large enough to accommodate whatever image format they choose in the
- * future.  We enable fixed size buffer mode from VIDIOCGMBUF, and
- * disable it from VIDIOC_REQBUFS.
- */
-static int fixed_fbsize = 1024 * 1024;
-module_param(fixed_fbsize, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(fixed_fbsize, "Size in bytes of fixed-length framebuffers");
-
-
-/*
- * Frame capture handling helpers follow
- */
-
-static inline struct usbcam_frame *
-usbcam_capture_curframe(struct usbcam_dev *udp)
-{
-	return list_empty(&udp->ud_frame_cap_queue)
-		? NULL
-		: list_entry(udp->ud_frame_cap_queue.next,
-			     struct usbcam_frame, cap_links);
-}
-
-static void usbcam_capture_abortall(struct usbcam_dev *udp)
-{
-	struct usbcam_frame *framep;
-
-	/* Abort all frames on the capture queue */
-	while (1) {
-		framep = usbcam_capture_curframe(udp);
-		if (!framep)
-			break;
-		usbcam_dbg(udp, VIDEOBUF, "completing frame %d STATE_ERROR",
-			   framep->vbb.i);
-		list_del_init(&framep->cap_links);
-		framep->vbb.state = STATE_ERROR;
-		wake_up_all(&framep->vbb.done);
-	}
-}
-
-static inline void usbcam_capture_complete_frame(struct usbcam_dev *udp,
-						 struct usbcam_frame *framep,
-						 int is_error)
-{
-	usbcam_chklock(udp);
-	usbcam_dbg(udp, VIDEOBUF, "completing frame %d/%p %s", framep->vbb.i,
-		   framep, is_error ? "STATE_ERROR" : "STATE_DONE");
-	list_del_init(&framep->cap_links);
-	framep->vbb.state = is_error ? STATE_ERROR : STATE_DONE;
-	wake_up_all(&framep->vbb.done);
-}
-
-static int usbcam_capture_start(struct usbcam_dev *udp)
-{
-	int res;
-
-	if (udp->ud_capturing) {
-		usbcam_warn(udp, "%s: already capturing", __FUNCTION__);
-		return 0;
-	}
-
-	if (list_empty(&udp->ud_frame_cap_queue)) {
-		usbcam_warn(udp, "%s: no frames queued to capture",
-			    __FUNCTION__);
-		return -ENOENT;
-	}
-
-	if (udp->ud_disconnected) {
-		/*
-		 * We can't let any frames through if the device has
-		 * been disconnected
-		 */
-		usbcam_capture_abortall(udp);
-		return -ENODEV;
-	}
-
-	usbcam_dbg(udp, CAPTURE, "invoking minidriver cap_start");
-
-	res = usbcam_minidrv_op(udp, cap_start);
-	if (res) {
-		usbcam_dbg(udp, CAPTURE,
-			   "%s: could not start capture for %s: %d",
-			   __FUNCTION__, usbcam_drvname(udp->ud_minidrv), res);
-
-		if (udp->ud_capturing) {
-			usbcam_warn(udp,
-				    "%s: minidriver left ud_capturing set\n",
-				    __FUNCTION__);
-		}
-
-		usbcam_capture_abortall(udp);
-		return res;
-	}
-
-	if (!udp->ud_capturing && usbcam_capture_curframe(udp)) {
-		usbcam_warn(udp, "%s: minidriver failed to set ud_capturing!",
-			    __FUNCTION__);
-	} else {
-		usbcam_dbg(udp, CAPTURE, "minidriver capture started");
-	}
-
-	return 0;
-}
-
-static void usbcam_capture_stop(struct usbcam_dev *udp)
-{
-	if (udp->ud_capturing) {
-		usbcam_dbg(udp, CAPTURE, "invoking minidriver cap_stop");
-		usbcam_minidrv_op(udp, cap_stop);
-
-		if (udp->ud_capturing) {
-			usbcam_warn(udp, "%s: minidriver failed to clear "
-				    "ud_capturing!", __FUNCTION__);
-		} else {
-			usbcam_dbg(udp, CAPTURE, "minidriver capture stopped");
-		}
-	}
-}
-
-static void usbcam_capture_stop_nondestructive(struct usbcam_dev *udp)
-{
-	/*
-	 * Only stop capturing if no frames are queued.
-	 *
-	 * We allow and encourage the minidriver to continue
-	 * capturing in the last requested format, and have it
-	 * stop autonomously when it receives its first data
-	 * for the next frame but finds no frame available.
-	 * This expedites the process for situations such as
-	 * S_FMT which cannot tolerate capture being in progress.
-	 */
-	if (udp->ud_capturing && list_empty(&udp->ud_frame_cap_queue))
-		usbcam_capture_stop(udp);
-}
-
-static inline struct videobuf_dmabuf* usbframe_get_dmabuf(struct videobuf_buffer *buf)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-    return buf->dma;
-#else
-    return videobuf_to_dma(buf);
-#endif
-}
-
-
-/*
- * External APIs for minidriver access to the frame queue
- */
-
-int usbcam_curframe_get(struct usbcam_dev *udp, struct usbcam_curframe *cf)
-{
-	struct usbcam_frame *framep = usbcam_capture_curframe(udp);
-	struct videobuf_dmabuf *dma;
-	
-	usbcam_chklock(udp);
-	
-	if (!framep || !&framep->vbb)
-		return -ENOENT;
-	
-    dma = usbframe_get_dmabuf(&framep->vbb);
-
-	cf->uc_base = (u8 *) (framep->vmap_sof
-			      ? framep->vmap_sof
-			      : dma->vmalloc);				
-	cf->uc_size = framep->vbb.size;
-	cf->uc_field = framep->vbb.field;
-	memset(&cf->uc_timestamp, 0, sizeof(cf->uc_timestamp));
-
-	return 0;
-}
-EXPORT_SYMBOL(usbcam_curframe_get);
-
-void usbcam_curframe_complete_detail(struct usbcam_dev *udp, int is_error,
-				     struct usbcam_curframe *cf)
-{
-	struct usbcam_frame *framep;
-
-	usbcam_chklock(udp);
-
-	framep = usbcam_capture_curframe(udp);
-	if (!framep) {
-		usbcam_warn(udp, "%s: no current frame!", __FUNCTION__);
-		return;
-	}
-
-	if (framep->vbb.state != STATE_ACTIVE) {
-		usbcam_err(udp, "%s: current frame is in unexpected state %d",
-			   __FUNCTION__, framep->vbb.state);
-	}
-
-	if (cf && !is_error) {
-		framep->vbb.size = cf->uc_size;
-		framep->vbb.field = cf->uc_field;
-		framep->vbb.ts = cf->uc_timestamp;
-
-		if (framep->vbb.bsize < cf->uc_size) {
-			usbcam_warn(udp, "%s: minidriver supplied "
-				    "excessive size %zu",
-				    __FUNCTION__, cf->uc_size);
-			framep->vbb.size = framep->vbb.bsize;
-		}
-	}
-
-	else if (is_error && usbcam_curframe_testpattern(udp)) {
-		/*
-		 * No test pattern available.
-		 * Punt: just memset the frame buffer to zero.
-		 */
-		const char tp[1] = { 0 };
-		usbcam_curframe_fill(udp, 0, tp, 1, udp->ud_format.sizeimage);
-	}
-
-	usbcam_capture_complete_frame(udp, framep, 0);
-}
-EXPORT_SYMBOL(usbcam_curframe_complete_detail);
-
-void usbcam_curframe_abortall(struct usbcam_dev *udp)
-{
-	usbcam_dbg(udp, CAPTURE, "minidriver aborting all frames");
-
-	usbcam_chklock(udp);
-
-	if (udp->ud_capturing) {
-		usbcam_warn(udp, "%s: minidriver left ud_capturing set",
-			    __FUNCTION__);
-	}
-	usbcam_capture_abortall(udp);
-}
-EXPORT_SYMBOL(usbcam_curframe_abortall);
-
-
-/*
- * Test pattern code
- */
-
-void usbcam_curframe_fill(struct usbcam_dev *udp, size_t offset,
-			  const void *pattern, int patlen, int nrecs)
-{
-	struct usbcam_curframe cf;
-	size_t end;
-
-	usbcam_chklock(udp);
-
-	if (usbcam_curframe_get(udp, &cf)) {
-		usbcam_warn(udp, "%s: no current frame", __FUNCTION__);
-		return;
-	}
-
-	end = offset + (patlen * nrecs);
-	if (end > cf.uc_size) {
-		usbcam_warn(udp, "%s(offs=%zu patlen=%d nrecs=%d) would "
-			    "write past end of %zu byte framebuffer",
-			    __FUNCTION__,
-			    offset, patlen, nrecs, cf.uc_size);
-		if (offset > cf.uc_size)
-			nrecs = 0;
-		else
-			nrecs = (cf.uc_size - offset) / patlen;
-	}
-	else if (end > udp->ud_format.sizeimage)
-		usbcam_warn(udp, "%s(offs=%zu patlen=%d nrecs=%d) writing "
-			    "beyond %u-byte sizeimage", __FUNCTION__,
-			    offset, patlen, nrecs, udp->ud_format.sizeimage);
-
-	if (!nrecs)
-		return;
-
-	if (patlen == 1) {
-		memset(cf.uc_base + offset, *(char *)pattern, nrecs);
-		return;
-	}
-
-	while (nrecs--) {
-		memcpy(cf.uc_base + offset, pattern, patlen);
-		offset += patlen;
-	}
-}
-EXPORT_SYMBOL(usbcam_curframe_fill);
-
-void usbcam_curframe_fill_lines(struct usbcam_dev *udp,
-				const char *pat, int patlen,
-				int pixperpat)
-{
-	int line, nrecperline, stride;
-	size_t offset = 0;
-
-	nrecperline = (udp->ud_format.width + pixperpat - 1) / pixperpat;
-	stride = udp->ud_format.bytesperline
-		? udp->ud_format.bytesperline
-		: (nrecperline * patlen);
-
-	if ((patlen * nrecperline) == stride) {
-		usbcam_curframe_fill(udp, 0, pat, patlen,
-				     nrecperline * udp->ud_format.height);
-		return;
-	}
-
-	for (line = 0; line < udp->ud_format.height; line++) {
-		usbcam_curframe_fill(udp, offset, pat, patlen, nrecperline);
-		offset += stride;
-	}
-}
-
-void usbcam_curframe_fill_interleaved(struct usbcam_dev *udp,
-				      const char *pat_even,
-				      const char *pat_odd,
-				      int patlen, int pixperpat)
-{
-	int line, nrecperline, stride;
-	size_t offset = 0;
-
-	nrecperline = (udp->ud_format.width + pixperpat - 1) / pixperpat;
-	stride = udp->ud_format.bytesperline
-		? udp->ud_format.bytesperline
-		: (nrecperline * patlen);
-
-	for (line = 0; line < udp->ud_format.height; line++) {
-		usbcam_curframe_fill(udp, offset,
-				     (line & 1) ? pat_odd : pat_even,
-				     patlen, nrecperline);
-		offset += stride;
-	}
-}
-
-void usbcam_curframe_fill_planar(struct usbcam_dev *udp,
-				 const char *pat0, int pat0len, int pixperpat0,
-				 const char *pat1, int pat1len, int pixperpat1,
-				 const char *pat2, int pat2len, int pixperpat2)
-{
-	int nrecperline;
-	size_t offset = 0;
-
-	if (pat0 && pat0len) {
-		nrecperline = ((udp->ud_format.width + pixperpat0 - 1) /
-			       pixperpat0);
-		usbcam_curframe_fill(udp, offset, pat0, pat0len,
-				     nrecperline * udp->ud_format.height);
-		offset += (nrecperline * udp->ud_format.height * pat0len);
-	}
-	if (pat1 && pat1len) {
-		nrecperline = ((udp->ud_format.width + pixperpat1 - 1) /
-			       pixperpat1);
-		usbcam_curframe_fill(udp, offset, pat1, pat1len,
-				     nrecperline * udp->ud_format.height);
-		offset += (nrecperline * udp->ud_format.height * pat1len);
-	}
-	if (pat2 && pat2len) {
-		nrecperline = ((udp->ud_format.width + pixperpat2 - 1) /
-			       pixperpat2);
-		usbcam_curframe_fill(udp, offset, pat2, pat2len,
-				     nrecperline * udp->ud_format.height);
-		offset += (nrecperline * udp->ud_format.height * pat2len);
-	}
-}
-
-/*
- * The goal is to be able to come up with a solid blue image in all
- * basic uncompressed formats.  No JPEG or compressed formats, at least
- * not yet.
- */
-int usbcam_curframe_testpattern(struct usbcam_dev *udp)
-{
-	usbcam_chklock(udp);
-
-#define DO_FILL(PIXPERPAT, TP...) {					\
-	const char tp[] = {TP};						\
-	usbcam_curframe_fill_lines(udp, tp, sizeof(tp),	PIXPERPAT);	\
-}
-	switch (udp->ud_format.pixelformat) {
-	case V4L2_PIX_FMT_RGB332:
-		DO_FILL(1, 0x03)
-		return 0;
-	case V4L2_PIX_FMT_RGB555:
-	case V4L2_PIX_FMT_RGB565:
-		DO_FILL(1, 0x1f, 0x00)
-		return 0;
-	case V4L2_PIX_FMT_RGB555X:
-	case V4L2_PIX_FMT_RGB565X:
-		DO_FILL(1, 0x00, 0x1f)
-		return 0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-	case V4L2_PIX_FMT_RGB444:
-		DO_FILL(1, 0x00, 0x0f)
-		return 0;
-#endif
-	case V4L2_PIX_FMT_BGR24:
-		DO_FILL(1, 0xff, 0x00, 0x00);
-		return 0;
-	case V4L2_PIX_FMT_RGB24:
-		DO_FILL(1, 0x00, 0x00, 0xff);
-		return 0;
-	case V4L2_PIX_FMT_BGR32:
-		DO_FILL(1, 0xff, 0x00, 0x00, 0x00);
-		return 0;
-	case V4L2_PIX_FMT_RGB32:
-		DO_FILL(1, 0x00, 0x00, 0xff, 0x00);
-		return 0;
-	case V4L2_PIX_FMT_GREY:
-		DO_FILL(1, 0x1f);
-		return 0;
-	case V4L2_PIX_FMT_YUYV:
-		DO_FILL(2, 0x29, 0xf0, 0x29, 0x6e);
-		return 0;
-	case V4L2_PIX_FMT_UYVY:
-		DO_FILL(2, 0xf0, 0x29, 0x6e, 0x29);
-		return 0;
-	case V4L2_PIX_FMT_YYUV:
-		DO_FILL(2, 0x29, 0x29, 0xf0, 0x6e);
-		return 0;
-	case V4L2_PIX_FMT_Y41P:
-		DO_FILL(8,
-			0xf0, 0x29, 0x6e, 0x29, 0xf0, 0x29, 0x6e, 0x29,
-			0x29, 0x29, 0x29, 0x29);
-		return 0;
-#undef DO_FILL
-
-	case V4L2_PIX_FMT_SBGGR8: {
-		const char tp0[] = { 0xff, 0x00 }, tp1[] = { 0x00, 0x00 };
-		usbcam_curframe_fill_interleaved(udp, tp0, tp1, 2, 2);
-		return 0;
-	}
-	case V4L2_PIX_FMT_YVU410: {
-		const char tp0[] = {0x29}, tp1[] = {0x6e}, tp2[] = {0xf0};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 16,
-					    tp2, sizeof(tp2), 16);
-		return 0;
-	}
-	case V4L2_PIX_FMT_YUV410: {
-		const char tp0[] = {0x29}, tp1[] = {0xf0}, tp2[] = {0x6e};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 16,
-					    tp2, sizeof(tp2), 16);
-		return 0;
-	}
-	case V4L2_PIX_FMT_YVU420: {
-		const char tp0[] = {0x29}, tp1[] = {0x6e}, tp2[] = {0xf0};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 4,
-					    tp2, sizeof(tp2), 4);
-		return 0;
-	}
-	case V4L2_PIX_FMT_YUV411P: 
-	case V4L2_PIX_FMT_YUV420: {
-		const char tp0[] = {0x29}, tp1[] = {0xf0}, tp2[] = {0x6e};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 4,
-					    tp2, sizeof(tp2), 4);
-		return 0;
-	}
-	case V4L2_PIX_FMT_YUV422P: {
-		const char tp0[] = {0x29}, tp1[] = {0xf0}, tp2[] = {0x6e};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 2,
-					    tp2, sizeof(tp2), 2);
-		return 0;
-	}
-	case V4L2_PIX_FMT_NV12: {
-		const char tp0[] = {0x29}, tp1[] = {0xf0, 0x6e};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 4,
-					    NULL, 0, 0);
-		return 0;
-	}
-	case V4L2_PIX_FMT_NV21: {
-		const char tp0[] = {0x29}, tp1[] = {0x6e, 0xf0};
-		usbcam_curframe_fill_planar(udp, tp0, sizeof(tp0), 1,
-					    tp1, sizeof(tp1), 4,
-					    NULL, 0, 0);
-		return 0;
-	}
-	}
-
-	return -EINVAL;
-}
-EXPORT_SYMBOL(usbcam_curframe_testpattern);
-
-
-/*
- * video-buf interfaces for managing frame buffers
- */
-
-static int usbcam_videobuf_setup(struct videobuf_queue *vq,
-				 unsigned int *count, unsigned int *size)
-{
-	struct usbcam_fh *ufp = container_of(vq, struct usbcam_fh, uf_vbq);
-	struct usbcam_dev *udp = ufp->uf_dev;
-
-	usbcam_lock(udp);
-
-	/* APPBUG: possibly request larger buffers than necessary */
-	if ((ufp->uf_flags & USBCAM_FH_USE_FIXED_FB) &&
-	    (fixed_fbsize > udp->ud_format.sizeimage))
-		*size = fixed_fbsize;
-	else
-		*size = udp->ud_format.sizeimage;
-
-	if (!*count)
-		*count = 2;
-
-	usbcam_dbg(udp, VIDEOBUF, "videobuf setup: size=%u count=%u",
-		   *size, *count);
-
-	usbcam_unlock(udp);
-	return 0;
-}
-
-static void usbcam_videobuf_free(struct videobuf_queue *vq,
-				 struct usbcam_frame *framep)
-{
-	struct videobuf_dmabuf *dma = usbframe_get_dmabuf(&framep->vbb);
-
-	videobuf_waiton(&framep->vbb, 0, 0);
-	videobuf_dma_unmap(vq, dma);
-	videobuf_dma_free(dma);
-	if (framep->vbb.state != STATE_NEEDS_INIT) {
-		if (framep->vmap_base) {
-			vunmap(framep->vmap_base);
-			framep->vmap_base = NULL;
-			framep->vmap_sof = NULL;
-		}
-		assert(list_empty(&framep->cap_links));
-		framep->vbb.state = STATE_NEEDS_INIT;
-	}
-}
-
-static int usbcam_videobuf_prepare(struct videobuf_queue *vq,
-				   struct videobuf_buffer *vb,
-				   enum v4l2_field field)
-{
-	struct usbcam_fh *ufp = container_of(vq, struct usbcam_fh, uf_vbq);
-	struct usbcam_dev *udp = ufp->uf_dev;
-	struct usbcam_frame *framep =
-		container_of(vb, struct usbcam_frame, vbb);
-    struct videobuf_dmabuf *dma = usbframe_get_dmabuf(&framep->vbb);
-	int res;
-	
-
-	framep->vbb.size = udp->ud_format.sizeimage;
-	if (framep->vbb.baddr && (framep->vbb.bsize < framep->vbb.size)) {
-		usbcam_warn(udp, "process %s requested capture of a frame "
-			    "larger than its", current->comm);
-		usbcam_warn(udp, "allocated frame buffer, fix it!");
-		return -EINVAL;
-	}
-
-	if (framep->vbb.state == STATE_NEEDS_INIT) {
-		/*
-		 * This is the place where we initialize the rest of
-		 * the usbcam_frame structure.
-		 */
-		INIT_LIST_HEAD(&framep->cap_links);
-		framep->vmap_base = NULL;
-		framep->vmap_sof = NULL;
-
-		usbcam_dbg(udp, VIDEOBUF,
-			   "preparing frame %d/%p", framep->vbb.i, framep);
-
-		/* We also lock down the memory that was allocated for it */
-		res = videobuf_iolock(vq, &framep->vbb, NULL);
-		if (res)
-			goto fail;
-
-		/* If there's no kernel mapping, we must create one */
-		if (!dma->vmalloc) {
-			framep->vmap_base = vmap(dma->pages,
-						 dma->nr_pages,
-						 VM_MAP,
-						 PAGE_KERNEL);
-			if (!framep->vmap_base) {
-				res = -ENOMEM;
-				goto fail;
-			}
-
-			framep->vmap_sof =
-				((char *)framep->vmap_base) +
-				dma->offset;
-		}
-	}
-
-	framep->vbb.field = field;
-	framep->vbb.state = STATE_PREPARED;
-	return 0;
-
-fail:
-	usbcam_warn(udp, "videobuf_prepare failed.");
-	usbcam_videobuf_free(vq, framep);
-	return res;
-}
-
-static void usbcam_videobuf_queue(struct videobuf_queue *vq,
-				  struct videobuf_buffer *vb)
-{
-	struct usbcam_fh *ufp = container_of(vq, struct usbcam_fh, uf_vbq);
-	struct usbcam_dev *udp = ufp->uf_dev;
-	struct usbcam_frame *framep =
-		container_of(vb, struct usbcam_frame, vbb);
-	int was_empty = 0;
-
-	assert(framep->vbb.state != STATE_NEEDS_INIT);
-
-	usbcam_lock(udp);
-
-	if (list_empty(&udp->ud_frame_cap_queue))
-		was_empty = 1;
-
-	usbcam_dbg(udp, VIDEOBUF, "queueing frame %d/%p",
-		   framep->vbb.i, framep);
-
-	/*
-	 * We always set buffers to STATE_ACTIVE to prevent them from
-	 * being manipulated / dequeued by the videobuf code.
-	 */
-	list_add_tail(&framep->cap_links, &udp->ud_frame_cap_queue);
-	framep->vbb.state = STATE_ACTIVE;
-
-	if (was_empty && !udp->ud_capturing) {
-		(void) usbcam_capture_start(udp);
-	}
-
-	usbcam_unlock(udp);
-}
-
-static void usbcam_videobuf_release(struct videobuf_queue *vq,
-				    struct videobuf_buffer *vb)
-{
-	struct usbcam_fh *ufp = container_of(vq, struct usbcam_fh, uf_vbq);
-	struct usbcam_dev *udp = ufp->uf_dev;
-	struct usbcam_frame *framep =
-		container_of(vb, struct usbcam_frame, vbb);
-	int stopped_capture = 0;
-
-	usbcam_lock(udp);
-
-	if ((framep->vbb.state != STATE_NEEDS_INIT) &&
-	    !list_empty(&framep->cap_links)) {
-
-		usbcam_dbg(udp, VIDEOBUF,
-			   "aborting frame %d/%p", framep->vbb.i, framep);
-
-		/*
-		 * An active frame is being shot down here, most
-		 * likely by videobuf_queue_cancel.
-		 */
-		assert(framep->vbb.state == STATE_ACTIVE);
-
-		if (udp->ud_capturing &&
-		    !list_empty(&udp->ud_frame_cap_queue) &&
-		    (framep == usbcam_capture_curframe(udp))) {
-			/*
-			 * The current frame has been user-aborted.
-			 * We will stop capturing.  The minidriver may complete
-			 * it with an error, or may leave it alone, in which
-			 * case we will complete it with an error.
-			 */
-			usbcam_dbg(udp, VIDEOBUF,
-				   "current frame aborted, stopping capture");
-
-			usbcam_capture_stop(udp);
-			stopped_capture = 1;
-		}
-
-		if (!list_empty(&framep->cap_links))
-			usbcam_capture_complete_frame(udp, framep, 1);
-
-		/*
-		 * Ideally, if we stopped capturing, and there are frames
-		 * still in the queue, we would restart.
-		 *
-		 * In reality, we only take this code path if all frames
-		 * from the owning file handle are aborted, and restarting
-		 * would pointlessly slow down this process.
-		 */
-	}
-
-	usbcam_unlock(udp);
-	usbcam_videobuf_free(vq, framep);
-}
-
-static struct videobuf_queue_ops usbcam_videobuf_qops = {
-	.buf_setup	= usbcam_videobuf_setup,
-	.buf_prepare	= usbcam_videobuf_prepare,
-	.buf_queue	= usbcam_videobuf_queue,
-	.buf_release	= usbcam_videobuf_release,
-};
-
-
-/*
- * Reference Counting Notes
- *
- * Each usbcam_minidrv gets:
- * - One reference for being in the registered state
- * - One reference for each outstanding usbcam_dev
- *
- * Each usbcam_dev gets:
- * - One reference for having its V4L minor registered and not released
- * - One reference for having its underlying USB device not disconnected
- * - One reference for each open file handle
- */
-
-static void usbcam_minidrv_release(struct kref *kref)
-{
-	struct usbcam_minidrv *minidrv =
-		container_of(kref, struct usbcam_minidrv, um_kref);
-
-	assert(!minidrv->um_dev_count);
-	usbcam_dbgm(minidrv, DEV_STATE, "%s: destroying minidrvier",
-		    __FUNCTION__);
-	kfree(minidrv);
-}
-
-/*
- */
-static void usbcam_work_stop(struct usbcam_dev *udp);
-static inline void usbcam_work_maybe_stop(struct usbcam_dev *udp)
-{
-	if (!udp->ud_work_refs)
-		usbcam_work_stop(udp);
-}
-
-static void usbcam_dev_free(struct kref *kref)
-{
-	struct usbcam_dev *udp =
-		container_of(kref, struct usbcam_dev, ud_kref);
-
-	if (udp->ud_work_refs) {
-		usbcam_lock(udp);
-		usbcam_warn(udp, "%s: work queue has %d leaked refs",
-			    __FUNCTION__, udp->ud_work_refs);
-		while (udp->ud_work_refs)
-			usbcam_work_unref(udp);
-		usbcam_unlock(udp);
-	}
-
-	usbcam_work_maybe_stop(udp);
-	assert(!udp->ud_work_thread);
-
-	usb_put_intf(udp->ud_intf);
-	udp->ud_intf = NULL;
-
-	usb_put_dev(udp->ud_dev);
-	udp->ud_dev = NULL;
-
-	mutex_lock(&udp->ud_minidrv->um_lock);
-
-	assert(!list_empty(&udp->ud_drv_links));
-	assert(udp->ud_minidrv->um_dev_count > 0);
-
-	list_del_init(&udp->ud_drv_links);
-	udp->ud_minidrv->um_dev_count--;
-
-	mutex_unlock(&udp->ud_minidrv->um_lock);
-
-	kref_put(&udp->ud_minidrv->um_kref, usbcam_minidrv_release);
-	kfree(udp);
-}
-
-static void usbcam_dev_release(struct kref *kref)
-{
-	struct usbcam_dev *udp =
-		container_of(kref, struct usbcam_dev, ud_kref);
-
-	usbcam_dbg(udp, DEV_STATE, "%s: destroying device", __FUNCTION__);
-
-	if (usbcam_minidrv_op_present(udp, release)) {
-		usbcam_lock(udp);
-		usbcam_minidrv_op(udp, release);
-		usbcam_unlock(udp);
-	}
-	usbcam_dev_free(kref);
-}
-
-void usbcam_put(struct usbcam_dev *udp)
-{
-	kref_put(&udp->ud_kref, usbcam_dev_release);
-}
-EXPORT_SYMBOL(usbcam_put);
-
-
-/*
- * Work item crap
- */
-
-enum {
-	USBCAM_WORKSTATE_DEAD,
-	USBCAM_WORKSTATE_IDLE,
-	USBCAM_WORKSTATE_MUTEX_WAIT,
-	USBCAM_WORKSTATE_RUNNING,
-};
-
-DECLARE_WAIT_QUEUE_HEAD(usbcam_work_idle_wait);
-
-static int usbcam_work_thread(void *arg)
-{
-	struct usbcam_dev *udp = (struct usbcam_dev *) arg;
-	struct usbcam_workitem *wip;
-	sigset_t wakesigs;
-	unsigned long flags;
-	usbcam_workfunc_t fn;
-	int res;
-
-	current->flags |= PF_NOFREEZE;
-	set_user_nice(current, -5);
-
-	sigemptyset(&wakesigs);
-	sigaddset(&wakesigs, SIGUSR1);
-
-	while (1) {
-		/* Wait for something to appear on the work queue */
-		spin_lock_irqsave(&udp->ud_work_lock, flags);
-		udp->ud_work_lockwait = 0;
-		if (list_empty(&udp->ud_work_queue)) {
-			if (kthread_should_stop()) {
-				spin_unlock_irqrestore(&udp->ud_work_lock,
-						       flags);
-				break;
-			}
-
-			set_current_state(TASK_INTERRUPTIBLE);
-			wake_up_all(&usbcam_work_idle_wait);
-			spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-			schedule();
-			spin_lock_irqsave(&udp->ud_work_lock, flags);
-		}
-		udp->ud_work_lockwait = 1;
-		spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-
-		/* Enable the mutex wait cancelation signal */
-		sigprocmask(SIG_UNBLOCK, &wakesigs, NULL);
-
-		/* Re-check the queue, wait if it's still nonempty */
-		res = -EINTR;
-		if (!list_empty(&udp->ud_work_queue)) {
-			res = mutex_lock_interruptible(&udp->ud_lock);
-		}
-
-		/* Disable the mutex wait cancelation signal */
-		sigprocmask(SIG_BLOCK, &wakesigs, NULL);
-		flush_signals(current);
-
-		if (res)
-			continue;
-
-		wip = NULL;
-		spin_lock_irqsave(&udp->ud_work_lock, flags);
-		udp->ud_work_lockwait = 0;
-		if (!list_empty(&udp->ud_work_queue)) {
-			wip = container_of(udp->ud_work_queue.next,
-					   struct usbcam_workitem,
-					   uw_links);
-			list_del_init(&wip->uw_links);
-		}
-
-		spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-
-		if (wip) {
-			fn = wip->uw_func;
-			fn(wip);
-		}
-
-		usbcam_unlock(udp);
-	}
-
-	return 0;
-}
-
-void usbcam_work_init(struct usbcam_workitem *wip, usbcam_workfunc_t func)
-{
-	INIT_LIST_HEAD(&wip->uw_links);
-	wip->uw_dev = NULL;
-	wip->uw_func = func;
-}
-EXPORT_SYMBOL(usbcam_work_init);
-
-int usbcam_work_queue(struct usbcam_dev *udp, struct usbcam_workitem *wip)
-{
-	unsigned long flags;
-	int res;
-
-	spin_lock_irqsave(&udp->ud_work_lock, flags);
-	if (!list_empty(&wip->uw_links)) {
-		res = -EALREADY;
-		assert(wip->uw_dev == udp);
-	} else if (udp->ud_work_refs) {
-		res = 0;
-		wip->uw_dev = udp;
-		list_add_tail(&wip->uw_links, &udp->ud_work_queue);
-		if (udp->ud_work_queue.next == &wip->uw_links)
-			wake_up_process(udp->ud_work_thread);
-	} else {
-		res = -EBUSY;
-	}
-	spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-
-	return res;
-}
-EXPORT_SYMBOL(usbcam_work_queue);
-
-int usbcam_work_cancel(struct usbcam_dev *udp, struct usbcam_workitem *wip)
-{
-	unsigned long flags;
-	int res, wakeit = 0;
-
-	usbcam_chklock(udp);
-
-	res = -ENOENT;
-	spin_lock_irqsave(&udp->ud_work_lock, flags);
-	if (!list_empty(&wip->uw_links)) {
-		res = 0;
-		assert(wip->uw_dev == udp);
-		if ((udp->ud_work_queue.next == &wip->uw_links) &&
-		    udp->ud_work_lockwait)
-			wakeit = 1;
-		list_del_init(&wip->uw_links);
-		if (wakeit)
-			force_sig(SIGUSR1, udp->ud_work_thread);
-	}
-	spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-
-	return res;
-}
-EXPORT_SYMBOL(usbcam_work_cancel);
-
-int usbcam_work_ref(struct usbcam_dev *udp)
-{
-	struct task_struct *kt_new;
-	unsigned long flags;
-
-	usbcam_chklock(udp);
-
-	/*
-	 * We adjust this value under the spinlock to synchronize with
-	 * usbcam_work_queue().
-	 */
-	spin_lock_irqsave(&udp->ud_work_lock, flags);
-	udp->ud_work_refs++;
-	spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-
-	if (!udp->ud_work_thread) {
-		kt_new = kthread_create(usbcam_work_thread, udp,
-					udp->ud_dev_name);
-		if (!kt_new) {
-			usbcam_err(udp, "%s: could not create worker thread",
-				   __FUNCTION__);
-			return -ENOMEM;
-		}
-
-		spin_lock_irqsave(&udp->ud_work_lock, flags);
-		udp->ud_work_thread = kt_new;
-		spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL(usbcam_work_ref);
-
-void usbcam_work_unref(struct usbcam_dev *udp)
-{
-	unsigned long flags;
-
-	usbcam_chklock(udp);
-
-	if (!udp->ud_work_refs) {
-		usbcam_warn(udp, "%s: work queue has zero refs", __FUNCTION__);
-		return;
-	}
-
-	spin_lock_irqsave(&udp->ud_work_lock, flags);
-	udp->ud_work_refs--;
-	spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-}
-EXPORT_SYMBOL(usbcam_work_unref);
-
-void usbcam_work_runqueue(struct usbcam_dev *udp)
-{
-	struct usbcam_workitem *wip;
-	unsigned long flags;
-	usbcam_workfunc_t fn;
-
-	usbcam_chklock(udp);
-
-	spin_lock_irqsave(&udp->ud_work_lock, flags);
-	while (!list_empty(&udp->ud_work_queue)) {
-		wip = container_of(udp->ud_work_queue.next,
-				   struct usbcam_workitem,
-				   uw_links);
-		list_del_init(&wip->uw_links);
-		spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-
-		fn = wip->uw_func;
-		fn(wip);
-
-		spin_lock_irqsave(&udp->ud_work_lock, flags);
-	}
-	spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-}
-EXPORT_SYMBOL(usbcam_work_runqueue);
-
-
-static void usbcam_work_stop(struct usbcam_dev *udp)
-{
-	struct task_struct *kt_stop = NULL;
-	unsigned long flags;
-
-	usbcam_lock(udp);
-
-	if (!udp->ud_work_refs) {
-		/* Prevent further tasks from being queued */
-		spin_lock_irqsave(&udp->ud_work_lock, flags);
-		kt_stop = udp->ud_work_thread;
-		udp->ud_work_thread = NULL;
-		spin_unlock_irqrestore(&udp->ud_work_lock, flags);
-	}
-
-	usbcam_unlock(udp);
-
-	if (kt_stop) {
-		/*
-		 * Wait for the queue to empty out, then stop the
-		 * thread.  It might be easier to just call
-		 * usbcam_work_flush() and execute the remaining
-		 * tasks synchronously in the current thread.
-		 */
-		wait_event(usbcam_work_idle_wait,
-			   list_empty(&udp->ud_work_queue));
-		kthread_stop(kt_stop);
-	}
-}
-
-
-
-/*
- * V4L file_operations callout implementations
- */
-
-static int usbcam_v4l_open(struct inode *inode, struct file *filp)
-{
-	struct usbcam_dev *udp;
-	struct usbcam_fh *ufp;
-	int autopm_ref = 0;
-	int work_ref = 0;
-	int res = 0;
-
-	/* The usbcam_dev is referenced by the videodev at this point */
-	udp = container_of(video_devdata(filp), struct usbcam_dev, ud_vdev);
-
-	ufp = (struct usbcam_fh *) kzalloc(sizeof(*ufp), GFP_KERNEL);
-	if (!ufp)
-		return -ENOMEM;
-
-	ufp->uf_dev = udp;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-	videobuf_queue_init(&ufp->uf_vbq,
-			    &usbcam_videobuf_qops,
-			    NULL,
-			    NULL,
-			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_INTERLACED,
-			    sizeof(struct usbcam_frame), ufp);
-#else
-	videobuf_queue_pci_init(&ufp->uf_vbq,
-			    &usbcam_videobuf_qops,
-			    NULL,
-			    NULL,
-			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			    V4L2_FIELD_INTERLACED,
-			    sizeof(struct usbcam_frame), ufp);
-#endif
-
-	mutex_lock(&udp->ud_open_lock);
-
-	if (!udp->ud_user_refs) {
-		res = usb_autopm_get_interface(udp->ud_intf);
-		if (res)
-			goto bail_nolock;
-		autopm_ref = 1;
-	}
-
-	usbcam_lock(udp);
-
-	if (udp->ud_disconnected) {
-		usbcam_warn(udp, "udp is disconnected; bailing");
-		res = -ENODEV;
-		goto bail;
-	}
-
-	if (!udp->ud_user_refs) {
-		if (!udp->ud_minidrv->um_ops->no_workref_on_open) {
-			res = usbcam_work_ref(udp);
-			if (res)
-				goto bail;
-			work_ref = 1;
-		}
-
-		if (usbcam_minidrv_op_present(udp, open)) {
-			res = usbcam_minidrv_op(udp, open);
-			if (res) {
-				/* Can release/reacquire device lock */
-				if (work_ref)
-					usbcam_work_unref(udp);
-				assert(!udp->ud_user_refs);	
-				goto bail;
-			}
-		}
-
-		/* Transfer the autopm reference */
-		assert(autopm_ref);
-		autopm_ref = 0;
-	}
-
-	udp->ud_user_refs++;
-	filp->private_data = ufp;
-	usbcam_get(udp);
-
-bail:
-	usbcam_unlock(udp);
-bail_nolock:
-	mutex_unlock(&udp->ud_open_lock);
-	if (res)
-		kfree(ufp);
-	if (autopm_ref)
-		usb_autopm_put_interface(udp->ud_intf);
-	usbcam_work_maybe_stop(udp);
-	return res;
-}
-
-static int usbcam_v4l_release(struct inode *inode, struct file *filp)
-{
-	struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
-	struct usbcam_dev *udp = ufp->uf_dev;
-	int autopm_ref = 0;
-	
-	videobuf_mmap_free(&ufp->uf_vbq);
-
-	mutex_lock(&udp->ud_open_lock);
-	usbcam_lock(udp);
-
-	assert(udp->ud_user_refs);
-	if (udp->ud_excl_owner == filp)
-		udp->ud_excl_owner = NULL;
-	kfree(ufp);
-	filp->private_data = NULL;
-
-	if (!--udp->ud_user_refs) {
-		usbcam_capture_stop(udp);
-
-		if (usbcam_minidrv_op_present(udp, close))
-			usbcam_minidrv_op(udp, close);
-		if (!udp->ud_minidrv->um_ops->no_workref_on_open)
-			usbcam_work_unref(udp);
-		autopm_ref = 1;
-	}
-
-	usbcam_unlock(udp);
-	mutex_unlock(&udp->ud_open_lock);
-	if (autopm_ref)
-		usb_autopm_put_interface(udp->ud_intf);
-	usbcam_work_maybe_stop(udp);
-	usbcam_put(udp);
-	return 0;
-}
-
-static ssize_t usbcam_v4l_read(struct file *filp, char __user *data,
-			       size_t count, loff_t *ppos)
-{
-	struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
-	int res;
-
-	res = videobuf_read_one(&ufp->uf_vbq, data, count, ppos,
-				(filp->f_flags & O_NONBLOCK) ? 1 : 0);
-	usbcam_work_maybe_stop(ufp->uf_dev);
-	return res;
-}
-
-static unsigned int usbcam_v4l_poll(struct file *filp,
-				    struct poll_table_struct *wait)
-{
-	struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
-
-	return videobuf_poll_stream(filp, &ufp->uf_vbq, wait);
-}
-
-static int usbcam_v4l_mmap(struct file *filp, struct vm_area_struct * vma)
-{
-	struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
-
-	return videobuf_mmap_mapper(&ufp->uf_vbq, vma);
-}
-
-static void usbcam_dbg_v4l2_buffer_res(struct usbcam_dev *udp, int res,
-				       void *arg, const char *prefix)
-{
-	struct v4l2_buffer *b __attribute__((unused)) =
-		(struct v4l2_buffer *) arg;
-
-	if (res) {
-		usbcam_dbg(udp, IOCTL_BUF, "%s res:%d", prefix, res);
-		return;
-	}
-
-	usbcam_dbg(udp, IOCTL_BUF, "%s out: index=%d type=%d bytesused=%d "
-		   "flags=0x%x field=%d memory=%d m=0x%lx length=%d",
-		   prefix, b->index, b->type, b->bytesused,
-		   b->flags, b->field, b->memory, b->m.userptr, b->length);
-}
-
-static void usbcam_dbg_v4l2_pix_format(struct usbcam_dev *udp,
-				       struct v4l2_pix_format *f,
-				       const char *prefix)
-{
-	__u32 pixfmt = f->pixelformat;
-	if (!pixfmt)
-		pixfmt = 0x3f3f3f3f;
-	usbcam_dbg(udp, IOCTL_FMT, "%s wid=%d hgt=%d fmt=%.4s field=%d "
-		   "bpl=%d size=%d cs=%d", prefix,
-		   f->width, f->height, (char *) &pixfmt, f->field,
-		   f->bytesperline, f->sizeimage, f->colorspace);
-}
-
-static void usbcam_dbg_v4l2_pix_format_res(struct usbcam_dev *udp, int res,
-					   struct v4l2_pix_format *f,
-					   const char *prefix)
-{
-	if (res) {
-		usbcam_dbg(udp, IOCTL_FMT, "%s %d", prefix, res);
-		return;
-	}
-	usbcam_dbg_v4l2_pix_format(udp, f, prefix);
-}
-
-static int usbcam_v4l_int_ioctl(struct inode *inodep, struct file *filp,
-				unsigned int cmd, void *arg)
-{
-	struct usbcam_fh *ufp = (struct usbcam_fh *) filp->private_data;
-	struct usbcam_dev *udp = ufp->uf_dev;
-	int droplock = 0, res;
-	
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-	/* V4L1 API -- Handle this before v4l_compat_translate_ioctl(). */
-	if (cmd == VIDIOCGMBUF) {
-		struct v4l2_requestbuffers req;
-		struct video_mbuf *p = (struct video_mbuf *) arg;
-		unsigned int i;
-		
-		/*
-		 * APPBUG: motion keeps the first mmap, yet requests
-		 * larger capture sizes.
-		 */
-		usbcam_lock(udp);
-		ufp->uf_flags |= USBCAM_FH_USE_FIXED_FB;
-		usbcam_unlock(udp);
-
-		req.type = ufp->uf_vbq.type;
-		req.count = 2;
-		req.memory = V4L2_MEMORY_MMAP;
-		res = videobuf_reqbufs(&ufp->uf_vbq, &req);
-		if (res == -EBUSY)
-		{
-			usbcam_dbg(udp, IOCTL_BUF,
-				   "VIDIOCGMBUF reqbufs failed: device was busy"
-				   " - closing and trying again."); 
-			
-			res = videobuf_streamoff(&ufp->uf_vbq);
-			if (res < 0)
-			{
-				usbcam_dbg(udp, IOCTL_BUF,
-					   "VIDIOCGMBUF reqbufs failed:"
-					   "couldn't free previous buffer.");
-				return -EBUSY;
-			}
-			else
-			{
-				// we freed previous reqbuf OK.
-				usbcam_lock(udp);
-				ufp->uf_flags |= USBCAM_FH_USE_FIXED_FB;
-				usbcam_unlock(udp);
-
-				req.type = ufp->uf_vbq.type;
-				req.count = 2;
-				req.memory = V4L2_MEMORY_MMAP;
-				res = videobuf_reqbufs(&ufp->uf_vbq, &req);
-			}
-		}
-		else if (res < 0) {
-			usbcam_dbg(udp, IOCTL_BUF,
-				   "VIDIOCGMBUF reqbufs failed: %d", res);
-			return res;
-		}
-
-		p->frames = req.count;
-		p->size = 0;
-		for (i = 0; i < p->frames; i++) {
-			p->offsets[i] = ufp->uf_vbq.bufs[i]->boff;
-			p->size += ufp->uf_vbq.bufs[i]->bsize;
-		}
-
-		usbcam_dbg(udp, IOCTL_BUF, "VIDIOCGMBUF frames=%d size=%d",
-			   p->frames, p->size);
-		return 0;
-	}
-	else if (cmd == VIDIOCGCAP) {
-		struct video_capability *cap = (struct video_capability *) arg;
-		
-		usbcam_lock(udp);
-		
-		strlcpy(cap->name, udp->ud_vdev.name, sizeof(cap->name));
-		cap->type = VID_TYPE_CAPTURE;
-		cap->audios = 0;
-		cap->channels = 1;	/* only one input source, the camera */
-		
-		cap->maxwidth = udp->ud_format.width;
-		cap->maxheight = udp->ud_format.height;
-		
-		/*
-		 * We lie, here. These values normally return 640x480, which is
-		 * actually the maximum, not the minimum. Minimum is usually
-		 * 160x120. It's sort of useful to lie since lots of software
-		 * just stick with the minimum - we want higher res for the
-		 * user where possible.
-		*/
-		
-		cap->minwidth = udp->ud_format.width;
-		cap->minheight = udp->ud_format.height;
-		
-		usbcam_unlock(udp);
-		return 0;
-	}
-	else if (cmd == VIDIOCGFBUF) {
-		struct video_buffer *buf = (struct video_buffer *) arg;
-		
-		usbcam_lock(udp);
-		buf->base = NULL;	/* no physical frame buffer access */
-		buf->height = udp->ud_format.height;
-		buf->width = udp->ud_format.width;
-		
-		// graciously stolen from drivers/media/video/v4l1-compat.c
-		// and modified slightly.
-		switch (udp->ud_format.pixelformat) {
-		case V4L2_PIX_FMT_RGB332:
-			buf->depth = 8;
-			break;
-		case V4L2_PIX_FMT_RGB555:
-			buf->depth = 15;
-			break;
-		case V4L2_PIX_FMT_RGB565:
-			buf->depth = 16;
-			break;
-		case V4L2_PIX_FMT_BGR24:
-			buf->depth = 24;
-			break;
-		case V4L2_PIX_FMT_BGR32:
-			buf->depth = 32;
-			break;
-		default:
-			buf->depth = 0;
-		}
-		
-		if (udp->ud_format.bytesperline) {
-			buf->bytesperline = udp->ud_format.bytesperline;
-			
-			/* typically comes out at 16 bit depth as non-rgb */
-			if (!buf->depth && buf->width)
-				buf->depth   = ((udp->ud_format.bytesperline<<3)
-						  + (buf->width-1) )
-						  /buf->width;
-		} else {
-			buf->bytesperline =
-				(buf->width * buf->depth + 7) & 7;
-			buf->bytesperline >>= 3;
-		}
-		
-		usbcam_unlock(udp);
-		return 0;
-	}
-#endif
-	/* If the command is any other V4L1 API, pass it to the translator */
-	if (_IOC_TYPE(cmd) == 'v')
-	{
-		return v4l_compat_translate_ioctl(inodep, filp, cmd, arg,
-						  usbcam_v4l_int_ioctl);
-	}
-
-	/*
-	 * Pass 1: filter out ioctls that we don't want to give
-	 * the minidriver a chance to handle.
-	 * These tend to be related to frame management, which is
-	 * none of the minidriver's business, and we do not allow the
-	 * minidriver to intercept.
-	 */
-
-	switch (cmd) {
-	case VIDIOC_REQBUFS: {
-		struct v4l2_requestbuffers *r =
-			(struct v4l2_requestbuffers *) arg;
-		/* APPBUG: disable USE_FIXED_FB if we enter this path */
-		usbcam_lock(udp);
-		ufp->uf_flags &= ~(USBCAM_FH_USE_FIXED_FB);
-		usbcam_unlock(udp);
-
-		usbcam_dbg(udp, IOCTL_BUF,
-			   "VIDIOC_REQBUFS count=%d type=%d memory=%d",
-			   r->count, r->type, r->memory);
-		res = videobuf_reqbufs(&ufp->uf_vbq, r);
-		usbcam_dbg(udp, IOCTL_BUF, "REQBUFS result=%d", res);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	case VIDIOC_QUERYBUF: {
-		struct v4l2_buffer *b = (struct v4l2_buffer *) arg;
-		usbcam_dbg(udp, IOCTL_BUF,
-			   "VIDIOC_QUERYBUF in: index=%d type=%d",
-			   b->index, b->type);
-		res = videobuf_querybuf(&ufp->uf_vbq, b);
-		usbcam_dbg_v4l2_buffer_res(udp, res, b, "VIDIOC_QUERYBUF");
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	case VIDIOC_QBUF: {
-		struct v4l2_buffer *b = (struct v4l2_buffer *) arg;
-		/*
-		 * APPBUG: ptlib / Ekiga has an issue with zeroing the
-		 * flags field before calling QBUF.
-		 *
-		 * Minidriver support for fast input switching is
-		 * unavailable for the time being.
-		 */
-		b->flags = 0;
-
-		usbcam_dbg(udp, IOCTL_BUF, "VIDIOC_QBUF in: index=%d type=%d",
-			   b->index, b->type);
-		res = videobuf_qbuf(&ufp->uf_vbq, b);
-		usbcam_dbg_v4l2_buffer_res(udp, res, b, "VIDIOC_QBUF");
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	case VIDIOC_DQBUF: {
-		struct v4l2_buffer *b = (struct v4l2_buffer *) arg;
-		res = videobuf_dqbuf(&ufp->uf_vbq, b,
-				     (filp->f_flags & O_NONBLOCK) ? 1 : 0);
-		usbcam_dbg_v4l2_buffer_res(udp, res, b, "VIDIOC_DQBUF");
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	case VIDIOC_STREAMON: {
-		enum v4l2_buf_type f = *(int *) arg;
-
-		if (f != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			usbcam_dbg(udp, IOCTL_BUF,
-				   "VIDIOC_STREAMON: invalid buf type %d", f);
-			return -EINVAL;
-		}
-		if (!udp->ud_excl_owner) {
-			usbcam_lock(udp);
-			if (!udp->ud_excl_owner)
-				udp->ud_excl_owner = filp;
-			usbcam_unlock(udp);
-		}
-		if (udp->ud_excl_owner != filp) {
-			usbcam_dbg(udp, IOCTL_BUF,
-				   "VIDIOC_STREAMON: not exclusive owner");
-			return -EBUSY;
-		}
-		res = videobuf_streamon(&ufp->uf_vbq);
-		usbcam_dbg(udp, IOCTL_BUF, "VIDIOC_STREAMON: res:%d", res);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	case VIDIOC_STREAMOFF: {
-		enum v4l2_buf_type f = *(int *) arg;
-
-		if (f != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			usbcam_dbg(udp, IOCTL_BUF,
-				   "VIDIOC_STREAMOFF: invalid buf type %d", f);
-			return -EINVAL;
-		}
-		res = videobuf_streamoff(&ufp->uf_vbq);
-		usbcam_dbg(udp, IOCTL_BUF, "VIDIOC_STREAMOFF: res:%d", res);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	}
-
-	/* Pass the ioctl to the minidriver, see if it takes responsibility */
-
-	if (usbcam_minidrv_op_present(udp, ioctl)) {
-		if (!udp->ud_minidrv->um_ops->unlocked_ioctl) {
-			usbcam_lock(udp);
-			droplock = 1;
-		}
-		res = usbcam_minidrv_op(udp, ioctl, cmd, arg);
-		if (droplock)
-			usbcam_unlock(udp);
-
-		usbcam_work_maybe_stop(udp);
-
-		if (res != -ENOIOCTLCMD)
-			return res;
-	}
-
-	/*
-	 * Pass 2: If the minidriver doesn't handle the ioctl, do something
-	 * default.  The minidriver can override all of this stuff by
-	 * intercepting.
-	 */
-
-	switch (cmd) {
-
-	/* DEFAULT CAPABILITIES / DEVICE NAME / DRIVER NAME / BUS INFO */
-	case VIDIOC_QUERYCAP: {
-		struct v4l2_capability *cap = (struct v4l2_capability *) arg;
-
-		usbcam_lock(udp);
-		strlcpy(cap->driver,
-			usbcam_drvname(udp->ud_minidrv),
-			sizeof(cap->driver));
-		strlcpy(cap->card, udp->ud_vdev.name, sizeof(cap->card));
-		snprintf(cap->bus_info, sizeof(cap->bus_info),
-			 "usb:%s", udp->ud_dev->dev.bus_id);
-		cap->version = udp->ud_minidrv->um_version;
-		cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE |
-				     V4L2_CAP_READWRITE |
-				     V4L2_CAP_STREAMING);
-		usbcam_unlock(udp);
-		return 0;
-	}
-
-	/* DEFAULT FORMAT HANDLING - USE MINDIRIVER CALLOUTS */
-	case VIDIOC_ENUM_FMT: {
-		struct v4l2_fmtdesc *f = (struct v4l2_fmtdesc *) arg;
-		struct usbcam_pix_fmt *pf;
-
-		usbcam_lock(udp);
-
-		res = -EINVAL;
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			goto enum_fmt_done;
-		if (f->index >= udp->ud_fmt_array_len)
-			goto enum_fmt_done;
-
-		res = 0;
-		pf = (struct usbcam_pix_fmt *)
-			&(((u8 *) udp->ud_fmt_array)
-			  [f->index * udp->ud_fmt_array_elem_size]);
-		f->flags = pf->flags;
-		f->pixelformat = pf->pixelformat;
-		strlcpy(f->description,
-			pf->description,
-			sizeof(f->description));
-
-	enum_fmt_done:
-		usbcam_unlock(udp);
-		return res;
-	}
-
-	case VIDIOC_G_FMT: {
-		struct v4l2_format *f = (struct v4l2_format *) arg;
-
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_G_FMT: invalid buf type %d"
-				   "(wasn't of type VIDEO_CAPTURE: %d)",
-				   f->type, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-			return -EINVAL;
-		}
-
-		usbcam_lock(udp);
-		f->fmt.pix = udp->ud_format;
-		usbcam_unlock(udp);
-		usbcam_dbg_v4l2_pix_format(udp, &f->fmt.pix,
-					   "VIDIOC_G_FMT: res:");
-		return 0;
-	}
-
-	case VIDIOC_S_FMT: {
-		struct v4l2_format *f = (struct v4l2_format *) arg;
-
-		usbcam_lock(udp);
-
-		usbcam_dbg_v4l2_pix_format(udp, &f->fmt.pix,
-					   "VIDIOC_S_FMT: param:");
-
-		if (udp->ud_disconnected) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_S_FMT: device disconnected");
-			res = -EIO;
-			goto s_fmt_done;
-		}
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_S_FMT: invalid buf type %d",
-				   f->type);
-			res = -EINVAL;
-			goto s_fmt_done;
-		}
-		if (!udp->ud_excl_owner)
-			udp->ud_excl_owner = filp;
-		if (!memcmp(&f->fmt.pix, &udp->ud_format,
-			    sizeof(f->fmt.pix))) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_S_FMT: nothing to do");
-			res = 0;
-			goto s_fmt_done;
-		}
-		if (!usbcam_minidrv_op_present(udp, set_format)) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_S_FMT: no minidriver op");
-			res = -EINVAL;
-			goto s_fmt_done;
-		}
-		if (udp->ud_excl_owner != filp) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_S_FMT: not exclusive owner");
-			res = -EBUSY;
-			goto s_fmt_done;
-		}
-		usbcam_capture_stop_nondestructive(udp);
-		if (udp->ud_capturing) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_S_FMT: capture in progress");
-			res = -EBUSY;
-			goto s_fmt_done;
-		}
-		res = usbcam_minidrv_op(udp, set_format, &f->fmt.pix);
-		usbcam_dbg_v4l2_pix_format_res(udp, res, &f->fmt.pix,
-					       "VIDIOC_S_FMT: res:");
-
-	s_fmt_done:
-		usbcam_unlock(udp);
-		return res;
-	}
-
-	case VIDIOC_TRY_FMT: {
-		struct v4l2_format *f = (struct v4l2_format *) arg;
-
-		usbcam_lock(udp);
-
-		usbcam_dbg_v4l2_pix_format(udp, &f->fmt.pix,
-					   "VIDIOC_TRY_FMT: param:");
-
-		if (udp->ud_disconnected) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_TRY_FMT: device disconnected");
-			res = -EIO;
-			goto s_fmt_done;
-		}
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_TRY_FMT: invalid buf type %d",
-				   f->type);
-			res = -EINVAL;
-			goto try_fmt_done;
-		}
-		if (!usbcam_minidrv_op_present(udp, try_format)) {
-			usbcam_dbg(udp, IOCTL_FMT,
-				   "VIDIOC_TRY_FMT: no minidriver op");
-			res = -EINVAL;
-			goto try_fmt_done;
-		}
-
-		res = usbcam_minidrv_op(udp, try_format, &f->fmt.pix);
-		usbcam_dbg_v4l2_pix_format_res(udp, res, &f->fmt.pix,
-					       "VIDIOC_TRY_FMT: res:");
-
-	try_fmt_done:
-		usbcam_unlock(udp);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-
-	/* DEFAULT CONTROL HANDLING - USE MINIDRIVER ARRAY / CALLOUTS */
-	case VIDIOC_QUERYCTRL: {
-		struct v4l2_queryctrl *a = (struct v4l2_queryctrl *) arg;
-		const struct usbcam_ctrl *ctrlp, *resp;
-		unsigned int targ, highest_id = 0;
-		int i, res;
-
-		usbcam_lock(udp);
-		droplock = 1;
-		targ = a->id;
-
-		resp = NULL;
-
-		if (targ & V4L2_CTRL_FLAG_NEXT_CTRL) {
-			/*
-			 * Find the control with the least ID greater than or
-			 * equal to a->id
-			 */
-			targ &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
-			for (i = 0, ctrlp = udp->ud_ctrl_array;
-			     i < udp->ud_ctrl_array_len;
-			     i++, ctrlp = (struct usbcam_ctrl *)
-				     (((u8 *) ctrlp) +
-				      udp->ud_ctrl_array_elem_size)) {
-				if (ctrlp->ctrl.id <= targ) {
-					if (!resp ||
-					    (ctrlp->ctrl.id < resp->ctrl.id))
-						resp = ctrlp;
-				}
-			}
-
-		} else {
-			/* Find an exact match */
-			for (i = 0, ctrlp = udp->ud_ctrl_array;
-			     i < udp->ud_ctrl_array_len;
-			     i++, ctrlp = (struct usbcam_ctrl *)
-				     (((u8 *) ctrlp) +
-				      udp->ud_ctrl_array_elem_size)) {
-				if (ctrlp->ctrl.id == targ) {
-					resp = ctrlp;
-					break;
-				}
-				else if ((ctrlp->ctrl.id >=
-					  V4L2_CID_PRIVATE_BASE) &&
-					 (ctrlp->ctrl.id <
-					  (V4L2_CID_PRIVATE_BASE + 1024)) &&
-					 (ctrlp->ctrl.id > highest_id)) {
-					highest_id = ctrlp->ctrl.id;
-				}
-			}
-		}
-
-		if (!resp && !highest_id)
-			res = -EINVAL;
-
-		else if (!resp) {
-			/*
-			 * Deal with the private control enumeration
-			 * nonsense that the CTRL_FLAG_NEXT_CTRL thing
-			 * fixes.
-			 */
-			memset(a, 0, sizeof(*a));
-			a->id = targ;
-			a->type = V4L2_CTRL_TYPE_INTEGER;
-			strlcpy(a->name, "Disabled", sizeof(a->name));
-			a->flags = V4L2_CTRL_FLAG_DISABLED;
-			res = 0;
-
-		} else {
-			*a = resp->ctrl;
-			res = 0;
-
-			/*
-			 * If a query function was provided, call it to
-			 * postprocess the response structure, e.g. to set
-			 * flags.
-			 */
-			if (resp->query_fn) {
-				if (udp->ud_minidrv->um_ops->unlocked_ctrl) {
-					usbcam_unlock(udp);
-					droplock = 0;
-				}
-				res = resp->query_fn(udp, resp, a);
-			}
-		}
-
-		if (droplock)
-			usbcam_unlock(udp);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-	
-	case VIDIOC_G_CTRL: {
-		struct v4l2_control *a = (struct v4l2_control *) arg;
-		const struct usbcam_ctrl *ctrlp, *resp;
-		int i, res;
-
-		usbcam_lock(udp);
-		droplock = 1;
-
-		if (udp->ud_disconnected) {
-			usbcam_unlock(udp);
-			return -EIO;
-		}
-
-		resp = NULL;
-		for (i = 0, ctrlp = udp->ud_ctrl_array;
-		     i < udp->ud_ctrl_array_len;
-		     i++, ctrlp = (struct usbcam_ctrl *)
-			     (((u8 *) ctrlp) +
-			      udp->ud_ctrl_array_elem_size)) {
-			if (ctrlp->ctrl.id == a->id) {
-				resp = ctrlp;
-				break;
-			}
-		}
-
-		if (!resp || (resp->ctrl.type == V4L2_CTRL_TYPE_BUTTON))
-			res = -EINVAL;
-		else {
-			if (udp->ud_minidrv->um_ops->unlocked_ctrl) {
-				usbcam_unlock(udp);
-				droplock = 0;
-			}
-			res = resp->get_fn(udp, resp, a);
-		}
-
-		if (droplock)
-			usbcam_unlock(udp);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-
-	case VIDIOC_S_CTRL: {
-		struct v4l2_control *a = (struct v4l2_control *) arg;
-		const struct usbcam_ctrl *ctrlp, *resp;
-		int i, res;
-
-		usbcam_lock(udp);
-		droplock = 1;
-
-		if (udp->ud_disconnected) {
-			usbcam_unlock(udp);
-			return -EIO;
-		}
-
-		resp = NULL;
-		for (i = 0, ctrlp = udp->ud_ctrl_array;
-		     i < udp->ud_ctrl_array_len;
-		     i++, ctrlp = (struct usbcam_ctrl *)
-			     (((u8 *) ctrlp) +
-			      udp->ud_ctrl_array_elem_size)) {
-			if (ctrlp->ctrl.id == a->id) {
-				resp = ctrlp;
-				break;
-			}
-		}
-
-		if (!resp) {
-			res = -EINVAL;
-		} else if (!resp->set_fn) {
-			/* Read-only control */
-			res = -EBUSY;
-		} else if ((resp->ctrl.type != V4L2_CTRL_TYPE_BUTTON) &&
-			   ((a->value < resp->ctrl.minimum) ||
-			    (a->value > resp->ctrl.maximum))) {
-			res = -ERANGE;
-		} else {
-			if (udp->ud_minidrv->um_ops->unlocked_ctrl) {
-				usbcam_unlock(udp);
-				droplock = 0;
-			}
-			res = resp->set_fn(udp, resp, a);
-		}
-
-		if (droplock)
-			usbcam_unlock(udp);
-		usbcam_work_maybe_stop(udp);
-		return res;
-	}
-
-	case VIDIOC_QUERYMENU: {
-		struct v4l2_querymenu *a = (struct v4l2_querymenu *) arg;
-		const struct usbcam_ctrl *ctrlp, *resp;
-		int i, res;
-
-		usbcam_lock(udp);
-
-		resp = NULL;
-		for (i = 0, ctrlp = udp->ud_ctrl_array;
-		     i < udp->ud_ctrl_array_len;
-		     i++, ctrlp = (struct usbcam_ctrl *)
-			     (((u8 *) ctrlp) +
-			      udp->ud_ctrl_array_elem_size)) {
-			if (ctrlp->ctrl.id == a->id) {
-				resp = ctrlp;
-				break;
-			}
-		}
-
-		if (!resp ||
-		    (resp->ctrl.type != V4L2_CTRL_TYPE_MENU) ||
-		    (a->index > resp->ctrl.maximum)) {
-			res = -EINVAL;
-			goto querymenu_done;
-		}
-
-		strlcpy(a->name, resp->menu_names[a->index], sizeof(a->name));
-		res = 0;
-
-	querymenu_done:
-		usbcam_unlock(udp);
-		return res;
-	}
-
-	/* DEFAULT INPUT HANDLING -- There is one input called "Camera" */
-	case VIDIOC_ENUMINPUT: {
-		const struct v4l2_input dfl_input = {
-			.name = "Camera",
-			.type = V4L2_INPUT_TYPE_CAMERA,
-		};
-		struct v4l2_input *inp = (struct v4l2_input *) arg;
-
-		if (inp->index > 0)
-			return -EINVAL;
-		*inp = dfl_input;
-		return 0;
-	}
-	
-	case VIDIOCGCHAN: {
-		const struct video_channel dfl_input = {
-			.name = "Camera",
-			.type = VIDEO_TYPE_CAMERA
-		};
-		struct video_channel *inp = (struct video_channel *) arg;
-		
-		if (inp->channel > 0)
-			return -EINVAL;
-		*inp = dfl_input;
-		return 0;
-	}
-
-	case VIDIOC_G_INPUT: {
-		unsigned int *i = (unsigned int *) arg;
-		*i = 0;
-		return 0;
-	}
-
-	case VIDIOC_S_INPUT: {
-		unsigned int *i = (unsigned int *) arg;
-		if (*i != 0)
-			return -EINVAL;
-		return 0;
-	}
-
-	/* DEFAULT VIDEO STANDARD HANDLING */
-	case VIDIOC_ENUMSTD: {
-		struct v4l2_standard *s = (struct v4l2_standard *) arg;
-		if (s->index > 0)
-			return -EINVAL;
-		v4l2_video_std_construct(s, V4L2_STD_NTSC_M, "NTSC-M");
-		return 0;
-	}
-
-	case VIDIOC_G_STD: {
-		v4l2_std_id *std = (v4l2_std_id *) arg;
-		*std = V4L2_STD_NTSC_M;
-		return 0;
-	}
-
-	case VIDIOC_S_STD:
-		return 0;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-	/* Workaround for v4l1_compat bug in older kernels */
-	case VIDIOC_G_FBUF: {
-		struct v4l2_framebuffer *f = (struct v4l2_framebuffer *) arg;
-		memset(f, 0, sizeof(*f));
-		return -ENOIOCTLCMD;
-	}
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */
-	}
-
-	/* video_usercopy() will convert this to -EINVAL. */
-	return -ENOIOCTLCMD;
-}
-
-static int usbcam_v4l_ioctl(struct inode *inodep, struct file *filp,
-			    unsigned int cmd, unsigned long arg)
-{
-	return video_usercopy(inodep, filp, cmd, arg, usbcam_v4l_int_ioctl);
-}
-	
-
-/*
- * The template file_operations structure
- *
- * Each usbcam_minidrv_t contains its own copy of this, which
- * is associated with the video4linux device created for that
- * minidriver.
- *
- * In general, copies will differ only in the .owner field, which
- * will refer to the minidriver module, not usbcam.
- */
-
-static struct file_operations usbcam_v4l_fops_template = {
-	.owner		= THIS_MODULE,
-	.open		= usbcam_v4l_open,
-	.release	= usbcam_v4l_release,
-	.read		= usbcam_v4l_read,
-	.poll		= usbcam_v4l_poll,
-	.mmap		= usbcam_v4l_mmap,
-	.ioctl		= usbcam_v4l_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl	= v4l_compat_ioctl32,
-#endif
-	.llseek		= no_llseek,
-};
-
-
-/*
- * V4L2 videodev callout implementations
- */
-
-static void usbcam_videodev_release(struct video_device *vfd)
-{
-	struct usbcam_dev *udp = container_of(vfd, struct usbcam_dev, ud_vdev);
-
-	usbcam_warn(udp, "releasing videodev device.");
-
-	usbcam_lock(udp);
-
-	assert(!udp->ud_videodev_released);
-	udp->ud_videodev_released = 1;
-
-	usbcam_unlock(udp);
-	usbcam_put(udp);
-}
-
-static struct video_device usbcam_videodev_template = {
-	.name			= "usbcam-unknown",
-	.type			= VFL_TYPE_GRABBER,
-	.type2			= VID_TYPE_CAPTURE,
-	.minor			= -1,
-	.release		= usbcam_videodev_release,
-};
-
-
-/*
- * USB subsystem operation implementations
- */
-
-static int usbcam_check_ctrl_array(struct usbcam_dev *udp,
-				   const struct usbcam_ctrl *ctrlp,
-				   int elem_size, int count)
-{	
-	const struct usbcam_ctrl *startp = ctrlp, *xctrlp;
-	int i, j;
-	int errors = 0;
-
-	for (i = 0; i < count;
-	     i++, ctrlp = (struct usbcam_ctrl *)
-		     (((u8 *) ctrlp) + elem_size)) {
-		/* Verify that the ID isn't already registered */
-		for (j = 0, xctrlp = startp;
-		     j < i;
-		     j++, xctrlp = (struct usbcam_ctrl *)
-			     (((u8 *) xctrlp) + elem_size)) {
-			if (ctrlp->ctrl.id == xctrlp->ctrl.id) {
-				usbcam_warn(udp, "control %d is registered "
-					    "more than once",
-					    ctrlp->ctrl.id);
-				errors++;
-				break;
-			}
-		}
-
-		/* Check minimum, maximum, step, and default */
-		switch (ctrlp->ctrl.type) {
-		case V4L2_CTRL_TYPE_INTEGER:
-			if (ctrlp->ctrl.minimum > ctrlp->ctrl.maximum) {
-				usbcam_warn(udp, "control %d has "
-					    "minimum > maximum",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			break;
-				
-		case V4L2_CTRL_TYPE_BOOLEAN:
-			if (ctrlp->ctrl.minimum) {
-				usbcam_warn(udp, "control %d is BOOLEAN "
-					    "and has minimum != 0",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (ctrlp->ctrl.maximum != 1) {
-				usbcam_warn(udp, "control %d is BOOLEAN "
-					    "and has maximum != 1",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (ctrlp->ctrl.step != 1) {
-				usbcam_warn(udp, "control %d is BOOLEAN "
-					    "and has step != 1",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			break;
-
-		case V4L2_CTRL_TYPE_MENU:
-			if (ctrlp->ctrl.minimum) {
-				usbcam_warn(udp, "control %d is MENU and has "
-					    "minimum != 0",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (!ctrlp->ctrl.maximum) {
-				usbcam_warn(udp, "control %d is MENU and has "
-					    "maximum == 0",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (ctrlp->ctrl.step != 1) {
-				usbcam_warn(udp, "control %d is MENU and has "
-					    "step != 1",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (!ctrlp->menu_names) {
-				usbcam_warn(udp, "control %d is MENU and has "
-					    "NULL menu_names",
-					    ctrlp->ctrl.id);
-				errors++;
-				break;
-			}
-			break;
-
-		case V4L2_CTRL_TYPE_BUTTON:
-			if (ctrlp->ctrl.minimum) {
-				usbcam_warn(udp, "control %d is BUTTON "
-					    "and has minimum != 0",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (ctrlp->ctrl.maximum) {
-				usbcam_warn(udp, "control %d is BUTTON "
-					    "and has maximum != 0",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			if (ctrlp->ctrl.step) {
-				usbcam_warn(udp, "control %d is BUTTON "
-					    "and has step != 0",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-			break;
-
-		default:
-			usbcam_warn(udp, "control %d is of invalid type %d",
-				    ctrlp->ctrl.id, ctrlp->ctrl.type);
-			errors++;
-			continue;
-		}
-
-		/* Check the range */
-		if ((ctrlp->ctrl.default_value < ctrlp->ctrl.minimum) ||
-		    (ctrlp->ctrl.default_value > ctrlp->ctrl.maximum)) {
-			usbcam_warn(udp, "control %d default out of range",
-				    ctrlp->ctrl.id);
-			errors++;
-		}
-
-		/* Check the get_fn callout */
-		if (ctrlp->ctrl.type == V4L2_CTRL_TYPE_BUTTON) {
-			if (ctrlp->get_fn) {
-				usbcam_warn(udp, "control %d is BUTTON "
-					    "and has a get_fn callout",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-		} else {
-			if (!ctrlp->get_fn) {
-				usbcam_warn(udp, "control %d has no "
-					    "get_fn callout",
-					    ctrlp->ctrl.id);
-				errors++;
-			}
-		}
-
-		if ((ctrlp->ctrl.type == V4L2_CTRL_TYPE_BUTTON) &&
-		    !ctrlp->set_fn) {
-			usbcam_warn(udp, "control %d has no set_fn callout",
-				    ctrlp->ctrl.id);
-			errors++;
-		}
-	}
-
-	return errors;
-}
-
-struct usbcam_claimed_interface {
-	struct list_head	uc_links;
-	struct usb_interface	*uc_intf;
-};
-
-static int usbcam_usb_probe(struct usb_interface *intf,
-			    const struct usb_device_id *devid)
-{
-	struct usb_driver *drvp;
-	struct usbcam_dev *udp = NULL, *udpx;
-	usbcam_minidrv_t *minidrv;
-	struct usb_device *dev;
-	struct list_head *listp;
-	struct usbcam_claimed_interface *cip;
-	int minidrv_init_failed = 0;
-	int res, i;
-
-	/* Locate the mini-driver */
-	dev = interface_to_usbdev(intf);
-	drvp = to_usb_driver(intf->dev.driver);
-	minidrv = container_of(drvp, usbcam_minidrv_t, um_usbdrv);
-
-	/* Allocate and initialize a device structure */
-	udp = (struct usbcam_dev *) kzalloc(sizeof(*udp) +
-					    minidrv->um_dev_privsize,
-					    GFP_KERNEL);
-	if (!udp)
-		return -ENOMEM;
-
-	mutex_init(&udp->ud_open_lock);
-	mutex_init(&udp->ud_lock);
-	spin_lock_init(&udp->ud_work_lock);
-	INIT_LIST_HEAD(&udp->ud_work_queue);
-	udp->ud_minidrv = minidrv;
-	udp->ud_dev = usb_get_dev(dev);
-	udp->ud_intf = usb_get_intf(intf);
-	udp->ud_debug = minidrv->um_debug;
-	INIT_LIST_HEAD(&udp->ud_drv_links);
-	kref_init(&udp->ud_kref);
-
-	INIT_LIST_HEAD(&udp->ud_interface_list);
-	INIT_LIST_HEAD(&udp->ud_frame_cap_queue);
-
-	if (minidrv->um_dev_privsize) {
-		udp->ud_minidrv_data = &udp[1];
-	}
-
-	/* Set up the video4linux structure */
-	udp->ud_vdev = minidrv->um_videodev_template;
-
-	/* Add the device to the minidriver's list of active devices */
-	usbcam_lock(udp);
-
-	mutex_lock(&minidrv->um_lock);
-
-	/* Inefficiently find an unused ID in the device list */
-	i = 0;
-	udpx = NULL;
-	list_for_each(listp, &minidrv->um_dev_list) {
-		udpx = list_entry(listp, struct usbcam_dev, ud_drv_links);
-		if (udpx->ud_minidrv_id < 0) {
-			udpx = NULL;
-			continue;
-		}
-		if (udpx->ud_minidrv_id != i)
-			break;
-		udpx = NULL;
-		i++;
-	}
-
-	udp->ud_minidrv_id = i;
-	if (udpx) {
-		list_add_tail(&udp->ud_drv_links, &udpx->ud_drv_links);
-	} else {
-		list_add_tail(&udp->ud_drv_links, &minidrv->um_dev_list);
-	}
-
-	minidrv->um_dev_count++;
-	kref_get(&minidrv->um_kref);
-
-	snprintf(udp->ud_dev_name, sizeof(udp->ud_dev_name),
-		 "%s-%d", usbcam_drvname(udp->ud_minidrv),
-		 udp->ud_minidrv_id);
-
-	snprintf(udp->ud_vdev.name, sizeof(udp->ud_vdev.name),
-		 "%s USB Camera #%d",
-		 usbcam_drvname(minidrv), udp->ud_minidrv_id + 1);
-
-
-	mutex_unlock(&minidrv->um_lock);
-	
-	/* Invoke the minidriver initialization callout */
-	udp->ud_initializing = 1;
-	res = usbcam_minidrv_op(udp, init, devid);
-	udp->ud_initializing = 0;
-	if (res) {
-		usbcam_dbg(udp, DEV_STATE, "minidriver init failed: %d", res);
-		minidrv_init_failed = 1;
-		goto out_nodisconn;
-	}
-
-	/* Complain if the device isn't filled out correctly */
-	if (!udp->ud_format.width || !udp->ud_format.height) {
-		usbcam_warn(udp, "minidriver did not set default size");
-		res = -EINVAL;
-		goto out;
-	}
-	if (!udp->ud_format.pixelformat) {
-		usbcam_warn(udp, "minidriver did not set default pixelformat");
-		res = -EINVAL;
-		goto out;
-	}
-
-	/* Check the control array */
-	if (udp->ud_ctrl_array_len &&
-	    usbcam_check_ctrl_array(udp,
-				    udp->ud_ctrl_array,
-				    udp->ud_ctrl_array_elem_size,
-				    udp->ud_ctrl_array_len)) {
-		usbcam_warn(udp, "minidriver supplied ctrl_array with errors");
-		res = -EINVAL;
-		goto out;
-	}
-
-	usb_set_intfdata(intf, udp);
-	usbcam_unlock(udp);
-
-	/*
-	 * Register the device with video4linux
-	 *
-	 * BUG: video_register_device() may or may not call back
-	 * into usbcam_videodev_release(), depending on how it fails,
-	 * and if it does call back, its callback may be latent.
-	 *
-	 * We will assume no callback on failure.
-	 */
-
-	if (udp->ud_vdev.minor != -1) {
-		/* Minidriver has indicated its preference for a minor */
-		res = video_register_device(&udp->ud_vdev, VFL_TYPE_GRABBER,
-					    -1);
-		if (!res)
-			goto video_registered;
-	}
-
-	for (i = 0; i < minidrv->um_video_nr_array_len; i++) {
-		res = video_register_device(&udp->ud_vdev, VFL_TYPE_GRABBER,
-					    minidrv->um_video_nr_array[i]);
-		if (!res)
-			goto video_registered;
-	}
-
-	res = video_register_device(&udp->ud_vdev, VFL_TYPE_GRABBER, -1);
-	if (res) {
-		usbcam_err(udp, "%s: video_register_device failed",
-			   __FUNCTION__);
-		usbcam_lock(udp);
-		assert(!udp->ud_videodev_released);
-		udp->ud_videodev_released = 1;
-		goto out;
-	}
-
-video_registered:
-	usbcam_get(udp);
-	/*
-	 * There should now be at least two references on udp:
-	 * One for the primary USB interface in the non-disconnected state
-	 * One for the videodev stuff
-	 * One for each additional claimed interface
-	 */
-
-	usbcam_dbg(udp, DEV_STATE, "registered as video%d",
-		   udp->ud_vdev.minor);
-
-	usbcam_work_maybe_stop(udp);
-	return 0;
-
-out:
-	assert(!udp->ud_disconnected);
-	udp->ud_disconnected = 1;
-	if (usbcam_minidrv_op_present(udp, disconnect))
-		usbcam_minidrv_op(udp, disconnect);
-
-out_nodisconn:
-	while (!list_empty(&udp->ud_interface_list)) {
-		cip = list_entry(udp->ud_interface_list.next,
-				 struct usbcam_claimed_interface,
-				 uc_links);
-		list_del_init(&cip->uc_links);
-		usb_set_intfdata(cip->uc_intf, NULL);
-		usb_driver_release_interface(&minidrv->um_usbdrv,
-					     cip->uc_intf);
-		usb_put_intf(cip->uc_intf);
-		kfree(cip);
-		usbcam_put(udp);
-	}
-
-	usbcam_unlock(udp);
-
-	if (minidrv_init_failed)
-		kref_put(&udp->ud_kref, usbcam_dev_free);
-	else
-		usbcam_put(udp);
-	return res;
-}
-
-static void usbcam_usb_disconnect(struct usb_interface *intf)
-{
-	struct usbcam_dev *udp = (struct usbcam_dev *) usb_get_intfdata(intf);
-	struct usbcam_claimed_interface *iterp, *cip;
-	int put_intf = 0;
-	int put_udp = 0;
-
-	if (!udp)
-		return;
-
-	usbcam_lock(udp);
-	if (!udp->ud_disconnected) {
-		udp->ud_disconnected = 1;
-		usbcam_unlock(udp);
-
-		usbcam_dbg(udp, DEV_STATE, "disconnected");
-		video_unregister_device(&udp->ud_vdev);
-
-		usbcam_dbg(udp, DEV_STATE, "unregistered from video%d",
-			   udp->ud_vdev.minor);
-
-		usbcam_lock(udp);
-		if (usbcam_minidrv_op_present(udp, disconnect))
-			usbcam_minidrv_op(udp, disconnect);
-
-		usbcam_capture_stop(udp);
-	}
-
-	if (intf == udp->ud_intf) {
-		assert(!udp->ud_disconnected_primary);
-		udp->ud_disconnected_primary = 1;
-		put_udp = 1;
-
-	} else {
-		cip = NULL;
-		list_for_each_entry(iterp, &udp->ud_interface_list, uc_links) {
-			if (iterp->uc_intf == intf) {
-				cip = iterp;
-				break;
-			}
-		}
-
-		if (cip) {
-			list_del_init(&cip->uc_links);
-			kfree(cip);
-			put_intf = 1;
-			put_udp = 1;
-		} else {
-			usbcam_err(udp, "interface %p is not claimed", intf);
-		}
-	}
-
-	usb_set_intfdata(intf, NULL);
-	usbcam_unlock(udp);
-
-	usbcam_work_maybe_stop(udp);
-
-	if (put_intf)
-		usb_put_intf(intf);
-	if (put_udp)
-		usbcam_put(udp);
-}
-
-#if defined(CONFIG_PM)
-static int usbcam_usb_suspend(struct usb_interface *intf, pm_message_t msg)
-{
-	struct usbcam_dev *udp = (struct usbcam_dev *) usb_get_intfdata(intf);
-	int relock = 0, res = 0;
-	if (!udp) {
-		printk(KERN_WARNING "%s: no associated device\n",
-		       __FUNCTION__);
-		return 0;
-	}
-
-	usbcam_lock(udp);
-	if ((intf != udp->ud_intf) || udp->ud_suspended) {
-		/* Do nothing */
-	} else if (usbcam_minidrv_op_present(udp, suspend)) {
-		usbcam_dbg(udp, DEV_STATE, "invoking minidriver suspend");
-		udp->ud_suspended = 1;
-		if (udp->ud_minidrv->um_ops->unlocked_pm) {
-			usbcam_unlock(udp);
-			relock = 1;
-		}
-
-		res = usbcam_minidrv_op(udp, suspend, msg);
-
-		if (relock)
-			usbcam_lock(udp);
-		if (res)
-			udp->ud_suspended = 0;
-	} else {
-		usbcam_dbg(udp, DEV_STATE, "no minidriver suspend method");
-		udp->ud_suspended = 1;
-	}
-
-	usbcam_unlock(udp);
-	usbcam_work_maybe_stop(udp);
-	return res;
-}
-
-static int usbcam_usb_resume(struct usb_interface *intf)
-{
-	struct usbcam_dev *udp = (struct usbcam_dev *) usb_get_intfdata(intf);
-	int relock = 0, res = 0;
-	if (!udp) {
-		printk(KERN_WARNING "%s: no associated device\n",
-		       __FUNCTION__);
-		return 0;
-	}
-
-	usbcam_lock(udp);
-	if ((intf != udp->ud_intf) || !udp->ud_suspended) {
-		/* Nothing to do! */
-	} else if (usbcam_minidrv_op_present(udp, resume)) {
-		usbcam_dbg(udp, DEV_STATE, "invoking minidriver resume");
-		if (udp->ud_minidrv->um_ops->unlocked_pm) {
-			usbcam_unlock(udp);
-			relock = 1;
-		}
-		res = usbcam_minidrv_op(udp, resume);
-		if (relock)
-			usbcam_lock(udp);
-	} else
-		usbcam_dbg(udp, DEV_STATE, "no minidriver resume method");
-
-	if (!res)
-		udp->ud_suspended = 0;
-
-	usbcam_unlock(udp);
-	usbcam_work_maybe_stop(udp);
-	return res;
-}
-#endif  /* defined(CONFIG_PM) */
-
-
-static const struct usb_driver usbcam_usb_driver_template = {
-	.name		= "usbcam minidriver",
-	.probe		= usbcam_usb_probe,
-	.disconnect	= usbcam_usb_disconnect,
-#if defined(CONFIG_PM)
-	.suspend	= usbcam_usb_suspend,
-	.resume		= usbcam_usb_resume,
-#endif
-};
-
-
-/*
- * Minidriver registration/unregistration
- */
-
-int usbcam_register_mod(usbcam_minidrv_t **driverpp,
-			int minidrv_version, const char *minidrv_verx,
-			const struct usbcam_dev_ops *ops,
-			const int dev_priv_size,
-			const struct usb_device_id *id_table,
-			const int *video_nrs, int video_nrs_len,
-			int *debug, struct module *md, const char *modname)
-{
-	usbcam_minidrv_t *minidrv;
-	int res;
-
-	printk(KERN_INFO "usbcam: registering driver %s %d.%d.%d%s\n",
-	       modname,
-	       (minidrv_version >> 16) & 0xff,
-	       (minidrv_version >> 8) & 0xff,
-	       minidrv_version & 0xff,
-	       minidrv_verx ? minidrv_verx : "");
-
-	minidrv = (usbcam_minidrv_t *) kzalloc(sizeof(*minidrv), GFP_KERNEL);
-	if (!minidrv) {
-		err("%s: Failed to allocate usbcam_minidrv_t", __FUNCTION__);
-		return -ENOMEM;
-	}
-
-	kref_init(&minidrv->um_kref);
-	minidrv->um_owner = md;
-	minidrv->um_modname = modname;
-	minidrv->um_version = minidrv_version;
-	minidrv->um_debug = debug;
-	minidrv->um_dev_privsize = dev_priv_size;
-	INIT_LIST_HEAD(&minidrv->um_dev_list);
-	mutex_init(&minidrv->um_lock);
-	minidrv->um_video_nr_array = video_nrs;
-	minidrv->um_video_nr_array_len = video_nrs_len;
-
-	minidrv->um_ops = ops;
-
-	minidrv->um_usbdrv = usbcam_usb_driver_template;
-	minidrv->um_usbdrv.name = usbcam_drvname(minidrv);
-	minidrv->um_usbdrv.id_table = id_table;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
-	minidrv->um_usbdrv.supports_autosuspend =
-		minidrv->um_ops->supports_autosuspend;
-#endif
-
-	/*
-	 * We have a separate fops per minidriver structure so that
-	 * module reference counting works without egregious hacks.
-	 */
-	minidrv->um_v4l_fops = usbcam_v4l_fops_template;
-	minidrv->um_v4l_fops.owner = minidrv->um_owner;
-
-	minidrv->um_videodev_template = usbcam_videodev_template;
-	minidrv->um_videodev_template.fops = &minidrv->um_v4l_fops;
-
-	*driverpp = minidrv;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
-	res = usb_register_driver(&minidrv->um_usbdrv, minidrv->um_owner,
-				  minidrv->um_modname);
-#else
-	res = usb_register_driver(&minidrv->um_usbdrv, minidrv->um_owner);
-#endif
-	if (res) {
-		kref_put(&minidrv->um_kref, usbcam_minidrv_release);
-		*driverpp = NULL;
-	}
-
-	usbcam_dbgm(minidrv, DEV_STATE, "registered minidriver");
-
-	return res;
-}
-EXPORT_SYMBOL(usbcam_register_mod);
-
-void usbcam_unregister(usbcam_minidrv_t *minidrv)
-{
-	usbcam_dbgm(minidrv, DEV_STATE, "unregistering minidriver");
-
-	usb_deregister(&minidrv->um_usbdrv);
-
-	if (minidrv->um_dev_count) {
-		err("%s: %d \"%s\" devices remain",
-		    __FUNCTION__, minidrv->um_dev_count,
-		    usbcam_drvname(minidrv));
-	}
-
-	kref_put(&minidrv->um_kref, usbcam_minidrv_release);
-}
-EXPORT_SYMBOL(usbcam_unregister);
-
-
-int usbcam_claim_interface(struct usbcam_dev *udp, int ifnum)
-{
-	struct usb_interface *intf;
-	struct usbcam_claimed_interface *cip;
-	int res;
-
-	usbcam_chklock(udp);
-
-	if (!udp->ud_initializing) {
-		usbcam_warn(udp, "%s may only be called from minidriver init",
-			    __FUNCTION__);
-		return -EINVAL;
-	}
-
-	intf = usb_ifnum_to_if(udp->ud_dev, ifnum);
-	if (!intf) {
-		usbcam_warn(udp, "%s: interface %d does not exist",
-			    __FUNCTION__, ifnum);
-		return -ENODEV;
-	}
-
-	res = usb_driver_claim_interface(&udp->ud_minidrv->um_usbdrv,
-					 intf, NULL);
-
-	if (!res) {
-		cip = kmalloc(sizeof(*cip), GFP_KERNEL);
-		if (!cip) {
-			usb_driver_release_interface(&udp->ud_minidrv->
-						     um_usbdrv, intf);
-			return -ENOMEM;
-		}
-
-		INIT_LIST_HEAD(&cip->uc_links);
-		cip->uc_intf = usb_get_intf(intf);
-		usb_set_intfdata(intf, udp);
-		usbcam_get(udp);
-		list_add_tail(&cip->uc_links, &udp->ud_interface_list);
-	}
-
-	return res;
-}
-EXPORT_SYMBOL(usbcam_claim_interface);
-
-
-/*
- * Traverse the alternate setting list and find one that provides
- * the least bandwidth that satisfies the minimum requirement.
- */
-int usbcam_choose_altsetting(struct usbcam_dev *udp, int ifnum,
-			     int pipe, int bytes_per_sec_min,
-			     int pkt_min, int pkt_max,
-			     int *altsetting_nr)
-{
-	struct usb_interface *intf;
-	const struct usb_host_interface *aintf;
-	const struct usb_endpoint_descriptor *epd = NULL;
-	int i, j;
-
-	int wmp, bw;
-	int best_alt = -1, best_alt_bw = 0;
-
-	usbcam_chklock(udp);
-
-	if (udp->ud_disconnected) {
-		usbcam_warn(udp, "%s: device is disconnected", __FUNCTION__);
-		return -ENODEV;
-	}
-
-	if (ifnum < 0)
-		ifnum = udp->ud_intf->cur_altsetting->desc.bInterfaceNumber;
-
-	intf = usb_ifnum_to_if(udp->ud_dev, ifnum);
-	if (!intf) {
-		usbcam_warn(udp, "%s: interface %d does not exist",
-			    __FUNCTION__, ifnum);
-		return -ENODEV;
-	}
-
-	if ((bytes_per_sec_min >= 0) &&
-	    !usb_pipeisoc(pipe) && !usb_pipeint(pipe)) {
-		usbcam_warn(udp, "%s: minidriver specified bytes_per_sec_min "
-			    "on non-iso non-int pipe", __FUNCTION__);
-	}
-
-	for (i = 0; i < intf->num_altsetting; i++) {
-
-		aintf = &intf->altsetting[i];
-		for (j = 0; j < aintf->desc.bNumEndpoints; j++) {
-			epd = &aintf->endpoint[j].desc;
-			if ((epd->bEndpointAddress &
-			     USB_ENDPOINT_NUMBER_MASK) ==
-			    usb_pipeendpoint(pipe))
-				break;
-		}
-
-		if (j == aintf->desc.bNumEndpoints) {
-			/* No endpoint 6 in this descriptor, huh?? */
-			usbcam_dbg(udp, ALTSETTING,
-				   "altsetting %d has no EP%d",
-				   i, usb_pipeendpoint(pipe));
-			continue;
-		}
-
-		if (((usb_pipetype(pipe) == PIPE_ISOCHRONOUS) &&
-		     !usb_endpoint_xfer_isoc(epd)) ||
-		    ((usb_pipetype(pipe) == PIPE_INTERRUPT) &&
-		     !usb_endpoint_xfer_int(epd)) ||
-		    (usb_pipein(pipe) && !usb_endpoint_dir_in(epd)) ||
-		    (!usb_pipein(pipe) && usb_endpoint_dir_in(epd))) {
-			/* Something is horribly wrong */
-			usbcam_dbg(udp, ALTSETTING,
-				   "altsetting %d has unexpected EP%d",
-				   i, usb_pipeendpoint(pipe));
-			continue;
-		}
-
-		bw = 0;
-		wmp = le16_to_cpu(epd->wMaxPacketSize);
-
-		/* Bandwidth only applies to iso & int pipes */
-		if (usb_pipeisoc(pipe) || usb_pipeint(pipe)) {
-			if (udp->ud_dev->speed == USB_SPEED_HIGH) {
-				/* 8 uframes per regular frame */
-				bw = 8000;
-
-				/* high bandwidth endpoint? */
-				wmp = ((wmp & 0x7ff) *
-				       (((wmp >> 11) & 0x3) + 1));
-			} else {
-				bw = 1000;
-				wmp &= 0x7ff;
-			}
-
-			bw *= wmp;
-
-			/* Divide by interval / frame skippage */
-			bw = bw / (1 << (epd->bInterval - 1));
-
-			usbcam_dbg(udp, ALTSETTING,
-				   "altsetting %d provides %d B/s bandwidth",
-				   i, bw);
-
-			/* Check the bandwidth */
-			if (bw < bytes_per_sec_min)
-				continue;
-
-		} else
-			wmp &= 0x7ff;
-
-		/* Check the packet size */
-		if (((pkt_min >= 0) && (wmp < pkt_min)) ||
-		    ((pkt_max >= 0) && (wmp > pkt_max)))
-			continue;
-
-		if ((best_alt < 0) || (bw < best_alt_bw)) {
-			best_alt = i;
-			best_alt_bw = bw;
-		}
-	}
-
-	if (best_alt == -1)
-		return -ENODEV;
-
-	*altsetting_nr = best_alt;
-	return 0;
-}
-EXPORT_SYMBOL(usbcam_choose_altsetting);
-
-
-/*
- * DMA buffer helper routines
- */
-static int usbcam_urb_allocbuf(struct usbcam_dev *udp, struct urb *urbp,
-			       size_t nbytes)
-{
-	urbp->transfer_buffer = usb_buffer_alloc(udp->ud_dev,
-						 nbytes,
-						 GFP_KERNEL,
-						 &urbp->transfer_dma);
-	if (!urbp->transfer_buffer)
-		return -ENOMEM;
-
-	urbp->dev = udp->ud_dev;
-	urbp->transfer_buffer_length = nbytes;
-	urbp->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-	return 0;
-}
-
-static inline void usbcam_urb_freebuf(struct urb *urbp)
-{
-	usb_buffer_free(urbp->dev,
-			urbp->transfer_buffer_length,
-			urbp->transfer_buffer,
-			urbp->transfer_dma);
-}
-
-
-/*
- * Isochronous stream helper functions
- * This depends on the other usbcam stuff, but they don't depend on it,
- * and it should be considered an extension sub-library.
- */
-
-/* Default isostream parameters */
-#define USBCAM_DFL_ISO_URBS		8
-#define USBCAM_DFL_ISO_URB_PKTS		32
-
-/*
- * This structure represents one Isoc request - URB and buffer
- */
-struct usbcam_isobuf {
-	struct list_head		ib_links;
-	struct usbcam_isostream		*ib_isostream;
-	struct urb			*ib_urb;
-	struct task_struct		**ib_worker;
-	struct usbcam_workitem		ib_workitem;
-};
-
-/* isop->iso_lock must be held on entry */
-static void usbcam_isostream_resubmit(struct usbcam_isostream *isop,
-				      struct usbcam_isobuf *ibp)
-{
-	int res;
-
-	list_del(&ibp->ib_links);
-	list_add(&ibp->ib_links, &isop->iso_active_list);
-
-	res = usb_submit_urb(ibp->ib_urb, GFP_ATOMIC);
-	if (res == -EL2NSYNC)
-		res = usb_submit_urb(ibp->ib_urb, GFP_ATOMIC);
-	if (res) {
- 		usbcam_dbg(isop->iso_dev, ISOSTREAM,
-			   "iso resubmit %p failed: %d", ibp, res);
-		isop->iso_resubmit_err = res;
-
-		list_del(&ibp->ib_links);
-		list_add(&ibp->ib_links, &isop->iso_unused_list);
-
-		(void) usbcam_work_queue(isop->iso_dev,
-					 &isop->iso_error_workitem);
-	}
-}
-
-static void usbcam_isostream_urb_process(struct usbcam_workitem *work)
-{
-	struct usbcam_isobuf *ibp = container_of(work, struct usbcam_isobuf,
-						 ib_workitem);
-	struct usbcam_isostream *isop = ibp->ib_isostream;
-	struct task_struct *me = current;
-	long flags;
-	int i;
-
-	usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso processing %p", ibp);
-
-	assert(!ibp->ib_worker);
-	ibp->ib_worker = &me;
-
-	for (i = 0; i < ibp->ib_urb->number_of_packets; i++) {
-		char *buf = (((char *) ibp->ib_urb->transfer_buffer) +
-			     ibp->ib_urb->iso_frame_desc[i].offset);
-		int len = ibp->ib_urb->iso_frame_desc[i].actual_length;
-		int status = ibp->ib_urb->iso_frame_desc[i].status;
-
-		ibp->ib_urb->iso_frame_desc[i].actual_length = 0;
-		ibp->ib_urb->iso_frame_desc[i].status = 0;
-
-		isop->iso_ops->packet_done(isop->iso_dev,
-					   isop, buf, len, status);
-		if (!me)
-			return;
-	}
-
-	assert(ibp->ib_worker == &me);
-	ibp->ib_worker = NULL;
-
-	spin_lock_irqsave(&isop->iso_lock, flags);
-
-	if (isop->iso_streaming && (isop->iso_resubmit_err == -ENOSPC)) {
-		/* Try to limp along with iso underflows */
-
-		usbcam_isostream_resubmit(isop, ibp);
-
-		if ((isop->iso_active_list.next !=
-		     isop->iso_active_list.prev) &&
-		    (isop->iso_resubmit_err == -ENOSPC))
-			isop->iso_resubmit_err = 0;
-
-	} else {
-		list_del(&ibp->ib_links);
-		list_add(&ibp->ib_links, &isop->iso_unused_list);
-	}
-
-	spin_unlock_irqrestore(&isop->iso_lock, flags);
-}
-
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
-static void usbcam_isostream_urb_complete(struct urb *urb)
-#else
-static void usbcam_isostream_urb_complete(struct urb *urb,
-					  struct pt_regs *unused)
-#endif
-{
-	struct usbcam_isobuf *ibp = (struct usbcam_isobuf *) urb->context;
-	struct usbcam_isostream *isop = ibp->ib_isostream;
-	long flags;
-	int res;
-
-	usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso urb complete: %p", ibp);
-
-	spin_lock_irqsave(&isop->iso_lock, flags);
-
-	if (list_empty(&ibp->ib_links)) {
-		/* We are being singled out for cancelation, do nothing */
-		usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso canceled, ignoring");
-		goto done;
-	}
-
-	else if (!isop->iso_streaming) {
-		/* Quietly and politely move this URB to the unused list */
-		list_del(&ibp->ib_links);
-		list_add(&ibp->ib_links, &isop->iso_unused_list);
-		usbcam_dbg(isop->iso_dev, ISOSTREAM,
-			   "not resubmitting, streaming off");
-		goto done;
-	}
-
-	/* Move to the done queue, submit a new URB, wake */
-	list_del(&ibp->ib_links);
-	list_add_tail(&ibp->ib_links, &isop->iso_complete_list);
-
-	res = usbcam_work_queue(isop->iso_dev, &ibp->ib_workitem);
-	if (res) {
-		assert(res == -EBUSY);
-		list_del(&ibp->ib_links);
-		list_add_tail(&ibp->ib_links, &isop->iso_unused_list);
-		goto done;
-	}
-
-	if (isop->iso_resubmit_err &&
-	    (isop->iso_resubmit_err != -ENOSPC)) {
-		/* Nothing to do here... */
-		usbcam_dbg(isop->iso_dev, ISOSTREAM,
-			   "not resubmitting, pending error");
-		goto done;
-	}
-
-	if (list_empty(&isop->iso_unused_list)) {
-		isop->iso_resubmit_err = -ENOSPC;
-		usbcam_dbg(isop->iso_dev, ISOSTREAM,
-			   "not resubmitting, no URBs available");
-		goto done;
-	}
-
-	ibp = list_entry(isop->iso_unused_list.next,
-			 struct usbcam_isobuf, ib_links);
-
-	usbcam_isostream_resubmit(isop, ibp);
-
-done:
-	spin_unlock_irqrestore(&isop->iso_lock, flags);
-}
-
-static void usbcam_isostream_freebuf(struct usbcam_isobuf *ibp)
-{
-	assert(list_empty(&ibp->ib_links));
-
-	usbcam_urb_freebuf(ibp->ib_urb);
-	usb_free_urb(ibp->ib_urb);
-	kfree(ibp);
-}
-
-static struct usbcam_isobuf *
-usbcam_isostream_allocbuf(struct usbcam_isostream *isop)
-{
-	struct usbcam_isobuf *ibp;
-	size_t nbytes;
-	int i;
-
-	ibp = kzalloc(sizeof(*ibp), GFP_KERNEL);
-	if (!ibp)
-		return NULL;
-
-	INIT_LIST_HEAD(&ibp->ib_links);
-	usbcam_work_init(&ibp->ib_workitem, usbcam_isostream_urb_process);
-	ibp->ib_isostream = isop;
-
-	ibp->ib_urb = usb_alloc_urb(isop->iso_packet_count, GFP_KERNEL);
-	if (!ibp->ib_urb) {
-		kfree(ibp);
-		return NULL;
-	}
-
-	nbytes = (isop->iso_packet_len * isop->iso_packet_count);
-
-	if (usbcam_urb_allocbuf(isop->iso_dev, ibp->ib_urb, nbytes)) {
-		usb_free_urb(ibp->ib_urb);
-		kfree(ibp);
-		return NULL;
-	}
-
-	ibp->ib_urb->context = ibp;
-	ibp->ib_urb->number_of_packets = isop->iso_packet_count;
-
-
-	for (i = 0; i < isop->iso_packet_count; i++) {
-		ibp->ib_urb->iso_frame_desc[i].offset =
-			(i * isop->iso_packet_len);
-		ibp->ib_urb->iso_frame_desc[i].length = isop->iso_packet_len;
-		ibp->ib_urb->iso_frame_desc[i].actual_length = 0;
-		ibp->ib_urb->iso_frame_desc[i].status = 0;
-	}
-
-	return ibp;
-}
-
-static void usbcam_isostream_freebufs(struct list_head *head)
-{
-	struct usbcam_isobuf *ibp;
-	while (!list_empty(head)) {
-		ibp = list_entry(head->next, struct usbcam_isobuf, ib_links);
-		list_del_init(&ibp->ib_links);
-		usbcam_isostream_freebuf(ibp);
-	}
-}
-
-static int usbcam_isostream_allocbufs(struct usbcam_isostream *isop,
-				      struct list_head *head, int count)
-{
-	struct usbcam_isobuf *ibp;
-	struct list_head new_bufs;
-
-	INIT_LIST_HEAD(&new_bufs);
-
-	while (count--) {
-		ibp = usbcam_isostream_allocbuf(isop);
-		if (!ibp) {
-			usbcam_isostream_freebufs(&new_bufs);
-			return -ENOMEM;
-		}
-		list_add_tail(&ibp->ib_links, &new_bufs);
-	}
-
-	list_splice(&new_bufs, head);
-	return 0;
-}
-
-static void usbcam_isostream_error(struct usbcam_workitem *work)
-{
-	struct usbcam_isostream *isop = container_of(work,
-						     struct usbcam_isostream,
-						     iso_error_workitem);
-	unsigned long flags;
-	int sts;
-
-	spin_lock_irqsave(&isop->iso_lock, flags);
-	sts = isop->iso_resubmit_err;
-	isop->iso_resubmit_err = 0;
-	spin_unlock_irqrestore(&isop->iso_lock, flags);
-
-	if (sts && isop->iso_ops && isop->iso_ops->submit_error)
-		isop->iso_ops->submit_error(isop->iso_dev, isop, sts);
-}
-
-int usbcam_isostream_init(struct usbcam_isostream *isop,
-			  struct usbcam_dev *udp,
-			  int ep, struct usbcam_isostream_ops *ops,
-			  int pktcount, int nurbs, int interval, int pktlen)
-{
-	int res;
-
-	if (!interval) {
-		/* FIXME: find the appropriate interval for the endpoint */
-		return -EINVAL;
-	}
-
-	if (!pktlen) {
-		/* Choose a packet length based on the current altsetting */
-		pktlen = usb_maxpacket(udp->ud_dev,
-				       usb_rcvisocpipe(udp->ud_dev, ep), 0);
-		if (!pktlen) {
-			usbcam_dbg(udp, ISOSTREAM,
-				   "current altsetting for ep%d has "
-				   "maxpacket=0", ep);
-			return -EINVAL;
-		}
-		if (udp->ud_dev->speed == USB_SPEED_HIGH)
-			pktlen = (pktlen & 0x7ff) *
-				(((pktlen >> 11) & 0x3) + 1);
-		else
-			pktlen &= 0x7ff;
-
-		usbcam_dbg(udp, ISOSTREAM, "isostream using pktlen %d",
-			   pktlen);
-	}
-
-	if (!pktcount)
-		pktcount = USBCAM_DFL_ISO_URB_PKTS;
-	if (!nurbs)
-		nurbs = USBCAM_DFL_ISO_URBS;
-	if (nurbs < 2) {
-		usbcam_warn(udp, "%s: at least two iso URBs are required",
-			    __FUNCTION__);
-		nurbs = 2;
-	}
-
-	memset(isop, 0, sizeof(*isop));
-	isop->iso_dev = udp;
-	isop->iso_endpoint = ep;
-	isop->iso_packet_len = pktlen;
-	isop->iso_packet_count = pktcount;
-	isop->iso_urb_interval = interval;
-	isop->iso_ops = ops;
-	spin_lock_init(&isop->iso_lock);
-	INIT_LIST_HEAD(&isop->iso_unused_list);
-	INIT_LIST_HEAD(&isop->iso_active_list);
-	INIT_LIST_HEAD(&isop->iso_complete_list);
-	usbcam_work_init(&isop->iso_error_workitem, usbcam_isostream_error);
-
-	res = usbcam_isostream_allocbufs(isop, &isop->iso_unused_list, nurbs);
-	return res;
-}
-EXPORT_SYMBOL(usbcam_isostream_init);
-
-void usbcam_isostream_stop(struct usbcam_isostream *isop)
-{
-	long flags;
-	struct usbcam_isobuf *ibp, *prev;
-	int res;
-
-	usbcam_chklock(isop->iso_dev);
-
-	usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso stream stopping");
-	spin_lock_irqsave(&isop->iso_lock, flags);
-
-	if (isop->iso_streaming) {
-		isop->iso_streaming = 0;
-
-		/* Cancel all in-flight requests */
-		while (!list_empty(&isop->iso_active_list)) {
-			ibp = list_entry(isop->iso_active_list.prev,
-					 struct usbcam_isobuf, ib_links);
-			list_del_init(&ibp->ib_links);
-			spin_unlock_irqrestore(&isop->iso_lock, flags);
-			usb_kill_urb(ibp->ib_urb);
-			spin_lock_irqsave(&isop->iso_lock, flags);
-			list_add(&ibp->ib_links, &isop->iso_unused_list);
-		}
-
-		/* Cancel all done queue work items */
-		list_for_each_entry_safe(ibp, prev,
-					 &isop->iso_complete_list,
-					 ib_links) {
-
-			res = usbcam_work_cancel(isop->iso_dev,
-						 &ibp->ib_workitem);
-
-			if (!ibp->ib_worker)
-				assert(!res);
-			else {
-				assert(res);
-				assert(*ibp->ib_worker == current);
-				*ibp->ib_worker = NULL;
-				ibp->ib_worker = NULL;
-			}
-
-			list_del(&ibp->ib_links);
-			list_add_tail(&ibp->ib_links, &isop->iso_unused_list);
-		}
-
-		/* Cancel the error work item */
-		(void) usbcam_work_cancel(isop->iso_dev,
-					  &isop->iso_error_workitem);
-	}
-
-	/* Clear the resubmission error code */
-	isop->iso_resubmit_err = 0;
-
-	spin_unlock_irqrestore(&isop->iso_lock, flags);
-	usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso stream stopped");
-}
-EXPORT_SYMBOL(usbcam_isostream_stop);
-
-int usbcam_isostream_start(struct usbcam_isostream *isop)
-{
-	long flags;
-	struct usbcam_dev *udp;
-	struct usbcam_isobuf *ibp;
-	int submitted = 0, res;
-
-	udp = isop->iso_dev;
-
-	usbcam_chklock(udp);
-
-	spin_lock_irqsave(&isop->iso_lock, flags);
-	if (isop->iso_streaming) {
-		spin_unlock_irqrestore(&isop->iso_lock, flags);
-		usbcam_warn(udp, "%s: already streaming", __FUNCTION__);
-		return -EEXIST;
-	}
-
-	if (list_empty(&isop->iso_unused_list) ||
-	    (isop->iso_unused_list.next == isop->iso_unused_list.prev)) {
-		spin_unlock_irqrestore(&isop->iso_lock, flags);
-		usbcam_warn(udp, "%s: not enough unused iso URBs",
-			    __FUNCTION__);
-		return -ENOENT;
-	}
-
-	usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso stream starting");
-	isop->iso_streaming = 1;
-
-	/*
-	 * Fill out generic details of each URB.
-	 * The interval and endpoints can be changed after init, but
-	 * the packet size and URB count cannot.
-	 */
-	list_for_each_entry(ibp, &isop->iso_unused_list, ib_links) {
-		ibp->ib_urb->pipe = usb_rcvisocpipe(ibp->ib_urb->dev,
-						    isop->iso_endpoint);
-		ibp->ib_urb->interval = isop->iso_urb_interval;
-		ibp->ib_urb->transfer_flags |= URB_ISO_ASAP;
-		ibp->ib_urb->complete = usbcam_isostream_urb_complete;
-		ibp->ib_urb->start_frame = 0;
-	}
-
-	/*
-	 * Submit two (2) URBs.
-	 */
-	while (1) {
-		assert(!list_empty(&isop->iso_unused_list));
-		ibp = list_entry(isop->iso_unused_list.next,
-				 struct usbcam_isobuf, ib_links);
-
-		list_del(&ibp->ib_links);
-		list_add_tail(&ibp->ib_links, &isop->iso_active_list);
-
-		spin_unlock_irqrestore(&isop->iso_lock, flags);
-
-		usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso submit %p", ibp);
-		res = usb_submit_urb(ibp->ib_urb, GFP_KERNEL);
-		if (res == -EL2NSYNC)
-			res = usb_submit_urb(ibp->ib_urb, GFP_KERNEL);
-
-		if (res) {
-			usbcam_dbg(isop->iso_dev, ISOSTREAM,
-				   "%s: ISO URB submit failed: %d",
-				   __FUNCTION__, res);
-			usbcam_isostream_stop(isop);
-			return res;
-		}
-
-		if (++submitted == 2)
-			break;
-
-		spin_lock_irqsave(&isop->iso_lock, flags);
-	}
-
-	usbcam_dbg(isop->iso_dev, ISOSTREAM, "iso stream started");
-	return 0;
-
-}
-EXPORT_SYMBOL(usbcam_isostream_start);
-
-void usbcam_isostream_cleanup(struct usbcam_isostream *isop)
-{
-	usbcam_isostream_stop(isop);
-	usbcam_isostream_freebufs(&isop->iso_unused_list);
-	assert(list_empty(&isop->iso_active_list));
-	assert(list_empty(&isop->iso_complete_list));
-}
-EXPORT_SYMBOL(usbcam_isostream_cleanup);
-
-
-#ifdef usbcam_hexdump
-#undef usbcam_hexdump
-#endif
-#define dumpable_char(X) (((X) >= ' ') && ((X) <= '~'))
-void usbcam_hexdump(struct usbcam_dev *udp, const u8 *buf, size_t len)
-{
-	const int bpl = 16;
-	const int cend_max = ((bpl * 4) + 1);
-	static const char n2x[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
-				      '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-	char x, outbuf[cend_max + 1];
-	unsigned int cstart, cend, xpos, cpos, offset;
-
-	offset = 0;
-	cstart = (3 * bpl) + 1;
-	cend = cstart + bpl;
-	outbuf[cend] = '\0';
-	goto beginning;
-
-	while (len) {
-		x = *buf++;
-		outbuf[xpos++] = n2x[(x >> 4) & 0xf];
-		outbuf[xpos++] = n2x[x & 0xf];
-		outbuf[cpos+cstart] = dumpable_char(x) ? x : '.';
-		cpos++;
-		xpos++;
-		len--;
-
-		if (!len || (cpos == bpl)) {
-			printk(KERN_DEBUG "%s: %08x %s\n",
-			       udp->ud_dev_name, offset, outbuf);
-			offset += bpl;
-
-		beginning:
-			memset(outbuf, ' ', cend);
-			cpos = 0;
-			xpos = 0;
-		}
-	}
-}
-EXPORT_SYMBOL(usbcam_hexdump);
-
-
-MODULE_DESCRIPTION("Abstraction Library for USB Webcam Drivers");
-MODULE_AUTHOR("Sam Revitch <samr7@cs.washington.edu>, "
-	      "Alexander Hixon <hixon.alexander@mediati.org>");
-MODULE_LICENSE("GPL");
diff --git a/usbcam.h b/usbcam.h
@@ -1,721 +0,0 @@
-/*
- * USBCAM abstraction library for USB webcam drivers
- * Version 0.10.2
- *
- * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * This library is intended to simplify the process of creating drivers
- * for simpler USB webcam devices.  It handles most V4L interactions, and
- * all USB driver entry points.  It provides a minidriver callback API
- * for handling most common tasks.
- */
-
-#ifndef __USBCAM_H__
-#define	__USBCAM_H__
-
-#ifdef __KERNEL__
-
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/version.h>
-
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-#include <media/video-buf.h>
-#else
-#include <media/videobuf-dma-sg.h>
-#endif
-
-
-/* The actual per-minidriver structure is opaque */
-typedef struct usbcam_minidrv usbcam_minidrv_t;
-struct usbcam_dev;
-
-
-/*
- * Log file and debug infrastructure
- */
-#define usbcam_info(UDP, FMT, ARG...) do {				\
-	printk(KERN_INFO "%s: " FMT "\n",				\
-	       (UDP)->ud_dev_name, ## ARG);				\
-} while (0)
-#define usbcam_warn(UDP, FMT, ARG...) do {				\
-	printk(KERN_WARNING "%s: " FMT "\n",				\
-	       (UDP)->ud_dev_name, ## ARG);				\
-} while (0)
-#define usbcam_err(UDP, FMT, ARG...) do {				\
-	printk(KERN_ERR "%s: " FMT "\n",				\
-	       (UDP)->ud_dev_name, ## ARG);				\
-} while (0)
-
-
-#if defined(CONFIG_USBCAM_DEBUG)
-#define usbcam_dbg(UDP, SUBSYS, FMT, ARG...) do {			\
-	if ((UDP)->ud_debug &&						\
-	    (*(UDP)->ud_debug & (1UL << USBCAM_DBG_ ## SUBSYS)))	\
-		printk(KERN_DEBUG "%s: " FMT "\n",			\
-		       (UDP)->ud_dev_name, ## ARG);			\
-} while (0)
-#define usbcam_assert(expr)						\
-do {									\
-	if (!(expr)) {							\
-		printk(KERN_ERR "%s:%d: assertion \"" # expr "\" "	\
-		       "failed", __FILE__, __LINE__);			\
-		dump_stack();						\
-	}								\
-} while (0)
-extern void usbcam_hexdump(struct usbcam_dev *udp, const u8 *buf, size_t len);
-#else
-#define usbcam_dbg(UDP, SUBSYS, FMT, ARG...)
-#define usbcam_assert(expr)
-#define usbcam_hexdump(udp, buf, len)
-#endif
-
-/*
- * Debug subsystem bit values
- *
- * The usbcam_dev.ud_debug debug subsystem mask is a pointer to a
- * per-minidriver integer, which is usually a module parameter and can
- * be manipulated via sysfs.
- */
-enum {
-	USBCAM_DBG_VIDEOBUF = 0,
-	USBCAM_DBG_CAPTURE,
-	USBCAM_DBG_IOCTL_BUF,
-	USBCAM_DBG_IOCTL_FMT,
-	USBCAM_DBG_IOCTL_MISC,
-	USBCAM_DBG_DEV_STATE,
-	USBCAM_DBG_ALTSETTING,
-	USBCAM_DBG_ISOSTREAM,
-
-	/* First bit available to minidrivers */
-	USBCAM_DBGBIT_MD_START = 8,
-};
-
-
-
-/*
- * The usbcam_pix_fmt structure is used to describe a pixel format natively
- * supported by the driver to V4L clients.  A minidriver may set the
- * ud_fmt_array member of usbcam_dev to point to an array of these
- * structures, and the array will be used to service the ENUMFMT ioctl,
- * as long as the minidriver does not intercept that ioctl.
- */
-struct usbcam_pix_fmt {
-	char description[32];
-	unsigned int pixelformat;
-	unsigned int flags;
-};
-
-
-/*
- * The control structure is interpreted by the usbcam ioctl handler to
- * answer QUERYCTRL/G_CTRL/S_CTRL/QUERYMENU requests.  A minidriver may
- * set the ud_ctrl_array field in usbcam_dev to point to an array of
- * usbcam_ctrl structures, or larger structures that have a usbcam_ctrl
- * as their first member.
- *
- * This mode of handling control-related ioctls is only used if the
- * minidriver does not intercept and handle the appropriate ioctl
- * commands in its ioctl callout.
- */
-struct usbcam_ctrl {
-	struct v4l2_queryctrl ctrl;
-
-	const char **menu_names;
-
-	/* Retrieves details about the control dynamically, may be NULL */
-	int (*query_fn)(struct usbcam_dev *, const struct usbcam_ctrl *,
-			struct v4l2_queryctrl *);
-
-	/* Retrieves the current value of the control */
-	int (*get_fn)(struct usbcam_dev *, const struct usbcam_ctrl *,
-		      struct v4l2_control *);
-
-	/* If set_fn is not set, the control is considered read-only. */
-	int (*set_fn)(struct usbcam_dev *, const struct usbcam_ctrl *,
-		      const struct v4l2_control *);
-};
-
-/*
- * usbcam_dev: The per-device structure representing:
- *	(1) A USB device/interface
- *	(2) A registered V4L device
- *
- * Commented fields are of interest to minidrivers.
- * Uncommented fields should be considered opaque.
- */
-
-struct usbcam_dev {
-	/*
-	 * ud_vdev is the video4linux device structure.
-	 * The minidriver may be interested in a few fields:
-	 *	ud_vdev.name: The device name displayed by applications
-	 */
-	struct video_device		ud_vdev;
-
-	/*
-	 * ud_dev, ud_intf: The associated USB device/primary interface
-	 * These members are read-only to all except when set during
-	 * usbcam_dev structure initialization.
-	 */
-	struct usb_device		*ud_dev;
-	struct usb_interface		*ud_intf;
-
-	usbcam_minidrv_t		*ud_minidrv;
-
-	/*
-	 * ud_minidrv_data: Minidriver private data
-	 * During structure initialization, if a minidriver structure
-	 * size was specified to usbcam_register(), that many bytes of
-	 * memory are allocated, the allocation is assigned here, and
-	 * the original allocation is automatically freed with the
-	 * usbcam_dev structure.  Otherwise this member is initialized
-	 * to NULL.
-	 * The minidriver may set whatever policies it wants with how
-	 * this field is managed.
-	 */
-	void				*ud_minidrv_data;
-
-	struct list_head		ud_drv_links;
-
-	/*
-	 * ud_minidrv_id: The device's unique number among all devices
-	 * belonging to the minidriver.  Set prior to the minidriver's
-	 * init handler being called.  Read-only at all other times.
-	 */
-	int				ud_minidrv_id;
-
-	/*
-	 * ud_lock: the mutex protecting most of this structure and all
-	 * minidriver entry points.
-	 */
-	struct mutex			ud_lock;
-
-	/*
-	 * ud_format: Currently configured size/format
-	 *	Protected by ud_lock
-	 *	Modified only by minidriver
-	 *	Examined by ioctl handler and framebuffer allocator
-	 */
-	struct v4l2_pix_format		ud_format;
-
-	/*
-	 * ud_fmt_array, ud_fmt_array_elem_size, ud_fmt_array_len:
-	 * Supported pixel formats for enumeration
-	 *	Protected by ud_lock
-	 *	Modified only by minidriver, usually set by init callout
-	 *	Examined by default ioctl handler for ENUMFMT
-	 */
-	const struct usbcam_pix_fmt	*ud_fmt_array;
-	int				ud_fmt_array_elem_size;
-	int				ud_fmt_array_len;
-
-	/*
-	 * ud_ctrl_array, ud_ctrl_array_elem_size, ud_ctrl_array_len:
-	 * Supported control knobs with get/set callouts
-	 *	Protected by ud_ctrl_lock
-	 *	Modified only by minidriver, usually set by init callout
-	 *	Examined by default ioctl handlers for:
-	 *		QUERYCTRL, G_CTRL, S_CTRL, QUERYMENU
-	 */
-	const struct usbcam_ctrl	*ud_ctrl_array;
-	int				ud_ctrl_array_elem_size;
-	int				ud_ctrl_array_len;
-
-	/*
-	 * ud_capturing: Minidriver capture-in-progress flag
-	 *	Protected by ud_lock
-	 *	Modified only by minidriver, e.g. cap_start, cap_stop
-	 *	Examined by framebuffer interface and S_FMT ioctl handler
-	 */
-	unsigned int			ud_capturing : 1,
-
-	/*
-	 * ud_disconnected: Set if the underlying USB device has been
-	 * disconnected, just prior to invoking the minidriver disconnect
-	 * callout, if one is provided.  This field should be considered
-	 * read-only to minidrivers.
-	 */
-					ud_disconnected : 1,
-
-					ud_initializing : 1,
-					ud_suspended : 1,
-					ud_disconnected_primary : 1,
-					ud_videodev_released : 1;
-
-	struct kref			ud_kref;
-	struct list_head		ud_interface_list;
-
-	struct list_head		ud_frame_cap_queue;
-
-	int				*ud_debug;
-
-	int				ud_work_refs;
-	spinlock_t			ud_work_lock;
-	int				ud_work_lockwait;
-	struct task_struct		*ud_work_thread;
-	struct list_head		ud_work_queue;
-
-	struct mutex			ud_open_lock;
-	int				ud_user_refs;
-	unsigned int			ud_autopm_ref : 1;
-	struct file			*ud_excl_owner;
-
-	/*
-	 * ud_dev_name: Name of device as used for worker thread names and
-	 * debug messages.  The minidriver may set this field in its init
-	 * callout, but should consider it read-only after that point.
-	 */
-	char				ud_dev_name[32];
-};
-
-
-/*
- * Per-device reference counting helpers
- *
- * When the last reference is released, the minidriver's release
- * callout will be invoked.
- *
- * usbcam_get() may be called from any context.
- * usbcam_put() can sleep, and may not be called while holding the device
- * lock (see below).
- */
-#define usbcam_get(UDP) kref_get(&(UDP)->ud_kref)
-extern void usbcam_put(struct usbcam_dev *udp);
-
-
-/*
- * Per-Device locking helpers
- *
- * The minidriver callouts, which are described below in usbcam_dev_ops
- * and usbcam_isostream_ops, are all invoked with the device lock held.
- * Also, all usbcam work queue callouts are invoked with the device lock
- * held.
- *
- * Minidrivers that must be entered through paths other than those
- * described above may need to examine or update data structures
- * protected by the device lock, and may do so using the lock
- * acquire/release macros.  For example, minidrivers that use
- * procfs/sysfs file operations, or completion callouts unsuitable for
- * the usbcam work queue will need this.
- *
- * Minidrivers may release and reacquire the lock inside of certain
- * usbcam minidriver callouts (see 
- */
-#define usbcam_lock(UDP) mutex_lock(&(UDP)->ud_lock)
-#define usbcam_unlock(UDP) mutex_unlock(&(UDP)->ud_lock)
-#define usbcam_chklock(UDP) usbcam_assert(mutex_is_locked(&(UDP)->ud_lock))
-
-
-/*
- * MINIDRIVER CALLOUTS
- *
- * Callouts invoked at various stages of the lifetime of a usbcam_dev
- * device.
- *
- * REQUIRED: init, cap_start, cap_stop.
- *
- * All other callouts are optional.
- *
- * By default, all callouts are invoked with the device lock held.
- *
- * The device lock is not intended to be held for long periods of time.
- * Some operations may run for a long time, and may need to sleep
- * waiting for an operation to complete on the device.  If these
- * operations need to be able to run at the same time as capture, the
- * minidriver must ensure that it does not hold the device lock while
- * waiting for such long operations to complete.
- *
- * To support operating without the device lock, there are flags
- * in the ops structure to selectively disable this behavior for the
- * ioctl callout, control callouts, and power management callouts.
- * The minidriver will be responsible for acquiring and releasing the
- * device lock, and re-verifying the device state upon reacquisition.
- *
- * Certain callouts are explicitly restricted from releasing and
- * reacquiring the device lock.  These include:
- *
- * disconnect, open, close, try_format, set_format, cap_start, cap_stop
- * 
- */
-struct usbcam_dev_ops {
-	int	unlocked_ioctl : 1,
-		unlocked_ctrl : 1,
-		unlocked_pm : 1,
-		supports_autosuspend : 1,
-		no_workref_on_open : 1;
-
-	/* init: invoked when a matching USB device is discovered */
-	int (*init)(struct usbcam_dev *udp, const struct usb_device_id *);
-
-	/* suspend/resume: invoked from power management paths */
-	int (*suspend)(struct usbcam_dev *udp, pm_message_t message);
-	int (*resume)(struct usbcam_dev *udp);
-
-	/* disconnect: invoked when a device has been disconnected */
-	void (*disconnect)(struct usbcam_dev *udp);
-
-	/* release: invoked when a usbcam_dev is about to be freed */
-	void (*release)(struct usbcam_dev *udp);
-
-	/* open: invoked on first user open of the device */
-	int (*open)(struct usbcam_dev *udp);
-
-	/* close: invoked on last user close of the device */
-	void (*close)(struct usbcam_dev *udp);
-
-	/* try_format: invoked to negotiate capture format */
-	int (*try_format)(struct usbcam_dev *udp,
-			  struct v4l2_pix_format *fmt_in_out);
-
-	/* set_format: invoked when the capture format is being set */
-	int (*set_format)(struct usbcam_dev *udp,
-			  struct v4l2_pix_format *fmt_in_out);
-
-	/* ioctl: ioctl call interception for most commands */
-	int (*ioctl)(struct usbcam_dev *udp, int cmd, void *arg);
-
-	/* cap_start: invoked when capture should be initiated */
-	int (*cap_start)(struct usbcam_dev *udp);
-
-	/* cap_stop: invoked when capture should be halted */
-	void (*cap_stop)(struct usbcam_dev *udp);
-};
-
-
-/*
- * Minidrivers may register themselves using usbcam_register_mod(),
- * although the recommended method is to use the usbcam_register()
- * macro instead.
- *
- * The driver should keep a usbcam_minidrv structure pointer as a
- * handle to the usbcam registration, as it will need it later when it
- * needs to unregister itself.  usbcam_register_mod() accepts a pointer
- * to this structure, and fills it in on success.
- *
- * The minidriver must report a primary version number in KERNEL_VERSION
- * format, which is used by the default VIDIOC_QUERYCAP ioctl handler.
- * The minidriver may optionally report an extra version string.
- *
- * usbcam_register_mod() will cause usbcam to register a new USB driver
- * with the given device ID table, so that it may be called when
- * matching devices are discovered.
- *
- * When a matching device is detected, usbcam will:
- *	-> Allocate a usbcam_dev structure, including a minidriver-specific
- *	   portion of a given size, attached to ud_minidrv_data
- *	-> Invoke the ->init() callout for the minidriver
- *	-> If successful, register a new video4linux device and
- *	   start accepting V4L API requests on it
- *
- * usbcam_register() depends on variables defined by the
- * DEFINE_USBCAM_MODPARAMS macro to function correctly.  This defines
- * a set of static variables and marks them as module parameters.  These
- * include:
- *	-> video_nr: Favored video4linux minor numbers
- *	-> debug: A pointer to the debug level variable
- */
-
-extern int usbcam_register_mod(usbcam_minidrv_t **driverpp,
-			       int mdrv_version, const char *mdrv_verx,
-			       const struct usbcam_dev_ops *ops,
-			       const int dev_priv_size,
-			       const struct usb_device_id *id_table,
-			       const int *video_nrs, int video_nrs_len,
-			       int *debug, struct module *md,
-			       const char *modname);
-
-/*
- * usbcam_unregister() will remove a minidriver registration with the
- * USB subsystem, and will prepare the minidriver structure to be
- * freed.  It is safe to call this API in paths other than minidriver
- * module unload, as long as the minidriver is registered.
- */
-extern void usbcam_unregister(usbcam_minidrv_t *driverp);
-
-#define DEFINE_USBCAM_MODPARAMS_BASE					\
-	static int video_nr_len = 0;					\
-	static int video_nr[8];						\
-	module_param_array(video_nr, int, &video_nr_len, S_IRUGO|S_IWUSR);    \
-	MODULE_PARM_DESC(video_nr, "=n[,n...] Force /dev/videoX IDs");
-
-#if defined(CONFIG_USBCAM_DEBUG)
-#ifndef USBCAM_DEBUG_DEFAULT
-#define USBCAM_DEBUG_DEFAULT 0x0020
-#endif
-#define DEFINE_USBCAM_MODPARAMS 					\
-	DEFINE_USBCAM_MODPARAMS_BASE					\
-	static int debug = USBCAM_DEBUG_DEFAULT;			\
-	module_param(debug, int, S_IRUGO|S_IWUSR);		      	\
-	MODULE_PARM_DESC(debug, "Enable debug trace messages");
-#define usbcam_register(DRVPP, MDV, VERX, CB, STRUCTSIZE, IDTBL)	\
-	usbcam_register_mod((DRVPP), (MDV), (VERX), (CB), (STRUCTSIZE),	\
-			    (IDTBL), video_nr, video_nr_len, &debug,	\
-			    THIS_MODULE, KBUILD_MODNAME)
-#else
-#define DEFINE_USBCAM_MODPARAMS 					\
-	DEFINE_USBCAM_MODPARAMS_BASE
-#define usbcam_register(DRVPP, MDV, VERX, CB, STRUCTSIZE, IDTBL)	\
-	usbcam_register_mod((DRVPP), (MDV), (VERX), (CB), (STRUCTSIZE),	\
-			    (IDTBL), video_nr, video_nr_len, NULL,	\
-			    THIS_MODULE, KBUILD_MODNAME)
-#endif
-
-
-/*
- * For minidrivers that do not need to do anything other than register
- * and unregister themselves as usbcam minidrivers when their modules
- * are loaded and unloaded, the DEFINE_USBCAM_MINIDRV_MODULE macro
- * is offered.
- */
-#define DEFINE_USBCAM_MINIDRV_MODULE(VER, VERX, OPS, STRUCTSIZE, IDTBL)	\
-	DEFINE_USBCAM_MODPARAMS						\
-	static usbcam_minidrv_t *usbcam_minidrv_driver;			\
-	static int __init usbcam_minidrv_init(void)			\
-	{								\
-		return usbcam_register(&usbcam_minidrv_driver,		\
-				       (VER), (VERX), (OPS),		\
-				       (STRUCTSIZE), (IDTBL));		\
-	}								\
-	static void __exit usbcam_minidrv_exit(void)			\
-	{								\
-		usbcam_unregister(usbcam_minidrv_driver);		\
-	}								\
-	module_init(usbcam_minidrv_init);				\
-	module_exit(usbcam_minidrv_exit);
-
-
-/*
- * Function for claiming additional interfaces
- *
- * This may only be called from the minidriver init callout
- *
- * For devices with multiple interfaces that pertain to a single driver,
- * a separate usbcam_dev would ordinarily be created for each interface,
- * and the init callout would be invoked.  With this function,
- * additional pertinent interfaces can be bound to the base usbcam_dev.
- *
- * Additional claimed interfaces will be automatically released at
- * disconnect time, or in the event of a failure from the init callout.
- *
- * If the subject interface is already claimed by another USB driver,
- * this function will fail with -EBUSY.
- */
-extern int usbcam_claim_interface(struct usbcam_dev *udp, int ifnum);
-
-
-/*
- * Alternate setting choosing helper function
- *
- * This function assists in choosing an alternate setting based on
- * overall bandwidth and packet size requirements for a given pipe.
- */
-extern int usbcam_choose_altsetting(struct usbcam_dev *udp, int ifnum,
-				    int pipe, int bytes_per_sec_min,
-				    int pkt_min, int pkt_max,
-				    int *altsetting_nr);
-
-
-/*
- * Minidrivers need to get the address to which the current frame
- * buffer is mapped, and the allocated size of the frame buffer in
- * order to do their job.  The below functions facilitate that.
- */
-struct usbcam_curframe {
-	u8			*uc_base;
-	size_t			uc_size;
-	enum v4l2_field		uc_field;
-	struct timeval		uc_timestamp;
-};
-
-extern int usbcam_curframe_get(struct usbcam_dev *udp,
-			       struct usbcam_curframe *cf);
-extern void usbcam_curframe_complete_detail(struct usbcam_dev *udp,
-					    int is_error,
-					    struct usbcam_curframe *cf);
-#define usbcam_curframe_complete(UDP, ISERR) \
-	usbcam_curframe_complete_detail(UDP, ISERR, NULL)
-
-extern void usbcam_curframe_abortall(struct usbcam_dev *udp);
-
-/*
- * usbcam_curframe_fill() is a glorified memset: it fills the current
- * frame buffer, starting at offs, with nrecs instances of the repeating
- * byte sequence pattern/patlen.
- *
- * It does range checking and will issue printk warnings if the frame
- * buffer or the ud_format.sizeimage is overshot.
- */
-extern void usbcam_curframe_fill(struct usbcam_dev *udp, size_t offset,
-				 const void *pattern, int patlen, int nrecs);
-
-/*
- * usbcam_curframe_testpattern() attempts to fill the current frame
- * buffer with a blue test pattern.  It paves over any partial frame
- * data.  If you wish to display part of an incomplete or interrupted
- * frame, don't use this function.  It is used by default to fill in
- * frames that are completed with is_error = 1.
- *
- * This function is aware of bytesperline and padded line formats.
- */
-extern int usbcam_curframe_testpattern(struct usbcam_dev *udp);
-
-
-/*
- * WORK ITEMS AND THE PER-DEVICE WORKER THREAD
- *
- * So long as a usbcam video4linux device is open, there is a worker
- * thread available to execute deferred minidriver tasks.  The worker
- * thread becomes available prior to the open callout issued to the
- * minidriver, and the last close of the device will block after the
- * minidriver close callout finishes, waiting for the work queue to
- * drain.
- *
- * A work item may be queued from any context, including interrupt
- * contexts and URB completion callouts.
- *
- * Work item callouts are invoked in the context of the worker thread
- * with the device mutex held.  When a work item is queued, when the
- * worker thread is next idle, it will wait for the device mutex, and
- * will start the work item once it acquires the device mutex.  Until
- * that point, the work item may be canceled and dequeued using the
- * usbcam_work_cancel() API, which may only be called while holding
- * the device mutex.
- *
- * It was decided not to use the core kernel work queue
- * implementation for the usbcam work queue because:
- * 1. Work item cancelation is seen as a useful feature
- * 2. Multithreading is not seen as a useful feature
- */
-
-struct usbcam_workitem;
-typedef void (*usbcam_workfunc_t)(struct usbcam_workitem *work);
-
-struct usbcam_workitem {
-	struct list_head	uw_links;
-	struct usbcam_dev	*uw_dev;
-	usbcam_workfunc_t	uw_func;
-};
-
-extern void usbcam_work_init(struct usbcam_workitem *wip,
-			     usbcam_workfunc_t func);
-extern int usbcam_work_queue(struct usbcam_dev *udp,
-			     struct usbcam_workitem *wip);
-extern int usbcam_work_cancel(struct usbcam_dev *udp,
-			      struct usbcam_workitem *wip);
-
-/*
- * usbcam_work_ref() and usbcam_work_unref() are for managing the start
- * and stop of the worker thread.
- */
-extern int usbcam_work_ref(struct usbcam_dev *udp);
-extern void usbcam_work_unref(struct usbcam_dev *udp);
-
-/*
- * usbcam_work_runqueue() will run work queue items in the current context
- * until the work queue becomes empty.
- */
-extern void usbcam_work_runqueue(struct usbcam_dev *udp);
-
-
-/*
- * Isochronous stream helper structure
- *
- * Minidrivers create any number of these, assign appropriate endpoints,
- * and invoke start.  Completed packets are automatically processed in the
- * worker thread.
- *
- * This infrastructure may only be used when a device is opened, as the
- * worker thread is shut down at other times.
- */
-
-struct usbcam_isostream;
-
-struct usbcam_isostream_ops {
-	void (*packet_done)(struct usbcam_dev *, struct usbcam_isostream *,
-			    void *pktdata, int pktlen, int pktstatus);
-	void (*submit_error)(struct usbcam_dev *, struct usbcam_isostream *,
-			     int status);
-};
-
-struct usbcam_isostream {
-	struct usbcam_dev		*iso_dev;
-	int				iso_endpoint;
-	int				iso_packet_len;
-	int				iso_packet_count;
-	int				iso_urb_interval;
-	struct usbcam_isostream_ops	*iso_ops;
-	spinlock_t			iso_lock;
-	int				iso_streaming;
-	struct list_head		iso_unused_list;
-	struct list_head		iso_active_list;
-	struct list_head		iso_complete_list;
-	int				iso_resubmit_err;
-	struct usbcam_workitem		iso_error_workitem;
-};
-
-extern int usbcam_isostream_init(struct usbcam_isostream *isop,
-				 struct usbcam_dev *udp,
-				 int ep, struct usbcam_isostream_ops *ops,
-				 int pktcount, int nurbs, int interval,
-				 int pktlen);
-extern void usbcam_isostream_cleanup(struct usbcam_isostream *);
-extern int usbcam_isostream_start(struct usbcam_isostream *);
-extern void usbcam_isostream_stop(struct usbcam_isostream *);
-
-
-/*
- * Backward compatibility crap for slightly older 2.6 series kernels
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-#if !defined(V4L2_CTRL_FLAG_NEXT_CTRL)
-#define V4L2_CTRL_FLAG_NEXT_CTRL 0
-#endif
-#if !defined(V4L2_CTRL_FLAG_SLIDER)
-#define V4L2_CTRL_FLAG_SLIDER 0
-#endif
-#if !defined(V4L2_CTRL_FLAG_INACTIVE)
-#define V4L2_CTRL_FLAG_INACTIVE 0
-#endif
-#if !defined(V4L2_CTRL_FLAG_UPDATE)
-#define V4L2_CTRL_FLAG_UPDATE 0
-#endif
-#define usb_endpoint_xfer_bulk(EPD) \
-	(((EPD)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == \
-	 USB_ENDPOINT_XFER_BULK)
-#define usb_endpoint_xfer_int(EPD) \
-	(((EPD)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == \
-	 USB_ENDPOINT_XFER_INT)
-#define usb_endpoint_xfer_isoc(EPD) \
-	(((EPD)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == \
-	 USB_ENDPOINT_XFER_ISOC)
-#define usb_endpoint_dir_in(EPD) \
-	(((EPD)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-#define usb_autopm_get_interface(X) 0
-#define usb_autopm_put_interface(X)
-#endif  /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
-
-#endif /* __KERNEL__ */
-
-#endif /* __USBCAM_H__ */