[PATCH 074/524] Staging: easycap: add easycap driver

Greg Kroah-Hartman gregkh at suse.de
Thu Aug 5 22:17:37 UTC 2010


From: R.M. Thomas <rmthomas at sciolus.org>

This adds the easycap USB video adapter driver to
the staging directory.

Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
---
 drivers/staging/Kconfig                    |    2 +
 drivers/staging/Makefile                   |    1 +
 drivers/staging/easycap/Kconfig            |   16 +
 drivers/staging/easycap/Makefile           |   13 +
 drivers/staging/easycap/README             |  130 +
 drivers/staging/easycap/easycap.h          |  632 ++++
 drivers/staging/easycap/easycap_debug.h    |   27 +
 drivers/staging/easycap/easycap_ioctl.c    | 2651 +++++++++++++++++
 drivers/staging/easycap/easycap_ioctl.h    |   29 +
 drivers/staging/easycap/easycap_low.c      | 1057 +++++++
 drivers/staging/easycap/easycap_main.c     | 4342 ++++++++++++++++++++++++++++
 drivers/staging/easycap/easycap_settings.c |  489 ++++
 drivers/staging/easycap/easycap_sound.c    |  973 +++++++
 drivers/staging/easycap/easycap_sound.h    |   30 +
 drivers/staging/easycap/easycap_standard.h |   27 +
 drivers/staging/easycap/easycap_testcard.c |  392 +++
 16 files changed, 10811 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/easycap/Kconfig
 create mode 100644 drivers/staging/easycap/Makefile
 create mode 100644 drivers/staging/easycap/README
 create mode 100644 drivers/staging/easycap/easycap.h
 create mode 100644 drivers/staging/easycap/easycap_debug.h
 create mode 100644 drivers/staging/easycap/easycap_ioctl.c
 create mode 100644 drivers/staging/easycap/easycap_ioctl.h
 create mode 100644 drivers/staging/easycap/easycap_low.c
 create mode 100644 drivers/staging/easycap/easycap_main.c
 create mode 100644 drivers/staging/easycap/easycap_settings.c
 create mode 100644 drivers/staging/easycap/easycap_sound.c
 create mode 100644 drivers/staging/easycap/easycap_sound.h
 create mode 100644 drivers/staging/easycap/easycap_standard.h
 create mode 100644 drivers/staging/easycap/easycap_testcard.c

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 2faff96..d5b827c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -149,5 +149,7 @@ source "drivers/staging/mrst-touchscreen/Kconfig"
 
 source "drivers/staging/msm/Kconfig"
 
+source "drivers/staging/easycap/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 6d21710..2c14f89 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -55,3 +55,4 @@ obj-$(CONFIG_ADIS16255)		+= adis16255/
 obj-$(CONFIG_FB_XGI)		+= xgifb/
 obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH)	+= mrst-touchscreen/
 obj-$(CONFIG_MSM_STAGING)	+= msm/
+obj-$(CONFIG_EASYCAP)		+= easycap/
diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/easycap/Kconfig
new file mode 100644
index 0000000..9bff7cf
--- /dev/null
+++ b/drivers/staging/easycap/Kconfig
@@ -0,0 +1,16 @@
+config EASYCAP
+	tristate "EasyCAP USB ID 05e1:0408 support"
+
+	---help---
+	  This is an integrated audio/video driver for EasyCAP cards with
+	  USB ID 05e1:0408.  It supports two hardware variants:
+
+	  *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
+	     having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
+
+	  *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
+	     1, 2, 3, 4 and an unlabelled input cable for a microphone.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called easycap
+
diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/easycap/Makefile
new file mode 100644
index 0000000..d93bd6b
--- /dev/null
+++ b/drivers/staging/easycap/Makefile
@@ -0,0 +1,13 @@
+
+obj-$(CONFIG_EASYCAP)	+= easycap.o
+
+easycap-objs	:= easycap_main.o easycap_low.o easycap_sound.o
+easycap-objs	+= easycap_ioctl.o easycap_settings.o
+easycap-objs	+= easycap_testcard.o
+
+EXTRA_CFLAGS += -Wall
+# Impose all or none of the following:
+EXTRA_CFLAGS += -DEASYCAP_IS_VIDEODEV_CLIENT
+EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_DEVICE_H
+EXTRA_CFLAGS += -DEASYCAP_NEEDS_V4L2_FOPS
+
diff --git a/drivers/staging/easycap/README b/drivers/staging/easycap/README
new file mode 100644
index 0000000..3775481
--- /dev/null
+++ b/drivers/staging/easycap/README
@@ -0,0 +1,130 @@
+
+        ***********************************************************
+        *   EasyCAP USB 2.0 Video Adapter with Audio, Model DC60  *
+        *                            and                          *
+        *             EasyCAP002 4-Channel USB 2.0 DVR            *
+        ***********************************************************
+                     Mike Thomas  <rmthomas at sciolus.org>
+
+
+
+SUPPORTED HARDWARE
+------------------
+
+This driver is intended for use with hardware having USB ID 05e1:0408.
+Two kinds of EasyCAP have this USB ID, namely:
+
+    *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
+       having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
+
+    *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
+       1, 2, 3, 4 and an unlabelled input cable for a microphone.
+
+
+BUILD OPTIONS AND DEPENDENCIES
+------------------------------
+
+If the parameter EASYCAP_IS_VIDEODEV_CLIENT is undefined during compilation
+the built module is entirely independent of the videodev module, and when
+the EasyCAP is physically plugged into a USB port the special files
+/dev/easycap0 and /dev/easysnd1 are created as video and sound sources
+respectively.
+
+If the parameter EASYCAP_IS_VIDEODEV_CLIENT is defined during compilation
+the built easycap module is configured to register with the videodev module,
+in which case the special files created when the EasyCAP is plugged in are
+/dev/video0 and /dev/easysnd0.  Use of the easycap module as a client of
+the videodev module has received very little testing as of June 2010.
+
+
+KNOWN BUILD PROBLEMS
+--------------------
+
+(1) Recent gcc versions may generate the message:
+
+     warning: the frame size of .... bytes is larger than 1024 bytes
+
+This warning can be suppressed by specifying in the Makefile:
+
+     EXTRA_CFLAGS += -Wframe-larger-than=8192
+
+but it would be preferable to remove the cause of the warning.
+
+
+KNOWN RUNTIME ISSUES
+--------------------
+
+(1) Randomly (maybe 5 to 10% of occasions) the driver fails to produce any
+output at start-up.  Closing mplayer (or whatever the user program is) and
+restarting it restores normal performance without any other remedial action
+being necessary.  The reason for this is not known.
+
+(2) Intentionally, this driver will not stream material which is unambiguously
+identified by the hardware as copy-protected.  The video output will freeze
+within about a minute when this situation arises.
+
+(3) The controls for luminance, contrast, saturation, hue and volume may not
+always work properly.
+
+(4) Reduced-resolution S-Video seems to suffer from moire artefacts.  No
+attempt has yet been made to rememdy this.
+
+
+SUPPORTED TV STANDARDS AND RESOLUTIONS
+--------------------------------------
+
+The following TV standards are natively supported by the hardware and are
+usable as (for example) the "norm=" parameter in the mplayer command:
+
+    PAL_BGHIN,    NTSC_N_443,
+    PAL_Nc,       NTSC_N,
+    SECAM,        NTSC_M,        NTSC_M_JP,
+    PAL_60,       NTSC_443,
+    PAL_M.
+
+The available picture sizes are:
+
+     at 25 frames per second:   720x576, 704x576, 640x480, 360x288, 320x240;
+     at 30 frames per second:   720x480, 640x480, 360x240, 320x240;
+
+
+WHAT'S TESTED AND WHAT'S NOT
+----------------------------
+
+This driver is known to work with mplayer, mencoder, tvtime and sufficiently
+recent versions of vlc.  An interface to ffmpeg is implemented, but serious
+audio-video synchronization problems remain.
+
+The driver is designed to support all the TV standards accepted by the
+hardware, but as yet it has actually been tested on only a few of these.
+
+I have been unable to test and calibrate the S-video input myself because I
+do not possess any equipment with S-video output.
+
+This driver does not understand the V4L1 IOCTL commands, so programs such
+as camorama are not compatible.  There are reports that the driver does
+work with sufficiently recent (V4L2) versions of zoneminder, but I have not
+attempted to confirm this myself.
+
+
+UDEV RULES
+----------
+
+In order that the special files /dev/easycap0 and /dev/easysnd1 are created
+with conveniently relaxed permissions when the EasyCAP is plugged in, a file
+is preferably to be provided in directory /etc/udev/rules.d with content:
+
+ACTION!="add|change", GOTO="easycap_rules_end"
+ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
+	MODE="0666", OWNER="root", GROUP="root"
+LABEL="easycap_rules_end"
+
+
+ACKNOWLEGEMENTS AND REFERENCES
+------------------------------
+This driver makes use of information contained in the Syntek Semicon DC-1125
+Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
+by Nicolas Vivien.  Particularly useful has been a patch to the latter driver
+provided by Ivor Hewitt in January 2009.  The NTSC implementation is taken
+from the work of Ben Trask.
+
diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/easycap/easycap.h
new file mode 100644
index 0000000..83ae2fb
--- /dev/null
+++ b/drivers/staging/easycap/easycap.h
@@ -0,0 +1,632 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap.h                                                                 *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE FOLLOWING PARAMETERS ARE UNDEFINED:
+ *
+ *                EASYCAP_DEBUG
+ *                EASYCAP_IS_VIDEODEV_CLIENT
+ *                EASYCAP_NEEDS_USBVIDEO_H
+ *                EASYCAP_NEEDS_V4L2_DEVICE_H
+ *                EASYCAP_NEEDS_V4L2_FOPS
+ *
+ *  IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
+ *  OPTIONS.
+ */
+/*---------------------------------------------------------------------------*/
+
+#if (!defined(EASYCAP_H))
+#define EASYCAP_H
+
+#if defined(EASYCAP_DEBUG)
+#if (9 < EASYCAP_DEBUG)
+#error Debug levels 0 to 9 are okay.\
+  To achieve higher levels, remove this trap manually from easycap.h
+#endif
+#endif /*EASYCAP_DEBUG*/
+/*---------------------------------------------------------------------------*/
+/*
+ *  THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
+ */
+/*---------------------------------------------------------------------------*/
+#undef  PREFER_NTSC
+#undef  EASYCAP_TESTCARD
+#undef  EASYCAP_TESTTONE
+#undef  LOCKFRAME
+#undef  NOREADBACK
+#undef  AUDIOTIME
+/*---------------------------------------------------------------------------*/
+/*
+ *
+ *  DEFINE   BRIDGER   TO ACTIVATE THE ROUTINE FOR BRIDGING VIDEOTAPE DROPOUTS.
+ *
+ *             *** UNDER DEVELOPMENT/TESTING - NOT READY YET!***
+ *
+ */
+/*---------------------------------------------------------------------------*/
+#undef  BRIDGER
+/*---------------------------------------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if (!defined(__OLD_VIDIOC_))
+#define __OLD_VIDIOC_
+#endif /* !defined(__OLD_VIDIOC_) */
+
+#include <media/v4l2-dev.h>
+
+#if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
+#include <media/v4l2-device.h>
+#endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+#if (!defined(__OLD_VIDIOC_))
+#define __OLD_VIDIOC_
+#endif /* !defined(__OLD_VIDIOC_) */
+#include <linux/videodev2.h>
+
+#include <linux/soundcard.h>
+
+#if defined(EASYCAP_NEEDS_USBVIDEO_H)
+#include <config/video/usbvideo.h>
+#endif /*EASYCAP_NEEDS_USBVIDEO_H*/
+
+#if (!defined(PAGE_SIZE))
+#error "PAGE_SIZE not defined"
+#endif
+
+#define STRINGIZE_AGAIN(x) #x
+#define STRINGIZE(x) STRINGIZE_AGAIN(x)
+
+/*---------------------------------------------------------------------------*/
+/*  VENDOR, PRODUCT:  Syntek Semiconductor Co., Ltd
+ *
+ *      EITHER        EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
+ *               with input cabling:  AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
+ *
+ *          OR        EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
+ *               with input cabling:  MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
+ */
+/*---------------------------------------------------------------------------*/
+#define USB_EASYCAP_VENDOR_ID	0x05e1
+#define USB_EASYCAP_PRODUCT_ID	0x0408
+
+#define EASYCAP_DRIVER_VERSION "0.8"
+#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
+
+#define USB_SKEL_MINOR_BASE     192
+#define VIDEO_DEVICE_MANY 8
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
+ */
+/*---------------------------------------------------------------------------*/
+#define SAA_0A_DEFAULT 0x7F
+#define SAA_0B_DEFAULT 0x3F
+#define SAA_0C_DEFAULT 0x2F
+#define SAA_0D_DEFAULT 0x00
+/*---------------------------------------------------------------------------*/
+/*
+ *  VIDEO STREAMING PARAMETERS:
+ *  USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
+ *  OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
+ */
+/*---------------------------------------------------------------------------*/
+#define VIDEO_ISOC_BUFFER_MANY 16
+#define VIDEO_ISOC_ORDER 3
+#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
+#define USB_2_0_MAXPACKETSIZE 3072
+#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
+#error video_isoc_buffer[.] will not be big enough
+#endif
+/*---------------------------------------------------------------------------*/
+/*
+ *  VIDEO BUFFERS
+ */
+/*---------------------------------------------------------------------------*/
+#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
+#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
+#define FIELD_BUFFER_MANY 4
+#define FRAME_BUFFER_MANY 6
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO STREAMING PARAMETERS
+ */
+/*---------------------------------------------------------------------------*/
+#define AUDIO_ISOC_BUFFER_MANY 16
+#define AUDIO_ISOC_ORDER 3
+#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO BUFFERS
+ */
+/*---------------------------------------------------------------------------*/
+#define AUDIO_FRAGMENT_MANY 32
+/*---------------------------------------------------------------------------*/
+/*
+ *  STRUCTURE DEFINITIONS
+ */
+/*---------------------------------------------------------------------------*/
+struct data_buffer {
+struct list_head list_head;
+void *pgo;
+void *pto;
+__u16 kount;
+};
+/*---------------------------------------------------------------------------*/
+struct data_urb {
+struct list_head list_head;
+struct urb *purb;
+int isbuf;
+int length;
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *   easycap.ilk == 0   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
+ *   easycap.ilk == 2   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
+ *   easycap.ilk == 3   =>     FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
+ */
+/*---------------------------------------------------------------------------*/
+struct easycap {
+
+int ilk;
+bool microphone;
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+struct video_device *pvideo_device;
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+struct usb_device *pusb_device;
+struct usb_interface *pusb_interface;
+
+struct kref kref;
+
+struct mutex mutex_mmap_video[FRAME_BUFFER_MANY];
+struct mutex mutex_timeval0;
+struct mutex mutex_timeval1;
+
+int queued[FRAME_BUFFER_MANY];
+int done[FRAME_BUFFER_MANY];
+
+wait_queue_head_t wq_video;
+wait_queue_head_t wq_audio;
+
+int input;
+int polled;
+int standard_offset;
+int format_offset;
+
+int fps;
+int usec;
+int tolerate;
+int merit[180];
+
+struct timeval timeval0;
+struct timeval timeval1;
+struct timeval timeval2;
+struct timeval timeval7;
+long long int dnbydt;
+
+int    video_interface;
+int    video_altsetting_on;
+int    video_altsetting_off;
+int    video_endpointnumber;
+int    video_isoc_maxframesize;
+int    video_isoc_buffer_size;
+int    video_isoc_framesperdesc;
+
+int    video_isoc_streaming;
+int    video_isoc_sequence;
+int    video_idle;
+int    video_eof;
+int    video_junk;
+
+int    fudge;
+
+struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
+struct data_buffer \
+	     field_buffer[FIELD_BUFFER_MANY][(FIELD_BUFFER_SIZE/PAGE_SIZE)];
+struct data_buffer \
+	     frame_buffer[FRAME_BUFFER_MANY][(FRAME_BUFFER_SIZE/PAGE_SIZE)];
+
+struct list_head urb_video_head;
+struct list_head *purb_video_head;
+
+int vma_many;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  BUFFER INDICATORS
+ */
+/*---------------------------------------------------------------------------*/
+int field_fill;		/* Field buffer being filled by easycap_complete().  */
+			/*   Bumped only by easycap_complete().              */
+int field_page;		/* Page of field buffer page being filled by         */
+			/*   easycap_complete().                             */
+int field_read;		/* Field buffer to be read by field2frame().         */
+			/*   Bumped only by easycap_complete().              */
+int frame_fill;		/* Frame buffer being filled by field2frame().       */
+			/*   Bumped only by easycap_dqbuf() when             */
+			/*   field2frame() has created a complete frame.     */
+int frame_read;		/* Frame buffer offered to user by DQBUF.            */
+			/*   Set only by easycap_dqbuf() to trail frame_fill.*/
+int frame_lock;		/* Flag set to 1 by DQBUF and cleared by QBUF        */
+/*---------------------------------------------------------------------------*/
+/*
+ *  IMAGE PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+__u32                   pixelformat;
+__u32                   field;
+int                     width;
+int                     height;
+int                     bytesperpixel;
+bool                    byteswaporder;
+bool                    decimatepixel;
+bool                    offerfields;
+int                     frame_buffer_used;
+int                     frame_buffer_many;
+int                     videofieldamount;
+
+int                     brightness;
+int                     contrast;
+int                     saturation;
+int                     hue;
+
+int allocation_video_urb;
+int allocation_video_page;
+int allocation_video_struct;
+int registered_video;
+/*---------------------------------------------------------------------------*/
+/*
+ *  SOUND PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+int audio_interface;
+int audio_altsetting_on;
+int audio_altsetting_off;
+int audio_endpointnumber;
+int audio_isoc_maxframesize;
+int audio_isoc_buffer_size;
+int audio_isoc_framesperdesc;
+
+int audio_isoc_streaming;
+int audio_idle;
+int audio_eof;
+int volume;
+int mute;
+
+struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
+
+struct list_head urb_audio_head;
+struct list_head *purb_audio_head;
+/*---------------------------------------------------------------------------*/
+/*
+ *  BUFFER INDICATORS
+ */
+/*---------------------------------------------------------------------------*/
+int audio_fill;		/* Audio buffer being filled by easysnd_complete().  */
+			/*   Bumped only by easysnd_complete().              */
+int audio_read;		/* Audio buffer page being read by easysnd_read().   */
+			/*   Set by easysnd_read() to trail audio_fill by    */
+			/*   one fragment.                                   */
+/*---------------------------------------------------------------------------*/
+/*
+ *  SOUND PROPERTIES
+ */
+/*---------------------------------------------------------------------------*/
+
+int audio_buffer_many;
+
+int allocation_audio_urb;
+int allocation_audio_page;
+int allocation_audio_struct;
+int registered_audio;
+
+long long int audio_sample;
+long long int audio_niveau;
+long long int audio_square;
+
+struct data_buffer audio_buffer[];
+};
+/*---------------------------------------------------------------------------*/
+struct easycap_standard {
+__u16 mask;
+struct v4l2_standard v4l2_standard;
+};
+struct easycap_format {
+__u16 mask;
+char name[128];
+struct v4l2_format v4l2_format;
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *  VIDEO FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+void             easycap_complete(struct urb *);
+int              easycap_open(struct inode *, struct file *);
+int              easycap_release(struct inode *, struct file *);
+int              easycap_ioctl(struct inode *, struct file *, \
+						unsigned int,  unsigned long);
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int              easycap_open_noinode(struct file *);
+int              easycap_release_noinode(struct file *);
+long             easycap_ioctl_noinode(struct file *, \
+						unsigned int,  unsigned long);
+int              videodev_release(struct video_device *);
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+unsigned int     easycap_poll(struct file *, poll_table *);
+int              easycap_mmap(struct file *, struct vm_area_struct *);
+int              easycap_usb_probe(struct usb_interface *, \
+						const struct usb_device_id *);
+void             easycap_usb_disconnect(struct usb_interface *);
+void             easycap_delete(struct kref *);
+
+void             easycap_vma_open(struct vm_area_struct *);
+void             easycap_vma_close(struct vm_area_struct *);
+int              easycap_vma_fault(struct vm_area_struct *, struct vm_fault *);
+int              easycap_dqbuf(struct easycap *, int);
+int              submit_video_urbs(struct easycap *);
+int              kill_video_urbs(struct easycap *);
+int              field2frame(struct easycap *);
+int              redaub(struct easycap *, void *, void *, \
+						int, int, __u8, __u8, bool);
+void             debrief(struct easycap *);
+void             sayreadonly(struct easycap *);
+void             easycap_testcard(struct easycap *, int);
+int              explain_ioctl(__u32);
+int              explain_cid(__u32);
+int              fillin_formats(void);
+int              adjust_standard(struct easycap *, v4l2_std_id);
+int              adjust_format(struct easycap *, __u32, __u32, __u32, \
+								int, bool);
+int              adjust_brightness(struct easycap *, int);
+int              adjust_contrast(struct easycap *, int);
+int              adjust_saturation(struct easycap *, int);
+int              adjust_hue(struct easycap *, int);
+int              adjust_volume(struct easycap *, int);
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+void             easysnd_complete(struct urb *);
+ssize_t          easysnd_read(struct file *, char __user *, size_t, loff_t *);
+int              easysnd_open(struct inode *, struct file *);
+int              easysnd_release(struct inode *, struct file *);
+int              easysnd_ioctl(struct inode *, struct file *, \
+						unsigned int,  unsigned long);
+unsigned int     easysnd_poll(struct file *, poll_table *);
+void             easysnd_delete(struct kref *);
+int              submit_audio_urbs(struct easycap *);
+int              kill_audio_urbs(struct easycap *);
+void             easysnd_testtone(struct easycap *, int);
+int              audio_setup(struct easycap *);
+/*---------------------------------------------------------------------------*/
+/*
+ *  LOW-LEVEL FUNCTION PROTOTYPES
+ */
+/*---------------------------------------------------------------------------*/
+int              audio_gainget(struct usb_device *);
+int              audio_gainset(struct usb_device *, __s8);
+
+int              set_interface(struct usb_device *, __u16);
+int              wakeup_device(struct usb_device *);
+int              confirm_resolution(struct usb_device *);
+int              confirm_stream(struct usb_device *);
+
+int              setup_stk(struct usb_device *);
+int              setup_saa(struct usb_device *);
+int              setup_vt(struct usb_device *);
+int              check_stk(struct usb_device *);
+int              check_saa(struct usb_device *);
+int              ready_saa(struct usb_device *);
+int              merit_saa(struct usb_device *);
+int              check_vt(struct usb_device *);
+int              select_input(struct usb_device *, int, int);
+int              set_resolution(struct usb_device *, \
+						__u16, __u16, __u16, __u16);
+
+int              read_saa(struct usb_device *, __u16);
+int              read_stk(struct usb_device *, __u32);
+int              write_saa(struct usb_device *, __u16, __u16);
+int              wait_i2c(struct usb_device *);
+int              write_000(struct usb_device *, __u16, __u16);
+int              start_100(struct usb_device *);
+int              stop_100(struct usb_device *);
+int              write_300(struct usb_device *);
+int              read_vt(struct usb_device *, __u16);
+int              write_vt(struct usb_device *, __u16, __u16);
+
+int              set2to78(struct usb_device *);
+int              set2to93(struct usb_device *);
+
+int              regset(struct usb_device *, __u16, __u16);
+int              regget(struct usb_device *, __u16, void *);
+/*---------------------------------------------------------------------------*/
+struct signed_div_result {
+long long int quotient;
+unsigned long long int remainder;
+} signed_div(long long int, long long int);
+/*---------------------------------------------------------------------------*/
+/*
+ *  IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
+ *                        ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
+ *  THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE.  NOT
+ *  ONLY MUST THE PARAMETER
+ *                             STANDARD_MANY
+ *  BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
+ *  NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE:  DUMMY STANDARDS
+ *  MAY NEED TO BE ADDED.   APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
+ *  ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+#define  PAL_BGHIN      0
+#define  PAL_Nc         2
+#define  SECAM          4
+#define  NTSC_N         6
+#define  NTSC_N_443     8
+#define  NTSC_M         1
+#define  NTSC_443       3
+#define  NTSC_M_JP      5
+#define  PAL_60         7
+#define  PAL_M          9
+#define  STANDARD_MANY 10
+/*---------------------------------------------------------------------------*/
+/*
+ *  ENUMS
+ */
+/*---------------------------------------------------------------------------*/
+enum {
+AT_720x576,
+AT_704x576,
+AT_640x480,
+AT_720x480,
+AT_360x288,
+AT_320x240,
+AT_360x240,
+RESOLUTION_MANY
+};
+enum {
+FMT_UYVY,
+FMT_YUY2,
+FMT_RGB24,
+FMT_RGB32,
+FMT_BGR24,
+FMT_BGR32,
+PIXELFORMAT_MANY
+};
+enum {
+FIELD_NONE,
+FIELD_INTERLACED,
+FIELD_ALTERNATE,
+INTERLACE_MANY
+};
+#define SETTINGS_MANY	(STANDARD_MANY * \
+			RESOLUTION_MANY * \
+			2 * \
+			PIXELFORMAT_MANY * \
+			INTERLACE_MANY)
+/*---------------------------------------------------------------------------*/
+/*
+ *  MACROS
+ */
+/*---------------------------------------------------------------------------*/
+#define GET(X, Y, Z) do { \
+	int rc; \
+	*(Z) = (__u16)0; \
+	rc = regget(X, Y, Z); \
+	if (0 > rc) { \
+		JOT(8, ":-(%i\n", __LINE__);  return(rc); \
+	} \
+} while (0)
+
+#define SET(X, Y, Z) do { \
+	int rc; \
+	rc = regset(X, Y, Z); \
+	if (0 > rc) { \
+		JOT(8, ":-(%i\n", __LINE__);  return(rc); \
+	} \
+} while (0)
+/*---------------------------------------------------------------------------*/
+
+#define SAY(format, args...) do { \
+	printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
+} while (0)
+
+
+#if defined(EASYCAP_DEBUG)
+#define JOT(n, format, args...) do { \
+	if (n <= easycap_debug) { \
+		printk(KERN_DEBUG "easycap: %s: " format, __func__, ##args); \
+	} \
+} while (0)
+#else
+#define JOT(n, format, args...) do {} while (0)
+#endif /*EASYCAP_DEBUG*/
+
+#define POUT JOT(8, ":-(in file %s line %4i\n", __FILE__, __LINE__)
+
+#define MICROSECONDS(X, Y) \
+			((1000000*((long long int)(X.tv_sec - Y.tv_sec))) + \
+					(long long int)(X.tv_usec - Y.tv_usec))
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  (unsigned char *)P           pointer to next byte pair
+ *       (long int *)X           pointer to accumulating count
+ *       (long int *)Y           pointer to accumulating sum
+ *  (long long int *)Z           pointer to accumulating sum of squares
+ */
+/*---------------------------------------------------------------------------*/
+#define SUMMER(P, X, Y, Z) do {                                 \
+	unsigned char *p;                                    \
+	unsigned int u0, u1, u2;                             \
+	long int s;                                          \
+	p = (unsigned char *)(P);                            \
+	u0 = (unsigned int) (*p);                            \
+	u1 = (unsigned int) (*(p + 1));                      \
+	u2 = (unsigned int) ((u1 << 8) | u0);                \
+	if (0x8000 & u2)                                     \
+		s = -(long int)(0x7FFF & (~u2));             \
+	else                                                 \
+		s =  (long int)(0x7FFF & u2);                \
+	*((X)) += (long int) 1;                              \
+	*((Y)) += (long int) s;                              \
+	*((Z)) += ((long long int)(s) * (long long int)(s)); \
+} while (0)
+/*---------------------------------------------------------------------------*/
+
+#endif /*EASYCAP_H*/
diff --git a/drivers/staging/easycap/easycap_debug.h b/drivers/staging/easycap/easycap_debug.h
new file mode 100644
index 0000000..1d10d7e
--- /dev/null
+++ b/drivers/staging/easycap/easycap_debug.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap_debug.h                                                           *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+extern int easycap_debug;
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c
new file mode 100644
index 0000000..f71cd9e
--- /dev/null
+++ b/drivers/staging/easycap/easycap_ioctl.c
@@ -0,0 +1,2651 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_ioctl.c                                                            *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+#include "easycap_standard.h"
+#include "easycap_ioctl.h"
+
+/*--------------------------------------------------------------------------*/
+/*
+ *  UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
+ *  FOLLOWING:
+ *          peasycap->standard_offset
+ *          peasycap->fps
+ *          peasycap->usec
+ *          peasycap->tolerate
+ */
+/*---------------------------------------------------------------------------*/
+int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
+{
+struct easycap_standard *peasycap_standard;
+__u16 reg, set;
+int ir, rc, need;
+unsigned int itwas, isnow;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+peasycap_standard = &easycap_standard[0];
+while (0xFFFF != peasycap_standard->mask) {
+	if (std_id & peasycap_standard->v4l2_standard.id)
+		break;
+	peasycap_standard++;
+}
+if (0xFFFF == peasycap_standard->mask) {
+	SAY("ERROR: 0x%08X=std_id: standard not found\n", \
+							(unsigned int)std_id);
+	return -EINVAL;
+}
+SAY("user requests standard: %s\n", \
+			&(peasycap_standard->v4l2_standard.name[0]));
+if (peasycap->standard_offset == \
+			(int)(peasycap_standard - &easycap_standard[0])) {
+	SAY("requested standard already in effect\n");
+	return 0;
+}
+peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]);
+peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \
+		peasycap_standard->v4l2_standard.frameperiod.numerator;
+if (!peasycap->fps) {
+	SAY("MISTAKE: frames-per-second is zero\n");
+	return -EFAULT;
+}
+JOT(8, "%i frames-per-second\n", peasycap->fps);
+peasycap->usec = 1000000 / (2 * peasycap->fps);
+peasycap->tolerate = 1000 * (25 / peasycap->fps);
+
+kill_video_urbs(peasycap);
+
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAA7113H DATASHEET PAGE 44, TABLE 42
+ */
+/*--------------------------------------------------------------------------*/
+need = 0;  itwas = 0;  reg = 0x00;  set = 0x00;
+switch (peasycap_standard->mask & 0x000F) {
+case NTSC_M_JP: {
+	reg = 0x0A;  set = 0x95;
+	ir = read_saa(peasycap->pusb_device, reg);
+	if (0 > ir)
+		SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
+	else
+		itwas = (unsigned int)ir;
+
+
+	set2to78(peasycap->pusb_device);
+
+
+	rc = write_saa(peasycap->pusb_device, reg, set);
+	if (0 != rc)
+		SAY("ERROR: failed to set SAA register " \
+			"0x%02X to 0x%02X for JP standard\n", reg, set);
+	else {
+		isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+		if (0 > ir)
+			JOT(8, "SAA register 0x%02X changed " \
+				"to 0x%02X\n", reg, isnow);
+		else
+			JOT(8, "SAA register 0x%02X changed " \
+				"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+
+		set2to78(peasycap->pusb_device);
+
+	}
+
+	reg = 0x0B;  set = 0x48;
+	ir = read_saa(peasycap->pusb_device, reg);
+	if (0 > ir)
+		SAY("ERROR: cannot read SAA register 0x%02X\n", reg);
+	else
+		itwas = (unsigned int)ir;
+
+	set2to78(peasycap->pusb_device);
+
+	rc = write_saa(peasycap->pusb_device, reg, set);
+	if (0 != rc)
+		SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X " \
+						"for JP standard\n", reg, set);
+	else {
+		isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+		if (0 > ir)
+			JOT(8, "SAA register 0x%02X changed " \
+				"to 0x%02X\n", reg, isnow);
+		else
+			JOT(8, "SAA register 0x%02X changed " \
+				"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+
+		set2to78(peasycap->pusb_device);
+
+	}
+/*--------------------------------------------------------------------------*/
+/*
+ *  NOTE:  NO break HERE:  RUN ON TO NEXT CASE
+ */
+/*--------------------------------------------------------------------------*/
+}
+case NTSC_M:
+case PAL_BGHIN: {
+	reg = 0x0E;  set = 0x01;  need = 1;  break;
+}
+case NTSC_N_443:
+case PAL_60: {
+	reg = 0x0E;  set = 0x11;  need = 1;  break;
+}
+case NTSC_443:
+case PAL_Nc: {
+	reg = 0x0E;  set = 0x21;  need = 1;  break;
+}
+case NTSC_N:
+case PAL_M: {
+	reg = 0x0E;  set = 0x31;  need = 1;  break;
+}
+case SECAM: {
+	reg = 0x0E;  set = 0x51;  need = 1;  break;
+}
+default:
+	break;
+}
+/*--------------------------------------------------------------------------*/
+if (need) {
+	ir = read_saa(peasycap->pusb_device, reg);
+	if (0 > ir)
+		SAY("ERROR: failed to read SAA register 0x%02X\n", reg);
+	else
+		itwas = (unsigned int)ir;
+
+	set2to78(peasycap->pusb_device);
+
+	rc = write_saa(peasycap->pusb_device, reg, set);
+	if (0 != write_saa(peasycap->pusb_device, reg, set)) {
+		SAY("ERROR: failed to set SAA register " \
+			"0x%02X to 0x%02X for table 42\n", reg, set);
+	} else {
+		isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+		if (0 > ir)
+			JOT(8, "SAA register 0x%02X changed " \
+				"to 0x%02X\n", reg, isnow);
+		else
+			JOT(8, "SAA register 0x%02X changed " \
+				"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+	}
+}
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAA7113H DATASHEET PAGE 41
+ */
+/*--------------------------------------------------------------------------*/
+reg = 0x08;
+ir = read_saa(peasycap->pusb_device, reg);
+if (0 > ir)
+	SAY("ERROR: failed to read SAA register 0x%02X " \
+						"so cannot reset\n", reg);
+else {
+	itwas = (unsigned int)ir;
+	if (peasycap_standard->mask & 0x0001)
+		set = itwas | 0x40 ;
+	else
+		set = itwas & ~0x40 ;
+
+set2to78(peasycap->pusb_device);
+
+rc  = write_saa(peasycap->pusb_device, reg, set);
+if (0 != rc)
+	SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
+else {
+	isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+	if (0 > ir)
+		JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
+	else
+		JOT(8, "SAA register 0x%02X changed " \
+			"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+	}
+}
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAA7113H DATASHEET PAGE 51, TABLE 57
+ */
+/*---------------------------------------------------------------------------*/
+reg = 0x40;
+ir = read_saa(peasycap->pusb_device, reg);
+if (0 > ir)
+	SAY("ERROR: failed to read SAA register 0x%02X " \
+						"so cannot reset\n", reg);
+else {
+	itwas = (unsigned int)ir;
+	if (peasycap_standard->mask & 0x0001)
+		set = itwas | 0x80 ;
+	else
+		set = itwas & ~0x80 ;
+
+set2to78(peasycap->pusb_device);
+
+rc = write_saa(peasycap->pusb_device, reg, set);
+if (0 != rc)
+	SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", reg, set);
+else {
+	isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+	if (0 > ir)
+		JOT(8, "SAA register 0x%02X changed to 0x%02X\n", reg, isnow);
+	else
+		JOT(8, "SAA register 0x%02X changed " \
+			"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+	}
+}
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAA7113H DATASHEET PAGE 53, TABLE 66
+ */
+/*--------------------------------------------------------------------------*/
+reg = 0x5A;
+ir = read_saa(peasycap->pusb_device, reg);
+if (0 > ir)
+	SAY("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
+	itwas = (unsigned int)ir;
+	if (peasycap_standard->mask & 0x0001)
+		set = 0x0A ;
+	else
+		set = 0x07 ;
+
+	set2to78(peasycap->pusb_device);
+
+	if (0 != write_saa(peasycap->pusb_device, reg, set))
+		SAY("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
+								reg, set);
+	else {
+		isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
+		if (0 > ir)
+			JOT(8, "SAA register 0x%02X changed "
+				"to 0x%02X\n", reg, isnow);
+		else
+			JOT(8, "SAA register 0x%02X changed "
+				"from 0x%02X to 0x%02X\n", reg, itwas, isnow);
+	}
+	if (0 != check_saa(peasycap->pusb_device))
+		SAY("ERROR: check_saa() failed\n");
+return 0;
+}
+/*****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL DEPENDS ON THE
+ *  CURRENT VALUE OF peasycap->standard_offset.
+ *  PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
+ *  THIS ROUTINE UPDATES THE FOLLOWING:
+ *          peasycap->format_offset
+ *          peasycap->pixelformat
+ *          peasycap->field
+ *          peasycap->height
+ *          peasycap->width
+ *          peasycap->bytesperpixel
+ *          peasycap->byteswaporder
+ *          peasycap->decimatepixel
+ *          peasycap->frame_buffer_used
+ *          peasycap->videofieldamount
+ *          peasycap->offerfields
+ *
+ *  IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
+ *  IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
+ *  ERRORS RETURN A NEGATIVE NUMBER.
+ */
+/*--------------------------------------------------------------------------*/
+int adjust_format(struct easycap *peasycap, \
+	__u32 width, __u32 height, __u32 pixelformat, int field, bool try)
+{
+struct easycap_format *peasycap_format, *peasycap_best_format;
+__u16 mask;
+struct usb_device *p;
+int miss, multiplier, best;
+char bf[5], *pc;
+__u32 uc;
+
+if ((struct easycap *)NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	return -EFAULT;
+}
+p = peasycap->pusb_device;
+if ((struct usb_device *)NULL == p) {
+	SAY("ERROR: peaycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+pc = &bf[0];
+uc = pixelformat;  memcpy((void *)pc, (void *)(&uc), 4);  bf[4] = 0;
+mask = easycap_standard[peasycap->standard_offset].mask;
+SAY("sought:    %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
+				width, height, pc, pixelformat, field, mask);
+if (V4L2_FIELD_ANY == field) {
+	field = V4L2_FIELD_INTERLACED;
+	SAY("prefer:    V4L2_FIELD_INTERLACED=field, was V4L2_FIELD_ANY\n");
+}
+peasycap_best_format = (struct easycap_format *)NULL;
+peasycap_format = &easycap_format[0];
+while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+	JOT(16, ".> %i %i 0x%08X %ix%i\n", \
+		peasycap_format->mask & 0x01,
+		peasycap_format->v4l2_format.fmt.pix.field,
+		peasycap_format->v4l2_format.fmt.pix.pixelformat,
+		peasycap_format->v4l2_format.fmt.pix.width,
+		peasycap_format->v4l2_format.fmt.pix.height);
+
+	if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+		(peasycap_format->v4l2_format.fmt.pix.field == field) && \
+		(peasycap_format->v4l2_format.fmt.pix.pixelformat == \
+							pixelformat) && \
+		(peasycap_format->v4l2_format.fmt.pix.width  == width) && \
+		(peasycap_format->v4l2_format.fmt.pix.height == height)) {
+			peasycap_best_format = peasycap_format;
+			break;
+		}
+	peasycap_format++;
+}
+if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
+	SAY("cannot do: %ix%i with standard mask 0x%02X\n", \
+							width, height, mask);
+	peasycap_format = &easycap_format[0];  best = -1;
+	while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
+		if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) && \
+				 (peasycap_format->v4l2_format.fmt.pix\
+						.field == field) && \
+				 (peasycap_format->v4l2_format.fmt.pix\
+						.pixelformat == pixelformat)) {
+			miss = abs(peasycap_format->\
+					v4l2_format.fmt.pix.width  - width);
+			if ((best > miss) || (best < 0)) {
+				best = miss;
+				peasycap_best_format = peasycap_format;
+				if (!miss)
+					break;
+			}
+		}
+		peasycap_format++;
+	}
+	if (-1 == best) {
+		SAY("cannot do %ix... with standard mask 0x%02X\n", \
+								width, mask);
+		SAY("cannot do ...x%i with standard mask 0x%02X\n", \
+								height, mask);
+		SAY("           %ix%i unmatched\n", width, height);
+		return peasycap->format_offset;
+	}
+}
+if ((struct easycap_format *)NULL == peasycap_best_format) {
+	SAY("MISTAKE: peasycap_best_format is NULL");
+	return -EINVAL;
+}
+peasycap_format = peasycap_best_format;
+
+/*...........................................................................*/
+if (true == try)
+	return (int)(peasycap_best_format - &easycap_format[0]);
+/*...........................................................................*/
+
+if (false != try) {
+	SAY("MISTAKE: true==try where is should be false\n");
+	return -EINVAL;
+}
+SAY("actioning: %ix%i %s\n", \
+			peasycap_format->v4l2_format.fmt.pix.width, \
+			peasycap_format->v4l2_format.fmt.pix.height,
+			&peasycap_format->name[0]);
+peasycap->height        = peasycap_format->v4l2_format.fmt.pix.height;
+peasycap->width         = peasycap_format->v4l2_format.fmt.pix.width;
+peasycap->pixelformat   = peasycap_format->v4l2_format.fmt.pix.pixelformat;
+peasycap->field         = peasycap_format->v4l2_format.fmt.pix.field;
+peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]);
+peasycap->bytesperpixel = (0x00F0 & peasycap_format->mask) >> 4 ;
+if (0x0100 & peasycap_format->mask)
+	peasycap->byteswaporder = true;
+else
+	peasycap->byteswaporder = false;
+if (0x0800 & peasycap_format->mask)
+	peasycap->decimatepixel = true;
+else
+	peasycap->decimatepixel = false;
+if (0x1000 & peasycap_format->mask)
+	peasycap->offerfields = true;
+else
+	peasycap->offerfields = false;
+if (true == peasycap->decimatepixel)
+	multiplier = 2;
+else
+	multiplier = 1;
+peasycap->videofieldamount = multiplier * peasycap->width * \
+					multiplier * peasycap->height;
+peasycap->frame_buffer_used = peasycap->bytesperpixel * \
+					peasycap->width * peasycap->height;
+
+if (true == peasycap->offerfields) {
+	SAY("WARNING: %i=peasycap->field is untested: " \
+				"please report problems\n", peasycap->field);
+
+
+/*
+ *    FIXME ---- THIS IS UNTESTED, MAY BE (AND PROBABLY IS) INCORRECT:
+ *
+ *    peasycap->frame_buffer_used = peasycap->frame_buffer_used / 2;
+ *
+ *    SO DO NOT RISK IT YET.
+ *
+ */
+
+
+
+}
+
+kill_video_urbs(peasycap);
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  PAL
+ */
+/*---------------------------------------------------------------------------*/
+if (0 == (0x01 & peasycap_format->mask)) {
+	if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
+			(576 == \
+			peasycap_format->v4l2_format.fmt.pix.height)) || \
+			((360 == \
+			peasycap_format->v4l2_format.fmt.pix.width) && \
+			(288 == \
+			peasycap_format->v4l2_format.fmt.pix.height))) {
+		if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
+			SAY("ERROR: set_resolution() failed\n");
+			return -EINVAL;
+		}
+	} else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \
+			(576 == peasycap_format->v4l2_format.fmt.pix.height)) {
+		if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
+			SAY("ERROR: set_resolution() failed\n");
+			return -EINVAL;
+		}
+	} else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
+			(480 == \
+			peasycap_format->v4l2_format.fmt.pix.height)) || \
+			((320 == \
+			peasycap_format->v4l2_format.fmt.pix.width) && \
+			(240 == \
+			peasycap_format->v4l2_format.fmt.pix.height))) {
+		if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
+			SAY("ERROR: set_resolution() failed\n");
+			return -EINVAL;
+		}
+	} else {
+		SAY("MISTAKE: bad format, cannot set resolution\n");
+		return -EINVAL;
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  NTSC
+ */
+/*---------------------------------------------------------------------------*/
+} else {
+	if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
+			(480 == \
+			peasycap_format->v4l2_format.fmt.pix.height)) || \
+			((360 == \
+			peasycap_format->v4l2_format.fmt.pix.width) && \
+			(240 == \
+			peasycap_format->v4l2_format.fmt.pix.height))) {
+		if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
+			SAY("ERROR: set_resolution() failed\n");
+			return -EINVAL;
+		}
+	} else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
+			(480 == \
+			peasycap_format->v4l2_format.fmt.pix.height)) || \
+			((320 == \
+			peasycap_format->v4l2_format.fmt.pix.width) && \
+			(240 == \
+			peasycap_format->v4l2_format.fmt.pix.height))) {
+		if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
+			SAY("ERROR: set_resolution() failed\n");
+			return -EINVAL;
+		}
+	} else {
+		SAY("MISTAKE: bad format, cannot set resolution\n");
+		return -EINVAL;
+	}
+}
+/*---------------------------------------------------------------------------*/
+
+check_stk(peasycap->pusb_device);
+
+return (int)(peasycap_best_format - &easycap_format[0]);
+}
+/*****************************************************************************/
+int adjust_brightness(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+	if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
+		if ((easycap_control[i1].minimum > value) || \
+					(easycap_control[i1].maximum < value))
+			value = easycap_control[i1].default_value;
+		peasycap->brightness = value;
+		mood = 0x00FF & (unsigned int)peasycap->brightness;
+
+		set2to78(peasycap->pusb_device);
+
+		if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
+			SAY("adjusting brightness to  0x%02X\n", mood);
+			return 0;
+		} else {
+			SAY("WARNING: failed to adjust brightness " \
+							"to 0x%02X\n", mood);
+			return -ENOENT;
+		}
+
+		set2to78(peasycap->pusb_device);
+
+		break;
+	}
+	i1++;
+}
+SAY("WARNING: failed to adjust brightness: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_contrast(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+	if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
+		if ((easycap_control[i1].minimum > value) || \
+					(easycap_control[i1].maximum < value))
+			value = easycap_control[i1].default_value;
+		peasycap->contrast = value;
+		mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
+
+		set2to78(peasycap->pusb_device);
+
+		if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
+			SAY("adjusting contrast to  0x%02X\n", mood);
+			return 0;
+		} else {
+			SAY("WARNING: failed to adjust contrast to " \
+							"0x%02X\n", mood);
+			return -ENOENT;
+		}
+
+		set2to78(peasycap->pusb_device);
+
+		break;
+	}
+	i1++;
+}
+SAY("WARNING: failed to adjust contrast: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_saturation(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+	if (V4L2_CID_SATURATION == easycap_control[i1].id) {
+		if ((easycap_control[i1].minimum > value) || \
+					(easycap_control[i1].maximum < value))
+			value = easycap_control[i1].default_value;
+		peasycap->saturation = value;
+		mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
+
+		set2to78(peasycap->pusb_device);
+
+		if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
+			SAY("adjusting saturation to  0x%02X\n", mood);
+			return 0;
+		} else {
+			SAY("WARNING: failed to adjust saturation to " \
+							"0x%02X\n", mood);
+			return -ENOENT;
+		}
+		break;
+
+		set2to78(peasycap->pusb_device);
+
+	}
+	i1++;
+}
+SAY("WARNING: failed to adjust saturation: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_hue(struct easycap *peasycap, int value)
+{
+unsigned int mood;
+int i1, i2;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+	if (V4L2_CID_HUE == easycap_control[i1].id) {
+		if ((easycap_control[i1].minimum > value) || \
+					(easycap_control[i1].maximum < value))
+			value = easycap_control[i1].default_value;
+		peasycap->hue = value;
+		i2 = peasycap->hue - 128;
+		mood = 0x00FF & ((int) i2);
+
+		set2to78(peasycap->pusb_device);
+
+		if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
+			SAY("adjusting hue to  0x%02X\n", mood);
+			return 0;
+		} else {
+			SAY("WARNING: failed to adjust hue to 0x%02X\n", mood);
+			return -ENOENT;
+		}
+
+		set2to78(peasycap->pusb_device);
+
+		break;
+	}
+	i1++;
+}
+SAY("WARNING: failed to adjust hue: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+int adjust_volume(struct easycap *peasycap, int value)
+{
+__s8 mood;
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+	if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
+		if ((easycap_control[i1].minimum > value) || \
+			(easycap_control[i1].maximum < value))
+			value = easycap_control[i1].default_value;
+		peasycap->volume = value;
+		mood = (16 > peasycap->volume) ? 16 : \
+			((31 < peasycap->volume) ? 31 : \
+			(__s8) peasycap->volume);
+		if (!audio_gainset(peasycap->pusb_device, mood)) {
+			SAY("adjusting volume to 0x%01X\n", mood);
+			return 0;
+		} else {
+			SAY("WARNING: failed to adjust volume to " \
+							"0x%1X\n", mood);
+			return -ENOENT;
+		}
+		break;
+	}
+i1++;
+}
+SAY("WARNING: failed to adjust volume: control not found\n");
+return -ENOENT;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
+ *            usb_set_interface(peasycap->pusb_device, \
+ *                              peasycap->audio_interface, \
+ *                              peasycap->audio_altsetting_off);
+ *  HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
+ *  -ESHUTDOWN.  THE HANDLER ROUTINE easysnd_complete() DECLINES TO RESUBMIT
+ *  THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+int adjust_mute(struct easycap *peasycap, int value)
+{
+int i1;
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+i1 = 0;
+while (0xFFFFFFFF != easycap_control[i1].id) {
+	if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
+		peasycap->mute = value;
+		switch (peasycap->mute) {
+		case 1: {
+			peasycap->audio_idle = 1;
+			peasycap->timeval0.tv_sec = 0;
+			SAY("adjusting mute: %i=peasycap->audio_idle\n", \
+							peasycap->audio_idle);
+			return 0;
+		}
+		default: {
+			peasycap->audio_idle = 0;
+			SAY("adjusting mute: %i=peasycap->audio_idle\n", \
+							peasycap->audio_idle);
+			return 0;
+		}
+		}
+		break;
+	}
+	i1++;
+}
+SAY("WARNING: failed to adjust mute: control not found\n");
+return -ENOENT;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+long
+easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg)\
+									{
+	return easycap_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+int easycap_ioctl(struct inode *inode, struct file *file, \
+					unsigned int cmd, unsigned long arg)
+{
+static struct easycap *peasycap;
+static struct usb_device *p;
+static __u32 isequence;
+
+peasycap = (struct easycap *)file->private_data;
+if (NULL == peasycap) {
+	SAY("ERROR:  peasycap is NULL\n");
+	return -1;
+}
+p = peasycap->pusb_device;
+if ((struct usb_device *)NULL == p) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  MOST OF THE VARIABLES DECLARED static IN THE case{} BLOCKS BELOW ARE SO
+ *  DECLARED SIMPLY TO AVOID A COMPILER WARNING OF THE KIND:
+ *  easycap_ioctl.c: warning:
+ *                       the frame size of ... bytes is larger than 1024 bytes
+ */
+/*---------------------------------------------------------------------------*/
+switch (cmd) {
+case VIDIOC_QUERYCAP: {
+	static struct v4l2_capability v4l2_capability;
+	static char version[16], *p1, *p2;
+	static int i, rc, k[3];
+	static long lng;
+
+	JOT(8, "VIDIOC_QUERYCAP\n");
+
+	if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
+		SAY("ERROR: bad driver version string\n"); return -EINVAL;
+	}
+	strcpy(&version[0], EASYCAP_DRIVER_VERSION);
+	for (i = 0; i < 3; i++)
+		k[i] = 0;
+	p2 = &version[0];  i = 0;
+	while (*p2) {
+		p1 = p2;
+		while (*p2 && ('.' != *p2))
+			p2++;
+		if (*p2)
+			*p2++ = 0;
+		if (3 > i) {
+			rc = (int) strict_strtol(p1, 10, &lng);
+			if (0 != rc) {
+				SAY("ERROR: %i=strict_strtol(%s,.,,)\n", \
+								rc, p1);
+				return -EINVAL;
+			}
+			k[i] = (int)lng;
+		}
+		i++;
+	}
+
+	memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
+	strlcpy(&v4l2_capability.driver[0], "easycap", \
+					sizeof(v4l2_capability.driver));
+
+	v4l2_capability.capabilities = \
+				V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
+				V4L2_CAP_AUDIO         | V4L2_CAP_READWRITE;
+
+	v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
+	JOT(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
+
+	strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \
+		sizeof(v4l2_capability.card));
+
+	if (usb_make_path(peasycap->pusb_device, &v4l2_capability.bus_info[0],\
+				sizeof(v4l2_capability.bus_info)) < 0) {
+		strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \
+					sizeof(v4l2_capability.bus_info));
+		JOT(8, "%s=v4l2_capability.bus_info\n", \
+					&v4l2_capability.bus_info[0]);
+	}
+	if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
+					sizeof(struct v4l2_capability))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUMINPUT: {
+	static struct v4l2_input v4l2_input;
+	static __u32 index;
+
+	JOT(8, "VIDIOC_ENUMINPUT\n");
+
+	if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
+					sizeof(struct v4l2_input))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	index = v4l2_input.index;
+	memset(&v4l2_input, 0, sizeof(struct v4l2_input));
+
+	switch (index) {
+	case 0: {
+		v4l2_input.index = index;
+		strcpy(&v4l2_input.name[0], "CVBS0");
+		v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+		v4l2_input.audioset = 0x01;
+		v4l2_input.tuner = 0;
+		v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+				V4L2_STD_NTSC ;
+		v4l2_input.status = 0;
+		JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+		break;
+	}
+	case 1: {
+		v4l2_input.index = index;
+		strcpy(&v4l2_input.name[0], "CVBS1");
+		v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+		v4l2_input.audioset = 0x01;
+		v4l2_input.tuner = 0;
+		v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+				V4L2_STD_NTSC ;
+		v4l2_input.status = 0;
+		JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+		break;
+	}
+	case 2: {
+		v4l2_input.index = index;
+		strcpy(&v4l2_input.name[0], "CVBS2");
+		v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+		v4l2_input.audioset = 0x01;
+		v4l2_input.tuner = 0;
+		v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+				V4L2_STD_NTSC ;
+		v4l2_input.status = 0;
+		JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+		break;
+	}
+	case 3: {
+		v4l2_input.index = index;
+		strcpy(&v4l2_input.name[0], "CVBS3");
+		v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+		v4l2_input.audioset = 0x01;
+		v4l2_input.tuner = 0;
+		v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+				V4L2_STD_NTSC ;
+		v4l2_input.status = 0;
+		JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+		break;
+	}
+	case 4: {
+		v4l2_input.index = index;
+		strcpy(&v4l2_input.name[0], "CVBS4");
+		v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+		v4l2_input.audioset = 0x01;
+		v4l2_input.tuner = 0;
+		v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+				V4L2_STD_NTSC ;
+		v4l2_input.status = 0;
+		JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+		break;
+	}
+	case 5: {
+		v4l2_input.index = index;
+		strcpy(&v4l2_input.name[0], "S-VIDEO");
+		v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
+		v4l2_input.audioset = 0x01;
+		v4l2_input.tuner = 0;
+		v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
+				V4L2_STD_NTSC ;
+		v4l2_input.status = 0;
+		JOT(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
+		break;
+	}
+	default: {
+		JOT(8, "%i=index: exhausts inputs\n", index);
+		return -EINVAL;
+	}
+	}
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
+						sizeof(struct v4l2_input))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_INPUT: {
+	static __u32 index;
+
+	JOT(8, "VIDIOC_G_INPUT\n");
+	index = (__u32)peasycap->input;
+	JOT(8, "user is told: %i\n", index);
+	if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_INPUT:
+	{
+	static __u32 index;
+
+	JOT(8, "VIDIOC_S_INPUT\n");
+
+	if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	JOT(8, "user requests input %i\n", index);
+
+	if ((int)index == peasycap->input) {
+		SAY("requested input already in effect\n");
+		break;
+	}
+
+	if ((0 > index) || (5 < index)) {
+		JOT(8, "ERROR:  bad requested input: %i\n", index);
+		return -EINVAL;
+	}
+	peasycap->input = (int)index;
+
+	select_input(peasycap->pusb_device, peasycap->input, 9);
+
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUMAUDIO: {
+	JOT(8, "VIDIOC_ENUMAUDIO\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUMAUDOUT: {
+	static struct v4l2_audioout v4l2_audioout;
+
+	JOT(8, "VIDIOC_ENUMAUDOUT\n");
+
+	if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
+					sizeof(struct v4l2_audioout))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (0 != v4l2_audioout.index)
+		return -EINVAL;
+	memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
+	v4l2_audioout.index = 0;
+	strcpy(&v4l2_audioout.name[0], "Soundtrack");
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
+					sizeof(struct v4l2_audioout))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYCTRL: {
+	static int i1;
+	static struct v4l2_queryctrl v4l2_queryctrl;
+
+	JOT(8, "VIDIOC_QUERYCTRL\n");
+
+	if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
+					sizeof(struct v4l2_queryctrl))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	i1 = 0;
+	while (0xFFFFFFFF != easycap_control[i1].id) {
+		if (easycap_control[i1].id == v4l2_queryctrl.id) {
+			JOT(8, "VIDIOC_QUERYCTRL  %s=easycap_control[%i]" \
+				".name\n", &easycap_control[i1].name[0], i1);
+			memcpy(&v4l2_queryctrl, &easycap_control[i1], \
+						sizeof(struct v4l2_queryctrl));
+			break;
+		}
+		i1++;
+	}
+	if (0xFFFFFFFF == easycap_control[i1].id) {
+		JOT(8, "%i=index: exhausts controls\n", i1);
+		return -EINVAL;
+	}
+	if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
+					sizeof(struct v4l2_queryctrl))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYMENU: {
+	JOT(8, "VIDIOC_QUERYMENU unsupported\n");
+	return -EINVAL;
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_CTRL: {
+	static struct v4l2_control v4l2_control;
+
+	JOT(8, "VIDIOC_G_CTRL\n");
+
+	if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
+					sizeof(struct v4l2_control))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	switch (v4l2_control.id) {
+	case V4L2_CID_BRIGHTNESS: {
+		v4l2_control.value = peasycap->brightness;
+		JOT(8, "user enquires brightness: %i\n", v4l2_control.value);
+		break;
+	}
+	case V4L2_CID_CONTRAST: {
+		v4l2_control.value = peasycap->contrast;
+		JOT(8, "user enquires contrast: %i\n", v4l2_control.value);
+		break;
+	}
+	case V4L2_CID_SATURATION: {
+		v4l2_control.value = peasycap->saturation;
+		JOT(8, "user enquires saturation: %i\n", v4l2_control.value);
+		break;
+	}
+	case V4L2_CID_HUE: {
+		v4l2_control.value = peasycap->hue;
+		JOT(8, "user enquires hue: %i\n", v4l2_control.value);
+		break;
+	}
+	case V4L2_CID_AUDIO_VOLUME: {
+		v4l2_control.value = peasycap->volume;
+		JOT(8, "user enquires volume: %i\n", v4l2_control.value);
+		break;
+	}
+	case V4L2_CID_AUDIO_MUTE: {
+		if (1 == peasycap->mute)
+			v4l2_control.value = true;
+		else
+			v4l2_control.value = false;
+		JOT(8, "user enquires mute: %i\n", v4l2_control.value);
+		break;
+	}
+	default: {
+		SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
+							v4l2_control.id);
+		explain_cid(v4l2_control.id);
+		return -EINVAL;
+	}
+	}
+	if (0 != copy_to_user((void __user *)arg, &v4l2_control, \
+					sizeof(struct v4l2_control))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#if defined(VIDIOC_S_CTRL_OLD)
+case VIDIOC_S_CTRL_OLD: {
+	JOT(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n");
+}
+#endif /*VIDIOC_S_CTRL_OLD*/
+case VIDIOC_S_CTRL:
+	{
+	static struct v4l2_control v4l2_control;
+
+	JOT(8, "VIDIOC_S_CTRL\n");
+
+	if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
+					sizeof(struct v4l2_control))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	switch (v4l2_control.id) {
+	case V4L2_CID_BRIGHTNESS: {
+		JOT(8, "user requests brightness %i\n", v4l2_control.value);
+		if (0 != adjust_brightness(peasycap, v4l2_control.value))
+			;
+		break;
+	}
+	case V4L2_CID_CONTRAST: {
+		JOT(8, "user requests contrast %i\n", v4l2_control.value);
+		if (0 != adjust_contrast(peasycap, v4l2_control.value))
+			;
+		break;
+	}
+	case V4L2_CID_SATURATION: {
+		JOT(8, "user requests saturation %i\n", v4l2_control.value);
+		if (0 != adjust_saturation(peasycap, v4l2_control.value))
+			;
+		break;
+	}
+	case V4L2_CID_HUE: {
+		JOT(8, "user requests hue %i\n", v4l2_control.value);
+		if (0 != adjust_hue(peasycap, v4l2_control.value))
+			;
+		break;
+	}
+	case V4L2_CID_AUDIO_VOLUME: {
+		JOT(8, "user requests volume %i\n", v4l2_control.value);
+		if (0 != adjust_volume(peasycap, v4l2_control.value))
+			;
+		break;
+	}
+	case V4L2_CID_AUDIO_MUTE: {
+		int mute;
+
+		JOT(8, "user requests mute %i\n", v4l2_control.value);
+		if (true == v4l2_control.value)
+			mute = 1;
+		else
+			mute = 0;
+
+		if (0 != adjust_mute(peasycap, mute))
+			SAY("WARNING: failed to adjust mute to %i\n", mute);
+		break;
+	}
+	default: {
+		SAY("ERROR: unknown V4L2 control: 0x%08X=id\n", \
+							v4l2_control.id);
+		explain_cid(v4l2_control.id);
+	return -EINVAL;
+			}
+		}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_EXT_CTRLS: {
+	JOT(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUM_FMT: {
+	static __u32 index;
+	static struct v4l2_fmtdesc v4l2_fmtdesc;
+
+	JOT(8, "VIDIOC_ENUM_FMT\n");
+
+	if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
+					sizeof(struct v4l2_fmtdesc))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	index = v4l2_fmtdesc.index;
+	memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
+
+	v4l2_fmtdesc.index = index;
+	v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	switch (index) {
+	case 0: {
+		v4l2_fmtdesc.flags = 0;
+		strcpy(&v4l2_fmtdesc.description[0], "uyvy");
+		v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
+		JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+		break;
+	}
+	case 1: {
+		v4l2_fmtdesc.flags = 0;
+		strcpy(&v4l2_fmtdesc.description[0], "yuy2");
+		v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
+		JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+		break;
+	}
+	case 2: {
+		v4l2_fmtdesc.flags = 0;
+		strcpy(&v4l2_fmtdesc.description[0], "rgb24");
+		v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
+		JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+		break;
+	}
+	case 3: {
+		v4l2_fmtdesc.flags = 0;
+		strcpy(&v4l2_fmtdesc.description[0], "rgb32");
+		v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
+		JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+		break;
+	}
+	case 4: {
+		v4l2_fmtdesc.flags = 0;
+		strcpy(&v4l2_fmtdesc.description[0], "bgr24");
+		v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
+		JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+		break;
+	}
+	case 5: {
+		v4l2_fmtdesc.flags = 0;
+		strcpy(&v4l2_fmtdesc.description[0], "bgr32");
+		v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
+		JOT(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
+		break;
+	}
+	default: {
+		JOT(8, "%i=index: exhausts formats\n", index);
+		return -EINVAL;
+	}
+	}
+	if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
+					sizeof(struct v4l2_fmtdesc))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_ENUM_FRAMESIZES: {
+	JOT(8, "VIDIOC_ENUM_FRAMESIZES unsupported\n");
+	return -EINVAL;
+}
+case VIDIOC_ENUM_FRAMEINTERVALS: {
+	JOT(8, "VIDIOC_ENUM_FRAME_INTERVALS unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_FMT: {
+	static struct v4l2_format v4l2_format;
+	static struct v4l2_pix_format v4l2_pix_format;
+
+	JOT(8, "VIDIOC_G_FMT\n");
+
+	if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
+					sizeof(struct v4l2_format))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		POUT;
+		return -EINVAL;
+	}
+
+	memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+	v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	memcpy(&(v4l2_format.fmt.pix), \
+			 &(easycap_format[peasycap->format_offset]\
+			.v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
+	JOT(8, "user is told: %s\n", \
+			&easycap_format[peasycap->format_offset].name[0]);
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
+					sizeof(struct v4l2_format))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_TRY_FMT:
+case VIDIOC_S_FMT: {
+	static struct v4l2_format v4l2_format;
+	static struct v4l2_pix_format v4l2_pix_format;
+	static bool try;
+	static int best_format;
+
+	if (VIDIOC_TRY_FMT == cmd) {
+		JOT(8, "VIDIOC_TRY_FMT\n");
+		try = true;
+	} else {
+		JOT(8, "VIDIOC_S_FMT\n");
+		try = false;
+	}
+
+	if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
+					sizeof(struct v4l2_format))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	best_format = adjust_format(peasycap, \
+					v4l2_format.fmt.pix.width, \
+					v4l2_format.fmt.pix.height, \
+					v4l2_format.fmt.pix.pixelformat, \
+					v4l2_format.fmt.pix.field, \
+					try);
+	if (0 > best_format) {
+		JOT(8, "WARNING: adjust_format() returned %i\n", best_format);
+		return -ENOENT;
+	}
+/*...........................................................................*/
+	memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
+	v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\
+			.v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
+	JOT(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
+					sizeof(struct v4l2_format))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_CROPCAP: {
+	static struct v4l2_cropcap v4l2_cropcap;
+
+	JOT(8, "VIDIOC_CROPCAP\n");
+
+	if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
+					sizeof(struct v4l2_cropcap))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		JOT(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+
+	memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
+	v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	v4l2_cropcap.bounds.left      = 0;
+	v4l2_cropcap.bounds.top       = 0;
+	v4l2_cropcap.bounds.width     = peasycap->width;
+	v4l2_cropcap.bounds.height    = peasycap->height;
+	v4l2_cropcap.defrect.left     = 0;
+	v4l2_cropcap.defrect.top      = 0;
+	v4l2_cropcap.defrect.width    = peasycap->width;
+	v4l2_cropcap.defrect.height   = peasycap->height;
+	v4l2_cropcap.pixelaspect.numerator = 1;
+	v4l2_cropcap.pixelaspect.denominator = 1;
+
+	JOT(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
+					sizeof(struct v4l2_cropcap))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_CROP:
+case VIDIOC_S_CROP: {
+	JOT(8, "VIDIOC_G_CROP|VIDIOC_S_CROP  unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYSTD: {
+	JOT(8, "VIDIOC_QUERYSTD: " \
+			"EasyCAP is incapable of detecting standard\n");
+	return -EINVAL;
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE MANIPULATIONS INVOLVING last0,last1,last2,last3 CONSTITUTE A WORKAROUND
+ *  FOR WHAT APPEARS TO BE A BUG IN 64-BIT mplayer.
+ *  NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
+ */
+/*---------------------------------------------------------------------------*/
+case VIDIOC_ENUMSTD: {
+	static int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
+	static struct v4l2_standard v4l2_standard;
+	static __u32 index;
+	static struct easycap_standard *peasycap_standard;
+
+	JOT(8, "VIDIOC_ENUMSTD\n");
+
+	if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
+					sizeof(struct v4l2_standard))) {
+		POUT;
+		return -EFAULT;
+	}
+	index = v4l2_standard.index;
+
+	last3 = last2; last2 = last1; last1 = last0; last0 = index;
+	if ((index == last3) && (index == last2) && \
+			(index == last1) && (index == last0)) {
+		index++;
+		last3 = last2; last2 = last1; last1 = last0; last0 = index;
+	}
+
+	memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
+
+	peasycap_standard = &easycap_standard[0];
+	while (0xFFFF != peasycap_standard->mask) {
+		if ((int)(peasycap_standard - &easycap_standard[0]) == index)
+			break;
+		peasycap_standard++;
+	}
+	if (0xFFFF == peasycap_standard->mask) {
+		JOT(8, "%i=index: exhausts standards\n", index);
+		return -EINVAL;
+	}
+	JOT(8, "%i=index: %s\n", index, \
+				&(peasycap_standard->v4l2_standard.name[0]));
+	peasycap_standard->v4l2_standard.index = index;
+	v4l2_standard.index = index;
+
+	if (0 != copy_to_user((void __user *)arg, \
+					&(peasycap_standard->v4l2_standard), \
+					sizeof(struct v4l2_standard))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_STD: {
+	static v4l2_std_id std_id;
+	static struct easycap_standard *peasycap_standard;
+
+	JOT(8, "VIDIOC_G_STD\n");
+
+	if (0 != copy_from_user(&std_id, (void __user *)arg, \
+						sizeof(v4l2_std_id))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	peasycap_standard = &easycap_standard[peasycap->standard_offset];
+	std_id = peasycap_standard->v4l2_standard.id;
+
+	JOT(8, "user is told: %s\n", \
+				&peasycap_standard->v4l2_standard.name[0]);
+
+	if (0 != copy_to_user((void __user *)arg, &std_id, \
+						sizeof(v4l2_std_id))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_STD: {
+	static v4l2_std_id std_id;
+	static int rc;
+
+	JOT(8, "VIDIOC_S_STD\n");
+
+	if (0 != copy_from_user(&std_id, (void __user *)arg, \
+						sizeof(v4l2_std_id))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	rc = adjust_standard(peasycap, std_id);
+	if (0 > rc) {
+		JOT(8, "WARNING: adjust_standard() returned %i\n", rc);
+		return -ENOENT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_REQBUFS: {
+	static int nbuffers;
+	static struct v4l2_requestbuffers v4l2_requestbuffers;
+
+	JOT(8, "VIDIOC_REQBUFS\n");
+
+	if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
+				sizeof(struct v4l2_requestbuffers))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
+		POUT;
+		return -EINVAL;
+	}
+	nbuffers = v4l2_requestbuffers.count;
+	JOT(8, "                   User requests %i buffers ...\n", nbuffers);
+	if (nbuffers < 2)
+		nbuffers = 2;
+	if (nbuffers > FRAME_BUFFER_MANY)
+		nbuffers = FRAME_BUFFER_MANY;
+	if (v4l2_requestbuffers.count == nbuffers) {
+		JOT(8, "                   ... agree to  %i buffers\n", \
+								nbuffers);
+	} else {
+		JOT(8, "                  ... insist on  %i buffers\n", \
+								nbuffers);
+		v4l2_requestbuffers.count = nbuffers;
+	}
+	peasycap->frame_buffer_many = nbuffers;
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
+				sizeof(struct v4l2_requestbuffers))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QUERYBUF: {
+	static __u32 index;
+	static struct v4l2_buffer v4l2_buffer;
+
+	JOT(8, "VIDIOC_QUERYBUF\n");
+
+	if (peasycap->video_eof) {
+		JOT(8, "returning -1 because  %i=video_eof\n", \
+							peasycap->video_eof);
+		return -1;
+	}
+
+	if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
+					sizeof(struct v4l2_buffer))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	index = v4l2_buffer.index;
+	if (index < 0 || index >= peasycap->frame_buffer_many)
+		return -EINVAL;
+	memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
+	v4l2_buffer.index = index;
+	v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	v4l2_buffer.bytesused = peasycap->frame_buffer_used;
+	v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \
+						peasycap->done[index] | \
+						peasycap->queued[index];
+	v4l2_buffer.field = peasycap->field;
+	v4l2_buffer.memory = V4L2_MEMORY_MMAP;
+	v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
+	v4l2_buffer.length = FRAME_BUFFER_SIZE;
+
+	JOT(16, "  %10i=index\n", v4l2_buffer.index);
+	JOT(16, "  0x%08X=type\n", v4l2_buffer.type);
+	JOT(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
+	JOT(16, "  0x%08X=flags\n", v4l2_buffer.flags);
+	JOT(16, "  %10i=field\n", v4l2_buffer.field);
+	JOT(16, "  %10li=timestamp.tv_usec\n", \
+					 (long)v4l2_buffer.timestamp.tv_usec);
+	JOT(16, "  %10i=sequence\n", v4l2_buffer.sequence);
+	JOT(16, "  0x%08X=memory\n", v4l2_buffer.memory);
+	JOT(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
+	JOT(16, "  %10i=length\n", v4l2_buffer.length);
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
+					sizeof(struct v4l2_buffer))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_QBUF: {
+	static struct v4l2_buffer v4l2_buffer;
+
+	JOT(8, "VIDIOC_QBUF\n");
+
+	if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
+					sizeof(struct v4l2_buffer))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (v4l2_buffer.memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+	if (v4l2_buffer.index < 0 || \
+		 (v4l2_buffer.index >= peasycap->frame_buffer_many))
+		return -EINVAL;
+	v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
+
+	peasycap->done[v4l2_buffer.index]   = 0;
+	peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
+					sizeof(struct v4l2_buffer))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	JOT(8, ".....   user queueing frame buffer %i\n", \
+						(int)v4l2_buffer.index);
+
+	peasycap->frame_lock = 0;
+
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_DQBUF:
+	{
+#if defined(AUDIOTIME)
+	static struct signed_div_result sdr;
+	static long long int above, below, dnbydt, fudge, sll;
+	static unsigned long long int ull;
+	static struct timeval timeval0;
+	struct timeval timeval1;
+#endif /*AUDIOTIME*/
+	static struct timeval timeval, timeval2;
+	static int i, j;
+	static struct v4l2_buffer v4l2_buffer;
+
+	JOT(8, "VIDIOC_DQBUF\n");
+
+	if ((peasycap->video_idle) || (peasycap->video_eof)) {
+		JOT(8, "returning -EIO because  " \
+				"%i=video_idle  %i=video_eof\n", \
+				peasycap->video_idle, peasycap->video_eof);
+		return -EIO;
+	}
+
+	if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
+					sizeof(struct v4l2_buffer))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (!peasycap->video_isoc_streaming) {
+		JOT(16, "returning -EIO because video urbs not streaming\n");
+		return -EIO;
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), AS DETERMINED BY FINDING
+ *  THE FLAG peasycap->polled SET, THERE MUST BE NO FURTHER WAIT HERE.  IN THIS
+ *  CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
+ */
+/*---------------------------------------------------------------------------*/
+
+	if (!peasycap->polled) {
+		if (-EIO == easycap_dqbuf(peasycap, 0))
+			return -EIO;
+	} else {
+		if (peasycap->video_eof)
+			return -EIO;
+	}
+	if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
+		SAY("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
+					peasycap->done[peasycap->frame_read]);
+	}
+	peasycap->polled = 0;
+
+	if (!(isequence % 10)) {
+		for (i = 0; i < 179; i++)
+			peasycap->merit[i] = peasycap->merit[i+1];
+		peasycap->merit[179] = merit_saa(peasycap->pusb_device);
+		j = 0;
+		for (i = 0; i < 180; i++)
+			j += peasycap->merit[i];
+		if (90 < j) {
+			SAY("easycap driver shutting down " \
+							"on condition blue\n");
+			peasycap->video_eof = 1; peasycap->audio_eof = 1;
+		}
+	}
+
+	v4l2_buffer.index = peasycap->frame_read;
+	v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	v4l2_buffer.bytesused = peasycap->frame_buffer_used;
+	v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
+	v4l2_buffer.field =  peasycap->field;
+	if (V4L2_FIELD_ALTERNATE == v4l2_buffer.field)
+		v4l2_buffer.field = \
+				0x000F & (peasycap->\
+				frame_buffer[peasycap->frame_read][0].kount);
+	do_gettimeofday(&timeval);
+	timeval2 = timeval;
+
+#if defined(AUDIOTIME)
+	if (!peasycap->timeval0.tv_sec) {
+		timeval0 = timeval;
+		timeval1 = timeval;
+		timeval2 = timeval;
+		dnbydt = 192000;
+
+		if (mutex_lock_interruptible(&(peasycap->mutex_timeval0)))
+			return -ERESTARTSYS;
+		peasycap->timeval0 = timeval0;
+		mutex_unlock(&(peasycap->mutex_timeval0));
+	} else {
+		if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
+			return -ERESTARTSYS;
+		dnbydt = peasycap->dnbydt;
+		timeval1 = peasycap->timeval1;
+		mutex_unlock(&(peasycap->mutex_timeval1));
+		above = dnbydt * MICROSECONDS(timeval, timeval1);
+		below = 192000;
+		sdr = signed_div(above, below);
+
+		above = sdr.quotient + timeval1.tv_usec - 350000;
+
+		below = 1000000;
+		sdr = signed_div(above, below);
+		timeval2.tv_usec = sdr.remainder;
+		timeval2.tv_sec = timeval1.tv_sec + sdr.quotient;
+	}
+	if (!(isequence % 500)) {
+		fudge = ((long long int)(1000000)) * \
+				((long long int)(timeval.tv_sec - \
+						timeval2.tv_sec)) + \
+				(long long int)(timeval.tv_usec - \
+				timeval2.tv_usec);
+		sdr = signed_div(fudge, 1000);
+		sll = sdr.quotient;
+		ull = sdr.remainder;
+
+		SAY("%5lli.%-3lli=ms timestamp fudge\n", sll, ull);
+	}
+#endif /*AUDIOTIME*/
+
+	v4l2_buffer.timestamp = timeval2;
+	v4l2_buffer.sequence = isequence++;
+	v4l2_buffer.memory = V4L2_MEMORY_MMAP;
+	v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
+	v4l2_buffer.length = FRAME_BUFFER_SIZE;
+
+	JOT(16, "  %10i=index\n", v4l2_buffer.index);
+	JOT(16, "  0x%08X=type\n", v4l2_buffer.type);
+	JOT(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
+	JOT(16, "  0x%08X=flags\n", v4l2_buffer.flags);
+	JOT(16, "  %10i=field\n", v4l2_buffer.field);
+	JOT(16, "  %10li=timestamp.tv_usec\n", \
+					(long)v4l2_buffer.timestamp.tv_usec);
+	JOT(16, "  %10i=sequence\n", v4l2_buffer.sequence);
+	JOT(16, "  0x%08X=memory\n", v4l2_buffer.memory);
+	JOT(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
+	JOT(16, "  %10i=length\n", v4l2_buffer.length);
+
+	if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
+						sizeof(struct v4l2_buffer))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	JOT(8, "..... user is offered frame buffer %i\n", \
+							peasycap->frame_read);
+	peasycap->frame_lock = 1;
+	if (peasycap->frame_read == peasycap->frame_fill) {
+		if (peasycap->frame_lock) {
+			JOT(8, "ERROR:  filling frame buffer " \
+						"while offered to user\n");
+		}
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*---------------------------------------------------------------------------*/
+/*
+ *  AUDIO URBS HAVE ALREADY BEEN SUBMITTED WHEN THIS COMMAND IS RECEIVED;
+ *  VIDEO URBS HAVE NOT.
+ */
+/*---------------------------------------------------------------------------*/
+case VIDIOC_STREAMON: {
+	static int i;
+
+	JOT(8, "VIDIOC_STREAMON\n");
+
+	isequence = 0;
+	for (i = 0; i < 180; i++)
+		peasycap->merit[i] = 0;
+	if ((struct usb_device *)NULL == peasycap->pusb_device) {
+		SAY("ERROR: peasycap->pusb_device is NULL\n");
+		return -EFAULT;
+	}
+	submit_video_urbs(peasycap);
+	peasycap->video_idle = 0;
+	peasycap->audio_idle = 0;
+	peasycap->video_eof = 0;
+	peasycap->audio_eof = 0;
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_STREAMOFF: {
+	JOT(8, "VIDIOC_STREAMOFF\n");
+
+	if ((struct usb_device *)NULL == peasycap->pusb_device) {
+		SAY("ERROR: peasycap->pusb_device is NULL\n");
+		return -EFAULT;
+	}
+
+	peasycap->video_idle = 1;
+	peasycap->audio_idle = 1;  peasycap->timeval0.tv_sec = 0;
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
+ *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+	JOT(8, "calling wake_up on wq_video and wq_audio\n");
+	wake_up_interruptible(&(peasycap->wq_video));
+	wake_up_interruptible(&(peasycap->wq_audio));
+/*---------------------------------------------------------------------------*/
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_PARM: {
+	static struct v4l2_streamparm v4l2_streamparm;
+
+	JOT(8, "VIDIOC_G_PARM\n");
+
+	if (0 != copy_from_user(&v4l2_streamparm, (void __user *)arg, \
+					sizeof(struct v4l2_streamparm))) {
+		POUT;
+		return -EFAULT;
+	}
+
+	if (v4l2_streamparm.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		POUT;
+		return -EINVAL;
+	}
+	v4l2_streamparm.parm.capture.capability = 0;
+	v4l2_streamparm.parm.capture.capturemode = 0;
+	v4l2_streamparm.parm.capture.timeperframe.numerator = 1;
+	v4l2_streamparm.parm.capture.timeperframe.denominator = 30;
+	v4l2_streamparm.parm.capture.readbuffers = peasycap->frame_buffer_many;
+	v4l2_streamparm.parm.capture.extendedmode = 0;
+	if (0 != copy_to_user((void __user *)arg, &v4l2_streamparm, \
+					sizeof(struct v4l2_streamparm))) {
+		POUT;
+		return -EFAULT;
+	}
+	break;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_PARM: {
+	JOT(8, "VIDIOC_S_PARM unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_AUDIO: {
+	JOT(8, "VIDIOC_G_AUDIO unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_AUDIO: {
+	JOT(8, "VIDIOC_S_AUDIO unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_S_TUNER: {
+	JOT(8, "VIDIOC_S_TUNER unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_FBUF:
+case VIDIOC_S_FBUF:
+case VIDIOC_OVERLAY: {
+	JOT(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+case VIDIOC_G_TUNER: {
+	JOT(8, "VIDIOC_G_TUNER unsupported\n");
+	return -EINVAL;
+}
+case VIDIOC_G_FREQUENCY:
+case VIDIOC_S_FREQUENCY: {
+	JOT(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
+	return -EINVAL;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+default: {
+	JOT(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
+	explain_ioctl(cmd);
+	POUT;
+	return -ENOIOCTLCMD;
+}
+}
+return 0;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+long
+easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	return easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+int easysnd_ioctl(struct inode *inode, struct file *file, \
+					unsigned int cmd, unsigned long arg)
+{
+struct easycap *peasycap;
+struct usb_device *p;
+
+peasycap = (struct easycap *)file->private_data;
+if (NULL == peasycap) {
+	SAY("ERROR:  peasycap is NULL.\n");
+	return -1;
+}
+p = peasycap->pusb_device;
+/*---------------------------------------------------------------------------*/
+switch (cmd) {
+case SNDCTL_DSP_GETCAPS: {
+	int caps;
+	JOT(8, "SNDCTL_DSP_GETCAPS\n");
+
+	if (true == peasycap->microphone)
+		caps = 0x02400000;
+	else
+		caps = 0x04400000;
+
+	if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int)))
+		return -EFAULT;
+	break;
+}
+case SNDCTL_DSP_GETFMTS: {
+	int incoming;
+	JOT(8, "SNDCTL_DSP_GETFMTS\n");
+
+	if (true == peasycap->microphone)
+		incoming = AFMT_S16_LE;
+	else
+		incoming = AFMT_S16_LE;
+
+	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+		return -EFAULT;
+	break;
+}
+case SNDCTL_DSP_SETFMT: {
+	int incoming, outgoing;
+	JOT(8, "SNDCTL_DSP_SETFMT\n");
+	if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+		return -EFAULT;
+	JOT(8, "........... %i=incoming\n", incoming);
+
+	if (true == peasycap->microphone)
+		outgoing = AFMT_S16_LE;
+	else
+		outgoing = AFMT_S16_LE;
+
+	if (incoming != outgoing) {
+		JOT(8, "........... %i=outgoing\n", outgoing);
+		JOT(8, "        cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
+		JOT(8, "        cf. %i=AFMT_U8\n", AFMT_U8);
+		if (0 != copy_to_user((void __user *)arg, &outgoing, \
+								sizeof(int)))
+			return -EFAULT;
+		return -EINVAL ;
+	}
+	break;
+}
+case SNDCTL_DSP_STEREO: {
+	int incoming;
+	JOT(8, "SNDCTL_DSP_STEREO\n");
+	if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+		return -EFAULT;
+	JOT(8, "........... %i=incoming\n", incoming);
+
+	if (true == peasycap->microphone)
+		incoming = 0;
+	else
+		incoming = 1;
+
+	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+		return -EFAULT;
+	break;
+}
+case SNDCTL_DSP_SPEED: {
+	int incoming;
+	JOT(8, "SNDCTL_DSP_SPEED\n");
+	if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+		return -EFAULT;
+	JOT(8, "........... %i=incoming\n", incoming);
+
+	if (true == peasycap->microphone)
+		incoming = 8000;
+	else
+		incoming = 48000;
+
+	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+		return -EFAULT;
+	break;
+}
+case SNDCTL_DSP_GETTRIGGER: {
+	int incoming;
+	JOT(8, "SNDCTL_DSP_GETTRIGGER\n");
+	if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+		return -EFAULT;
+	JOT(8, "........... %i=incoming\n", incoming);
+
+	incoming = PCM_ENABLE_INPUT;
+	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+		return -EFAULT;
+	break;
+}
+case SNDCTL_DSP_SETTRIGGER: {
+	int incoming;
+	JOT(8, "SNDCTL_DSP_SETTRIGGER\n");
+	if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+		return -EFAULT;
+	JOT(8, "........... %i=incoming\n", incoming);
+	JOT(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
+				"0x%x=PCM_ENABLE_OUTPUT\n", \
+					PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
+	;
+	;
+	;
+	;
+	break;
+}
+case SNDCTL_DSP_GETBLKSIZE: {
+	int incoming;
+	JOT(8, "SNDCTL_DSP_GETBLKSIZE\n");
+	if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+		return -EFAULT;
+	JOT(8, "........... %i=incoming\n", incoming);
+	incoming = audio_bytes_per_fragment;
+	if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+		return -EFAULT;
+	break;
+}
+case SNDCTL_DSP_GETISPACE: {
+	struct audio_buf_info audio_buf_info;
+
+	JOT(8, "SNDCTL_DSP_GETISPACE\n");
+
+	audio_buf_info.bytes      = audio_bytes_per_fragment;
+	audio_buf_info.fragments  = 1;
+	audio_buf_info.fragsize   = 0;
+	audio_buf_info.fragstotal = 0;
+
+	if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
+								sizeof(int)))
+		return -EFAULT;
+	break;
+}
+default: {
+	JOT(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
+	POUT;
+	return -ENOIOCTLCMD;
+}
+}
+return 0;
+}
+/*****************************************************************************/
+int explain_ioctl(__u32 wot)
+{
+int k;
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
+ *  SHELL SCRIPT:
+ *  #
+ *  cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
+ *     grep "^#define VIDIOC_" - | grep -v "_OLD" - | \
+ *     sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
+ *     sed -e "s/^#define /  {/;s/#define /, \"/;s/$/\"},/" | \
+ *     sed -e "s,	,,g;s, ,,g" >ioctl.tmp
+ *  echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
+ *  exit 0
+ *  #
+ * AND REINSTATING THE EXCISED "_OLD" CASES WERE LATER MANUALLY.
+ *
+ * THE DATA FOR THE ARRAY mess1 BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
+ * SHELL SCRIPT:
+ *  cat /usr/src/linux-headers-`uname -r`/include/linux/videodev.h | \
+ *     grep "^#define VIDIOC" - | grep -v "_OLD" - | \
+ *     sed -e "s,_IO.*$,,;p" | sed -e "N;s,\n,, " | \
+ *     sed -e "s/^#define /  {/;s/#define /, \"/;s/$/\"},/" | \
+ *     sed -e "s,   ,,g;s, ,,g" >ioctl.tmp
+ *  echo "{0xFFFFFFFF,\"\"}" >>ioctl.tmp
+ *  exit 0
+ *  #
+ */
+/*---------------------------------------------------------------------------*/
+static struct mess {
+	__u32 command;
+	char  name[64];
+} mess[] = {
+#if defined(VIDIOC_QUERYCAP)
+{VIDIOC_QUERYCAP, "VIDIOC_QUERYCAP"},
+#endif
+#if defined(VIDIOC_RESERVED)
+{VIDIOC_RESERVED, "VIDIOC_RESERVED"},
+#endif
+#if defined(VIDIOC_ENUM_FMT)
+{VIDIOC_ENUM_FMT, "VIDIOC_ENUM_FMT"},
+#endif
+#if defined(VIDIOC_G_FMT)
+{VIDIOC_G_FMT, "VIDIOC_G_FMT"},
+#endif
+#if defined(VIDIOC_S_FMT)
+{VIDIOC_S_FMT, "VIDIOC_S_FMT"},
+#endif
+#if defined(VIDIOC_REQBUFS)
+{VIDIOC_REQBUFS, "VIDIOC_REQBUFS"},
+#endif
+#if defined(VIDIOC_QUERYBUF)
+{VIDIOC_QUERYBUF, "VIDIOC_QUERYBUF"},
+#endif
+#if defined(VIDIOC_G_FBUF)
+{VIDIOC_G_FBUF, "VIDIOC_G_FBUF"},
+#endif
+#if defined(VIDIOC_S_FBUF)
+{VIDIOC_S_FBUF, "VIDIOC_S_FBUF"},
+#endif
+#if defined(VIDIOC_OVERLAY)
+{VIDIOC_OVERLAY, "VIDIOC_OVERLAY"},
+#endif
+#if defined(VIDIOC_QBUF)
+{VIDIOC_QBUF, "VIDIOC_QBUF"},
+#endif
+#if defined(VIDIOC_DQBUF)
+{VIDIOC_DQBUF, "VIDIOC_DQBUF"},
+#endif
+#if defined(VIDIOC_STREAMON)
+{VIDIOC_STREAMON, "VIDIOC_STREAMON"},
+#endif
+#if defined(VIDIOC_STREAMOFF)
+{VIDIOC_STREAMOFF, "VIDIOC_STREAMOFF"},
+#endif
+#if defined(VIDIOC_G_PARM)
+{VIDIOC_G_PARM, "VIDIOC_G_PARM"},
+#endif
+#if defined(VIDIOC_S_PARM)
+{VIDIOC_S_PARM, "VIDIOC_S_PARM"},
+#endif
+#if defined(VIDIOC_G_STD)
+{VIDIOC_G_STD, "VIDIOC_G_STD"},
+#endif
+#if defined(VIDIOC_S_STD)
+{VIDIOC_S_STD, "VIDIOC_S_STD"},
+#endif
+#if defined(VIDIOC_ENUMSTD)
+{VIDIOC_ENUMSTD, "VIDIOC_ENUMSTD"},
+#endif
+#if defined(VIDIOC_ENUMINPUT)
+{VIDIOC_ENUMINPUT, "VIDIOC_ENUMINPUT"},
+#endif
+#if defined(VIDIOC_G_CTRL)
+{VIDIOC_G_CTRL, "VIDIOC_G_CTRL"},
+#endif
+#if defined(VIDIOC_S_CTRL)
+{VIDIOC_S_CTRL, "VIDIOC_S_CTRL"},
+#endif
+#if defined(VIDIOC_G_TUNER)
+{VIDIOC_G_TUNER, "VIDIOC_G_TUNER"},
+#endif
+#if defined(VIDIOC_S_TUNER)
+{VIDIOC_S_TUNER, "VIDIOC_S_TUNER"},
+#endif
+#if defined(VIDIOC_G_AUDIO)
+{VIDIOC_G_AUDIO, "VIDIOC_G_AUDIO"},
+#endif
+#if defined(VIDIOC_S_AUDIO)
+{VIDIOC_S_AUDIO, "VIDIOC_S_AUDIO"},
+#endif
+#if defined(VIDIOC_QUERYCTRL)
+{VIDIOC_QUERYCTRL, "VIDIOC_QUERYCTRL"},
+#endif
+#if defined(VIDIOC_QUERYMENU)
+{VIDIOC_QUERYMENU, "VIDIOC_QUERYMENU"},
+#endif
+#if defined(VIDIOC_G_INPUT)
+{VIDIOC_G_INPUT, "VIDIOC_G_INPUT"},
+#endif
+#if defined(VIDIOC_S_INPUT)
+{VIDIOC_S_INPUT, "VIDIOC_S_INPUT"},
+#endif
+#if defined(VIDIOC_G_OUTPUT)
+{VIDIOC_G_OUTPUT, "VIDIOC_G_OUTPUT"},
+#endif
+#if defined(VIDIOC_S_OUTPUT)
+{VIDIOC_S_OUTPUT, "VIDIOC_S_OUTPUT"},
+#endif
+#if defined(VIDIOC_ENUMOUTPUT)
+{VIDIOC_ENUMOUTPUT, "VIDIOC_ENUMOUTPUT"},
+#endif
+#if defined(VIDIOC_G_AUDOUT)
+{VIDIOC_G_AUDOUT, "VIDIOC_G_AUDOUT"},
+#endif
+#if defined(VIDIOC_S_AUDOUT)
+{VIDIOC_S_AUDOUT, "VIDIOC_S_AUDOUT"},
+#endif
+#if defined(VIDIOC_G_MODULATOR)
+{VIDIOC_G_MODULATOR, "VIDIOC_G_MODULATOR"},
+#endif
+#if defined(VIDIOC_S_MODULATOR)
+{VIDIOC_S_MODULATOR, "VIDIOC_S_MODULATOR"},
+#endif
+#if defined(VIDIOC_G_FREQUENCY)
+{VIDIOC_G_FREQUENCY, "VIDIOC_G_FREQUENCY"},
+#endif
+#if defined(VIDIOC_S_FREQUENCY)
+{VIDIOC_S_FREQUENCY, "VIDIOC_S_FREQUENCY"},
+#endif
+#if defined(VIDIOC_CROPCAP)
+{VIDIOC_CROPCAP, "VIDIOC_CROPCAP"},
+#endif
+#if defined(VIDIOC_G_CROP)
+{VIDIOC_G_CROP, "VIDIOC_G_CROP"},
+#endif
+#if defined(VIDIOC_S_CROP)
+{VIDIOC_S_CROP, "VIDIOC_S_CROP"},
+#endif
+#if defined(VIDIOC_G_JPEGCOMP)
+{VIDIOC_G_JPEGCOMP, "VIDIOC_G_JPEGCOMP"},
+#endif
+#if defined(VIDIOC_S_JPEGCOMP)
+{VIDIOC_S_JPEGCOMP, "VIDIOC_S_JPEGCOMP"},
+#endif
+#if defined(VIDIOC_QUERYSTD)
+{VIDIOC_QUERYSTD, "VIDIOC_QUERYSTD"},
+#endif
+#if defined(VIDIOC_TRY_FMT)
+{VIDIOC_TRY_FMT, "VIDIOC_TRY_FMT"},
+#endif
+#if defined(VIDIOC_ENUMAUDIO)
+{VIDIOC_ENUMAUDIO, "VIDIOC_ENUMAUDIO"},
+#endif
+#if defined(VIDIOC_ENUMAUDOUT)
+{VIDIOC_ENUMAUDOUT, "VIDIOC_ENUMAUDOUT"},
+#endif
+#if defined(VIDIOC_G_PRIORITY)
+{VIDIOC_G_PRIORITY, "VIDIOC_G_PRIORITY"},
+#endif
+#if defined(VIDIOC_S_PRIORITY)
+{VIDIOC_S_PRIORITY, "VIDIOC_S_PRIORITY"},
+#endif
+#if defined(VIDIOC_G_SLICED_VBI_CAP)
+{VIDIOC_G_SLICED_VBI_CAP, "VIDIOC_G_SLICED_VBI_CAP"},
+#endif
+#if defined(VIDIOC_LOG_STATUS)
+{VIDIOC_LOG_STATUS, "VIDIOC_LOG_STATUS"},
+#endif
+#if defined(VIDIOC_G_EXT_CTRLS)
+{VIDIOC_G_EXT_CTRLS, "VIDIOC_G_EXT_CTRLS"},
+#endif
+#if defined(VIDIOC_S_EXT_CTRLS)
+{VIDIOC_S_EXT_CTRLS, "VIDIOC_S_EXT_CTRLS"},
+#endif
+#if defined(VIDIOC_TRY_EXT_CTRLS)
+{VIDIOC_TRY_EXT_CTRLS, "VIDIOC_TRY_EXT_CTRLS"},
+#endif
+#if defined(VIDIOC_ENUM_FRAMESIZES)
+{VIDIOC_ENUM_FRAMESIZES, "VIDIOC_ENUM_FRAMESIZES"},
+#endif
+#if defined(VIDIOC_ENUM_FRAMEINTERVALS)
+{VIDIOC_ENUM_FRAMEINTERVALS, "VIDIOC_ENUM_FRAMEINTERVALS"},
+#endif
+#if defined(VIDIOC_G_ENC_INDEX)
+{VIDIOC_G_ENC_INDEX, "VIDIOC_G_ENC_INDEX"},
+#endif
+#if defined(VIDIOC_ENCODER_CMD)
+{VIDIOC_ENCODER_CMD, "VIDIOC_ENCODER_CMD"},
+#endif
+#if defined(VIDIOC_TRY_ENCODER_CMD)
+{VIDIOC_TRY_ENCODER_CMD, "VIDIOC_TRY_ENCODER_CMD"},
+#endif
+#if defined(VIDIOC_G_CHIP_IDENT)
+{VIDIOC_G_CHIP_IDENT, "VIDIOC_G_CHIP_IDENT"},
+#endif
+
+#if defined(VIDIOC_OVERLAY_OLD)
+{VIDIOC_OVERLAY_OLD, "VIDIOC_OVERLAY_OLD"},
+#endif
+#if defined(VIDIOC_S_PARM_OLD)
+{VIDIOC_S_PARM_OLD, "VIDIOC_S_PARM_OLD"},
+#endif
+#if defined(VIDIOC_S_CTRL_OLD)
+{VIDIOC_S_CTRL_OLD, "VIDIOC_S_CTRL_OLD"},
+#endif
+#if defined(VIDIOC_G_AUDIO_OLD)
+{VIDIOC_G_AUDIO_OLD, "VIDIOC_G_AUDIO_OLD"},
+#endif
+#if defined(VIDIOC_G_AUDOUT_OLD)
+{VIDIOC_G_AUDOUT_OLD, "VIDIOC_G_AUDOUT_OLD"},
+#endif
+#if defined(VIDIOC_CROPCAP_OLD)
+{VIDIOC_CROPCAP_OLD, "VIDIOC_CROPCAP_OLD"},
+#endif
+{0xFFFFFFFF, ""}
+};
+
+static struct mess mess1[] = \
+{
+#if defined(VIDIOCGCAP)
+{VIDIOCGCAP, "VIDIOCGCAP"},
+#endif
+#if defined(VIDIOCGCHAN)
+{VIDIOCGCHAN, "VIDIOCGCHAN"},
+#endif
+#if defined(VIDIOCSCHAN)
+{VIDIOCSCHAN, "VIDIOCSCHAN"},
+#endif
+#if defined(VIDIOCGTUNER)
+{VIDIOCGTUNER, "VIDIOCGTUNER"},
+#endif
+#if defined(VIDIOCSTUNER)
+{VIDIOCSTUNER, "VIDIOCSTUNER"},
+#endif
+#if defined(VIDIOCGPICT)
+{VIDIOCGPICT, "VIDIOCGPICT"},
+#endif
+#if defined(VIDIOCSPICT)
+{VIDIOCSPICT, "VIDIOCSPICT"},
+#endif
+#if defined(VIDIOCCAPTURE)
+{VIDIOCCAPTURE, "VIDIOCCAPTURE"},
+#endif
+#if defined(VIDIOCGWIN)
+{VIDIOCGWIN, "VIDIOCGWIN"},
+#endif
+#if defined(VIDIOCSWIN)
+{VIDIOCSWIN, "VIDIOCSWIN"},
+#endif
+#if defined(VIDIOCGFBUF)
+{VIDIOCGFBUF, "VIDIOCGFBUF"},
+#endif
+#if defined(VIDIOCSFBUF)
+{VIDIOCSFBUF, "VIDIOCSFBUF"},
+#endif
+#if defined(VIDIOCKEY)
+{VIDIOCKEY, "VIDIOCKEY"},
+#endif
+#if defined(VIDIOCGFREQ)
+{VIDIOCGFREQ, "VIDIOCGFREQ"},
+#endif
+#if defined(VIDIOCSFREQ)
+{VIDIOCSFREQ, "VIDIOCSFREQ"},
+#endif
+#if defined(VIDIOCGAUDIO)
+{VIDIOCGAUDIO, "VIDIOCGAUDIO"},
+#endif
+#if defined(VIDIOCSAUDIO)
+{VIDIOCSAUDIO, "VIDIOCSAUDIO"},
+#endif
+#if defined(VIDIOCSYNC)
+{VIDIOCSYNC, "VIDIOCSYNC"},
+#endif
+#if defined(VIDIOCMCAPTURE)
+{VIDIOCMCAPTURE, "VIDIOCMCAPTURE"},
+#endif
+#if defined(VIDIOCGMBUF)
+{VIDIOCGMBUF, "VIDIOCGMBUF"},
+#endif
+#if defined(VIDIOCGUNIT)
+{VIDIOCGUNIT, "VIDIOCGUNIT"},
+#endif
+#if defined(VIDIOCGCAPTURE)
+{VIDIOCGCAPTURE, "VIDIOCGCAPTURE"},
+#endif
+#if defined(VIDIOCSCAPTURE)
+{VIDIOCSCAPTURE, "VIDIOCSCAPTURE"},
+#endif
+#if defined(VIDIOCSPLAYMODE)
+{VIDIOCSPLAYMODE, "VIDIOCSPLAYMODE"},
+#endif
+#if defined(VIDIOCSWRITEMODE)
+{VIDIOCSWRITEMODE, "VIDIOCSWRITEMODE"},
+#endif
+#if defined(VIDIOCGPLAYINFO)
+{VIDIOCGPLAYINFO, "VIDIOCGPLAYINFO"},
+#endif
+#if defined(VIDIOCSMICROCODE)
+{VIDIOCSMICROCODE, "VIDIOCSMICROCODE"},
+#endif
+{0xFFFFFFFF, ""}
+};
+
+k = 0;
+while (mess[k].name[0]) {
+	if (wot == mess[k].command) {
+		JOT(8, "ioctl 0x%08X is %s\n", \
+					mess[k].command, &mess[k].name[0]);
+		return 0;
+	}
+	k++;
+}
+JOT(8, "ioctl 0x%08X is not in videodev2.h\n", wot);
+
+k = 0;
+while (mess1[k].name[0]) {
+	if (wot == mess1[k].command) {
+		JOT(8, "ioctl 0x%08X is %s (V4L1)\n", \
+					mess1[k].command, &mess1[k].name[0]);
+		return 0;
+	}
+	k++;
+}
+JOT(8, "ioctl 0x%08X is not in videodev.h\n", wot);
+return -1;
+}
+/*****************************************************************************/
+int explain_cid(__u32 wot)
+{
+int k;
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE DATA FOR THE ARRAY mess BELOW WERE CONSTRUCTED BY RUNNING THE FOLLOWING
+ *  SHELL SCRIPT:
+ *  #
+ *  cat /usr/src/linux-headers-`uname -r`/include/linux/videodev2.h | \
+ *     grep "^#define V4L2_CID_" |  \
+ *     sed -e "s,(.*$,,;p" | sed -e "N;s,\n,, " | \
+ *     sed -e "s/^#define /  {/;s/#define /, \"/;s/$/\"},/" | \
+ *     sed -e "s,	,,g;s, ,,g" | grep -v "_BASE" | grep -v "MPEG" >cid.tmp
+ *  echo "{0xFFFFFFFF,\"\"}" >>cid.tmp
+ *  exit 0
+ *  #
+ */
+/*---------------------------------------------------------------------------*/
+static struct mess
+{
+__u32 command;
+char  name[64];
+} mess[] = {
+#if defined(V4L2_CID_USER_CLASS)
+{V4L2_CID_USER_CLASS, "V4L2_CID_USER_CLASS"},
+#endif
+#if defined(V4L2_CID_BRIGHTNESS)
+{V4L2_CID_BRIGHTNESS, "V4L2_CID_BRIGHTNESS"},
+#endif
+#if defined(V4L2_CID_CONTRAST)
+{V4L2_CID_CONTRAST, "V4L2_CID_CONTRAST"},
+#endif
+#if defined(V4L2_CID_SATURATION)
+{V4L2_CID_SATURATION, "V4L2_CID_SATURATION"},
+#endif
+#if defined(V4L2_CID_HUE)
+{V4L2_CID_HUE, "V4L2_CID_HUE"},
+#endif
+#if defined(V4L2_CID_AUDIO_VOLUME)
+{V4L2_CID_AUDIO_VOLUME, "V4L2_CID_AUDIO_VOLUME"},
+#endif
+#if defined(V4L2_CID_AUDIO_BALANCE)
+{V4L2_CID_AUDIO_BALANCE, "V4L2_CID_AUDIO_BALANCE"},
+#endif
+#if defined(V4L2_CID_AUDIO_BASS)
+{V4L2_CID_AUDIO_BASS, "V4L2_CID_AUDIO_BASS"},
+#endif
+#if defined(V4L2_CID_AUDIO_TREBLE)
+{V4L2_CID_AUDIO_TREBLE, "V4L2_CID_AUDIO_TREBLE"},
+#endif
+#if defined(V4L2_CID_AUDIO_MUTE)
+{V4L2_CID_AUDIO_MUTE, "V4L2_CID_AUDIO_MUTE"},
+#endif
+#if defined(V4L2_CID_AUDIO_LOUDNESS)
+{V4L2_CID_AUDIO_LOUDNESS, "V4L2_CID_AUDIO_LOUDNESS"},
+#endif
+#if defined(V4L2_CID_BLACK_LEVEL)
+{V4L2_CID_BLACK_LEVEL, "V4L2_CID_BLACK_LEVEL"},
+#endif
+#if defined(V4L2_CID_AUTO_WHITE_BALANCE)
+{V4L2_CID_AUTO_WHITE_BALANCE, "V4L2_CID_AUTO_WHITE_BALANCE"},
+#endif
+#if defined(V4L2_CID_DO_WHITE_BALANCE)
+{V4L2_CID_DO_WHITE_BALANCE, "V4L2_CID_DO_WHITE_BALANCE"},
+#endif
+#if defined(V4L2_CID_RED_BALANCE)
+{V4L2_CID_RED_BALANCE, "V4L2_CID_RED_BALANCE"},
+#endif
+#if defined(V4L2_CID_BLUE_BALANCE)
+{V4L2_CID_BLUE_BALANCE, "V4L2_CID_BLUE_BALANCE"},
+#endif
+#if defined(V4L2_CID_GAMMA)
+{V4L2_CID_GAMMA, "V4L2_CID_GAMMA"},
+#endif
+#if defined(V4L2_CID_WHITENESS)
+{V4L2_CID_WHITENESS, "V4L2_CID_WHITENESS"},
+#endif
+#if defined(V4L2_CID_EXPOSURE)
+{V4L2_CID_EXPOSURE, "V4L2_CID_EXPOSURE"},
+#endif
+#if defined(V4L2_CID_AUTOGAIN)
+{V4L2_CID_AUTOGAIN, "V4L2_CID_AUTOGAIN"},
+#endif
+#if defined(V4L2_CID_GAIN)
+{V4L2_CID_GAIN, "V4L2_CID_GAIN"},
+#endif
+#if defined(V4L2_CID_HFLIP)
+{V4L2_CID_HFLIP, "V4L2_CID_HFLIP"},
+#endif
+#if defined(V4L2_CID_VFLIP)
+{V4L2_CID_VFLIP, "V4L2_CID_VFLIP"},
+#endif
+#if defined(V4L2_CID_HCENTER)
+{V4L2_CID_HCENTER, "V4L2_CID_HCENTER"},
+#endif
+#if defined(V4L2_CID_VCENTER)
+{V4L2_CID_VCENTER, "V4L2_CID_VCENTER"},
+#endif
+#if defined(V4L2_CID_POWER_LINE_FREQUENCY)
+{V4L2_CID_POWER_LINE_FREQUENCY, "V4L2_CID_POWER_LINE_FREQUENCY"},
+#endif
+#if defined(V4L2_CID_HUE_AUTO)
+{V4L2_CID_HUE_AUTO, "V4L2_CID_HUE_AUTO"},
+#endif
+#if defined(V4L2_CID_WHITE_BALANCE_TEMPERATURE)
+{V4L2_CID_WHITE_BALANCE_TEMPERATURE, "V4L2_CID_WHITE_BALANCE_TEMPERATURE"},
+#endif
+#if defined(V4L2_CID_SHARPNESS)
+{V4L2_CID_SHARPNESS, "V4L2_CID_SHARPNESS"},
+#endif
+#if defined(V4L2_CID_BACKLIGHT_COMPENSATION)
+{V4L2_CID_BACKLIGHT_COMPENSATION, "V4L2_CID_BACKLIGHT_COMPENSATION"},
+#endif
+#if defined(V4L2_CID_CHROMA_AGC)
+{V4L2_CID_CHROMA_AGC, "V4L2_CID_CHROMA_AGC"},
+#endif
+#if defined(V4L2_CID_COLOR_KILLER)
+{V4L2_CID_COLOR_KILLER, "V4L2_CID_COLOR_KILLER"},
+#endif
+#if defined(V4L2_CID_LASTP1)
+{V4L2_CID_LASTP1, "V4L2_CID_LASTP1"},
+#endif
+#if defined(V4L2_CID_CAMERA_CLASS)
+{V4L2_CID_CAMERA_CLASS, "V4L2_CID_CAMERA_CLASS"},
+#endif
+#if defined(V4L2_CID_EXPOSURE_AUTO)
+{V4L2_CID_EXPOSURE_AUTO, "V4L2_CID_EXPOSURE_AUTO"},
+#endif
+#if defined(V4L2_CID_EXPOSURE_ABSOLUTE)
+{V4L2_CID_EXPOSURE_ABSOLUTE, "V4L2_CID_EXPOSURE_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_EXPOSURE_AUTO_PRIORITY)
+{V4L2_CID_EXPOSURE_AUTO_PRIORITY, "V4L2_CID_EXPOSURE_AUTO_PRIORITY"},
+#endif
+#if defined(V4L2_CID_PAN_RELATIVE)
+{V4L2_CID_PAN_RELATIVE, "V4L2_CID_PAN_RELATIVE"},
+#endif
+#if defined(V4L2_CID_TILT_RELATIVE)
+{V4L2_CID_TILT_RELATIVE, "V4L2_CID_TILT_RELATIVE"},
+#endif
+#if defined(V4L2_CID_PAN_RESET)
+{V4L2_CID_PAN_RESET, "V4L2_CID_PAN_RESET"},
+#endif
+#if defined(V4L2_CID_TILT_RESET)
+{V4L2_CID_TILT_RESET, "V4L2_CID_TILT_RESET"},
+#endif
+#if defined(V4L2_CID_PAN_ABSOLUTE)
+{V4L2_CID_PAN_ABSOLUTE, "V4L2_CID_PAN_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_TILT_ABSOLUTE)
+{V4L2_CID_TILT_ABSOLUTE, "V4L2_CID_TILT_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_FOCUS_ABSOLUTE)
+{V4L2_CID_FOCUS_ABSOLUTE, "V4L2_CID_FOCUS_ABSOLUTE"},
+#endif
+#if defined(V4L2_CID_FOCUS_RELATIVE)
+{V4L2_CID_FOCUS_RELATIVE, "V4L2_CID_FOCUS_RELATIVE"},
+#endif
+#if defined(V4L2_CID_FOCUS_AUTO)
+{V4L2_CID_FOCUS_AUTO, "V4L2_CID_FOCUS_AUTO"},
+#endif
+{0xFFFFFFFF, ""}
+};
+
+k = 0;
+while (mess[k].name[0]) {
+	if (wot == mess[k].command) {
+		JOT(8, "ioctl 0x%08X is %s\n", \
+					mess[k].command, &mess[k].name[0]);
+		return 0;
+	}
+	k++;
+}
+JOT(8, "cid 0x%08X is not in videodev2.h\n", wot);
+return -1;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_ioctl.h b/drivers/staging/easycap/easycap_ioctl.h
new file mode 100644
index 0000000..7cab094
--- /dev/null
+++ b/drivers/staging/easycap/easycap_ioctl.h
@@ -0,0 +1,29 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap_ioctl.h                                                           *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+extern struct easycap_format easycap_format[];
+extern struct v4l2_queryctrl easycap_control[];
+extern unsigned int audio_bytes_per_fragment;
diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/easycap/easycap_low.c
new file mode 100644
index 0000000..e7c189a
--- /dev/null
+++ b/drivers/staging/easycap/easycap_low.c
@@ -0,0 +1,1057 @@
+/*****************************************************************************
+*                                                                            *
+*                                                                            *
+*  easycap_low.c                                                             *
+*                                                                            *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+/*
+ *  ACKNOWLEGEMENTS AND REFERENCES
+ *  ------------------------------
+ *  This driver makes use of register information contained in the Syntek
+ *  Semicon DC-1125 driver hosted at
+ *               http://sourceforge.net/projects/syntekdriver/.
+ *  Particularly useful has been a patch to the latter driver provided by
+ *  Ivor Hewitt in January 2009.  The NTSC implementation is taken from the
+ *  work of Ben Trask.
+*/
+/****************************************************************************/
+
+#include "easycap_debug.h"
+#include "easycap.h"
+
+/*--------------------------------------------------------------------------*/
+const struct stk1160config { int reg; int set; } stk1160config[256] = {
+	{0x000, 0x0098},
+	{0x002, 0x0093},
+
+	{0x001, 0x0003},
+	{0x003, 0x0080},
+	{0x00D, 0x0000},
+	{0x00F, 0x0002},
+	{0x018, 0x0010},
+	{0x019, 0x0000},
+	{0x01A, 0x0014},
+	{0x01B, 0x000E},
+	{0x01C, 0x0046},
+
+	{0x100, 0x0033},
+	{0x103, 0x0000},
+	{0x104, 0x0000},
+	{0x105, 0x0000},
+	{0x106, 0x0000},
+
+#if defined(PREFER_NTSC)
+
+#undef  OLDMARGIN
+#if defined(OLDMARGIN)
+	{0x110, 0x0008},
+#else
+	{0x110, 0x0014},
+#endif /*OLDMARGIN*/
+
+	{0x111, 0x0000},
+	{0x112, 0x0003},
+	{0x113, 0x0000},
+
+#if defined(OLDMARGIN)
+	{0x114, 0x0508},
+#else
+	{0x114, 0x0514},
+#endif /*OLDMARGIN*/
+
+	{0x115, 0x0005},
+	{0x116, 0x00F3},
+	{0x117, 0x0000},
+
+#else /* ! PREFER_NTSC*/
+
+#if defined(OLDMARGIN)
+	{0x110, 0x0008},
+#else
+	{0x110, 0x0014},
+#endif /*OLDMARGIN*/
+
+	{0x111, 0x0000},
+	{0x112, 0x0020},
+	{0x113, 0x0000},
+
+#if defined(OLDMARGIN)
+	{0x114, 0x0508},
+#else
+	{0x114, 0x0514},
+#endif /*OLDMARGIN*/
+
+	{0x115, 0x0005},
+	{0x116, 0x0110},
+	{0x117, 0x0001},
+
+#endif /* ! PREFER_NTSC*/
+
+	{0x202, 0x000F},
+	{0x203, 0x004A},
+	{0x2FF, 0x0000},
+/*---------------------------------------------------------------------------*/
+	{0xFFF, 0xFFFF}
+	};
+/*--------------------------------------------------------------------------*/
+const struct saa7113config { int reg; int set; } saa7113config[256] = {
+	{0x01, 0x08},
+	{0x02, 0x80},
+	{0x03, 0x33},
+	{0x04, 0x00},
+	{0x05, 0x00},
+	{0x06, 0xE9},
+	{0x07, 0x0D},
+#if defined(PREFER_NTSC)
+	{0x08, 0x78},
+#else
+	{0x08, 0x38},
+#endif /* ! PREFER_NTSC*/
+	{0x09, 0x00},
+	{0x0A, SAA_0A_DEFAULT},
+	{0x0B, SAA_0B_DEFAULT},
+	{0x0C, SAA_0C_DEFAULT},
+	{0x0D, SAA_0D_DEFAULT},
+	{0x0E, 0x01},
+	{0x0F, 0x36},
+	{0x10, 0x00},
+	{0x11, 0x0C},
+	{0x12, 0xE7},
+	{0x13, 0x00},
+	{0x15, 0x00},
+	{0x16, 0x00},
+#if defined(PREFER_NTSC)
+	{0x40, 0x82},
+#else
+	{0x40, 0x02},
+#endif /* ! PREFER_NTSC*/
+	{0x41, 0xFF},
+	{0x42, 0xFF},
+	{0x43, 0xFF},
+	{0x44, 0xFF},
+	{0x45, 0xFF},
+	{0x46, 0xFF},
+	{0x47, 0xFF},
+	{0x48, 0xFF},
+	{0x49, 0xFF},
+	{0x4A, 0xFF},
+	{0x4B, 0xFF},
+	{0x4C, 0xFF},
+	{0x4D, 0xFF},
+	{0x4E, 0xFF},
+	{0x4F, 0xFF},
+	{0x50, 0xFF},
+	{0x51, 0xFF},
+	{0x52, 0xFF},
+	{0x53, 0xFF},
+	{0x54, 0xFF},
+	{0x55, 0xFF},
+	{0x56, 0xFF},
+	{0x57, 0xFF},
+	{0x58, 0x40},
+	{0x59, 0x54},
+#if defined(PREFER_NTSC)
+	{0x5A, 0x0A},
+#else
+	{0x5A, 0x07},
+#endif /* ! PREFER_NTSC*/
+	{0x5B, 0x83},
+	{0xFF, 0xFF}
+	};
+/*--------------------------------------------------------------------------*/
+
+/****************************************************************************/
+int
+confirm_resolution(struct usb_device *p)
+{
+__u8 get0, get1, get2, get3, get4, get5, get6, get7;
+GET(p, 0x0110, &get0);
+GET(p, 0x0111, &get1);
+GET(p, 0x0112, &get2);
+GET(p, 0x0113, &get3);
+GET(p, 0x0114, &get4);
+GET(p, 0x0115, &get5);
+GET(p, 0x0116, &get6);
+GET(p, 0x0117, &get7);
+JOT(8,  "0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X\n", \
+	get0, get1, get2, get3, get4, get5, get6, get7);
+JOT(8,  "....cf PAL_720x526: " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X\n", \
+	0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001);
+JOT(8,  "....cf PAL_704x526: " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X\n", \
+	0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001);
+JOT(8,  "....cf VGA_640x480: " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X, " \
+	"0x%03X, 0x%03X\n", \
+	0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001);
+return 0;
+}
+/****************************************************************************/
+int
+confirm_stream(struct usb_device *p)
+{
+__u16 get2;
+__u8 igot;
+
+GET(p, 0x0100, &igot);  get2 = 0x80 & igot;
+if (0x80 == get2)
+	JOT(8, "confirm_stream:  OK\n");
+else
+	JOT(8, "confirm_stream:  STUCK\n");
+return 0;
+}
+/****************************************************************************/
+int
+setup_stk(struct usb_device *p)
+{
+int i0;
+
+i0 = 0;
+while (0xFFF != stk1160config[i0].reg) {
+	SET(p, stk1160config[i0].reg, stk1160config[i0].set);
+	i0++;
+	}
+
+write_300(p);
+
+return 0;
+}
+/****************************************************************************/
+int
+setup_saa(struct usb_device *p)
+{
+int i0, ir;
+
+
+set2to78(p);
+
+
+i0 = 0;
+while (0xFF != saa7113config[i0].reg) {
+	ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set);
+	i0++;
+	}
+return 0;
+}
+/****************************************************************************/
+int
+write_000(struct usb_device *p, __u16 set2, __u16 set0)
+{
+__u8 igot0, igot2;
+
+GET(p, 0x0002, &igot2);
+GET(p, 0x0000, &igot0);
+SET(p, 0x0002, set2);
+SET(p, 0x0000, set0);
+return 0;
+}
+/****************************************************************************/
+int
+write_saa(struct usb_device *p, __u16 reg0, __u16 set0)
+{
+SET(p, 0x200, 0x00);
+SET(p, 0x204, reg0);
+SET(p, 0x205, set0);
+SET(p, 0x200, 0x01);
+return wait_i2c(p);
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
+ *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
+ *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO SET
+ *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO SET
+ *  REGISTER 504:  TARGET ADDRESS ON VT1612A
+ */
+/*--------------------------------------------------------------------------*/
+int
+write_vt(struct usb_device *p, __u16 reg0, __u16 set0)
+{
+__u8 igot;
+__u16 got502, got503;
+__u16 set502, set503;
+
+SET(p, 0x0504, reg0);
+SET(p, 0x0500, 0x008B);
+
+GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
+GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
+
+JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n", \
+					reg0, set0, ((got503 << 8) | got502));
+
+set502 =  (0x00FF & set0);
+set503 = ((0xFF00 & set0) >> 8);
+
+SET(p, 0x0504, reg0);
+SET(p, 0x0502, set502);
+SET(p, 0x0503, set503);
+SET(p, 0x0500, 0x008C);
+
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
+ *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
+ *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO GET
+ *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO GET
+ *  REGISTER 504:  TARGET ADDRESS ON VT1612A
+ */
+/*--------------------------------------------------------------------------*/
+int
+read_vt(struct usb_device *p, __u16 reg0)
+{
+__u8 igot;
+__u16 got502, got503;
+
+SET(p, 0x0504, reg0);
+SET(p, 0x0500, 0x008B);
+
+GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
+GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
+
+JOT(16, "read_vt(., 0x%04X): has 0x%04X\n", reg0, ((got503 << 8) | got502));
+
+return (got503 << 8) | got502;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
+ */
+/*--------------------------------------------------------------------------*/
+int
+write_300(struct usb_device *p)
+{
+SET(p, 0x300, 0x0012);
+SET(p, 0x350, 0x002D);
+SET(p, 0x351, 0x0001);
+SET(p, 0x352, 0x0000);
+SET(p, 0x353, 0x0000);
+SET(p, 0x300, 0x0080);
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  NOTE: THE FOLLOWING IS NOT CHECKED:
+ *  REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL.
+ */
+/*--------------------------------------------------------------------------*/
+int
+check_saa(struct usb_device *p)
+{
+int i0, ir, rc;
+i0 = 0;
+
+rc = 0;
+while (0xFF != saa7113config[i0].reg) {
+	if (0x0F == saa7113config[i0].reg) {
+		i0++; continue;
+	}
+
+	ir = read_saa(p, saa7113config[i0].reg);
+	if (ir != saa7113config[i0].set) {
+		SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \
+			saa7113config[i0].reg, ir, saa7113config[i0].set);
+		rc--;
+	}
+	i0++;
+}
+if (-8 > rc)
+	return rc;
+else
+	return 0;
+}
+/****************************************************************************/
+int
+merit_saa(struct usb_device *p)
+{
+int rc;
+
+rc = read_saa(p, 0x1F);
+if ((0 > rc) || (0x02 & rc))
+	return 1 ;
+else
+	return 0;
+}
+/****************************************************************************/
+int
+ready_saa(struct usb_device *p)
+{
+int j, rc;
+static int max = 10;
+
+j = 0;
+while (max > j) {
+	rc = read_saa(p, 0x1F);
+	if (0 <= rc) {
+		if ((1 == (0x01 & rc))&&(0 == (0x40 & rc)))
+			break;
+	}
+	msleep(100);  j++;
+}
+if (max == j)
+	return -1;
+else {
+	if (0x20 & rc)
+		JOT(8, "hardware detects 60 Hz\n");
+	else
+		JOT(8, "hardware detects 50 Hz\n");
+	if (0x80 & rc)
+		JOT(8, "hardware detects interlacing\n");
+	else
+		JOT(8, "hardware detects no interlacing\n");
+}
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  NOTE: THE FOLLOWING ARE NOT CHECKED:
+ *  REGISTERS 0x000, 0x002:  FUNCTIONALITY IS NOT KNOWN
+ *  REGISTER  0x100:  ACCEPT ALSO (0x80 | stk1160config[.].set)
+ */
+/*--------------------------------------------------------------------------*/
+int
+check_stk(struct usb_device *p)
+{
+int i0, ir;
+i0 = 0;
+while (0xFFF != stk1160config[i0].reg) {
+	if (0x000 == stk1160config[i0].reg) {
+		i0++; continue;
+	}
+	if (0x002 == stk1160config[i0].reg) {
+		i0++; continue;
+	}
+
+	ir = read_stk(p, stk1160config[i0].reg);
+
+	if (0x100 == stk1160config[i0].reg) {
+		if ((ir != (0xFF & stk1160config[i0].set)) && \
+			(ir != (0x80 | (0xFF & stk1160config[i0].set))) && \
+				(0xFFFF != stk1160config[i0].set)) {
+			SAY("STK register 0x%03X has 0x%02X, " \
+					"expected 0x%02X\n", \
+					stk1160config[i0].reg, ir, \
+					stk1160config[i0].set);
+			}
+		i0++; continue;
+		}
+
+	if ((ir != (0xFF & stk1160config[i0].set)) && \
+			(0xFFFF != stk1160config[i0].set)) {
+		SAY("STK register 0x%03X has 0x%02X, " \
+					"expected 0x%02X\n", \
+					stk1160config[i0].reg, ir, \
+					stk1160config[i0].set);
+		}
+	i0++;
+	}
+return 0;
+}
+/****************************************************************************/
+int
+read_saa(struct usb_device *p, __u16 reg0)
+{
+__u8 igot;
+
+SET(p, 0x208, reg0);
+SET(p, 0x200, 0x20);
+if (0 != wait_i2c(p))
+	return -1;
+igot = 0;
+GET(p, 0x0209, &igot);
+return igot;
+}
+/****************************************************************************/
+int
+read_stk(struct usb_device *p, __u32 reg0)
+{
+__u8 igot;
+
+igot = 0;
+GET(p, reg0, &igot);
+return igot;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *    HARDWARE    USERSPACE INPUT NUMBER   PHYSICAL INPUT   DRIVER input VALUE
+ *
+ *  CVBS+S-VIDEO           0 or 1              CVBS                 1
+ *   FOUR-CVBS             0 or 1              CVBS1                1
+ *   FOUR-CVBS                2                CVBS2                2
+ *   FOUR-CVBS                3                CVBS3                3
+ *   FOUR-CVBS                4                CVBS4                4
+ *  CVBS+S-VIDEO              5               S-VIDEO               5
+ *
+ *  WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED:
+ *
+ *     mode  7   => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED)
+ *     mode  9   => USE AUTOMATIC GAIN CONTROL (DEFAULT)
+ *
+*/
+/*---------------------------------------------------------------------------*/
+int
+select_input(struct usb_device *p, int input, int mode)
+{
+
+stop_100(p);
+
+msleep(20);
+switch (input) {
+case 0:
+case 1: {
+	SET(p, 0x0000, 0x0098); break;
+}
+case 2: {
+	SET(p, 0x0000, 0x0090); break;
+}
+case 3: {
+	SET(p, 0x0000, 0x0088); break;
+}
+case 4: {
+	SET(p, 0x0000, 0x0080); break;
+}
+case 5: {
+	if (9 != mode)
+		mode = 7;
+	switch (mode) {
+	case 7:
+		{
+		if (0 != write_saa(p, 0x02, 0x87)) {
+			SAY("ERROR: failed to set SAA " \
+				"register 0x02 for input " \
+				"%i\n", input);
+		}
+		if (0 != write_saa(p, 0x05, 0xFF)) {
+			SAY("ERROR: failed to set SAA " \
+				"register 0x05 for input " \
+				"%i\n", input);
+		}
+		break;
+	}
+	case 9:
+		{
+		if (0 != write_saa(p, 0x02, 0x89)) {
+			SAY("ERROR: failed to set SAA " \
+				"register 0x02 for input " \
+				"%i\n", input);
+		}
+		if (0 != write_saa(p, 0x05, 0x00)) {
+			SAY("ERROR: failed to set SAA " \
+				"register 0x05 for input " \
+				"%i\n", input);
+		}
+		break;
+	}
+	default:
+		{
+		SAY("MISTAKE:  bad mode: %i\n", mode);
+		return -1;
+		}
+	}
+	if (0 != write_saa(p, 0x04, 0x00)) {
+		SAY("ERROR: failed to set SAA register 0x04 " \
+					"for input %i\n", input);
+	}
+	if (0 != write_saa(p, 0x09, 0x80)) {
+		SAY("ERROR: failed to set SAA register 0x09 " \
+					"for input %i\n", input);
+	}
+	break;
+}
+default:
+	{
+	SAY("ERROR:  bad input: %i\n", input);
+	return -1;
+}
+}
+msleep(20);
+SET(p, 0x0002, 0x0093);
+msleep(20);
+
+start_100(p);
+
+return 0;
+}
+/****************************************************************************/
+int
+set_resolution(struct usb_device *p, \
+				__u16 set0, __u16 set1, __u16 set2, __u16 set3)
+{
+__u16 u0x0111, u0x0113, u0x0115, u0x0117;
+
+u0x0111 = ((0xFF00 & set0) >> 8);
+u0x0113 = ((0xFF00 & set1) >> 8);
+u0x0115 = ((0xFF00 & set2) >> 8);
+u0x0117 = ((0xFF00 & set3) >> 8);
+
+SET(p, 0x0110, (0x00FF & set0));
+SET(p, 0x0111, u0x0111);
+SET(p, 0x0112, (0x00FF & set1));
+SET(p, 0x0113, u0x0113);
+SET(p, 0x0114, (0x00FF & set2));
+SET(p, 0x0115, u0x0115);
+SET(p, 0x0116, (0x00FF & set3));
+SET(p, 0x0117, u0x0117);
+
+return 0;
+}
+/****************************************************************************/
+int
+start_100(struct usb_device *p)
+{
+__u16 get0;
+__u8 igot;
+
+GET(p, 0x0100, &igot);  get0 = igot;
+msleep(0x1f4);
+SET(p, 0x0100, (0x80 | get0));
+msleep(0x1f4);
+return 0;
+}
+/****************************************************************************/
+int
+stop_100(struct usb_device *p)
+{
+__u16 get0;
+__u8 igot;
+
+GET(p, 0x0100, &igot);  get0 = igot;
+msleep(0x1f4);
+SET(p, 0x0100, (0x7F & get0));
+msleep(0x1f4);
+return 0;
+}
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
+*/
+/*--------------------------------------------------------------------------*/
+int
+wait_i2c(struct usb_device *p)
+{
+__u16 get0;
+__u8 igot;
+const int max = 4;
+int k;
+
+for (k = 0;  k < max;  k++) {
+	GET(p, 0x0201, &igot);  get0 = igot;
+	switch (get0) {
+	case 0x04:
+	case 0x01: {
+		return 0;
+	}
+	case 0x00: {
+		msleep(10);
+		continue;
+	}
+	default: {
+		return get0 - 1;
+	}
+	}
+}
+return -1;
+}
+/****************************************************************************/
+int
+regset(struct usb_device *pusb_device, __u16 index, __u16 value)
+{
+__u16 igot;
+int rc0, rc1;
+
+if (!pusb_device)
+	return -EFAULT;
+
+rc1 = 0;  igot = 0;
+rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
+		(__u8)0x01, \
+		(__u8)(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
+		(__u16)value, \
+		(__u16)index, \
+		(void *)NULL, \
+		(__u16)0, \
+		(int)500);
+
+#if defined(NOREADBACK)
+#
+#else
+rc1 = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
+		(__u8)0x00, \
+		(__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
+		(__u16)0x00, \
+		(__u16)index, \
+		(void *)&igot, \
+		(__u16)sizeof(__u16), \
+		(int)50000);
+igot = 0xFF & igot;
+switch (index) {
+case 0x000:
+case 0x500:
+case 0x502:
+case 0x503:
+case 0x504:
+case 0x506:
+case 0x507: {
+	break;
+}
+case 0x204:
+case 0x205:
+case 0x350:
+case 0x351: {
+	if (0 != igot) {
+		JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \
+								igot, index);
+	}
+break;
+}
+case 0x114:
+case 0x116: {
+	if ((0xFF & value) != igot) {
+		JOT(8, "unexpected 0x%02X != 0x%02X " \
+						"for STK register 0x%03X\n", \
+						igot, value, index);
+	}
+break;
+}
+case 0x200: {
+	if (0 == igot)
+		break;
+}
+default: {
+	if (value != igot) {
+		JOT(8, "unexpected 0x%02X != 0x%02X " \
+					"for STK register 0x%03X\n", \
+					igot, value, index);
+	}
+break;
+}
+}
+#endif /* ! NOREADBACK*/
+
+return (0 > rc0) ? rc0 : rc1;
+}
+/*****************************************************************************/
+int
+regget(struct usb_device *pusb_device, __u16 index, void *pvoid)
+{
+int ir;
+
+if (!pusb_device)
+	return -EFAULT;
+
+ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \
+		(__u8)0x00, \
+		(__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \
+		(__u16)0x00, \
+		(__u16)index, \
+		(void *)pvoid, \
+		sizeof(__u8), \
+		(int)50000);
+return 0xFF & ir;
+}
+/*****************************************************************************/
+int
+wakeup_device(struct usb_device *pusb_device)
+{
+return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \
+		(__u8)USB_REQ_SET_FEATURE, \
+		(__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \
+		USB_DEVICE_REMOTE_WAKEUP, \
+		(__u16)0, \
+		(void *) NULL, \
+		(__u16)0, \
+		(int)50000);
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *                                IMPORTANT:
+ *  THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+ *  CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
+ *  TO ENABLE AUDIO  THE VALUE 0x0200 MUST BE SENT.
+ */
+/*---------------------------------------------------------------------------*/
+int
+audio_setup(struct easycap *peasycap)
+{
+struct usb_device *pusb_device;
+static __u8 request = 0x01;
+static __u8 requesttype = \
+		(__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+
+static __u16 value_unmute = 0x0200;
+static __u16 index = 0x0301;
+
+static unsigned char buffer[1];
+static __u16 length = 1;
+int rc;
+
+if (NULL == peasycap)
+	return -EFAULT;
+
+pusb_device = peasycap->pusb_device;
+if (NULL == pusb_device)
+	return -EFAULT;
+
+JOT(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",	\
+			requesttype, request,		\
+			(0x00FF & value_unmute),	\
+			(0xFF00 & value_unmute) >> 8,	\
+			(0x00FF & index),		\
+			(0xFF00 & index) >> 8,		\
+			(0x00FF & length),		\
+			(0xFF00 & length) >> 8);
+
+buffer[0] = 0x01;
+
+rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),	\
+			(__u8)request,					\
+			(__u8)requesttype,				\
+			(__u16)value_unmute,				\
+			(__u16)index,					\
+			(void *)&buffer[0],				\
+			(__u16)length,					\
+			(int)50000);
+
+JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0]));
+if (rc != (int)length)
+	SAY("ERROR: usb_control_msg returned %i\n", rc);
+
+/*--------------------------------------------------------------------------*/
+/*
+ *  REGISTER 500:  SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
+ *  REGISTER 506:  ANALOGUE AUDIO ATTENTUATOR ???
+ *                 FOR THE CVBS+S-VIDEO HARDWARE:
+ *                    SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
+ *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
+ *                 FOR THE FOUR-CVBS HARDWARE:
+ *                    SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
+ *  REGISTER 507:  ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
+ *                 FOR THE CVBS-S-VIDEO HARDWARE:
+ *                    SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
+ *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
+ */
+/*--------------------------------------------------------------------------*/
+
+SET(pusb_device, 0x0500, 0x0094);
+
+SET(pusb_device, 0x0500, 0x008C);
+
+SET(pusb_device, 0x0506, 0x0001);
+SET(pusb_device, 0x0507, 0x0000);
+
+if (false == peasycap->microphone) {
+	/*-------------------------------------------------------------------*/
+	/*
+	*   SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0dB.
+	*/
+	/*-------------------------------------------------------------------*/
+	write_vt(pusb_device, 0x0002, 0x8000);
+	write_vt(pusb_device, 0x001C, 0x8000);
+
+	write_vt(pusb_device, 0x000E, 0x0000);
+	write_vt(pusb_device, 0x0010, 0x0000);
+	write_vt(pusb_device, 0x0012, 0x8000);
+	write_vt(pusb_device, 0x0016, 0x0000);
+
+	write_vt(pusb_device, 0x001A, 0x0404);
+	write_vt(pusb_device, 0x0002, 0x0000);
+	write_vt(pusb_device, 0x001C, 0x0000);
+} else {
+	/*-------------------------------------------------------------------*/
+	/*
+	*   SELECT AUDIO SOURCE "MIC" AND SET DEFAULT GAIN TO 0 dB.
+	*
+	*   REGISTER 0x000E CAN BE SET TO PROVIDE UP TO 34.5 dB ATTENTUATION,
+	*   BUT THIS HAS NOT PROVED NECESSARY FOR THE FEW SIGNAL SOURCES
+	*   TESTED HITHERTO.
+	*/
+	/*-------------------------------------------------------------------*/
+	write_vt(pusb_device, 0x0006, 0x8000);
+	write_vt(pusb_device, 0x001C, 0x8000);
+
+	write_vt(pusb_device, 0x000E, 0x0008);
+
+	write_vt(pusb_device, 0x0010, 0x0000);
+	write_vt(pusb_device, 0x0012, 0x8000);
+	write_vt(pusb_device, 0x0016, 0x0000);
+
+	write_vt(pusb_device, 0x001A, 0x0000);
+	write_vt(pusb_device, 0x0006, 0x0000);
+	write_vt(pusb_device, 0x001C, 0x0000);
+}
+
+check_vt(pusb_device);
+
+return 0;
+}
+/*****************************************************************************/
+int
+check_vt(struct usb_device *pusb_device)
+{
+int igot;
+
+igot = read_vt(pusb_device, 0x0002);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x02\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x02);
+
+igot = read_vt(pusb_device, 0x000E);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x0E\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x0E);
+
+igot = read_vt(pusb_device, 0x0010);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x10\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x10);
+
+igot = read_vt(pusb_device, 0x0012);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x12\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x12);
+
+igot = read_vt(pusb_device, 0x0016);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x16\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x16);
+
+igot = read_vt(pusb_device, 0x001A);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x1A\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x1A);
+
+igot = read_vt(pusb_device, 0x001C);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x1C\n");
+if (0x8000 & igot)
+	SAY("register 0x%02X muted\n", 0x1C);
+
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  NOTE:  THIS DOES INCREASE THE VOLUME DRAMATICALLY:
+ *         audio_gainset(pusb_device, 0x000F);
+ *
+ *  IF 16<loud<31 VT1621A REGISTER 0x1C IS SET FOR POSITIVE GAIN.
+ *  IF loud<=16 VT1621A REGISTER 0x1C IS SET FOR ZERO GAIN.
+ *  THERE IS NEVER ANY (ADDITIONAL) ATTENUATION.
+ */
+/*---------------------------------------------------------------------------*/
+int
+audio_gainset(struct usb_device *pusb_device, __s8 loud)
+{
+int igot;
+__u8 u8;
+__u16 mute;
+
+if (16 > loud)
+	loud = 16;
+u8 = 0x000F & (__u8)(loud - 16);
+
+write_vt(pusb_device, 0x0002, 0x8000);
+
+igot = read_vt(pusb_device, 0x001C);
+if (0 > igot) {
+	SAY("ERROR: failed to read VT1612A register 0x1C\n");
+	mute = 0x0000;
+} else
+	mute = 0x8000 & ((unsigned int)igot);
+
+JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8));
+
+write_vt(pusb_device, 0x001C, 0x8000);
+write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8)));
+write_vt(pusb_device, 0x0002, 0x0000);
+
+return 0;
+}
+/*****************************************************************************/
+int
+audio_gainget(struct usb_device *pusb_device)
+{
+int igot;
+
+igot = read_vt(pusb_device, 0x001C);
+if (0 > igot)
+	SAY("ERROR: failed to read VT1612A register 0x1C\n");
+return igot;
+}
+/*****************************************************************************/
+int
+set2to78(struct usb_device *p)
+{
+int ir;
+
+msleep(20);
+ir = regset(p, 0x0002, 0x0078);
+if (0 > ir)
+	SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
+msleep(20);
+return ir;
+}
+/*****************************************************************************/
+int
+set2to93(struct usb_device *p)
+{
+int ir;
+
+msleep(20);
+ir = regset(p, 0x0002, 0x0093);
+if (0 > ir)
+	SAY("ERROR: failed to set register 0x0002 to 0x0078\n");
+msleep(20);
+return ir;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/easycap/easycap_main.c
new file mode 100644
index 0000000..18259df
--- /dev/null
+++ b/drivers/staging/easycap/easycap_main.c
@@ -0,0 +1,4342 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_main.c                                                             *
+*                                                                             *
+*  Video driver for EasyCAP USB2.0 Video Capture Device DC60                  *
+*                                                                             *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_standard.h"
+
+int easycap_debug;
+module_param(easycap_debug, int, S_IRUGO | S_IWUSR);
+
+unsigned int audio_pages_per_fragment;
+unsigned int audio_bytes_per_fragment;
+unsigned int audio_buffer_page_many;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
+ */
+/*---------------------------------------------------------------------------*/
+struct usb_device_id easycap_usb_device_id_table[] = {
+{ USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID) },
+{ }
+};
+MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
+struct usb_driver easycap_usb_driver = {
+.name = "easycap",
+.id_table = easycap_usb_device_id_table,
+.probe = easycap_usb_probe,
+.disconnect = easycap_usb_disconnect,
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *  PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE
+ *
+ *  NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY
+ *        CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.
+ *        THIS IS THE CASE FOR OpenSUSE.
+ */
+/*---------------------------------------------------------------------------*/
+const struct file_operations easycap_fops = {
+.owner =   THIS_MODULE,
+.open =    easycap_open,
+.release = easycap_release,
+.ioctl =   easycap_ioctl,
+.poll =    easycap_poll,
+.mmap =    easycap_mmap,
+.llseek =  no_llseek,
+};
+struct vm_operations_struct easycap_vm_ops = {
+.open  = easycap_vma_open,
+.close = easycap_vma_close,
+.fault = easycap_vma_fault,
+};
+struct usb_class_driver easycap_class = {
+.name = "usb/easycap%d",
+.fops = &easycap_fops,
+.minor_base = USB_SKEL_MINOR_BASE,
+};
+
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+#if defined(EASYCAP_NEEDS_V4L2_FOPS)
+struct v4l2_file_operations v4l2_fops = {
+.owner =   THIS_MODULE,
+.open =    easycap_open_noinode,
+.release = easycap_release_noinode,
+.ioctl =   easycap_ioctl_noinode,
+.poll =    easycap_poll,
+.mmap =    easycap_mmap,
+};
+#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
+int video_device_many /*=0*/;
+struct video_device *pvideo_array[VIDEO_DEVICE_MANY], *pvideo_device;
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+
+/*--------------------------------------------------------------------------*/
+/*
+ *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
+ */
+/*--------------------------------------------------------------------------*/
+const struct file_operations easysnd_fops = {
+.owner =   THIS_MODULE,
+.open =    easysnd_open,
+.release = easysnd_release,
+.ioctl =   easysnd_ioctl,
+.read =    easysnd_read,
+.llseek =  no_llseek,
+};
+struct usb_class_driver easysnd_class = {
+.name = "usb/easysnd%d",
+.fops = &easysnd_fops,
+.minor_base = USB_SKEL_MINOR_BASE,
+};
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  IT IS NOT APPROPRIATE FOR easycap_open() TO SUBMIT THE VIDEO URBS HERE,
+ *  BECAUSE THERE WILL ALWAYS BE SUBSEQUENT NEGOTIATION OF TV STANDARD AND
+ *  FORMAT BY IOCTL AND IT IS INADVISABLE TO HAVE THE URBS RUNNING WHILE
+ *  REGISTERS OF THE SA7113H ARE BEING MANIPULATED.
+ *
+ *  THE SUBMISSION OF VIDEO URBS IS THEREFORE DELAYED UNTIL THE IOCTL COMMAND
+ *  STREAMON IS RECEIVED.
+ */
+/*--------------------------------------------------------------------------*/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int
+easycap_open_noinode(struct file *file)
+{
+return easycap_open((struct inode *)NULL, file);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+int
+easycap_open(struct inode *inode, struct file *file)
+{
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+struct usb_interface *pusb_interface;
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+struct usb_device *p;
+struct easycap *peasycap;
+int i, k, m, rc;
+
+JOT(4, "\n");
+SAY("==========OPEN=========\n");
+
+peasycap = (struct easycap *)NULL;
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+if ((struct inode *)NULL == inode) {
+	SAY("ERROR: inode is NULL.\n");
+	return -EFAULT;
+}
+pusb_interface = usb_find_interface(&easycap_usb_driver, iminor(inode));
+if (!pusb_interface) {
+	SAY("ERROR: pusb_interface is NULL.\n");
+	return -EFAULT;
+}
+peasycap = usb_get_intfdata(pusb_interface);
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+for (i = 0;  i < video_device_many;  i++) {
+	pvideo_device = pvideo_array[i];
+	if ((struct video_device *)NULL != pvideo_device) {
+		peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
+		break;
+	}
+}
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+if ((struct easycap *)NULL == peasycap) {
+	SAY("MISTAKE: peasycap is NULL\n");
+	return -EFAULT;
+}
+file->private_data = peasycap;
+/*---------------------------------------------------------------------------*/
+/*
+ *  INITIALIZATION
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "starting initialization\n");
+
+for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
+	for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++)
+		memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
+}
+p = peasycap->pusb_device;
+if ((struct usb_device *)NULL == p) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+} else {
+	JOT(16, "0x%08lX=peasycap->pusb_device\n", \
+					(long int)peasycap->pusb_device);
+}
+rc = wakeup_device(peasycap->pusb_device);
+if (0 == rc)
+	JOT(8, "wakeup_device() OK\n");
+else {
+	SAY("ERROR: wakeup_device() returned %i\n", rc);
+	return -EFAULT;
+}
+rc = setup_stk(p);  peasycap->input = 0;
+if (0 == rc)
+	JOT(8, "setup_stk() OK\n");
+else {
+	SAY("ERROR: setup_stk() returned %i\n", rc);
+	return -EFAULT;
+}
+rc = setup_saa(p);
+if (0 == rc)
+	JOT(8, "setup_saa() OK\n");
+else {
+	SAY("ERROR: setup_saa() returned %i\n", rc);
+	return -EFAULT;
+}
+rc = check_saa(p);
+if (0 == rc)
+	JOT(8, "check_saa() OK\n");
+else if (-8 < rc)
+	SAY("check_saa() returned %i\n", rc);
+else {
+	SAY("ERROR: check_saa() returned %i\n", rc);
+	return -EFAULT;
+}
+peasycap->standard_offset = -1;
+/*---------------------------------------------------------------------------*/
+#if defined(PREFER_NTSC)
+
+rc = adjust_standard(peasycap, V4L2_STD_NTSC_M);
+if (0 == rc)
+	JOT(8, "adjust_standard(.,NTSC_M) OK\n");
+else {
+	SAY("ERROR: adjust_standard(.,NTSC_M) returned %i\n", rc);
+	return -EFAULT;
+}
+rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \
+									false);
+if (0 <= rc)
+	JOT(8, "adjust_format(.,640,480,UYVY) OK\n");
+else {
+	SAY("ERROR: adjust_format(.,640,480,UYVY) returned %i\n", rc);
+	return -EFAULT;
+}
+
+#else
+
+rc = adjust_standard(peasycap, \
+		(V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
+		V4L2_STD_PAL_I | V4L2_STD_PAL_N));
+if (0 == rc)
+	JOT(8, "adjust_standard(.,PAL_BGHIN) OK\n");
+else {
+	SAY("ERROR: adjust_standard(.,PAL_BGHIN) returned %i\n", rc);
+	return -EFAULT;
+}
+rc = adjust_format(peasycap, 640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, \
+									false);
+if (0 <= rc)
+	JOT(8, "adjust_format(.,640,480,uyvy,false) OK\n");
+else {
+	SAY("ERROR: adjust_format(.,640,480,uyvy,false) returned %i\n", rc);
+	return -EFAULT;
+}
+
+#endif /* !PREFER_NTSC*/
+/*---------------------------------------------------------------------------*/
+rc = adjust_brightness(peasycap, -8192);
+if (0 != rc) {
+	SAY("ERROR: adjust_brightness(default) returned %i\n", rc);
+	return -EFAULT;
+}
+rc = adjust_contrast(peasycap, -8192);
+if (0 != rc) {
+	SAY("ERROR: adjust_contrast(default) returned %i\n", rc);
+	return -EFAULT;
+}
+rc = adjust_saturation(peasycap, -8192);
+if (0 != rc) {
+	SAY("ERROR: adjust_saturation(default) returned %i\n", rc);
+	return -EFAULT;
+}
+rc = adjust_hue(peasycap, -8192);
+if (0 != rc) {
+	SAY("ERROR: adjust_hue(default) returned %i\n", rc);
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+rc = usb_set_interface(peasycap->pusb_device, peasycap->video_interface, \
+						peasycap->video_altsetting_on);
+if (0 == rc)
+	JOT(8, "usb_set_interface(.,%i,%i) OK\n", peasycap->video_interface, \
+						peasycap->video_altsetting_on);
+else {
+	SAY("ERROR: usb_set_interface() returned %i\n", rc);
+	return -EFAULT;
+}
+rc = start_100(p);
+if (0 == rc)
+	JOT(8, "start_100() OK\n");
+else {
+	SAY("ERROR: start_100() returned %i\n", rc);
+	return -EFAULT;
+}
+peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
+peasycap->video_idle = 0;
+peasycap->video_junk = 0;
+for (i = 0; i < 180; i++)
+	peasycap->merit[i] = 0;
+peasycap->video_eof = 0;
+peasycap->audio_eof = 0;
+
+do_gettimeofday(&peasycap->timeval7);
+
+peasycap->fudge = 0;
+
+JOT(4, "finished initialization\n");
+return 0;
+}
+/*****************************************************************************/
+int
+submit_video_urbs(struct easycap *peasycap)
+{
+struct data_urb *pdata_urb;
+struct urb *purb;
+struct list_head *plist_head;
+int j, isbad, m, rc;
+int isbuf;
+
+if ((struct list_head *)NULL == peasycap->purb_video_head) {
+	SAY("ERROR: peasycap->urb_video_head uninitialized\n");
+	return -EFAULT;
+}
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+if (!peasycap->video_isoc_streaming) {
+
+
+
+
+
+
+
+
+	JOT(4, "submission of all video urbs\n");
+	if (0 != ready_saa(peasycap->pusb_device)) {
+		SAY("ERROR: not ready to capture after waiting " \
+							"one second\n");
+		SAY(".....  continuing anyway\n");
+	}
+	isbad = 0;  m = 0;
+	list_for_each(plist_head, (peasycap->purb_video_head)) {
+		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+		if (NULL != pdata_urb) {
+			purb = pdata_urb->purb;
+			if (NULL != purb) {
+				isbuf = pdata_urb->isbuf;
+				purb->interval = 1;
+				purb->dev = peasycap->pusb_device;
+				purb->pipe = \
+					usb_rcvisocpipe(peasycap->pusb_device,\
+					peasycap->video_endpointnumber);
+				purb->transfer_flags = URB_ISO_ASAP;
+				purb->transfer_buffer = \
+					peasycap->video_isoc_buffer[isbuf].pgo;
+				purb->transfer_buffer_length = \
+					peasycap->video_isoc_buffer_size;
+				purb->complete = easycap_complete;
+				purb->context = peasycap;
+				purb->start_frame = 0;
+				purb->number_of_packets = \
+					peasycap->video_isoc_framesperdesc;
+
+				for (j = 0;  j < peasycap->\
+					video_isoc_framesperdesc; j++) {
+						purb->iso_frame_desc[j].\
+						offset = j * \
+						peasycap->\
+						video_isoc_maxframesize;
+						purb->iso_frame_desc[j].\
+						length = peasycap->\
+						video_isoc_maxframesize;
+					}
+
+				rc = usb_submit_urb(purb, GFP_KERNEL);
+				if (0 != rc) {
+					isbad++;
+					SAY("ERROR: usb_submit_urb() failed " \
+							"for urb with rc:\n");
+					switch (rc) {
+					case -ENOMEM: {
+						SAY("ENOMEM\n");
+						break;
+					}
+					case -ENODEV: {
+						SAY("ENODEV\n");
+						break;
+					}
+					case -ENXIO: {
+						SAY("ENXIO\n");
+						break;
+					}
+					case -EINVAL: {
+						SAY("EINVAL\n");
+						break;
+					}
+					case -EAGAIN: {
+						SAY("EAGAIN\n");
+						break;
+					}
+					case -EFBIG: {
+						SAY("EFBIG\n");
+						break;
+					}
+					case -EPIPE: {
+						SAY("EPIPE\n");
+						break;
+					}
+					case -EMSGSIZE: {
+						SAY("EMSGSIZE\n");
+						break;
+					}
+					default: {
+						SAY("unknown error code %i\n",\
+									 rc);
+						break;
+					}
+					}
+				} else {
+					m++;
+				}
+				} else {
+					isbad++;
+				}
+			} else {
+				 isbad++;
+			}
+		}
+	if (isbad) {
+		JOT(4, "attempting cleanup instead of submitting\n");
+		list_for_each(plist_head, (peasycap->purb_video_head)) {
+			pdata_urb = list_entry(plist_head, struct data_urb, \
+								list_head);
+			if (NULL != pdata_urb) {
+				purb = pdata_urb->purb;
+				if (NULL != purb)
+					usb_kill_urb(purb);
+			}
+		}
+		peasycap->video_isoc_streaming = 0;
+	} else {
+		peasycap->video_isoc_streaming = 1;
+		JOT(4, "submitted %i video urbs\n", m);
+	}
+
+
+
+
+
+
+} else {
+	JOT(4, "already streaming video urbs\n");
+}
+return 0;
+}
+/*****************************************************************************/
+int
+kill_video_urbs(struct easycap *peasycap)
+{
+int m;
+struct list_head *plist_head;
+struct data_urb *pdata_urb;
+
+if ((struct easycap *)NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	return -EFAULT;
+}
+if (peasycap->video_isoc_streaming) {
+
+
+
+	if ((struct list_head *)NULL != peasycap->purb_video_head) {
+		peasycap->video_isoc_streaming = 0;
+		JOT(4, "killing video urbs\n");
+		m = 0;
+		list_for_each(plist_head, (peasycap->purb_video_head)) {
+			pdata_urb = list_entry(plist_head, struct data_urb, \
+								list_head);
+			if ((struct data_urb *)NULL != pdata_urb) {
+				if ((struct urb *)NULL != pdata_urb->purb) {
+					usb_kill_urb(pdata_urb->purb);
+					m++;
+				}
+			}
+		}
+		JOT(4, "%i video urbs killed\n", m);
+	} else {
+		SAY("ERROR: peasycap->purb_video_head is NULL\n");
+		return -EFAULT;
+	}
+} else {
+	JOT(8, "%i=video_isoc_streaming, no video urbs killed\n", \
+					peasycap->video_isoc_streaming);
+}
+return 0;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int
+easycap_release_noinode(struct file *file)
+{
+return easycap_release((struct inode *)NULL, file);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*--------------------------------------------------------------------------*/
+int
+easycap_release(struct inode *inode, struct file *file)
+{
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+struct easycap *peasycap;
+
+JOT(4, "\n");
+
+peasycap = (struct easycap *)file->private_data;
+if (NULL == peasycap) {
+	SAY("ERROR:  peasycap is NULL.\n");
+	SAY("ending unsuccessfully\n");
+	return -EFAULT;
+}
+if (0 != kill_video_urbs(peasycap)) {
+	SAY("ERROR: kill_video_urbs() failed\n");
+	return -EFAULT;
+}
+JOT(4, "ending successfully\n");
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+#
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+
+return 0;
+}
+/****************************************************************************/
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if defined(EASYCAP_IS_VIDEODEV_CLIENT)
+int
+videodev_release(struct video_device *pvd)
+{
+struct easycap *peasycap;
+int i, j, k;
+
+JOT(4, "\n");
+
+k = 0;
+for (i = 0;  i < video_device_many;  i++) {
+	pvideo_device = pvideo_array[i];
+	if ((struct video_device *)NULL != pvideo_device) {
+		if (pvd->minor == pvideo_device->minor) {
+			peasycap = (struct easycap *)\
+					video_get_drvdata(pvideo_device);
+			if ((struct easycap *)NULL == peasycap) {
+				SAY("ERROR:  peasycap is NULL\n");
+				SAY("ending unsuccessfully\n");
+				return -EFAULT;
+			}
+			if (0 != kill_video_urbs(peasycap)) {
+				SAY("ERROR: kill_video_urbs() failed\n");
+				return -EFAULT;
+			}
+			JOT(4, "freeing video_device structure: " \
+							"/dev/video%i\n", i);
+			kfree((void *)pvideo_device);
+			for (j = i;  j < (VIDEO_DEVICE_MANY - 1);  j++)
+				pvideo_array[j] = pvideo_array[j + 1];
+			video_device_many--;  k++;
+			break;
+		}
+	}
+}
+if (!k) {
+	SAY("ERROR: lost video_device structure for %i=minor\n", pvd->minor);
+	SAY("cannot free: may cause memory leak\n");
+	SAY("ending unsuccessfully\n");
+	return -EFAULT;
+}
+
+JOT(4, "ending successfully\n");
+return 0;
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/****************************************************************************/
+/*--------------------------------------------------------------------------*/
+/*
+ *  THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect().
+ *  BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED.
+ *  peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL.
+ */
+/*---------------------------------------------------------------------------*/
+void
+easycap_delete(struct kref *pkref)
+{
+int k, m, lost;
+int allocation_video_urb, allocation_video_page, allocation_video_struct;
+int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
+int registered_video, registered_audio;
+struct easycap *peasycap;
+struct data_urb *pdata_urb;
+struct list_head *plist_head, *plist_next;
+
+JOT(4, "\n");
+
+peasycap = container_of(pkref, struct easycap, kref);
+if ((struct easycap *)NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL: cannot perform deletions\n");
+	return;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  FREE VIDEO.
+ */
+/*---------------------------------------------------------------------------*/
+if ((struct list_head *)NULL != peasycap->purb_video_head) {
+	JOT(4, "freeing video urbs\n");
+	m = 0;
+	list_for_each(plist_head, (peasycap->purb_video_head)) {
+		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+		if (NULL == pdata_urb)
+			JOT(4, "ERROR: pdata_urb is NULL\n");
+		else {
+			if ((struct urb *)NULL != pdata_urb->purb) {
+				usb_free_urb(pdata_urb->purb);
+				pdata_urb->purb = (struct urb *)NULL;
+				peasycap->allocation_video_urb -= 1;
+				m++;
+			}
+		}
+	}
+
+	JOT(4, "%i video urbs freed\n", m);
+/*---------------------------------------------------------------------------*/
+	JOT(4, "freeing video data_urb structures.\n");
+	m = 0;
+	list_for_each_safe(plist_head, plist_next, peasycap->purb_video_head) {
+		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+		if ((struct data_urb *)NULL != pdata_urb) {
+			kfree(pdata_urb);  pdata_urb = (struct data_urb *)NULL;
+			peasycap->allocation_video_struct -= \
+						sizeof(struct data_urb);
+			m++;
+		}
+	}
+	JOT(4, "%i video data_urb structures freed\n", m);
+	JOT(4, "setting peasycap->purb_video_head=NULL\n");
+	peasycap->purb_video_head = (struct list_head *)NULL;
+	} else {
+JOT(4, "peasycap->purb_video_head is NULL\n");
+}
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing video isoc buffers.\n");
+m = 0;
+for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
+	if ((void *)NULL != peasycap->video_isoc_buffer[k].pgo) {
+		free_pages((unsigned long)\
+				(peasycap->video_isoc_buffer[k].pgo), \
+				VIDEO_ISOC_ORDER);
+		peasycap->video_isoc_buffer[k].pgo = (void *)NULL;
+		peasycap->allocation_video_page -= \
+				((unsigned int)(0x01 << VIDEO_ISOC_ORDER));
+		m++;
+	}
+}
+JOT(4, "isoc video buffers freed: %i pages\n", m * (0x01 << VIDEO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing video field buffers.\n");
+lost = 0;
+for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
+	for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
+		if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
+			free_page((unsigned long)\
+					(peasycap->field_buffer[k][m].pgo));
+			peasycap->field_buffer[k][m].pgo = (void *)NULL;
+			peasycap->allocation_video_page -= 1;
+			lost++;
+		}
+	}
+}
+JOT(4, "video field buffers freed: %i pages\n", lost);
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing video frame buffers.\n");
+lost = 0;
+for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
+	for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
+		if ((void *)NULL != peasycap->frame_buffer[k][m].pgo) {
+			free_page((unsigned long)\
+					(peasycap->frame_buffer[k][m].pgo));
+			peasycap->frame_buffer[k][m].pgo = (void *)NULL;
+			peasycap->allocation_video_page -= 1;
+			lost++;
+		}
+	}
+}
+JOT(4, "video frame buffers freed: %i pages\n", lost);
+/*---------------------------------------------------------------------------*/
+/*
+ *  FREE AUDIO.
+ */
+/*---------------------------------------------------------------------------*/
+if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+	JOT(4, "freeing audio urbs\n");
+	m = 0;
+	list_for_each(plist_head, (peasycap->purb_audio_head)) {
+		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+		if (NULL == pdata_urb)
+			JOT(4, "ERROR: pdata_urb is NULL\n");
+		else {
+			if ((struct urb *)NULL != pdata_urb->purb) {
+				usb_free_urb(pdata_urb->purb);
+				pdata_urb->purb = (struct urb *)NULL;
+				peasycap->allocation_audio_urb -= 1;
+				m++;
+			}
+		}
+	}
+	JOT(4, "%i audio urbs freed\n", m);
+/*---------------------------------------------------------------------------*/
+	JOT(4, "freeing audio data_urb structures.\n");
+	m = 0;
+	list_for_each_safe(plist_head, plist_next, peasycap->purb_audio_head) {
+		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+		if ((struct data_urb *)NULL != pdata_urb) {
+			kfree(pdata_urb);  pdata_urb = (struct data_urb *)NULL;
+			peasycap->allocation_audio_struct -= \
+						sizeof(struct data_urb);
+			m++;
+		}
+	}
+JOT(4, "%i audio data_urb structures freed\n", m);
+JOT(4, "setting peasycap->purb_audio_head=NULL\n");
+peasycap->purb_audio_head = (struct list_head *)NULL;
+} else {
+JOT(4, "peasycap->purb_audio_head is NULL\n");
+}
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing audio isoc buffers.\n");
+m = 0;
+for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
+	if ((void *)NULL != peasycap->audio_isoc_buffer[k].pgo) {
+		free_pages((unsigned long)\
+				(peasycap->audio_isoc_buffer[k].pgo), \
+				AUDIO_ISOC_ORDER);
+		peasycap->audio_isoc_buffer[k].pgo = (void *)NULL;
+		peasycap->allocation_audio_page -= \
+				((unsigned int)(0x01 << AUDIO_ISOC_ORDER));
+		m++;
+	}
+}
+JOT(4, "easysnd_delete(): isoc audio buffers freed: %i pages\n", \
+					m * (0x01 << AUDIO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing audio buffers.\n");
+lost = 0;
+for (k = 0;  k < audio_buffer_page_many;  k++) {
+	if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
+		free_page((unsigned long)(peasycap->audio_buffer[k].pgo));
+		peasycap->audio_buffer[k].pgo = (void *)NULL;
+		peasycap->allocation_audio_page -= 1;
+		lost++;
+	}
+}
+JOT(4, "easysnd_delete(): audio buffers freed: %i pages\n", lost);
+/*---------------------------------------------------------------------------*/
+JOT(4, "freeing easycap structure.\n");
+allocation_video_urb    = peasycap->allocation_video_urb;
+allocation_video_page   = peasycap->allocation_video_page;
+allocation_video_struct = peasycap->allocation_video_struct;
+registered_video        = peasycap->registered_video;
+allocation_audio_urb    = peasycap->allocation_audio_urb;
+allocation_audio_page   = peasycap->allocation_audio_page;
+allocation_audio_struct = peasycap->allocation_audio_struct;
+registered_audio        = peasycap->registered_audio;
+m = 0;
+if ((struct easycap *)NULL != peasycap) {
+	kfree(peasycap);  peasycap = (struct easycap *)NULL;
+	allocation_video_struct -= sizeof(struct easycap);
+	m++;
+}
+JOT(4, "%i easycap structure freed\n", m);
+/*---------------------------------------------------------------------------*/
+
+SAY("%8i= video urbs     after all deletions\n", allocation_video_urb);
+SAY("%8i= video pages    after all deletions\n", allocation_video_page);
+SAY("%8i= video structs  after all deletions\n", allocation_video_struct);
+SAY("%8i= video devices  after all deletions\n", registered_video);
+SAY("%8i= audio urbs     after all deletions\n", allocation_audio_urb);
+SAY("%8i= audio pages    after all deletions\n", allocation_audio_page);
+SAY("%8i= audio structs  after all deletions\n", allocation_audio_struct);
+SAY("%8i= audio devices  after all deletions\n", registered_audio);
+
+JOT(4, "ending.\n");
+return;
+}
+/*****************************************************************************/
+unsigned int easycap_poll(struct file *file, poll_table *wait)
+{
+struct easycap *peasycap;
+
+JOT(8, "\n");
+
+if (NULL == ((poll_table *)wait))
+	JOT(8, "WARNING:  poll table pointer is NULL ... continuing\n");
+if (NULL == ((struct file *)file)) {
+	SAY("ERROR:  file pointer is NULL\n");
+	return -EFAULT;
+}
+peasycap = (struct easycap *)file->private_data;
+if (NULL == peasycap) {
+	SAY("ERROR:  peasycap is NULL\n");
+	return -EFAULT;
+}
+peasycap->polled = 1;
+
+if (0 == easycap_dqbuf(peasycap, 0))
+	return POLLIN | POLLRDNORM;
+else
+	return POLLERR;
+
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
+ */
+/*---------------------------------------------------------------------------*/
+int
+easycap_dqbuf(struct easycap *peasycap, int mode)
+{
+int miss, rc;
+
+JOT(8, "\n");
+
+if (NULL == peasycap) {
+	SAY("ERROR:  peasycap is NULL\n");
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  WAIT FOR FIELD 0
+ */
+/*---------------------------------------------------------------------------*/
+miss = 0;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+	return -ERESTARTSYS;
+while ((peasycap->field_read == peasycap->field_fill) || \
+				(0 != (0xFF00 & peasycap->field_buffer\
+					[peasycap->field_read][0].kount)) || \
+				(0 != (0x00FF & peasycap->field_buffer\
+					[peasycap->field_read][0].kount))) {
+	mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+
+	if (mode)
+		return -EAGAIN;
+
+	JOT(8, "first wait  on wq_video, " \
+				"%i=field_read  %i=field_fill\n", \
+				peasycap->field_read, peasycap->field_fill);
+
+	msleep(1);
+	if (0 != (wait_event_interruptible(peasycap->wq_video, \
+			(peasycap->video_idle || peasycap->video_eof  || \
+			((peasycap->field_read != peasycap->field_fill) && \
+				(0 == (0xFF00 & peasycap->field_buffer\
+					[peasycap->field_read][0].kount)) && \
+				(0 == (0x00FF & peasycap->field_buffer\
+					[peasycap->field_read][0].kount))))))){
+		SAY("aborted by signal\n");
+		return -EIO;
+		}
+	if (peasycap->video_idle) {
+		JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);
+		return -EIO;
+	}
+	if (peasycap->video_eof) {
+		JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+		debrief(peasycap);
+		kill_video_urbs(peasycap);
+		return -EIO;
+	}
+miss++;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+	return -ERESTARTSYS;
+}
+mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+JOT(8, "first awakening on wq_video after %i waits\n", miss);
+
+rc = field2frame(peasycap);
+if (0 != rc)
+	SAY("ERROR: field2frame() returned %i\n", rc);
+
+if (true == peasycap->offerfields) {
+	peasycap->frame_read = peasycap->frame_fill;
+	(peasycap->frame_fill)++;
+	if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+		peasycap->frame_fill = 0;
+
+	if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
+		peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+							V4L2_FIELD_BOTTOM;
+	} else {
+		peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+							V4L2_FIELD_TOP;
+	}
+JOT(8, "setting:    %i=peasycap->frame_read\n", peasycap->frame_read);
+JOT(8, "bumped to:  %i=peasycap->frame_fill\n", peasycap->frame_fill);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  WAIT FOR FIELD 1
+ */
+/*---------------------------------------------------------------------------*/
+miss = 0;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+	return -ERESTARTSYS;
+while ((peasycap->field_read == peasycap->field_fill) || \
+				(0 != (0xFF00 & peasycap->field_buffer\
+					[peasycap->field_read][0].kount)) || \
+				(0 == (0x00FF & peasycap->field_buffer\
+					[peasycap->field_read][0].kount))) {
+	mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+
+	if (mode)
+		return -EAGAIN;
+
+	JOT(8, "second wait on wq_video, " \
+				"%i=field_read  %i=field_fill\n", \
+				peasycap->field_read, peasycap->field_fill);
+	msleep(1);
+	if (0 != (wait_event_interruptible(peasycap->wq_video, \
+			(peasycap->video_idle || peasycap->video_eof  || \
+			((peasycap->field_read != peasycap->field_fill) && \
+				(0 == (0xFF00 & peasycap->field_buffer\
+					[peasycap->field_read][0].kount)) && \
+				(0 != (0x00FF & peasycap->field_buffer\
+					[peasycap->field_read][0].kount))))))){
+		SAY("aborted by signal\n");
+		return -EIO;
+	}
+	if (peasycap->video_idle) {
+		JOT(8, "%i=peasycap->video_idle\n", peasycap->video_idle);
+		return -EIO;
+	}
+	if (peasycap->video_eof) {
+		JOT(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
+		debrief(peasycap);
+		kill_video_urbs(peasycap);
+		return -EIO;
+	}
+miss++;
+if (mutex_lock_interruptible(&(peasycap->mutex_mmap_video[0])))
+	return -ERESTARTSYS;
+}
+mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+JOT(8, "second awakening on wq_video after %i waits\n", miss);
+
+rc = field2frame(peasycap);
+if (0 != rc)
+	SAY("ERROR: field2frame() returned %i\n", rc);
+
+peasycap->frame_read = peasycap->frame_fill;
+peasycap->queued[peasycap->frame_read] = 0;
+peasycap->done[peasycap->frame_read]   = V4L2_BUF_FLAG_DONE;
+
+(peasycap->frame_fill)++;
+if (peasycap->frame_buffer_many <= peasycap->frame_fill)
+	peasycap->frame_fill = 0;
+
+if (0x01 & easycap_standard[peasycap->standard_offset].mask) {
+	peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+							V4L2_FIELD_TOP;
+} else {
+	peasycap->frame_buffer[peasycap->frame_read][0].kount = \
+							V4L2_FIELD_BOTTOM;
+}
+
+JOT(8, "setting:    %i=peasycap->frame_read\n", peasycap->frame_read);
+JOT(8, "bumped to:  %i=peasycap->frame_fill\n", peasycap->frame_fill);
+
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  BY DEFINITION, odd IS true  FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
+ *                 odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
+ *
+ *  WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
+ *  odd==false IS TRANSFERRED TO THE FRAME BUFFER.
+ *
+ *  THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
+ *  CHOOSES THE OPTION V4L2_FIELD_ALTERNATE.  NO USERSPACE PROGRAM TESTED
+ *  TO DATE HAS DONE THIS.  BUGS ARE LIKELY.
+ */
+/*---------------------------------------------------------------------------*/
+int
+field2frame(struct easycap *peasycap)
+{
+static struct timeval timeval0;
+struct timeval timeval;
+long long int above, below;
+__u32 remainder;
+struct signed_div_result sdr;
+
+void *pex, *pad;
+int kex, kad, mex, mad, rex, rad, rad2;
+int c2, c3, w2, w3, cz, wz;
+int rc, bytesperpixel, multiplier, much, more, over, rump, caches;
+__u8 mask, margin;
+bool odd, isuy, decimatepixel, offerfields;
+
+JOT(8, "=====  parity %i, field buffer %i --> frame buffer %i\n", \
+			peasycap->field_buffer[peasycap->field_read][0].kount,\
+			peasycap->field_read, peasycap->frame_fill);
+JOT(8, "=====  %i=bytesperpixel\n", peasycap->bytesperpixel);
+if (true == peasycap->offerfields)
+	JOT(8, "===== offerfields\n");
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  REJECT OR CLEAN BAD FIELDS
+ */
+/*---------------------------------------------------------------------------*/
+if (peasycap->field_read == peasycap->field_fill) {
+	SAY("ERROR: on entry, still filling field buffer %i\n", \
+							peasycap->field_read);
+	return 0;
+}
+#if defined(EASYCAP_TESTCARD)
+easycap_testcard(peasycap, peasycap->field_read);
+#else
+if (0 != (0x0400 & peasycap->field_buffer[peasycap->field_read][0].kount))
+	easycap_testcard(peasycap, peasycap->field_read);
+#endif /*EASYCAP_TESTCARD*/
+/*---------------------------------------------------------------------------*/
+
+offerfields = peasycap->offerfields;
+bytesperpixel = peasycap->bytesperpixel;
+decimatepixel = peasycap->decimatepixel;
+
+if ((2 != bytesperpixel) && \
+			(3 != bytesperpixel) && \
+			(4 != bytesperpixel)) {
+	SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+	return -EFAULT;
+}
+if (true == decimatepixel)
+	multiplier = 2;
+else
+	multiplier = 1;
+
+w2 = 2 * multiplier * (peasycap->width);
+w3 = bytesperpixel * \
+		multiplier * \
+		(peasycap->width);
+wz = multiplier * \
+		(peasycap->height) * \
+		multiplier * \
+		(peasycap->width);
+
+kex = peasycap->field_read;  mex = 0;
+kad = peasycap->frame_fill;  mad = 0;
+
+pex = peasycap->field_buffer[kex][0].pgo;  rex = PAGE_SIZE;
+pad = peasycap->frame_buffer[kad][0].pgo;  rad = PAGE_SIZE;
+if (peasycap->field_buffer[kex][0].kount)
+	odd = true;
+else
+	odd = false;
+
+if ((true == odd) && (false == offerfields) &&(false == decimatepixel)) {
+	JOT(8, "  initial skipping    %4i          bytes p.%4i\n", \
+							w3/multiplier, mad);
+	pad += (w3 / multiplier);  rad -= (w3 / multiplier);
+}
+isuy = true;
+mask = 0;  rump = 0;  caches = 0;
+
+cz = 0;
+while (cz < wz) {
+	/*-------------------------------------------------------------------*/
+	/*
+	**  PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
+	**  READ   w2   BYTES FROM FIELD BUFFER,
+	**  WRITE  w3   BYTES TO FRAME BUFFER
+	**/
+	/*-------------------------------------------------------------------*/
+	if (false == decimatepixel) {
+		over = w2;
+		do {
+			much = over;  more = 0;  margin = 0;  mask = 0x00;
+			if (rex < much)
+				much = rex;
+			rump = 0;
+
+			if (much % 2) {
+				SAY("MISTAKE: much is odd\n");
+				return -EFAULT;
+			}
+
+			more = (bytesperpixel * \
+					much) / 2;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+			if (1 < bytesperpixel) {
+				if ((rad * \
+					2) < (much * \
+						bytesperpixel)) {
+					/*
+					**   INJUDICIOUS ALTERATION OF THIS
+					**   BLOCK WILL CAUSE BREAKAGE.
+					**   BEWARE.
+					**/
+					rad2 = rad + bytesperpixel - 1;
+					much = ((((2 * \
+						rad2)/bytesperpixel)/2) * 2);
+					rump = ((bytesperpixel * \
+							much) / 2) - rad;
+					more = rad;
+					}
+				mask = (__u8)rump;
+				margin = 0;
+				if (much == rex) {
+					mask |= 0x04;
+					if ((mex + 1) < FIELD_BUFFER_SIZE/ \
+								PAGE_SIZE) {
+						margin = *((__u8 *)(peasycap->\
+							field_buffer\
+							[kex][mex + 1].pgo));
+					} else
+						mask |= 0x08;
+				}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+			} else {
+				SAY("MISTAKE: %i=bytesperpixel\n", \
+						bytesperpixel);
+				return -EFAULT;
+			}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+			if (rump)
+				caches++;
+
+			rc = redaub(peasycap, pad, pex, much, more, \
+							mask, margin, isuy);
+			if (0 > rc) {
+				SAY("ERROR: redaub() failed\n");
+				return -EFAULT;
+			}
+			if (much % 4) {
+				if (isuy)
+					isuy = false;
+				else
+					isuy = true;
+			}
+			over -= much;   cz += much;
+			pex  += much;  rex -= much;
+			if (!rex) {
+				mex++;
+				pex = peasycap->field_buffer[kex][mex].pgo;
+				rex = PAGE_SIZE;
+			}
+			pad  += more;
+			rad -= more;
+			if (!rad) {
+				mad++;
+				pad = peasycap->frame_buffer[kad][mad].pgo;
+				rad = PAGE_SIZE;
+				if (rump) {
+					pad += rump;
+					rad -= rump;
+				}
+			}
+		} while (over);
+/*---------------------------------------------------------------------------*/
+/*
+ *  SKIP  w3 BYTES IN TARGET FRAME BUFFER,
+ *  UNLESS IT IS THE LAST LINE OF AN ODD FRAME
+ */
+/*---------------------------------------------------------------------------*/
+		if (((false == odd) || (cz != wz))&&(false == offerfields)) {
+			over = w3;
+			do {
+				if (!rad) {
+					mad++;
+					pad = peasycap->frame_buffer\
+						[kad][mad].pgo;
+					rad = PAGE_SIZE;
+				}
+				more = over;
+				if (rad < more)
+					more = rad;
+				over -= more;
+				pad  += more;
+				rad  -= more;
+			} while (over);
+		}
+/*---------------------------------------------------------------------------*/
+/*
+ *  PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
+ *  ONLY IF false==odd,
+ *  READ   w2   BYTES FROM FIELD BUFFER,
+ *  WRITE  w3 / 2  BYTES TO FRAME BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+	} else if (false == odd) {
+		over = w2;
+		do {
+			much = over;  more = 0;  margin = 0;  mask = 0x00;
+			if (rex < much)
+				much = rex;
+			rump = 0;
+
+			if (much % 2) {
+				SAY("MISTAKE: much is odd\n");
+				return -EFAULT;
+			}
+
+			more = (bytesperpixel * \
+					much) / 4;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+			if (1 < bytesperpixel) {
+				if ((rad * 4) < (much * \
+						bytesperpixel)) {
+					/*
+					**   INJUDICIOUS ALTERATION OF THIS
+					**   BLOCK WILL CAUSE BREAKAGE.
+					**   BEWARE.
+					**/
+					rad2 = rad + bytesperpixel - 1;
+					much = ((((2 * rad2)/bytesperpixel)/2)\
+									* 4);
+					rump = ((bytesperpixel * \
+							much) / 4) - rad;
+					more = rad;
+					}
+				mask = (__u8)rump;
+				margin = 0;
+				if (much == rex) {
+					mask |= 0x04;
+					if ((mex + 1) < FIELD_BUFFER_SIZE/ \
+								PAGE_SIZE) {
+						margin = *((__u8 *)(peasycap->\
+							field_buffer\
+							[kex][mex + 1].pgo));
+						}
+					else
+						mask |= 0x08;
+					}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+				} else {
+					SAY("MISTAKE: %i=bytesperpixel\n", \
+						bytesperpixel);
+					return -EFAULT;
+				}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+			if (rump)
+				caches++;
+
+			rc = redaub(peasycap, pad, pex, much, more, \
+							mask, margin, isuy);
+			if (0 > rc) {
+				SAY("ERROR: redaub() failed\n");
+				return -EFAULT;
+			}
+			over -= much;   cz += much;
+			pex  += much;  rex -= much;
+			if (!rex) {
+				mex++;
+				pex = peasycap->field_buffer[kex][mex].pgo;
+				rex = PAGE_SIZE;
+			}
+			pad  += more;
+			rad -= more;
+			if (!rad) {
+				mad++;
+				pad = peasycap->frame_buffer[kad][mad].pgo;
+				rad = PAGE_SIZE;
+				if (rump) {
+					pad += rump;
+					rad -= rump;
+				}
+			}
+		} while (over);
+/*---------------------------------------------------------------------------*/
+/*
+ *  OTHERWISE JUST
+ *  READ   w2   BYTES FROM FIELD BUFFER AND DISCARD THEM
+ */
+/*---------------------------------------------------------------------------*/
+	} else {
+		over = w2;
+		do {
+			if (!rex) {
+				mex++;
+				pex = peasycap->field_buffer[kex][mex].pgo;
+				rex = PAGE_SIZE;
+			}
+			much = over;
+			if (rex < much)
+				much = rex;
+			over -= much;
+			cz += much;
+			pex  += much;
+			rex -= much;
+		} while (over);
+	}
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  SANITY CHECKS
+ */
+/*---------------------------------------------------------------------------*/
+c2 = (mex + 1)*PAGE_SIZE - rex;
+if (cz != c2)
+	SAY("ERROR: discrepancy %i in bytes read\n", c2 - cz);
+c3 = (mad + 1)*PAGE_SIZE - rad;
+
+if (false == decimatepixel) {
+	if (bytesperpixel * \
+		cz != c3) \
+		SAY("ERROR: discrepancy %i in bytes written\n", \
+						c3 - (bytesperpixel * \
+									cz));
+} else {
+	if (false == odd) {
+		if (bytesperpixel * \
+			cz != (4 * c3))
+			SAY("ERROR: discrepancy %i in bytes written\n", \
+						(2*c3)-(bytesperpixel * \
+									cz));
+		} else {
+			if (0 != c3)
+				SAY("ERROR: discrepancy %i " \
+						"in bytes written\n", c3);
+		}
+}
+if (rump)
+	SAY("ERROR: undischarged cache at end of line in frame buffer\n");
+
+JOT(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
+JOT(8, "===== field2frame(): %i=mad  %i=rad\n", mad, rad);
+
+if (true == odd)
+	JOT(8, "+++++ field2frame():  frame buffer %i is full\n", kad);
+
+if (peasycap->field_read == peasycap->field_fill)
+	SAY("WARNING: on exit, filling field buffer %i\n", \
+							peasycap->field_read);
+/*---------------------------------------------------------------------------*/
+/*
+ *  CALCULATE VIDEO STREAMING RATE
+ */
+/*---------------------------------------------------------------------------*/
+do_gettimeofday(&timeval);
+if (timeval0.tv_sec) {
+	below = ((long long int)(1000000)) * \
+		((long long int)(timeval.tv_sec  - timeval0.tv_sec)) + \
+			 (long long int)(timeval.tv_usec - timeval0.tv_usec);
+	above = (long long int)1000000;
+
+	sdr = signed_div(above, below);
+	above = sdr.quotient;
+	remainder = (__u32)sdr.remainder;
+
+	JOT(8, "video streaming at %3lli.%03i fields per second\n", above, \
+							(remainder/1000));
+}
+timeval0 = timeval;
+
+if (caches)
+	JOT(8, "%i=caches\n", caches);
+return 0;
+}
+/*****************************************************************************/
+struct signed_div_result
+signed_div(long long int above, long long int below)
+{
+struct signed_div_result sdr;
+
+if (((0 <= above) && (0 <= below)) || ((0  > above) && (0  > below))) {
+	sdr.remainder = (unsigned long long int) do_div(above, below);
+	sdr.quotient  = (long long int) above;
+} else {
+	if (0 > above)
+		above = -above;
+	if (0 > below)
+		below = -below;
+	sdr.remainder = (unsigned long long int) do_div(above, below);
+	sdr.quotient  = -((long long int) above);
+}
+return sdr;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  DECIMATION AND COLOURSPACE CONVERSION.
+ *
+ *  THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
+ *  AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
+ *  THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
+ *  ALSO ENSURE THAT much IS EVEN.
+ *
+ *  much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
+ *  IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
+ *
+ *  mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
+ *     0x03 & mask =  number of bytes to be written to cache instead of to
+ *                    frame buffer
+ *     0x04 & mask => use argument margin to set the chrominance for last pixel
+ *     0x08 & mask => do not set the chrominance for last pixel
+ *
+ *  YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
+ *
+ *  THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
+ *  INEFFICIENT SWITCHING INSIDE INNER LOOPS.  REARRANGING THE LOGIC TO
+ *  REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE.  BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+int
+redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more, \
+					__u8 mask, __u8 margin, bool isuy)
+{
+static __s32 ay[256], bu[256], rv[256], gu[256], gv[256];
+static __u8 cache[8], *pcache;
+__u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
+int  bytesperpixel;
+bool byteswaporder, decimatepixel, last;
+int j, rump;
+__s32 s32;
+
+if (much % 2) {
+	SAY("MISTAKE: much is odd\n");
+	return -EFAULT;
+}
+bytesperpixel = peasycap->bytesperpixel;
+byteswaporder = peasycap->byteswaporder;
+decimatepixel = peasycap->decimatepixel;
+
+/*---------------------------------------------------------------------------*/
+if (!bu[255]) {
+	for (j = 0; j < 112; j++) {
+		s32 = (0xFF00 & (453 * j)) >> 8;
+		bu[j + 128] =  s32; bu[127 - j] = -s32;
+		s32 = (0xFF00 & (359 * j)) >> 8;
+		rv[j + 128] =  s32; rv[127 - j] = -s32;
+		s32 = (0xFF00 & (88 * j)) >> 8;
+		gu[j + 128] =  s32; gu[127 - j] = -s32;
+		s32 = (0xFF00 & (183 * j)) >> 8;
+		gv[j + 128] =  s32; gv[127 - j] = -s32;
+	}
+	for (j = 0; j < 16; j++) {
+		bu[j] = bu[16]; rv[j] = rv[16];
+		gu[j] = gu[16]; gv[j] = gv[16];
+	}
+	for (j = 240; j < 256; j++) {
+		bu[j] = bu[239]; rv[j] = rv[239];
+		gu[j] = gu[239]; gv[j] = gv[239];
+	}
+	for (j =  16; j < 236; j++)
+		ay[j] = j;
+	for (j =   0; j <  16; j++)
+		ay[j] = ay[16];
+	for (j = 236; j < 256; j++)
+		ay[j] = ay[235];
+	JOT(8, "lookup tables are prepared\n");
+}
+if ((__u8 *)NULL == pcache)
+	pcache = &cache[0];
+/*---------------------------------------------------------------------------*/
+/*
+ *  TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+if (!pcache) {
+	SAY("MISTAKE: pcache is NULL\n");
+	return -EFAULT;
+}
+
+if (pcache != &cache[0])
+	JOT(16, "cache has %i bytes\n", (int)(pcache - &cache[0]));
+p2 = &cache[0];
+p3 = (__u8 *)pad - (int)(pcache - &cache[0]);
+while (p2 < pcache) {
+	*p3++ = *p2;  p2++;
+}
+pcache = &cache[0];
+if (p3 != pad) {
+	SAY("MISTAKE: pointer misalignment\n");
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+rump = (int)(0x03 & mask);
+u = 0; v = 0;
+p2 = (__u8 *)pex;  pz = p2 + much;  pr = p3 + more;  last = false;
+p2++;
+
+if (true == isuy)
+	u = *(p2 - 1);
+else
+	v = *(p2 - 1);
+
+if (rump)
+	JOT(16, "%4i=much  %4i=more  %i=rump\n", much, more, rump);
+
+/*---------------------------------------------------------------------------*/
+switch (bytesperpixel) {
+case 2: {
+	if (false == decimatepixel) {
+		memcpy(pad, pex, (size_t)much);
+		if (false == byteswaporder)
+			/*---------------------------------------------------*/
+			/*
+			**  UYVY
+			*/
+			/*---------------------------------------------------*/
+			return 0;
+		else {
+			/*---------------------------------------------------*/
+			/*
+			**  YUYV
+			*/
+			/*---------------------------------------------------*/
+			p3 = (__u8 *)pad;  pz = p3 + much;
+			while  (pz > p3) {
+				c = *p3;
+				*p3 = *(p3 + 1);
+				*(p3 + 1) = c;
+				p3 += 2;
+			}
+			return 0;
+		}
+	} else {
+		if (false == byteswaporder) {
+			/*---------------------------------------------------*/
+			/*
+			**  UYVY DECIMATED
+			*/
+			/*---------------------------------------------------*/
+			p2 = (__u8 *)pex;  p3 = (__u8 *)pad;  pz = p2 + much;
+			while (pz > p2) {
+				*p3 = *p2;
+				*(p3 + 1) = *(p2 + 1);
+				*(p3 + 2) = *(p2 + 2);
+				*(p3 + 3) = *(p2 + 3);
+				p3 += 4;  p2 += 8;
+			}
+			return 0;
+		} else {
+			/*---------------------------------------------------*/
+			/*
+			**  YUYV DECIMATED
+			**/
+			/*---------------------------------------------------*/
+			p2 = (__u8 *)pex;  p3 = (__u8 *)pad;  pz = p2 + much;
+			while (pz > p2) {
+				*p3 = *(p2 + 1);
+				*(p3 + 1) = *p2;
+				*(p3 + 2) = *(p2 + 3);
+				*(p3 + 3) = *(p2 + 2);
+				p3 += 4;  p2 += 8;
+			}
+			return 0;
+		}
+	}
+	break;
+	}
+case 3:
+	{
+	if (false == decimatepixel) {
+		if (false == byteswaporder) {
+			/*---------------------------------------------------*/
+			/*
+			**  RGB
+			**/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				s32 = ay[(int)y] + rv[(int)v];
+				r = (255 < s32) ? 255 : ((0 > s32) ? \
+							0 : (__u8)s32);
+				s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+				g = (255 < s32) ? 255 : ((0 > s32) ? \
+							0 : (__u8)s32);
+				s32 = ay[(int)y] + bu[(int)u];
+				b = (255 < s32) ? 255 : ((0 > s32) ? \
+							0 : (__u8)s32);
+
+				if ((true == last) && rump) {
+					pcache = &cache[0];
+					switch (bytesperpixel - rump) {
+					case 1: {
+						*p3 = r;
+						*pcache++ = g;
+						*pcache++ = b;
+						break;
+					}
+					case 2: {
+						*p3 = r;
+						*(p3 + 1) = g;
+						*pcache++ = b;
+						break;
+					}
+					default: {
+						SAY("MISTAKE: %i=rump\n", \
+							bytesperpixel - rump);
+						return -EFAULT;
+					}
+					}
+				} else {
+					*p3 = r;
+					*(p3 + 1) = g;
+					*(p3 + 2) = b;
+				}
+				p2 += 2;
+				if (true == isuy)
+					isuy = false;
+				else
+					isuy = true;
+				p3 += bytesperpixel;
+			}
+			return 0;
+		} else {
+			/*---------------------------------------------------*/
+			/*
+			**  BGR
+			*/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					}
+				else
+					if (0x08 & mask)
+						;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				s32 = ay[(int)y] + rv[(int)v];
+				r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+				s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+				g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+				s32 = ay[(int)y] + bu[(int)u];
+				b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+				if ((true == last) && rump) {
+					pcache = &cache[0];
+					switch (bytesperpixel - rump) {
+					case 1: {
+						*p3 = b;
+						*pcache++ = g;
+						*pcache++ = r;
+						break;
+					}
+					case 2: {
+						*p3 = b;
+						*(p3 + 1) = g;
+						*pcache++ = r;
+						break;
+					}
+					default: {
+						SAY("MISTAKE: %i=rump\n", \
+							bytesperpixel - rump);
+						return -EFAULT;
+					}
+					}
+				} else {
+					*p3 = b;
+					*(p3 + 1) = g;
+					*(p3 + 2) = r;
+					}
+				p2 += 2;
+				if (true == isuy)
+					isuy = false;
+				else
+					isuy = true;
+				p3 += bytesperpixel;
+				}
+			}
+		return 0;
+	} else {
+		if (false == byteswaporder) {
+			/*---------------------------------------------------*/
+			/*
+			**  RGB DECIMATED
+			*/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				if (true == isuy) {
+					s32 = ay[(int)y] + rv[(int)v];
+					r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] - gu[(int)u] - \
+								gv[(int)v];
+					g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] + bu[(int)u];
+					b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+					if ((true == last) && rump) {
+						pcache = &cache[0];
+						switch (bytesperpixel - rump) {
+						case 1: {
+							*p3 = r;
+							*pcache++ = g;
+							*pcache++ = b;
+							break;
+						}
+						case 2: {
+							*p3 = r;
+							*(p3 + 1) = g;
+							*pcache++ = b;
+							break;
+						}
+						default: {
+							SAY("MISTAKE: " \
+							"%i=rump\n", \
+							bytesperpixel - rump);
+							return -EFAULT;
+						}
+						}
+					} else {
+						*p3 = r;
+						*(p3 + 1) = g;
+						*(p3 + 2) = b;
+					}
+					isuy = false;
+					p3 += bytesperpixel;
+				} else {
+					isuy = true;
+				}
+				p2 += 2;
+			}
+			return 0;
+		} else {
+			/*---------------------------------------------------*/
+			/*
+			 *  BGR DECIMATED
+			 */
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				if (true == isuy) {
+
+					s32 = ay[(int)y] + rv[(int)v];
+					r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] - gu[(int)u] - \
+								gv[(int)v];
+					g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] + bu[(int)u];
+					b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+					if ((true == last) && rump) {
+						pcache = &cache[0];
+						switch (bytesperpixel - rump) {
+						case 1: {
+							*p3 = b;
+							*pcache++ = g;
+							*pcache++ = r;
+							break;
+						}
+						case 2: {
+							*p3 = b;
+							*(p3 + 1) = g;
+							*pcache++ = r;
+							break;
+						}
+						default: {
+							SAY("MISTAKE: " \
+							"%i=rump\n", \
+							bytesperpixel - rump);
+							return -EFAULT;
+						}
+						}
+					} else {
+						*p3 = b;
+						*(p3 + 1) = g;
+						*(p3 + 2) = r;
+						}
+					isuy = false;
+					p3 += bytesperpixel;
+					}
+				else
+					isuy = true;
+				p2 += 2;
+				}
+			return 0;
+			}
+		}
+	break;
+	}
+case 4:
+	{
+	if (false == decimatepixel) {
+		if (false == byteswaporder) {
+			/*---------------------------------------------------*/
+			/*
+			**  RGBA
+			*/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						 if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				s32 = ay[(int)y] + rv[(int)v];
+				r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+				s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+				g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+				s32 = ay[(int)y] + bu[(int)u];
+				b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+				if ((true == last) && rump) {
+					pcache = &cache[0];
+					switch (bytesperpixel - rump) {
+					case 1: {
+						*p3 = r;
+						*pcache++ = g;
+						*pcache++ = b;
+						*pcache++ = 0;
+						break;
+					}
+					case 2: {
+						*p3 = r;
+						*(p3 + 1) = g;
+						*pcache++ = b;
+						*pcache++ = 0;
+						break;
+					}
+					case 3: {
+						*p3 = r;
+						*(p3 + 1) = g;
+						*(p3 + 2) = b;
+						*pcache++ = 0;
+						break;
+					}
+					default: {
+						SAY("MISTAKE: %i=rump\n", \
+							bytesperpixel - rump);
+						return -EFAULT;
+					}
+					}
+				} else {
+					*p3 = r;
+					*(p3 + 1) = g;
+					*(p3 + 2) = b;
+					*(p3 + 3) = 0;
+				}
+				p2 += 2;
+				if (true == isuy)
+					isuy = false;
+				else
+					isuy = true;
+				p3 += bytesperpixel;
+			}
+			return 0;
+		} else {
+			/*---------------------------------------------------*/
+			/*
+			**  BGRA
+			*/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						 if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				s32 = ay[(int)y] + rv[(int)v];
+				r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+				s32 = ay[(int)y] - gu[(int)u] - gv[(int)v];
+				g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+				s32 = ay[(int)y] + bu[(int)u];
+				b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+				if ((true == last) && rump) {
+					pcache = &cache[0];
+					switch (bytesperpixel - rump) {
+					case 1: {
+						*p3 = b;
+						*pcache++ = g;
+						*pcache++ = r;
+						*pcache++ = 0;
+						break;
+					}
+					case 2: {
+						*p3 = b;
+						*(p3 + 1) = g;
+						*pcache++ = r;
+						*pcache++ = 0;
+						break;
+					}
+					case 3: {
+						*p3 = b;
+						*(p3 + 1) = g;
+						*(p3 + 2) = r;
+						*pcache++ = 0;
+						break;
+					}
+					default: {
+						SAY("MISTAKE: %i=rump\n", \
+							bytesperpixel - rump);
+						return -EFAULT;
+					}
+					}
+				} else {
+					*p3 = b;
+					*(p3 + 1) = g;
+					*(p3 + 2) = r;
+					*(p3 + 3) = 0;
+				}
+				p2 += 2;
+				if (true == isuy)
+					isuy = false;
+				else
+					isuy = true;
+				p3 += bytesperpixel;
+			}
+		}
+		return 0;
+	} else {
+		if (false == byteswaporder) {
+			/*---------------------------------------------------*/
+			/*
+			**  RGBA DECIMATED
+			*/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				if (true == isuy) {
+
+					s32 = ay[(int)y] + rv[(int)v];
+					r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] - gu[(int)u] - \
+								gv[(int)v];
+					g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] + bu[(int)u];
+					b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+					if ((true == last) && rump) {
+						pcache = &cache[0];
+						switch (bytesperpixel - rump) {
+						case 1: {
+							*p3 = r;
+							*pcache++ = g;
+							*pcache++ = b;
+							*pcache++ = 0;
+							break;
+						}
+						case 2: {
+							*p3 = r;
+							*(p3 + 1) = g;
+							*pcache++ = b;
+							*pcache++ = 0;
+							break;
+						}
+						case 3: {
+							*p3 = r;
+							*(p3 + 1) = g;
+							*(p3 + 2) = b;
+							*pcache++ = 0;
+							break;
+						}
+						default: {
+							SAY("MISTAKE: " \
+							"%i=rump\n", \
+							bytesperpixel - \
+							rump);
+							return -EFAULT;
+							}
+						}
+					} else {
+						*p3 = r;
+						*(p3 + 1) = g;
+						*(p3 + 2) = b;
+						*(p3 + 3) = 0;
+						}
+					isuy = false;
+					p3 += bytesperpixel;
+				} else
+					isuy = true;
+				p2 += 2;
+			}
+			return 0;
+		} else {
+			/*---------------------------------------------------*/
+			/*
+			**  BGRA DECIMATED
+			*/
+			/*---------------------------------------------------*/
+			while (pz > p2) {
+				if (pr <= (p3 + bytesperpixel))
+					last = true;
+				else
+					last = false;
+				y = *p2;
+				if ((true == last) && (0x0C & mask)) {
+					if (0x04 & mask) {
+						if (true == isuy)
+							v = margin;
+						else
+							u = margin;
+					} else
+						if (0x08 & mask)
+							;
+				} else {
+					if (true == isuy)
+						v = *(p2 + 1);
+					else
+						u = *(p2 + 1);
+				}
+
+				if (true == isuy) {
+					s32 = ay[(int)y] + rv[(int)v];
+					r = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] - gu[(int)u] - \
+								gv[(int)v];
+					g = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+					s32 = ay[(int)y] + bu[(int)u];
+					b = (255 < s32) ? 255 : ((0 > s32) ? \
+								0 : (__u8)s32);
+
+					if ((true == last) && rump) {
+						pcache = &cache[0];
+						switch (bytesperpixel - rump) {
+						case 1: {
+							*p3 = b;
+							*pcache++ = g;
+							*pcache++ = r;
+							*pcache++ = 0;
+							break;
+						}
+						case 2: {
+							*p3 = b;
+							*(p3 + 1) = g;
+							*pcache++ = r;
+							*pcache++ = 0;
+							break;
+						}
+						case 3: {
+							*p3 = b;
+							*(p3 + 1) = g;
+							*(p3 + 2) = r;
+							*pcache++ = 0;
+							break;
+						}
+						default: {
+							SAY("MISTAKE: " \
+							"%i=rump\n", \
+							bytesperpixel - rump);
+							return -EFAULT;
+						}
+						}
+					} else {
+						*p3 = b;
+						*(p3 + 1) = g;
+						*(p3 + 2) = r;
+						*(p3 + 3) = 0;
+					}
+					isuy = false;
+					p3 += bytesperpixel;
+				} else
+					isuy = true;
+					p2 += 2;
+				}
+				return 0;
+			}
+		}
+	break;
+	}
+default: {
+	SAY("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
+	return -EFAULT;
+	}
+}
+return 0;
+}
+/*****************************************************************************/
+void
+debrief(struct easycap *peasycap)
+{
+if ((struct usb_device *)NULL != peasycap->pusb_device) {
+	check_stk(peasycap->pusb_device);
+	check_saa(peasycap->pusb_device);
+	sayreadonly(peasycap);
+	SAY("%i=peasycap->field_fill\n", peasycap->field_fill);
+	SAY("%i=peasycap->field_read\n", peasycap->field_read);
+	SAY("%i=peasycap->frame_fill\n", peasycap->frame_fill);
+	SAY("%i=peasycap->frame_read\n", peasycap->frame_read);
+}
+return;
+}
+/*****************************************************************************/
+void
+sayreadonly(struct easycap *peasycap)
+{
+static int done;
+int got00, got1F, got60, got61, got62;
+
+if ((!done) && ((struct usb_device *)NULL != peasycap->pusb_device)) {
+	done = 1;
+	got00 = read_saa(peasycap->pusb_device, 0x00);
+	got1F = read_saa(peasycap->pusb_device, 0x1F);
+	got60 = read_saa(peasycap->pusb_device, 0x60);
+	got61 = read_saa(peasycap->pusb_device, 0x61);
+	got62 = read_saa(peasycap->pusb_device, 0x62);
+	SAY("0x%02X=reg0x00  0x%02X=reg0x1F\n", got00, got1F);
+	SAY("0x%02X=reg0x60  0x%02X=reg0x61  0x%02X=reg0x62\n", \
+							got60, got61, got62);
+}
+return;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
+ */
+/*---------------------------------------------------------------------------*/
+int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
+{
+
+JOT(8, "\n");
+
+pvma->vm_ops = &easycap_vm_ops;
+pvma->vm_flags |= VM_RESERVED;
+if (NULL != file)
+	pvma->vm_private_data = file->private_data;
+easycap_vma_open(pvma);
+return 0;
+}
+/*****************************************************************************/
+void
+easycap_vma_open(struct vm_area_struct *pvma)
+{
+struct easycap *peasycap;
+
+peasycap = pvma->vm_private_data;
+if (NULL != peasycap)
+	peasycap->vma_many++;
+
+JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+
+return;
+}
+/*****************************************************************************/
+void
+easycap_vma_close(struct vm_area_struct *pvma)
+{
+struct easycap *peasycap;
+
+peasycap = pvma->vm_private_data;
+if (NULL != peasycap) {
+	peasycap->vma_many--;
+	JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
+}
+return;
+}
+/*****************************************************************************/
+int
+easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
+{
+int k, m, retcode;
+void *pbuf;
+struct page *page;
+struct easycap *peasycap;
+
+retcode = VM_FAULT_NOPAGE;
+pbuf = (void *)NULL;
+page = (struct page *)NULL;
+
+if (NULL == pvma) {
+	SAY("pvma is NULL\n");
+	return retcode;
+}
+if (NULL == pvmf) {
+	SAY("pvmf is NULL\n");
+	return retcode;
+}
+
+k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
+m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+if (!m)
+	JOT(4, "%4i=k, %4i=m\n", k, m);
+else
+	JOT(16, "%4i=k, %4i=m\n", k, m);
+
+if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
+	SAY("ERROR: buffer index %i out of range\n", k);
+	return retcode;
+}
+if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
+	SAY("ERROR: page number  %i out of range\n", m);
+	return retcode;
+}
+peasycap = pvma->vm_private_data;
+if (NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	return retcode;
+}
+mutex_lock(&(peasycap->mutex_mmap_video[0]));
+/*---------------------------------------------------------------------------*/
+pbuf = peasycap->frame_buffer[k][m].pgo;
+if (NULL == pbuf) {
+	SAY("ERROR:  pbuf is NULL\n");
+	goto finish;
+}
+page = virt_to_page(pbuf);
+if (NULL == page) {
+	SAY("ERROR:  page is NULL\n");
+	goto finish;
+}
+get_page(page);
+/*---------------------------------------------------------------------------*/
+finish:
+mutex_unlock(&(peasycap->mutex_mmap_video[0]));
+if (NULL == page) {
+	SAY("ERROR:  page is NULL after get_page(page)\n");
+} else {
+	pvmf->page = page;
+	retcode = VM_FAULT_MINOR;
+}
+return retcode;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
+ *  PROVIDED peasycap->video_idle IS ZER0.  REGARDLESS OF THIS BEING TRUE,
+ *  IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
+ *
+ *  THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
+ *
+ *  INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
+ *  STORED IN THE TWO-BYTE STATUS PARAMETER
+ *        peasycap->field_buffer[peasycap->field_fill][0].kount
+ *  NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
+ *
+ *  THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
+ *  CHIP.
+ *
+ *  THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
+ *      0 != (kount & 0x8000)   => AT LEAST ONE URB COMPLETED WITH ERRORS
+ *      0 != (kount & 0x4000)   => BUFFER HAS TOO MUCH DATA
+ *      0 != (kount & 0x2000)   => BUFFER HAS NOT ENOUGH DATA
+ *      0 != (kount & 0x0400)   => FIELD WAS SUBMITTED BY BRIDGER ROUTINE
+ *      0 != (kount & 0x0200)   => FIELD BUFFER NOT YET CHECKED
+ *      0 != (kount & 0x0100)   => BUFFER HAS TWO EXTRA BYTES - WHY?
+ */
+/*---------------------------------------------------------------------------*/
+void
+easycap_complete(struct urb *purb)
+{
+static int mt;
+struct easycap *peasycap;
+struct data_buffer *pfield_buffer;
+char errbuf[16];
+int i, more, much, leap, rc, last;
+int videofieldamount;
+unsigned int override;
+int framestatus, framelength, frameactual, frameoffset;
+__u8 *pu;
+#if defined(BRIDGER)
+struct timeval timeval;
+long long usec;
+#endif /*BRIDGER*/
+
+if (NULL == purb) {
+	SAY("ERROR: easycap_complete(): purb is NULL\n");
+	return;
+}
+peasycap = purb->context;
+if (NULL == peasycap) {
+	SAY("ERROR: easycap_complete(): peasycap is NULL\n");
+	return;
+}
+
+if (peasycap->video_eof)
+	return;
+
+for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
+	if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
+		break;
+JOT(16, "%2i=urb\n", i);
+last = peasycap->video_isoc_sequence;
+if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && \
+						(0 != i)) || \
+	(((VIDEO_ISOC_BUFFER_MANY - 1) != last) && \
+						((last + 1) != i))) {
+	SAY("ERROR: out-of-order urbs %i,%i ... continuing\n", last, i);
+}
+peasycap->video_isoc_sequence = i;
+
+if (peasycap->video_idle) {
+	JOT(16, "%i=video_idle  %i=video_isoc_streaming\n", \
+			peasycap->video_idle, peasycap->video_isoc_streaming);
+	if (peasycap->video_isoc_streaming) {
+		rc = usb_submit_urb(purb, GFP_ATOMIC);
+		if (0 != rc) {
+			SAY("ERROR: while %i=video_idle, " \
+					"usb_submit_urb() failed with rc:\n", \
+							peasycap->video_idle);
+			switch (rc) {
+			case -ENOMEM: {
+				SAY("ENOMEM\n");
+				break;
+			}
+			case -ENODEV: {
+				SAY("ENODEV\n");
+				break;
+			}
+			case -ENXIO: {
+				SAY("ENXIO\n");
+				break;
+			}
+			case -EINVAL: {
+				SAY("EINVAL\n");
+				break;
+			}
+			case -EAGAIN: {
+				SAY("EAGAIN\n");
+				break;
+			}
+			case -EFBIG: {
+				SAY("EFBIG\n");
+				break;
+			}
+			case -EPIPE: {
+				SAY("EPIPE\n");
+				break;
+			}
+			case -EMSGSIZE: {
+				SAY("EMSGSIZE\n");
+				break;
+			}
+			default: {
+				SAY("0x%08X\n", rc);
+				break;
+			}
+			}
+		}
+	}
+return;
+}
+override = 0;
+/*---------------------------------------------------------------------------*/
+if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+	SAY("ERROR: bad peasycap->field_fill\n");
+	return;
+}
+if (purb->status) {
+	if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
+		JOT(8, "urb status -ESHUTDOWN or -ENOENT\n");
+		return;
+	}
+
+	(peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
+	SAY("ERROR: bad urb status:\n");
+	switch (purb->status) {
+	case -EINPROGRESS: {
+		SAY("-EINPROGRESS\n"); break;
+	}
+	case -ENOSR: {
+		SAY("-ENOSR\n"); break;
+	}
+	case -EPIPE: {
+		SAY("-EPIPE\n"); break;
+	}
+	case -EOVERFLOW: {
+		SAY("-EOVERFLOW\n"); break;
+	}
+	case -EPROTO: {
+		SAY("-EPROTO\n"); break;
+	}
+	case -EILSEQ: {
+		SAY("-EILSEQ\n"); break;
+	}
+	case -ETIMEDOUT: {
+		SAY("-ETIMEDOUT\n"); break;
+	}
+	case -EMSGSIZE: {
+		SAY("-EMSGSIZE\n"); break;
+	}
+	case -EOPNOTSUPP: {
+		SAY("-EOPNOTSUPP\n"); break;
+	}
+	case -EPFNOSUPPORT: {
+		SAY("-EPFNOSUPPORT\n"); break;
+	}
+	case -EAFNOSUPPORT: {
+		SAY("-EAFNOSUPPORT\n"); break;
+	}
+	case -EADDRINUSE: {
+		SAY("-EADDRINUSE\n"); break;
+	}
+	case -EADDRNOTAVAIL: {
+		SAY("-EADDRNOTAVAIL\n"); break;
+	}
+	case -ENOBUFS: {
+		SAY("-ENOBUFS\n"); break;
+	}
+	case -EISCONN: {
+		SAY("-EISCONN\n"); break;
+	}
+	case -ENOTCONN: {
+		SAY("-ENOTCONN\n"); break;
+	}
+	case -ESHUTDOWN: {
+		SAY("-ESHUTDOWN\n"); break;
+	}
+	case -ENOENT: {
+		SAY("-ENOENT\n"); break;
+	}
+	case -ECONNRESET: {
+		SAY("-ECONNRESET\n"); break;
+	}
+	default: {
+		SAY("unknown error code 0x%08X\n", purb->status); break;
+	}
+	}
+/*---------------------------------------------------------------------------*/
+} else {
+	for (i = 0;  i < purb->number_of_packets; i++) {
+		if (0 != purb->iso_frame_desc[i].status) {
+			(peasycap->field_buffer\
+				[peasycap->field_fill][0].kount) |= 0x8000 ;
+			switch (purb->iso_frame_desc[i].status) {
+			case  0: {
+				strcpy(&errbuf[0], "OK"); break;
+			}
+			case -ENOENT: {
+				strcpy(&errbuf[0], "-ENOENT"); break;
+			}
+			case -EINPROGRESS: {
+				strcpy(&errbuf[0], "-EINPROGRESS"); break;
+			}
+			case -EPROTO: {
+				strcpy(&errbuf[0], "-EPROTO"); break;
+			}
+			case -EILSEQ: {
+				strcpy(&errbuf[0], "-EILSEQ"); break;
+			}
+			case -ETIME: {
+				strcpy(&errbuf[0], "-ETIME"); break;
+			}
+			case -ETIMEDOUT: {
+				strcpy(&errbuf[0], "-ETIMEDOUT"); break;
+			}
+			case -EPIPE: {
+				strcpy(&errbuf[0], "-EPIPE"); break;
+			}
+			case -ECOMM: {
+				strcpy(&errbuf[0], "-ECOMM"); break;
+			}
+			case -ENOSR: {
+				strcpy(&errbuf[0], "-ENOSR"); break;
+			}
+			case -EOVERFLOW: {
+				strcpy(&errbuf[0], "-EOVERFLOW"); break;
+			}
+			case -EREMOTEIO: {
+				strcpy(&errbuf[0], "-EREMOTEIO"); break;
+			}
+			case -ENODEV: {
+				strcpy(&errbuf[0], "-ENODEV"); break;
+			}
+			case -EXDEV: {
+				strcpy(&errbuf[0], "-EXDEV"); break;
+			}
+			case -EINVAL: {
+				strcpy(&errbuf[0], "-EINVAL"); break;
+			}
+			case -ECONNRESET: {
+				strcpy(&errbuf[0], "-ECONNRESET"); break;
+			}
+			case -ESHUTDOWN: {
+				strcpy(&errbuf[0], "-ESHUTDOWN"); break;
+			}
+			default: {
+				strcpy(&errbuf[0], "unknown error"); break;
+			}
+			}
+		}
+		framestatus = purb->iso_frame_desc[i].status;
+		framelength = purb->iso_frame_desc[i].length;
+		frameactual = purb->iso_frame_desc[i].actual_length;
+		frameoffset = purb->iso_frame_desc[i].offset;
+
+		JOT(16, "frame[%2i]:" \
+				"%4i=status "  \
+				"%4i=actual "  \
+				"%4i=length "  \
+				"%5i=offset\n", \
+			i, framestatus, frameactual, framelength, frameoffset);
+		if (!purb->iso_frame_desc[i].status) {
+			more = purb->iso_frame_desc[i].actual_length;
+			pfield_buffer = &peasycap->field_buffer\
+				  [peasycap->field_fill][peasycap->field_page];
+			videofieldamount = (peasycap->field_page * \
+				PAGE_SIZE) + \
+				(int)(pfield_buffer->pto - pfield_buffer->pgo);
+		if (4 == more)
+			mt++;
+		if (4 < more) {
+			if (mt) {
+				JOT(8, "%4i empty video urb frames\n", mt);
+				mt = 0;
+			}
+			if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+				SAY("ERROR: bad peasycap->field_fill\n");
+				return;
+			}
+			if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
+							peasycap->field_page) {
+				SAY("ERROR: bad peasycap->field_page\n");
+				return;
+			}
+			pfield_buffer = &peasycap->field_buffer\
+				[peasycap->field_fill][peasycap->field_page];
+			pu = (__u8 *)(purb->transfer_buffer + \
+					purb->iso_frame_desc[i].offset);
+			if (0x80 & *pu)
+				leap = 8;
+			else
+				leap = 4;
+/*--------------------------------------------------------------------------*/
+/*
+ *  EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
+ *  NOTE:  A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
+ *         CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
+ *
+ *  PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
+ *  BYTE OF
+ *        peasycap->field_buffer[peasycap->field_fill][0].kount
+ *  THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
+ *  UPDATED AND field_fill IS BUMPED.  IF THE FIELD BUFFER CONTAINS BAD DATA
+ *  NOTHING IS OFFERED TO dqbuf().
+ *
+ *  THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
+ *  RESTS WITH dqbuf().
+ */
+/*---------------------------------------------------------------------------*/
+			if ((8 == more) || override) {
+				if (videofieldamount > \
+						peasycap->videofieldamount) {
+					if (2 == videofieldamount - \
+							peasycap->\
+							videofieldamount)
+						(peasycap->field_buffer\
+						[peasycap->field_fill]\
+							[0].kount) |= 0x0100;
+					else
+						(peasycap->field_buffer\
+						[peasycap->field_fill]\
+							[0].kount) |= 0x4000;
+					} else if (videofieldamount < \
+							peasycap->\
+							videofieldamount) {
+						(peasycap->field_buffer\
+						[peasycap->field_fill]\
+							[0].kount) |= 0x2000;
+					}
+				if (!(0xFF00 & peasycap->field_buffer\
+						[peasycap->field_fill]\
+						[0].kount)) {
+					(peasycap->video_junk)--;
+					if (-16 > peasycap->video_junk)
+						peasycap->video_junk = -16;
+					peasycap->field_read = \
+							(peasycap->\
+								field_fill)++;
+
+					if (FIELD_BUFFER_MANY <= \
+						peasycap->field_fill)
+						peasycap->field_fill = 0;
+					peasycap->field_page = 0;
+					pfield_buffer = &peasycap->\
+						field_buffer\
+						[peasycap->field_fill]\
+						[peasycap->field_page];
+					pfield_buffer->pto = \
+							pfield_buffer->pgo;
+
+					JOT(8, "bumped to: %i=peasycap->" \
+						"field_fill  %i=parity\n", \
+						peasycap->field_fill, \
+						0x00FF & pfield_buffer->kount);
+					JOT(8, "field buffer %i has %i " \
+						"bytes fit to be read\n", \
+						peasycap->field_read, \
+						videofieldamount);
+					JOT(8, "wakeup call to wq_video, " \
+						"%i=field_read %i=field_fill "\
+						"%i=parity\n", \
+						peasycap->field_read, \
+						peasycap->field_fill, \
+						0x00FF & peasycap->\
+						field_buffer[peasycap->\
+						field_read][0].kount);
+					wake_up_interruptible(&(peasycap->\
+								wq_video));
+					do_gettimeofday(&peasycap->timeval7);
+					} else {
+					peasycap->video_junk++;
+					JOT(8, "field buffer %i had %i " \
+						"bytes, now discarded\n", \
+						peasycap->field_fill, \
+						videofieldamount);
+
+					(peasycap->field_fill)++;
+
+					if (FIELD_BUFFER_MANY <= \
+							peasycap->field_fill)
+						peasycap->field_fill = 0;
+					peasycap->field_page = 0;
+					pfield_buffer = \
+						&peasycap->field_buffer\
+						[peasycap->field_fill]\
+						[peasycap->field_page];
+					pfield_buffer->pto = \
+							pfield_buffer->pgo;
+
+					JOT(8, "bumped to: %i=peasycap->" \
+						"field_fill  %i=parity\n", \
+						peasycap->field_fill, \
+						0x00FF & pfield_buffer->kount);
+				}
+				if (8 == more) {
+					JOT(8, "end-of-field: received " \
+						"parity byte 0x%02X\n", \
+						(0xFF & *pu));
+					if (0x40 & *pu)
+						pfield_buffer->kount = 0x0000;
+					else
+						pfield_buffer->kount = 0x0001;
+					JOT(8, "end-of-field: 0x%02X=kount\n",\
+						0xFF & pfield_buffer->kount);
+				}
+			}
+/*---------------------------------------------------------------------------*/
+/*
+ *  COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
+ */
+/*---------------------------------------------------------------------------*/
+			pu += leap;
+			more -= leap;
+
+			if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
+				SAY("ERROR: bad peasycap->field_fill\n");
+				return;
+			}
+			if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
+							peasycap->field_page) {
+				SAY("ERROR: bad peasycap->field_page\n");
+				return;
+			}
+			pfield_buffer = &peasycap->field_buffer\
+				[peasycap->field_fill][peasycap->field_page];
+			while (more) {
+				pfield_buffer = &peasycap->field_buffer\
+						[peasycap->field_fill]\
+						[peasycap->field_page];
+				if (PAGE_SIZE < (pfield_buffer->pto - \
+							pfield_buffer->pgo)) {
+					SAY("ERROR: bad pfield_buffer->pto\n");
+					return;
+				}
+				if (PAGE_SIZE == (pfield_buffer->pto - \
+							pfield_buffer->pgo)) {
+					(peasycap->field_page)++;
+					if (FIELD_BUFFER_SIZE/PAGE_SIZE <= \
+							peasycap->field_page) {
+						JOT(16, "wrapping peasycap->" \
+							"field_page\n");
+						peasycap->field_page = 0;
+					}
+					pfield_buffer = &peasycap->\
+							field_buffer\
+							[peasycap->field_fill]\
+							[peasycap->field_page];
+					pfield_buffer->pto = \
+							pfield_buffer->pgo;
+				}
+
+				much = PAGE_SIZE - (int)(pfield_buffer->pto - \
+							pfield_buffer->pgo);
+
+				if (much > more)
+					much = more;
+				memcpy(pfield_buffer->pto, pu, much);
+				pu += much;
+				(pfield_buffer->pto) += much;
+				more -= much;
+				}
+			}
+		}
+	}
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *
+ *
+ *             *** UNDER DEVELOPMENT/TESTING - NOT READY YET! ***
+ *
+ *
+ *
+ *  VIDEOTAPES MAY HAVE BEEN MANUALLY PAUSED AND RESTARTED DURING RECORDING.
+ *  THIS CAUSES LOSS OF SYNC, CONFUSING DOWNSTREAM USERSPACE PROGRAMS WHICH
+ *  MAY INTERPRET THE INTERRUPTION AS A SYMPTOM OF LATENCY.  TO OVERCOME THIS
+ *  THE DRIVER BRIDGES THE HIATUS BY SENDING DUMMY VIDEO FRAMES AT ROUGHLY
+ *  THE RIGHT TIME INTERVALS IN THE HOPE OF PERSUADING THE DOWNSTREAM USERSPACE
+ *  PROGRAM TO RESUME NORMAL SERVICE WHEN THE INTERRUPTION IS OVER.
+ */
+/*---------------------------------------------------------------------------*/
+#if defined(BRIDGER)
+do_gettimeofday(&timeval);
+if (peasycap->timeval7.tv_sec) {
+	usec = 1000000*(timeval.tv_sec  - peasycap->timeval7.tv_sec) + \
+			(timeval.tv_usec - peasycap->timeval7.tv_usec);
+	if (usec > (peasycap->usec + peasycap->tolerate)) {
+		JOT(8, "bridging hiatus\n");
+		peasycap->video_junk = 0;
+		peasycap->field_buffer[peasycap->field_fill][0].kount |= 0x0400;
+
+		peasycap->field_read = (peasycap->field_fill)++;
+
+		if (FIELD_BUFFER_MANY <= peasycap->field_fill) \
+						peasycap->field_fill = 0;
+		peasycap->field_page = 0;
+		pfield_buffer = &peasycap->field_buffer\
+				[peasycap->field_fill][peasycap->field_page];
+		pfield_buffer->pto = pfield_buffer->pgo;
+
+		JOT(8, "bumped to: %i=peasycap->field_fill  %i=parity\n", \
+			peasycap->field_fill, 0x00FF & pfield_buffer->kount);
+		JOT(8, "field buffer %i has %i bytes to be overwritten\n", \
+			peasycap->field_read, videofieldamount);
+		JOT(8, "wakeup call to wq_video, " \
+			"%i=field_read %i=field_fill %i=parity\n", \
+			peasycap->field_read, peasycap->field_fill, \
+			0x00FF & \
+			peasycap->field_buffer[peasycap->field_read][0].kount);
+		wake_up_interruptible(&(peasycap->wq_video));
+		do_gettimeofday(&peasycap->timeval7);
+	}
+}
+#endif /*BRIDGER*/
+/*---------------------------------------------------------------------------*/
+/*
+ *  RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
+ *
+ *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
+ *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
+ */
+/*---------------------------------------------------------------------------*/
+if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
+	SAY("easycap driver shutting down on condition green\n");
+	peasycap->video_eof = 1;
+	peasycap->audio_eof = 1;
+	peasycap->video_junk = -VIDEO_ISOC_BUFFER_MANY;
+	wake_up_interruptible(&(peasycap->wq_video));
+	wake_up_interruptible(&(peasycap->wq_audio));
+	return;
+}
+if (peasycap->video_isoc_streaming) {
+	rc = usb_submit_urb(purb, GFP_ATOMIC);
+	if (0 != rc) {
+		SAY("ERROR: while %i=video_idle, usb_submit_urb() failed " \
+					"with rc:\n", peasycap->video_idle);
+		switch (rc) {
+		case -ENOMEM: {
+			SAY("ENOMEM\n"); break;
+		}
+		case -ENODEV: {
+			SAY("ENODEV\n"); break;
+		}
+		case -ENXIO: {
+			SAY("ENXIO\n"); break;
+		}
+		case -EINVAL: {
+			SAY("EINVAL\n"); break;
+		}
+		case -EAGAIN: {
+			SAY("EAGAIN\n"); break;
+		}
+		case -EFBIG: {
+			SAY("EFBIG\n"); break;
+		}
+		case -EPIPE: {
+			SAY("EPIPE\n"); break;
+		}
+		case -EMSGSIZE: {
+			SAY("EMSGSIZE\n");  break;
+		}
+		default: {
+			SAY("0x%08X\n", rc); break;
+		}
+		}
+	}
+}
+return;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *
+ *                                  FIXME
+ *
+ *
+ *  THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS
+ *  PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
+ *  IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
+ *
+ *  THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
+ */
+/*---------------------------------------------------------------------------*/
+int
+easycap_usb_probe(struct usb_interface *pusb_interface, \
+						const struct usb_device_id *id)
+{
+struct usb_device *pusb_device, *pusb_device1;
+struct usb_host_interface *pusb_host_interface;
+struct usb_endpoint_descriptor *pepd;
+struct usb_interface_descriptor *pusb_interface_descriptor;
+struct usb_interface_assoc_descriptor *pusb_interface_assoc_descriptor;
+struct urb *purb;
+static struct easycap *peasycap /*=NULL*/;
+struct data_urb *pdata_urb;
+size_t wMaxPacketSize;
+int ISOCwMaxPacketSize;
+int BULKwMaxPacketSize;
+int INTwMaxPacketSize;
+int CTRLwMaxPacketSize;
+__u8 bEndpointAddress;
+__u8 ISOCbEndpointAddress;
+__u8 INTbEndpointAddress;
+int isin, i, j, k, m;
+__u8 bInterfaceNumber;
+__u8 bInterfaceClass;
+__u8 bInterfaceSubClass;
+void *pbuf;
+int okalt[8], isokalt;
+int okepn[8], isokepn;
+int okmps[8], isokmps;
+int maxpacketsize;
+int rc;
+
+JOT(4, "\n");
+
+if ((struct usb_interface *)NULL == pusb_interface) {
+	SAY("ERROR: pusb_interface is NULL\n");
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  GET POINTER TO STRUCTURE usb_device
+ */
+/*---------------------------------------------------------------------------*/
+pusb_device1 = container_of(pusb_interface->dev.parent, \
+						struct usb_device, dev);
+if ((struct usb_device *)NULL == pusb_device1) {
+	SAY("ERROR: pusb_device1 is NULL\n");
+	return -EFAULT;
+}
+pusb_device = usb_get_dev(pusb_device1);
+if ((struct usb_device *)NULL == pusb_device) {
+	SAY("ERROR: pusb_device is NULL\n");
+	return -EFAULT;
+}
+if ((unsigned long int)pusb_device1 != (unsigned long int)pusb_device) {
+	JOT(4, "ERROR: pusb_device1 != pusb_device\n");
+	return -EFAULT;
+}
+
+JOT(4, "bNumConfigurations=%i\n", pusb_device->descriptor.bNumConfigurations);
+
+/*---------------------------------------------------------------------------*/
+pusb_host_interface = pusb_interface->cur_altsetting;
+if (NULL == pusb_host_interface) {
+	SAY("ERROR: pusb_host_interface is NULL\n");
+	return -EFAULT;
+}
+pusb_interface_descriptor = &(pusb_host_interface->desc);
+if (NULL == pusb_interface_descriptor) {
+	SAY("ERROR: pusb_interface_descriptor is NULL\n");
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  GET PROPERTIES OF PROBED INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
+bInterfaceClass = pusb_interface_descriptor->bInterfaceClass;
+bInterfaceSubClass = pusb_interface_descriptor->bInterfaceSubClass;
+
+JOT(4, "intf[%i]: pusb_interface->num_altsetting=%i\n", \
+			bInterfaceNumber, pusb_interface->num_altsetting);
+JOT(4, "intf[%i]: pusb_interface->cur_altsetting - " \
+			"pusb_interface->altsetting=%li\n", bInterfaceNumber, \
+			(long int)(pusb_interface->cur_altsetting - \
+						pusb_interface->altsetting));
+switch (bInterfaceClass) {
+case USB_CLASS_AUDIO: {
+	JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_AUDIO\n", \
+				bInterfaceNumber, bInterfaceClass); break;
+	}
+case USB_CLASS_VIDEO: {
+	JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_VIDEO\n", \
+				bInterfaceNumber, bInterfaceClass); break;
+	}
+case USB_CLASS_VENDOR_SPEC: {
+	JOT(4, "intf[%i]: bInterfaceClass=0x%02X=USB_CLASS_VENDOR_SPEC\n", \
+				bInterfaceNumber, bInterfaceClass); break;
+	}
+default:
+	break;
+}
+switch (bInterfaceSubClass) {
+case 0x01: {
+	JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=AUDIOCONTROL\n", \
+			bInterfaceNumber, bInterfaceSubClass); break;
+}
+case 0x02: {
+	JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=AUDIOSTREAMING\n", \
+			bInterfaceNumber, bInterfaceSubClass); break;
+}
+case 0x03: {
+	JOT(4, "intf[%i]: bInterfaceSubClass=0x%02X=MIDISTREAMING\n", \
+			bInterfaceNumber, bInterfaceSubClass); break;
+}
+default:
+	break;
+}
+/*---------------------------------------------------------------------------*/
+pusb_interface_assoc_descriptor = pusb_interface->intf_assoc;
+if (NULL != pusb_interface_assoc_descriptor) {
+	JOT(4, "intf[%i]: bFirstInterface=0x%02X  bInterfaceCount=0x%02X\n", \
+			bInterfaceNumber, \
+			pusb_interface_assoc_descriptor->bFirstInterface, \
+			pusb_interface_assoc_descriptor->bInterfaceCount);
+} else {
+JOT(4, "intf[%i]: pusb_interface_assoc_descriptor is NULL\n", \
+							bInterfaceNumber);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
+ *  IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap.  THIS
+ *  SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE DEVICE WAS PHYSICALLY
+ *  UNPLUGGED.
+ */
+/*---------------------------------------------------------------------------*/
+if (0 == bInterfaceNumber) {
+	peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
+	if (NULL == peasycap) {
+		SAY("ERROR: Could not allocate peasycap\n");
+		return -ENOMEM;
+	} else {
+		peasycap->allocation_video_struct = sizeof(struct easycap);
+		peasycap->allocation_video_page = 0;
+		peasycap->allocation_video_urb = 0;
+		peasycap->allocation_audio_struct = 0;
+		peasycap->allocation_audio_page = 0;
+		peasycap->allocation_audio_urb = 0;
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  INITIALIZE THE NEW easycap STRUCTURE.
+ *  NO PARAMETERS ARE SPECIFIED HERE REQUIRING THE SETTING OF REGISTERS.
+ *  THAT IS DONE FIRST BY easycap_open() AND LATER BY easycap_ioctl().
+ */
+/*---------------------------------------------------------------------------*/
+	peasycap->pusb_device = pusb_device;
+	peasycap->pusb_interface = pusb_interface;
+
+	kref_init(&peasycap->kref);
+	JOT(8, "intf[%i]: after kref_init(..._video) " \
+			"%i=peasycap->kref.refcount.counter\n", \
+			bInterfaceNumber, peasycap->kref.refcount.counter);
+
+	init_waitqueue_head(&(peasycap->wq_video));
+	init_waitqueue_head(&(peasycap->wq_audio));
+
+	mutex_init(&(peasycap->mutex_timeval0));
+	mutex_init(&(peasycap->mutex_timeval1));
+
+	for (k = 0; k < FRAME_BUFFER_MANY; k++)
+		mutex_init(&(peasycap->mutex_mmap_video[k]));
+
+	peasycap->ilk = 0;
+	peasycap->microphone = false;
+
+	peasycap->video_interface = -1;
+	peasycap->video_altsetting_on = -1;
+	peasycap->video_altsetting_off = -1;
+	peasycap->video_endpointnumber = -1;
+	peasycap->video_isoc_maxframesize = -1;
+	peasycap->video_isoc_buffer_size = -1;
+
+	peasycap->audio_interface = -1;
+	peasycap->audio_altsetting_on = -1;
+	peasycap->audio_altsetting_off = -1;
+	peasycap->audio_endpointnumber = -1;
+	peasycap->audio_isoc_maxframesize = -1;
+	peasycap->audio_isoc_buffer_size = -1;
+
+	peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+
+	if ((struct mutex *)NULL == &(peasycap->mutex_mmap_video[0])) {
+		SAY("ERROR: &(peasycap->mutex_mmap_video[%i]) is NULL\n", 0);
+		return -EFAULT;
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  DYNAMICALLY FILL IN THE AVAILABLE FORMATS.
+ */
+/*---------------------------------------------------------------------------*/
+	rc = fillin_formats();
+	if (0 > rc) {
+		SAY("ERROR: fillin_formats() returned %i\n", rc);
+		return -EFAULT;
+	}
+	JOT(4, "%i formats available\n", rc);
+	} else {
+/*---------------------------------------------------------------------------*/
+		if ((struct easycap *)NULL == peasycap) {
+			SAY("ERROR: peasycap is NULL " \
+					"when probing interface %i\n", \
+							bInterfaceNumber);
+			return -EFAULT;
+		}
+
+	JOT(8, "kref_get() with %i=peasycap->kref.refcount.counter\n", \
+					(int)peasycap->kref.refcount.counter);
+	kref_get(&peasycap->kref);
+}
+/*---------------------------------------------------------------------------*/
+if ((USB_CLASS_VIDEO == bInterfaceClass) || \
+	(USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
+	if (-1 == peasycap->video_interface) {
+		peasycap->video_interface = bInterfaceNumber;
+		JOT(4, "setting peasycap->video_interface=%i\n", \
+						peasycap->video_interface);
+	} else {
+		if (peasycap->video_interface != bInterfaceNumber) {
+			SAY("ERROR: attempting to reset " \
+					"peasycap->video_interface\n");
+			SAY("...... continuing with " \
+					"%i=peasycap->video_interface\n", \
+					peasycap->video_interface);
+		}
+	}
+} else if ((USB_CLASS_AUDIO == bInterfaceClass) && \
+						(0x02 == bInterfaceSubClass)) {
+	if (-1 == peasycap->audio_interface) {
+		peasycap->audio_interface = bInterfaceNumber;
+		JOT(4, "setting peasycap->audio_interface=%i\n", \
+						 peasycap->audio_interface);
+	} else {
+		if (peasycap->audio_interface != bInterfaceNumber) {
+			SAY("ERROR: attempting to reset " \
+					"peasycap->audio_interface\n");
+			SAY("...... continuing with " \
+					"%i=peasycap->audio_interface\n", \
+					peasycap->audio_interface);
+		}
+	}
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  INVESTIGATE ALL ALTSETTINGS.
+ *  DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
+ */
+/*---------------------------------------------------------------------------*/
+isokalt = 0;
+isokepn = 0;
+isokmps = 0;
+
+for (i = 0; i < pusb_interface->num_altsetting; i++) {
+	pusb_host_interface = &(pusb_interface->altsetting[i]);
+	if ((struct usb_host_interface *)NULL == pusb_host_interface) {
+		SAY("ERROR: pusb_host_interface is NULL\n");
+		return -EFAULT;
+	}
+	pusb_interface_descriptor = &(pusb_host_interface->desc);
+	if ((struct usb_interface_descriptor *)NULL == \
+						pusb_interface_descriptor) {
+		SAY("ERROR: pusb_interface_descriptor is NULL\n");
+		return -EFAULT;
+	}
+
+	JOT(4, "intf[%i]alt[%i]: desc.bDescriptorType=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bDescriptorType);
+	JOT(4, "intf[%i]alt[%i]: desc.bInterfaceNumber=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceNumber);
+	JOT(4, "intf[%i]alt[%i]: desc.bAlternateSetting=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bAlternateSetting);
+	JOT(4, "intf[%i]alt[%i]: desc.bNumEndpoints=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bNumEndpoints);
+	JOT(4, "intf[%i]alt[%i]: desc.bInterfaceClass=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceClass);
+	JOT(4, "intf[%i]alt[%i]: desc.bInterfaceSubClass=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceSubClass);
+	JOT(4, "intf[%i]alt[%i]: desc.bInterfaceProtocol=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->bInterfaceProtocol);
+	JOT(4, "intf[%i]alt[%i]: desc.iInterface=0x%02X\n", \
+	bInterfaceNumber, i, pusb_interface_descriptor->iInterface);
+
+	ISOCwMaxPacketSize = -1;
+	BULKwMaxPacketSize = -1;
+	INTwMaxPacketSize = -1;
+	CTRLwMaxPacketSize = -1;
+	ISOCbEndpointAddress = 0;
+	INTbEndpointAddress = 0;
+
+	if (0 == pusb_interface_descriptor->bNumEndpoints)
+				JOT(4, "intf[%i]alt[%i] has no endpoints\n", \
+							bInterfaceNumber, i);
+/*---------------------------------------------------------------------------*/
+	for (j = 0; j < pusb_interface_descriptor->bNumEndpoints; j++) {
+		pepd = &(pusb_host_interface->endpoint[j].desc);
+		if ((struct usb_endpoint_descriptor *)NULL == pepd) {
+			SAY("ERROR:  pepd is NULL.\n");
+			SAY("...... skipping\n");
+			continue;
+		}
+		wMaxPacketSize = le16_to_cpu(pepd->wMaxPacketSize);
+		bEndpointAddress = pepd->bEndpointAddress;
+
+		JOT(4, "intf[%i]alt[%i]end[%i]: bEndpointAddress=0x%X\n", \
+				bInterfaceNumber, i, j, \
+				pepd->bEndpointAddress);
+		JOT(4, "intf[%i]alt[%i]end[%i]: bmAttributes=0x%X\n", \
+				bInterfaceNumber, i, j, \
+				pepd->bmAttributes);
+		JOT(4, "intf[%i]alt[%i]end[%i]: wMaxPacketSize=%i\n", \
+				bInterfaceNumber, i, j, \
+				pepd->wMaxPacketSize);
+		JOT(4, "intf[%i]alt[%i]end[%i]: bInterval=%i\n",
+				bInterfaceNumber, i, j, \
+				pepd->bInterval);
+
+		if (pepd->bEndpointAddress & USB_DIR_IN) {
+			JOT(4, "intf[%i]alt[%i]end[%i] is an  IN  endpoint\n",\
+						bInterfaceNumber, i, j);
+			isin = 1;
+		} else {
+			JOT(4, "intf[%i]alt[%i]end[%i] is an  OUT endpoint\n",\
+						bInterfaceNumber, i, j);
+			SAY("ERROR: OUT endpoint unexpected\n");
+			SAY("...... continuing\n");
+			isin = 0;
+		}
+		if ((pepd->bmAttributes & \
+				USB_ENDPOINT_XFERTYPE_MASK) == \
+				USB_ENDPOINT_XFER_ISOC) {
+			JOT(4, "intf[%i]alt[%i]end[%i] is an ISOC endpoint\n",\
+						bInterfaceNumber, i, j);
+			if (isin) {
+				switch (bInterfaceClass) {
+				case USB_CLASS_VIDEO:
+				case USB_CLASS_VENDOR_SPEC: {
+					if (!peasycap) {
+						SAY("MISTAKE: " \
+							"peasycap is NULL\n");
+						return -EFAULT;
+					}
+					if (pepd->wMaxPacketSize) {
+						if (8 > isokalt) {
+							okalt[isokalt] = i;
+							JOT(4,\
+							"%i=okalt[%i]\n", \
+							okalt[isokalt], \
+							isokalt);
+							isokalt++;
+						}
+						if (8 > isokepn) {
+							okepn[isokepn] = \
+							pepd->\
+							bEndpointAddress & \
+							0x0F;
+							JOT(4,\
+							"%i=okepn[%i]\n", \
+							okepn[isokepn], \
+							isokepn);
+							isokepn++;
+						}
+						if (8 > isokmps) {
+							okmps[isokmps] = \
+							le16_to_cpu(pepd->\
+							wMaxPacketSize);
+							JOT(4,\
+							"%i=okmps[%i]\n", \
+							okmps[isokmps], \
+							isokmps);
+							isokmps++;
+						}
+					} else {
+						if (-1 == peasycap->\
+							video_altsetting_off) {
+							peasycap->\
+							video_altsetting_off =\
+									 i;
+							JOT(4, "%i=video_" \
+							"altsetting_off " \
+								"<====\n", \
+							peasycap->\
+							video_altsetting_off);
+						} else {
+							SAY("ERROR: peasycap" \
+							"->video_altsetting_" \
+							"off already set\n");
+							SAY("...... " \
+							"continuing with " \
+							"%i=peasycap->video_" \
+							"altsetting_off\n", \
+							peasycap->\
+							video_altsetting_off);
+						}
+					}
+					break;
+				}
+				case USB_CLASS_AUDIO: {
+					if (0x02 != bInterfaceSubClass)
+						break;
+					if (!peasycap) {
+						SAY("MISTAKE: " \
+						"peasycap is NULL\n");
+						return -EFAULT;
+					}
+					if (pepd->wMaxPacketSize) {
+						if (8 > isokalt) {
+							okalt[isokalt] = i ;
+							JOT(4,\
+							"%i=okalt[%i]\n", \
+							okalt[isokalt], \
+							isokalt);
+							isokalt++;
+						}
+						if (8 > isokepn) {
+							okepn[isokepn] = \
+							pepd->\
+							bEndpointAddress & \
+							0x0F;
+							JOT(4,\
+							"%i=okepn[%i]\n", \
+							okepn[isokepn], \
+							isokepn);
+							isokepn++;
+						}
+						if (8 > isokmps) {
+							okmps[isokmps] = \
+							le16_to_cpu(pepd->\
+							wMaxPacketSize);
+							JOT(4,\
+							"%i=okmps[%i]\n",\
+							okmps[isokmps], \
+							isokmps);
+							isokmps++;
+						}
+					} else {
+						if (-1 == peasycap->\
+							audio_altsetting_off) {
+							peasycap->\
+							audio_altsetting_off =\
+									 i;
+							JOT(4, "%i=audio_" \
+							"altsetting_off " \
+							"<====\n", \
+							peasycap->\
+							audio_altsetting_off);
+						} else {
+							SAY("ERROR: peasycap" \
+							"->audio_altsetting_" \
+							"off already set\n");
+							SAY("...... " \
+							"continuing with " \
+							"%i=peasycap->\
+							audio_altsetting_" \
+							"off\n",
+							peasycap->\
+							audio_altsetting_off);
+						}
+					}
+				break;
+				}
+				default:
+					break;
+				}
+			}
+		} else if ((pepd->bmAttributes & \
+						USB_ENDPOINT_XFERTYPE_MASK) ==\
+						USB_ENDPOINT_XFER_BULK) {
+			JOT(4, "intf[%i]alt[%i]end[%i] is a  BULK endpoint\n",\
+						bInterfaceNumber, i, j);
+		} else if ((pepd->bmAttributes & \
+						USB_ENDPOINT_XFERTYPE_MASK) ==\
+						USB_ENDPOINT_XFER_INT) {
+			JOT(4, "intf[%i]alt[%i]end[%i] is an  INT endpoint\n",\
+						bInterfaceNumber, i, j);
+		} else {
+			JOT(4, "intf[%i]alt[%i]end[%i] is a  CTRL endpoint\n",\
+						bInterfaceNumber, i, j);
+		}
+		if (0 == pepd->wMaxPacketSize) {
+			JOT(4, "intf[%i]alt[%i]end[%i] " \
+						"has zero packet size\n", \
+						bInterfaceNumber, i, j);
+		}
+	}
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  PERFORM INITIALIZATION OF THE PROBED INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "initialization begins for interface %i\n", \
+				pusb_interface_descriptor->bInterfaceNumber);
+switch (bInterfaceNumber) {
+/*---------------------------------------------------------------------------*/
+/*
+ *  INTERFACE 0 IS THE VIDEO INTERFACE
+ */
+/*---------------------------------------------------------------------------*/
+case 0: {
+	if (!peasycap) {
+		SAY("MISTAKE: peasycap is NULL\n");
+		return -EFAULT;
+	}
+	if (!isokalt) {
+		SAY("ERROR:  no viable video_altsetting_on\n");
+		return -ENOENT;
+	} else {
+		peasycap->video_altsetting_on = okalt[isokalt - 1];
+		JOT(4, "%i=video_altsetting_on <====\n", \
+					peasycap->video_altsetting_on);
+	}
+	if (!isokepn) {
+		SAY("ERROR:  no viable video_endpointnumber\n");
+		return -ENOENT;
+	} else {
+		peasycap->video_endpointnumber = okepn[isokepn - 1];
+		JOT(4, "%i=video_endpointnumber\n", \
+					peasycap->video_endpointnumber);
+		}
+	if (!isokmps) {
+		SAY("ERROR:  no viable video_maxpacketsize\n");
+		return -ENOENT;
+/*---------------------------------------------------------------------------*/
+/*
+ *  DECIDE THE VIDEO STREAMING PARAMETERS
+ */
+/*---------------------------------------------------------------------------*/
+	} else {
+		maxpacketsize = okmps[isokmps - 1] - 1024;
+		if (USB_2_0_MAXPACKETSIZE > maxpacketsize) {
+			peasycap->video_isoc_maxframesize = maxpacketsize;
+		} else {
+			peasycap->video_isoc_maxframesize = \
+							USB_2_0_MAXPACKETSIZE;
+		}
+		JOT(4, "%i=video_isoc_maxframesize\n", \
+					peasycap->video_isoc_maxframesize);
+		if (0 >= peasycap->video_isoc_maxframesize) {
+			SAY("ERROR:  bad video_isoc_maxframesize\n");
+			return -ENOENT;
+		}
+		peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
+		JOT(4, "%i=video_isoc_framesperdesc\n", \
+					peasycap->video_isoc_framesperdesc);
+		if (0 >= peasycap->video_isoc_framesperdesc) {
+			SAY("ERROR:  bad video_isoc_framesperdesc\n");
+			return -ENOENT;
+		}
+		peasycap->video_isoc_buffer_size = \
+					peasycap->video_isoc_maxframesize * \
+					peasycap->video_isoc_framesperdesc;
+		JOT(4, "%i=video_isoc_buffer_size\n", \
+					peasycap->video_isoc_buffer_size);
+		if ((PAGE_SIZE << VIDEO_ISOC_ORDER) < \
+					peasycap->video_isoc_buffer_size) {
+			SAY("MISTAKE: " \
+				"peasycap->video_isoc_buffer_size too big\n");
+			return -EFAULT;
+		}
+	}
+/*---------------------------------------------------------------------------*/
+	if (-1 == peasycap->video_interface) {
+		SAY("MISTAKE:  video_interface is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->video_altsetting_on) {
+		SAY("MISTAKE:  video_altsetting_on is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->video_altsetting_off) {
+		SAY("MISTAKE:  video_interface_off is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->video_endpointnumber) {
+		SAY("MISTAKE:  video_endpointnumber is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->video_isoc_maxframesize) {
+		SAY("MISTAKE:  video_isoc_maxframesize is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->video_isoc_buffer_size) {
+		SAY("MISTAKE:  video_isoc_buffer_size is unset\n");
+		return -EFAULT;
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE MEMORY FOR VIDEO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
+ */
+/*---------------------------------------------------------------------------*/
+	INIT_LIST_HEAD(&(peasycap->urb_video_head));
+	peasycap->purb_video_head = &(peasycap->urb_video_head);
+/*---------------------------------------------------------------------------*/
+	JOT(4, "allocating %i frame buffers of size %li\n",  \
+			FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
+	JOT(4, ".... each scattered over %li pages\n", \
+						FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+	for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
+		for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
+			if ((void *)NULL != peasycap->frame_buffer[k][m].pgo)
+				SAY("attempting to reallocate frame " \
+								" buffers\n");
+			else {
+				pbuf = (void *)__get_free_page(GFP_KERNEL);
+				if ((void *)NULL == pbuf) {
+					SAY("ERROR: Could not allocate frame "\
+						"buffer %i page %i\n", k, m);
+					return -ENOMEM;
+				} else
+					peasycap->allocation_video_page += 1;
+				peasycap->frame_buffer[k][m].pgo = pbuf;
+			}
+			peasycap->frame_buffer[k][m].pto = \
+					peasycap->frame_buffer[k][m].pgo;
+		}
+	}
+
+	peasycap->frame_fill = 0;
+	peasycap->frame_read = 0;
+	JOT(4, "allocation of frame buffers done:  %i pages\n", k * \
+								m);
+/*---------------------------------------------------------------------------*/
+	JOT(4, "allocating %i field buffers of size %li\n",  \
+			FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
+	JOT(4, ".... each scattered over %li pages\n", \
+					FIELD_BUFFER_SIZE/PAGE_SIZE);
+
+	for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
+		for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
+			if ((void *)NULL != peasycap->field_buffer[k][m].pgo) {
+				SAY("ERROR: attempting to reallocate " \
+							"field buffers\n");
+			} else {
+				pbuf = (void *) __get_free_page(GFP_KERNEL);
+				if ((void *)NULL == pbuf) {
+					SAY("ERROR: Could not allocate field" \
+						" buffer %i page %i\n", k, m);
+					return -ENOMEM;
+					}
+				else
+					peasycap->allocation_video_page += 1;
+				peasycap->field_buffer[k][m].pgo = pbuf;
+				}
+			peasycap->field_buffer[k][m].pto = \
+					peasycap->field_buffer[k][m].pgo;
+		}
+		peasycap->field_buffer[k][0].kount = 0x0200;
+	}
+	peasycap->field_fill = 0;
+	peasycap->field_page = 0;
+	peasycap->field_read = 0;
+	JOT(4, "allocation of field buffers done:  %i pages\n", k * \
+								m);
+/*---------------------------------------------------------------------------*/
+	JOT(4, "allocating %i isoc video buffers of size %i\n",  \
+					VIDEO_ISOC_BUFFER_MANY, \
+					peasycap->video_isoc_buffer_size);
+	JOT(4, ".... each occupying contiguous memory pages\n");
+
+	for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
+		pbuf = (void *)__get_free_pages(GFP_KERNEL, VIDEO_ISOC_ORDER);
+		if (NULL == pbuf) {
+			SAY("ERROR: Could not allocate isoc video buffer " \
+								"%i\n", k);
+			return -ENOMEM;
+		} else
+			peasycap->allocation_video_page += \
+				((unsigned int)(0x01 << VIDEO_ISOC_ORDER));
+
+		peasycap->video_isoc_buffer[k].pgo = pbuf;
+		peasycap->video_isoc_buffer[k].pto = pbuf + \
+					peasycap->video_isoc_buffer_size;
+		peasycap->video_isoc_buffer[k].kount = k;
+	}
+	JOT(4, "allocation of isoc video buffers done: %i pages\n", \
+					k * (0x01 << VIDEO_ISOC_ORDER));
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
+ */
+/*---------------------------------------------------------------------------*/
+	JOT(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+	JOT(4, "using %i=peasycap->video_isoc_framesperdesc\n", \
+					peasycap->video_isoc_framesperdesc);
+	JOT(4, "using %i=peasycap->video_isoc_maxframesize\n", \
+					peasycap->video_isoc_maxframesize);
+	JOT(4, "using %i=peasycap->video_isoc_buffer_sizen", \
+					peasycap->video_isoc_buffer_size);
+
+	for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY; k++) {
+		purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc, \
+								GFP_KERNEL);
+		if (NULL == purb) {
+			SAY("ERROR: usb_alloc_urb returned NULL for buffer " \
+								"%i\n", k);
+			return -ENOMEM;
+		} else
+			peasycap->allocation_video_urb += 1;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+		pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+		if (NULL == pdata_urb) {
+			SAY("ERROR: Could not allocate struct data_urb.\n");
+			return -ENOMEM;
+		} else
+			peasycap->allocation_video_struct += \
+						sizeof(struct data_urb);
+
+		pdata_urb->purb = purb;
+		pdata_urb->isbuf = k;
+		pdata_urb->length = 0;
+		list_add_tail(&(pdata_urb->list_head), \
+						peasycap->purb_video_head);
+/*---------------------------------------------------------------------------*/
+/*
+ *  ... AND INITIALIZE THEM
+ */
+/*---------------------------------------------------------------------------*/
+		if (!k) {
+			JOT(4, "initializing video urbs thus:\n");
+			JOT(4, "  purb->interval = 1;\n");
+			JOT(4, "  purb->dev = peasycap->pusb_device;\n");
+			JOT(4, "  purb->pipe = usb_rcvisocpipe" \
+					"(peasycap->pusb_device,%i);\n", \
+					peasycap->video_endpointnumber);
+			JOT(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
+			JOT(4, "  purb->transfer_buffer = peasycap->" \
+					"video_isoc_buffer[.].pgo;\n");
+			JOT(4, "  purb->transfer_buffer_length = %i;\n", \
+					peasycap->video_isoc_buffer_size);
+			JOT(4, "  purb->complete = easycap_complete;\n");
+			JOT(4, "  purb->context = peasycap;\n");
+			JOT(4, "  purb->start_frame = 0;\n");
+			JOT(4, "  purb->number_of_packets = %i;\n", \
+					peasycap->video_isoc_framesperdesc);
+			JOT(4, "  for (j = 0; j < %i; j++)\n", \
+					peasycap->video_isoc_framesperdesc);
+			JOT(4, "    {\n");
+			JOT(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",\
+					peasycap->video_isoc_maxframesize);
+			JOT(4, "    purb->iso_frame_desc[j].length = %i;\n", \
+					peasycap->video_isoc_maxframesize);
+			JOT(4, "    }\n");
+		}
+
+		purb->interval = 1;
+		purb->dev = peasycap->pusb_device;
+		purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, \
+					peasycap->video_endpointnumber);
+		purb->transfer_flags = URB_ISO_ASAP;
+		purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
+		purb->transfer_buffer_length = \
+					peasycap->video_isoc_buffer_size;
+		purb->complete = easycap_complete;
+		purb->context = peasycap;
+		purb->start_frame = 0;
+		purb->number_of_packets = peasycap->video_isoc_framesperdesc;
+		for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
+			purb->iso_frame_desc[j].offset = j * \
+					peasycap->video_isoc_maxframesize;
+			purb->iso_frame_desc[j].length = \
+					peasycap->video_isoc_maxframesize;
+		}
+	}
+	JOT(4, "allocation of %i struct urb done.\n", k);
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAVE POINTER peasycap IN THIS INTERFACE.
+ */
+/*--------------------------------------------------------------------------*/
+	usb_set_intfdata(pusb_interface, peasycap);
+/*--------------------------------------------------------------------------*/
+/*
+ *  THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
+ */
+/*--------------------------------------------------------------------------*/
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+	if (0 != (usb_register_dev(pusb_interface, &easycap_class))) {
+		err("Not able to get a minor for this device");
+		usb_set_intfdata(pusb_interface, NULL);
+		return -ENODEV;
+	} else
+		(peasycap->registered_video)++;
+	SAY("easycap attached to minor #%d\n", pusb_interface->minor);
+	break;
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+	pvideo_device = (struct video_device *)\
+			kzalloc(sizeof(struct video_device), GFP_KERNEL);
+	if ((struct video_device *)NULL == pvideo_device) {
+		SAY("ERROR: Could not allocate structure video_device\n");
+		return -ENOMEM;
+	}
+	if (VIDEO_DEVICE_MANY <= video_device_many) {
+		SAY("ERROR: Too many /dev/videos\n");
+		return -ENOMEM;
+	}
+	pvideo_array[video_device_many] = pvideo_device;  video_device_many++;
+
+	strcpy(&pvideo_device->name[0], "easycapdc60");
+#if defined(EASYCAP_NEEDS_V4L2_FOPS)
+	pvideo_device->fops = &v4l2_fops;
+#else
+	pvideo_device->fops = &easycap_fops;
+#endif /*EASYCAP_NEEDS_V4L2_FOPS*/
+	pvideo_device->minor = -1;
+	pvideo_device->release = (void *)(&videodev_release);
+
+	video_set_drvdata(pvideo_device, (void *)peasycap);
+
+	rc = video_register_device(pvideo_device, VFL_TYPE_GRABBER, -1);
+	if (0 != rc) {
+		err("Not able to register with videodev");
+		videodev_release(pvideo_device);
+		return -ENODEV;
+	} else {
+		peasycap->pvideo_device = pvideo_device;
+		(peasycap->registered_video)++;
+		JOT(4, "registered with videodev: %i=minor\n", \
+							pvideo_device->minor);
+	}
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+	break;
+}
+/*--------------------------------------------------------------------------*/
+/*
+ *  INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
+ *  INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
+ */
+/*--------------------------------------------------------------------------*/
+case 1: {
+/*--------------------------------------------------------------------------*/
+/*
+ *  SAVE POINTER peasycap IN INTERFACE 1
+ */
+/*--------------------------------------------------------------------------*/
+	usb_set_intfdata(pusb_interface, peasycap);
+	JOT(4, "no initialization required for interface %i\n", \
+				pusb_interface_descriptor->bInterfaceNumber);
+	break;
+}
+/*--------------------------------------------------------------------------*/
+case 2: {
+	if (!peasycap) {
+		SAY("MISTAKE: peasycap is NULL\n");
+		return -EFAULT;
+	}
+	if (!isokalt) {
+		SAY("ERROR:  no viable audio_altsetting_on\n");
+		return -ENOENT;
+	} else {
+		peasycap->audio_altsetting_on = okalt[isokalt - 1];
+		JOT(4, "%i=audio_altsetting_on <====\n", \
+						peasycap->audio_altsetting_on);
+	}
+	if (!isokepn) {
+		SAY("ERROR:  no viable audio_endpointnumber\n");
+		return -ENOENT;
+	} else {
+		peasycap->audio_endpointnumber = okepn[isokepn - 1];
+		JOT(4, "%i=audio_endpointnumber\n", \
+					peasycap->audio_endpointnumber);
+	}
+	if (!isokmps) {
+		SAY("ERROR:  no viable audio_maxpacketsize\n");
+		return -ENOENT;
+	} else {
+		peasycap->audio_isoc_maxframesize = okmps[isokmps - 1];
+		JOT(4, "%i=audio_isoc_maxframesize\n", \
+					peasycap->audio_isoc_maxframesize);
+		if (0 >= peasycap->audio_isoc_maxframesize) {
+			SAY("ERROR:  bad audio_isoc_maxframesize\n");
+			return -ENOENT;
+		}
+		if (9 == peasycap->audio_isoc_maxframesize) {
+			peasycap->ilk |= 0x02;
+			SAY("hardware is FOUR-CVBS\n");
+			peasycap->microphone = true;
+			audio_pages_per_fragment = 2;
+		} else if (256 == peasycap->audio_isoc_maxframesize) {
+			peasycap->ilk &= ~0x02;
+			SAY("hardware is CVBS+S-VIDEO\n");
+			peasycap->microphone = false;
+			audio_pages_per_fragment = 4;
+		} else {
+			SAY("hardware is unidentified:\n");
+			SAY("%i=audio_isoc_maxframesize\n", \
+					peasycap->audio_isoc_maxframesize);
+			return -ENOENT;
+		}
+
+		audio_bytes_per_fragment = audio_pages_per_fragment * \
+								PAGE_SIZE ;
+		audio_buffer_page_many = (AUDIO_FRAGMENT_MANY * \
+						audio_pages_per_fragment);
+
+		JOT(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
+		JOT(4, "%6i=audio_pages_per_fragment\n", \
+						audio_pages_per_fragment);
+		JOT(4, "%6i=audio_bytes_per_fragment\n", \
+						audio_bytes_per_fragment);
+		JOT(4, "%6i=audio_buffer_page_many\n", audio_buffer_page_many);
+
+		peasycap->audio_isoc_framesperdesc = 128;
+
+		JOT(4, "%i=audio_isoc_framesperdesc\n", \
+					peasycap->audio_isoc_framesperdesc);
+		if (0 >= peasycap->audio_isoc_framesperdesc) {
+			SAY("ERROR:  bad audio_isoc_framesperdesc\n");
+			return -ENOENT;
+		}
+
+		peasycap->audio_isoc_buffer_size = \
+				peasycap->audio_isoc_maxframesize * \
+				peasycap->audio_isoc_framesperdesc;
+		JOT(4, "%i=audio_isoc_buffer_size\n", \
+					peasycap->audio_isoc_buffer_size);
+		if (AUDIO_ISOC_BUFFER_SIZE < \
+					peasycap->audio_isoc_buffer_size) {
+			SAY("MISTAKE:  audio_isoc_buffer_size bigger "
+			"than %li=AUDIO_ISOC_BUFFER_SIZE\n", \
+						AUDIO_ISOC_BUFFER_SIZE);
+			return -EFAULT;
+		}
+	}
+
+	if (-1 == peasycap->audio_interface) {
+		SAY("MISTAKE:  audio_interface is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->audio_altsetting_on) {
+		SAY("MISTAKE:  audio_altsetting_on is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->audio_altsetting_off) {
+		SAY("MISTAKE:  audio_interface_off is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->audio_endpointnumber) {
+		SAY("MISTAKE:  audio_endpointnumber is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->audio_isoc_maxframesize) {
+		SAY("MISTAKE:  audio_isoc_maxframesize is unset\n");
+		return -EFAULT;
+	}
+	if (-1 == peasycap->audio_isoc_buffer_size) {
+		SAY("MISTAKE:  audio_isoc_buffer_size is unset\n");
+		return -EFAULT;
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE MEMORY FOR AUDIO BUFFERS.  LISTS MUST BE INITIALIZED FIRST.
+ */
+/*---------------------------------------------------------------------------*/
+	INIT_LIST_HEAD(&(peasycap->urb_audio_head));
+	peasycap->purb_audio_head = &(peasycap->urb_audio_head);
+
+	JOT(4, "allocating an audio buffer\n");
+	JOT(4, ".... scattered over %i pages\n", audio_buffer_page_many);
+
+	for (k = 0;  k < audio_buffer_page_many;  k++) {
+		if ((void *)NULL != peasycap->audio_buffer[k].pgo) {
+			SAY("ERROR: attempting to reallocate audio buffers\n");
+		} else {
+			pbuf = (void *) __get_free_page(GFP_KERNEL);
+			if ((void *)NULL == pbuf) {
+				SAY("ERROR: Could not allocate audio " \
+							"buffer page %i\n", k);
+				return -ENOMEM;
+			} else
+				peasycap->allocation_audio_page += 1;
+
+			peasycap->audio_buffer[k].pgo = pbuf;
+		}
+		peasycap->audio_buffer[k].pto = peasycap->audio_buffer[k].pgo;
+	}
+
+	peasycap->audio_fill = 0;
+	peasycap->audio_read = 0;
+	JOT(4, "allocation of audio buffer done:  %i pages\n", k);
+/*---------------------------------------------------------------------------*/
+	JOT(4, "allocating %i isoc audio buffers of size %i\n",  \
+		AUDIO_ISOC_BUFFER_MANY, peasycap->audio_isoc_buffer_size);
+	JOT(4, ".... each occupying contiguous memory pages\n");
+
+	for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
+		pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
+		if (NULL == pbuf) {
+			SAY("ERROR: Could not allocate isoc audio buffer " \
+							"%i\n", k);
+			return -ENOMEM;
+		} else
+			peasycap->allocation_audio_page += \
+				((unsigned int)(0x01 << AUDIO_ISOC_ORDER));
+
+		peasycap->audio_isoc_buffer[k].pgo = pbuf;
+		peasycap->audio_isoc_buffer[k].pto = pbuf + \
+		peasycap->audio_isoc_buffer_size;
+		peasycap->audio_isoc_buffer[k].kount = k;
+	}
+	JOT(4, "allocation of isoc audio buffers done.\n");
+/*---------------------------------------------------------------------------*/
+/*
+ *  ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
+ */
+/*---------------------------------------------------------------------------*/
+	JOT(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+	JOT(4, "using %i=peasycap->audio_isoc_framesperdesc\n", \
+					peasycap->audio_isoc_framesperdesc);
+	JOT(4, "using %i=peasycap->audio_isoc_maxframesize\n", \
+					peasycap->audio_isoc_maxframesize);
+	JOT(4, "using %i=peasycap->audio_isoc_buffer_size\n", \
+					peasycap->audio_isoc_buffer_size);
+
+	for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY; k++) {
+		purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc, \
+								GFP_KERNEL);
+		if (NULL == purb) {
+			SAY("ERROR: usb_alloc_urb returned NULL for buffer " \
+							"%i\n", k);
+			return -ENOMEM;
+		} else
+			peasycap->allocation_audio_urb += 1 ;
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+		pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+		if (NULL == pdata_urb) {
+			SAY("ERROR: Could not allocate struct data_urb.\n");
+			return -ENOMEM;
+		} else
+			peasycap->allocation_audio_struct += \
+						sizeof(struct data_urb);
+
+		pdata_urb->purb = purb;
+		pdata_urb->isbuf = k;
+		pdata_urb->length = 0;
+		list_add_tail(&(pdata_urb->list_head), \
+						peasycap->purb_audio_head);
+/*---------------------------------------------------------------------------*/
+/*
+ *  ... AND INITIALIZE THEM
+ */
+/*---------------------------------------------------------------------------*/
+		if (!k) {
+			JOT(4, "initializing audio urbs thus:\n");
+			JOT(4, "  purb->interval = 1;\n");
+			JOT(4, "  purb->dev = peasycap->pusb_device;\n");
+			JOT(4, "  purb->pipe = usb_rcvisocpipe(peasycap->" \
+					"pusb_device,%i);\n", \
+					peasycap->audio_endpointnumber);
+			JOT(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
+			JOT(4, "  purb->transfer_buffer = " \
+				"peasycap->audio_isoc_buffer[.].pgo;\n");
+			JOT(4, "  purb->transfer_buffer_length = %i;\n", \
+					peasycap->audio_isoc_buffer_size);
+			JOT(4, "  purb->complete = easysnd_complete;\n");
+			JOT(4, "  purb->context = peasycap;\n");
+			JOT(4, "  purb->start_frame = 0;\n");
+			JOT(4, "  purb->number_of_packets = %i;\n", \
+					peasycap->audio_isoc_framesperdesc);
+			JOT(4, "  for (j = 0; j < %i; j++)\n", \
+					peasycap->audio_isoc_framesperdesc);
+			JOT(4, "    {\n");
+			JOT(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",\
+					peasycap->audio_isoc_maxframesize);
+			JOT(4, "    purb->iso_frame_desc[j].length = %i;\n", \
+					peasycap->audio_isoc_maxframesize);
+			JOT(4, "    }\n");
+			}
+
+		purb->interval = 1;
+		purb->dev = peasycap->pusb_device;
+		purb->pipe = usb_rcvisocpipe(peasycap->pusb_device, \
+					peasycap->audio_endpointnumber);
+		purb->transfer_flags = URB_ISO_ASAP;
+		purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
+		purb->transfer_buffer_length = \
+					peasycap->audio_isoc_buffer_size;
+		purb->complete = easysnd_complete;
+		purb->context = peasycap;
+		purb->start_frame = 0;
+		purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+		for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
+			purb->iso_frame_desc[j].offset = j * \
+					peasycap->audio_isoc_maxframesize;
+			purb->iso_frame_desc[j].length = \
+					peasycap->audio_isoc_maxframesize;
+		}
+	}
+	JOT(4, "allocation of %i struct urb done.\n", k);
+/*---------------------------------------------------------------------------*/
+/*
+ *  SAVE POINTER peasycap IN THIS INTERFACE.
+ */
+/*---------------------------------------------------------------------------*/
+	usb_set_intfdata(pusb_interface, peasycap);
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
+ */
+/*---------------------------------------------------------------------------*/
+	rc = usb_register_dev(pusb_interface, &easysnd_class);
+	if (0 != rc) {
+		err("Not able to get a minor for this device.");
+		usb_set_intfdata(pusb_interface, NULL);
+		return -ENODEV;
+	} else
+		(peasycap->registered_audio)++;
+/*---------------------------------------------------------------------------*/
+/*
+ *  LET THE USER KNOW WHAT NODE THE AUDIO DEVICE IS ATTACHED TO.
+ */
+/*---------------------------------------------------------------------------*/
+	SAY("easysnd attached to minor #%d\n", pusb_interface->minor);
+	break;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
+ */
+/*---------------------------------------------------------------------------*/
+default: {
+	JOT(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
+	return -EINVAL;
+}
+}
+JOT(4, "ends successfully for interface %i\n", \
+				pusb_interface_descriptor->bInterfaceNumber);
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY
+ *  UNPLUGGED.
+ *  HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL.
+ */
+/*---------------------------------------------------------------------------*/
+void
+easycap_usb_disconnect(struct usb_interface *pusb_interface)
+{
+struct usb_host_interface *pusb_host_interface;
+struct usb_interface_descriptor *pusb_interface_descriptor;
+__u8 bInterfaceNumber;
+struct easycap *peasycap;
+
+struct list_head *plist_head;
+struct data_urb *pdata_urb;
+int minor, m;
+
+JOT(4, "\n");
+
+if ((struct usb_interface *)NULL == pusb_interface) {
+	JOT(4, "ERROR: pusb_interface is NULL\n");
+	return;
+}
+pusb_host_interface = pusb_interface->cur_altsetting;
+if ((struct usb_host_interface *)NULL == pusb_host_interface) {
+	JOT(4, "ERROR: pusb_host_interface is NULL\n");
+	return;
+}
+pusb_interface_descriptor = &(pusb_host_interface->desc);
+if ((struct usb_interface_descriptor *)NULL == pusb_interface_descriptor) {
+	JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
+	return;
+}
+bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
+minor = pusb_interface->minor;
+JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
+
+peasycap = usb_get_intfdata(pusb_interface);
+if ((struct easycap *)NULL == peasycap)
+	SAY("ERROR: peasycap is NULL\n");
+else {
+	peasycap->pusb_device = (struct usb_device *)NULL;
+	switch (bInterfaceNumber) {
+/*---------------------------------------------------------------------------*/
+	case 0: {
+		if ((struct list_head *)NULL != peasycap->purb_video_head) {
+			JOT(4, "killing video urbs\n");
+			m = 0;
+			list_for_each(plist_head, (peasycap->purb_video_head))
+				{
+				pdata_urb = list_entry(plist_head, \
+						struct data_urb, list_head);
+				if ((struct data_urb *)NULL != pdata_urb) {
+					if ((struct urb *)NULL != \
+							pdata_urb->purb) {
+						usb_kill_urb(pdata_urb->purb);
+						m++;
+					}
+				}
+			}
+			JOT(4, "%i video urbs killed\n", m);
+		} else
+			SAY("ERROR: peasycap->purb_video_head is NULL\n");
+		break;
+	}
+/*---------------------------------------------------------------------------*/
+	case 2: {
+		if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+			JOT(4, "killing audio urbs\n");
+			m = 0;
+			list_for_each(plist_head, \
+						(peasycap->purb_audio_head)) {
+				pdata_urb = list_entry(plist_head, \
+						struct data_urb, list_head);
+				if ((struct data_urb *)NULL != pdata_urb) {
+					if ((struct urb *)NULL != \
+							pdata_urb->purb) {
+						usb_kill_urb(pdata_urb->purb);
+						m++;
+					}
+				}
+			}
+			JOT(4, "%i audio urbs killed\n", m);
+		} else
+			SAY("ERROR: peasycap->purb_audio_head is NULL\n");
+		break;
+	}
+/*---------------------------------------------------------------------------*/
+	default:
+		break;
+	}
+}
+/*--------------------------------------------------------------------------*/
+/*
+ *  DEREGISTER
+ */
+/*--------------------------------------------------------------------------*/
+switch (bInterfaceNumber) {
+case 0: {
+#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
+	if ((struct easycap *)NULL == peasycap) {
+		SAY("ERROR: peasycap has become NULL\n");
+	} else {
+		lock_kernel();
+		usb_deregister_dev(pusb_interface, &easycap_class);
+		(peasycap->registered_video)--;
+
+		JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
+		unlock_kernel();
+		SAY("easycap detached from minor #%d\n", minor);
+	}
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#else
+	if ((struct easycap *)NULL == peasycap)
+		SAY("ERROR: peasycap has become NULL\n");
+	else {
+		lock_kernel();
+		video_unregister_device(peasycap->pvideo_device);
+		(peasycap->registered_video)--;
+		unlock_kernel();
+		JOT(4, "unregistered with videodev: %i=minor\n", \
+							pvideo_device->minor);
+	}
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+	break;
+}
+case 2: {
+	lock_kernel();
+
+	usb_deregister_dev(pusb_interface, &easysnd_class);
+	if ((struct easycap *)NULL != peasycap)
+		(peasycap->registered_audio)--;
+
+	JOT(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
+	unlock_kernel();
+
+	SAY("easysnd detached from minor #%d\n", minor);
+	break;
+}
+default:
+	break;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
+ */
+/*---------------------------------------------------------------------------*/
+if ((struct easycap *)NULL == peasycap) {
+	SAY("ERROR: peasycap has become NULL\n");
+	SAY("cannot call kref_put()\n");
+	SAY("ending unsuccessfully: may cause memory leak\n");
+	return;
+}
+if (!peasycap->kref.refcount.counter) {
+	SAY("ERROR: peasycap->kref.refcount.counter is zero " \
+						"so cannot call kref_put()\n");
+	SAY("ending unsuccessfully: may cause memory leak\n");
+	return;
+}
+JOT(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \
+		bInterfaceNumber, (int)peasycap->kref.refcount.counter);
+kref_put(&peasycap->kref, easycap_delete);
+JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
+/*---------------------------------------------------------------------------*/
+
+JOT(4, "ends\n");
+return;
+}
+/*****************************************************************************/
+int __init
+easycap_module_init(void)
+{
+int result;
+
+SAY("========easycap=======\n");
+JOT(4, "begins.  %i=debug\n", easycap_debug);
+SAY("version: " EASYCAP_DRIVER_VERSION "\n");
+/*---------------------------------------------------------------------------*/
+/*
+ *  REGISTER THIS DRIVER WITH THE USB SUBSYTEM.
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "registering driver easycap\n");
+
+result = usb_register(&easycap_usb_driver);
+if (0 != result)
+	SAY("ERROR:  usb_register returned %i\n", result);
+
+JOT(4, "ends\n");
+return result;
+}
+/*****************************************************************************/
+void __exit
+easycap_module_exit(void)
+{
+JOT(4, "begins\n");
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  DEREGISTER THIS DRIVER WITH THE USB SUBSYTEM.
+ */
+/*---------------------------------------------------------------------------*/
+usb_deregister(&easycap_usb_driver);
+
+JOT(4, "ends\n");
+}
+/*****************************************************************************/
+
+module_init(easycap_module_init);
+module_exit(easycap_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("R.M. Thomas <rmthomas at sciolus.org>");
+MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
+MODULE_VERSION(EASYCAP_DRIVER_VERSION);
+#if defined(EASYCAP_DEBUG)
+MODULE_PARM_DESC(easycap_debug, "debug: 0 (default), 1, 2,...");
+#endif /*EASYCAP_DEBUG*/
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/easycap/easycap_settings.c
new file mode 100644
index 0000000..1e4eb23
--- /dev/null
+++ b/drivers/staging/easycap/easycap_settings.c
@@ -0,0 +1,489 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_settings.c                                                         *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
+ *                         0 => 25 fps
+ *                         1 => 30 fps
+ */
+/*---------------------------------------------------------------------------*/
+struct easycap_standard easycap_standard[] = {
+{
+.mask = 0x000F & PAL_BGHIN ,
+.v4l2_standard = {
+	.index = PAL_BGHIN,
+	.id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G | V4L2_STD_PAL_H | \
+					V4L2_STD_PAL_I | V4L2_STD_PAL_N),
+	.name = "PAL_BGHIN",
+	.frameperiod = {1, 25},
+	.framelines = 625,
+	.reserved = {0, 0, 0, 0}
+	}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_N_443 ,
+.v4l2_standard = {
+	.index = NTSC_N_443,
+	.id = V4L2_STD_UNKNOWN,
+	.name = "NTSC_N_443",
+	.frameperiod = {1, 25},
+	.framelines = 480,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & PAL_Nc ,
+.v4l2_standard = {
+	.index = PAL_Nc,
+	.id = V4L2_STD_PAL_Nc,
+	.name = "PAL_Nc",
+	.frameperiod = {1, 25},
+	.framelines = 625,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_N ,
+.v4l2_standard = {
+	.index = NTSC_N,
+	.id = V4L2_STD_UNKNOWN,
+	.name = "NTSC_N",
+	.frameperiod = {1, 25},
+	.framelines = 525,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & SECAM ,
+.v4l2_standard = {
+	.index = SECAM,
+	.id = V4L2_STD_SECAM,
+	.name = "SECAM",
+	.frameperiod = {1, 25},
+	.framelines = 625,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_M ,
+.v4l2_standard = {
+	.index = NTSC_M,
+	.id = V4L2_STD_NTSC_M,
+	.name = "NTSC_M",
+	.frameperiod = {1, 30},
+	.framelines = 525,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_M_JP ,
+.v4l2_standard = {
+	.index = NTSC_M_JP,
+	.id = V4L2_STD_NTSC_M_JP,
+	.name = "NTSC_M_JP",
+	.frameperiod = {1, 30},
+	.framelines = 525,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & PAL_60 ,
+.v4l2_standard = {
+	.index = PAL_60,
+	.id = V4L2_STD_PAL_60,
+	.name = "PAL_60",
+	.frameperiod = {1, 30},
+	.framelines = 525,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & NTSC_443 ,
+.v4l2_standard = {
+	.index = NTSC_443,
+	.id = V4L2_STD_NTSC_443,
+	.name = "NTSC_443",
+	.frameperiod = {1, 30},
+	.framelines = 525,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0x000F & PAL_M ,
+.v4l2_standard = {
+	.index = PAL_M,
+	.id = V4L2_STD_PAL_M,
+	.name = "PAL_M",
+	.frameperiod = {1, 30},
+	.framelines = 525,
+	.reserved = {0, 0, 0, 0}
+}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.mask = 0xFFFF
+}
+};
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE 16-BIT easycap_format.mask HAS MEANING:
+ *    (least significant) BIT  0:     0 => PAL, 25 FPS;   1 => NTSC, 30 FPS
+ *                        BITS 1-3:   RESERVED FOR DIFFERENTIATING STANDARDS
+ *                        BITS 4-7:   NUMBER OF BYTES PER PIXEL
+ *                        BIT  8:     0 => NATIVE BYTE ORDER;  1 => SWAPPED
+ *                        BITS 9-10:  RESERVED FOR OTHER BYTE PERMUTATIONS
+ *                        BIT 11:     0 => UNDECIMATED;  1 => DECIMATED
+ *                        BIT 12:     0 => OFFER FRAMES; 1 => OFFER FIELDS
+ *     (most significant) BITS 13-15: RESERVED FOR OTHER FIELD ORDER OPTIONS
+ *  IT FOLLOWS THAT:
+ *     bytesperpixel IS         ((0x00F0 & easycap_format.mask) >> 4)
+ *     byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
+ *
+ *     decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
+ *
+ *       offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
+ */
+/*---------------------------------------------------------------------------*/
+
+struct easycap_format easycap_format[1 + SETTINGS_MANY];
+
+int
+fillin_formats(void)
+{
+int i, j, k, m, n;
+__u32 width, height, pixelformat, bytesperline, sizeimage;
+__u32 field, colorspace;
+__u16 mask1, mask2, mask3, mask4;
+char name1[32], name2[32], name3[32], name4[32];
+
+for (i = 0, n = 0; i < STANDARD_MANY; i++) {
+	mask1 = 0x0000;
+	switch (i) {
+	case PAL_BGHIN: {
+		mask1 = PAL_BGHIN;
+		strcpy(&name1[0], "PAL_BGHIN");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+		break;
+	}
+	case SECAM: {
+		mask1 = SECAM;
+		strcpy(&name1[0], "SECAM");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+		break;
+	}
+	case PAL_Nc: {
+		mask1 = PAL_Nc;
+		strcpy(&name1[0], "PAL_Nc");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+		break;
+	}
+	case PAL_60: {
+		mask1 = PAL_60;
+		strcpy(&name1[0], "PAL_60");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+		break;
+	}
+	case PAL_M: {
+		mask1 = PAL_M;
+		strcpy(&name1[0], "PAL_M");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
+		break;
+	}
+	case NTSC_M: {
+		mask1 = NTSC_M;
+		strcpy(&name1[0], "NTSC_M");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+		break;
+	}
+	case NTSC_443: {
+		mask1 = NTSC_443;
+		strcpy(&name1[0], "NTSC_443");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+		break;
+	}
+	case NTSC_M_JP: {
+		mask1 = NTSC_M_JP;
+		strcpy(&name1[0], "NTSC_M_JP");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+		break;
+	}
+	case NTSC_N: {
+		mask1 = NTSC_M;
+		strcpy(&name1[0], "NTSC_N");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+		break;
+	}
+	case NTSC_N_443: {
+		mask1 = NTSC_N_443;
+		strcpy(&name1[0], "NTSC_N_443");
+		colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
+		break;
+	}
+	default:
+		return -1;
+	}
+
+	for (j = 0; j < RESOLUTION_MANY; j++) {
+		mask2 = 0x0000;
+		switch (j) {
+		case AT_720x576: {
+			if (0x1 & mask1)
+				continue;
+			strcpy(&name2[0], "_AT_720x576");
+			width = 720; height = 576; break;
+		}
+		case AT_704x576: {
+			if (0x1 & mask1)
+				continue;
+			strcpy(&name2[0], "_AT_704x576");
+			width = 704; height = 576; break;
+		}
+		case AT_640x480: {
+			strcpy(&name2[0], "_AT_640x480");
+			width = 640; height = 480; break;
+		}
+		case AT_720x480: {
+			if (!(0x1 & mask1))
+				continue;
+			strcpy(&name2[0], "_AT_720x480");
+			width = 720; height = 480; break;
+		}
+		case AT_360x288: {
+			if (0x1 & mask1)
+				continue;
+			strcpy(&name2[0], "_AT_360x288");
+			width = 360; height = 288; mask2 = 0x0800; break;
+		}
+		case AT_320x240: {
+			strcpy(&name2[0], "_AT_320x240");
+			width = 320; height = 240; mask2 = 0x0800; break;
+		}
+		case AT_360x240: {
+			if (!(0x1 & mask1))
+				continue;
+			strcpy(&name2[0], "_AT_360x240");
+			width = 360; height = 240; mask2 = 0x0800; break;
+		}
+		default:
+			return -2;
+		}
+
+		for (k = 0; k < PIXELFORMAT_MANY; k++) {
+			mask3 = 0x0000;
+			switch (k) {
+			case FMT_UYVY: {
+				strcpy(&name3[0], "_" STRINGIZE(FMT_UYVY));
+				pixelformat = V4L2_PIX_FMT_UYVY;
+				mask3 |= (0x02 << 4);
+				break;
+			}
+			case FMT_YUY2: {
+				strcpy(&name3[0], "_" STRINGIZE(FMT_YUY2));
+				pixelformat = V4L2_PIX_FMT_YUYV;
+				mask3 |= (0x02 << 4);
+				mask3 |= 0x0100;
+				break;
+			}
+			case FMT_RGB24: {
+				strcpy(&name3[0], "_" STRINGIZE(FMT_RGB24));
+				pixelformat = V4L2_PIX_FMT_RGB24;
+				mask3 |= (0x03 << 4);
+				break;
+			}
+			case FMT_RGB32: {
+				strcpy(&name3[0], "_" STRINGIZE(FMT_RGB32));
+				pixelformat = V4L2_PIX_FMT_RGB32;
+				mask3 |= (0x04 << 4);
+				break;
+			}
+			case FMT_BGR24: {
+				strcpy(&name3[0], "_" STRINGIZE(FMT_BGR24));
+				pixelformat = V4L2_PIX_FMT_BGR24;
+				mask3 |= (0x03 << 4);
+				mask3 |= 0x0100;
+				break;
+			}
+			case FMT_BGR32: {
+				strcpy(&name3[0], "_" STRINGIZE(FMT_BGR32));
+				pixelformat = V4L2_PIX_FMT_BGR32;
+				mask3 |= (0x04 << 4);
+				mask3 |= 0x0100;
+				break;
+			}
+			default:
+				return -3;
+			}
+			bytesperline = width * ((mask3 & 0x00F0) >> 4);
+			sizeimage =  bytesperline * height;
+
+			for (m = 0; m < INTERLACE_MANY; m++) {
+				mask4 = 0x0000;
+				switch (m) {
+				case FIELD_NONE: {
+					strcpy(&name4[0], "-n");
+					field = V4L2_FIELD_NONE;
+					break;
+				}
+				case FIELD_INTERLACED: {
+					strcpy(&name4[0], "-i");
+					field = V4L2_FIELD_INTERLACED;
+					break;
+				}
+				case FIELD_ALTERNATE: {
+					strcpy(&name4[0], "-a");
+					mask4 |= 0x1000;
+					field = V4L2_FIELD_ALTERNATE;
+					break;
+				}
+				default:
+					return -4;
+				}
+				if (SETTINGS_MANY <= n)
+					return -5;
+				strcpy(&easycap_format[n].name[0], &name1[0]);
+				strcat(&easycap_format[n].name[0], &name2[0]);
+				strcat(&easycap_format[n].name[0], &name3[0]);
+				strcat(&easycap_format[n].name[0], &name4[0]);
+				easycap_format[n].mask = \
+						mask1 | mask2 | mask3 | mask4;
+				easycap_format[n].v4l2_format\
+					.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.width = width;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.height = height;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.pixelformat = pixelformat;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.field = field;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.bytesperline = bytesperline;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.sizeimage = sizeimage;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.colorspace = colorspace;
+				easycap_format[n].v4l2_format\
+					.fmt.pix.priv = 0;
+				n++;
+			}
+		}
+	}
+}
+if ((1 + SETTINGS_MANY) <= n)
+	return -6;
+easycap_format[n].mask = 0xFFFF;
+return n;
+}
+/*---------------------------------------------------------------------------*/
+struct v4l2_queryctrl easycap_control[] = \
+ {{
+.id       = V4L2_CID_BRIGHTNESS,
+.type     = V4L2_CTRL_TYPE_INTEGER,
+.name     = "Brightness",
+.minimum  = 0,
+.maximum  = 255,
+.step     =  1,
+.default_value = SAA_0A_DEFAULT,
+.flags    = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id       = V4L2_CID_CONTRAST,
+.type     = V4L2_CTRL_TYPE_INTEGER,
+.name     = "Contrast",
+.minimum  = 0,
+.maximum  = 255,
+.step     =   1,
+.default_value = SAA_0B_DEFAULT + 128,
+.flags    = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id       = V4L2_CID_SATURATION,
+.type     = V4L2_CTRL_TYPE_INTEGER,
+.name     = "Saturation",
+.minimum  = 0,
+.maximum  = 255,
+.step     =   1,
+.default_value = SAA_0C_DEFAULT + 128,
+.flags    = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id       = V4L2_CID_HUE,
+.type     = V4L2_CTRL_TYPE_INTEGER,
+.name     = "Hue",
+.minimum  = 0,
+.maximum  = 255,
+.step     =   1,
+.default_value = SAA_0D_DEFAULT + 128,
+.flags    = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id       = V4L2_CID_AUDIO_VOLUME,
+.type     = V4L2_CTRL_TYPE_INTEGER,
+.name     = "Volume",
+.minimum  = 0,
+.maximum  = 31,
+.step     =   1,
+.default_value = 16,
+.flags    = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id       = V4L2_CID_AUDIO_MUTE,
+.type     = V4L2_CTRL_TYPE_BOOLEAN,
+.name     = "Mute",
+.default_value = true,
+.flags    = 0,
+.reserved = {0, 0}
+},
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+{
+.id = 0xFFFFFFFF
+}
+ };
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/easycap/easycap_sound.c
new file mode 100644
index 0000000..532c410
--- /dev/null
+++ b/drivers/staging/easycap/easycap_sound.c
@@ -0,0 +1,973 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_sound.c                                                            *
+*                                                                             *
+*  Audio driver for EasyCAP USB2.0 Video Capture Device DC60                  *
+*                                                                             *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+#include "easycap_sound.h"
+
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
+ *  PROVIDED peasycap->audio_idle IS ZER0.  REGARDLESS OF THIS BEING TRUE,
+ *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
+ */
+/*---------------------------------------------------------------------------*/
+void
+easysnd_complete(struct urb *purb)
+{
+static int mt;
+struct easycap *peasycap;
+struct data_buffer *paudio_buffer;
+char errbuf[16];
+__u8 *p1, *p2;
+__s16 s16;
+int i, j, more, much, leap, rc;
+
+JOT(16, "\n");
+
+if (NULL == purb) {
+	SAY("ERROR: purb is NULL\n");
+	return;
+}
+peasycap = purb->context;
+if (NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	return;
+}
+much = 0;
+
+
+if (peasycap->audio_idle) {
+	JOT(16, "%i=audio_idle  %i=audio_isoc_streaming\n", \
+			peasycap->audio_idle, peasycap->audio_isoc_streaming);
+	if (peasycap->audio_isoc_streaming) {
+		rc = usb_submit_urb(purb, GFP_ATOMIC);
+		if (0 != rc) {
+			SAY("ERROR: while %i=audio_idle, " \
+					"usb_submit_urb() failed with rc:\n", \
+							peasycap->audio_idle);
+			switch (rc) {
+			case -ENOMEM: {
+				SAY("ENOMEM\n");    break;
+			}
+			case -ENODEV: {
+				SAY("ENODEV\n");    break;
+			}
+			case -ENXIO: {
+				SAY("ENXIO\n");     break;
+			}
+			case -EINVAL: {
+				SAY("EINVAL\n");    break;
+			}
+			case -EAGAIN: {
+				SAY("EAGAIN\n");    break;
+			}
+			case -EFBIG: {
+				SAY("EFBIG\n");     break;
+			}
+			case -EPIPE: {
+				SAY("EPIPE\n");     break;
+			}
+			case -EMSGSIZE: {
+				SAY("EMSGSIZE\n");  break;
+			}
+			default: {
+				SAY("0x%08X\n", rc); break;
+			}
+			}
+		}
+	}
+return;
+}
+/*---------------------------------------------------------------------------*/
+if (purb->status) {
+	if (-ESHUTDOWN == purb->status) {
+		JOT(16, "immediate return because -ESHUTDOWN=purb->status\n");
+		return;
+	}
+	SAY("ERROR: non-zero urb status:\n");
+	switch (purb->status) {
+	case -EINPROGRESS: {
+		SAY("-EINPROGRESS\n"); break;
+	}
+	case -ENOSR: {
+		SAY("-ENOSR\n"); break;
+	}
+	case -EPIPE: {
+		SAY("-EPIPE\n"); break;
+	}
+	case -EOVERFLOW: {
+		SAY("-EOVERFLOW\n"); break;
+	}
+	case -EPROTO: {
+		SAY("-EPROTO\n"); break;
+	}
+	case -EILSEQ: {
+		SAY("-EILSEQ\n"); break;
+	}
+	case -ETIMEDOUT: {
+		SAY("-ETIMEDOUT\n"); break;
+	}
+	case -EMSGSIZE: {
+		SAY("-EMSGSIZE\n"); break;
+	}
+	case -EOPNOTSUPP: {
+		SAY("-EOPNOTSUPP\n"); break;
+	}
+	case -EPFNOSUPPORT: {
+		SAY("-EPFNOSUPPORT\n"); break;
+	}
+	case -EAFNOSUPPORT: {
+		SAY("-EAFNOSUPPORT\n"); break;
+	}
+	case -EADDRINUSE: {
+		SAY("-EADDRINUSE\n"); break;
+	}
+	case -EADDRNOTAVAIL: {
+		SAY("-EADDRNOTAVAIL\n"); break;
+	}
+	case -ENOBUFS: {
+		SAY("-ENOBUFS\n"); break;
+	}
+	case -EISCONN: {
+		SAY("-EISCONN\n"); break;
+	}
+	case -ENOTCONN: {
+		SAY("-ENOTCONN\n"); break;
+	}
+	case -ESHUTDOWN: {
+		SAY("-ESHUTDOWN\n"); break;
+	}
+	case -ENOENT: {
+		SAY("-ENOENT\n"); break;
+	}
+	case -ECONNRESET: {
+		SAY("-ECONNRESET\n"); break;
+	}
+	default: {
+		SAY("unknown error code 0x%08X\n", purb->status); break;
+	}
+	}
+/*---------------------------------------------------------------------------*/
+/*
+ *  RESUBMIT THIS URB AFTER AN ERROR
+ *
+ *  (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)
+ */
+/*---------------------------------------------------------------------------*/
+	if (peasycap->audio_isoc_streaming) {
+		rc = usb_submit_urb(purb, GFP_ATOMIC);
+		if (0 != rc) {
+			SAY("ERROR: while %i=audio_idle, usb_submit_urb() "
+				"failed with rc:\n", peasycap->audio_idle);
+			switch (rc) {
+			case -ENOMEM: {
+				SAY("ENOMEM\n");    break;
+			}
+			case -ENODEV: {
+				SAY("ENODEV\n");    break;
+			}
+			case -ENXIO: {
+				SAY("ENXIO\n");     break;
+			}
+			case -EINVAL: {
+				SAY("EINVAL\n");    break;
+			}
+			case -EAGAIN: {
+				SAY("EAGAIN\n");    break;
+			}
+			case -EFBIG: {
+				SAY("EFBIG\n");     break;
+			}
+			case -EPIPE: {
+				SAY("EPIPE\n");     break;
+			}
+			case -EMSGSIZE: {
+				SAY("EMSGSIZE\n");  break;
+			}
+			default: {
+				SAY("0x%08X\n", rc); break;
+			}
+			}
+		}
+	}
+	return;
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  PROCEED HERE WHEN NO ERROR
+ */
+/*---------------------------------------------------------------------------*/
+for (i = 0;  i < purb->number_of_packets; i++) {
+	switch (purb->iso_frame_desc[i].status) {
+	case  0: {
+		strcpy(&errbuf[0], "OK"); break;
+	}
+	case -ENOENT: {
+		strcpy(&errbuf[0], "-ENOENT"); break;
+	}
+	case -EINPROGRESS: {
+		strcpy(&errbuf[0], "-EINPROGRESS"); break;
+	}
+	case -EPROTO: {
+		strcpy(&errbuf[0], "-EPROTO"); break;
+	}
+	case -EILSEQ: {
+		strcpy(&errbuf[0], "-EILSEQ"); break;
+	}
+	case -ETIME: {
+		strcpy(&errbuf[0], "-ETIME"); break;
+	}
+	case -ETIMEDOUT: {
+		strcpy(&errbuf[0], "-ETIMEDOUT"); break;
+	}
+	case -EPIPE: {
+		strcpy(&errbuf[0], "-EPIPE"); break;
+	}
+	case -ECOMM: {
+		strcpy(&errbuf[0], "-ECOMM"); break;
+	}
+	case -ENOSR: {
+		strcpy(&errbuf[0], "-ENOSR"); break;
+	}
+	case -EOVERFLOW: {
+		strcpy(&errbuf[0], "-EOVERFLOW"); break;
+	}
+	case -EREMOTEIO: {
+		strcpy(&errbuf[0], "-EREMOTEIO"); break;
+	}
+	case -ENODEV: {
+		strcpy(&errbuf[0], "-ENODEV"); break;
+	}
+	case -EXDEV: {
+		strcpy(&errbuf[0], "-EXDEV"); break;
+	}
+	case -EINVAL: {
+		strcpy(&errbuf[0], "-EINVAL"); break;
+	}
+	case -ECONNRESET: {
+		strcpy(&errbuf[0], "-ECONNRESET"); break;
+	}
+	case -ESHUTDOWN: {
+		strcpy(&errbuf[0], "-ESHUTDOWN"); break;
+	}
+	default: {
+		strcpy(&errbuf[0], "UNKNOWN"); break;
+	}
+	}
+	if ((!purb->iso_frame_desc[i].status) && 0) {
+		JOT(16, "frame[%2i]: %i=status{=%16s}  "  \
+						"%5i=actual  "  \
+						"%5i=length  "  \
+						"%3i=offset\n", \
+				i, purb->iso_frame_desc[i].status, &errbuf[0],
+				purb->iso_frame_desc[i].actual_length,
+				purb->iso_frame_desc[i].length,
+				purb->iso_frame_desc[i].offset);
+	}
+	if (!purb->iso_frame_desc[i].status) {
+		more = purb->iso_frame_desc[i].actual_length;
+
+#if defined(TESTTONE)
+		if (!more)
+			more = purb->iso_frame_desc[i].length;
+#endif
+
+		if (!more)
+			mt++;
+		else {
+			if (mt) {
+				JOT(16, "%4i empty audio urb frames\n", mt);
+				mt = 0;
+			}
+
+			p1 = (__u8 *)(purb->transfer_buffer + \
+					purb->iso_frame_desc[i].offset);
+
+			leap = 0;
+			p1 += leap;
+			more -= leap;
+/*---------------------------------------------------------------------------*/
+/*
+ *  COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
+ *  CONVERTING 8-BIT SAMPLES TO 16-BIT SIGNED LITTLE-ENDED SAMPLES IF NECESSARY
+ */
+/*---------------------------------------------------------------------------*/
+			while (more) {
+				if (0 > more) {
+					SAY("easysnd_complete: MISTAKE: " \
+							"more is negative\n");
+					return;
+				}
+				if (audio_buffer_page_many <= \
+							peasycap->audio_fill) {
+					SAY("ERROR: bad " \
+						"peasycap->audio_fill\n");
+					return;
+				}
+
+				paudio_buffer = &peasycap->audio_buffer\
+							[peasycap->audio_fill];
+				if (PAGE_SIZE < (paudio_buffer->pto - \
+						paudio_buffer->pgo)) {
+					SAY("ERROR: bad paudio_buffer->pto\n");
+					return;
+				}
+				if (PAGE_SIZE == (paudio_buffer->pto - \
+							paudio_buffer->pgo)) {
+
+#if defined(TESTTONE)
+					easysnd_testtone(peasycap, \
+							peasycap->audio_fill);
+#endif /*TESTTONE*/
+
+					paudio_buffer->pto = \
+							paudio_buffer->pgo;
+					(peasycap->audio_fill)++;
+					if (audio_buffer_page_many <= \
+							peasycap->audio_fill)
+						peasycap->audio_fill = 0;
+
+					JOT(12, "bumped peasycap->" \
+							"audio_fill to %i\n", \
+							peasycap->audio_fill);
+
+					paudio_buffer = &peasycap->\
+							audio_buffer\
+							[peasycap->audio_fill];
+					paudio_buffer->pto = \
+							paudio_buffer->pgo;
+
+					if (!(peasycap->audio_fill % \
+						audio_pages_per_fragment)) {
+						JOT(12, "wakeup call on wq_" \
+						"audio, %i=frag reading  %i" \
+						"=fragment fill\n", \
+						(peasycap->audio_read / \
+						audio_pages_per_fragment), \
+						(peasycap->audio_fill / \
+						audio_pages_per_fragment));
+						wake_up_interruptible\
+						(&(peasycap->wq_audio));
+					}
+				}
+
+				much = PAGE_SIZE - (int)(paudio_buffer->pto -\
+							 paudio_buffer->pgo);
+				if (much % 2)
+					JOT(8, "MISTAKE?  much is odd\n");
+
+				if (false == peasycap->microphone) {
+					if (much > more)
+						much = more;
+
+					memcpy(paudio_buffer->pto, p1, much);
+					p1 += much;
+					more -= much;
+				} else {
+					if (much > (2 * more))
+						much = 2 * more;
+					p2 = (__u8 *)paudio_buffer->pto;
+
+					for (j = 0;  j < (much / 2);  j++) {
+						s16 =  ((int) *p1) - 128;
+						*p2      = (0xFF00 & s16) >> 8;
+						*(p2 + 1) = (0x00FF & s16);
+						p1++;  p2 += 2;
+						more--;
+					}
+				}
+				(paudio_buffer->pto) += much;
+			}
+		}
+	} else {
+		JOT(12, "discarding audio samples because " \
+			"%i=purb->iso_frame_desc[i].status\n", \
+				purb->iso_frame_desc[i].status);
+	}
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  RESUBMIT THIS URB AFTER NO ERROR
+ */
+/*---------------------------------------------------------------------------*/
+if (peasycap->audio_isoc_streaming) {
+	rc = usb_submit_urb(purb, GFP_ATOMIC);
+	if (0 != rc) {
+		SAY("ERROR: while %i=audio_idle, usb_submit_urb() failed " \
+					"with rc:\n", peasycap->audio_idle);
+		switch (rc) {
+		case -ENOMEM: {
+			SAY("ENOMEM\n");    break;
+		}
+		case -ENODEV: {
+			SAY("ENODEV\n");    break;
+		}
+		case -ENXIO: {
+			SAY("ENXIO\n");     break;
+		}
+		case -EINVAL: {
+			SAY("EINVAL\n");    break;
+		}
+		case -EAGAIN: {
+			SAY("EAGAIN\n");    break;
+		}
+		case -EFBIG: {
+			SAY("EFBIG\n");     break;
+		}
+		case -EPIPE: {
+			SAY("EPIPE\n");     break;
+		}
+		case -EMSGSIZE: {
+			SAY("EMSGSIZE\n");  break;
+		}
+		default: {
+			SAY("0x%08X\n", rc); break;
+		}
+		}
+	}
+}
+return;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
+ *  STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
+ *  HAVE AN IOCTL INTERFACE.  THE VIDEO URBS, BY CONTRAST, MUST BE SUBMITTED
+ *  MUCH LATER: SEE COMMENTS IN FILE easycap_main.c.
+ */
+/*---------------------------------------------------------------------------*/
+int
+easysnd_open(struct inode *inode, struct file *file)
+{
+struct usb_interface *pusb_interface;
+struct easycap *peasycap;
+int subminor, rc;
+
+JOT(4, "begins.\n");
+
+subminor = iminor(inode);
+
+pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
+if (NULL == pusb_interface) {
+	SAY("ERROR: pusb_interface is NULL\n");
+	SAY("ending unsuccessfully\n");
+	return -1;
+}
+peasycap = usb_get_intfdata(pusb_interface);
+if (NULL == peasycap) {
+	SAY("ERROR: peasycap is NULL\n");
+	SAY("ending unsuccessfully\n");
+	return -1;
+}
+
+file->private_data = peasycap;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  INITIALIZATION.
+ */
+/*---------------------------------------------------------------------------*/
+JOT(4, "starting initialization\n");
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+} else {
+	JOT(16, "0x%08lX=peasycap->pusb_device\n", \
+					(long int)peasycap->pusb_device);
+}
+
+rc = audio_setup(peasycap);
+if (0 <= rc)
+	JOT(8, "audio_setup() returned %i\n", rc);
+else
+	JOT(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device has become NULL\n");
+	return -EFAULT;
+}
+rc = adjust_volume(peasycap, -8192);
+if (0 != rc) {
+	SAY("ERROR: adjust_volume(default) returned %i\n", rc);
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device has become NULL\n");
+	return -EFAULT;
+}
+rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
+					peasycap->audio_altsetting_on);
+JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
+					peasycap->audio_altsetting_on, rc);
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device has become NULL\n");
+	return -EFAULT;
+}
+rc = wakeup_device(peasycap->pusb_device);
+if (0 == rc)
+	JOT(8, "wakeup_device() returned %i\n", rc);
+else
+	JOT(8, "easysnd open(): ERROR: wakeup_device() returned %i\n", rc);
+
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device has become NULL\n");
+	return -EFAULT;
+}
+submit_audio_urbs(peasycap);
+peasycap->audio_idle = 0;
+
+peasycap->timeval1.tv_sec  = 0;
+peasycap->timeval1.tv_usec = 0;
+
+JOT(4, "finished initialization\n");
+return 0;
+}
+/*****************************************************************************/
+int
+easysnd_release(struct inode *inode, struct file *file)
+{
+struct easycap *peasycap;
+
+JOT(4, "begins\n");
+
+peasycap = (struct easycap *)file->private_data;
+if (NULL == peasycap) {
+	SAY("ERROR:  peasycap is NULL.\n");
+	return -EFAULT;
+}
+if (0 != kill_audio_urbs(peasycap)) {
+	SAY("ERROR: kill_audio_urbs() failed\n");
+	return -EFAULT;
+}
+JOT(4, "ending successfully\n");
+return 0;
+}
+/*****************************************************************************/
+ssize_t
+easysnd_read(struct file *file, char __user *puserspacebuffer, \
+						size_t kount, loff_t *poff)
+{
+struct timeval timeval;
+static struct timeval timeval1;
+static long long int audio_bytes, above, below, mean;
+struct signed_div_result sdr;
+unsigned char *p0;
+long int kount1, more, rc, l0, lm;
+int fragment;
+struct easycap *peasycap;
+struct data_buffer *pdata_buffer;
+size_t szret;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
+ *
+ ******************************************************************************
+ *****  N.B.  IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
+ *****        THIS CONDITION SIGNIFIES END-OF-FILE.                      ******
+ ******************************************************************************
+ */
+/*---------------------------------------------------------------------------*/
+
+JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
+
+peasycap = (struct easycap *)(file->private_data);
+if (NULL == peasycap) {
+	SAY("ERROR in easysnd_read(): peasycap is NULL\n");
+	return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+if ((0 > peasycap->audio_read) || \
+			(audio_buffer_page_many <= peasycap->audio_read)) {
+	SAY("ERROR: peasycap->audio_read out of range\n");
+	return -EFAULT;
+}
+pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
+if ((struct data_buffer *)NULL == pdata_buffer) {
+	SAY("ERROR: pdata_buffer is NULL\n");
+	return -EFAULT;
+}
+JOT(12, "before wait, %i=frag read  %i=frag fill\n", \
+		(peasycap->audio_read / audio_pages_per_fragment), \
+		(peasycap->audio_fill / audio_pages_per_fragment));
+fragment = (peasycap->audio_read / audio_pages_per_fragment);
+while ((fragment == (peasycap->audio_fill / audio_pages_per_fragment)) || \
+		(0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
+	if (file->f_flags & O_NONBLOCK) {
+		JOT(16, "returning -EAGAIN as instructed\n");
+		return -EAGAIN;
+	}
+	rc = wait_event_interruptible(peasycap->wq_audio, \
+		(peasycap->audio_idle  || peasycap->audio_eof   || \
+		((fragment != (peasycap->audio_fill / \
+					audio_pages_per_fragment)) && \
+		(0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
+	if (0 != rc) {
+		SAY("aborted by signal\n");
+		return -ERESTARTSYS;
+	}
+	if (peasycap->audio_eof) {
+		JOT(8, "returning 0 because  %i=audio_eof\n", \
+							peasycap->audio_eof);
+		kill_audio_urbs(peasycap);
+		msleep(500);
+		return 0;
+	}
+	if (peasycap->audio_idle) {
+		JOT(16, "returning 0 because  %i=audio_idle\n", \
+							peasycap->audio_idle);
+		return 0;
+	}
+	if (!peasycap->audio_isoc_streaming) {
+		JOT(16, "returning 0 because audio urbs not streaming\n");
+		return 0;
+	}
+}
+JOT(12, "after  wait, %i=frag read  %i=frag fill\n", \
+			(peasycap->audio_read / audio_pages_per_fragment), \
+			(peasycap->audio_fill / audio_pages_per_fragment));
+szret = (size_t)0;
+while (fragment == (peasycap->audio_read / audio_pages_per_fragment)) {
+	if (NULL == pdata_buffer->pgo) {
+		SAY("ERROR: pdata_buffer->pgo is NULL\n");
+		return -EFAULT;
+	}
+	if (NULL == pdata_buffer->pto) {
+		SAY("ERROR: pdata_buffer->pto is NULL\n");
+		return -EFAULT;
+	}
+	kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
+	if (0 > kount1) {
+		SAY("easysnd_read: MISTAKE: kount1 is negative\n");
+		return -ERESTARTSYS;
+	}
+	if (!kount1) {
+		(peasycap->audio_read)++;
+		if (audio_buffer_page_many <= peasycap->audio_read)
+			peasycap->audio_read = 0;
+		JOT(12, "bumped peasycap->audio_read to %i\n", \
+						peasycap->audio_read);
+
+		if (fragment != (peasycap->audio_read / \
+						audio_pages_per_fragment))
+			break;
+
+		if ((0 > peasycap->audio_read) || \
+			(audio_buffer_page_many <= peasycap->audio_read)) {
+			SAY("ERROR: peasycap->audio_read out of range\n");
+			return -EFAULT;
+		}
+		pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
+		if ((struct data_buffer *)NULL == pdata_buffer) {
+			SAY("ERROR: pdata_buffer is NULL\n");
+			return -EFAULT;
+		}
+		if (NULL == pdata_buffer->pgo) {
+			SAY("ERROR: pdata_buffer->pgo is NULL\n");
+			return -EFAULT;
+		}
+		if (NULL == pdata_buffer->pto) {
+			SAY("ERROR: pdata_buffer->pto is NULL\n");
+			return -EFAULT;
+		}
+		kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
+	}
+	JOT(12, "ready  to send %li bytes\n", (long int) kount1);
+	JOT(12, "still  to send %li bytes\n", (long int) kount);
+	more = kount1;
+	if (more > kount)
+		more = kount;
+	JOT(12, "agreed to send %li bytes from page %i\n", \
+						more, peasycap->audio_read);
+	if (!more)
+		break;
+
+/*---------------------------------------------------------------------------*/
+/*
+ *  ACCUMULATE DYNAMIC-RANGE INFORMATION
+ */
+/*---------------------------------------------------------------------------*/
+	p0 = (unsigned char *)pdata_buffer->pgo;  l0 = 0;  lm = more/2;
+	while (l0 < lm) {
+		SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau, \
+				&peasycap->audio_square);  l0++;  p0 += 2;
+	}
+/*---------------------------------------------------------------------------*/
+	rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
+	if (0 != rc) {
+		SAY("ERROR: copy_to_user() returned %li\n", rc);
+		return -EFAULT;
+	}
+	*poff += (loff_t)more;
+	szret += (size_t)more;
+	pdata_buffer->pto += more;
+	puserspacebuffer += more;
+	kount -= (size_t)more;
+}
+JOT(12, "after  read, %i=frag read  %i=frag fill\n", \
+			(peasycap->audio_read / audio_pages_per_fragment), \
+			(peasycap->audio_fill / audio_pages_per_fragment));
+if (kount < 0) {
+	SAY("MISTAKE:  %li=kount  %li=szret\n", \
+					(long int)kount, (long int)szret);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
+ */
+/*---------------------------------------------------------------------------*/
+if (peasycap->audio_sample) {
+	below = peasycap->audio_sample;
+	above = peasycap->audio_square;
+	sdr = signed_div(above, below);
+	above = sdr.quotient;
+	mean = peasycap->audio_niveau;
+	sdr = signed_div(mean, peasycap->audio_sample);
+
+	JOT(12, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n", \
+				sdr.quotient, above, peasycap->audio_sample);
+
+	sdr = signed_div(above, 32768);
+	JOT(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
+}
+/*---------------------------------------------------------------------------*/
+/*
+ *  UPDATE THE AUDIO CLOCK
+ */
+/*---------------------------------------------------------------------------*/
+do_gettimeofday(&timeval);
+if (!peasycap->timeval1.tv_sec) {
+	audio_bytes = 0;
+	timeval1 = timeval;
+
+	if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
+		return -ERESTARTSYS;
+	peasycap->timeval1 = timeval1;
+	mutex_unlock(&(peasycap->mutex_timeval1));
+	sdr.quotient = 192000;
+} else {
+	audio_bytes += (long long int) szret;
+	below = ((long long int)(1000000)) * \
+		((long long int)(timeval.tv_sec  - timeval1.tv_sec)) + \
+		(long long int)(timeval.tv_usec - timeval1.tv_usec);
+	above = 1000000 * ((long long int) audio_bytes);
+
+	if (below)
+		sdr = signed_div(above, below);
+	else
+		sdr.quotient = 192000;
+}
+JOT(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
+if (mutex_lock_interruptible(&(peasycap->mutex_timeval1)))
+	return -ERESTARTSYS;
+peasycap->dnbydt = sdr.quotient;
+mutex_unlock(&(peasycap->mutex_timeval1));
+
+JOT(8, "returning %li\n", (long int)szret);
+return szret;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  SUBMIT ALL AUDIO URBS.
+ */
+/*---------------------------------------------------------------------------*/
+int
+submit_audio_urbs(struct easycap *peasycap)
+{
+struct data_urb *pdata_urb;
+struct urb *purb;
+struct list_head *plist_head;
+int j, isbad, m, rc;
+int isbuf;
+
+if ((struct list_head *)NULL == peasycap->purb_audio_head) {
+	SAY("ERROR: peasycap->urb_audio_head uninitialized\n");
+	return -EFAULT;
+}
+if ((struct usb_device *)NULL == peasycap->pusb_device) {
+	SAY("ERROR: peasycap->pusb_device is NULL\n");
+	return -EFAULT;
+}
+if (!peasycap->audio_isoc_streaming) {
+	JOT(4, "initial submission of all audio urbs\n");
+	rc = usb_set_interface(peasycap->pusb_device,
+					peasycap->audio_interface, \
+					peasycap->audio_altsetting_on);
+	JOT(8, "usb_set_interface(.,%i,%i) returned %i\n", \
+					peasycap->audio_interface, \
+					peasycap->audio_altsetting_on, rc);
+
+	isbad = 0;  m = 0;
+	list_for_each(plist_head, (peasycap->purb_audio_head)) {
+		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
+		if (NULL != pdata_urb) {
+			purb = pdata_urb->purb;
+			if (NULL != purb) {
+				isbuf = pdata_urb->isbuf;
+
+				purb->interval = 1;
+				purb->dev = peasycap->pusb_device;
+				purb->pipe = \
+					usb_rcvisocpipe(peasycap->pusb_device,\
+					peasycap->audio_endpointnumber);
+				purb->transfer_flags = URB_ISO_ASAP;
+				purb->transfer_buffer = \
+					peasycap->audio_isoc_buffer[isbuf].pgo;
+				purb->transfer_buffer_length = \
+					peasycap->audio_isoc_buffer_size;
+				purb->complete = easysnd_complete;
+				purb->context = peasycap;
+				purb->start_frame = 0;
+				purb->number_of_packets = \
+					peasycap->audio_isoc_framesperdesc;
+				for (j = 0;  j < peasycap->\
+						audio_isoc_framesperdesc; \
+									j++) {
+					purb->iso_frame_desc[j].offset = j * \
+						peasycap->\
+						audio_isoc_maxframesize;
+					purb->iso_frame_desc[j].length = \
+						peasycap->\
+						audio_isoc_maxframesize;
+				}
+
+				rc = usb_submit_urb(purb, GFP_KERNEL);
+				if (0 != rc) {
+					isbad++;
+					SAY("ERROR: usb_submit_urb() failed" \
+							" for urb with rc:\n");
+					switch (rc) {
+					case -ENOMEM: {
+						SAY("ENOMEM\n"); break;
+					}
+					case -ENODEV: {
+						SAY("ENODEV\n"); break;
+					}
+					case -ENXIO: {
+						SAY("ENXIO\n"); break;
+					}
+					case -EINVAL: {
+						SAY("EINVAL\n"); break;
+					}
+					case -EAGAIN: {
+						SAY("EAGAIN\n"); break;
+					}
+					case -EFBIG: {
+						SAY("EFBIG\n"); break;
+					}
+					case -EPIPE: {
+						SAY("EPIPE\n"); break;
+					}
+					case -EMSGSIZE: {
+						SAY("EMSGSIZE\n"); break;
+					}
+					default: {
+						SAY("unknown error code %i\n",\
+								 rc); break;
+					}
+					}
+				} else {
+					 m++;
+				}
+			} else {
+				isbad++;
+			}
+		} else {
+			isbad++;
+		}
+	}
+	if (isbad) {
+		JOT(4, "attempting cleanup instead of submitting\n");
+		list_for_each(plist_head, (peasycap->purb_audio_head)) {
+			pdata_urb = list_entry(plist_head, struct data_urb, \
+								list_head);
+			if (NULL != pdata_urb) {
+				purb = pdata_urb->purb;
+				if (NULL != purb)
+					usb_kill_urb(purb);
+			}
+		}
+		peasycap->audio_isoc_streaming = 0;
+	} else {
+		peasycap->audio_isoc_streaming = 1;
+		JOT(4, "submitted %i audio urbs\n", m);
+	}
+} else
+	JOT(4, "already streaming audio urbs\n");
+
+return 0;
+}
+/*****************************************************************************/
+/*---------------------------------------------------------------------------*/
+/*
+ *  KILL ALL AUDIO URBS.
+ */
+/*---------------------------------------------------------------------------*/
+int
+kill_audio_urbs(struct easycap *peasycap)
+{
+int m;
+struct list_head *plist_head;
+struct data_urb *pdata_urb;
+
+if (peasycap->audio_isoc_streaming) {
+	if ((struct list_head *)NULL != peasycap->purb_audio_head) {
+		peasycap->audio_isoc_streaming = 0;
+		JOT(4, "killing audio urbs\n");
+		m = 0;
+		list_for_each(plist_head, (peasycap->purb_audio_head)) {
+			pdata_urb = list_entry(plist_head, struct data_urb,
+								list_head);
+			if ((struct data_urb *)NULL != pdata_urb) {
+				if ((struct urb *)NULL != pdata_urb->purb) {
+					usb_kill_urb(pdata_urb->purb);
+					m++;
+				}
+			}
+		}
+		JOT(4, "%i audio urbs killed\n", m);
+	} else {
+		SAY("ERROR: peasycap->purb_audio_head is NULL\n");
+		return -EFAULT;
+	}
+} else {
+	JOT(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
+					peasycap->audio_isoc_streaming);
+}
+return 0;
+}
+/*****************************************************************************/
diff --git a/drivers/staging/easycap/easycap_sound.h b/drivers/staging/easycap/easycap_sound.h
new file mode 100644
index 0000000..a6e2a9d
--- /dev/null
+++ b/drivers/staging/easycap/easycap_sound.h
@@ -0,0 +1,30 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap_sound.h                                                           *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+extern struct easycap *peasycap;
+extern struct usb_driver easycap_usb_driver;
+extern unsigned int audio_buffer_page_many;
+extern unsigned int audio_pages_per_fragment;
diff --git a/drivers/staging/easycap/easycap_standard.h b/drivers/staging/easycap/easycap_standard.h
new file mode 100644
index 0000000..cadc8d2
--- /dev/null
+++ b/drivers/staging/easycap/easycap_standard.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+*                                                                            *
+*  easycap_standard.h                                                        *
+*                                                                            *
+*****************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+extern struct easycap_standard easycap_standard[];
diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/easycap/easycap_testcard.c
new file mode 100644
index 0000000..3c2ce28
--- /dev/null
+++ b/drivers/staging/easycap/easycap_testcard.c
@@ -0,0 +1,392 @@
+/******************************************************************************
+*                                                                             *
+*  easycap_testcard.c                                                         *
+*                                                                             *
+******************************************************************************/
+/*
+ *
+ *  Copyright (C) 2010 R.M. Thomas  <rmthomas at sciolus.org>
+ *
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The software 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 software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+/*****************************************************************************/
+
+#include "easycap.h"
+#include "easycap_debug.h"
+
+/*****************************************************************************/
+#define TESTCARD_BYTESPERLINE (2 * 1440)
+void
+easycap_testcard(struct easycap *peasycap, int field_fill)
+{
+int total;
+int y, u, v, r, g, b;
+unsigned char uyvy[4];
+
+int i1, line, k, m, n, more, much, barwidth;
+unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
+struct data_buffer *pfield_buffer;
+
+JOT(8, "%i=field_fill\n", field_fill);
+
+if ((TESTCARD_BYTESPERLINE / 2) < peasycap->width) {
+	SAY("ERROR: image is too wide\n");
+	return;
+}
+if (peasycap->width % 16) {
+	SAY("ERROR: indivisible image width\n");
+	return;
+}
+
+total = 0;
+barwidth = (2 * peasycap->width) / 8;
+
+k = field_fill;
+m = 0;
+n = 0;
+
+for (line = 0;  line < (peasycap->height / 2);  line++) {
+	for (i1 = 0;  i1 < 8;  i1++) {
+		r = (i1 * 256)/8;
+		g = (i1 * 256)/8;
+		b = (i1 * 256)/8;
+
+		y =  299*r/1000 + 587*g/1000 + 114*b/1000 ;
+		u = -147*r/1000 - 289*g/1000 + 436*b/1000 ;  u = u + 128;
+		v =  615*r/1000 - 515*g/1000 - 100*b/1000 ;  v = v + 128;
+
+		uyvy[0] =  0xFF & u ;
+		uyvy[1] =  0xFF & y ;
+		uyvy[2] =  0xFF & v ;
+		uyvy[3] =  0xFF & y ;
+
+		p1 = &bfbar[0];
+		while (p1 < &bfbar[barwidth]) {
+			*p1++ = uyvy[0] ;
+			*p1++ = uyvy[1] ;
+			*p1++ = uyvy[2] ;
+			*p1++ = uyvy[3] ;
+			total += 4;
+			}
+
+		p1 = &bfbar[0];
+		more = barwidth;
+
+		while (more) {
+			if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
+				SAY("ERROR:  bad m reached\n");
+				return;
+			}
+		if (PAGE_SIZE < n) {
+			SAY("ERROR:  bad n reached\n"); return;
+		}
+
+		if (0 > more) {
+			SAY("ERROR:  internal fault\n");
+			return;
+		}
+
+		much = PAGE_SIZE - n;
+		if (much > more)
+			much = more;
+		pfield_buffer = &peasycap->field_buffer[k][m];
+		p2 = pfield_buffer->pgo + n;
+		memcpy(p2, p1, much);
+
+		p1 += much;
+		n += much;
+		more -= much;
+		if (PAGE_SIZE == n) {
+			m++;
+			n = 0;
+			}
+		}
+	}
+}
+
+JOT(8, "%i=total\n", total);
+if (total != peasycap->width * peasycap->height)
+	SAY("ERROR: wrong number of bytes written:  %i\n", total);
+return;
+}
+/*****************************************************************************/
+#if defined(EASYCAP_TESTTONE)
+/*-----------------------------------------------------------------------------
+THE tones[] ARRAY BELOW IS THE OUTPUT OF THIS PROGRAM,
+COMPILED gcc -o prog -lm prog.c
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#include <stdio.h>
+#include <math.h>
+
+int main(void);
+int
+main(void)
+{
+int i1, i2, last;
+double d1, d2;
+
+last = 1024 - 1;
+d1 = 10.0*3.14159265/1024.0;
+printf("int tones[2048] =\n{\n");
+for (i1 = 0;  i1 <= last;  i1++)
+	{
+	d2 = ((double)i1) * d1;
+	i2 = (int)(16384.0*sin(d2));
+
+	if (last != i1)
+		{
+		printf("%6i, ", i2);  printf("%6i, ", i2);
+		if (!((i1 + 1)%5)) printf("\n");
+		}
+	else
+		{
+		printf("%6i, ", i2);  printf("%6i\n};\n", i2);
+		}
+	}
+return(0);
+}
+-----------------------------------------------------------------------------*/
+int tones[2048] = {
+     0,     0,   502,   502,  1004,  1004,  1505,  1505,  2005,  2005,
+  2503,  2503,  2998,  2998,  3491,  3491,  3980,  3980,  4466,  4466,
+  4948,  4948,  5424,  5424,  5896,  5896,  6362,  6362,  6822,  6822,
+  7276,  7276,  7723,  7723,  8162,  8162,  8594,  8594,  9018,  9018,
+  9434,  9434,  9840,  9840, 10237, 10237, 10625, 10625, 11002, 11002,
+ 11370, 11370, 11726, 11726, 12072, 12072, 12406, 12406, 12728, 12728,
+ 13038, 13038, 13337, 13337, 13622, 13622, 13895, 13895, 14155, 14155,
+ 14401, 14401, 14634, 14634, 14853, 14853, 15058, 15058, 15249, 15249,
+ 15426, 15426, 15588, 15588, 15735, 15735, 15868, 15868, 15985, 15985,
+ 16088, 16088, 16175, 16175, 16248, 16248, 16305, 16305, 16346, 16346,
+ 16372, 16372, 16383, 16383, 16379, 16379, 16359, 16359, 16323, 16323,
+ 16272, 16272, 16206, 16206, 16125, 16125, 16028, 16028, 15917, 15917,
+ 15790, 15790, 15649, 15649, 15492, 15492, 15322, 15322, 15136, 15136,
+ 14937, 14937, 14723, 14723, 14496, 14496, 14255, 14255, 14001, 14001,
+ 13733, 13733, 13452, 13452, 13159, 13159, 12854, 12854, 12536, 12536,
+ 12207, 12207, 11866, 11866, 11513, 11513, 11150, 11150, 10777, 10777,
+ 10393, 10393, 10000, 10000,  9597,  9597,  9185,  9185,  8765,  8765,
+  8336,  8336,  7900,  7900,  7456,  7456,  7005,  7005,  6547,  6547,
+  6083,  6083,  5614,  5614,  5139,  5139,  4659,  4659,  4175,  4175,
+  3687,  3687,  3196,  3196,  2701,  2701,  2204,  2204,  1705,  1705,
+  1205,  1205,   703,   703,   201,   201,  -301,  -301,  -803,  -803,
+ -1305, -1305, -1805, -1805, -2304, -2304, -2801, -2801, -3294, -3294,
+ -3785, -3785, -4272, -4272, -4756, -4756, -5234, -5234, -5708, -5708,
+ -6176, -6176, -6639, -6639, -7095, -7095, -7545, -7545, -7988, -7988,
+ -8423, -8423, -8850, -8850, -9268, -9268, -9679, -9679, -10079, -10079,
+-10471, -10471, -10853, -10853, -11224, -11224, -11585, -11585, -11935, -11935,
+-12273, -12273, -12600, -12600, -12916, -12916, -13219, -13219, -13510, -13510,
+-13788, -13788, -14053, -14053, -14304, -14304, -14543, -14543, -14767, -14767,
+-14978, -14978, -15175, -15175, -15357, -15357, -15525, -15525, -15678, -15678,
+-15817, -15817, -15940, -15940, -16049, -16049, -16142, -16142, -16221, -16221,
+-16284, -16284, -16331, -16331, -16364, -16364, -16381, -16381, -16382, -16382,
+-16368, -16368, -16339, -16339, -16294, -16294, -16234, -16234, -16159, -16159,
+-16069, -16069, -15963, -15963, -15842, -15842, -15707, -15707, -15557, -15557,
+-15392, -15392, -15212, -15212, -15018, -15018, -14810, -14810, -14589, -14589,
+-14353, -14353, -14104, -14104, -13842, -13842, -13566, -13566, -13278, -13278,
+-12977, -12977, -12665, -12665, -12340, -12340, -12003, -12003, -11656, -11656,
+-11297, -11297, -10928, -10928, -10548, -10548, -10159, -10159, -9759, -9759,
+ -9351, -9351, -8934, -8934, -8509, -8509, -8075, -8075, -7634, -7634,
+ -7186, -7186, -6731, -6731, -6269, -6269, -5802, -5802, -5329, -5329,
+ -4852, -4852, -4369, -4369, -3883, -3883, -3393, -3393, -2900, -2900,
+ -2404, -2404, -1905, -1905, -1405, -1405,  -904,  -904,  -402,  -402,
+   100,   100,   603,   603,  1105,  1105,  1605,  1605,  2105,  2105,
+  2602,  2602,  3097,  3097,  3589,  3589,  4078,  4078,  4563,  4563,
+  5043,  5043,  5519,  5519,  5990,  5990,  6455,  6455,  6914,  6914,
+  7366,  7366,  7811,  7811,  8249,  8249,  8680,  8680,  9102,  9102,
+  9516,  9516,  9920,  9920, 10315, 10315, 10701, 10701, 11077, 11077,
+ 11442, 11442, 11796, 11796, 12139, 12139, 12471, 12471, 12791, 12791,
+ 13099, 13099, 13395, 13395, 13678, 13678, 13948, 13948, 14205, 14205,
+ 14449, 14449, 14679, 14679, 14895, 14895, 15098, 15098, 15286, 15286,
+ 15459, 15459, 15618, 15618, 15763, 15763, 15892, 15892, 16007, 16007,
+ 16107, 16107, 16191, 16191, 16260, 16260, 16314, 16314, 16353, 16353,
+ 16376, 16376, 16384, 16384, 16376, 16376, 16353, 16353, 16314, 16314,
+ 16260, 16260, 16191, 16191, 16107, 16107, 16007, 16007, 15892, 15892,
+ 15763, 15763, 15618, 15618, 15459, 15459, 15286, 15286, 15098, 15098,
+ 14895, 14895, 14679, 14679, 14449, 14449, 14205, 14205, 13948, 13948,
+ 13678, 13678, 13395, 13395, 13099, 13099, 12791, 12791, 12471, 12471,
+ 12139, 12139, 11796, 11796, 11442, 11442, 11077, 11077, 10701, 10701,
+ 10315, 10315,  9920,  9920,  9516,  9516,  9102,  9102,  8680,  8680,
+  8249,  8249,  7811,  7811,  7366,  7366,  6914,  6914,  6455,  6455,
+  5990,  5990,  5519,  5519,  5043,  5043,  4563,  4563,  4078,  4078,
+  3589,  3589,  3097,  3097,  2602,  2602,  2105,  2105,  1605,  1605,
+  1105,  1105,   603,   603,   100,   100,  -402,  -402,  -904,  -904,
+ -1405, -1405, -1905, -1905, -2404, -2404, -2900, -2900, -3393, -3393,
+ -3883, -3883, -4369, -4369, -4852, -4852, -5329, -5329, -5802, -5802,
+ -6269, -6269, -6731, -6731, -7186, -7186, -7634, -7634, -8075, -8075,
+ -8509, -8509, -8934, -8934, -9351, -9351, -9759, -9759, -10159, -10159,
+-10548, -10548, -10928, -10928, -11297, -11297, -11656, -11656, -12003, -12003,
+-12340, -12340, -12665, -12665, -12977, -12977, -13278, -13278, -13566, -13566,
+-13842, -13842, -14104, -14104, -14353, -14353, -14589, -14589, -14810, -14810,
+-15018, -15018, -15212, -15212, -15392, -15392, -15557, -15557, -15707, -15707,
+-15842, -15842, -15963, -15963, -16069, -16069, -16159, -16159, -16234, -16234,
+-16294, -16294, -16339, -16339, -16368, -16368, -16382, -16382, -16381, -16381,
+-16364, -16364, -16331, -16331, -16284, -16284, -16221, -16221, -16142, -16142,
+-16049, -16049, -15940, -15940, -15817, -15817, -15678, -15678, -15525, -15525,
+-15357, -15357, -15175, -15175, -14978, -14978, -14767, -14767, -14543, -14543,
+-14304, -14304, -14053, -14053, -13788, -13788, -13510, -13510, -13219, -13219,
+-12916, -12916, -12600, -12600, -12273, -12273, -11935, -11935, -11585, -11585,
+-11224, -11224, -10853, -10853, -10471, -10471, -10079, -10079, -9679, -9679,
+ -9268, -9268, -8850, -8850, -8423, -8423, -7988, -7988, -7545, -7545,
+ -7095, -7095, -6639, -6639, -6176, -6176, -5708, -5708, -5234, -5234,
+ -4756, -4756, -4272, -4272, -3785, -3785, -3294, -3294, -2801, -2801,
+ -2304, -2304, -1805, -1805, -1305, -1305,  -803,  -803,  -301,  -301,
+   201,   201,   703,   703,  1205,  1205,  1705,  1705,  2204,  2204,
+  2701,  2701,  3196,  3196,  3687,  3687,  4175,  4175,  4659,  4659,
+  5139,  5139,  5614,  5614,  6083,  6083,  6547,  6547,  7005,  7005,
+  7456,  7456,  7900,  7900,  8336,  8336,  8765,  8765,  9185,  9185,
+  9597,  9597, 10000, 10000, 10393, 10393, 10777, 10777, 11150, 11150,
+ 11513, 11513, 11866, 11866, 12207, 12207, 12536, 12536, 12854, 12854,
+ 13159, 13159, 13452, 13452, 13733, 13733, 14001, 14001, 14255, 14255,
+ 14496, 14496, 14723, 14723, 14937, 14937, 15136, 15136, 15322, 15322,
+ 15492, 15492, 15649, 15649, 15790, 15790, 15917, 15917, 16028, 16028,
+ 16125, 16125, 16206, 16206, 16272, 16272, 16323, 16323, 16359, 16359,
+ 16379, 16379, 16383, 16383, 16372, 16372, 16346, 16346, 16305, 16305,
+ 16248, 16248, 16175, 16175, 16088, 16088, 15985, 15985, 15868, 15868,
+ 15735, 15735, 15588, 15588, 15426, 15426, 15249, 15249, 15058, 15058,
+ 14853, 14853, 14634, 14634, 14401, 14401, 14155, 14155, 13895, 13895,
+ 13622, 13622, 13337, 13337, 13038, 13038, 12728, 12728, 12406, 12406,
+ 12072, 12072, 11726, 11726, 11370, 11370, 11002, 11002, 10625, 10625,
+ 10237, 10237,  9840,  9840,  9434,  9434,  9018,  9018,  8594,  8594,
+  8162,  8162,  7723,  7723,  7276,  7276,  6822,  6822,  6362,  6362,
+  5896,  5896,  5424,  5424,  4948,  4948,  4466,  4466,  3980,  3980,
+  3491,  3491,  2998,  2998,  2503,  2503,  2005,  2005,  1505,  1505,
+  1004,  1004,   502,   502,     0,     0,  -502,  -502, -1004, -1004,
+ -1505, -1505, -2005, -2005, -2503, -2503, -2998, -2998, -3491, -3491,
+ -3980, -3980, -4466, -4466, -4948, -4948, -5424, -5424, -5896, -5896,
+ -6362, -6362, -6822, -6822, -7276, -7276, -7723, -7723, -8162, -8162,
+ -8594, -8594, -9018, -9018, -9434, -9434, -9840, -9840, -10237, -10237,
+-10625, -10625, -11002, -11002, -11370, -11370, -11726, -11726, -12072, -12072,
+-12406, -12406, -12728, -12728, -13038, -13038, -13337, -13337, -13622, -13622,
+-13895, -13895, -14155, -14155, -14401, -14401, -14634, -14634, -14853, -14853,
+-15058, -15058, -15249, -15249, -15426, -15426, -15588, -15588, -15735, -15735,
+-15868, -15868, -15985, -15985, -16088, -16088, -16175, -16175, -16248, -16248,
+-16305, -16305, -16346, -16346, -16372, -16372, -16383, -16383, -16379, -16379,
+-16359, -16359, -16323, -16323, -16272, -16272, -16206, -16206, -16125, -16125,
+-16028, -16028, -15917, -15917, -15790, -15790, -15649, -15649, -15492, -15492,
+-15322, -15322, -15136, -15136, -14937, -14937, -14723, -14723, -14496, -14496,
+-14255, -14255, -14001, -14001, -13733, -13733, -13452, -13452, -13159, -13159,
+-12854, -12854, -12536, -12536, -12207, -12207, -11866, -11866, -11513, -11513,
+-11150, -11150, -10777, -10777, -10393, -10393, -10000, -10000, -9597, -9597,
+ -9185, -9185, -8765, -8765, -8336, -8336, -7900, -7900, -7456, -7456,
+ -7005, -7005, -6547, -6547, -6083, -6083, -5614, -5614, -5139, -5139,
+ -4659, -4659, -4175, -4175, -3687, -3687, -3196, -3196, -2701, -2701,
+ -2204, -2204, -1705, -1705, -1205, -1205,  -703,  -703,  -201,  -201,
+   301,   301,   803,   803,  1305,  1305,  1805,  1805,  2304,  2304,
+  2801,  2801,  3294,  3294,  3785,  3785,  4272,  4272,  4756,  4756,
+  5234,  5234,  5708,  5708,  6176,  6176,  6639,  6639,  7095,  7095,
+  7545,  7545,  7988,  7988,  8423,  8423,  8850,  8850,  9268,  9268,
+  9679,  9679, 10079, 10079, 10471, 10471, 10853, 10853, 11224, 11224,
+ 11585, 11585, 11935, 11935, 12273, 12273, 12600, 12600, 12916, 12916,
+ 13219, 13219, 13510, 13510, 13788, 13788, 14053, 14053, 14304, 14304,
+ 14543, 14543, 14767, 14767, 14978, 14978, 15175, 15175, 15357, 15357,
+ 15525, 15525, 15678, 15678, 15817, 15817, 15940, 15940, 16049, 16049,
+ 16142, 16142, 16221, 16221, 16284, 16284, 16331, 16331, 16364, 16364,
+ 16381, 16381, 16382, 16382, 16368, 16368, 16339, 16339, 16294, 16294,
+ 16234, 16234, 16159, 16159, 16069, 16069, 15963, 15963, 15842, 15842,
+ 15707, 15707, 15557, 15557, 15392, 15392, 15212, 15212, 15018, 15018,
+ 14810, 14810, 14589, 14589, 14353, 14353, 14104, 14104, 13842, 13842,
+ 13566, 13566, 13278, 13278, 12977, 12977, 12665, 12665, 12340, 12340,
+ 12003, 12003, 11656, 11656, 11297, 11297, 10928, 10928, 10548, 10548,
+ 10159, 10159,  9759,  9759,  9351,  9351,  8934,  8934,  8509,  8509,
+  8075,  8075,  7634,  7634,  7186,  7186,  6731,  6731,  6269,  6269,
+  5802,  5802,  5329,  5329,  4852,  4852,  4369,  4369,  3883,  3883,
+  3393,  3393,  2900,  2900,  2404,  2404,  1905,  1905,  1405,  1405,
+   904,   904,   402,   402,  -100,  -100,  -603,  -603, -1105, -1105,
+ -1605, -1605, -2105, -2105, -2602, -2602, -3097, -3097, -3589, -3589,
+ -4078, -4078, -4563, -4563, -5043, -5043, -5519, -5519, -5990, -5990,
+ -6455, -6455, -6914, -6914, -7366, -7366, -7811, -7811, -8249, -8249,
+ -8680, -8680, -9102, -9102, -9516, -9516, -9920, -9920, -10315, -10315,
+-10701, -10701, -11077, -11077, -11442, -11442, -11796, -11796, -12139, -12139,
+-12471, -12471, -12791, -12791, -13099, -13099, -13395, -13395, -13678, -13678,
+-13948, -13948, -14205, -14205, -14449, -14449, -14679, -14679, -14895, -14895,
+-15098, -15098, -15286, -15286, -15459, -15459, -15618, -15618, -15763, -15763,
+-15892, -15892, -16007, -16007, -16107, -16107, -16191, -16191, -16260, -16260,
+-16314, -16314, -16353, -16353, -16376, -16376, -16383, -16383, -16376, -16376,
+-16353, -16353, -16314, -16314, -16260, -16260, -16191, -16191, -16107, -16107,
+-16007, -16007, -15892, -15892, -15763, -15763, -15618, -15618, -15459, -15459,
+-15286, -15286, -15098, -15098, -14895, -14895, -14679, -14679, -14449, -14449,
+-14205, -14205, -13948, -13948, -13678, -13678, -13395, -13395, -13099, -13099,
+-12791, -12791, -12471, -12471, -12139, -12139, -11796, -11796, -11442, -11442,
+-11077, -11077, -10701, -10701, -10315, -10315, -9920, -9920, -9516, -9516,
+ -9102, -9102, -8680, -8680, -8249, -8249, -7811, -7811, -7366, -7366,
+ -6914, -6914, -6455, -6455, -5990, -5990, -5519, -5519, -5043, -5043,
+ -4563, -4563, -4078, -4078, -3589, -3589, -3097, -3097, -2602, -2602,
+ -2105, -2105, -1605, -1605, -1105, -1105,  -603,  -603,  -100,  -100,
+   402,   402,   904,   904,  1405,  1405,  1905,  1905,  2404,  2404,
+  2900,  2900,  3393,  3393,  3883,  3883,  4369,  4369,  4852,  4852,
+  5329,  5329,  5802,  5802,  6269,  6269,  6731,  6731,  7186,  7186,
+  7634,  7634,  8075,  8075,  8509,  8509,  8934,  8934,  9351,  9351,
+  9759,  9759, 10159, 10159, 10548, 10548, 10928, 10928, 11297, 11297,
+ 11656, 11656, 12003, 12003, 12340, 12340, 12665, 12665, 12977, 12977,
+ 13278, 13278, 13566, 13566, 13842, 13842, 14104, 14104, 14353, 14353,
+ 14589, 14589, 14810, 14810, 15018, 15018, 15212, 15212, 15392, 15392,
+ 15557, 15557, 15707, 15707, 15842, 15842, 15963, 15963, 16069, 16069,
+ 16159, 16159, 16234, 16234, 16294, 16294, 16339, 16339, 16368, 16368,
+ 16382, 16382, 16381, 16381, 16364, 16364, 16331, 16331, 16284, 16284,
+ 16221, 16221, 16142, 16142, 16049, 16049, 15940, 15940, 15817, 15817,
+ 15678, 15678, 15525, 15525, 15357, 15357, 15175, 15175, 14978, 14978,
+ 14767, 14767, 14543, 14543, 14304, 14304, 14053, 14053, 13788, 13788,
+ 13510, 13510, 13219, 13219, 12916, 12916, 12600, 12600, 12273, 12273,
+ 11935, 11935, 11585, 11585, 11224, 11224, 10853, 10853, 10471, 10471,
+ 10079, 10079,  9679,  9679,  9268,  9268,  8850,  8850,  8423,  8423,
+  7988,  7988,  7545,  7545,  7095,  7095,  6639,  6639,  6176,  6176,
+  5708,  5708,  5234,  5234,  4756,  4756,  4272,  4272,  3785,  3785,
+  3294,  3294,  2801,  2801,  2304,  2304,  1805,  1805,  1305,  1305,
+   803,   803,   301,   301,  -201,  -201,  -703,  -703, -1205, -1205,
+ -1705, -1705, -2204, -2204, -2701, -2701, -3196, -3196, -3687, -3687,
+ -4175, -4175, -4659, -4659, -5139, -5139, -5614, -5614, -6083, -6083,
+ -6547, -6547, -7005, -7005, -7456, -7456, -7900, -7900, -8336, -8336,
+ -8765, -8765, -9185, -9185, -9597, -9597, -10000, -10000, -10393, -10393,
+-10777, -10777, -11150, -11150, -11513, -11513, -11866, -11866, -12207, -12207,
+-12536, -12536, -12854, -12854, -13159, -13159, -13452, -13452, -13733, -13733,
+-14001, -14001, -14255, -14255, -14496, -14496, -14723, -14723, -14937, -14937,
+-15136, -15136, -15322, -15322, -15492, -15492, -15649, -15649, -15790, -15790,
+-15917, -15917, -16028, -16028, -16125, -16125, -16206, -16206, -16272, -16272,
+-16323, -16323, -16359, -16359, -16379, -16379, -16383, -16383, -16372, -16372,
+-16346, -16346, -16305, -16305, -16248, -16248, -16175, -16175, -16088, -16088,
+-15985, -15985, -15868, -15868, -15735, -15735, -15588, -15588, -15426, -15426,
+-15249, -15249, -15058, -15058, -14853, -14853, -14634, -14634, -14401, -14401,
+-14155, -14155, -13895, -13895, -13622, -13622, -13337, -13337, -13038, -13038,
+-12728, -12728, -12406, -12406, -12072, -12072, -11726, -11726, -11370, -11370,
+-11002, -11002, -10625, -10625, -10237, -10237, -9840, -9840, -9434, -9434,
+ -9018, -9018, -8594, -8594, -8162, -8162, -7723, -7723, -7276, -7276,
+ -6822, -6822, -6362, -6362, -5896, -5896, -5424, -5424, -4948, -4948,
+ -4466, -4466, -3980, -3980, -3491, -3491, -2998, -2998, -2503, -2503,
+ -2005, -2005, -1505, -1505, -1004, -1004,  -502,  -502
+};
+/*****************************************************************************/
+void
+easysnd_testtone(struct easycap *peasycap, int audio_fill)
+{
+int i1;
+unsigned char *p2;
+struct data_buffer *paudio_buffer;
+
+JOT(8, "%i=audio_fill\n", audio_fill);
+
+paudio_buffer = &peasycap->audio_buffer[audio_fill];
+
+p2 = (unsigned char *)(paudio_buffer->pgo);
+for (i1 = 0;  i1 < PAGE_SIZE;  i1 += 4, p2 += 4) {
+	*p2       = (unsigned char) (0x00FF & tones[i1/2]);
+	*(p2 + 1) = (unsigned char)((0xFF00 & tones[i1/2]) >> 8);
+	*(p2 + 2) = (unsigned char) (0x00FF & tones[i1/2 + 1]);
+	*(p2 + 3) = (unsigned char)((0xFF00 & tones[i1/2 + 1]) >> 8);
+	}
+return;
+}
+#endif /*EASYCAP_TESTTONE*/
+/*****************************************************************************/
-- 
1.7.1




More information about the devel mailing list