V4L/DVB (3599a): Move drivers/usb/media to drivers/media/video
authorMauro Carvalho Chehab <mchehab@infradead.org>
Sat, 25 Mar 2006 12:05:39 +0000 (09:05 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sat, 25 Mar 2006 12:29:04 +0000 (09:29 -0300)
Because of historic reasons, there are two separate directories with
V4L stuff. Most drivers are located at driver/media/video. However, some
code for USB Webcams were inserted under drivers/usb/media.

This makes difficult for module authors to know were things should be.
Also, makes Kconfig menu confusing for normal users.

This patch moves all V4L content under drivers/usb/media to
drivers/media/video, and fixes Kconfig/Makefile entries.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
117 files changed:
drivers/media/Kconfig
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/dabfirmware.h [new file with mode: 0644]
drivers/media/video/dabusb.c [new file with mode: 0644]
drivers/media/video/dabusb.h [new file with mode: 0644]
drivers/media/video/dsbr100.c [new file with mode: 0644]
drivers/media/video/et61x251/Makefile [new file with mode: 0644]
drivers/media/video/et61x251/et61x251.h [new file with mode: 0644]
drivers/media/video/et61x251/et61x251_core.c [new file with mode: 0644]
drivers/media/video/et61x251/et61x251_sensor.h [new file with mode: 0644]
drivers/media/video/et61x251/et61x251_tas5130d1b.c [new file with mode: 0644]
drivers/media/video/ov511.c [new file with mode: 0644]
drivers/media/video/ov511.h [new file with mode: 0644]
drivers/media/video/pwc/Makefile [new file with mode: 0644]
drivers/media/video/pwc/philips.txt [new file with mode: 0644]
drivers/media/video/pwc/pwc-ctrl.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-if.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-ioctl.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-kiara.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-kiara.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-misc.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-nala.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-timon.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-timon.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-uncompress.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-uncompress.h [new file with mode: 0644]
drivers/media/video/pwc/pwc.h [new file with mode: 0644]
drivers/media/video/se401.c [new file with mode: 0644]
drivers/media/video/se401.h [new file with mode: 0644]
drivers/media/video/sn9c102/Makefile [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102.h [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_core.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_hv7131d.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_mi0343.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_ov7630.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas106b.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas202bca.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_pas202bcb.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_sensor.h [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_tas5110c1b.c [new file with mode: 0644]
drivers/media/video/sn9c102/sn9c102_tas5130d1b.c [new file with mode: 0644]
drivers/media/video/stv680.c [new file with mode: 0644]
drivers/media/video/stv680.h [new file with mode: 0644]
drivers/media/video/usbvideo/Makefile [new file with mode: 0644]
drivers/media/video/usbvideo/ibmcam.c [new file with mode: 0644]
drivers/media/video/usbvideo/konicawc.c [new file with mode: 0644]
drivers/media/video/usbvideo/ultracam.c [new file with mode: 0644]
drivers/media/video/usbvideo/usbvideo.c [new file with mode: 0644]
drivers/media/video/usbvideo/usbvideo.h [new file with mode: 0644]
drivers/media/video/usbvideo/vicam.c [new file with mode: 0644]
drivers/media/video/w9968cf.c [new file with mode: 0644]
drivers/media/video/w9968cf.h [new file with mode: 0644]
drivers/media/video/w9968cf_decoder.h [new file with mode: 0644]
drivers/media/video/w9968cf_vpp.h [new file with mode: 0644]
drivers/media/video/zc0301/Makefile [new file with mode: 0644]
drivers/media/video/zc0301/zc0301.h [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_core.c [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_pas202bcb.c [new file with mode: 0644]
drivers/media/video/zc0301/zc0301_sensor.h [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/media/Kconfig [deleted file]
drivers/usb/media/Makefile [deleted file]
drivers/usb/media/dabfirmware.h [deleted file]
drivers/usb/media/dabusb.c [deleted file]
drivers/usb/media/dabusb.h [deleted file]
drivers/usb/media/dsbr100.c [deleted file]
drivers/usb/media/et61x251.h [deleted file]
drivers/usb/media/et61x251_core.c [deleted file]
drivers/usb/media/et61x251_sensor.h [deleted file]
drivers/usb/media/et61x251_tas5130d1b.c [deleted file]
drivers/usb/media/ibmcam.c [deleted file]
drivers/usb/media/konicawc.c [deleted file]
drivers/usb/media/ov511.c [deleted file]
drivers/usb/media/ov511.h [deleted file]
drivers/usb/media/pwc/Makefile [deleted file]
drivers/usb/media/pwc/philips.txt [deleted file]
drivers/usb/media/pwc/pwc-ctrl.c [deleted file]
drivers/usb/media/pwc/pwc-if.c [deleted file]
drivers/usb/media/pwc/pwc-ioctl.h [deleted file]
drivers/usb/media/pwc/pwc-kiara.c [deleted file]
drivers/usb/media/pwc/pwc-kiara.h [deleted file]
drivers/usb/media/pwc/pwc-misc.c [deleted file]
drivers/usb/media/pwc/pwc-nala.h [deleted file]
drivers/usb/media/pwc/pwc-timon.c [deleted file]
drivers/usb/media/pwc/pwc-timon.h [deleted file]
drivers/usb/media/pwc/pwc-uncompress.c [deleted file]
drivers/usb/media/pwc/pwc-uncompress.h [deleted file]
drivers/usb/media/pwc/pwc.h [deleted file]
drivers/usb/media/se401.c [deleted file]
drivers/usb/media/se401.h [deleted file]
drivers/usb/media/sn9c102.h [deleted file]
drivers/usb/media/sn9c102_core.c [deleted file]
drivers/usb/media/sn9c102_hv7131d.c [deleted file]
drivers/usb/media/sn9c102_mi0343.c [deleted file]
drivers/usb/media/sn9c102_ov7630.c [deleted file]
drivers/usb/media/sn9c102_pas106b.c [deleted file]
drivers/usb/media/sn9c102_pas202bca.c [deleted file]
drivers/usb/media/sn9c102_pas202bcb.c [deleted file]
drivers/usb/media/sn9c102_sensor.h [deleted file]
drivers/usb/media/sn9c102_tas5110c1b.c [deleted file]
drivers/usb/media/sn9c102_tas5130d1b.c [deleted file]
drivers/usb/media/stv680.c [deleted file]
drivers/usb/media/stv680.h [deleted file]
drivers/usb/media/ultracam.c [deleted file]
drivers/usb/media/usbvideo.c [deleted file]
drivers/usb/media/usbvideo.h [deleted file]
drivers/usb/media/vicam.c [deleted file]
drivers/usb/media/w9968cf.c [deleted file]
drivers/usb/media/w9968cf.h [deleted file]
drivers/usb/media/w9968cf_decoder.h [deleted file]
drivers/usb/media/w9968cf_vpp.h [deleted file]
drivers/usb/media/zc0301.h [deleted file]
drivers/usb/media/zc0301_core.c [deleted file]
drivers/usb/media/zc0301_pas202bcb.c [deleted file]
drivers/usb/media/zc0301_sensor.h [deleted file]

index c2602b34049198c52fecec30caf4d5922eb9e633..baa9f58beffc73b1029f69cc17cf5eba259c7012 100644 (file)
@@ -50,5 +50,19 @@ config VIDEO_IR
 config VIDEO_TVEEPROM
        tristate
 
+config USB_DABUSB
+        tristate "DABUSB driver"
+        depends on USB
+        ---help---
+          A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
+          brought to you by the DAB-Team
+          <http://wwwbode.cs.tum.edu/Par/arch/dab/>.  This driver can be taken
+          as an example for URB-based bulk, control, and isochronous
+          transactions. URB's are explained in
+          <Documentation/usb/URB.txt>.
+
+          To compile this driver as a module, choose M here: the
+          module will be called dabusb.
+
 endmenu
 
index b3d3b22d3f787ba4f318f9806ba66c1b04926867..1f8a46b5916e001250f67566373a365264040933 100644 (file)
@@ -291,8 +291,6 @@ config VIDEO_HEXIUM_GEMINI
 
 source "drivers/media/video/cx88/Kconfig"
 
-source "drivers/media/video/em28xx/Kconfig"
-
 config VIDEO_OVCAMCHIP
        tristate "OmniVision Camera Chip support"
        depends on VIDEO_DEV && I2C
@@ -367,4 +365,234 @@ config VIDEO_SAA7127
          To compile this driver as a module, choose M here: the
          module will be called saa7127
 
+#
+# USB Multimedia device configuration
+#
+
+menu "V4L USB devices"
+        depends on USB && VIDEO_DEV
+
+source "drivers/media/video/em28xx/Kconfig"
+
+config USB_VICAM
+       tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
+       depends on USB && VIDEO_DEV && EXPERIMENTAL
+       ---help---
+         Say Y here if you have 3com homeconnect camera (vicam).
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Multimedia Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vicam.
+
+config USB_DSBR
+       tristate "D-Link USB FM radio support (EXPERIMENTAL)"
+       depends on USB && VIDEO_DEV && EXPERIMENTAL
+       ---help---
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port. Note that the audio is not digital, and
+         you must connect the line out connector to a sound card or a
+         set of speakers.
+
+         This driver uses the Video For Linux API.  You must enable
+         (Y or M in config) Video For Linux (under Character Devices)
+         to use this driver.  Information on this API and pointers to
+         "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called dsbr100.
+
+config USB_ET61X251
+       tristate "USB ET61X[12]51 PC Camera Controller support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on Etoms ET61X151
+         or ET61X251 PC Camera Controllers.
+
+         See <file:Documentation/usb/et61x251.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called et61x251.
+
+config USB_IBMCAM
+       tristate "USB IBM (Xirlink) C-it Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect a IBM "C-It" camera, also known as
+         "Xirlink PC Camera" to your computer's USB port.  For more
+         information, read <file:Documentation/usb/ibmcam.txt>.
+
+         This driver uses the Video For Linux API.  You must enable
+         (Y or M in config) Video For Linux (under Character Devices)
+         to use this driver.  Information on this API and pointers to
+         "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ibmcam.
+
+         This camera has several configuration options which
+         can be specified when you load the module. Read
+         <file:Documentation/usb/ibmcam.txt> to learn more.
+
+config USB_KONICAWC
+       tristate "USB Konica Webcam support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for webcams based on a Konica
+         chipset. This is known to work with the Intel YC76 webcam.
+
+         This driver uses the Video For Linux API.  You must enable
+         (Y or M in config) Video For Linux (under Character Devices)
+         to use this driver.  Information on this API and pointers to
+         "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called konicawc.
+
+config USB_OV511
+       tristate "USB OV511 Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port. See <file:Documentation/usb/ov511.txt> for more
+         information and for a list of supported cameras.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Character Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ov511.
+
+config USB_SE401
+       tristate "USB SE401 Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port. See <file:Documentation/usb/se401.txt> for more
+         information and for a list of supported cameras.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Multimedia Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called se401.
+
+config USB_SN9C102
+       tristate "USB SN9C10x PC Camera Controller support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on SONiX SN9C101,
+         SN9C102 or SN9C103 PC Camera Controllers.
+
+         See <file:Documentation/usb/sn9c102.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sn9c102.
+
+config USB_STV680
+       tristate "USB STV680 (Pencam) Camera support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want to connect this type of camera to your
+         computer's USB port. This includes the Pencam line of cameras.
+         See <file:Documentation/usb/stv680.txt> for more information and for
+         a list of supported cameras.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Multimedia Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stv680.
+
+config USB_W9968CF
+       tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+       depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP
+       ---help---
+         Say Y here if you want support for cameras based on OV681 or
+         Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
+       
+         This driver has an optional plugin, which is distributed as a
+         separate module only (released under GPL). It allows to use higher 
+         resolutions and framerates, but cannot be included in the official 
+         Linux kernel for performance purposes.
+
+         See <file:Documentation/usb/w9968cf.txt> for more informations.
+
+         This driver uses the Video For Linux and the I2C APIs. It needs the
+         OmniVision Camera Chip support as well. You must say Y or M to
+         "Video For Linux", "I2C Support" and "OmniVision Camera Chip 
+         support" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w9968cf.
+
+config USB_ZC0301
+       tristate "USB ZC0301 Image Processor and Control Chip support"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y here if you want support for cameras based on the ZC0301
+         Image Processor and Control Chip.
+
+         See <file:Documentation/usb/zc0301.txt> for more informations.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" to use this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called zc0301.
+
+config USB_PWC
+       tristate "USB Philips Cameras"
+       depends on USB && VIDEO_DEV
+       ---help---
+         Say Y or M here if you want to use one of these Philips & OEM
+          webcams:
+           * Philips PCA645, PCA646
+           * Philips PCVC675, PCVC680, PCVC690
+           * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+          * Askey VC010
+          * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' 
+             and 'Orbit'/'Sphere'
+           * Samsung MPC-C10, MPC-C30
+          * Creative Webcam 5, Pro Ex
+          * SOTEC Afina Eye
+          * Visionite VCS-UC300, VCS-UM100
+          
+         The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
+         and never will be, but the 665 and 720/20 are supported by other 
+         drivers.
+
+         See <file:Documentation/usb/philips.txt> for more information and
+         installation instructions.
+
+         The built-in microphone is enabled by selecting USB Audio support.
+
+         This driver uses the Video For Linux API. You must say Y or M to
+         "Video For Linux" (under Character Devices) to use this driver.
+         Information on this API and pointers to "v4l" programs may be found
+         at <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called pwc.
+
+endmenu # V4L USB devices
+
 endmenu
index 1a56a2d9e294da6d2b999c46d8f28e5a615f9e32..1c0e72e5a593ac6a44e133fc16f25aa409afc50e 100644 (file)
@@ -65,4 +65,23 @@ obj-$(CONFIG_VIDEO_CX25840) += cx25840/
 obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 
+et61x251-objs   := et61x251_core.o et61x251_tas5130d1b.o
+zc0301-objs     := zc0301_core.o zc0301_pas202bcb.o
+
+obj-$(CONFIG_USB_DABUSB)        += dabusb.o
+obj-$(CONFIG_USB_DSBR)          += dsbr100.o
+obj-$(CONFIG_USB_OV511)         += ov511.o
+obj-$(CONFIG_USB_SE401)         += se401.o
+obj-$(CONFIG_USB_STV680)        += stv680.o
+obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
+
+obj-$(CONFIG_USB_SN9C102)       += sn9c102/
+obj-$(CONFIG_USB_ET61X251)      += et61x251/
+obj-$(CONFIG_USB_PWC)           += pwc/
+obj-$(CONFIG_USB_ZC0301)        += zc0301/
+
+obj-$(CONFIG_USB_IBMCAM)        += usbvideo/
+obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
+obj-$(CONFIG_USB_VICAM)         += usbvideo/
+
 EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/dabfirmware.h b/drivers/media/video/dabfirmware.h
new file mode 100644 (file)
index 0000000..d14d803
--- /dev/null
@@ -0,0 +1,1408 @@
+/*
+ * dabdata.h - dab usb firmware and bitstream data
+ */
+
+static INTEL_HEX_RECORD firmware[] = {
+
+{  2, 0x0000, 0, {0x21,0x57} },
+{  3, 0x0003, 0, {0x02,0x01,0x66} },
+{  3, 0x000b, 0, {0x02,0x01,0x66} },
+{  3, 0x0013, 0, {0x02,0x01,0x66} },
+{  3, 0x001b, 0, {0x02,0x01,0x66} },
+{  3, 0x0023, 0, {0x02,0x01,0x66} },
+{  3, 0x002b, 0, {0x02,0x01,0x66} },
+{  3, 0x0033, 0, {0x02,0x03,0x0f} },
+{  3, 0x003b, 0, {0x02,0x01,0x66} },
+{  3, 0x0043, 0, {0x02,0x01,0x00} },
+{  3, 0x004b, 0, {0x02,0x01,0x66} },
+{  3, 0x0053, 0, {0x02,0x01,0x66} },
+{  3, 0x005b, 0, {0x02,0x04,0xbd} },
+{  3, 0x0063, 0, {0x02,0x01,0x67} },
+{  3, 0x0100, 0, {0x02,0x0c,0x5a} },
+{  3, 0x0104, 0, {0x02,0x01,0xed} },
+{  3, 0x0108, 0, {0x02,0x02,0x51} },
+{  3, 0x010c, 0, {0x02,0x02,0x7c} },
+{  3, 0x0110, 0, {0x02,0x02,0xe4} },
+{  1, 0x0114, 0, {0x32} },
+{  1, 0x0118, 0, {0x32} },
+{  3, 0x011c, 0, {0x02,0x05,0xfd} },
+{  3, 0x0120, 0, {0x02,0x00,0x00} },
+{  3, 0x0124, 0, {0x02,0x00,0x00} },
+{  3, 0x0128, 0, {0x02,0x04,0x3c} },
+{  3, 0x012c, 0, {0x02,0x04,0x6a} },
+{  3, 0x0130, 0, {0x02,0x00,0x00} },
+{  3, 0x0134, 0, {0x02,0x00,0x00} },
+{  3, 0x0138, 0, {0x02,0x00,0x00} },
+{  3, 0x013c, 0, {0x02,0x00,0x00} },
+{  3, 0x0140, 0, {0x02,0x00,0x00} },
+{  3, 0x0144, 0, {0x02,0x00,0x00} },
+{  3, 0x0148, 0, {0x02,0x00,0x00} },
+{  3, 0x014c, 0, {0x02,0x00,0x00} },
+{  3, 0x0150, 0, {0x02,0x00,0x00} },
+{  3, 0x0154, 0, {0x02,0x00,0x00} },
+{ 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} },
+{  5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} },
+{  1, 0x0166, 0, {0x32} },
+{ 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} },
+{ 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} },
+{  3, 0x019f, 0, {0x55,0x7f,0xf0} },
+{ 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} },
+{  3, 0x01da, 0, {0xd0,0xd0,0x32} },
+{  8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} },
+{  7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} },
+{  1, 0x01ec, 0, {0x22} },
+{ 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} },
+{ 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} },
+{ 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} },
+{  9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} },
+{  4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} },
+{ 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} },
+{ 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} },
+{  2, 0x023c, 0, {0x01,0x0b} },
+{  2, 0x023e, 0, {0x80,0xe3} },
+{  2, 0x0240, 0, {0xd0,0x86} },
+{ 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} },
+{  1, 0x0250, 0, {0x32} },
+{ 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
+{  4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} },
+{ 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} },
+{  6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} },
+{  6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
+{ 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} },
+{ 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
+{  4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} },
+{ 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} },
+{  7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} },
+{  6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
+{ 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} },
+{  5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} },
+{ 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
+{ 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} },
+{ 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} },
+{  1, 0x0398, 0, {0xf0} },
+{  1, 0x0399, 0, {0x22} },
+{ 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
+{ 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} },
+{ 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} },
+{ 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} },
+{  1, 0x03ca, 0, {0x22} },
+{ 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} },
+{  9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} },
+{  2, 0x03de, 0, {0x03,0x72} },
+{  1, 0x03e0, 0, {0x22} },
+{ 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} },
+{  9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} },
+{  9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} },
+{  9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} },
+{  8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} },
+{  1, 0x0410, 0,{0x22} },
+{ 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
+{  4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} },
+{ 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} },
+{  7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} },
+{ 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
+{  7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} },
+{ 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} },
+{ 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} },
+{ 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} },
+{  1, 0x04ee, 0, {0x22} },
+{  7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} },
+{  1, 0x04f6, 0, {0x22} },
+{ 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} },
+{ 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} },
+{ 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} },
+{ 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} },
+{  2, 0x052c, 0, {0x7a,0x00} },
+{  7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} },
+{  2, 0x0535, 0, {0x7b,0x00} },
+{ 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} },
+{  7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} },
+{  9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} },
+{  4, 0x0552, 0, {0x70,0x47,0x75,0x71} },
+{  8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} },
+{  5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} },
+{  1, 0x0563, 0, {0x22} },
+{ 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
+{ 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} },
+{ 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} },
+{ 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} },
+{  5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} },
+{  3, 0x05a1, 0, {0x02,0x05,0xf9} },
+{  6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} },
+{ 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} },
+{ 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} },
+{  2, 0x05c6, 0, {0x80,0x31} },
+{ 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} },
+{ 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} },
+{ 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} },
+{  7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} },
+{  3, 0x05f9, 0, {0x75,0x38,0x01} },
+{  1, 0x05fc, 0, {0x22} },
+{ 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} },
+{ 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} },
+{ 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} },
+{ 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} },
+{ 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} },
+{ 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} },
+{ 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} },
+{  3, 0x06a2, 0, {0xbf,0x81,0x0a} },
+{ 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} },
+{  8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} },
+{  3, 0x06b7, 0, {0xba,0x01,0x0c} },
+{ 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
+{ 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} },
+{  8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} },
+{  3, 0x06d9, 0, {0xba,0x01,0x0d} },
+{ 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
+{ 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} },
+{  8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} },
+{  3, 0x06fc, 0, {0xba,0x01,0x0d} },
+{ 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} },
+{ 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} },
+{  5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} },
+{  1, 0x071d, 0, {0x22} },
+{ 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} },
+{ 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} },
+{  3, 0x074d, 0, {0xba,0xff,0x00} },
+{  2, 0x0750, 0, {0x50,0x0a} },
+{ 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
+{ 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} },
+{  8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} },
+{  1, 0x076e, 0, {0x22} },
+{ 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} },
+{ 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} },
+{ 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} },
+{  9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} },
+{  5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} },
+{  7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} },
+{ 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} },
+{  4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} },
+{  9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} },
+{  7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} },
+{ 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} },
+{ 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} },
+{ 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
+{ 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} },
+{ 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} },
+{ 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} },
+{ 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} },
+{ 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} },
+{ 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} },
+{ 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} },
+{ 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} },
+{ 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} },
+{ 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} },
+{  9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} },
+{ 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} },
+{  9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x089d, 0, {0x80,0xe0} },
+{ 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} },
+{ 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} },
+{ 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{ 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x08d0, 0, {0x80,0xd9} },
+{ 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} },
+{ 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} },
+{ 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} },
+{ 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} },
+{ 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} },
+{ 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} },
+{ 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} },
+{ 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} },
+{  3, 0x0937, 0, {0x02,0x0a,0x3f} },
+{ 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} },
+{ 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} },
+{ 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
+{ 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} },
+{ 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} },
+{  2, 0x097a, 0, {0x60,0x0c} },
+{ 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} },
+{ 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} },
+{ 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} },
+{  6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} },
+{  3, 0x09a7, 0, {0xba,0xa0,0x00} },
+{  2, 0x09aa, 0, {0x50,0x24} },
+{ 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} },
+{ 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} },
+{  9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
+{  5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} },
+{  6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} },
+{ 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} },
+{ 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} },
+{  6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} },
+{  5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} },
+{  4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} },
+{ 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} },
+{ 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
+{  3, 0x0a1a, 0, {0x05,0xd0,0x04} },
+{  5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} },
+{  4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} },
+{ 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} },
+{ 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
+{  3, 0x0a3c, 0, {0x05,0xd0,0x04} },
+{ 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} },
+{ 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} },
+{ 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} },
+{  8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} },
+{  8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} },
+{ 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} },
+{  5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} },
+{  5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} },
+{  5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} },
+{ 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} },
+{  1, 0x0a9f, 0, {0x00} },
+{  7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} },
+{ 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} },
+{ 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
+{  9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} },
+{  3, 0x0ac8, 0, {0x02,0x0b,0x36} },
+{  5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} },
+{  3, 0x0ad0, 0, {0xbb,0x64,0x00} },
+{  2, 0x0ad3, 0, {0x50,0x1c} },
+{ 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{ 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} },
+{  1, 0x0af0, 0, {0xdf} },
+{ 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} },
+{ 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} },
+{ 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} },
+{  9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} },
+{ 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
+{ 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} },
+{  3, 0x0b36, 0, {0xba,0x2a,0x3b} },
+{ 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
+{ 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} },
+{  2, 0x0b54, 0, {0x7b,0x00} },
+{  3, 0x0b56, 0, {0xbb,0x0a,0x00} },
+{  5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} },
+{ 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{  8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} },
+{  3, 0x0b74, 0, {0xba,0x2b,0x1a} },
+{  8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} },
+{ 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0b91, 0, {0xba,0x10,0x1f} },
+{ 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} },
+{ 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
+{  3, 0x0bb0, 0, {0x02,0x0c,0x2d} },
+{  3, 0x0bb3, 0, {0xba,0x11,0x12} },
+{ 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0bc8, 0, {0xba,0x12,0x12} },
+{ 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0bdd, 0, {0xba,0x13,0x0b} },
+{ 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} },
+{  3, 0x0beb, 0, {0xba,0x14,0x11} },
+{ 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} },
+{  3, 0x0bfc, 0, {0x02,0x80,0x2e} },
+{  3, 0x0bff, 0, {0xba,0x15,0x1d} },
+{ 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} },
+{ 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} },
+{  3, 0x0c1c, 0, {0x02,0x80,0x0e} },
+{  3, 0x0c1f, 0, {0xba,0x16,0x0b} },
+{ 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} },
+{ 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} },
+{  1, 0x0c38, 0, {0x22} },
+{  7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} },
+{  7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} },
+{  6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} },
+{ 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} },
+{ 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} },
+{  6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} },
+{  3, 0x0c97, 0, {0x02,0x0d,0x38} },
+{  3, 0x0c9a, 0, {0xba,0x80,0x14} },
+{ 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} },
+{  6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} },
+{  5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} },
+{  3, 0x0cb6, 0, {0x02,0x0d,0x1d} },
+{  8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} },
+{  2, 0x0cc1, 0, {0x40,0x21} },
+{  6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} },
+{ 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
+{ 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} },
+{  3, 0x0ce4, 0, {0xbc,0x81,0x00} },
+{  2, 0x0ce7, 0, {0x40,0x21} },
+{  6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} },
+{ 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
+{ 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} },
+{  5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} },
+{ 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} },
+{  5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} },
+{  3, 0x0d22, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} },
+{  5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} },
+{  3, 0x0d38, 0, {0xbb,0x01,0x2d} },
+{  6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
+{  3, 0x0d41, 0, {0xba,0x02,0x11} },
+{ 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
+{  4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} },
+{  5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} },
+{  3, 0x0d5a, 0, {0x02,0x0e,0xcd} },
+{ 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} },
+{  3, 0x0d68, 0, {0xbb,0x03,0x1f} },
+{  6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
+{  5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} },
+{  3, 0x0d76, 0, {0x02,0x0e,0xcd} },
+{ 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
+{  4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} },
+{  3, 0x0d8a, 0, {0xbb,0x06,0x54} },
+{  5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} },
+{  3, 0x0d92, 0, {0x02,0x0e,0xc5} },
+{  8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} },
+{ 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
+{  9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
+{ 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} },
+{  3, 0x0dbc, 0, {0x02,0x0e,0xc5} },
+{ 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} },
+{  3, 0x0dc9, 0, {0x02,0x0e,0xc5} },
+{ 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
+{  9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
+{  6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} },
+{  3, 0x0de7, 0, {0xbb,0x08,0x10} },
+{ 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
+{  3, 0x0df7, 0, {0x02,0x0e,0xcd} },
+{  3, 0x0dfa, 0, {0xbb,0x09,0x31} },
+{  5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} },
+{  3, 0x0e02, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} },
+{  8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} },
+{ 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} },
+{  9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} },
+{  3, 0x0e2e, 0, {0xbb,0x0a,0x27} },
+{  5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} },
+{  3, 0x0e36, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} },
+{ 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
+{  3, 0x0e55, 0, {0x02,0x0e,0xcd} },
+{  5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} },
+{  3, 0x0e5d, 0, {0x02,0x0e,0xa9} },
+{ 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} },
+{  8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} },
+{ 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} },
+{  4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} },
+{  8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} },
+{  8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} },
+{ 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} },
+{  5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} },
+{  5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} },
+{  5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} },
+{  5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} },
+{  5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} },
+{  3, 0x0ebd, 0, {0xbb,0x84,0x05} },
+{  5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} },
+{  8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} },
+{  6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} },
+{  2, 0x0ed3, 0, {0xd0,0x86} },
+{ 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} },
+{  7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} },
+{ 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} },
+{  9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} },
+{  7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} },
+{  7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} },
+{ 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} },
+{  7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} },
+{  1, 0x0f3a, 0, {0x22} },
+{ 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} },
+{ 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} },
+{ 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} },
+{ 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} },
+{ 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} },
+{ 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} },
+{ 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} },
+{ 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} },
+{ 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} },
+{ 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} },
+{ 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} },
+{ 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} },
+{ 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} },
+{ 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} },
+{ 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} },
+{ 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} },
+{  4, 0x1017, 0, {0x00,0x03,0x01,0x00} },
+{  2, 0x101b, 0, {0x7a,0x00} },
+{  3, 0x101d, 0, {0xba,0x05,0x00} },
+{  2, 0x1020, 0, {0x50,0x17} },
+{  8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} },
+{  5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} },
+{ 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} },
+{  3, 0x1039, 0, {0x90,0x00,0x01} },
+{  1, 0x103c, 0, {0x22} },
+{ 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} },
+{  4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} },
+{ 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} },
+{  4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} },
+{  8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} },
+{  1, 0x1069, 0, {0x22} },
+{ 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} },
+{  4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} },
+{ 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} },
+{  4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} },
+{  1, 0x108e, 0, {0x22} },
+{ 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} },
+{ 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} },
+{  5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} },
+{ 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} },
+{  6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} },
+{  6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} },
+{  1, 0x10c9, 0, {0x22} },
+{  8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} },
+{  3, 0x10d2, 0, {0xba,0xff,0x00} },
+{  2, 0x10d5, 0, {0x50,0x0a} },
+{ 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
+{  1, 0x10e1, 0, {0x22} },
+{  5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} },
+{  8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} },
+{  6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} },
+{  4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} },
+{ 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} },
+{  5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x1109, 0, {0x80,0xee} },
+{  1, 0x110b, 0, {0x22} },
+{ 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} },
+{  3, 0x1116, 0, {0xba,0x28,0x00} },
+{  2, 0x1119, 0, {0x50,0x03} },
+{  3, 0x111b, 0, {0x0a,0x80,0xf8} },
+{  5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} },
+{  8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} },
+{  5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} },
+{  9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} },
+{  2, 0x1139, 0, {0x7a,0x00} },
+{  3, 0x113b, 0, {0xba,0x28,0x00} },
+{  2, 0x113e, 0, {0x50,0x03} },
+{  3, 0x1140, 0, {0x0a,0x80,0xf8} },
+{  1, 0x1143, 0, {0x22} },
+{  4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} },
+{  2, 0x1148, 0, {0x80,0x07} },
+{  7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} },
+{  5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} },
+{  9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} },
+{ 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} },
+{  8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} },
+{  3, 0x1171, 0, {0x0a,0x80,0xf5} },
+{  1, 0x1174, 0, {0x22} },
+{  6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} },
+{ 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} },
+{ 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} },
+{  9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x119d, 0, {0x80,0xdc} },
+{  1, 0x119f, 0, {0x22} },
+{ 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} },
+{  2, 0x11ad, 0, {0x50,0x06} },
+{  6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
+{  4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} },
+{ 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} },
+{  8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} },
+{  6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
+{  4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} },
+{  5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} },
+{  1, 0x11dc, 0, {0x22} },
+{  7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} },
+{ 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} },
+{  3, 0x11f0, 0, {0x12,0x11,0x44} },
+{ 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} },
+{  5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} },
+{  1, 0x1204, 0, {0x22} },
+{  2, 0x1205, 0, {0x7a,0x04} },
+{  3, 0x1207, 0, {0xba,0x40,0x00} },
+{  2, 0x120a, 0, {0x50,0x36} },
+{ 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} },
+{  3, 0x121a, 0, {0xbc,0x08,0x00} },
+{  2, 0x121d, 0, {0x50,0x20} },
+{  6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} },
+{ 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} },
+{  8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} },
+{  7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} },
+{  3, 0x123f, 0, {0x0a,0x80,0xc5} },
+{  1, 0x1242, 0, {0x22} },
+{  4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} },
+{  3, 0x1247, 0, {0xba,0x10,0x00} },
+{  2, 0x124a, 0, {0x50,0x20} },
+{ 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} },
+{ 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} },
+{  4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} },
+{  1, 0x126c, 0, {0x22} },
+{ 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{  1, 0x12b3, 0, {0x22} },
+{ 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} },
+{ 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} },
+{ 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} },
+{ 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} },
+{ 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} },
+{ 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} },
+{ 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} },
+{ 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} },
+{ 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} },
+{ 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} },
+{ 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} },
+{ 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} },
+{  3, 0x135c, 0, {0xbd,0x06,0x00} },
+{  2, 0x135f, 0, {0x50,0x12} },
+{ 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
+{  7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} },
+{ 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} },
+{ 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} },
+{ 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} },
+{  6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} },
+{  1, 0x13a2, 0, {0x22} },
+{ 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} },
+{ 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} },
+{  3, 0x13be, 0, {0xfa,0x7b,0x00} },
+{  3, 0x13c1, 0, {0xbb,0x10,0x00} },
+{  2, 0x13c4, 0, {0x50,0x24} },
+{ 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} },
+{ 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} },
+{  8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} },
+{ 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} },
+{  5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} },
+{  1, 0x13fd, 0, {0x22} },
+{  4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} },
+{  2, 0x1402, 0, {0x80,0x16} },
+{ 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} },
+{ 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} },
+{ 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} },
+{  6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} },
+{  6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} },
+{ 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} },
+{  1, 0x143b, 0, {0xe4} },
+{  3, 0x143c, 0, {0xfa,0x70,0x0f} },
+{ 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} },
+{  3, 0x144b, 0, {0x02,0x80,0x0a} },
+{ 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} },
+{ 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} },
+{  4, 0x1464, 0, {0x02,0xea,0x70,0x1a} },
+{ 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} },
+{  9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} },
+{  4, 0x147e, 0, {0x11,0x75,0x80,0x36} },
+{  2, 0x1482, 0, {0x7a,0x00} },
+{  3, 0x1484, 0, {0xba,0x10,0x00} },
+{  2, 0x1487, 0, {0x50,0x2f} },
+{ 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} },
+{  4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} },
+{ 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} },
+{  9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} },
+{  4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} },
+{  3, 0x14b5, 0, {0x0a,0x80,0xcc} },
+{  1, 0x14b8, 0, {0x22} },
+{  6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} },
+{ 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} },
+{  7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} },
+{  7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} },
+{  5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} },
+{  4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} },
+{  5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} },
+{  4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} },
+{  1, 0x14ed, 0, {0x22} },
+{ 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} },
+{  6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} },
+{  5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} },
+{  3, 0x1507, 0, {0xe0,0x80,0x07} },
+{  4, 0x150a, 0, {0xe4,0x93,0x80,0x03} },
+{  3, 0x150e, 0, {0xa8,0x82,0xe2} },
+{  4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} },
+{  1, 0x1515, 0, {0x22} },
+{  0, 0x0000, 1, {0} }
+
+};
+
+static unsigned char bitstream[] = {
+
+0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D,
+0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B,
+0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39,
+0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34,
+0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B,
+0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F,
+0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF,
+0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF,
+0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE,
+0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF,
+0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF,
+0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF,
+0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD,
+0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,
+0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF,
+0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D,
+0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE,
+0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF,
+0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F,
+0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F,
+0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF,
+0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F,
+0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F,
+0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2,
+0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF,
+0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE,
+0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF,
+0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF,
+0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B,
+0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF,
+0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7,
+0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF,
+0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF,
+0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5,
+0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD,
+0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF,
+0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF,
+0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B,
+0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF,
+0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED,
+0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF,
+0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB,
+0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF,
+0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE,
+0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7,
+0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE,
+0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF,
+0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD,
+0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD,
+0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF,
+0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD,
+0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A,
+0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF,
+0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF,
+0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA,
+0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF,
+0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD,
+0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF,
+0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,
+0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E,
+0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF,
+0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF,
+0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF,
+0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3,
+0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF,
+0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F,
+0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF,
+0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF,
+0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7,
+0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF,
+0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD,
+0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD,
+0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE,
+0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF,
+0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF,
+0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3,
+0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A,
+0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF,
+0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB,
+0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF,
+0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD,
+0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF,
+0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,
+0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F,
+0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
+0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F,
+0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
+0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED,
+0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7,
+0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7,
+0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF,
+0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F,
+0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE,
+0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
+0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA,
+0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F,
+0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA,
+0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB,
+0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF,
+0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB,
+0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF,
+0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF,
+0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD,
+0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C,
+0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF,
+0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF,
+0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD,
+0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF,
+0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3,
+0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB,
+0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F,
+0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3,
+0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF,
+0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7,
+0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7,
+0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF,
+0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE,
+0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF,
+0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB,
+0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66,
+0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE,
+0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6,
+0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED,
+0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD,
+0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7,
+0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF,
+0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB,
+0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF,
+0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F,
+0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7,
+0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9,
+0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF,
+0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF,
+0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE,
+0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF,
+0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF,
+0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF,
+0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD,
+0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1,
+0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF,
+0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5,
+0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF,
+0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB,
+0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF,
+0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF,
+0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3,
+0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE,
+0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD,
+0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE,
+0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF,
+0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF,
+0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB,
+0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF,
+0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF,
+0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF,
+0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F,
+0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C,
+0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD,
+0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF,
+0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F,
+0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE,
+0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD,
+0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54,
+0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2,
+0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD,
+0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF,
+0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF,
+0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7,
+0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA,
+0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF,
+0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C,
+0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF,
+0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5,
+0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB,
+0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF,
+0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF,
+0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F,
+0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F,
+0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF,
+0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF,
+0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5,
+0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF,
+0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF,
+0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A,
+0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36,
+0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF,
+0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F,
+0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F,
+0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF,
+0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF,
+0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF,
+0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF,
+0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE,
+0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,
+0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF,
+0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F,
+0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B,
+0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB,
+0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF,
+0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF,
+0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA,
+0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37,
+0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD,
+0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B,
+0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF,
+0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B,
+0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B,
+0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF,
+0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD,
+0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF,
+0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE,
+0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF,
+0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF,
+0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA,
+0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E,
+0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF,
+0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF,
+0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6,
+0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD,
+0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB,
+0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F,
+0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F,
+0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7,
+0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB,
+0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD,
+0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E,
+0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF,
+0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE,
+0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF,
+0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF,
+0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE,
+0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2,
+0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF,
+0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF,
+0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF,
+0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC,
+0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF,
+0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7,
+0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7,
+0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3,
+0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9,
+0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF,
+0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,
+0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F,
+0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B,
+0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE,
+0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79,
+0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F,
+0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7,
+0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC,
+0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7,
+0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF,
+0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,
+0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F,
+0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE,
+0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF,
+0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F,
+0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7,
+0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7,
+0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF,
+0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,
+0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD,
+0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF,
+0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB,
+0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE,
+0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3,
+0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF,
+0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF,
+0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE,
+0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6,
+0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF,
+0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF,
+0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F,
+0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE,
+0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6,
+0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77,
+0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF,
+0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A,
+0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F,
+0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F,
+0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF,
+0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB,
+0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F,
+0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67,
+0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF,
+0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D,
+0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3,
+0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D,
+0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB,
+0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE,
+0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5,
+0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D,
+0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F,
+0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB,
+0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB,
+0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9,
+0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF,
+0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF,
+0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF,
+0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77,
+0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F,
+0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE,
+0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
+0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF,
+0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD,
+0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F,
+0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A,
+0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA,
+0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF,
+0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF,
+0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF,
+0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF,
+0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF,
+0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9,
+0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F,
+0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7,
+0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4,
+0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9,
+0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF,
+0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7,
+0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF,
+0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF,
+0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF,
+0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5,
+0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF,
+0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD,
+0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77,
+0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE,
+0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF,
+0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF,
+0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC,
+0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB,
+0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F,
+0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6,
+0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD,
+0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF,
+0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC,
+0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,
+0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E,
+0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F,
+0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB,
+0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF,
+0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7,
+0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F,
+0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2,
+0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA,
+0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF,
+0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8,
+0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB,
+0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF,
+0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB,
+0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF,
+0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF,
+0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7,
+0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3,
+0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F,
+0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD,
+0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF,
+0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
+0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF,
+0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F,
+0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF,
+0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F,
+0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF,
+0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7,
+0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9,
+0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71,
+0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF,
+0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF,
+0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F,
+0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7,
+0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC,
+0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE,
+0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7,
+0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF,
+0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB,
+0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B,
+0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF,
+0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF,
+0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE,
+0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17,
+0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9,
+0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F,
+0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE,
+0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,
+0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F,
+0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF,
+0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF,
+0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F,
+0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF,
+0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5,
+0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA,
+0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE,
+0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF,
+0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA,
+0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3,
+0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,
+0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7,
+0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
+0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF,
+0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB,
+0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9,
+0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF,
+0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD,
+0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE,
+0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE,
+0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB,
+0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB,
+0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB,
+0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF,
+0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF,
+0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77,
+0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE,
+0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8,
+0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E,
+0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3,
+0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,
+0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7,
+0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB,
+0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF,
+0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF,
+0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF,
+0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3,
+0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F,
+0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F,
+0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF,
+0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,
+0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF,
+0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF,
+0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD,
+0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE,
+0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1,
+0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF,
+0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC,
+0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF,
+0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB,
+0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9,
+0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E,
+0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF,
+0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,
+0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,
+0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF,
+0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7,
+0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF,
+0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F,
+0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF,
+0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF,
+0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF,
+0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3,
+0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC,
+0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF,
+0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF,
+0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF,
+0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF,
+0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF,
+0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF,
+0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF,
+0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF,
+0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF,
+0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB,
+0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F,
+0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF,
+0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD,
+0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD,
+0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE,
+0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF,
+0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5,
+0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F,
+0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF,
+0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE,
+0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF,
+0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF,
+0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF,
+0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB,
+0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7,
+0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF,
+0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F,
+0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
+0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF,
+0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB,
+0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF,
+0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF,
+0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF,
+0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,
+0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,
+0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE,
+0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE,
+0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4,
+0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC,
+0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF,
+0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7,
+0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65,
+0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3,
+0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,
+0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB,
+0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF,
+0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B,
+0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF,
+0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF,
+0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF,
+0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7,
+0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF,
+0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9,
+0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,
+0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF,
+0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF,
+0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A,
+0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7,
+0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF,
+0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD,
+0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC,
+0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA,
+0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D,
+0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF,
+0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6,
+0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
+0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF,
+0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF,
+0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF,
+0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF,
+0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB,
+0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E,
+0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF,
+0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF,
+0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF,
+0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16,
+0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF,
+0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7,
+0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9,
+0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF,
+0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F,
+0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A,
+0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE,
+0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB,
+0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB,
+0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3,
+0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF,
+0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE,
+0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB,
+0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF,
+0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE,
+0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5,
+0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF,
+0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD,
+0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F,
+0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7,
+0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
+0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA,
+0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD,
+0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA,
+0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33,
+0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9,
+0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF,
+0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77,
+0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF,
+0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F,
+0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF,
+0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF,
+0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7,
+0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,
+0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB,
+0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF,
+0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD,
+0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE,
+0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF,
+0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F,
+0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B,
+0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9,
+0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD,
+0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF,
+0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB,
+0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF,
+0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF,
+0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF,
+0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9,
+0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF,
+0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD,
+0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE,
+0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF,
+0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF,
+0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE,
+0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE,
+0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF,
+0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF,
+0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF,
+0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF,
+0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF,
+0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF,
+0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD,
+0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF,
+0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F,
+0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF,
+0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE,
+0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB,
+0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF,
+0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF,
+0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5,
+0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF,
+0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF,
+0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB,
+0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7,
+0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF,
+0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE,
+0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB,
+0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB,
+0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF,
+0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7,
+0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F,
+0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF,
+0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF,
+0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F,
+0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD,
+0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF,
+0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF,
+0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF,
+0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7,
+0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,
+0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,
+0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC,
+0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC,
+0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF,
+0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF,
+0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB,
+0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD,
+0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF
+
+};
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
new file mode 100644 (file)
index 0000000..1774ab7
--- /dev/null
@@ -0,0 +1,874 @@
+/*****************************************************************************/
+
+/*
+ *      dabusb.c  --  dab usb driver.
+ *
+ *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.de)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *  $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+
+#include "dabusb.h"
+#include "dabfirmware.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.54"
+#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
+#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
+
+/* --------------------------------------------------------------------- */
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define NRDABUSB 256
+#else
+#define NRDABUSB 4
+#endif
+
+/*-------------------------------------------------------------------*/
+
+static dabusb_t dabusb[NRDABUSB];
+static int buffers = 256;
+static struct usb_driver dabusb_driver;
+
+/*-------------------------------------------------------------------*/
+
+static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src)
+{
+       unsigned long flags;
+       struct list_head *tmp;
+       int ret = 0;
+
+       spin_lock_irqsave (&s->lock, flags);
+
+       if (list_empty (src)) {
+               // no elements in source buffer
+               ret = -1;
+               goto err;
+       }
+       tmp = src->next;
+       list_move_tail (tmp, dst);
+
+  err: spin_unlock_irqrestore (&s->lock, flags);
+       return ret;
+}
+/*-------------------------------------------------------------------*/
+#ifdef DEBUG 
+static void dump_urb (struct urb *urb)
+{
+       dbg("urb                   :%p", urb);
+       dbg("dev                   :%p", urb->dev);
+       dbg("pipe                  :%08X", urb->pipe);
+       dbg("status                :%d", urb->status);
+       dbg("transfer_flags        :%08X", urb->transfer_flags);
+       dbg("transfer_buffer       :%p", urb->transfer_buffer);
+       dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
+       dbg("actual_length         :%d", urb->actual_length);
+       dbg("setup_packet          :%p", urb->setup_packet);
+       dbg("start_frame           :%d", urb->start_frame);
+       dbg("number_of_packets     :%d", urb->number_of_packets);
+       dbg("interval              :%d", urb->interval);
+       dbg("error_count           :%d", urb->error_count);
+       dbg("context               :%p", urb->context);
+       dbg("complete              :%p", urb->complete);
+}
+#endif
+/*-------------------------------------------------------------------*/
+static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
+{
+       unsigned long flags;
+       pbuff_t b;
+
+       dbg("dabusb_cancel_queue");
+
+       spin_lock_irqsave (&s->lock, flags);
+
+       list_for_each_entry(b, q, buff_list) {
+#ifdef DEBUG
+               dump_urb(b->purb);
+#endif
+               usb_unlink_urb (b->purb);
+       }
+       spin_unlock_irqrestore (&s->lock, flags);
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_free_queue (struct list_head *q)
+{
+       struct list_head *tmp;
+       struct list_head *p;
+       pbuff_t b;
+
+       dbg("dabusb_free_queue");
+       for (p = q->next; p != q;) {
+               b = list_entry (p, buff_t, buff_list);
+
+#ifdef DEBUG 
+               dump_urb(b->purb);
+#endif
+               kfree(b->purb->transfer_buffer);
+               usb_free_urb(b->purb);
+               tmp = p->next;
+               list_del (p);
+               kfree (b);
+               p = tmp;
+       }
+
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_free_buffers (pdabusb_t s)
+{
+       unsigned long flags;
+       dbg("dabusb_free_buffers");
+
+       spin_lock_irqsave(&s->lock, flags);
+
+       dabusb_free_queue (&s->free_buff_list);
+       dabusb_free_queue (&s->rec_buff_list);
+
+       spin_unlock_irqrestore(&s->lock, flags);
+
+       s->got_mem = 0;
+       return 0;
+}
+/*-------------------------------------------------------------------*/
+static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)
+{
+       pbuff_t b = purb->context;
+       pdabusb_t s = b->s;
+       int i;
+       int len;
+       int dst = 0;
+       void *buf = purb->transfer_buffer;
+
+       dbg("dabusb_iso_complete");
+
+       // process if URB was not killed
+       if (purb->status != -ENOENT) {
+               unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
+               int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+               for (i = 0; i < purb->number_of_packets; i++)
+                       if (!purb->iso_frame_desc[i].status) {
+                               len = purb->iso_frame_desc[i].actual_length;
+                               if (len <= pipesize) {
+                                       memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);
+                                       dst += len;
+                               }
+                               else
+                                       err("dabusb_iso_complete: invalid len %d", len);
+                       }
+                       else
+                               warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status);
+               if (dst != purb->actual_length)
+                       err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
+       }
+
+       if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
+               s->overruns++;
+               err("overrun (%d)", s->overruns);
+       }
+       wake_up (&s->wait);
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_alloc_buffers (pdabusb_t s)
+{
+       int buffers = 0;
+       pbuff_t b;
+       unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
+       int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
+       int packets = _ISOPIPESIZE / pipesize;
+       int transfer_buffer_length = packets * pipesize;
+       int i;
+
+       dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
+                pipesize, packets, transfer_buffer_length);
+
+       while (buffers < (s->total_buffer_size << 10)) {
+               b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
+               if (!b) {
+                       err("kzalloc(sizeof(buff_t))==NULL");
+                       goto err;
+               }
+               b->s = s;
+               b->purb = usb_alloc_urb(packets, GFP_KERNEL);
+               if (!b->purb) {
+                       err("usb_alloc_urb == NULL");
+                       kfree (b);
+                       goto err;
+               }
+
+               b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);
+               if (!b->purb->transfer_buffer) {
+                       kfree (b->purb);
+                       kfree (b);
+                       err("kmalloc(%d)==NULL", transfer_buffer_length);
+                       goto err;
+               }
+
+               b->purb->transfer_buffer_length = transfer_buffer_length;
+               b->purb->number_of_packets = packets;
+               b->purb->complete = dabusb_iso_complete;
+               b->purb->context = b;
+               b->purb->dev = s->usbdev;
+               b->purb->pipe = pipe;
+               b->purb->transfer_flags = URB_ISO_ASAP;
+
+               for (i = 0; i < packets; i++) {
+                       b->purb->iso_frame_desc[i].offset = i * pipesize;
+                       b->purb->iso_frame_desc[i].length = pipesize;
+               }
+
+               buffers += transfer_buffer_length;
+               list_add_tail (&b->buff_list, &s->free_buff_list);
+       }
+       s->got_mem = buffers;
+
+       return 0;
+
+       err:
+       dabusb_free_buffers (s);
+       return -ENOMEM;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
+{
+       int ret;
+       unsigned int pipe;
+       int actual_length;
+
+       dbg("dabusb_bulk");
+
+       if (!pb->pipe)
+               pipe = usb_rcvbulkpipe (s->usbdev, 2);
+       else
+               pipe = usb_sndbulkpipe (s->usbdev, 2);
+
+       ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
+       if(ret<0) {
+               err("dabusb: usb_bulk_msg failed(%d)",ret);
+
+               if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+                       err("set_interface failed");
+                       return -EINVAL;
+               }
+
+       }
+       
+       if( ret == -EPIPE ) {
+               warn("CLEAR_FEATURE request to remove STALL condition.");
+               if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
+                       err("request failed");
+       }
+
+       pb->size = actual_length;
+       return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len)
+{
+       int ret;
+       unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);
+
+       if (!transfer_buffer) {
+               err("dabusb_writemem: kmalloc(%d) failed.", len);
+               return -ENOMEM;
+       }
+
+       memcpy (transfer_buffer, data, len);
+
+       ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
+
+       kfree (transfer_buffer);
+       return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit)
+{
+       dbg("dabusb_8051_reset: %d",reset_bit);
+       return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_loadmem (pdabusb_t s, const char *fname)
+{
+       int ret;
+       PINTEL_HEX_RECORD ptr = firmware;
+
+       dbg("Enter dabusb_loadmem (internal)");
+       
+       ret = dabusb_8051_reset (s, 1);
+       while (ptr->Type == 0) {
+
+               dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length);
+
+               ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length);
+               if (ret < 0) {
+                       err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length);
+                       break;
+               }
+               ptr++;
+       }
+       ret = dabusb_8051_reset (s, 0);
+
+       dbg("dabusb_loadmem: exit");
+
+       return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b)
+{
+       b->size = 4;
+       b->data[0] = 0x2a;
+       b->data[1] = 0;
+       b->data[2] = 0;
+       b->data[3] = 0;
+
+       dbg("dabusb_fpga_clear");
+
+       return dabusb_bulk (s, b);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b)
+{
+       b->size = 4;
+       b->data[0] = 0x2c;
+       b->data[1] = 0;
+       b->data[2] = 0;
+       b->data[3] = 0;
+
+       dbg("dabusb_fpga_init");
+
+       return dabusb_bulk (s, b);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_download (pdabusb_t s, const char *fname)
+{
+       pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+       unsigned int blen, n;
+       int ret;
+       unsigned char *buf = bitstream;
+
+       dbg("Enter dabusb_fpga_download (internal)");
+
+       if (!b) {
+               err("kmalloc(sizeof(bulk_transfer_t))==NULL");
+               return -ENOMEM;
+       }
+
+       b->pipe = 1;
+       ret = dabusb_fpga_clear (s, b);
+       mdelay (10);
+       blen = buf[73] + (buf[72] << 8);
+
+       dbg("Bitstream len: %i", blen);
+
+       b->data[0] = 0x2b;
+       b->data[1] = 0;
+       b->data[2] = 0;
+       b->data[3] = 60;
+
+       for (n = 0; n <= blen + 60; n += 60) {
+               // some cclks for startup
+               b->size = 64;
+               memcpy (b->data + 4, buf + 74 + n, 60);
+               ret = dabusb_bulk (s, b);
+               if (ret < 0) {
+                       err("dabusb_bulk failed.");
+                       break;
+               }
+               mdelay (1);
+       }
+
+       ret = dabusb_fpga_init (s, b);
+       kfree (b);
+
+       dbg("exit dabusb_fpga_download");
+
+       return ret;
+}
+
+static int dabusb_stop (pdabusb_t s)
+{
+       dbg("dabusb_stop");
+
+       s->state = _stopped;
+       dabusb_cancel_queue (s, &s->rec_buff_list);
+
+       dbg("pending_io: %d", s->pending_io.counter);
+
+       s->pending_io.counter = 0;
+       return 0;
+}
+
+static int dabusb_startrek (pdabusb_t s)
+{
+       if (!s->got_mem && s->state != _started) {
+
+               dbg("dabusb_startrek");
+
+               if (dabusb_alloc_buffers (s) < 0)
+                       return -ENOMEM;
+               dabusb_stop (s);
+               s->state = _started;
+               s->readptr = 0;
+       }
+
+       if (!list_empty (&s->free_buff_list)) {
+               pbuff_t end;
+               int ret;
+               
+       while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) {
+
+                       dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
+
+                       end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
+
+                       ret = usb_submit_urb (end->purb, GFP_KERNEL);
+                       if (ret) {
+                               err("usb_submit_urb returned:%d", ret);
+                               if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+                                       err("startrek: dabusb_add_buf_tail failed");
+                               break;
+                       }
+                       else
+                               atomic_inc (&s->pending_io);
+               }
+               dbg("pending_io: %d",s->pending_io.counter);
+       }
+
+       return 0;
+}
+
+static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
+{
+       pdabusb_t s = (pdabusb_t) file->private_data;
+       unsigned long flags;
+       unsigned ret = 0;
+       int rem;
+       int cnt;
+       pbuff_t b;
+       struct urb *purb = NULL;
+
+       dbg("dabusb_read");
+
+       if (*ppos)
+               return -ESPIPE;
+
+       if (s->remove_pending)
+               return -EIO;
+
+
+       if (!s->usbdev)
+               return -EIO;
+
+       while (count > 0) {
+               dabusb_startrek (s);
+
+               spin_lock_irqsave (&s->lock, flags);
+
+               if (list_empty (&s->rec_buff_list)) {
+
+                       spin_unlock_irqrestore(&s->lock, flags);
+
+                       err("error: rec_buf_list is empty");
+                       goto err;
+               }
+               
+               b = list_entry (s->rec_buff_list.next, buff_t, buff_list);
+               purb = b->purb;
+
+               spin_unlock_irqrestore(&s->lock, flags);
+
+               if (purb->status == -EINPROGRESS) {
+                       if (file->f_flags & O_NONBLOCK)         // return nonblocking
+                        {
+                               if (!ret)
+                                       ret = -EAGAIN;
+                               goto err;
+                       }
+
+                       interruptible_sleep_on (&s->wait);
+
+                       if (signal_pending (current)) {
+                               if (!ret)
+                                       ret = -ERESTARTSYS;
+                               goto err;
+                       }
+
+                       spin_lock_irqsave (&s->lock, flags);
+
+                       if (list_empty (&s->rec_buff_list)) {
+                               spin_unlock_irqrestore(&s->lock, flags);
+                               err("error: still no buffer available.");
+                               goto err;
+                       }
+                       spin_unlock_irqrestore(&s->lock, flags);
+                       s->readptr = 0;
+               }
+               if (s->remove_pending) {
+                       ret = -EIO;
+                       goto err;
+               }
+
+               rem = purb->actual_length - s->readptr;         // set remaining bytes to copy
+
+               if (count >= rem)
+                       cnt = rem;
+               else
+                       cnt = count;
+
+               dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
+
+               if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
+                       err("read: copy_to_user failed");
+                       if (!ret)
+                               ret = -EFAULT;
+                       goto err;
+               }
+
+               s->readptr += cnt;
+               count -= cnt;
+               buf += cnt;
+               ret += cnt;
+
+               if (s->readptr == purb->actual_length) {
+                       // finished, take next buffer
+                       if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+                               err("read: dabusb_add_buf_tail failed");
+                       s->readptr = 0;
+               }
+       }
+      err:                     //mutex_unlock(&s->mutex);
+       return ret;
+}
+
+static int dabusb_open (struct inode *inode, struct file *file)
+{
+       int devnum = iminor(inode);
+       pdabusb_t s;
+
+       if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
+               return -EIO;
+
+       s = &dabusb[devnum - DABUSB_MINOR];
+
+       dbg("dabusb_open");
+       mutex_lock(&s->mutex);
+
+       while (!s->usbdev || s->opened) {
+               mutex_unlock(&s->mutex);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       return -EBUSY;
+               }
+               msleep_interruptible(500);
+
+               if (signal_pending (current)) {
+                       return -EAGAIN;
+               }
+               mutex_lock(&s->mutex);
+       }
+       if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+               mutex_unlock(&s->mutex);
+               err("set_interface failed");
+               return -EINVAL;
+       }
+       s->opened = 1;
+       mutex_unlock(&s->mutex);
+
+       file->f_pos = 0;
+       file->private_data = s;
+
+       return nonseekable_open(inode, file);
+}
+
+static int dabusb_release (struct inode *inode, struct file *file)
+{
+       pdabusb_t s = (pdabusb_t) file->private_data;
+
+       dbg("dabusb_release");
+
+       mutex_lock(&s->mutex);
+       dabusb_stop (s);
+       dabusb_free_buffers (s);
+       mutex_unlock(&s->mutex);
+
+       if (!s->remove_pending) {
+               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
+                       err("set_interface failed");
+       }
+       else
+               wake_up (&s->remove_ok);
+
+       s->opened = 0;
+       return 0;
+}
+
+static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       pdabusb_t s = (pdabusb_t) file->private_data;
+       pbulk_transfer_t pbulk;
+       int ret = 0;
+       int version = DABUSB_VERSION;
+
+       dbg("dabusb_ioctl");
+
+       if (s->remove_pending)
+               return -EIO;
+
+       mutex_lock(&s->mutex);
+
+       if (!s->usbdev) {
+               mutex_unlock(&s->mutex);
+               return -EIO;
+       }
+
+       switch (cmd) {
+
+       case IOCTL_DAB_BULK:
+               pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+
+               if (!pbulk) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
+                       ret = -EFAULT;
+                       kfree (pbulk);
+                       break;
+               }
+
+               ret=dabusb_bulk (s, pbulk);
+               if(ret==0)
+                       if (copy_to_user((void __user *)arg, pbulk,
+                                        sizeof(bulk_transfer_t)))
+                               ret = -EFAULT;
+               kfree (pbulk);
+               break;
+
+       case IOCTL_DAB_OVERRUNS:
+               ret = put_user (s->overruns, (unsigned int __user *) arg);
+               break;
+
+       case IOCTL_DAB_VERSION:
+               ret = put_user (version, (unsigned int __user *) arg);
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+       mutex_unlock(&s->mutex);
+       return ret;
+}
+
+static struct file_operations dabusb_fops =
+{
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+       .read =         dabusb_read,
+       .ioctl =        dabusb_ioctl,
+       .open =         dabusb_open,
+       .release =      dabusb_release,
+};
+
+static struct usb_class_driver dabusb_class = {
+       .name =         "dabusb%d",
+       .fops =         &dabusb_fops,
+       .minor_base =   DABUSB_MINOR,
+};
+
+
+/* --------------------------------------------------------------------- */
+static int dabusb_probe (struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+       int retval;
+       pdabusb_t s;
+
+       dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+           le16_to_cpu(usbdev->descriptor.idVendor),
+           le16_to_cpu(usbdev->descriptor.idProduct),
+           intf->altsetting->desc.bInterfaceNumber);
+
+       /* We don't handle multiple configurations */
+       if (usbdev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF &&
+           le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999)
+               return -ENODEV;
+
+
+
+       s = &dabusb[intf->minor];
+
+       mutex_lock(&s->mutex);
+       s->remove_pending = 0;
+       s->usbdev = usbdev;
+       s->devnum = intf->minor;
+
+       if (usb_reset_configuration (usbdev) < 0) {
+               err("reset_configuration failed");
+               goto reject;
+       }
+       if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
+               dabusb_loadmem (s, NULL);
+               goto reject;
+       }
+       else {
+               dabusb_fpga_download (s, NULL);
+
+               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
+                       err("set_interface failed");
+                       goto reject;
+               }
+       }
+       dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
+       usb_set_intfdata (intf, s);
+       mutex_unlock(&s->mutex);
+
+       retval = usb_register_dev(intf, &dabusb_class);
+       if (retval) {
+               usb_set_intfdata (intf, NULL);
+               return -ENOMEM;
+       }
+
+       return 0;
+
+      reject:
+       mutex_unlock(&s->mutex);
+       s->usbdev = NULL;
+       return -ENODEV;
+}
+
+static void dabusb_disconnect (struct usb_interface *intf)
+{
+       wait_queue_t __wait;
+       pdabusb_t s = usb_get_intfdata (intf);
+
+       dbg("dabusb_disconnect");
+       
+       init_waitqueue_entry(&__wait, current);
+       
+       usb_set_intfdata (intf, NULL);
+       if (s) {
+               usb_deregister_dev (intf, &dabusb_class);
+               s->remove_pending = 1;
+               wake_up (&s->wait);
+               add_wait_queue(&s->remove_ok, &__wait);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (s->state == _started)
+                       schedule();
+               current->state = TASK_RUNNING;
+               remove_wait_queue(&s->remove_ok, &__wait);
+               
+               s->usbdev = NULL;
+               s->overruns = 0;
+       }
+}
+
+static struct usb_device_id dabusb_ids [] = {
+       // { USB_DEVICE(0x0547, 0x2131) },      /* An2131 chip, no boot ROM */
+       { USB_DEVICE(0x0547, 0x9999) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, dabusb_ids);
+
+static struct usb_driver dabusb_driver = {
+       .name =         "dabusb",
+       .probe =        dabusb_probe,
+       .disconnect =   dabusb_disconnect,
+       .id_table =     dabusb_ids,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int __init dabusb_init (void)
+{
+       int retval;
+       unsigned u;
+
+       /* initialize struct */
+       for (u = 0; u < NRDABUSB; u++) {
+               pdabusb_t s = &dabusb[u];
+               memset (s, 0, sizeof (dabusb_t));
+               mutex_init (&s->mutex);
+               s->usbdev = NULL;
+               s->total_buffer_size = buffers;
+               init_waitqueue_head (&s->wait);
+               init_waitqueue_head (&s->remove_ok);
+               spin_lock_init (&s->lock);
+               INIT_LIST_HEAD (&s->free_buff_list);
+               INIT_LIST_HEAD (&s->rec_buff_list);
+       }
+
+       /* register misc device */
+       retval = usb_register(&dabusb_driver);
+       if (retval)
+               goto out;
+
+       dbg("dabusb_init: driver registered");
+
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+
+out:
+       return retval;
+}
+
+static void __exit dabusb_cleanup (void)
+{
+       dbg("dabusb_cleanup");
+
+       usb_deregister (&dabusb_driver);
+}
+
+/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(buffers, int, 0);
+MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
+
+module_init (dabusb_init);
+module_exit (dabusb_cleanup);
+
+/* --------------------------------------------------------------------- */
diff --git a/drivers/media/video/dabusb.h b/drivers/media/video/dabusb.h
new file mode 100644 (file)
index 0000000..96b03e4
--- /dev/null
@@ -0,0 +1,85 @@
+#define _BULK_DATA_LEN 64
+typedef struct
+{
+       unsigned char data[_BULK_DATA_LEN];
+       unsigned int size;
+       unsigned int pipe;
+}bulk_transfer_t,*pbulk_transfer_t;
+
+#define DABUSB_MINOR 240               /* some unassigned USB minor */
+#define DABUSB_VERSION 0x1000
+#define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
+#define IOCTL_DAB_OVERRUNS         _IOR('d',  0x15, int)
+#define IOCTL_DAB_VERSION           _IOR('d', 0x3f, int) 
+
+#ifdef __KERNEL__
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+       struct mutex mutex;
+       struct usb_device *usbdev;
+       wait_queue_head_t wait;
+       wait_queue_head_t remove_ok;
+       spinlock_t lock;
+       atomic_t pending_io;
+       driver_state_t state;
+       int remove_pending;
+       int got_mem;
+       int total_buffer_size;
+       unsigned int overruns;
+       int readptr;
+       int opened;
+       int devnum;
+       struct list_head free_buff_list;
+       struct list_head rec_buff_list;
+} dabusb_t,*pdabusb_t;
+
+typedef struct 
+{
+       pdabusb_t s;
+       struct urb *purb;
+       struct list_head buff_list;
+} buff_t,*pbuff_t;
+
+typedef struct
+{
+       wait_queue_head_t wait;
+} bulk_completion_context_t, *pbulk_completion_context_t;
+
+
+#define _DABUSB_IF 2
+#define _DABUSB_ISOPIPE 0x09
+#define _ISOPIPESIZE   16384
+
+#define _BULK_DATA_LEN 64
+// Vendor specific request code for Anchor Upload/Download
+// This one is implemented in the core
+#define ANCHOR_LOAD_INTERNAL  0xA0
+
+// EZ-USB Control and Status Register.  Bit 0 controls 8051 reset
+#define CPUCS_REG    0x7F92
+#define _TOTAL_BUFFERS 384
+
+#define MAX_INTEL_HEX_RECORD_LENGTH 16
+
+#ifndef _BYTE_DEFINED
+#define _BYTE_DEFINED
+typedef unsigned char BYTE;
+#endif // !_BYTE_DEFINED
+
+#ifndef _WORD_DEFINED
+#define _WORD_DEFINED
+typedef unsigned short WORD;
+#endif // !_WORD_DEFINED
+
+typedef struct _INTEL_HEX_RECORD
+{
+   BYTE  Length;
+   WORD  Address;
+   BYTE  Type;
+   BYTE  Data[MAX_INTEL_HEX_RECORD_LENGTH];
+} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
+
+#endif
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/video/dsbr100.c
new file mode 100644 (file)
index 0000000..2564680
--- /dev/null
@@ -0,0 +1,429 @@
+/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
+ into both the USB and an analog audio input, so this thing
+ only deals with initialisation and frequency setting, the
+ audio data has to be handled by a sound driver.
+
+ Major issue: I can't find out where the device reports the signal
+ strength, and indeed the windows software appearantly just looks
+ at the stereo indicator as well.  So, scanning will only find
+ stereo stations.  Sad, but I can't help it.
+
+ Also, the windows program sends oodles of messages over to the
+ device, and I couldn't figure out their meaning.  My suspicion
+ is that they don't have any:-)
+
+ You might find some interesting stuff about this module at
+ http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
+
+ Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ History:
+
+ Version 0.40:
+  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+
+ Version 0.30:
+       Markus: Updates for 2.5.x kernel and more ISO compliant source
+
+ Version 0.25:
+        PSL and Markus: Cleanup, radio now doesn't stop on device close
+
+ Version 0.24:
+       Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
+       right.  Some minor cleanup, improved standalone compilation
+
+ Version 0.23:
+       Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
+
+ Version 0.22:
+       Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, 
+       thanks to Mike Cox for pointing the problem out.
+
+ Version 0.21:
+       Markus: Minor cleanup, warnings if something goes wrong, lame attempt
+       to adhere to Documentation/CodingStyle
+
+ Version 0.2: 
+       Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
+       Markus: Copyright clarification
+
+ Version 0.01: Markus: initial release
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.40"
+#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
+#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
+
+#define DSB100_VENDOR 0x04b4
+#define DSB100_PRODUCT 0x1002
+
+/* Commands the device appears to understand */
+#define DSB100_TUNE 1
+#define DSB100_ONOFF 2
+
+#define TB_LEN 16
+
+/* Frequency limits in MHz -- these are European values.  For Japanese
+devices, that would be 76 and 91.  */
+#define FREQ_MIN  87.5
+#define FREQ_MAX 108.0
+#define FREQ_MUL 16000
+
+
+static int usb_dsbr100_probe(struct usb_interface *intf,
+                            const struct usb_device_id *id);
+static void usb_dsbr100_disconnect(struct usb_interface *intf);
+static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg);
+static int usb_dsbr100_open(struct inode *inode, struct file *file);
+static int usb_dsbr100_close(struct inode *inode, struct file *file);
+
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+
+/* Data for one (physical) device */
+typedef struct {
+       struct usb_device *usbdev;
+       struct video_device *videodev;
+       unsigned char transfer_buffer[TB_LEN];
+       int curfreq;
+       int stereo;
+       int users;
+       int removed;
+} dsbr100_device;
+
+
+/* File system interface */
+static struct file_operations usb_dsbr100_fops = {
+       .owner =        THIS_MODULE,
+       .open =         usb_dsbr100_open,
+       .release =      usb_dsbr100_close,
+       .ioctl =        usb_dsbr100_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+
+/* V4L interface */
+static struct video_device dsbr100_videodev_template=
+{
+       .owner =        THIS_MODULE,
+       .name =         "D-Link DSB-R 100",
+       .type =         VID_TYPE_TUNER,
+       .hardware =     VID_HARDWARE_AZTECH,
+       .fops =         &usb_dsbr100_fops,
+       .release = video_device_release,
+};
+
+static struct usb_device_id usb_dsbr100_device_table [] = {
+       { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_dsbr100_driver = {
+       .name =         "dsbr100",
+       .probe =        usb_dsbr100_probe,
+       .disconnect =   usb_dsbr100_disconnect,
+       .id_table =     usb_dsbr100_device_table,
+};
+
+/* Low-level device interface begins here */
+
+/* switch on radio */
+static int dsbr100_start(dsbr100_device *radio)
+{
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
+       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       DSB100_ONOFF, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+               return -1;
+       return (radio->transfer_buffer)[0];
+}
+
+
+/* switch off radio */
+static int dsbr100_stop(dsbr100_device *radio)
+{
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
+       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       DSB100_ONOFF, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+               return -1;
+       return (radio->transfer_buffer)[0];
+}
+
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int dsbr100_setfreq(dsbr100_device *radio, int freq)
+{
+       freq = (freq/16*80)/1000+856;
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       DSB100_TUNE, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       (freq>>8)&0x00ff, freq&0xff, 
+                       radio->transfer_buffer, 8, 300)<0 ||
+          usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                       0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
+       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       USB_REQ_GET_STATUS, 
+                       USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
+                       0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
+               radio->stereo = -1;
+               return -1;
+       }
+       radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
+       return (radio->transfer_buffer)[0];
+}
+
+/* return the device status.  This is, in effect, just whether it
+sees a stereo signal or not.  Pity. */
+static void dsbr100_getstat(dsbr100_device *radio)
+{
+       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+               USB_REQ_GET_STATUS, 
+               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+               0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
+               radio->stereo = -1;
+       else
+               radio->stereo = ! (radio->transfer_buffer[0]&0x01);
+}
+
+
+/* USB subsystem interface begins here */
+
+/* check if the device is present and register with v4l and
+usb if it is */
+static int usb_dsbr100_probe(struct usb_interface *intf, 
+                        const struct usb_device_id *id)
+{
+       dsbr100_device *radio;
+
+       if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
+               return -ENOMEM;
+       if (!(radio->videodev = video_device_alloc())) {
+               kfree(radio);
+               return -ENOMEM;
+       }
+       memcpy(radio->videodev, &dsbr100_videodev_template, 
+               sizeof(dsbr100_videodev_template));
+       radio->removed = 0;
+       radio->users = 0;
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->curfreq = FREQ_MIN*FREQ_MUL;
+       video_set_drvdata(radio->videodev, radio);
+       if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
+               radio_nr)) {
+               warn("Could not register video device");
+               video_device_release(radio->videodev);
+               kfree(radio);
+               return -EIO;
+       }
+       usb_set_intfdata(intf, radio);
+       return 0;
+}
+
+/* handle unplugging of the device, release data structures
+if nothing keeps us from doing it.  If something is still
+keeping us busy, the release callback of v4l will take care
+of releasing it.  stv680.c does not relase its private
+data, so I don't do this here either.  Checking out the
+code I'd expect I better did that, but if there's a memory
+leak here it's tiny (~50 bytes per disconnect) */
+static void usb_dsbr100_disconnect(struct usb_interface *intf)
+{
+       dsbr100_device *radio = usb_get_intfdata(intf);
+
+       usb_set_intfdata (intf, NULL);
+       if (radio) {
+               video_unregister_device(radio->videodev);
+               radio->videodev = NULL;
+               if (radio->users) {
+                       kfree(radio);
+               } else {
+                       radio->removed = 1;
+               }
+       }
+}
+
+
+/* Video for Linux interface */
+
+static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
+                               unsigned int cmd, void *arg)
+{
+       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+       if (!radio)
+               return -EIO;
+
+       switch(cmd) {
+               case VIDIOCGCAP: {
+                       struct video_capability *v = arg;
+
+                       memset(v, 0, sizeof(*v));
+                       v->type = VID_TYPE_TUNER;
+                       v->channels = 1;
+                       v->audios = 1;
+                       strcpy(v->name, "D-Link R-100 USB FM Radio");
+                       return 0;
+               }
+               case VIDIOCGTUNER: {
+                       struct video_tuner *v = arg;
+
+                       dsbr100_getstat(radio);
+                       if(v->tuner)    /* Only 1 tuner */ 
+                               return -EINVAL;
+                       v->rangelow = FREQ_MIN*FREQ_MUL;
+                       v->rangehigh = FREQ_MAX*FREQ_MUL;
+                       v->flags = VIDEO_TUNER_LOW;
+                       v->mode = VIDEO_MODE_AUTO;
+                       v->signal = radio->stereo*0x7000;
+                               /* Don't know how to get signal strength */
+                       v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+                       strcpy(v->name, "DSB R-100");
+                       return 0;
+               }
+               case VIDIOCSTUNER: {
+                       struct video_tuner *v = arg;
+
+                       if(v->tuner!=0)
+                               return -EINVAL;
+                       /* Only 1 tuner so no setting needed ! */
+                       return 0;
+               }
+               case VIDIOCGFREQ: {
+                       int *freq = arg;
+
+                       if (radio->curfreq==-1)
+                               return -EINVAL;
+                       *freq = radio->curfreq;
+                       return 0;
+               }
+               case VIDIOCSFREQ: {
+                       int *freq = arg;
+
+                       radio->curfreq = *freq;
+                       if (dsbr100_setfreq(radio, radio->curfreq)==-1)
+                               warn("Set frequency failed");
+                       return 0;
+               }
+               case VIDIOCGAUDIO: {
+                       struct video_audio *v = arg;
+
+                       memset(v, 0, sizeof(*v));
+                       v->flags |= VIDEO_AUDIO_MUTABLE;
+                       v->mode = VIDEO_SOUND_STEREO;
+                       v->volume = 1;
+                       v->step = 1;
+                       strcpy(v->name, "Radio");
+                       return 0;                       
+               }
+               case VIDIOCSAUDIO: {
+                       struct video_audio *v = arg;
+
+                       if (v->audio) 
+                               return -EINVAL;
+                       if (v->flags&VIDEO_AUDIO_MUTE) {
+                               if (dsbr100_stop(radio)==-1)
+                                       warn("Radio did not respond properly");
+                       }
+                       else
+                               if (dsbr100_start(radio)==-1)
+                                       warn("Radio did not respond properly");
+                       return 0;
+               }
+               default:
+                       return -ENOIOCTLCMD;
+       }
+}
+
+static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
+}
+
+static int usb_dsbr100_open(struct inode *inode, struct file *file)
+{
+       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+       radio->users = 1;
+       if (dsbr100_start(radio)<0) {
+               warn("Radio did not start up properly");
+               radio->users = 0;
+               return -EIO;
+       }
+       dsbr100_setfreq(radio, radio->curfreq);
+       return 0;
+}
+
+static int usb_dsbr100_close(struct inode *inode, struct file *file)
+{
+       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+
+       if (!radio)
+               return -ENODEV;
+       radio->users = 0;
+       if (radio->removed) {
+               kfree(radio);
+       }
+       return 0;
+}
+
+static int __init dsbr100_init(void)
+{
+       int retval = usb_register(&usb_dsbr100_driver);
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+       return retval;
+}
+
+static void __exit dsbr100_exit(void)
+{
+       usb_deregister(&usb_dsbr100_driver);
+}
+
+module_init (dsbr100_init);
+module_exit (dsbr100_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/et61x251/Makefile b/drivers/media/video/et61x251/Makefile
new file mode 100644 (file)
index 0000000..2ff4db9
--- /dev/null
@@ -0,0 +1,4 @@
+et61x251-objs   := et61x251_core.o et61x251_tas5130d1b.o
+
+obj-$(CONFIG_USB_ET61X251)      += et61x251.o
+
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
new file mode 100644 (file)
index 0000000..eee8afc
--- /dev/null
@@ -0,0 +1,234 @@
+/***************************************************************************
+ * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ET61X251_H_
+#define _ET61X251_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include "et61x251_sensor.h"
+
+/*****************************************************************************/
+
+#define ET61X251_DEBUG
+#define ET61X251_DEBUG_LEVEL         2
+#define ET61X251_MAX_DEVICES         64
+#define ET61X251_PRESERVE_IMGSCALE   0
+#define ET61X251_FORCE_MUNMAP        0
+#define ET61X251_MAX_FRAMES          32
+#define ET61X251_COMPRESSION_QUALITY 0
+#define ET61X251_URBS                2
+#define ET61X251_ISO_PACKETS         7
+#define ET61X251_ALTERNATE_SETTING   13
+#define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
+#define ET61X251_CTRL_TIMEOUT        100
+#define ET61X251_FRAME_TIMEOUT       2
+
+/*****************************************************************************/
+
+static const struct usb_device_id et61x251_id_table[] = {
+       { USB_DEVICE(0x102c, 0x6151), },
+       { USB_DEVICE(0x102c, 0x6251), },
+       { USB_DEVICE(0x102c, 0x6253), },
+       { USB_DEVICE(0x102c, 0x6254), },
+       { USB_DEVICE(0x102c, 0x6255), },
+       { USB_DEVICE(0x102c, 0x6256), },
+       { USB_DEVICE(0x102c, 0x6257), },
+       { USB_DEVICE(0x102c, 0x6258), },
+       { USB_DEVICE(0x102c, 0x6259), },
+       { USB_DEVICE(0x102c, 0x625a), },
+       { USB_DEVICE(0x102c, 0x625b), },
+       { USB_DEVICE(0x102c, 0x625c), },
+       { USB_DEVICE(0x102c, 0x625d), },
+       { USB_DEVICE(0x102c, 0x625e), },
+       { USB_DEVICE(0x102c, 0x625f), },
+       { USB_DEVICE(0x102c, 0x6260), },
+       { USB_DEVICE(0x102c, 0x6261), },
+       { USB_DEVICE(0x102c, 0x6262), },
+       { USB_DEVICE(0x102c, 0x6263), },
+       { USB_DEVICE(0x102c, 0x6264), },
+       { USB_DEVICE(0x102c, 0x6265), },
+       { USB_DEVICE(0x102c, 0x6266), },
+       { USB_DEVICE(0x102c, 0x6267), },
+       { USB_DEVICE(0x102c, 0x6268), },
+       { USB_DEVICE(0x102c, 0x6269), },
+       { }
+};
+
+ET61X251_SENSOR_TABLE
+
+/*****************************************************************************/
+
+enum et61x251_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct et61x251_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum et61x251_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum et61x251_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum et61x251_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum et61x251_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+struct et61x251_sysfs_attr {
+       u8 reg, i2c_reg;
+};
+
+struct et61x251_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DEFINE_MUTEX(et61x251_sysfs_lock);
+static DECLARE_RWSEM(et61x251_disconnect);
+
+struct et61x251_device {
+       struct video_device* v4ldev;
+
+       struct et61x251_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[ET61X251_URBS];
+       void* transfer_buffer[ET61X251_URBS];
+       u8* control_buffer;
+
+       struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum et61x251_io_method io;
+       enum et61x251_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct et61x251_sysfs_attr sysfs;
+       struct et61x251_module_param module_param;
+
+       enum et61x251_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
+{
+       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+               return cam;
+
+       return NULL;
+}
+
+
+void
+et61x251_attach_sensor(struct et61x251_device* cam,
+                       struct et61x251_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ET61X251_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("et61x251: " fmt "\n", ## args);              \
+               else if ((level) == 3)                                        \
+                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ET61X251_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
new file mode 100644 (file)
index 0000000..7cc01b8
--- /dev/null
@@ -0,0 +1,2630 @@
+/***************************************************************************
+ * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "et61x251.h"
+
+/*****************************************************************************/
+
+#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
+                                "PC Camera Controllers"
+#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ET61X251_MODULE_LICENSE "GPL"
+#define ET61X251_MODULE_VERSION "1:1.02"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, et61x251_id_table);
+
+MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
+MODULE_VERSION(ET61X251_MODULE_VERSION);
+MODULE_LICENSE(ET61X251_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "
+                 __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second registered camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+
+static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                               ET61X251_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
+                 "\ndetected camera."
+                 "\n 0 = do not force memory unmapping"
+                 "\n 1 = force memory unmapping (save memory)"
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                 "\n");
+
+static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
+                                       ET61X251_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "
+                 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
+                 "\n");
+
+#ifdef ET61X251_DEBUG
+static unsigned short debug = ET61X251_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 3:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = more verbose messages"
+                 "\nLevel 3 is useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
+                 "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+et61x251_request_buffers(struct et61x251_device* cam, u32 count,
+                         enum et61x251_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > ET61X251_MAX_FRAMES)
+               count = ET61X251_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void et61x251_release_buffers(struct et61x251_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void et61x251_empty_framequeues(struct et61x251_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void et61x251_requeue_outqueue(struct et61x251_device* cam)
+{
+       struct et61x251_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void et61x251_queue_unusedframes(struct et61x251_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       *buff = value;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (value 0x%02X, index "
+                      "0x%02X, error %d)", value, index, res);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int et61x251_read_reg(struct et61x251_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
+                   index, res);
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+static int
+et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+{
+       int i, r;
+
+       for (i = 1; i <= 8; i++) {
+               if (sensor->interface == ET61X251_I2C_3WIRES) {
+                       r = et61x251_read_reg(cam, 0x8e);
+                       if (!(r & 0x02) && (r >= 0))
+                               return 0;
+               } else {
+                       r = et61x251_read_reg(cam, 0x8b);
+                       if (!(r & 0x01) && (r >= 0))
+                               return 0;
+               }
+               if (r < 0)
+                       return -EIO;
+               udelay(8*8); /* minimum for sensors at 400kHz */
+       }
+
+       return -EBUSY;
+}
+
+
+int
+et61x251_i2c_try_read(struct et61x251_device* cam,
+                      struct et61x251_sensor* sensor, u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x10;
+       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+
+       return err ? -1 : (int)data[0];
+}
+
+
+int
+et61x251_i2c_try_write(struct et61x251_device* cam,
+                       struct et61x251_sensor* sensor, u8 address, u8 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x12;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = value;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, sensor);
+
+       if (err)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+
+       return err ? -1 : 0;
+}
+
+
+int
+et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
+                       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
+                       u8 data8, u8 address)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       data[0] = data2;
+       data[1] = data3;
+       data[2] = data4;
+       data[3] = data5;
+       data[4] = data6;
+       data[5] = data7;
+       data[6] = data8;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       data[0] = address;
+       data[1] = cam->sensor.i2c_slave_id;
+       data[2] = cam->sensor.rsta | 0x02 | (n << 4);
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       /* Start writing through the serial interface */
+       data[0] = data1;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += et61x251_i2c_wait(cam, &cam->sensor);
+
+       if (err)
+               DBG(3, "I2C raw write failed for %s image sensor",
+                   cam->sensor.name);
+
+       PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
+             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
+             " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
+             data1, data2, data3, data4, data5, data6, data7, data8);
+
+       return err ? -1 : 0;
+
+}
+
+
+int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
+{
+       return et61x251_i2c_try_read(cam, &cam->sensor, address);
+}
+
+
+int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
+{
+       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
+}
+
+/*****************************************************************************/
+
+static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct et61x251_device* cam = urb->context;
+       struct et61x251_frame_t** f;
+       size_t imagesize;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int len, status;
+               void *pos;
+               u8* b1, * b2, sof;
+               const u8 VOID_BYTES = 6;
+               size_t imglen;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               b1 = pos++;
+               b2 = pos++;
+               sof = ((*b1 & 0x3f) == 63);
+               imglen = ((*b1 & 0xc0) << 2) | *b2;
+
+               PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
+                     len, i, imglen);
+
+               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+                       if (sof) {
+                               (*f)->state = F_GRABBING;
+                               (*f)->buf.bytesused = 0;
+                               do_gettimeofday(&(*f)->buf.timestamp);
+                               pos += 22;
+                               DBG(3, "SOF detected: new video frame");
+                       }
+
+               if ((*f)->state == F_GRABBING) {
+                       if (sof && (*f)->buf.bytesused) {
+                               if (cam->sensor.pix_format.pixelformat ==
+                                                        V4L2_PIX_FMT_ET61X251)
+                                       goto end_of_frame;
+                               else {
+                                       DBG(3, "Not expected SOF detected "
+                                              "after %lu bytes",
+                                          (unsigned long)(*f)->buf.bytesused);
+                                       (*f)->state = F_ERROR;
+                                       continue;
+                               }
+                       }
+
+                       if ((*f)->buf.bytesused + imglen > imagesize) {
+                               DBG(3, "Video frame size exceeded");
+                               (*f)->state = F_ERROR;
+                               continue;
+                       }
+
+                       pos += VOID_BYTES;
+
+                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
+                       (*f)->buf.bytesused += imglen;
+
+                       if ((*f)->buf.bytesused == imagesize) {
+                               u32 b;
+end_of_frame:
+                               b = (*f)->buf.bytesused;
+                               (*f)->state = F_DONE;
+                               (*f)->buf.sequence= ++cam->frame_count;
+                               spin_lock(&cam->queue_lock);
+                               list_move_tail(&(*f)->frame, &cam->outqueue);
+                               if (!list_empty(&cam->inqueue))
+                                       (*f) = list_entry(cam->inqueue.next,
+                                                      struct et61x251_frame_t,
+                                                         frame);
+                               else
+                                       (*f) = NULL;
+                               spin_unlock(&cam->queue_lock);
+                               DBG(3, "Video frame captured: : %lu bytes",
+                                      (unsigned long)(b));
+
+                               if (!(*f))
+                                       goto resubmit_urb;
+
+                               if (sof &&
+                                   cam->sensor.pix_format.pixelformat ==
+                                                        V4L2_PIX_FMT_ET61X251)
+                                       goto start_of_frame;
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int et61x251_start_transfer(struct et61x251_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
+                                              864, 896, 920, 956, 980, 1000,
+                                              1022};
+       const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = ET61X251_ISO_PACKETS;
+               urb->complete = et61x251_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       err = et61x251_write_reg(cam, 0x01, 0x03);
+       err = et61x251_write_reg(cam, 0x00, 0x03);
+       err = et61x251_write_reg(cam, 0x08, 0x03);
+       if (err) {
+               err = -EIO;
+               DBG(1, "I/O hardware error");
+               goto free_urbs;
+       }
+
+       err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < ET61X251_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int et61x251_stop_transfer(struct et61x251_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = ET61X251_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int et61x251_stream_interrupt(struct et61x251_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    ET61X251_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. To "
+                      "use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
+{
+       char str[5];
+       char* endp;
+       unsigned long val;
+
+       if (len < 4) {
+               strncpy(str, buff, len);
+               str[len+1] = '\0';
+       } else {
+               strncpy(str, buff, 4);
+               str[4] = '\0';
+       }
+
+       val = simple_strtoul(str, &endp, 0);
+
+       *count = 0;
+       if (val <= 0xff)
+               *count = (ssize_t)(endp - str);
+       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
+               *count += 1;
+
+       return (u8)val;
+}
+
+/*
+   NOTE 1: being inside one of the following methods implies that the v4l
+           device exists for sure (see kobjects and reference counters)
+   NOTE 2: buffers are PAGE_SIZE long
+*/
+
+static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.reg);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = et61x251_strtou8(buf, len, &count);
+       if (index > 0x8e || !count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.reg = index;
+
+       DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       value = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = et61x251_write_reg(cam, value, cam->sysfs.reg);
+       if (err) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.i2c_reg = index;
+
+       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
+{
+       struct et61x251_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct et61x251_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       value = et61x251_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
+       if (err) {
+               mutex_unlock(&et61x251_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.i2c_reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       return count;
+}
+
+
+static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+                         et61x251_show_reg, et61x251_store_reg);
+static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+                         et61x251_show_val, et61x251_store_val);
+static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+                         et61x251_show_i2c_reg, et61x251_store_i2c_reg);
+static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+                         et61x251_show_i2c_val, et61x251_store_i2c_val);
+
+
+static void et61x251_create_sysfs(struct et61x251_device* cam)
+{
+       struct video_device *v4ldev = cam->v4ldev;
+
+       video_device_create_file(v4ldev, &class_device_attr_reg);
+       video_device_create_file(v4ldev, &class_device_attr_val);
+       if (cam->sensor.sysfs_ops) {
+               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+       }
+}
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+/*****************************************************************************/
+
+static int
+et61x251_set_pix_format(struct et61x251_device* cam,
+                        struct v4l2_pix_format* pix)
+{
+       int r, err = 0;
+
+       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
+               err += r;
+       if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
+               err += et61x251_write_reg(cam, r & 0xfd, 0x12);
+       else
+               err += et61x251_write_reg(cam, r | 0x02, 0x12);
+
+       return err ? -EIO : 0;
+}
+
+
+static int
+et61x251_set_compression(struct et61x251_device* cam,
+                         struct v4l2_jpegcompression* compression)
+{
+       int r, err = 0;
+
+       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
+               err += r;
+       if (compression->quality == 0)
+               err += et61x251_write_reg(cam, r & 0xfb, 0x12);
+       else
+               err += et61x251_write_reg(cam, r | 0x04, 0x12);
+
+       return err ? -EIO : 0;
+}
+
+
+static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
+{
+       int r = 0, err = 0;
+
+       r = et61x251_read_reg(cam, 0x12);
+       if (r < 0)
+               err += r;
+
+       if (scale == 1)
+               err += et61x251_write_reg(cam, r & ~0x01, 0x12);
+       else if (scale == 2)
+               err += et61x251_write_reg(cam, r | 0x01, 0x12);
+
+       if (err)
+               return -EIO;
+
+       PDBGG("Scaling factor: %u", scale);
+
+       return 0;
+}
+
+
+static int
+et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
+                          s->active_pixel.left),
+           fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
+                          s->active_pixel.top),
+           fmw_length = (u16)(rect->width),
+           fmw_height = (u16)(rect->height);
+       int err = 0;
+
+       err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
+       err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
+       err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
+       err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
+       err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
+                                      | ((fmw_length & 0x300) >> 4)
+                                      | ((fmw_height & 0x300) >> 2), 0x6d);
+       if (err)
+               return -EIO;
+
+       PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
+             fmw_sx, fmw_sy, fmw_length, fmw_height);
+
+       return 0;
+}
+
+
+static int et61x251_init(struct et61x251_device* cam)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+               cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
+       err += et61x251_set_crop(cam, rect);
+       if (err)
+               return err;
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       err += et61x251_set_compression(cam, &cam->compression);
+       err += et61x251_set_pix_format(cam, &s->pix_format);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, &s->pix_format);
+       if (err)
+               return err;
+
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
+               DBG(3, "Compressed video format is active, quality %d",
+                   cam->compression.quality);
+       else
+               DBG(3, "Uncompressed video format is active");
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void et61x251_release_resources(struct et61x251_device* cam)
+{
+       mutex_lock(&et61x251_sysfs_lock);
+
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+
+       usb_put_dev(cam->usbdev);
+
+       mutex_unlock(&et61x251_sysfs_lock);
+
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int et61x251_open(struct inode* inode, struct file* filp)
+{
+       struct et61x251_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&et61x251_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&et61x251_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&et61x251_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&et61x251_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = et61x251_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = et61x251_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       et61x251_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&et61x251_disconnect);
+       return err;
+}
+
+
+static int et61x251_release(struct inode* inode, struct file* filp)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       et61x251_stop_transfer(cam);
+
+       et61x251_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               et61x251_release_resources(cam);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+et61x251_read(struct file* filp, char __user * buf,
+              size_t count, loff_t* f_pos)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose the read "
+                      "method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
+                                             IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       et61x251_empty_framequeues(cam);
+               et61x251_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       et61x251_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err ? err : count;
+}
+
+
+static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       struct et61x251_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
+                                             IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               et61x251_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void et61x251_vm_open(struct vm_area_struct* vma)
+{
+       struct et61x251_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void et61x251_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct et61x251_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct et61x251_vm_ops = {
+       .open = et61x251_vm_open,
+       .close = et61x251_vm_close,
+};
+
+
+static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &et61x251_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       et61x251_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "et61x251",
+               .version = ET61X251_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_pix_format* pix_format = &(s->pix_format);
+       u8 scale;
+       const enum et61x251_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       /* Preserve R,G or B origin */
+       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+       if (rect->width < 4)
+               rect->width = 4;
+       if (rect->height < 4)
+               rect->height = 4;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+
+       rect->width &= ~3L;
+       rect->height &= ~3L;
+
+       if (ET61X251_PRESERVE_IMGSCALE) {
+               /* Calculate the actual scaling factor */
+               u32 a, b;
+               a = rect->width * rect->height;
+               b = pix_format->width * pix_format->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       } else
+               scale = 1;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               et61x251_release_buffers(cam);
+
+       err = et61x251_set_crop(cam, rect);
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+       err += et61x251_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width/scale;
+       s->pix_format.height = rect->height/scale;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               et61x251_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               et61x251_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+       } else if (fmtd.index == 1) {
+               strcpy(fmtd.description, "compressed");
+               fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
+                          void __user * arg)
+{
+       struct et61x251_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       u8 scale;
+       const enum et61x251_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       { /* calculate the actual scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       }
+
+       rect.width = scale * pix->width;
+       rect.height = scale * pix->height;
+
+       if (rect.width < 4)
+               rect.width = 4;
+       if (rect.height < 4)
+               rect.height = 4;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+
+       rect.width &= ~3L;
+       rect.height &= ~3L;
+
+       { /* adjust the scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
+       }
+
+       pix->width = rect.width / scale;
+       pix->height = rect.height / scale;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
+           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+               pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
+                           ? 0 : (pix->width * pix->priv) / 8;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               et61x251_release_buffers(cam);
+
+       err += et61x251_set_pix_format(cam, pix);
+       err += et61x251_set_crop(cam, &rect);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, pix);
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+       err += et61x251_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               et61x251_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               et61x251_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression,
+                        sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum et61x251_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0 && jc.quality != 1)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       err += et61x251_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. "
+                              "Previous buffers are still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       et61x251_empty_framequeues(cam);
+
+       et61x251_release_buffers(cam);
+       if (rb.count)
+               rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               et61x251_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
+                      void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct et61x251_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = et61x251_stream_interrupt(cam)))
+                       return err;
+
+       et61x251_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
+               sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
+                               unsigned int cmd, void __user * arg)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return et61x251_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return et61x251_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return et61x251_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return et61x251_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return et61x251_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return et61x251_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return et61x251_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return et61x251_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return et61x251_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return et61x251_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return et61x251_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return et61x251_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return et61x251_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return et61x251_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return et61x251_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return et61x251_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return et61x251_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return et61x251_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return et61x251_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return et61x251_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return et61x251_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return et61x251_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int et61x251_ioctl(struct inode* inode, struct file* filp,
+                         unsigned int cmd, unsigned long arg)
+{
+       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "et61x251", cmd);
+
+       err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+
+static struct file_operations et61x251_fops = {
+       .owner = THIS_MODULE,
+       .open =    et61x251_open,
+       .release = et61x251_release,
+       .ioctl =   et61x251_ioctl,
+       .read =    et61x251_read,
+       .poll =    et61x251_poll,
+       .mmap =    et61x251_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+/* It exists a single interface only. We do not need to validate anything. */
+static int
+et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct et61x251_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0;
+
+       if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       DBG(2, "ET61X[12]51 PC Camera Controller detected "
+              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+       for  (i = 0; et61x251_sensor_table[i]; i++) {
+               err = et61x251_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err)
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+       else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (et61x251_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &et61x251_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       et61x251_create_sysfs(cam);
+       DBG(2, "Optional device control through 'sysfs' interface ready");
+#endif
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void et61x251_usb_disconnect(struct usb_interface* intf)
+{
+       struct et61x251_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&et61x251_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               et61x251_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               et61x251_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&et61x251_disconnect);
+}
+
+
+static struct usb_driver et61x251_usb_driver = {
+       .name =       "et61x251",
+       .id_table =   et61x251_id_table,
+       .probe =      et61x251_usb_probe,
+       .disconnect = et61x251_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init et61x251_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION);
+       KDBG(3, ET61X251_MODULE_AUTHOR);
+
+       if ((err = usb_register(&et61x251_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit et61x251_module_exit(void)
+{
+       usb_deregister(&et61x251_usb_driver);
+}
+
+
+module_init(et61x251_module_init);
+module_exit(et61x251_module_exit);
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
new file mode 100644 (file)
index 0000000..56841ae
--- /dev/null
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ET61X251_SENSOR_H_
+#define _ET61X251_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct et61x251_device;
+struct et61x251_sensor;
+
+/*****************************************************************************/
+
+extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
+
+#define ET61X251_SENSOR_TABLE                                                 \
+/* Weak detections must go at the end of the list */                          \
+static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
+       &et61x251_probe_tas5130d1b,                                           \
+       NULL,                                                                 \
+};
+
+extern struct et61x251_device*
+et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
+
+extern void
+et61x251_attach_sensor(struct et61x251_device* cam,
+                       struct et61x251_sensor* sensor);
+
+/*****************************************************************************/
+
+extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
+extern int et61x251_read_reg(struct et61x251_device*, u16 index);
+extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
+extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
+extern int et61x251_i2c_try_write(struct et61x251_device*,
+                                  struct et61x251_sensor*, u8 address,
+                                  u8 value);
+extern int et61x251_i2c_try_read(struct et61x251_device*,
+                                 struct et61x251_sensor*, u8 address);
+extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
+                                  u8 data2, u8 data3, u8 data4, u8 data5,
+                                  u8 data6, u8 data7, u8 data8, u8 address);
+
+/*****************************************************************************/
+
+enum et61x251_i2c_sysfs_ops {
+       ET61X251_I2C_READ = 0x01,
+       ET61X251_I2C_WRITE = 0x02,
+};
+
+enum et61x251_i2c_interface {
+       ET61X251_I2C_2WIRES,
+       ET61X251_I2C_3WIRES,
+};
+
+/* Repeat start condition when RSTA is high */
+enum et61x251_i2c_rsta {
+       ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
+       ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
+};
+
+#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+
+struct et61x251_sensor {
+       char name[32];
+
+       enum et61x251_i2c_sysfs_ops sysfs_ops;
+
+       enum et61x251_i2c_interface interface;
+       u8 i2c_slave_id;
+       enum et61x251_i2c_rsta rsta;
+       struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
+
+       struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
+       struct v4l2_cropcap cropcap;
+       struct v4l2_pix_format pix_format;
+
+       int (*init)(struct et61x251_device* cam);
+       int (*get_ctrl)(struct et61x251_device* cam,
+                       struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct et61x251_device* cam,
+                       const struct v4l2_control* ctrl);
+       int (*set_crop)(struct et61x251_device* cam,
+                       const struct v4l2_rect* rect);
+       int (*set_pix_format)(struct et61x251_device* cam,
+                             const struct v4l2_pix_format* pix);
+
+       /* Private */
+       struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
new file mode 100644 (file)
index 0000000..3998d76
--- /dev/null
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
+ * PC Camera Controllers                                                   *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "et61x251_sensor.h"
+
+
+static int tas5130d1b_init(struct et61x251_device* cam)
+{
+       int err = 0;
+
+       err += et61x251_write_reg(cam, 0x14, 0x01);
+       err += et61x251_write_reg(cam, 0x1b, 0x02);
+       err += et61x251_write_reg(cam, 0x02, 0x12);
+       err += et61x251_write_reg(cam, 0x0e, 0x60);
+       err += et61x251_write_reg(cam, 0x80, 0x61);
+       err += et61x251_write_reg(cam, 0xf0, 0x62);
+       err += et61x251_write_reg(cam, 0x03, 0x63);
+       err += et61x251_write_reg(cam, 0x14, 0x64);
+       err += et61x251_write_reg(cam, 0xf4, 0x65);
+       err += et61x251_write_reg(cam, 0x01, 0x66);
+       err += et61x251_write_reg(cam, 0x05, 0x67);
+       err += et61x251_write_reg(cam, 0x8f, 0x68);
+       err += et61x251_write_reg(cam, 0x0f, 0x8d);
+       err += et61x251_write_reg(cam, 0x08, 0x8e);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
+                               const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += et61x251_i2c_raw_write(cam, 2, 0x20,
+                                             0xf6-ctrl->value, 0, 0, 0,
+                                             0, 0, 0, 0);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err += et61x251_i2c_raw_write(cam, 2, 0x40,
+                                             0x47-ctrl->value, 0, 0, 0,
+                                             0, 0, 0, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static struct et61x251_sensor tas5130d1b = {
+       .name = "TAS5130D1B",
+       .interface = ET61X251_I2C_3WIRES,
+       .rsta = ET61X251_I2C_RSTA_STOP,
+       .active_pixel = {
+               .left = 106,
+               .top = 13,
+       },
+       .init = &tas5130d1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x02,
+                       .default_value = 0x0d,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x47,
+                       .step = 0x01,
+                       .default_value = 0x23,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5130d1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+};
+
+
+int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
+{
+       const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x102c, 0x6251), },
+               { }
+       };
+
+       /* Sensor detection is based on USB pid/vid */
+       if (!et61x251_match_id(cam, tas5130d1b_id_table))
+               return -ENODEV;
+
+       et61x251_attach_sensor(cam, &tas5130d1b);
+
+       return 0;
+}
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
new file mode 100644 (file)
index 0000000..da44579
--- /dev/null
@@ -0,0 +1,5932 @@
+/*
+ * OmniVision OV511 Camera-to-USB Bridge Driver
+ *
+ * Copyright (c) 1999-2003 Mark W. McClelland
+ * Original decompression code Copyright 1998-2000 OmniVision Technologies
+ * Many improvements by Bret Wallach <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
+ * Snapshot code by Kevin Moore
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka <claudio@conectiva.com>
+ * Original SAA7111A code by Dave Perks <dperks@ibm.net>
+ * URB error messages from pwc driver by Nemosoft
+ * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
+ * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
+ *
+ * Based on the Linux CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt.
+ * 
+ * Please see the file: Documentation/usb/ov511.txt
+ * and the website at:  http://alpha.dyndns.org/ov511
+ * for more info.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+
+#if defined (__i386__)
+       #include <asm/cpufeature.h>
+#endif
+
+#include "ov511.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.64 for Linux 2.5"
+#define EMAIL "mark@alpha.dyndns.org"
+#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
+       & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
+       <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
+#define DRIVER_DESC "ov511 USB Camera Driver"
+
+#define OV511_I2C_RETRIES 3
+#define ENABLE_Y_QUANTABLE 1
+#define ENABLE_UV_QUANTABLE 1
+
+#define OV511_MAX_UNIT_VIDEO 16
+
+/* Pixel count * bytes per YUV420 pixel (1.5) */
+#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
+
+#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
+
+/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
+#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
+
+#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
+
+/**********************************************************************
+ * Module Parameters
+ * (See ov511.txt for detailed descriptions of these)
+ **********************************************************************/
+
+/* These variables (and all static globals) default to zero */
+static int autobright          = 1;
+static int autogain            = 1;
+static int autoexp             = 1;
+static int debug;
+static int snapshot;
+static int cams                        = 1;
+static int compress;
+static int testpat;
+static int dumppix;
+static int led                         = 1;
+static int dump_bridge;
+static int dump_sensor;
+static int printph;
+static int phy                 = 0x1f;
+static int phuv                        = 0x05;
+static int pvy                 = 0x06;
+static int pvuv                        = 0x06;
+static int qhy                 = 0x14;
+static int qhuv                        = 0x03;
+static int qvy                 = 0x04;
+static int qvuv                        = 0x04;
+static int lightfreq;
+static int bandingfilter;
+static int clockdiv            = -1;
+static int packetsize          = -1;
+static int framedrop           = -1;
+static int fastset;
+static int force_palette;
+static int backlight;
+static int unit_video[OV511_MAX_UNIT_VIDEO];
+static int remove_zeros;
+static int mirror;
+static int ov518_color;
+
+module_param(autobright, int, 0);
+MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
+module_param(autogain, int, 0);
+MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
+module_param(autoexp, int, 0);
+MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug,
+  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
+module_param(snapshot, int, 0);
+MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
+module_param(cams, int, 0);
+MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
+module_param(compress, int, 0);
+MODULE_PARM_DESC(compress, "Turn on compression");
+module_param(testpat, int, 0);
+MODULE_PARM_DESC(testpat,
+  "Replace image with vertical bar testpattern (only partially working)");
+module_param(dumppix, int, 0);
+MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
+module_param(led, int, 0);
+MODULE_PARM_DESC(led,
+  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
+module_param(dump_bridge, int, 0);
+MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
+module_param(dump_sensor, int, 0);
+MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
+module_param(printph, int, 0);
+MODULE_PARM_DESC(printph, "Print frame start/end headers");
+module_param(phy, int, 0);
+MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
+module_param(phuv, int, 0);
+MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
+module_param(pvy, int, 0);
+MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
+module_param(pvuv, int, 0);
+MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
+module_param(qhy, int, 0);
+MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
+module_param(qhuv, int, 0);
+MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
+module_param(qvy, int, 0);
+MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
+module_param(qvuv, int, 0);
+MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
+module_param(lightfreq, int, 0);
+MODULE_PARM_DESC(lightfreq,
+  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
+module_param(bandingfilter, int, 0);
+MODULE_PARM_DESC(bandingfilter,
+  "Enable banding filter (to reduce effects of fluorescent lighting)");
+module_param(clockdiv, int, 0);
+MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
+module_param(packetsize, int, 0);
+MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
+module_param(framedrop, int, 0);
+MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
+module_param(fastset, int, 0);
+MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
+module_param(force_palette, int, 0);
+MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
+module_param(backlight, int, 0);
+MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
+static int num_uv;
+module_param_array(unit_video, int, &num_uv, 0);
+MODULE_PARM_DESC(unit_video,
+  "Force use of specific minor number(s). 0 is not allowed.");
+module_param(remove_zeros, int, 0);
+MODULE_PARM_DESC(remove_zeros,
+  "Remove zero-padding from uncompressed incoming data");
+module_param(mirror, int, 0);
+MODULE_PARM_DESC(mirror, "Reverse image horizontally");
+module_param(ov518_color, int, 0);
+MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/**********************************************************************
+ * Miscellaneous Globals
+ **********************************************************************/
+
+static struct usb_driver ov511_driver;
+
+/* Number of times to retry a failed I2C transaction. Increase this if you
+ * are getting "Failed to read sensor ID..." */
+static const int i2c_detect_tries = 5;
+
+static struct usb_device_id device_table [] = {
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
+       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
+       { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
+       { }  /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, device_table);
+
+static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
+static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
+static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
+static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
+
+/**********************************************************************
+ * Symbolic Names
+ **********************************************************************/
+
+/* Known OV511-based cameras */
+static struct symbolic_list camlist[] = {
+       {   0, "Generic Camera (no ID)" },
+       {   1, "Mustek WCam 3X" },
+       {   3, "D-Link DSB-C300" },
+       {   4, "Generic OV511/OV7610" },
+       {   5, "Puretek PT-6007" },
+       {   6, "Lifeview USB Life TV (NTSC)" },
+       {  21, "Creative Labs WebCam 3" },
+       {  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
+       {  36, "Koala-Cam" },
+       {  38, "Lifeview USB Life TV (PAL)" },
+       {  41, "Samsung Anycam MPC-M10" },
+       {  43, "Mtekvision Zeca MV402" },
+       {  46, "Suma eON" },
+       {  70, "Lifeview USB Life TV (PAL/SECAM)" },
+       { 100, "Lifeview RoboCam" },
+       { 102, "AverMedia InterCam Elite" },
+       { 112, "MediaForte MV300" },    /* or OV7110 evaluation kit */
+       { 134, "Ezonics EZCam II" },
+       { 192, "Webeye 2000B" },
+       { 253, "Alpha Vision Tech. AlphaCam SE" },
+       {  -1, NULL }
+};
+
+/* Video4Linux1 Palettes */
+static struct symbolic_list v4l1_plist[] = {
+       { VIDEO_PALETTE_GREY,   "GREY" },
+       { VIDEO_PALETTE_HI240,  "HI240" },
+       { VIDEO_PALETTE_RGB565, "RGB565" },
+       { VIDEO_PALETTE_RGB24,  "RGB24" },
+       { VIDEO_PALETTE_RGB32,  "RGB32" },
+       { VIDEO_PALETTE_RGB555, "RGB555" },
+       { VIDEO_PALETTE_YUV422, "YUV422" },
+       { VIDEO_PALETTE_YUYV,   "YUYV" },
+       { VIDEO_PALETTE_UYVY,   "UYVY" },
+       { VIDEO_PALETTE_YUV420, "YUV420" },
+       { VIDEO_PALETTE_YUV411, "YUV411" },
+       { VIDEO_PALETTE_RAW,    "RAW" },
+       { VIDEO_PALETTE_YUV422P,"YUV422P" },
+       { VIDEO_PALETTE_YUV411P,"YUV411P" },
+       { VIDEO_PALETTE_YUV420P,"YUV420P" },
+       { VIDEO_PALETTE_YUV410P,"YUV410P" },
+       { -1, NULL }
+};
+
+static struct symbolic_list brglist[] = {
+       { BRG_OV511,            "OV511" },
+       { BRG_OV511PLUS,        "OV511+" },
+       { BRG_OV518,            "OV518" },
+       { BRG_OV518PLUS,        "OV518+" },
+       { -1, NULL }
+};
+
+static struct symbolic_list senlist[] = {
+       { SEN_OV76BE,   "OV76BE" },
+       { SEN_OV7610,   "OV7610" },
+       { SEN_OV7620,   "OV7620" },
+       { SEN_OV7620AE, "OV7620AE" },
+       { SEN_OV6620,   "OV6620" },
+       { SEN_OV6630,   "OV6630" },
+       { SEN_OV6630AE, "OV6630AE" },
+       { SEN_OV6630AF, "OV6630AF" },
+       { SEN_OV8600,   "OV8600" },
+       { SEN_KS0127,   "KS0127" },
+       { SEN_KS0127B,  "KS0127B" },
+       { SEN_SAA7111A, "SAA7111A" },
+       { -1, NULL }
+};
+
+/* URB error codes: */
+static struct symbolic_list urb_errlist[] = {
+       { -ENOSR,       "Buffer error (overrun)" },
+       { -EPIPE,       "Stalled (device not responding)" },
+       { -EOVERFLOW,   "Babble (bad cable?)" },
+       { -EPROTO,      "Bit-stuff error (bad cable?)" },
+       { -EILSEQ,      "CRC/Timeout" },
+       { -ETIMEDOUT,   "NAK (device does not respond)" },
+       { -1, NULL }
+};
+
+/**********************************************************************
+ * Memory management
+ **********************************************************************/
+static void *
+rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void
+rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+/**********************************************************************
+ *
+ * Register I/O
+ *
+ **********************************************************************/
+
+/* Write an OV51x register */
+static int
+reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
+{
+       int rc;
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       mutex_lock(&ov->cbuf_lock);
+       ov->cbuf[0] = value;
+       rc = usb_control_msg(ov->dev,
+                            usb_sndctrlpipe(ov->dev, 0),
+                            (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
+       mutex_unlock(&ov->cbuf_lock);
+
+       if (rc < 0)
+               err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
+
+       return rc;
+}
+
+/* Read from an OV51x register */
+/* returns: negative is error, pos or zero is data */
+static int
+reg_r(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc;
+
+       mutex_lock(&ov->cbuf_lock);
+       rc = usb_control_msg(ov->dev,
+                            usb_rcvctrlpipe(ov->dev, 0),
+                            (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
+                            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
+
+       if (rc < 0) {
+               err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
+       } else {
+               rc = ov->cbuf[0];
+               PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
+       }
+
+       mutex_unlock(&ov->cbuf_lock);
+
+       return rc;
+}
+
+/*
+ * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int
+reg_w_mask(struct usb_ov511 *ov,
+          unsigned char reg,
+          unsigned char value,
+          unsigned char mask)
+{
+       int ret;
+       unsigned char oldval, newval;
+
+       ret = reg_r(ov, reg);
+       if (ret < 0)
+               return ret;
+
+       oldval = (unsigned char) ret;
+       oldval &= (~mask);              /* Clear the masked bits */
+       value &= mask;                  /* Enforce mask on value */
+       newval = oldval | value;        /* Set the desired bits */
+
+       return (reg_w(ov, reg, newval));
+}
+
+/* 
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
+static int
+ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
+{
+       int rc;
+
+       PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
+
+       mutex_lock(&ov->cbuf_lock);
+
+       *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
+
+       rc = usb_control_msg(ov->dev,
+                            usb_sndctrlpipe(ov->dev, 0),
+                            1 /* REG_IO */,
+                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                            0, (__u16)reg, ov->cbuf, n, 1000);
+       mutex_unlock(&ov->cbuf_lock);
+
+       if (rc < 0)
+               err("reg write multiple: error %d: %s", rc,
+                   symbolic(urb_errlist, rc));
+
+       return rc;
+}
+
+static int
+ov511_upload_quan_tables(struct usb_ov511 *ov)
+{
+       unsigned char *pYTable = yQuanTable511;
+       unsigned char *pUVTable = uvQuanTable511;
+       unsigned char val0, val1;
+       int i, rc, reg = R511_COMP_LUT_BEGIN;
+
+       PDEBUG(4, "Uploading quantization tables");
+
+       for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
+               if (ENABLE_Y_QUANTABLE) {
+                       val0 = *pYTable++;
+                       val1 = *pYTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               if (ENABLE_UV_QUANTABLE) {
+                       val0 = *pUVTable++;
+                       val1 = *pUVTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               reg++;
+       }
+
+       return 0;
+}
+
+/* OV518 quantization tables are 8x4 (instead of 8x8) */
+static int
+ov518_upload_quan_tables(struct usb_ov511 *ov)
+{
+       unsigned char *pYTable = yQuanTable518;
+       unsigned char *pUVTable = uvQuanTable518;
+       unsigned char val0, val1;
+       int i, rc, reg = R511_COMP_LUT_BEGIN;
+
+       PDEBUG(4, "Uploading quantization tables");
+
+       for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
+               if (ENABLE_Y_QUANTABLE) {
+                       val0 = *pYTable++;
+                       val1 = *pYTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               if (ENABLE_UV_QUANTABLE) {
+                       val0 = *pUVTable++;
+                       val1 = *pUVTable++;
+                       val0 &= 0x0f;
+                       val1 &= 0x0f;
+                       val0 |= val1 << 4;
+                       rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               reg++;
+       }
+
+       return 0;
+}
+
+static int
+ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
+{
+       int rc;
+
+       /* Setting bit 0 not allowed on 518/518Plus */
+       if (ov->bclass == BCL_OV518)
+               reset_type &= 0xfe;
+
+       PDEBUG(4, "Reset: type=0x%02X", reset_type);
+
+       rc = reg_w(ov, R51x_SYS_RESET, reset_type);
+       rc = reg_w(ov, R51x_SYS_RESET, 0);
+
+       if (rc < 0)
+               err("reset: command failed");
+
+       return rc;
+}
+
+/**********************************************************************
+ *
+ * Low-level I2C I/O functions
+ *
+ **********************************************************************/
+
+/* NOTE: Do not call this function directly!
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_w(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int
+ov518_i2c_write_internal(struct usb_ov511 *ov,
+                        unsigned char reg,
+                        unsigned char value)
+{
+       int rc;
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       /* Select camera register */
+       rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Write "value" to I2C data port of OV511 */
+       rc = reg_w(ov, R51x_I2C_DATA, value);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 3-byte write cycle */
+       rc = reg_w(ov, R518_I2C_CTL, 0x01);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+/* NOTE: Do not call this function directly! */
+static int
+ov511_i2c_write_internal(struct usb_ov511 *ov,
+                        unsigned char reg,
+                        unsigned char value)
+{
+       int rc, retries;
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       /* Three byte write cycle */
+       for (retries = OV511_I2C_RETRIES; ; ) {
+               /* Select camera register */
+               rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
+               if (rc < 0)
+                       break;
+
+               /* Write "value" to I2C data port of OV511 */
+               rc = reg_w(ov, R51x_I2C_DATA, value);
+               if (rc < 0)
+                       break;
+
+               /* Initiate 3-byte write cycle */
+               rc = reg_w(ov, R511_I2C_CTL, 0x01);
+               if (rc < 0)
+                       break;
+
+               /* Retry until idle */
+               do
+                       rc = reg_r(ov, R511_I2C_CTL);
+               while (rc > 0 && ((rc&1) == 0)); 
+               if (rc < 0)
+                       break;
+
+               /* Ack? */
+               if ((rc&2) == 0) {
+                       rc = 0;
+                       break;
+               }
+#if 0
+               /* I2C abort */
+               reg_w(ov, R511_I2C_CTL, 0x10);
+#endif
+               if (--retries < 0) {
+                       err("i2c write retries exhausted");
+                       rc = -1;
+                       break;
+               }
+       }
+
+       return rc;
+}
+
+/* NOTE: Do not call this function directly!
+ * The OV518 I2C I/O procedure is different, hence, this function.
+ * This is normally only called from i2c_r(). Note that this function
+ * always succeeds regardless of whether the sensor is present and working.
+ */
+static int
+ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc, value;
+
+       /* Select camera register */
+       rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 2-byte write cycle */
+       rc = reg_w(ov, R518_I2C_CTL, 0x03);
+       if (rc < 0)
+               return rc;
+
+       /* Initiate 2-byte read cycle */
+       rc = reg_w(ov, R518_I2C_CTL, 0x05);
+       if (rc < 0)
+               return rc;
+
+       value = reg_r(ov, R51x_I2C_DATA);
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       return value;
+}
+
+/* NOTE: Do not call this function directly!
+ * returns: negative is error, pos or zero is data */
+static int
+ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc, value, retries;
+
+       /* Two byte write cycle */
+       for (retries = OV511_I2C_RETRIES; ; ) {
+               /* Select camera register */
+               rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
+               if (rc < 0)
+                       return rc;
+
+               /* Initiate 2-byte write cycle */
+               rc = reg_w(ov, R511_I2C_CTL, 0x03);
+               if (rc < 0)
+                       return rc;
+
+               /* Retry until idle */
+               do
+                        rc = reg_r(ov, R511_I2C_CTL);
+               while (rc > 0 && ((rc&1) == 0));
+               if (rc < 0)
+                       return rc;
+
+               if ((rc&2) == 0) /* Ack? */
+                       break;
+
+               /* I2C abort */
+               reg_w(ov, R511_I2C_CTL, 0x10);
+
+               if (--retries < 0) {
+                       err("i2c write retries exhausted");
+                       return -1;
+               }
+       }
+
+       /* Two byte read cycle */
+       for (retries = OV511_I2C_RETRIES; ; ) {
+               /* Initiate 2-byte read cycle */
+               rc = reg_w(ov, R511_I2C_CTL, 0x05);
+               if (rc < 0)
+                       return rc;
+
+               /* Retry until idle */
+               do
+                       rc = reg_r(ov, R511_I2C_CTL);
+               while (rc > 0 && ((rc&1) == 0));
+               if (rc < 0)
+                       return rc;
+
+               if ((rc&2) == 0) /* Ack? */
+                       break;
+
+               /* I2C abort */
+               rc = reg_w(ov, R511_I2C_CTL, 0x10);
+               if (rc < 0)
+                       return rc;
+
+               if (--retries < 0) {
+                       err("i2c read retries exhausted");
+                       return -1;
+               }
+       }
+
+       value = reg_r(ov, R51x_I2C_DATA);
+
+       PDEBUG(5, "0x%02X:0x%02X", reg, value);
+
+       /* This is needed to make i2c_w() work */
+       rc = reg_w(ov, R511_I2C_CTL, 0x05);
+       if (rc < 0)
+               return rc;
+
+       return value;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int
+i2c_r(struct usb_ov511 *ov, unsigned char reg)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       if (ov->bclass == BCL_OV518)
+               rc = ov518_i2c_read_internal(ov, reg);
+       else
+               rc = ov511_i2c_read_internal(ov, reg);
+
+       mutex_unlock(&ov->i2c_lock);
+
+       return rc;
+}
+
+static int
+i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       if (ov->bclass == BCL_OV518)
+               rc = ov518_i2c_write_internal(ov, reg, value);
+       else
+               rc = ov511_i2c_write_internal(ov, reg, value);
+
+       mutex_unlock(&ov->i2c_lock);
+
+       return rc;
+}
+
+/* Do not call this function directly! */
+static int
+ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
+                             unsigned char reg,
+                             unsigned char value,
+                             unsigned char mask)
+{
+       int rc;
+       unsigned char oldval, newval;
+
+       if (mask == 0xff) {
+               newval = value;
+       } else {
+               if (ov->bclass == BCL_OV518)
+                       rc = ov518_i2c_read_internal(ov, reg);
+               else
+                       rc = ov511_i2c_read_internal(ov, reg);
+               if (rc < 0)
+                       return rc;
+
+               oldval = (unsigned char) rc;
+               oldval &= (~mask);              /* Clear the masked bits */
+               value &= mask;                  /* Enforce mask on value */
+               newval = oldval | value;        /* Set the desired bits */
+       }
+
+       if (ov->bclass == BCL_OV518)
+               return (ov518_i2c_write_internal(ov, reg, newval));
+       else
+               return (ov511_i2c_write_internal(ov, reg, newval));
+}
+
+/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
+ * the same position as 1's in "mask" are cleared and set to "value". Bits
+ * that are in the same position as 0's in "mask" are preserved, regardless
+ * of their respective state in "value".
+ */
+static int
+i2c_w_mask(struct usb_ov511 *ov,
+          unsigned char reg,
+          unsigned char value,
+          unsigned char mask)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
+       mutex_unlock(&ov->i2c_lock);
+
+       return rc;
+}
+
+/* Set the read and write slave IDs. The "slave" argument is the write slave,
+ * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
+ * when calling this. This should not be called from outside the i2c I/O
+ * functions.
+ */
+static int
+i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
+{
+       int rc;
+
+       rc = reg_w(ov, R51x_I2C_W_SID, slave);
+       if (rc < 0)
+               return rc;
+
+       rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+/* Write to a specific I2C slave ID and register, using the specified mask */
+static int
+i2c_w_slave(struct usb_ov511 *ov,
+           unsigned char slave,
+           unsigned char reg,
+           unsigned char value,
+           unsigned char mask)
+{
+       int rc = 0;
+
+       mutex_lock(&ov->i2c_lock);
+
+       /* Set new slave IDs */
+       rc = i2c_set_slave_internal(ov, slave);
+       if (rc < 0)
+               goto out;
+
+       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
+
+out:
+       /* Restore primary IDs */
+       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+               err("Couldn't restore primary I2C slave");
+
+       mutex_unlock(&ov->i2c_lock);
+       return rc;
+}
+
+/* Read from a specific I2C slave ID and register */
+static int
+i2c_r_slave(struct usb_ov511 *ov,
+           unsigned char slave,
+           unsigned char reg)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       /* Set new slave IDs */
+       rc = i2c_set_slave_internal(ov, slave);
+       if (rc < 0)
+               goto out;
+
+       if (ov->bclass == BCL_OV518)
+               rc = ov518_i2c_read_internal(ov, reg);
+       else
+               rc = ov511_i2c_read_internal(ov, reg);
+
+out:
+       /* Restore primary IDs */
+       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
+               err("Couldn't restore primary I2C slave");
+
+       mutex_unlock(&ov->i2c_lock);
+       return rc;
+}
+
+/* Sets I2C read and write slave IDs. Returns <0 for error */
+static int
+ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
+{
+       int rc;
+
+       mutex_lock(&ov->i2c_lock);
+
+       rc = i2c_set_slave_internal(ov, sid);
+       if (rc < 0)
+               goto out;
+
+       // FIXME: Is this actually necessary?
+       rc = ov51x_reset(ov, OV511_RESET_NOREGS);
+out:
+       mutex_unlock(&ov->i2c_lock);
+       return rc;
+}
+
+static int
+write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
+{
+       int rc;
+
+       while (pRegvals->bus != OV511_DONE_BUS) {
+               if (pRegvals->bus == OV511_REG_BUS) {
+                       if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
+                               return rc;
+               } else if (pRegvals->bus == OV511_I2C_BUS) {
+                       if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
+                               return rc;
+               } else {
+                       err("Bad regval array");
+                       return -1;
+               }
+               pRegvals++;
+       }
+       return 0;
+}
+
+#ifdef OV511_DEBUG
+static void
+dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
+{
+       int i, rc;
+
+       for (i = reg1; i <= regn; i++) {
+               rc = i2c_r(ov, i);
+               info("Sensor[0x%02X] = 0x%02X", i, rc);
+       }
+}
+
+static void
+dump_i2c_regs(struct usb_ov511 *ov)
+{
+       info("I2C REGS");
+       dump_i2c_range(ov, 0x00, 0x7C);
+}
+
+static void
+dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
+{
+       int i, rc;
+
+       for (i = reg1; i <= regn; i++) {
+               rc = reg_r(ov, i);
+               info("OV511[0x%02X] = 0x%02X", i, rc);
+       }
+}
+
+static void
+ov511_dump_regs(struct usb_ov511 *ov)
+{
+       info("CAMERA INTERFACE REGS");
+       dump_reg_range(ov, 0x10, 0x1f);
+       info("DRAM INTERFACE REGS");
+       dump_reg_range(ov, 0x20, 0x23);
+       info("ISO FIFO REGS");
+       dump_reg_range(ov, 0x30, 0x31);
+       info("PIO REGS");
+       dump_reg_range(ov, 0x38, 0x39);
+       dump_reg_range(ov, 0x3e, 0x3e);
+       info("I2C REGS");
+       dump_reg_range(ov, 0x40, 0x49);
+       info("SYSTEM CONTROL REGS");
+       dump_reg_range(ov, 0x50, 0x55);
+       dump_reg_range(ov, 0x5e, 0x5f);
+       info("OmniCE REGS");
+       dump_reg_range(ov, 0x70, 0x79);
+       /* NOTE: Quantization tables are not readable. You will get the value
+        * in reg. 0x79 for every table register */
+       dump_reg_range(ov, 0x80, 0x9f);
+       dump_reg_range(ov, 0xa0, 0xbf);
+
+}
+
+static void
+ov518_dump_regs(struct usb_ov511 *ov)
+{
+       info("VIDEO MODE REGS");
+       dump_reg_range(ov, 0x20, 0x2f);
+       info("DATA PUMP AND SNAPSHOT REGS");
+       dump_reg_range(ov, 0x30, 0x3f);
+       info("I2C REGS");
+       dump_reg_range(ov, 0x40, 0x4f);
+       info("SYSTEM CONTROL AND VENDOR REGS");
+       dump_reg_range(ov, 0x50, 0x5f);
+       info("60 - 6F");
+       dump_reg_range(ov, 0x60, 0x6f);
+       info("70 - 7F");
+       dump_reg_range(ov, 0x70, 0x7f);
+       info("Y QUANTIZATION TABLE");
+       dump_reg_range(ov, 0x80, 0x8f);
+       info("UV QUANTIZATION TABLE");
+       dump_reg_range(ov, 0x90, 0x9f);
+       info("A0 - BF");
+       dump_reg_range(ov, 0xa0, 0xbf);
+       info("CBR");
+       dump_reg_range(ov, 0xc0, 0xcf);
+}
+#endif
+
+/*****************************************************************************/
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int
+ov51x_stop(struct usb_ov511 *ov)
+{
+       PDEBUG(4, "stopping");
+       ov->stopped = 1;
+       if (ov->bclass == BCL_OV518)
+               return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
+       else
+               return (reg_w(ov, R51x_SYS_RESET, 0x3d));
+}
+
+/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
+ * actually stopped (for performance). */
+static inline int
+ov51x_restart(struct usb_ov511 *ov)
+{
+       if (ov->stopped) {
+               PDEBUG(4, "restarting");
+               ov->stopped = 0;
+
+               /* Reinitialize the stream */
+               if (ov->bclass == BCL_OV518)
+                       reg_w(ov, 0x2f, 0x80);
+
+               return (reg_w(ov, R51x_SYS_RESET, 0x00));
+       }
+
+       return 0;
+}
+
+/* Sleeps until no frames are active. Returns !0 if got signal */
+static int
+ov51x_wait_frames_inactive(struct usb_ov511 *ov)
+{
+       return wait_event_interruptible(ov->wq, ov->curframe < 0);
+}
+
+/* Resets the hardware snapshot button */
+static void
+ov51x_clear_snapshot(struct usb_ov511 *ov)
+{
+       if (ov->bclass == BCL_OV511) {
+               reg_w(ov, R51x_SYS_SNAP, 0x00);
+               reg_w(ov, R51x_SYS_SNAP, 0x02);
+               reg_w(ov, R51x_SYS_SNAP, 0x00);
+       } else if (ov->bclass == BCL_OV518) {
+               warn("snapshot reset not supported yet on OV518(+)");
+       } else {
+               err("clear snap: invalid bridge type");
+       }
+}
+
+#if 0
+/* Checks the status of the snapshot button. Returns 1 if it was pressed since
+ * it was last cleared, and zero in all other cases (including errors) */
+static int
+ov51x_check_snapshot(struct usb_ov511 *ov)
+{
+       int ret, status = 0;
+
+       if (ov->bclass == BCL_OV511) {
+               ret = reg_r(ov, R51x_SYS_SNAP);
+               if (ret < 0) {
+                       err("Error checking snspshot status (%d)", ret);
+               } else if (ret & 0x08) {
+                       status = 1;
+               }
+       } else if (ov->bclass == BCL_OV518) {
+               warn("snapshot check not supported yet on OV518(+)");
+       } else {
+               err("check snap: invalid bridge type");
+       }
+
+       return status;
+}
+#endif
+
+/* This does an initial reset of an OmniVision sensor and ensures that I2C
+ * is synchronized. Returns <0 for failure.
+ */
+static int
+init_ov_sensor(struct usb_ov511 *ov)
+{
+       int i, success;
+
+       /* Reset the sensor */
+       if (i2c_w(ov, 0x12, 0x80) < 0)
+               return -EIO;
+
+       /* Wait for it to initialize */
+       msleep(150);
+
+       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+               if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
+                   (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
+                       success = 1;
+                       continue;
+               }
+
+               /* Reset the sensor */
+               if (i2c_w(ov, 0x12, 0x80) < 0)
+                       return -EIO;
+               /* Wait for it to initialize */
+               msleep(150);
+               /* Dummy read to sync I2C */
+               if (i2c_r(ov, 0x00) < 0)
+                       return -EIO;
+       }
+
+       if (!success)
+               return -EIO;
+
+       PDEBUG(1, "I2C synced in %d attempt(s)", i);
+
+       return 0;
+}
+
+static int
+ov511_set_packet_size(struct usb_ov511 *ov, int size)
+{
+       int alt, mult;
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       mult = size >> 5;
+
+       if (ov->bridge == BRG_OV511) {
+               if (size == 0)
+                       alt = OV511_ALT_SIZE_0;
+               else if (size == 257)
+                       alt = OV511_ALT_SIZE_257;
+               else if (size == 513)
+                       alt = OV511_ALT_SIZE_513;
+               else if (size == 769)
+                       alt = OV511_ALT_SIZE_769;
+               else if (size == 993)
+                       alt = OV511_ALT_SIZE_993;
+               else {
+                       err("Set packet size: invalid size (%d)", size);
+                       return -EINVAL;
+               }
+       } else if (ov->bridge == BRG_OV511PLUS) {
+               if (size == 0)
+                       alt = OV511PLUS_ALT_SIZE_0;
+               else if (size == 33)
+                       alt = OV511PLUS_ALT_SIZE_33;
+               else if (size == 129)
+                       alt = OV511PLUS_ALT_SIZE_129;
+               else if (size == 257)
+                       alt = OV511PLUS_ALT_SIZE_257;
+               else if (size == 385)
+                       alt = OV511PLUS_ALT_SIZE_385;
+               else if (size == 513)
+                       alt = OV511PLUS_ALT_SIZE_513;
+               else if (size == 769)
+                       alt = OV511PLUS_ALT_SIZE_769;
+               else if (size == 961)
+                       alt = OV511PLUS_ALT_SIZE_961;
+               else {
+                       err("Set packet size: invalid size (%d)", size);
+                       return -EINVAL;
+               }
+       } else {
+               err("Set packet size: Invalid bridge type");
+               return -EINVAL;
+       }
+
+       PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
+
+       if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
+               return -EIO;
+
+       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
+               err("Set packet size: set interface error");
+               return -EBUSY;
+       }
+
+       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+               return -EIO;
+
+       ov->packet_size = size;
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
+ * optional packet number byte. The actual size *is* stored in ov->packet_size,
+ * though. */
+static int
+ov518_set_packet_size(struct usb_ov511 *ov, int size)
+{
+       int alt;
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       if (ov->bclass == BCL_OV518) {
+               if (size == 0)
+                       alt = OV518_ALT_SIZE_0;
+               else if (size == 128)
+                       alt = OV518_ALT_SIZE_128;
+               else if (size == 256)
+                       alt = OV518_ALT_SIZE_256;
+               else if (size == 384)
+                       alt = OV518_ALT_SIZE_384;
+               else if (size == 512)
+                       alt = OV518_ALT_SIZE_512;
+               else if (size == 640)
+                       alt = OV518_ALT_SIZE_640;
+               else if (size == 768)
+                       alt = OV518_ALT_SIZE_768;
+               else if (size == 896)
+                       alt = OV518_ALT_SIZE_896;
+               else {
+                       err("Set packet size: invalid size (%d)", size);
+                       return -EINVAL;
+               }
+       } else {
+               err("Set packet size: Invalid bridge type");
+               return -EINVAL;
+       }
+
+       PDEBUG(3, "%d, alt=%d", size, alt);
+
+       ov->packet_size = size;
+       if (size > 0) {
+               /* Program ISO FIFO size reg (packet number isn't included) */
+               ov518_reg_w32(ov, 0x30, size, 2);
+
+               if (ov->packet_numbering)
+                       ++ov->packet_size;
+       }
+
+       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
+               err("Set packet size: set interface error");
+               return -EBUSY;
+       }
+
+       /* Initialize the stream */
+       if (reg_w(ov, 0x2f, 0x80) < 0)
+               return -EIO;
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* Upload compression params and quantization tables. Returns 0 for success. */
+static int
+ov511_init_compression(struct usb_ov511 *ov)
+{
+       int rc = 0;
+
+       if (!ov->compress_inited) {
+               reg_w(ov, 0x70, phy);
+               reg_w(ov, 0x71, phuv);
+               reg_w(ov, 0x72, pvy);
+               reg_w(ov, 0x73, pvuv);
+               reg_w(ov, 0x74, qhy);
+               reg_w(ov, 0x75, qhuv);
+               reg_w(ov, 0x76, qvy);
+               reg_w(ov, 0x77, qvuv);
+
+               if (ov511_upload_quan_tables(ov) < 0) {
+                       err("Error uploading quantization tables");
+                       rc = -EIO;
+                       goto out;
+               }
+       }
+
+       ov->compress_inited = 1;
+out:
+       return rc;
+}
+
+/* Upload compression params and quantization tables. Returns 0 for success. */
+static int
+ov518_init_compression(struct usb_ov511 *ov)
+{
+       int rc = 0;
+
+       if (!ov->compress_inited) {
+               if (ov518_upload_quan_tables(ov) < 0) {
+                       err("Error uploading quantization tables");
+                       rc = -EIO;
+                       goto out;
+               }
+       }
+
+       ov->compress_inited = 1;
+out:
+       return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's contrast setting to "val" */
+static int
+sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       {
+               rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       case SEN_OV6630:
+       {
+               rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       case SEN_OV7620:
+       {
+               unsigned char ctab[] = {
+                       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
+                       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
+               };
+
+               /* Use Y gamma control instead. Bit 0 enables it. */
+               rc = i2c_w(ov, 0x64, ctab[val>>12]);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       case SEN_SAA7111A:
+       {
+               rc = i2c_w(ov, 0x0b, val >> 9);
+               if (rc < 0)
+                       goto out;
+               break;
+       }
+       default:
+       {
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+       }
+
+       rc = 0;         /* Success */
+       ov->contrast = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's contrast setting */
+static int
+sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+               rc = i2c_r(ov, OV7610_REG_CNT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_CNT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 12;
+               break;
+       case SEN_OV7620:
+               /* Use Y gamma reg instead. Bit 0 is the enable bit. */
+               rc = i2c_r(ov, 0x64);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = (rc & 0xfe) << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->contrast;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->contrast = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's brightness setting to "val" */
+static int
+sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(4, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_OV7620:
+               /* 7620 doesn't like manual changes when in auto mode */
+               if (!ov->auto_brt) {
+                       rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
+                       if (rc < 0)
+                               goto out;
+               }
+               break;
+       case SEN_SAA7111A:
+               rc = i2c_w(ov, 0x0a, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+
+       rc = 0;         /* Success */
+       ov->brightness = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's brightness setting */
+static int
+sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV7620:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_BRT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->brightness;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->brightness = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's saturation (color intensity) setting to "val" */
+static int
+sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_OV7620:
+//             /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
+//             rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
+//             if (rc < 0)
+//                     goto out;
+               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_SAA7111A:
+               rc = i2c_w(ov, 0x0c, val >> 9);
+               if (rc < 0)
+                       goto out;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+
+       rc = 0;         /* Success */
+       ov->colour = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's saturation (color intensity) setting */
+static int
+sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_SAT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_OV7620:
+//             /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
+//             rc = i2c_r(ov, 0x62);
+//             if (rc < 0)
+//                     return rc;
+//             else
+//                     *val = (rc & 0x7e) << 9;
+               rc = i2c_r(ov, OV7610_REG_SAT);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->colour;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->colour = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Sets sensor's hue (red/blue balance) setting to "val" */
+static int
+sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
+               if (rc < 0)
+                       goto out;
+
+               rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       case SEN_OV7620:
+// Hue control is causing problems. I will enable it once it's fixed.
+#if 0
+               rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
+               if (rc < 0)
+                       goto out;
+
+               rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
+               if (rc < 0)
+                       goto out;
+#endif
+               break;
+       case SEN_SAA7111A:
+               rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
+               if (rc < 0)
+                       goto out;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               rc = -EPERM;
+               goto out;
+       }
+
+       rc = 0;         /* Success */
+       ov->hue = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+
+/* Gets sensor's hue (red/blue balance) setting */
+static int
+sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = i2c_r(ov, OV7610_REG_BLUE);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_OV7620:
+               rc = i2c_r(ov, 0x7a);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc << 8;
+               break;
+       case SEN_SAA7111A:
+               *val = ov->hue;
+               break;
+       default:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->hue = *val;
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int
+sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
+{
+       int rc;
+
+       PDEBUG(4, "sensor_set_picture");
+
+       ov->whiteness = p->whiteness;
+
+       /* Don't return error if a setting is unsupported, or rest of settings
+         * will not be performed */
+
+       rc = sensor_set_contrast(ov, p->contrast);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_brightness(ov, p->brightness);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_saturation(ov, p->colour);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_hue(ov, p->hue);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       return 0;
+}
+
+static int
+sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
+{
+       int rc;
+
+       PDEBUG(4, "sensor_get_picture");
+
+       /* Don't return error if a setting is unsupported, or rest of settings
+         * will not be performed */
+
+       rc = sensor_get_contrast(ov, &(p->contrast));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_get_brightness(ov, &(p->brightness));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_get_saturation(ov, &(p->colour));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_get_hue(ov, &(p->hue));
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       p->whiteness = 105 << 8;
+
+       return 0;
+}
+
+#if 0
+// FIXME: Exposure range is only 0x00-0x7f in interlace mode
+/* Sets current exposure for sensor. This only has an effect if auto-exposure
+ * is off */
+static inline int
+sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
+{
+       int rc;
+
+       PDEBUG(3, "%d", val);
+
+       if (ov->stop_during_set)
+               if (ov51x_stop(ov) < 0)
+                       return -EIO;
+
+       switch (ov->sensor) {
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7610:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               rc = i2c_w(ov, 0x10, val);
+               if (rc < 0)
+                       goto out;
+
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_exposure");
+               return -EINVAL;
+       }
+
+       rc = 0;         /* Success */
+       ov->exposure = val;
+out:
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return rc;
+}
+#endif
+
+/* Gets current exposure level from sensor, regardless of whether it is under
+ * manual control. */
+static int
+sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
+{
+       int rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               rc = i2c_r(ov, 0x10);
+               if (rc < 0)
+                       return rc;
+               else
+                       *val = rc;
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               val = NULL;
+               PDEBUG(3, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for get_exposure");
+               return -EINVAL;
+       }
+
+       PDEBUG(3, "%d", *val);
+       ov->exposure = *val;
+
+       return 0;
+}
+
+/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
+static void
+ov51x_led_control(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       if (ov->bridge == BRG_OV511PLUS)
+               reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
+       else if (ov->bclass == BCL_OV518)
+               reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
+
+       return;
+}
+
+/* Matches the sensor's internal frame rate to the lighting frequency.
+ * Valid frequencies are:
+ *     50 - 50Hz, for European and Asian lighting
+ *     60 - 60Hz, for American lighting
+ *
+ * Tested with: OV7610, OV7620, OV76BE, OV6620
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_light_freq(struct usb_ov511 *ov, int freq)
+{
+       int sixty;
+
+       PDEBUG(4, "%d Hz", freq);
+
+       if (freq == 60)
+               sixty = 1;
+       else if (freq == 50)
+               sixty = 0;
+       else {
+               err("Invalid light freq (%d Hz)", freq);
+               return -EINVAL;
+       }
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
+               i2c_w(ov, 0x2b, sixty?0x00:0xac);
+               i2c_w_mask(ov, 0x13, 0x10, 0x10);
+               i2c_w_mask(ov, 0x13, 0x00, 0x10);
+               break;
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
+               i2c_w(ov, 0x2b, sixty?0x00:0xac);
+               i2c_w_mask(ov, 0x76, 0x01, 0x01);
+               break;
+       case SEN_OV6620:
+       case SEN_OV6630:
+               i2c_w(ov, 0x2b, sixty?0xa8:0x28);
+               i2c_w(ov, 0x2a, sixty?0x84:0xa4);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_light_freq");
+               return -EINVAL;
+       }
+
+       ov->lightfreq = freq;
+
+       return 0;
+}
+
+/* If enable is true, turn on the sensor's banding filter, otherwise turn it
+ * off. This filter tries to reduce the pattern of horizontal light/dark bands
+ * caused by some (usually fluorescent) lighting. The light frequency must be
+ * set either before or after enabling it with ov51x_set_light_freq().
+ *
+ * Tested with: OV7610, OV7620, OV76BE, OV6620.
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
+{
+       int rc;
+
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
+               || ov->sensor == SEN_SAA7111A) {
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
+       if (rc < 0)
+               return rc;
+
+       ov->bandfilt = enable;
+
+       return 0;
+}
+
+/* If enable is true, turn on the sensor's auto brightness control, otherwise
+ * turn it off.
+ *
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
+{
+       int rc;
+
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
+               || ov->sensor == SEN_SAA7111A) {
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       }
+
+       rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
+       if (rc < 0)
+               return rc;
+
+       ov->auto_brt = enable;
+
+       return 0;
+}
+
+/* If enable is true, turn on the sensor's auto exposure control, otherwise
+ * turn it off.
+ *
+ * Unsupported: KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+               i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
+               break;
+       case SEN_OV6620:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
+               break;
+       case SEN_OV6630:
+               i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_auto_exposure");
+               return -EINVAL;
+       }
+
+       ov->auto_exp = enable;
+
+       return 0;
+}
+
+/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
+ * that are illuminated from behind.
+ *
+ * Tested with: OV6620, OV7620
+ * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
+ * Returns: 0 for success
+ */
+static int
+sensor_set_backlight(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       switch (ov->sensor) {
+       case SEN_OV7620:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
+               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
+               break;
+       case SEN_OV6620:
+               i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
+               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+               i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
+               break;
+       case SEN_OV6630:
+               i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
+               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
+               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
+               break;
+       case SEN_OV7610:
+       case SEN_OV76BE:
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_backlight");
+               return -EINVAL;
+       }
+
+       ov->backlight = enable;
+
+       return 0;
+}
+
+static int
+sensor_set_mirror(struct usb_ov511 *ov, int enable)
+{
+       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
+
+       switch (ov->sensor) {
+       case SEN_OV6620:
+       case SEN_OV6630:
+       case SEN_OV7610:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+               i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+       case SEN_SAA7111A:
+               PDEBUG(5, "Unsupported with this sensor");
+               return -EPERM;
+       default:
+               err("Sensor not supported for set_mirror");
+               return -EINVAL;
+       }
+
+       ov->mirror = enable;
+
+       return 0;
+}
+
+/* Returns number of bits per pixel (regardless of where they are located;
+ * planar or not), or zero for unsupported format.
+ */
+static inline int
+get_depth(int palette)
+{
+       switch (palette) {
+       case VIDEO_PALETTE_GREY:    return 8;
+       case VIDEO_PALETTE_YUV420:  return 12;
+       case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
+       default:                    return 0;  /* Invalid format */
+       }
+}
+
+/* Bytes per frame. Used by read(). Return of 0 indicates error */
+static inline long int
+get_frame_length(struct ov511_frame *frame)
+{
+       if (!frame)
+               return 0;
+       else
+               return ((frame->width * frame->height
+                        * get_depth(frame->format)) >> 3);
+}
+
+static int
+mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
+                        int mode, int sub_flag, int qvga)
+{
+       int clock;
+
+       /******** Mode (VGA/QVGA) and sensor specific regs ********/
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+               i2c_w(ov, 0x14, qvga?0x24:0x04);
+// FIXME: Does this improve the image quality or frame rate?
+#if 0
+               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+               i2c_w(ov, 0x24, 0x10);
+               i2c_w(ov, 0x25, qvga?0x40:0x8a);
+               i2c_w(ov, 0x2f, qvga?0x30:0xb0);
+               i2c_w(ov, 0x35, qvga?0x1c:0x9c);
+#endif
+               break;
+       case SEN_OV7620:
+//             i2c_w(ov, 0x2b, 0x00);
+               i2c_w(ov, 0x14, qvga?0xa4:0x84);
+               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+               i2c_w(ov, 0x24, qvga?0x20:0x3a);
+               i2c_w(ov, 0x25, qvga?0x30:0x60);
+               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
+               i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
+               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
+               break;
+       case SEN_OV76BE:
+//             i2c_w(ov, 0x2b, 0x00);
+               i2c_w(ov, 0x14, qvga?0xa4:0x84);
+// FIXME: Enable this once 7620AE uses 7620 initial settings
+#if 0
+               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
+               i2c_w(ov, 0x24, qvga?0x20:0x3a);
+               i2c_w(ov, 0x25, qvga?0x30:0x60);
+               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
+               i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
+               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
+#endif
+               break;
+       case SEN_OV6620:
+               i2c_w(ov, 0x14, qvga?0x24:0x04);
+               break;
+       case SEN_OV6630:
+               i2c_w(ov, 0x14, qvga?0xa0:0x80);
+               break;
+       default:
+               err("Invalid sensor");
+               return -EINVAL;
+       }
+
+       /******** Palette-specific regs ********/
+
+       if (mode == VIDEO_PALETTE_GREY) {
+               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
+                       /* these aren't valid on the OV6620/OV7620/6630? */
+                       i2c_w_mask(ov, 0x0e, 0x40, 0x40);
+               }
+
+               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
+                   && ov518_color) {
+                       i2c_w_mask(ov, 0x12, 0x00, 0x10);
+                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
+               } else {
+                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
+               }
+       } else {
+               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
+                       /* not valid on the OV6620/OV7620/6630? */
+                       i2c_w_mask(ov, 0x0e, 0x00, 0x40);
+               }
+
+               /* The OV518 needs special treatment. Although both the OV518
+                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
+                * bus is actually used. The UV bus is tied to ground.
+                * Therefore, the OV6630 needs to be in 8-bit multiplexed
+                * output mode */
+
+               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
+                   && ov518_color) {
+                       i2c_w_mask(ov, 0x12, 0x10, 0x10);
+                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
+               } else {
+                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
+               }
+       }
+
+       /******** Clock programming ********/
+
+       /* The OV6620 needs special handling. This prevents the 
+        * severe banding that normally occurs */
+       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
+       {
+               /* Clock down */
+
+               i2c_w(ov, 0x2a, 0x04);
+
+               if (ov->compress) {
+//                     clock = 0;    /* This ensures the highest frame rate */
+                       clock = 3;
+               } else if (clockdiv == -1) {   /* If user didn't override it */
+                       clock = 3;    /* Gives better exposure time */
+               } else {
+                       clock = clockdiv;
+               }
+
+               PDEBUG(4, "Setting clock divisor to %d", clock);
+
+               i2c_w(ov, 0x11, clock);
+
+               i2c_w(ov, 0x2a, 0x84);
+               /* This next setting is critical. It seems to improve
+                * the gain or the contrast. The "reserved" bits seem
+                * to have some effect in this case. */
+               i2c_w(ov, 0x2d, 0x85);
+       }
+       else
+       {
+               if (ov->compress) {
+                       clock = 1;    /* This ensures the highest frame rate */
+               } else if (clockdiv == -1) {   /* If user didn't override it */
+                       /* Calculate and set the clock divisor */
+                       clock = ((sub_flag ? ov->subw * ov->subh
+                                 : width * height)
+                                * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
+                                / 66000;
+               } else {
+                       clock = clockdiv;
+               }
+
+               PDEBUG(4, "Setting clock divisor to %d", clock);
+
+               i2c_w(ov, 0x11, clock);
+       }
+
+       /******** Special Features ********/
+
+       if (framedrop >= 0)
+               i2c_w(ov, 0x16, framedrop);
+
+       /* Test Pattern */
+       i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
+
+       /* Enable auto white balance */
+       i2c_w_mask(ov, 0x12, 0x04, 0x04);
+
+       // This will go away as soon as ov51x_mode_init_sensor_regs()
+       // is fully tested.
+       /* 7620/6620/6630? don't have register 0x35, so play it safe */
+       if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
+               if (width == 640 && height == 480)
+                       i2c_w(ov, 0x35, 0x9e);
+               else
+                       i2c_w(ov, 0x35, 0x1e);
+       }
+
+       return 0;
+}
+
+static int
+set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
+                    int sub_flag)
+{
+       int ret;
+       int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; 
+       int hoffset, voffset, hwscale = 0, vwscale = 0;
+
+       /* The different sensor ICs handle setting up of window differently.
+        * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV76BE:
+               hwsbase = 0x38;
+               hwebase = 0x3a;
+               vwsbase = vwebase = 0x05;
+               break;
+       case SEN_OV6620:
+       case SEN_OV6630:
+               hwsbase = 0x38;
+               hwebase = 0x3a;
+               vwsbase = 0x05;
+               vwebase = 0x06;
+               break;
+       case SEN_OV7620:
+               hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
+               hwebase = 0x2f;
+               vwsbase = vwebase = 0x05;
+               break;
+       default:
+               err("Invalid sensor");
+               return -EINVAL;
+       }
+
+       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
+               /* Note: OV518(+) does downsample on its own) */
+               if ((width > 176 && height > 144)
+                   || ov->bclass == BCL_OV518) {  /* CIF */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 0);
+                       if (ret < 0)
+                               return ret;
+                       hwscale = 1;
+                       vwscale = 1;  /* The datasheet says 0; it's wrong */
+                       hwsize = 352;
+                       vwsize = 288;
+               } else if (width > 176 || height > 144) {
+                       err("Illegal dimensions");
+                       return -EINVAL;
+               } else {                            /* QCIF */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 1);
+                       if (ret < 0)
+                               return ret;
+                       hwsize = 176;
+                       vwsize = 144;
+               }
+       } else {
+               if (width > 320 && height > 240) {  /* VGA */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 0);
+                       if (ret < 0)
+                               return ret;
+                       hwscale = 2;
+                       vwscale = 1;
+                       hwsize = 640;
+                       vwsize = 480;
+               } else if (width > 320 || height > 240) {
+                       err("Illegal dimensions");
+                       return -EINVAL;
+               } else {                            /* QVGA */
+                       ret = mode_init_ov_sensor_regs(ov, width, height,
+                               mode, sub_flag, 1);
+                       if (ret < 0)
+                               return ret;
+                       hwscale = 1;
+                       hwsize = 320;
+                       vwsize = 240;
+               }
+       }
+
+       /* Center the window */
+       hoffset = ((hwsize - width) / 2) >> hwscale;
+       voffset = ((vwsize - height) / 2) >> vwscale;
+
+       /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
+       if (sub_flag) {
+               i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
+               i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
+               i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
+               i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
+       } else {
+               i2c_w(ov, 0x17, hwsbase + hoffset);
+               i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
+               i2c_w(ov, 0x19, vwsbase + voffset);
+               i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
+       }
+
+#ifdef OV511_DEBUG
+       if (dump_sensor)
+               dump_i2c_regs(ov);
+#endif
+
+       return 0;
+}
+
+/* Set up the OV511/OV511+ with the given image parameters.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int
+ov511_mode_init_regs(struct usb_ov511 *ov,
+                    int width, int height, int mode, int sub_flag)
+{
+       int hsegs, vsegs;
+
+       if (sub_flag) {
+               width = ov->subw;
+               height = ov->subh;
+       }
+
+       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
+              width, height, mode, sub_flag);
+
+       // FIXME: This should be moved to a 7111a-specific function once
+       // subcapture is dealt with properly
+       if (ov->sensor == SEN_SAA7111A) {
+               if (width == 320 && height == 240) {
+                       /* No need to do anything special */
+               } else if (width == 640 && height == 480) {
+                       /* Set the OV511 up as 320x480, but keep the
+                        * V4L resolution as 640x480 */
+                       width = 320;
+               } else {
+                       err("SAA7111A only allows 320x240 or 640x480");
+                       return -EINVAL;
+               }
+       }
+
+       /* Make sure width and height are a multiple of 8 */
+       if (width % 8 || height % 8) {
+               err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
+               return -EINVAL;
+       }
+
+       if (width < ov->minwidth || height < ov->minheight) {
+               err("Requested dimensions are too small");
+               return -EINVAL;
+       }
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       if (mode == VIDEO_PALETTE_GREY) {
+               reg_w(ov, R511_CAM_UV_EN, 0x00);
+               reg_w(ov, R511_SNAP_UV_EN, 0x00);
+               reg_w(ov, R511_SNAP_OPTS, 0x01);
+       } else {
+               reg_w(ov, R511_CAM_UV_EN, 0x01);
+               reg_w(ov, R511_SNAP_UV_EN, 0x01);
+               reg_w(ov, R511_SNAP_OPTS, 0x03);
+       }
+
+       /* Here I'm assuming that snapshot size == image size.
+        * I hope that's always true. --claudio
+        */
+       hsegs = (width >> 3) - 1;
+       vsegs = (height >> 3) - 1;
+
+       reg_w(ov, R511_CAM_PXCNT, hsegs);
+       reg_w(ov, R511_CAM_LNCNT, vsegs);
+       reg_w(ov, R511_CAM_PXDIV, 0x00);
+       reg_w(ov, R511_CAM_LNDIV, 0x00);
+
+       /* YUV420, low pass filter on */
+       reg_w(ov, R511_CAM_OPTS, 0x03);
+
+       /* Snapshot additions */
+       reg_w(ov, R511_SNAP_PXCNT, hsegs);
+       reg_w(ov, R511_SNAP_LNCNT, vsegs);
+       reg_w(ov, R511_SNAP_PXDIV, 0x00);
+       reg_w(ov, R511_SNAP_LNDIV, 0x00);
+
+       if (ov->compress) {
+               /* Enable Y and UV quantization and compression */
+               reg_w(ov, R511_COMP_EN, 0x07);
+               reg_w(ov, R511_COMP_LUT_EN, 0x03);
+               ov51x_reset(ov, OV511_RESET_OMNICE);
+       }
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* Sets up the OV518/OV518+ with the given image parameters
+ *
+ * OV518 needs a completely different approach, until we can figure out what
+ * the individual registers do. Also, only 15 FPS is supported now.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int
+ov518_mode_init_regs(struct usb_ov511 *ov,
+                    int width, int height, int mode, int sub_flag)
+{
+       int hsegs, vsegs, hi_res;
+
+       if (sub_flag) {
+               width = ov->subw;
+               height = ov->subh;
+       }
+
+       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
+              width, height, mode, sub_flag);
+
+       if (width % 16 || height % 8) {
+               err("Invalid size (%d, %d)", width, height);
+               return -EINVAL;
+       }
+
+       if (width < ov->minwidth || height < ov->minheight) {
+               err("Requested dimensions are too small");
+               return -EINVAL;
+       }
+
+       if (width >= 320 && height >= 240) {
+               hi_res = 1;
+       } else if (width >= 320 || height >= 240) {
+               err("Invalid width/height combination (%d, %d)", width, height);
+               return -EINVAL;
+       } else {
+               hi_res = 0;
+       }
+
+       if (ov51x_stop(ov) < 0)
+               return -EIO;
+
+       /******** Set the mode ********/
+
+       reg_w(ov, 0x2b, 0);
+       reg_w(ov, 0x2c, 0);
+       reg_w(ov, 0x2d, 0);
+       reg_w(ov, 0x2e, 0);
+       reg_w(ov, 0x3b, 0);
+       reg_w(ov, 0x3c, 0);
+       reg_w(ov, 0x3d, 0);
+       reg_w(ov, 0x3e, 0);
+
+       if (ov->bridge == BRG_OV518 && ov518_color) {
+               /* OV518 needs U and V swapped */
+               i2c_w_mask(ov, 0x15, 0x00, 0x01);
+
+               if (mode == VIDEO_PALETTE_GREY) {
+                       /* Set 16-bit input format (UV data are ignored) */
+                       reg_w_mask(ov, 0x20, 0x00, 0x08);
+
+                       /* Set 8-bit (4:0:0) output format */
+                       reg_w_mask(ov, 0x28, 0x00, 0xf0);
+                       reg_w_mask(ov, 0x38, 0x00, 0xf0);
+               } else {
+                       /* Set 8-bit (YVYU) input format */
+                       reg_w_mask(ov, 0x20, 0x08, 0x08);
+
+                       /* Set 12-bit (4:2:0) output format */
+                       reg_w_mask(ov, 0x28, 0x80, 0xf0);
+                       reg_w_mask(ov, 0x38, 0x80, 0xf0);
+               }
+       } else {
+               reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+               reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
+       }
+
+       hsegs = width / 16;
+       vsegs = height / 4;
+
+       reg_w(ov, 0x29, hsegs);
+       reg_w(ov, 0x2a, vsegs);
+
+       reg_w(ov, 0x39, hsegs);
+       reg_w(ov, 0x3a, vsegs);
+
+       /* Windows driver does this here; who knows why */
+       reg_w(ov, 0x2f, 0x80);
+
+       /******** Set the framerate (to 15 FPS) ********/
+
+       /* Mode independent, but framerate dependent, regs */
+       reg_w(ov, 0x51, 0x02);  /* Clock divider; lower==faster */
+       reg_w(ov, 0x22, 0x18);
+       reg_w(ov, 0x23, 0xff);
+
+       if (ov->bridge == BRG_OV518PLUS)
+               reg_w(ov, 0x21, 0x19);
+       else
+               reg_w(ov, 0x71, 0x19);  /* Compression-related? */
+
+       // FIXME: Sensor-specific
+       /* Bit 5 is what matters here. Of course, it is "reserved" */
+       i2c_w(ov, 0x54, 0x23);
+
+       reg_w(ov, 0x2f, 0x80);
+
+       if (ov->bridge == BRG_OV518PLUS) {
+               reg_w(ov, 0x24, 0x94);
+               reg_w(ov, 0x25, 0x90);
+               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(ov, 0xc6,    540, 2);     /* 21ch   */
+               ov518_reg_w32(ov, 0xc7,    540, 2);     /* 21ch   */
+               ov518_reg_w32(ov, 0xc8,    108, 2);     /* 6ch    */
+               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(ov, 0xcc,   2400, 2);     /* 960h   */
+               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
+       } else {
+               reg_w(ov, 0x24, 0x9f);
+               reg_w(ov, 0x25, 0x90);
+               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(ov, 0xc6,    500, 2);     /* 1f4h   */
+               ov518_reg_w32(ov, 0xc7,    500, 2);     /* 1f4h   */
+               ov518_reg_w32(ov, 0xc8,    142, 2);     /* 8eh    */
+               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(ov, 0xcc,   2000, 2);     /* 7d0h   */
+               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
+       }
+
+       reg_w(ov, 0x2f, 0x80);
+
+       if (ov51x_restart(ov) < 0)
+               return -EIO;
+
+       /* Reset it just for good measure */
+       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+/* This is a wrapper around the OV511, OV518, and sensor specific functions */
+static int
+mode_init_regs(struct usb_ov511 *ov,
+              int width, int height, int mode, int sub_flag)
+{
+       int rc = 0;
+
+       if (!ov || !ov->dev)
+               return -EFAULT;
+
+       if (ov->bclass == BCL_OV518) {
+               rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
+       } else {
+               rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
+       }
+
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       switch (ov->sensor) {
+       case SEN_OV7610:
+       case SEN_OV7620:
+       case SEN_OV76BE:
+       case SEN_OV8600:
+       case SEN_OV6620:
+       case SEN_OV6630:
+               rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
+               break;
+       case SEN_KS0127:
+       case SEN_KS0127B:
+               err("KS0127-series decoders not supported yet");
+               rc = -EINVAL;
+               break;
+       case SEN_SAA7111A:
+//             rc = mode_init_saa_sensor_regs(ov, width, height, mode,
+//                                            sub_flag);
+
+               PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
+               break;
+       default:
+               err("Unknown sensor");
+               rc = -EINVAL;
+       }
+
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       /* Sensor-independent settings */
+       rc = sensor_set_auto_brightness(ov, ov->auto_brt);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_auto_exposure(ov, ov->auto_exp);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_banding_filter(ov, bandingfilter);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       if (ov->lightfreq) {
+               rc = sensor_set_light_freq(ov, lightfreq);
+               if (FATAL_ERROR(rc))
+                       return rc;
+       }
+
+       rc = sensor_set_backlight(ov, ov->backlight);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       rc = sensor_set_mirror(ov, ov->mirror);
+       if (FATAL_ERROR(rc))
+               return rc;
+
+       return 0;
+}
+
+/* This sets the default image parameters. This is useful for apps that use
+ * read() and do not set these.
+ */
+static int
+ov51x_set_default_params(struct usb_ov511 *ov)
+{
+       int i;
+
+       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
+        * (using read() instead). */
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].width = ov->maxwidth;
+               ov->frame[i].height = ov->maxheight;
+               ov->frame[i].bytes_read = 0;
+               if (force_palette)
+                       ov->frame[i].format = force_palette;
+               else
+                       ov->frame[i].format = VIDEO_PALETTE_YUV420;
+
+               ov->frame[i].depth = get_depth(ov->frame[i].format);
+       }
+
+       PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
+              symbolic(v4l1_plist, ov->frame[0].format));
+
+       /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
+       if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
+                          ov->frame[0].format, 0) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**********************************************************************
+ *
+ * Video decoder stuff
+ *
+ **********************************************************************/
+
+/* Set analog input port of decoder */
+static int
+decoder_set_input(struct usb_ov511 *ov, int input)
+{
+       PDEBUG(4, "port %d", input);
+
+       switch (ov->sensor) {
+       case SEN_SAA7111A:
+       {
+               /* Select mode */
+               i2c_w_mask(ov, 0x02, input, 0x07);
+               /* Bypass chrominance trap for modes 4..7 */
+               i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Get ASCII name of video input */
+static int
+decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
+{
+       switch (ov->sensor) {
+       case SEN_SAA7111A:
+       {
+               if (input < 0 || input > 7)
+                       return -EINVAL;
+               else if (input < 4)
+                       sprintf(name, "CVBS-%d", input);
+               else // if (input < 8)
+                       sprintf(name, "S-Video-%d", input - 4);
+               break;
+       }
+       default:
+               sprintf(name, "%s", "Camera");
+       }
+
+       return 0;
+}
+
+/* Set norm (NTSC, PAL, SECAM, AUTO) */
+static int
+decoder_set_norm(struct usb_ov511 *ov, int norm)
+{
+       PDEBUG(4, "%d", norm);
+
+       switch (ov->sensor) {
+       case SEN_SAA7111A:
+       {
+               int reg_8, reg_e;
+
+               if (norm == VIDEO_MODE_NTSC) {
+                       reg_8 = 0x40;   /* 60 Hz */
+                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
+               } else if (norm == VIDEO_MODE_PAL) {
+                       reg_8 = 0x00;   /* 50 Hz */
+                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
+               } else if (norm == VIDEO_MODE_AUTO) {
+                       reg_8 = 0x80;   /* Auto field detect */
+                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
+               } else if (norm == VIDEO_MODE_SECAM) {
+                       reg_8 = 0x00;   /* 50 Hz */
+                       reg_e = 0x50;   /* SECAM / PAL 4.43 */
+               } else {
+                       return -EINVAL;
+               }
+
+               i2c_w_mask(ov, 0x08, reg_8, 0xc0);
+               i2c_w_mask(ov, 0x0e, reg_e, 0x70);
+               break;
+       }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**********************************************************************
+ *
+ * Raw data parsing
+ *
+ **********************************************************************/
+
+/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
+ * image at pOut is specified by w.
+ */
+static inline void
+make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
+{
+       unsigned char *pOut1 = pOut;
+       int x, y;
+
+       for (y = 0; y < 8; y++) {
+               pOut1 = pOut;
+               for (x = 0; x < 8; x++) {
+                       *pOut1++ = *pIn++;
+               }
+               pOut += w;
+       }
+}
+
+/*
+ * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
+ * The segments represent 4 squares of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121 ... 127        248 249 ... 255
+ *
+ */ 
+static void
+yuv400raw_to_yuv400p(struct ov511_frame *frame,
+                    unsigned char *pIn0, unsigned char *pOut0)
+{
+       int x, y;
+       unsigned char *pIn, *pOut, *pOutLine;
+
+       /* Copy Y */
+       pIn = pIn0;
+       pOutLine = pOut0;
+       for (y = 0; y < frame->rawheight - 1; y += 8) {
+               pOut = pOutLine;
+               for (x = 0; x < frame->rawwidth - 1; x += 8) {
+                       make_8x8(pIn, pOut, frame->rawwidth);
+                       pIn += 64;
+                       pOut += 8;
+               }
+               pOutLine += 8 * frame->rawwidth;
+       }
+}
+
+/*
+ * For YUV 4:2:0 images, the data show up in 384 byte segments.
+ * The first 64 bytes of each segment are U, the next 64 are V.  The U and
+ * V are arranged as follows:
+ *
+ *      0  1 ...  7
+ *      8  9 ... 15
+ *           ...   
+ *     56 57 ... 63
+ *
+ * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
+ *
+ * The next 256 bytes are full resolution Y data and represent 4 squares
+ * of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
+ *
+ * Note that the U and V data in one segment represent a 16 x 16 pixel
+ * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
+ * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
+ * next horizontal stripe.
+ *
+ * If dumppix module param is set, _parse_data just dumps the incoming segments,
+ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
+ * this puts the data on the standard output and can be analyzed with the
+ * parseppm.c utility I wrote.  That's a much faster way for figuring out how
+ * these data are scrambled.
+ */
+
+/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
+ *
+ * FIXME: Currently only handles width and height that are multiples of 16
+ */
+static void
+yuv420raw_to_yuv420p(struct ov511_frame *frame,
+                    unsigned char *pIn0, unsigned char *pOut0)
+{
+       int k, x, y;
+       unsigned char *pIn, *pOut, *pOutLine;
+       const unsigned int a = frame->rawwidth * frame->rawheight;
+       const unsigned int w = frame->rawwidth / 2;
+
+       /* Copy U and V */
+       pIn = pIn0;
+       pOutLine = pOut0 + a;
+       for (y = 0; y < frame->rawheight - 1; y += 16) {
+               pOut = pOutLine;
+               for (x = 0; x < frame->rawwidth - 1; x += 16) {
+                       make_8x8(pIn, pOut, w);
+                       make_8x8(pIn + 64, pOut + a/4, w);
+                       pIn += 384;
+                       pOut += 8;
+               }
+               pOutLine += 8 * w;
+       }
+
+       /* Copy Y */
+       pIn = pIn0 + 128;
+       pOutLine = pOut0;
+       k = 0;
+       for (y = 0; y < frame->rawheight - 1; y += 8) {
+               pOut = pOutLine;
+               for (x = 0; x < frame->rawwidth - 1; x += 8) {
+                       make_8x8(pIn, pOut, frame->rawwidth);
+                       pIn += 64;
+                       pOut += 8;
+                       if ((++k) > 3) {
+                               k = 0;
+                               pIn += 128;
+                       }
+               }
+               pOutLine += 8 * frame->rawwidth;
+       }
+}
+
+/**********************************************************************
+ *
+ * Decompression
+ *
+ **********************************************************************/
+
+static int
+request_decompressor(struct usb_ov511 *ov)
+{
+       if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
+               err("No decompressor available");
+       } else {
+               err("Unknown bridge");
+       }
+
+       return -ENOSYS;
+}
+
+static void
+decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
+          unsigned char *pIn0, unsigned char *pOut0)
+{
+       if (!ov->decomp_ops)
+               if (request_decompressor(ov))
+                       return;
+
+}
+
+/**********************************************************************
+ *
+ * Format conversion
+ *
+ **********************************************************************/
+
+/* Fuses even and odd fields together, and doubles width.
+ * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
+ * OUTPUT: a normal YUV planar image, with correct aspect ratio
+ */
+static void
+deinterlace(struct ov511_frame *frame, int rawformat,
+            unsigned char *pIn0, unsigned char *pOut0)
+{
+       const int fieldheight = frame->rawheight / 2;
+       const int fieldpix = fieldheight * frame->rawwidth;
+       const int w = frame->width;
+       int x, y;
+       unsigned char *pInEven, *pInOdd, *pOut;
+
+       PDEBUG(5, "fieldheight=%d", fieldheight);
+
+       if (frame->rawheight != frame->height) {
+               err("invalid height");
+               return;
+       }
+
+       if ((frame->rawwidth * 2) != frame->width) {
+               err("invalid width");
+               return;
+       }
+
+       /* Y */
+       pInOdd = pIn0;
+       pInEven = pInOdd + fieldpix;
+       pOut = pOut0;
+       for (y = 0; y < fieldheight; y++) {
+               for (x = 0; x < frame->rawwidth; x++) {
+                       *pOut = *pInEven;
+                       *(pOut+1) = *pInEven++;
+                       *(pOut+w) = *pInOdd;
+                       *(pOut+w+1) = *pInOdd++;
+                       pOut += 2;
+               }
+               pOut += w;
+       }
+
+       if (rawformat == RAWFMT_YUV420) {
+       /* U */
+               pInOdd = pIn0 + fieldpix * 2;
+               pInEven = pInOdd + fieldpix / 4;
+               for (y = 0; y < fieldheight / 2; y++) {
+                       for (x = 0; x < frame->rawwidth / 2; x++) {
+                               *pOut = *pInEven;
+                               *(pOut+1) = *pInEven++;
+                               *(pOut+w/2) = *pInOdd;
+                               *(pOut+w/2+1) = *pInOdd++;
+                               pOut += 2;
+                       }
+                       pOut += w/2;
+               }
+       /* V */
+               pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
+               pInEven = pInOdd + fieldpix / 4;
+               for (y = 0; y < fieldheight / 2; y++) {
+                       for (x = 0; x < frame->rawwidth / 2; x++) {
+                               *pOut = *pInEven;
+                               *(pOut+1) = *pInEven++;
+                               *(pOut+w/2) = *pInOdd;
+                               *(pOut+w/2+1) = *pInOdd++;
+                               pOut += 2;
+                       }
+                       pOut += w/2;
+               }
+       }
+}
+
+static void
+ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+               /* Deinterlace frame, if necessary */
+               if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
+                       if (frame->compressed)
+                               decompress(ov, frame, frame->rawdata,
+                                                frame->tempdata);
+                       else
+                               yuv400raw_to_yuv400p(frame, frame->rawdata,
+                                                    frame->tempdata);
+
+                       deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
+                                   frame->data);
+               } else {
+                       if (frame->compressed)
+                               decompress(ov, frame, frame->rawdata,
+                                                frame->data);
+                       else
+                               yuv400raw_to_yuv400p(frame, frame->rawdata,
+                                                    frame->data);
+               }
+}
+
+/* Process raw YUV420 data into standard YUV420P */
+static void
+ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+       /* Deinterlace frame, if necessary */
+       if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
+               if (frame->compressed)
+                       decompress(ov, frame, frame->rawdata, frame->tempdata);
+               else
+                       yuv420raw_to_yuv420p(frame, frame->rawdata,
+                                            frame->tempdata);
+
+               deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
+                           frame->data);
+       } else {
+               if (frame->compressed)
+                       decompress(ov, frame, frame->rawdata, frame->data);
+               else
+                       yuv420raw_to_yuv420p(frame, frame->rawdata,
+                                            frame->data);
+       }
+}
+
+/* Post-processes the specified frame. This consists of:
+ *     1. Decompress frame, if necessary
+ *     2. Deinterlace frame and scale to proper size, if necessary
+ *     3. Convert from YUV planar to destination format, if necessary
+ *     4. Fix the RGB offset, if necessary
+ */
+static void
+ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
+{
+       if (dumppix) {
+               memset(frame->data, 0,
+                       MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+               PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
+               memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
+       } else {
+               switch (frame->format) {
+               case VIDEO_PALETTE_GREY:
+                       ov51x_postprocess_grey(ov, frame);
+                       break;
+               case VIDEO_PALETTE_YUV420:
+               case VIDEO_PALETTE_YUV420P:
+                       ov51x_postprocess_yuv420(ov, frame);
+                       break;
+               default:
+                       err("Cannot convert data to %s",
+                           symbolic(v4l1_plist, frame->format));
+               }
+       }
+}
+
+/**********************************************************************
+ *
+ * OV51x data transfer, IRQ handler
+ *
+ **********************************************************************/
+
+static inline void
+ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
+{
+       int num, offset;
+       int pnum = in[ov->packet_size - 1];             /* Get packet number */
+       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+       struct ov511_frame *frame = &ov->frame[ov->curframe];
+       struct timeval *ts;
+
+       /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+        * byte non-zero. The EOF packet has image width/height in the
+        * 10th and 11th bytes. The 9th byte is given as follows:
+        *
+        * bit 7: EOF
+        *     6: compression enabled
+        *     5: 422/420/400 modes
+        *     4: 422/420/400 modes
+        *     3: 1
+        *     2: snapshot button on
+        *     1: snapshot frame
+        *     0: even/odd field
+        */
+
+       if (printph) {
+               info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
+                    pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
+                    in[7], in[8], in[9], in[10], in[11]);
+       }
+
+       /* Check for SOF/EOF packet */
+       if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
+           (~in[8] & 0x08))
+               goto check_middle;
+
+       /* Frame end */
+       if (in[8] & 0x80) {
+               ts = (struct timeval *)(frame->data
+                     + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+               do_gettimeofday(ts);
+
+               /* Get the actual frame size from the EOF header */
+               frame->rawwidth = ((int)(in[9]) + 1) * 8;
+               frame->rawheight = ((int)(in[10]) + 1) * 8;
+
+               PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
+                       ov->curframe, pnum, frame->rawwidth, frame->rawheight,
+                       frame->bytes_recvd);
+
+               /* Validate the header data */
+               RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+               RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
+                                 ov->maxheight);
+
+               /* Don't allow byte count to exceed buffer size */
+               RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+               if (frame->scanstate == STATE_LINES) {
+                       int nextf;
+
+                       frame->grabstate = FRAME_DONE;
+                       wake_up_interruptible(&frame->wq);
+
+                       /* If next frame is ready or grabbing,
+                        * point to it */
+                       nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+                       if (ov->frame[nextf].grabstate == FRAME_READY
+                           || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+                               ov->curframe = nextf;
+                               ov->frame[nextf].scanstate = STATE_SCANNING;
+                       } else {
+                               if (frame->grabstate == FRAME_DONE) {
+                                       PDEBUG(4, "** Frame done **");
+                               } else {
+                                       PDEBUG(4, "Frame not ready? state = %d",
+                                               ov->frame[nextf].grabstate);
+                               }
+
+                               ov->curframe = -1;
+                       }
+               } else {
+                       PDEBUG(5, "Frame done, but not scanning");
+               }
+               /* Image corruption caused by misplaced frame->segment = 0
+                * fixed by carlosf@conectiva.com.br
+                */
+       } else {
+               /* Frame start */
+               PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+
+               /* Check to see if it's a snapshot frame */
+               /* FIXME?? Should the snapshot reset go here? Performance? */
+               if (in[8] & 0x02) {
+                       frame->snapshot = 1;
+                       PDEBUG(3, "snapshot detected");
+               }
+
+               frame->scanstate = STATE_LINES;
+               frame->bytes_recvd = 0;
+               frame->compressed = in[8] & 0x40;
+       }
+
+check_middle:
+       /* Are we in a frame? */
+       if (frame->scanstate != STATE_LINES) {
+               PDEBUG(5, "Not in a frame; packet skipped");
+               return;
+       }
+
+       /* If frame start, skip header */
+       if (frame->bytes_recvd == 0)
+               offset = 9;
+       else
+               offset = 0;
+
+       num = n - offset - 1;
+
+       /* Dump all data exactly as received */
+       if (dumppix == 2) {
+               frame->bytes_recvd += n - 1;
+               if (frame->bytes_recvd <= max_raw)
+                       memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
+                               in, n - 1);
+               else
+                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
+                               frame->bytes_recvd - max_raw);
+       } else if (!frame->compressed && !remove_zeros) {
+               frame->bytes_recvd += num;
+               if (frame->bytes_recvd <= max_raw)
+                       memcpy(frame->rawdata + frame->bytes_recvd - num,
+                               in + offset, num);
+               else
+                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
+                               frame->bytes_recvd - max_raw);
+       } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
+               int b, read = 0, allzero, copied = 0;
+               if (offset) {
+                       frame->bytes_recvd += 32 - offset;      // Bytes out
+                       memcpy(frame->rawdata,  in + offset, 32 - offset);
+                       read += 32;
+               }
+
+               while (read < n - 1) {
+                       allzero = 1;
+                       for (b = 0; b < 32; b++) {
+                               if (in[read + b]) {
+                                       allzero = 0;
+                                       break;
+                               }
+                       }
+
+                       if (allzero) {
+                               /* Don't copy it */
+                       } else {
+                               if (frame->bytes_recvd + copied + 32 <= max_raw)
+                               {
+                                       memcpy(frame->rawdata
+                                               + frame->bytes_recvd + copied,
+                                               in + read, 32);
+                                       copied += 32;
+                               } else {
+                                       PDEBUG(3, "Raw data buffer overrun!!");
+                               }
+                       }
+                       read += 32;
+               }
+
+               frame->bytes_recvd += copied;
+       }
+}
+
+static inline void
+ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
+{
+       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
+       struct ov511_frame *frame = &ov->frame[ov->curframe];
+       struct timeval *ts;
+
+       /* Don't copy the packet number byte */
+       if (ov->packet_numbering)
+               --n;
+
+       /* A false positive here is likely, until OVT gives me
+        * the definitive SOF/EOF format */
+       if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
+               if (printph) {
+                       info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
+                            in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
+               }
+
+               if (frame->scanstate == STATE_LINES) {
+                       PDEBUG(4, "Detected frame end/start");
+                       goto eof;
+               } else { //scanstate == STATE_SCANNING
+                       /* Frame start */
+                       PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
+                       goto sof;
+               }
+       } else {
+               goto check_middle;
+       }
+
+eof:
+       ts = (struct timeval *)(frame->data
+             + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
+       do_gettimeofday(ts);
+
+       PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
+               ov->curframe,
+               (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
+
+       // FIXME: Since we don't know the header formats yet,
+       // there is no way to know what the actual image size is
+       frame->rawwidth = frame->width;
+       frame->rawheight = frame->height;
+
+       /* Validate the header data */
+       RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
+       RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
+
+       /* Don't allow byte count to exceed buffer size */
+       RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
+
+       if (frame->scanstate == STATE_LINES) {
+               int nextf;
+
+               frame->grabstate = FRAME_DONE;
+               wake_up_interruptible(&frame->wq);
+
+               /* If next frame is ready or grabbing,
+                * point to it */
+               nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
+               if (ov->frame[nextf].grabstate == FRAME_READY
+                   || ov->frame[nextf].grabstate == FRAME_GRABBING) {
+                       ov->curframe = nextf;
+                       ov->frame[nextf].scanstate = STATE_SCANNING;
+                       frame = &ov->frame[nextf];
+               } else {
+                       if (frame->grabstate == FRAME_DONE) {
+                               PDEBUG(4, "** Frame done **");
+                       } else {
+                               PDEBUG(4, "Frame not ready? state = %d",
+                                      ov->frame[nextf].grabstate);
+                       }
+
+                       ov->curframe = -1;
+                       PDEBUG(4, "SOF dropped (no active frame)");
+                       return;  /* Nowhere to store this frame */
+               }
+       }
+sof:
+       PDEBUG(4, "Starting capture on frame %d", frame->framenum);
+
+// Snapshot not reverse-engineered yet.
+#if 0
+       /* Check to see if it's a snapshot frame */
+       /* FIXME?? Should the snapshot reset go here? Performance? */
+       if (in[8] & 0x02) {
+               frame->snapshot = 1;
+               PDEBUG(3, "snapshot detected");
+       }
+#endif
+       frame->scanstate = STATE_LINES;
+       frame->bytes_recvd = 0;
+       frame->compressed = 1;
+
+check_middle:
+       /* Are we in a frame? */
+       if (frame->scanstate != STATE_LINES) {
+               PDEBUG(4, "scanstate: no SOF yet");
+               return;
+       }
+
+       /* Dump all data exactly as received */
+       if (dumppix == 2) {
+               frame->bytes_recvd += n;
+               if (frame->bytes_recvd <= max_raw)
+                       memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
+               else
+                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
+                               frame->bytes_recvd - max_raw);
+       } else {
+               /* All incoming data are divided into 8-byte segments. If the
+                * segment contains all zero bytes, it must be skipped. These
+                * zero-segments allow the OV518 to mainain a constant data rate
+                * regardless of the effectiveness of the compression. Segments
+                * are aligned relative to the beginning of each isochronous
+                * packet. The first segment in each image is a header (the
+                * decompressor skips it later).
+                */
+
+               int b, read = 0, allzero, copied = 0;
+
+               while (read < n) {
+                       allzero = 1;
+                       for (b = 0; b < 8; b++) {
+                               if (in[read + b]) {
+                                       allzero = 0;
+                                       break;
+                               }
+                       }
+
+                       if (allzero) {
+                       /* Don't copy it */
+                       } else {
+                               if (frame->bytes_recvd + copied + 8 <= max_raw)
+                               {
+                                       memcpy(frame->rawdata
+                                               + frame->bytes_recvd + copied,
+                                               in + read, 8);
+                                       copied += 8;
+                               } else {
+                                       PDEBUG(3, "Raw data buffer overrun!!");
+                               }
+                       }
+                       read += 8;
+               }
+               frame->bytes_recvd += copied;
+       }
+}
+
+static void
+ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+       int i;
+       struct usb_ov511 *ov;
+       struct ov511_sbuf *sbuf;
+
+       if (!urb->context) {
+               PDEBUG(4, "no context");
+               return;
+       }
+
+       sbuf = urb->context;
+       ov = sbuf->ov;
+
+       if (!ov || !ov->dev || !ov->user) {
+               PDEBUG(4, "no device, or not open");
+               return;
+       }
+
+       if (!ov->streaming) {
+               PDEBUG(4, "hmmm... not streaming, but got interrupt");
+               return;
+       }
+
+        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+                PDEBUG(4, "URB unlinked");
+                return;
+        }
+
+       if (urb->status != -EINPROGRESS && urb->status != 0) {
+               err("ERROR: urb->status=%d: %s", urb->status,
+                   symbolic(urb_errlist, urb->status));
+       }
+
+       /* Copy the data received into our frame buffer */
+       PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
+              urb->number_of_packets);
+       for (i = 0; i < urb->number_of_packets; i++) {
+               /* Warning: Don't call *_move_data() if no frame active! */
+               if (ov->curframe >= 0) {
+                       int n = urb->iso_frame_desc[i].actual_length;
+                       int st = urb->iso_frame_desc[i].status;
+                       unsigned char *cdata;
+
+                       urb->iso_frame_desc[i].actual_length = 0;
+                       urb->iso_frame_desc[i].status = 0;
+
+                       cdata = urb->transfer_buffer
+                               + urb->iso_frame_desc[i].offset;
+
+                       if (!n) {
+                               PDEBUG(4, "Zero-length packet");
+                               continue;
+                       }
+
+                       if (st)
+                               PDEBUG(2, "data error: [%d] len=%d, status=%d",
+                                      i, n, st);
+
+                       if (ov->bclass == BCL_OV511)
+                               ov511_move_data(ov, cdata, n);
+                       else if (ov->bclass == BCL_OV518)
+                               ov518_move_data(ov, cdata, n);
+                       else
+                               err("Unknown bridge device (%d)", ov->bridge);
+
+               } else if (waitqueue_active(&ov->wq)) {
+                       wake_up_interruptible(&ov->wq);
+               }
+       }
+
+       /* Resubmit this URB */
+       urb->dev = ov->dev;
+       if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+               err("usb_submit_urb() ret %d", i);
+
+       return;
+}
+
+/****************************************************************************
+ *
+ * Stream initialization and termination
+ *
+ ***************************************************************************/
+
+static int
+ov51x_init_isoc(struct usb_ov511 *ov)
+{
+       struct urb *urb;
+       int fx, err, n, size;
+
+       PDEBUG(3, "*** Initializing capture ***");
+
+       ov->curframe = -1;
+
+       if (ov->bridge == BRG_OV511) {
+               if (cams == 1)
+                       size = 993;
+               else if (cams == 2)
+                       size = 513;
+               else if (cams == 3 || cams == 4)
+                       size = 257;
+               else {
+                       err("\"cams\" parameter too high!");
+                       return -1;
+               }
+       } else if (ov->bridge == BRG_OV511PLUS) {
+               if (cams == 1)
+                       size = 961;
+               else if (cams == 2)
+                       size = 513;
+               else if (cams == 3 || cams == 4)
+                       size = 257;
+               else if (cams >= 5 && cams <= 8)
+                       size = 129;
+               else if (cams >= 9 && cams <= 31)
+                       size = 33;
+               else {
+                       err("\"cams\" parameter too high!");
+                       return -1;
+               }
+       } else if (ov->bclass == BCL_OV518) {
+               if (cams == 1)
+                       size = 896;
+               else if (cams == 2)
+                       size = 512;
+               else if (cams == 3 || cams == 4)
+                       size = 256;
+               else if (cams >= 5 && cams <= 8)
+                       size = 128;
+               else {
+                       err("\"cams\" parameter too high!");
+                       return -1;
+               }
+       } else {
+               err("invalid bridge type");
+               return -1;
+       }
+
+       // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
+       if (ov->bclass == BCL_OV518) {
+               if (packetsize == -1) {
+                       ov518_set_packet_size(ov, 640);
+               } else {
+                       info("Forcing packet size to %d", packetsize);
+                       ov518_set_packet_size(ov, packetsize);
+               }
+       } else {
+               if (packetsize == -1) {
+                       ov511_set_packet_size(ov, size);
+               } else {
+                       info("Forcing packet size to %d", packetsize);
+                       ov511_set_packet_size(ov, packetsize);
+               }
+       }
+
+       for (n = 0; n < OV511_NUMSBUF; n++) {
+               urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+               if (!urb) {
+                       err("init isoc: usb_alloc_urb ret. NULL");
+                       return -ENOMEM;
+               }
+               ov->sbuf[n].urb = urb;
+               urb->dev = ov->dev;
+               urb->context = &ov->sbuf[n];
+               urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = ov->sbuf[n].data;
+               urb->complete = ov51x_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
+               urb->interval = 1;
+               for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+                       urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
+                       urb->iso_frame_desc[fx].length = ov->packet_size;
+               }
+       }
+
+       ov->streaming = 1;
+
+       for (n = 0; n < OV511_NUMSBUF; n++) {
+               ov->sbuf[n].urb->dev = ov->dev;
+               err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
+               if (err) {
+                       err("init isoc: usb_submit_urb(%d) ret %d", n, err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static void
+ov51x_unlink_isoc(struct usb_ov511 *ov)
+{
+       int n;
+
+       /* Unschedule all of the iso td's */
+       for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
+               if (ov->sbuf[n].urb) {
+                       usb_kill_urb(ov->sbuf[n].urb);
+                       usb_free_urb(ov->sbuf[n].urb);
+                       ov->sbuf[n].urb = NULL;
+               }
+       }
+}
+
+static void
+ov51x_stop_isoc(struct usb_ov511 *ov)
+{
+       if (!ov->streaming || !ov->dev)
+               return;
+
+       PDEBUG(3, "*** Stopping capture ***");
+
+       if (ov->bclass == BCL_OV518)
+               ov518_set_packet_size(ov, 0);
+       else
+               ov511_set_packet_size(ov, 0);
+
+       ov->streaming = 0;
+
+       ov51x_unlink_isoc(ov);
+}
+
+static int
+ov51x_new_frame(struct usb_ov511 *ov, int framenum)
+{
+       struct ov511_frame *frame;
+       int newnum;
+
+       PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
+
+       if (!ov->dev)
+               return -1;
+
+       /* If we're not grabbing a frame right now and the other frame is */
+       /* ready to be grabbed into, then use it instead */
+       if (ov->curframe == -1) {
+               newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
+               if (ov->frame[newnum].grabstate == FRAME_READY)
+                       framenum = newnum;
+       } else
+               return 0;
+
+       frame = &ov->frame[framenum];
+
+       PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
+              frame->width, frame->height);
+
+       frame->grabstate = FRAME_GRABBING;
+       frame->scanstate = STATE_SCANNING;
+       frame->snapshot = 0;
+
+       ov->curframe = framenum;
+
+       /* Make sure it's not too big */
+       if (frame->width > ov->maxwidth)
+               frame->width = ov->maxwidth;
+
+       frame->width &= ~7L;            /* Multiple of 8 */
+
+       if (frame->height > ov->maxheight)
+               frame->height = ov->maxheight;
+
+       frame->height &= ~3L;           /* Multiple of 4 */
+
+       return 0;
+}
+
+/****************************************************************************
+ *
+ * Buffer management
+ *
+ ***************************************************************************/
+
+/*
+ * - You must acquire buf_lock before entering this function.
+ * - Because this code will free any non-null pointer, you must be sure to null
+ *   them if you explicitly free them somewhere else!
+ */
+static void
+ov51x_do_dealloc(struct usb_ov511 *ov)
+{
+       int i;
+       PDEBUG(4, "entered");
+
+       if (ov->fbuf) {
+               rvfree(ov->fbuf, OV511_NUMFRAMES
+                      * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
+               ov->fbuf = NULL;
+       }
+
+       vfree(ov->rawfbuf);
+       ov->rawfbuf = NULL;
+
+       vfree(ov->tempfbuf);
+       ov->tempfbuf = NULL;
+
+       for (i = 0; i < OV511_NUMSBUF; i++) {
+               kfree(ov->sbuf[i].data);
+               ov->sbuf[i].data = NULL;
+       }
+
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].data = NULL;
+               ov->frame[i].rawdata = NULL;
+               ov->frame[i].tempdata = NULL;
+               if (ov->frame[i].compbuf) {
+                       free_page((unsigned long) ov->frame[i].compbuf);
+                       ov->frame[i].compbuf = NULL;
+               }
+       }
+
+       PDEBUG(4, "buffer memory deallocated");
+       ov->buf_state = BUF_NOT_ALLOCATED;
+       PDEBUG(4, "leaving");
+}
+
+static int
+ov51x_alloc(struct usb_ov511 *ov)
+{
+       int i;
+       const int w = ov->maxwidth;
+       const int h = ov->maxheight;
+       const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
+       const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
+
+       PDEBUG(4, "entered");
+       mutex_lock(&ov->buf_lock);
+
+       if (ov->buf_state == BUF_ALLOCATED)
+               goto out;
+
+       ov->fbuf = rvmalloc(data_bufsize);
+       if (!ov->fbuf)
+               goto error;
+
+       ov->rawfbuf = vmalloc(raw_bufsize);
+       if (!ov->rawfbuf)
+               goto error;
+
+       memset(ov->rawfbuf, 0, raw_bufsize);
+
+       ov->tempfbuf = vmalloc(raw_bufsize);
+       if (!ov->tempfbuf)
+               goto error;
+
+       memset(ov->tempfbuf, 0, raw_bufsize);
+
+       for (i = 0; i < OV511_NUMSBUF; i++) {
+               ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+                       MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+               if (!ov->sbuf[i].data)
+                       goto error;
+
+               PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
+       }
+
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
+               ov->frame[i].rawdata = ov->rawfbuf
+                + i * MAX_RAW_DATA_SIZE(w, h);
+               ov->frame[i].tempdata = ov->tempfbuf
+                + i * MAX_RAW_DATA_SIZE(w, h);
+
+               ov->frame[i].compbuf =
+                (unsigned char *) __get_free_page(GFP_KERNEL);
+               if (!ov->frame[i].compbuf)
+                       goto error;
+
+               PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
+       }
+
+       ov->buf_state = BUF_ALLOCATED;
+out:
+       mutex_unlock(&ov->buf_lock);
+       PDEBUG(4, "leaving");
+       return 0;
+error:
+       ov51x_do_dealloc(ov);
+       mutex_unlock(&ov->buf_lock);
+       PDEBUG(4, "errored");
+       return -ENOMEM;
+}
+
+static void
+ov51x_dealloc(struct usb_ov511 *ov)
+{
+       PDEBUG(4, "entered");
+       mutex_lock(&ov->buf_lock);
+       ov51x_do_dealloc(ov);
+       mutex_unlock(&ov->buf_lock);
+       PDEBUG(4, "leaving");
+}
+
+/****************************************************************************
+ *
+ * V4L 1 API
+ *
+ ***************************************************************************/
+
+static int
+ov51x_v4l1_open(struct inode *inode, struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       int err, i;
+
+       PDEBUG(4, "opening");
+
+       mutex_lock(&ov->lock);
+
+       err = -EBUSY;
+       if (ov->user)
+               goto out;
+
+       ov->sub_flag = 0;
+
+       /* In case app doesn't set them... */
+       err = ov51x_set_default_params(ov);
+       if (err < 0)
+               goto out;
+
+       /* Make sure frames are reset */
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].grabstate = FRAME_UNUSED;
+               ov->frame[i].bytes_read = 0;
+       }
+
+       /* If compression is on, make sure now that a
+        * decompressor can be loaded */
+       if (ov->compress && !ov->decomp_ops) {
+               err = request_decompressor(ov);
+               if (err && !dumppix)
+                       goto out;
+       }
+
+       err = ov51x_alloc(ov);
+       if (err < 0)
+               goto out;
+
+       err = ov51x_init_isoc(ov);
+       if (err) {
+               ov51x_dealloc(ov);
+               goto out;
+       }
+
+       ov->user++;
+       file->private_data = vdev;
+
+       if (ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 1);
+
+out:
+       mutex_unlock(&ov->lock);
+       return err;
+}
+
+static int
+ov51x_v4l1_close(struct inode *inode, struct file *file)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+
+       PDEBUG(4, "ov511_close");
+
+       mutex_lock(&ov->lock);
+
+       ov->user--;
+       ov51x_stop_isoc(ov);
+
+       if (ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 0);
+
+       if (ov->dev)
+               ov51x_dealloc(ov);
+
+       mutex_unlock(&ov->lock);
+
+       /* Device unplugged while open. Only a minimum of unregistration is done
+        * here; the disconnect callback already did the rest. */
+       if (!ov->dev) {
+               mutex_lock(&ov->cbuf_lock);
+               kfree(ov->cbuf);
+               ov->cbuf = NULL;
+               mutex_unlock(&ov->cbuf_lock);
+
+               ov51x_dealloc(ov);
+               kfree(ov);
+               ov = NULL;
+       }
+
+       file->private_data = NULL;
+       return 0;
+}
+
+/* Do not call this function directly! */
+static int
+ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
+                         unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       PDEBUG(5, "IOCtl: 0x%X", cmd);
+
+       if (!ov->dev)
+               return -EIO;
+
+       switch (cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability *b = arg;
+
+               PDEBUG(4, "VIDIOCGCAP");
+
+               memset(b, 0, sizeof(struct video_capability));
+               sprintf(b->name, "%s USB Camera",
+                       symbolic(brglist, ov->bridge));
+               b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+               b->channels = ov->num_inputs;
+               b->audios = 0;
+               b->maxwidth = ov->maxwidth;
+               b->maxheight = ov->maxheight;
+               b->minwidth = ov->minwidth;
+               b->minheight = ov->minheight;
+
+               return 0;
+       }
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *v = arg;
+
+               PDEBUG(4, "VIDIOCGCHAN");
+
+               if ((unsigned)(v->channel) >= ov->num_inputs) {
+                       err("Invalid channel (%d)", v->channel);
+                       return -EINVAL;
+               }
+
+               v->norm = ov->norm;
+               v->type = VIDEO_TYPE_CAMERA;
+               v->flags = 0;
+//             v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
+               v->tuners = 0;
+               decoder_get_input_name(ov, v->channel, v->name);
+
+               return 0;
+       }
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *v = arg;
+               int err;
+
+               PDEBUG(4, "VIDIOCSCHAN");
+
+               /* Make sure it's not a camera */
+               if (!ov->has_decoder) {
+                       if (v->channel == 0)
+                               return 0;
+                       else
+                               return -EINVAL;
+               }
+
+               if (v->norm != VIDEO_MODE_PAL &&
+                   v->norm != VIDEO_MODE_NTSC &&
+                   v->norm != VIDEO_MODE_SECAM &&
+                   v->norm != VIDEO_MODE_AUTO) {
+                       err("Invalid norm (%d)", v->norm);
+                       return -EINVAL;
+               }
+
+               if ((unsigned)(v->channel) >= ov->num_inputs) {
+                       err("Invalid channel (%d)", v->channel);
+                       return -EINVAL;
+               }
+
+               err = decoder_set_input(ov, v->channel);
+               if (err)
+                       return err;
+
+               err = decoder_set_norm(ov, v->norm);
+               if (err)
+                       return err;
+
+               return 0;
+       }
+       case VIDIOCGPICT:
+       {
+               struct video_picture *p = arg;
+
+               PDEBUG(4, "VIDIOCGPICT");
+
+               memset(p, 0, sizeof(struct video_picture));
+               if (sensor_get_picture(ov, p))
+                       return -EIO;
+
+               /* Can we get these from frame[0]? -claudio? */
+               p->depth = ov->frame[0].depth;
+               p->palette = ov->frame[0].format;
+
+               return 0;
+       }
+       case VIDIOCSPICT:
+       {
+               struct video_picture *p = arg;
+               int i, rc;
+
+               PDEBUG(4, "VIDIOCSPICT");
+
+               if (!get_depth(p->palette))
+                       return -EINVAL;
+
+               if (sensor_set_picture(ov, p))
+                       return -EIO;
+
+               if (force_palette && p->palette != force_palette) {
+                       info("Palette rejected (%s)",
+                            symbolic(v4l1_plist, p->palette));
+                       return -EINVAL;
+               }
+
+               // FIXME: Format should be independent of frames
+               if (p->palette != ov->frame[0].format) {
+                       PDEBUG(4, "Detected format change");
+
+                       rc = ov51x_wait_frames_inactive(ov);
+                       if (rc)
+                               return rc;
+
+                       mode_init_regs(ov, ov->frame[0].width,
+                               ov->frame[0].height, p->palette, ov->sub_flag);
+               }
+
+               PDEBUG(4, "Setting depth=%d, palette=%s",
+                      p->depth, symbolic(v4l1_plist, p->palette));
+
+               for (i = 0; i < OV511_NUMFRAMES; i++) {
+                       ov->frame[i].depth = p->depth;
+                       ov->frame[i].format = p->palette;
+               }
+
+               return 0;
+       }
+       case VIDIOCGCAPTURE:
+       {
+               int *vf = arg;
+
+               PDEBUG(4, "VIDIOCGCAPTURE");
+
+               ov->sub_flag = *vf;
+               return 0;
+       }
+       case VIDIOCSCAPTURE:
+       {
+               struct video_capture *vc = arg;
+
+               PDEBUG(4, "VIDIOCSCAPTURE");
+
+               if (vc->flags)
+                       return -EINVAL;
+               if (vc->decimation)
+                       return -EINVAL;
+
+               vc->x &= ~3L;
+               vc->y &= ~1L;
+               vc->y &= ~31L;
+
+               if (vc->width == 0)
+                       vc->width = 32;
+
+               vc->height /= 16;
+               vc->height *= 16;
+               if (vc->height == 0)
+                       vc->height = 16;
+
+               ov->subx = vc->x;
+               ov->suby = vc->y;
+               ov->subw = vc->width;
+               ov->subh = vc->height;
+
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window *vw = arg;
+               int i, rc;
+
+               PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
+
+#if 0
+               if (vw->flags)
+                       return -EINVAL;
+               if (vw->clipcount)
+                       return -EINVAL;
+               if (vw->height != ov->maxheight)
+                       return -EINVAL;
+               if (vw->width != ov->maxwidth)
+                       return -EINVAL;
+#endif
+
+               rc = ov51x_wait_frames_inactive(ov);
+               if (rc)
+                       return rc;
+
+               rc = mode_init_regs(ov, vw->width, vw->height,
+                       ov->frame[0].format, ov->sub_flag);
+               if (rc < 0)
+                       return rc;
+
+               for (i = 0; i < OV511_NUMFRAMES; i++) {
+                       ov->frame[i].width = vw->width;
+                       ov->frame[i].height = vw->height;
+               }
+
+               return 0;
+       }
+       case VIDIOCGWIN:
+       {
+               struct video_window *vw = arg;
+
+               memset(vw, 0, sizeof(struct video_window));
+               vw->x = 0;              /* FIXME */
+               vw->y = 0;
+               vw->width = ov->frame[0].width;
+               vw->height = ov->frame[0].height;
+               vw->flags = 30;
+
+               PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
+
+               return 0;
+       }
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *vm = arg;
+               int i;
+
+               PDEBUG(4, "VIDIOCGMBUF");
+
+               memset(vm, 0, sizeof(struct video_mbuf));
+               vm->size = OV511_NUMFRAMES
+                          * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+               vm->frames = OV511_NUMFRAMES;
+
+               vm->offsets[0] = 0;
+               for (i = 1; i < OV511_NUMFRAMES; i++) {
+                       vm->offsets[i] = vm->offsets[i-1]
+                          + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
+               }
+
+               return 0;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *vm = arg;
+               int rc, depth;
+               unsigned int f = vm->frame;
+
+               PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
+                       vm->height, symbolic(v4l1_plist, vm->format));
+
+               depth = get_depth(vm->format);
+               if (!depth) {
+                       PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
+                              symbolic(v4l1_plist, vm->format));
+                       return -EINVAL;
+               }
+
+               if (f >= OV511_NUMFRAMES) {
+                       err("VIDIOCMCAPTURE: invalid frame (%d)", f);
+                       return -EINVAL;
+               }
+
+               if (vm->width > ov->maxwidth
+                   || vm->height > ov->maxheight) {
+                       err("VIDIOCMCAPTURE: requested dimensions too big");
+                       return -EINVAL;
+               }
+
+               if (ov->frame[f].grabstate == FRAME_GRABBING) {
+                       PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
+                       return -EBUSY;
+               }
+
+               if (force_palette && (vm->format != force_palette)) {
+                       PDEBUG(2, "palette rejected (%s)",
+                              symbolic(v4l1_plist, vm->format));
+                       return -EINVAL;
+               }
+
+               if ((ov->frame[f].width != vm->width) ||
+                   (ov->frame[f].height != vm->height) ||
+                   (ov->frame[f].format != vm->format) ||
+                   (ov->frame[f].sub_flag != ov->sub_flag) ||
+                   (ov->frame[f].depth != depth)) {
+                       PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
+
+                       rc = ov51x_wait_frames_inactive(ov);
+                       if (rc)
+                               return rc;
+
+                       rc = mode_init_regs(ov, vm->width, vm->height,
+                               vm->format, ov->sub_flag);
+#if 0
+                       if (rc < 0) {
+                               PDEBUG(1, "Got error while initializing regs ");
+                               return ret;
+                       }
+#endif
+                       ov->frame[f].width = vm->width;
+                       ov->frame[f].height = vm->height;
+                       ov->frame[f].format = vm->format;
+                       ov->frame[f].sub_flag = ov->sub_flag;
+                       ov->frame[f].depth = depth;
+               }
+
+               /* Mark it as ready */
+               ov->frame[f].grabstate = FRAME_READY;
+
+               PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
+
+               return ov51x_new_frame(ov, f);
+       }
+       case VIDIOCSYNC:
+       {
+               unsigned int fnum = *((unsigned int *) arg);
+               struct ov511_frame *frame;
+               int rc;
+
+               if (fnum >= OV511_NUMFRAMES) {
+                       err("VIDIOCSYNC: invalid frame (%d)", fnum);
+                       return -EINVAL;
+               }
+
+               frame = &ov->frame[fnum];
+
+               PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
+                      frame->grabstate);
+
+               switch (frame->grabstate) {
+               case FRAME_UNUSED:
+                       return -EINVAL;
+               case FRAME_READY:
+               case FRAME_GRABBING:
+               case FRAME_ERROR:
+redo:
+                       if (!ov->dev)
+                               return -EIO;
+
+                       rc = wait_event_interruptible(frame->wq,
+                           (frame->grabstate == FRAME_DONE)
+                           || (frame->grabstate == FRAME_ERROR));
+
+                       if (rc)
+                               return rc;
+
+                       if (frame->grabstate == FRAME_ERROR) {
+                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
+                                       return rc;
+                               goto redo;
+                       }
+                       /* Fall through */
+               case FRAME_DONE:
+                       if (ov->snap_enabled && !frame->snapshot) {
+                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
+                                       return rc;
+                               goto redo;
+                       }
+
+                       frame->grabstate = FRAME_UNUSED;
+
+                       /* Reset the hardware snapshot button */
+                       /* FIXME - Is this the best place for this? */
+                       if ((ov->snap_enabled) && (frame->snapshot)) {
+                               frame->snapshot = 0;
+                               ov51x_clear_snapshot(ov);
+                       }
+
+                       /* Decompression, format conversion, etc... */
+                       ov51x_postprocess(ov, frame);
+
+                       break;
+               } /* end switch */
+
+               return 0;
+       }
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer *vb = arg;
+
+               PDEBUG(4, "VIDIOCGFBUF");
+
+               memset(vb, 0, sizeof(struct video_buffer));
+
+               return 0;
+       }
+       case VIDIOCGUNIT:
+       {
+               struct video_unit *vu = arg;
+
+               PDEBUG(4, "VIDIOCGUNIT");
+
+               memset(vu, 0, sizeof(struct video_unit));
+
+               vu->video = ov->vdev->minor;
+               vu->vbi = VIDEO_NO_UNIT;
+               vu->radio = VIDEO_NO_UNIT;
+               vu->audio = VIDEO_NO_UNIT;
+               vu->teletext = VIDEO_NO_UNIT;
+
+               return 0;
+       }
+       case OV511IOC_WI2C:
+       {
+               struct ov511_i2c_struct *w = arg;
+
+               return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
+       }
+       case OV511IOC_RI2C:
+       {
+               struct ov511_i2c_struct *r = arg;
+               int rc;
+
+               rc = i2c_r_slave(ov, r->slave, r->reg);
+               if (rc < 0)
+                       return rc;
+
+               r->value = rc;
+               return 0;
+       }
+       default:
+               PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
+               return -ENOIOCTLCMD;
+       } /* end switch */
+
+       return 0;
+}
+
+static int
+ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
+                unsigned int cmd, unsigned long arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       int rc;
+
+       if (mutex_lock_interruptible(&ov->lock))
+               return -EINTR;
+
+       rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
+
+       mutex_unlock(&ov->lock);
+       return rc;
+}
+
+static ssize_t
+ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
+{
+       struct video_device *vdev = file->private_data;
+       int noblock = file->f_flags&O_NONBLOCK;
+       unsigned long count = cnt;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       int i, rc = 0, frmx = -1;
+       struct ov511_frame *frame;
+
+       if (mutex_lock_interruptible(&ov->lock))
+               return -EINTR;
+
+       PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
+
+       if (!vdev || !buf) {
+               rc = -EFAULT;
+               goto error;
+       }
+
+       if (!ov->dev) {
+               rc = -EIO;
+               goto error;
+       }
+
+// FIXME: Only supports two frames
+       /* See if a frame is completed, then use it. */
+       if (ov->frame[0].grabstate >= FRAME_DONE)       /* _DONE or _ERROR */
+               frmx = 0;
+       else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
+               frmx = 1;
+
+       /* If nonblocking we return immediately */
+       if (noblock && (frmx == -1)) {
+               rc = -EAGAIN;
+               goto error;
+       }
+
+       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
+       /* See if a frame is in process (grabbing), then use it. */
+       if (frmx == -1) {
+               if (ov->frame[0].grabstate == FRAME_GRABBING)
+                       frmx = 0;
+               else if (ov->frame[1].grabstate == FRAME_GRABBING)
+                       frmx = 1;
+       }
+
+       /* If no frame is active, start one. */
+       if (frmx == -1) {
+               if ((rc = ov51x_new_frame(ov, frmx = 0))) {
+                       err("read: ov51x_new_frame error");
+                       goto error;
+               }
+       }
+
+       frame = &ov->frame[frmx];
+
+restart:
+       if (!ov->dev) {
+               rc = -EIO;
+               goto error;
+       }
+
+       /* Wait while we're grabbing the image */
+       PDEBUG(4, "Waiting image grabbing");
+       rc = wait_event_interruptible(frame->wq,
+               (frame->grabstate == FRAME_DONE)
+               || (frame->grabstate == FRAME_ERROR));
+
+       if (rc)
+               goto error;
+
+       PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
+       PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
+
+       if (frame->grabstate == FRAME_ERROR) {
+               frame->bytes_read = 0;
+               err("** ick! ** Errored frame %d", ov->curframe);
+               if (ov51x_new_frame(ov, frmx)) {
+                       err("read: ov51x_new_frame error");
+                       goto error;
+               }
+               goto restart;
+       }
+
+
+       /* Repeat until we get a snapshot frame */
+       if (ov->snap_enabled)
+               PDEBUG(4, "Waiting snapshot frame");
+       if (ov->snap_enabled && !frame->snapshot) {
+               frame->bytes_read = 0;
+               if ((rc = ov51x_new_frame(ov, frmx))) {
+                       err("read: ov51x_new_frame error");
+                       goto error;
+               }
+               goto restart;
+       }
+
+       /* Clear the snapshot */
+       if (ov->snap_enabled && frame->snapshot) {
+               frame->snapshot = 0;
+               ov51x_clear_snapshot(ov);
+       }
+
+       /* Decompression, format conversion, etc... */
+       ov51x_postprocess(ov, frame);
+
+       PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
+               frame->bytes_read,
+               get_frame_length(frame));
+
+       /* copy bytes to user space; we allow for partials reads */
+//     if ((count + frame->bytes_read)
+//         > get_frame_length((struct ov511_frame *)frame))
+//             count = frame->scanlength - frame->bytes_read;
+
+       /* FIXME - count hardwired to be one frame... */
+       count = get_frame_length(frame);
+
+       PDEBUG(4, "Copy to user space: %ld bytes", count);
+       if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
+               PDEBUG(4, "Copy failed! %d bytes not copied", i);
+               rc = -EFAULT;
+               goto error;
+       }
+
+       frame->bytes_read += count;
+       PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
+               count, frame->bytes_read);
+
+       /* If all data have been read... */
+       if (frame->bytes_read
+           >= get_frame_length(frame)) {
+               frame->bytes_read = 0;
+
+// FIXME: Only supports two frames
+               /* Mark it as available to be used again. */
+               ov->frame[frmx].grabstate = FRAME_UNUSED;
+               if ((rc = ov51x_new_frame(ov, !frmx))) {
+                       err("ov51x_new_frame returned error");
+                       goto error;
+               }
+       }
+
+       PDEBUG(4, "read finished, returning %ld (sweet)", count);
+
+       mutex_unlock(&ov->lock);
+       return count;
+
+error:
+       mutex_unlock(&ov->lock);
+       return rc;
+}
+
+static int
+ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = file->private_data;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end - vma->vm_start;
+       struct usb_ov511 *ov = video_get_drvdata(vdev);
+       unsigned long page, pos;
+
+       if (ov->dev == NULL)
+               return -EIO;
+
+       PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
+
+       if (size > (((OV511_NUMFRAMES
+                     * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
+                     + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&ov->lock))
+               return -EINTR;
+
+       pos = (unsigned long)ov->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       mutex_unlock(&ov->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       mutex_unlock(&ov->lock);
+       return 0;
+}
+
+static struct file_operations ov511_fops = {
+       .owner =        THIS_MODULE,
+       .open =         ov51x_v4l1_open,
+       .release =      ov51x_v4l1_close,
+       .read =         ov51x_v4l1_read,
+       .mmap =         ov51x_v4l1_mmap,
+       .ioctl =        ov51x_v4l1_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+
+static struct video_device vdev_template = {
+       .owner =        THIS_MODULE,
+       .name =         "OV511 USB Camera",
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_OV511,
+       .fops =         &ov511_fops,
+       .release =      video_device_release,
+       .minor =        -1,
+};
+
+/****************************************************************************
+ *
+ * OV511 and sensor configuration
+ *
+ ***************************************************************************/
+
+/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
+ * the same register settings as the OV7610, since they are very similar.
+ */
+static int
+ov7xx0_configure(struct usb_ov511 *ov)
+{
+       int i, success;
+       int rc;
+
+       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
+        *
+        * Register 0x0f in the 7610 has the following effects:
+        *
+        * 0x85 (AEC method 1): Best overall, good contrast range
+        * 0x45 (AEC method 2): Very overexposed
+        * 0xa5 (spec sheet default): Ok, but the black level is
+        *      shifted resulting in loss of contrast
+        * 0x05 (old driver setting): very overexposed, too much
+        *      contrast
+        */
+       static struct ov511_regvals aRegvalsNorm7610[] = {
+               { OV511_I2C_BUS, 0x10, 0xff },
+               { OV511_I2C_BUS, 0x16, 0x06 },
+               { OV511_I2C_BUS, 0x28, 0x24 },
+               { OV511_I2C_BUS, 0x2b, 0xac },
+               { OV511_I2C_BUS, 0x12, 0x00 },
+               { OV511_I2C_BUS, 0x38, 0x81 },
+               { OV511_I2C_BUS, 0x28, 0x24 },  /* 0c */
+               { OV511_I2C_BUS, 0x0f, 0x85 },  /* lg's setting */
+               { OV511_I2C_BUS, 0x15, 0x01 },
+               { OV511_I2C_BUS, 0x20, 0x1c },
+               { OV511_I2C_BUS, 0x23, 0x2a },
+               { OV511_I2C_BUS, 0x24, 0x10 },
+               { OV511_I2C_BUS, 0x25, 0x8a },
+               { OV511_I2C_BUS, 0x26, 0xa2 },
+               { OV511_I2C_BUS, 0x27, 0xc2 },
+               { OV511_I2C_BUS, 0x2a, 0x04 },
+               { OV511_I2C_BUS, 0x2c, 0xfe },
+               { OV511_I2C_BUS, 0x2d, 0x93 },
+               { OV511_I2C_BUS, 0x30, 0x71 },
+               { OV511_I2C_BUS, 0x31, 0x60 },
+               { OV511_I2C_BUS, 0x32, 0x26 },
+               { OV511_I2C_BUS, 0x33, 0x20 },
+               { OV511_I2C_BUS, 0x34, 0x48 },
+               { OV511_I2C_BUS, 0x12, 0x24 },
+               { OV511_I2C_BUS, 0x11, 0x01 },
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0d, 0x24 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       static struct ov511_regvals aRegvalsNorm7620[] = {
+               { OV511_I2C_BUS, 0x00, 0x00 },
+               { OV511_I2C_BUS, 0x01, 0x80 },
+               { OV511_I2C_BUS, 0x02, 0x80 },
+               { OV511_I2C_BUS, 0x03, 0xc0 },
+               { OV511_I2C_BUS, 0x06, 0x60 },
+               { OV511_I2C_BUS, 0x07, 0x00 },
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0d, 0x24 },
+               { OV511_I2C_BUS, 0x11, 0x01 },
+               { OV511_I2C_BUS, 0x12, 0x24 },
+               { OV511_I2C_BUS, 0x13, 0x01 },
+               { OV511_I2C_BUS, 0x14, 0x84 },
+               { OV511_I2C_BUS, 0x15, 0x01 },
+               { OV511_I2C_BUS, 0x16, 0x03 },
+               { OV511_I2C_BUS, 0x17, 0x2f },
+               { OV511_I2C_BUS, 0x18, 0xcf },
+               { OV511_I2C_BUS, 0x19, 0x06 },
+               { OV511_I2C_BUS, 0x1a, 0xf5 },
+               { OV511_I2C_BUS, 0x1b, 0x00 },
+               { OV511_I2C_BUS, 0x20, 0x18 },
+               { OV511_I2C_BUS, 0x21, 0x80 },
+               { OV511_I2C_BUS, 0x22, 0x80 },
+               { OV511_I2C_BUS, 0x23, 0x00 },
+               { OV511_I2C_BUS, 0x26, 0xa2 },
+               { OV511_I2C_BUS, 0x27, 0xea },
+               { OV511_I2C_BUS, 0x28, 0x20 },
+               { OV511_I2C_BUS, 0x29, 0x00 },
+               { OV511_I2C_BUS, 0x2a, 0x10 },
+               { OV511_I2C_BUS, 0x2b, 0x00 },
+               { OV511_I2C_BUS, 0x2c, 0x88 },
+               { OV511_I2C_BUS, 0x2d, 0x91 },
+               { OV511_I2C_BUS, 0x2e, 0x80 },
+               { OV511_I2C_BUS, 0x2f, 0x44 },
+               { OV511_I2C_BUS, 0x60, 0x27 },
+               { OV511_I2C_BUS, 0x61, 0x02 },
+               { OV511_I2C_BUS, 0x62, 0x5f },
+               { OV511_I2C_BUS, 0x63, 0xd5 },
+               { OV511_I2C_BUS, 0x64, 0x57 },
+               { OV511_I2C_BUS, 0x65, 0x83 },
+               { OV511_I2C_BUS, 0x66, 0x55 },
+               { OV511_I2C_BUS, 0x67, 0x92 },
+               { OV511_I2C_BUS, 0x68, 0xcf },
+               { OV511_I2C_BUS, 0x69, 0x76 },
+               { OV511_I2C_BUS, 0x6a, 0x22 },
+               { OV511_I2C_BUS, 0x6b, 0x00 },
+               { OV511_I2C_BUS, 0x6c, 0x02 },
+               { OV511_I2C_BUS, 0x6d, 0x44 },
+               { OV511_I2C_BUS, 0x6e, 0x80 },
+               { OV511_I2C_BUS, 0x6f, 0x1d },
+               { OV511_I2C_BUS, 0x70, 0x8b },
+               { OV511_I2C_BUS, 0x71, 0x00 },
+               { OV511_I2C_BUS, 0x72, 0x14 },
+               { OV511_I2C_BUS, 0x73, 0x54 },
+               { OV511_I2C_BUS, 0x74, 0x00 },
+               { OV511_I2C_BUS, 0x75, 0x8e },
+               { OV511_I2C_BUS, 0x76, 0x00 },
+               { OV511_I2C_BUS, 0x77, 0xff },
+               { OV511_I2C_BUS, 0x78, 0x80 },
+               { OV511_I2C_BUS, 0x79, 0x80 },
+               { OV511_I2C_BUS, 0x7a, 0x80 },
+               { OV511_I2C_BUS, 0x7b, 0xe2 },
+               { OV511_I2C_BUS, 0x7c, 0x00 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       PDEBUG(4, "starting configuration");
+
+       /* This looks redundant, but is necessary for WebCam 3 */
+       ov->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
+               return -1;
+
+       if (init_ov_sensor(ov) >= 0) {
+               PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
+       } else {
+               /* Reset the 76xx */
+               if (i2c_w(ov, 0x12, 0x80) < 0)
+                       return -1;
+
+               /* Wait for it to initialize */
+               msleep(150);
+
+               i = 0;
+               success = 0;
+               while (i <= i2c_detect_tries) {
+                       if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
+                           (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
+                               success = 1;
+                               break;
+                       } else {
+                               i++;
+                       }
+               }
+
+// Was (i == i2c_detect_tries) previously. This obviously used to always report
+// success. Whether anyone actually depended on that bug is unknown
+               if ((i >= i2c_detect_tries) && (success == 0)) {
+                       err("Failed to read sensor ID. You might not have an");
+                       err("OV7610/20, or it may be not responding. Report");
+                       err("this to " EMAIL);
+                       err("This is only a warning. You can attempt to use");
+                       err("your camera anyway");
+// Only issue a warning for now
+//                     return -1;
+               } else {
+                       PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
+               }
+       }
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(ov, OV7610_REG_COM_I);
+
+       if (rc < 0) {
+               err("Error detecting sensor type");
+               return -1;
+       } else if ((rc & 3) == 3) {
+               info("Sensor is an OV7610");
+               ov->sensor = SEN_OV7610;
+       } else if ((rc & 3) == 1) {
+               /* I don't know what's different about the 76BE yet. */
+               if (i2c_r(ov, 0x15) & 1)
+                       info("Sensor is an OV7620AE");
+               else
+                       info("Sensor is an OV76BE");
+
+               /* OV511+ will return all zero isoc data unless we
+                * configure the sensor as a 7620. Someone needs to
+                * find the exact reg. setting that causes this. */
+               if (ov->bridge == BRG_OV511PLUS) {
+                       info("Enabling 511+/7620AE workaround");
+                       ov->sensor = SEN_OV7620;
+               } else {
+                       ov->sensor = SEN_OV76BE;
+               }
+       } else if ((rc & 3) == 0) {
+               info("Sensor is an OV7620");
+               ov->sensor = SEN_OV7620;
+       } else {
+               err("Unknown image sensor version: %d", rc & 3);
+               return -1;
+       }
+
+       if (ov->sensor == SEN_OV7620) {
+               PDEBUG(4, "Writing 7620 registers");
+               if (write_regvals(ov, aRegvalsNorm7620))
+                       return -1;
+       } else {
+               PDEBUG(4, "Writing 7610 registers");
+               if (write_regvals(ov, aRegvalsNorm7610))
+                       return -1;
+       }
+
+       /* Set sensor-specific vars */
+       ov->maxwidth = 640;
+       ov->maxheight = 480;
+       ov->minwidth = 64;
+       ov->minheight = 48;
+
+       // FIXME: These do not match the actual settings yet
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x80 << 8;
+       ov->colour = 0x80 << 8;
+       ov->hue = 0x80 << 8;
+
+       return 0;
+}
+
+/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
+static int
+ov6xx0_configure(struct usb_ov511 *ov)
+{
+       int rc;
+
+       static struct ov511_regvals aRegvalsNorm6x20[] = {
+               { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
+               { OV511_I2C_BUS, 0x11, 0x01 },
+               { OV511_I2C_BUS, 0x03, 0x60 },
+               { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
+               { OV511_I2C_BUS, 0x07, 0xa8 },
+               /* The ratio of 0x0c and 0x0d  controls the white point */
+               { OV511_I2C_BUS, 0x0c, 0x24 },
+               { OV511_I2C_BUS, 0x0d, 0x24 },
+               { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
+               { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
+               { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
+               { OV511_I2C_BUS, 0x14, 0x04 },
+               /* 0x16: 0x06 helps frame stability with moving objects */
+               { OV511_I2C_BUS, 0x16, 0x06 },
+//             { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+               { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+               /* 0x28: 0x05 Selects RGB format if RGB on */
+               { OV511_I2C_BUS, 0x28, 0x05 },
+               { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//             { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
+               { OV511_I2C_BUS, 0x2d, 0x99 },
+               { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
+               { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
+               { OV511_I2C_BUS, 0x38, 0x8b },
+               { OV511_I2C_BUS, 0x39, 0x40 },
+
+               { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
+               { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
+               { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
+
+               { OV511_I2C_BUS, 0x3d, 0x80 },
+               /* These next two registers (0x4a, 0x4b) are undocumented. They
+                * control the color balance */
+               { OV511_I2C_BUS, 0x4a, 0x80 },
+               { OV511_I2C_BUS, 0x4b, 0x80 },
+               { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
+               { OV511_I2C_BUS, 0x4e, 0xc1 },
+               { OV511_I2C_BUS, 0x4f, 0x04 },
+// Do 50-53 have any effect?
+// Toggle 0x12[2] off and on here?
+               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
+       };
+
+       static struct ov511_regvals aRegvalsNorm6x30[] = {
+       /*OK*/  { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
+               { OV511_I2C_BUS, 0x11, 0x00 },
+       /*OK*/  { OV511_I2C_BUS, 0x03, 0x60 },
+       /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
+               { OV511_I2C_BUS, 0x07, 0xa8 },
+               /* The ratio of 0x0c and 0x0d  controls the white point */
+       /*OK*/  { OV511_I2C_BUS, 0x0c, 0x24 },
+       /*OK*/  { OV511_I2C_BUS, 0x0d, 0x24 },
+       /*A*/   { OV511_I2C_BUS, 0x0e, 0x20 },
+//     /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
+               { OV511_I2C_BUS, 0x16, 0x03 },
+//     /*OK*/  { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
+               // 21 & 22? The suggested values look wrong. Go with default
+       /*A*/   { OV511_I2C_BUS, 0x23, 0xc0 },
+       /*A*/   { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
+//     /*OK*/  { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
+
+               /* 0x28: 0x05 Selects RGB format if RGB on */
+//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
+//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
+
+       /*OK*/  { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
+//     /*OK*/  { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
+               { OV511_I2C_BUS, 0x2d, 0x99 },
+//     /*A*/   { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
+//     /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
+//     /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
+//     /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
+//             { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
+//             { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
+//             { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
+               { OV511_I2C_BUS, 0x3d, 0x80 },
+//     /*A*/   { OV511_I2C_BUS, 0x3f, 0x0e },
+
+               /* These next two registers (0x4a, 0x4b) are undocumented. They
+                * control the color balance */
+//     /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
+//     /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
+               { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
+       /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
+
+               /* UV average mode, color killer: strongest */
+               { OV511_I2C_BUS, 0x4f, 0x07 },
+
+               { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
+               { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
+               { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
+               { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
+               { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
+//             { OV511_I2C_BUS, 0x5c, 0x10 },
+               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
+       };
+
+       PDEBUG(4, "starting sensor configuration");
+
+       if (init_ov_sensor(ov) < 0) {
+               err("Failed to read sensor ID. You might not have an OV6xx0,");
+               err("or it may be not responding. Report this to " EMAIL);
+               return -1;
+       } else {
+               PDEBUG(1, "OV6xx0 sensor detected");
+       }
+
+       /* Detect sensor (sub)type */
+       rc = i2c_r(ov, OV7610_REG_COM_I);
+
+       if (rc < 0) {
+               err("Error detecting sensor type");
+               return -1;
+       }
+
+       if ((rc & 3) == 0) {
+               ov->sensor = SEN_OV6630;
+               info("Sensor is an OV6630");
+       } else if ((rc & 3) == 1) {
+               ov->sensor = SEN_OV6620;
+               info("Sensor is an OV6620");
+       } else if ((rc & 3) == 2) {
+               ov->sensor = SEN_OV6630;
+               info("Sensor is an OV6630AE");
+       } else if ((rc & 3) == 3) {
+               ov->sensor = SEN_OV6630;
+               info("Sensor is an OV6630AF");
+       }
+
+       /* Set sensor-specific vars */
+       ov->maxwidth = 352;
+       ov->maxheight = 288;
+       ov->minwidth = 64;
+       ov->minheight = 48;
+
+       // FIXME: These do not match the actual settings yet
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x80 << 8;
+       ov->colour = 0x80 << 8;
+       ov->hue = 0x80 << 8;
+
+       if (ov->sensor == SEN_OV6620) {
+               PDEBUG(4, "Writing 6x20 registers");
+               if (write_regvals(ov, aRegvalsNorm6x20))
+                       return -1;
+       } else {
+               PDEBUG(4, "Writing 6x30 registers");
+               if (write_regvals(ov, aRegvalsNorm6x30))
+                       return -1;
+       }
+
+       return 0;
+}
+
+/* This initializes the KS0127 and KS0127B video decoders. */
+static int 
+ks0127_configure(struct usb_ov511 *ov)
+{
+       int rc;
+
+// FIXME: I don't know how to sync or reset it yet
+#if 0
+       if (ov51x_init_ks_sensor(ov) < 0) {
+               err("Failed to initialize the KS0127");
+               return -1;
+       } else {
+               PDEBUG(1, "KS012x(B) sensor detected");
+       }
+#endif
+
+       /* Detect decoder subtype */
+       rc = i2c_r(ov, 0x00);
+       if (rc < 0) {
+               err("Error detecting sensor type");
+               return -1;
+       } else if (rc & 0x08) {
+               rc = i2c_r(ov, 0x3d);
+               if (rc < 0) {
+                       err("Error detecting sensor type");
+                       return -1;
+               } else if ((rc & 0x0f) == 0) {
+                       info("Sensor is a KS0127");
+                       ov->sensor = SEN_KS0127;
+               } else if ((rc & 0x0f) == 9) {
+                       info("Sensor is a KS0127B Rev. A");
+                       ov->sensor = SEN_KS0127B;
+               }
+       } else {
+               err("Error: Sensor is an unsupported KS0122");
+               return -1;
+       }
+
+       /* Set sensor-specific vars */
+       ov->maxwidth = 640;
+       ov->maxheight = 480;
+       ov->minwidth = 64;
+       ov->minheight = 48;
+
+       // FIXME: These do not match the actual settings yet
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x80 << 8;
+       ov->colour = 0x80 << 8;
+       ov->hue = 0x80 << 8;
+
+       /* This device is not supported yet. Bail out now... */
+       err("This sensor is not supported yet.");
+       return -1;
+
+       return 0;
+}
+
+/* This initializes the SAA7111A video decoder. */
+static int
+saa7111a_configure(struct usb_ov511 *ov)
+{
+       int rc;
+
+       /* Since there is no register reset command, all registers must be
+        * written, otherwise gives erratic results */
+       static struct ov511_regvals aRegvalsNormSAA7111A[] = {
+               { OV511_I2C_BUS, 0x06, 0xce },
+               { OV511_I2C_BUS, 0x07, 0x00 },
+               { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
+               { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
+               { OV511_I2C_BUS, 0x00, 0x00 },
+               { OV511_I2C_BUS, 0x01, 0x00 },
+               { OV511_I2C_BUS, 0x03, 0x23 },
+               { OV511_I2C_BUS, 0x04, 0x00 },
+               { OV511_I2C_BUS, 0x05, 0x00 },
+               { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
+               { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
+               { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
+               { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
+               { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
+               { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
+               { OV511_I2C_BUS, 0x0f, 0x00 },
+               { OV511_I2C_BUS, 0x11, 0x0c },
+               { OV511_I2C_BUS, 0x12, 0x00 },
+               { OV511_I2C_BUS, 0x13, 0x00 },
+               { OV511_I2C_BUS, 0x14, 0x00 },
+               { OV511_I2C_BUS, 0x15, 0x00 },
+               { OV511_I2C_BUS, 0x16, 0x00 },
+               { OV511_I2C_BUS, 0x17, 0x00 },
+               { OV511_I2C_BUS, 0x02, 0xc0 },  /* Composite input 0 */
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+// FIXME: I don't know how to sync or reset it yet
+#if 0
+       if (ov51x_init_saa_sensor(ov) < 0) {
+               err("Failed to initialize the SAA7111A");
+               return -1;
+       } else {
+               PDEBUG(1, "SAA7111A sensor detected");
+       }
+#endif
+
+       /* 640x480 not supported with PAL */
+       if (ov->pal) {
+               ov->maxwidth = 320;
+               ov->maxheight = 240;            /* Even field only */
+       } else {
+               ov->maxwidth = 640;
+               ov->maxheight = 480;            /* Even/Odd fields */
+       }
+
+       ov->minwidth = 320;
+       ov->minheight = 240;            /* Even field only */
+
+       ov->has_decoder = 1;
+       ov->num_inputs = 8;
+       ov->norm = VIDEO_MODE_AUTO;
+       ov->stop_during_set = 0;        /* Decoder guarantees stable image */
+
+       /* Decoder doesn't change these values, so we use these instead of
+        * acutally reading the registers (which doesn't work) */
+       ov->brightness = 0x80 << 8;
+       ov->contrast = 0x40 << 9;
+       ov->colour = 0x40 << 9;
+       ov->hue = 32768;
+
+       PDEBUG(4, "Writing SAA7111A registers");
+       if (write_regvals(ov, aRegvalsNormSAA7111A))
+               return -1;
+
+       /* Detect version of decoder. This must be done after writing the
+         * initial regs or the decoder will lock up. */
+       rc = i2c_r(ov, 0x00);
+
+       if (rc < 0) {
+               err("Error detecting sensor version");
+               return -1;
+       } else {
+               info("Sensor is an SAA7111A (version 0x%x)", rc);
+               ov->sensor = SEN_SAA7111A;
+       }
+
+       // FIXME: Fix this for OV518(+)
+       /* Latch to negative edge of clock. Otherwise, we get incorrect
+        * colors and jitter in the digital signal. */
+       if (ov->bclass == BCL_OV511)
+               reg_w(ov, 0x11, 0x00);
+       else
+               warn("SAA7111A not yet supported with OV518/OV518+");
+
+       return 0;
+}
+
+/* This initializes the OV511/OV511+ and the sensor */
+static int 
+ov511_configure(struct usb_ov511 *ov)
+{
+       static struct ov511_regvals aRegvalsInit511[] = {
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x3f },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x3d },
+               { OV511_DONE_BUS, 0x0, 0x00},
+       };
+
+       static struct ov511_regvals aRegvalsNorm511[] = {
+               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0x01 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R511_FIFO_OPTS,        0x1f },
+               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
+               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       static struct ov511_regvals aRegvalsNorm511Plus[] = {
+               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0xff },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
+               { OV511_REG_BUS, R511_FIFO_OPTS,        0xff },
+               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
+               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       PDEBUG(4, "");
+
+       ov->customid = reg_r(ov, R511_SYS_CUST_ID);
+       if (ov->customid < 0) {
+               err("Unable to read camera bridge registers");
+               goto error;
+       }
+
+       PDEBUG (1, "CustomID = %d", ov->customid);
+       ov->desc = symbolic(camlist, ov->customid);
+       info("model: %s", ov->desc);
+
+       if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
+               err("Camera type (%d) not recognized", ov->customid);
+               err("Please notify " EMAIL " of the name,");
+               err("manufacturer, model, and this number of your camera.");
+               err("Also include the output of the detection process.");
+       } 
+
+       if (ov->customid == 70)         /* USB Life TV (PAL/SECAM) */
+               ov->pal = 1;
+
+       if (write_regvals(ov, aRegvalsInit511))
+               goto error;
+
+       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 0);
+
+       /* The OV511+ has undocumented bits in the flow control register.
+        * Setting it to 0xff fixes the corruption with moving objects. */
+       if (ov->bridge == BRG_OV511) {
+               if (write_regvals(ov, aRegvalsNorm511))
+                       goto error;
+       } else if (ov->bridge == BRG_OV511PLUS) {
+               if (write_regvals(ov, aRegvalsNorm511Plus))
+                       goto error;
+       } else {
+               err("Invalid bridge");
+       }
+
+       if (ov511_init_compression(ov))
+               goto error;
+
+       ov->packet_numbering = 1;
+       ov511_set_packet_size(ov, 0);
+
+       ov->snap_enabled = snapshot;
+
+       /* Test for 7xx0 */
+       PDEBUG(3, "Testing for 0V7xx0");
+       ov->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
+               goto error;
+
+       if (i2c_w(ov, 0x12, 0x80) < 0) {
+               /* Test for 6xx0 */
+               PDEBUG(3, "Testing for 0V6xx0");
+               ov->primary_i2c_slave = OV6xx0_SID;
+               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
+                       goto error;
+
+               if (i2c_w(ov, 0x12, 0x80) < 0) {
+                       /* Test for 8xx0 */
+                       PDEBUG(3, "Testing for 0V8xx0");
+                       ov->primary_i2c_slave = OV8xx0_SID;
+                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
+                               goto error;
+
+                       if (i2c_w(ov, 0x12, 0x80) < 0) {
+                               /* Test for SAA7111A */
+                               PDEBUG(3, "Testing for SAA7111A");
+                               ov->primary_i2c_slave = SAA7111A_SID;
+                               if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
+                                       goto error;
+
+                               if (i2c_w(ov, 0x0d, 0x00) < 0) {
+                                       /* Test for KS0127 */
+                                       PDEBUG(3, "Testing for KS0127");
+                                       ov->primary_i2c_slave = KS0127_SID;
+                                       if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
+                                               goto error;
+
+                                       if (i2c_w(ov, 0x10, 0x00) < 0) {
+                                               err("Can't determine sensor slave IDs");
+                                               goto error;
+                                       } else {
+                                               if (ks0127_configure(ov) < 0) {
+                                                       err("Failed to configure KS0127");
+                                                       goto error;
+                                               }
+                                       }
+                               } else {
+                                       if (saa7111a_configure(ov) < 0) {
+                                               err("Failed to configure SAA7111A");
+                                               goto error;
+                                       }
+                               }
+                       } else {
+                               err("Detected unsupported OV8xx0 sensor");
+                               goto error;
+                       }
+               } else {
+                       if (ov6xx0_configure(ov) < 0) {
+                               err("Failed to configure OV6xx0");
+                               goto error;
+                       }
+               }
+       } else {
+               if (ov7xx0_configure(ov) < 0) {
+                       err("Failed to configure OV7xx0");
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       err("OV511 Config failed");
+
+       return -EBUSY;
+}
+
+/* This initializes the OV518/OV518+ and the sensor */
+static int
+ov518_configure(struct usb_ov511 *ov)
+{
+       /* For 518 and 518+ */
+       static struct ov511_regvals aRegvalsInit518[] = {
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x40 },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x3e },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
+               { OV511_REG_BUS, R51x_SYS_RESET,        0x00 },
+               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
+               { OV511_REG_BUS, 0x46,                  0x00 }, 
+               { OV511_REG_BUS, 0x5d,                  0x03 },
+               { OV511_DONE_BUS, 0x0, 0x00},
+       };
+
+       static struct ov511_regvals aRegvalsNorm518[] = {
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
+               { OV511_REG_BUS, 0x31,                  0x0f },
+               { OV511_REG_BUS, 0x5d,                  0x03 },
+               { OV511_REG_BUS, 0x24,                  0x9f },
+               { OV511_REG_BUS, 0x25,                  0x90 },
+               { OV511_REG_BUS, 0x20,                  0x00 },
+               { OV511_REG_BUS, 0x51,                  0x04 },
+               { OV511_REG_BUS, 0x71,                  0x19 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       static struct ov511_regvals aRegvalsNorm518Plus[] = {
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
+               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
+               { OV511_REG_BUS, 0x31,                  0x0f },
+               { OV511_REG_BUS, 0x5d,                  0x03 },
+               { OV511_REG_BUS, 0x24,                  0x9f },
+               { OV511_REG_BUS, 0x25,                  0x90 },
+               { OV511_REG_BUS, 0x20,                  0x60 },
+               { OV511_REG_BUS, 0x51,                  0x02 },
+               { OV511_REG_BUS, 0x71,                  0x19 },
+               { OV511_REG_BUS, 0x40,                  0xff },
+               { OV511_REG_BUS, 0x41,                  0x42 },
+               { OV511_REG_BUS, 0x46,                  0x00 },
+               { OV511_REG_BUS, 0x33,                  0x04 },
+               { OV511_REG_BUS, 0x21,                  0x19 },
+               { OV511_REG_BUS, 0x3f,                  0x10 },
+               { OV511_DONE_BUS, 0x0, 0x00 },
+       };
+
+       PDEBUG(4, "");
+
+       /* First 5 bits of custom ID reg are a revision ID on OV518 */
+       info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
+
+       /* Give it the default description */
+       ov->desc = symbolic(camlist, 0);
+
+       if (write_regvals(ov, aRegvalsInit518))
+               goto error;
+
+       /* Set LED GPIO pin to output mode */
+       if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
+               goto error;
+
+       /* LED is off by default with OV518; have to explicitly turn it on */
+       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
+               ov51x_led_control(ov, 0);
+       else
+               ov51x_led_control(ov, 1);
+
+       /* Don't require compression if dumppix is enabled; otherwise it's
+        * required. OV518 has no uncompressed mode, to save RAM. */
+       if (!dumppix && !ov->compress) {
+               ov->compress = 1;
+               warn("Compression required with OV518...enabling");
+       }
+
+       if (ov->bridge == BRG_OV518) {
+               if (write_regvals(ov, aRegvalsNorm518))
+                       goto error;
+       } else if (ov->bridge == BRG_OV518PLUS) {
+               if (write_regvals(ov, aRegvalsNorm518Plus))
+                       goto error;
+       } else {
+               err("Invalid bridge");
+       }
+
+       if (reg_w(ov, 0x2f, 0x80) < 0)
+               goto error;
+
+       if (ov518_init_compression(ov))
+               goto error;
+
+       if (ov->bridge == BRG_OV518)
+       {
+               struct usb_interface *ifp;
+               struct usb_host_interface *alt;
+               __u16 mxps = 0;
+
+               ifp = usb_ifnum_to_if(ov->dev, 0);
+               if (ifp) {
+                       alt = usb_altnum_to_altsetting(ifp, 7);
+                       if (alt)
+                               mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+               }
+
+               /* Some OV518s have packet numbering by default, some don't */
+               if (mxps == 897)
+                       ov->packet_numbering = 1;
+               else
+                       ov->packet_numbering = 0;
+       } else {
+               /* OV518+ has packet numbering turned on by default */
+               ov->packet_numbering = 1;
+       }
+
+       ov518_set_packet_size(ov, 0);
+
+       ov->snap_enabled = snapshot;
+
+       /* Test for 76xx */
+       ov->primary_i2c_slave = OV7xx0_SID;
+       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
+               goto error;
+
+       /* The OV518 must be more aggressive about sensor detection since
+        * I2C write will never fail if the sensor is not present. We have
+        * to try to initialize the sensor to detect its presence */
+
+       if (init_ov_sensor(ov) < 0) {
+               /* Test for 6xx0 */
+               ov->primary_i2c_slave = OV6xx0_SID;
+               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
+                       goto error;
+
+               if (init_ov_sensor(ov) < 0) {
+                       /* Test for 8xx0 */
+                       ov->primary_i2c_slave = OV8xx0_SID;
+                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
+                               goto error;
+
+                       if (init_ov_sensor(ov) < 0) {
+                               err("Can't determine sensor slave IDs");
+                               goto error;
+                       } else {
+                               err("Detected unsupported OV8xx0 sensor");
+                               goto error;
+                       }
+               } else {
+                       if (ov6xx0_configure(ov) < 0) {
+                               err("Failed to configure OV6xx0");
+                               goto error;
+                       }
+               }
+       } else {
+               if (ov7xx0_configure(ov) < 0) {
+                       err("Failed to configure OV7xx0");
+                       goto error;
+               }
+       }
+
+       ov->maxwidth = 352;
+       ov->maxheight = 288;
+
+       // The OV518 cannot go as low as the sensor can
+       ov->minwidth = 160;
+       ov->minheight = 120;
+
+       return 0;
+
+error:
+       err("OV518 Config failed");
+
+       return -EBUSY;
+}
+
+/****************************************************************************
+ *  sysfs
+ ***************************************************************************/
+
+static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
+{
+       struct video_device *vdev = to_video_device(cd);
+       return video_get_drvdata(vdev);
+}
+
+static ssize_t show_custom_id(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%d\n", ov->customid);
+} 
+static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
+
+static ssize_t show_model(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%s\n", ov->desc);
+} 
+static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+static ssize_t show_bridge(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
+} 
+static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
+
+static ssize_t show_sensor(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
+} 
+static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
+
+static ssize_t show_brightness(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_brightness(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+} 
+static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+
+static ssize_t show_saturation(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_saturation(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+} 
+static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+
+static ssize_t show_contrast(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_contrast(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+} 
+static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+
+static ssize_t show_hue(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned short x;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_hue(ov, &x);
+       return sprintf(buf, "%d\n", x >> 8);
+} 
+static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+
+static ssize_t show_exposure(struct class_device *cd, char *buf)
+{
+       struct usb_ov511 *ov = cd_to_ov(cd);
+       unsigned char exp = 0;
+
+       if (!ov->dev)
+               return -ENODEV;
+       sensor_get_exposure(ov, &exp);
+       return sprintf(buf, "%d\n", exp >> 8);
+} 
+static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
+
+static void ov_create_sysfs(struct video_device *vdev)
+{
+       video_device_create_file(vdev, &class_device_attr_custom_id);
+       video_device_create_file(vdev, &class_device_attr_model);
+       video_device_create_file(vdev, &class_device_attr_bridge);
+       video_device_create_file(vdev, &class_device_attr_sensor);
+       video_device_create_file(vdev, &class_device_attr_brightness);
+       video_device_create_file(vdev, &class_device_attr_saturation);
+       video_device_create_file(vdev, &class_device_attr_contrast);
+       video_device_create_file(vdev, &class_device_attr_hue);
+       video_device_create_file(vdev, &class_device_attr_exposure);
+}
+
+/****************************************************************************
+ *  USB routines
+ ***************************************************************************/
+
+static int
+ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_interface_descriptor *idesc;
+       struct usb_ov511 *ov;
+       int i;
+
+       PDEBUG(1, "probing for device...");
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       idesc = &intf->cur_altsetting->desc;
+
+       if (idesc->bInterfaceClass != 0xFF)
+               return -ENODEV;
+       if (idesc->bInterfaceSubClass != 0x00)
+               return -ENODEV;
+
+       if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
+               err("couldn't kmalloc ov struct");
+               goto error_out;
+       }
+
+       ov->dev = dev;
+       ov->iface = idesc->bInterfaceNumber;
+       ov->led_policy = led;
+       ov->compress = compress;
+       ov->lightfreq = lightfreq;
+       ov->num_inputs = 1;        /* Video decoder init functs. change this */
+       ov->stop_during_set = !fastset;
+       ov->backlight = backlight;
+       ov->mirror = mirror;
+       ov->auto_brt = autobright;
+       ov->auto_gain = autogain;
+       ov->auto_exp = autoexp;
+
+       switch (le16_to_cpu(dev->descriptor.idProduct)) {
+       case PROD_OV511:
+               ov->bridge = BRG_OV511;
+               ov->bclass = BCL_OV511;
+               break;
+       case PROD_OV511PLUS:
+               ov->bridge = BRG_OV511PLUS;
+               ov->bclass = BCL_OV511;
+               break;
+       case PROD_OV518:
+               ov->bridge = BRG_OV518;
+               ov->bclass = BCL_OV518;
+               break;
+       case PROD_OV518PLUS:
+               ov->bridge = BRG_OV518PLUS;
+               ov->bclass = BCL_OV518;
+               break;
+       case PROD_ME2CAM:
+               if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
+                       goto error;
+               ov->bridge = BRG_OV511PLUS;
+               ov->bclass = BCL_OV511;
+               break;
+       default:
+               err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
+               goto error;
+       }
+
+       info("USB %s video device found", symbolic(brglist, ov->bridge));
+
+       init_waitqueue_head(&ov->wq);
+
+       mutex_init(&ov->lock);  /* to 1 == available */
+       mutex_init(&ov->buf_lock);
+       mutex_init(&ov->i2c_lock);
+       mutex_init(&ov->cbuf_lock);
+
+       ov->buf_state = BUF_NOT_ALLOCATED;
+
+       if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
+               err("usb_make_path error");
+               goto error;
+       }
+
+       /* Allocate control transfer buffer. */
+       /* Must be kmalloc()'ed, for DMA compatibility */
+       ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
+       if (!ov->cbuf)
+               goto error;
+
+       if (ov->bclass == BCL_OV518) {
+               if (ov518_configure(ov) < 0)
+                       goto error;
+       } else {
+               if (ov511_configure(ov) < 0)
+                       goto error;
+       }
+
+       for (i = 0; i < OV511_NUMFRAMES; i++) {
+               ov->frame[i].framenum = i;
+               init_waitqueue_head(&ov->frame[i].wq);
+       }
+
+       for (i = 0; i < OV511_NUMSBUF; i++) {
+               ov->sbuf[i].ov = ov;
+               spin_lock_init(&ov->sbuf[i].lock);
+               ov->sbuf[i].n = i;
+       }
+
+       /* Unnecessary? (This is done on open(). Need to make sure variables
+        * are properly initialized without this before removing it, though). */
+       if (ov51x_set_default_params(ov) < 0)
+               goto error;
+
+#ifdef OV511_DEBUG
+       if (dump_bridge) {
+               if (ov->bclass == BCL_OV511)
+                       ov511_dump_regs(ov);
+               else
+                       ov518_dump_regs(ov);
+       }
+#endif
+
+       ov->vdev = video_device_alloc();
+       if (!ov->vdev)
+               goto error;
+
+       memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
+       ov->vdev->dev = &dev->dev;
+       video_set_drvdata(ov->vdev, ov);
+
+       for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
+               /* Minor 0 cannot be specified; assume user wants autodetect */
+               if (unit_video[i] == 0)
+                       break;
+
+               if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
+                       unit_video[i]) >= 0) {
+                       break;
+               }
+       }
+
+       /* Use the next available one */
+       if ((ov->vdev->minor == -1) &&
+           video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
+               err("video_register_device failed");
+               goto error;
+       }
+
+       info("Device at %s registered to minor %d", ov->usb_path,
+            ov->vdev->minor);
+
+       usb_set_intfdata(intf, ov);
+       ov_create_sysfs(ov->vdev);
+       return 0;
+
+error:
+       if (ov->vdev) {
+               if (-1 == ov->vdev->minor)
+                       video_device_release(ov->vdev);
+               else
+                       video_unregister_device(ov->vdev);
+               ov->vdev = NULL;
+       }
+
+       if (ov->cbuf) {
+               mutex_lock(&ov->cbuf_lock);
+               kfree(ov->cbuf);
+               ov->cbuf = NULL;
+               mutex_unlock(&ov->cbuf_lock);
+       }
+
+       kfree(ov);
+       ov = NULL;
+
+error_out:
+       err("Camera initialization failed");
+       return -EIO;
+}
+
+static void
+ov51x_disconnect(struct usb_interface *intf)
+{
+       struct usb_ov511 *ov = usb_get_intfdata(intf);
+       int n;
+
+       PDEBUG(3, "");
+
+       usb_set_intfdata (intf, NULL);
+
+       if (!ov)
+               return;
+
+       if (ov->vdev)
+               video_unregister_device(ov->vdev);
+
+       for (n = 0; n < OV511_NUMFRAMES; n++)
+               ov->frame[n].grabstate = FRAME_ERROR;
+
+       ov->curframe = -1;
+
+       /* This will cause the process to request another frame */
+       for (n = 0; n < OV511_NUMFRAMES; n++)
+               wake_up_interruptible(&ov->frame[n].wq);
+
+       wake_up_interruptible(&ov->wq);
+
+       ov->streaming = 0;
+       ov51x_unlink_isoc(ov);
+
+       ov->dev = NULL;
+
+       /* Free the memory */
+       if (ov && !ov->user) {
+               mutex_lock(&ov->cbuf_lock);
+               kfree(ov->cbuf);
+               ov->cbuf = NULL;
+               mutex_unlock(&ov->cbuf_lock);
+
+               ov51x_dealloc(ov);
+               kfree(ov);
+               ov = NULL;
+       }
+
+       PDEBUG(3, "Disconnect complete");
+}
+
+static struct usb_driver ov511_driver = {
+       .name =         "ov511",
+       .id_table =     device_table,
+       .probe =        ov51x_probe,
+       .disconnect =   ov51x_disconnect
+};
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init
+usb_ov511_init(void)
+{
+       int retval;
+
+       retval = usb_register(&ov511_driver);
+       if (retval)
+               goto out;
+
+       info(DRIVER_VERSION " : " DRIVER_DESC);
+
+out:
+       return retval;
+}
+
+static void __exit
+usb_ov511_exit(void)
+{
+       usb_deregister(&ov511_driver);
+       info("driver deregistered");
+
+}
+
+module_init(usb_ov511_init);
+module_exit(usb_ov511_exit);
+
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
new file mode 100644 (file)
index 0000000..bce9b36
--- /dev/null
@@ -0,0 +1,568 @@
+#ifndef __LINUX_OV511_H
+#define __LINUX_OV511_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#define OV511_DEBUG    /* Turn on debug messages */
+
+#ifdef OV511_DEBUG
+       #define PDEBUG(level, fmt, args...) \
+               if (debug >= (level)) info("[%s:%d] " fmt, \
+               __FUNCTION__, __LINE__ , ## args)
+#else
+       #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { \
+       if ((v) < (mi)) (v) = (mi); \
+       else if ((v) > (ma)) (v) = (ma); \
+}
+
+/* --------------------------------- */
+/* DEFINES FOR OV511 AND OTHER CHIPS */
+/* --------------------------------- */
+
+/* USB IDs */
+#define VEND_OMNIVISION        0x05A9
+#define PROD_OV511     0x0511
+#define PROD_OV511PLUS 0xA511
+#define PROD_OV518     0x0518
+#define PROD_OV518PLUS 0xA518
+
+#define VEND_MATTEL    0x0813
+#define PROD_ME2CAM    0x0002
+
+/* --------------------------------- */
+/*     OV51x REGISTER MNEMONICS      */
+/* --------------------------------- */
+
+/* Camera interface register numbers */
+#define R511_CAM_DELAY         0x10
+#define R511_CAM_EDGE          0x11
+#define R511_CAM_PXCNT         0x12
+#define R511_CAM_LNCNT         0x13
+#define R511_CAM_PXDIV         0x14
+#define R511_CAM_LNDIV         0x15
+#define R511_CAM_UV_EN         0x16
+#define R511_CAM_LINE_MODE     0x17
+#define R511_CAM_OPTS          0x18
+
+/* Snapshot mode camera interface register numbers */
+#define R511_SNAP_FRAME                0x19
+#define R511_SNAP_PXCNT                0x1A
+#define R511_SNAP_LNCNT                0x1B
+#define R511_SNAP_PXDIV                0x1C
+#define R511_SNAP_LNDIV                0x1D
+#define R511_SNAP_UV_EN                0x1E
+#define R511_SNAP_OPTS         0x1F
+
+/* DRAM register numbers */
+#define R511_DRAM_FLOW_CTL     0x20
+#define R511_DRAM_ARCP         0x21
+#define R511_DRAM_MRC          0x22
+#define R511_DRAM_RFC          0x23
+
+/* ISO FIFO register numbers */
+#define R51x_FIFO_PSIZE                0x30    /* 2 bytes wide w/ OV518(+) */
+#define R511_FIFO_OPTS         0x31
+
+/* Parallel IO register numbers */
+#define R511_PIO_OPTS          0x38
+#define R511_PIO_DATA          0x39
+#define R511_PIO_BIST          0x3E
+#define R518_GPIO_IN           0x55    /* OV518(+) only */
+#define R518_GPIO_OUT          0x56    /* OV518(+) only */
+#define R518_GPIO_CTL          0x57    /* OV518(+) only */
+#define R518_GPIO_PULSE_IN     0x58    /* OV518(+) only */
+#define R518_GPIO_PULSE_CLEAR  0x59    /* OV518(+) only */
+#define R518_GPIO_PULSE_POL    0x5a    /* OV518(+) only */
+#define R518_GPIO_PULSE_EN     0x5b    /* OV518(+) only */
+#define R518_GPIO_RESET                0x5c    /* OV518(+) only */
+
+/* I2C registers */
+#define R511_I2C_CTL           0x40
+#define R518_I2C_CTL           0x47    /* OV518(+) only */
+#define R51x_I2C_W_SID         0x41
+#define R51x_I2C_SADDR_3       0x42
+#define R51x_I2C_SADDR_2       0x43
+#define R51x_I2C_R_SID         0x44
+#define R51x_I2C_DATA          0x45
+#define R51x_I2C_CLOCK         0x46
+#define R51x_I2C_TIMEOUT       0x47
+
+/* I2C snapshot registers */
+#define R511_SI2C_SADDR_3      0x48
+#define R511_SI2C_DATA         0x49
+
+/* System control registers */
+#define R51x_SYS_RESET         0x50
+               /* Reset type definitions */
+#define        OV511_RESET_UDC         0x01
+#define        OV511_RESET_I2C         0x02
+#define        OV511_RESET_FIFO        0x04
+#define        OV511_RESET_OMNICE      0x08
+#define        OV511_RESET_DRAM        0x10
+#define        OV511_RESET_CAM_INT     0x20
+#define        OV511_RESET_OV511       0x40
+#define        OV511_RESET_NOREGS      0x3F /* All but OV511 & regs */
+#define        OV511_RESET_ALL         0x7F
+
+#define R511_SYS_CLOCK_DIV     0x51
+#define R51x_SYS_SNAP          0x52
+#define R51x_SYS_INIT          0x53
+#define R511_SYS_PWR_CLK       0x54 /* OV511+/OV518(+) only */
+#define R511_SYS_LED_CTL       0x55 /* OV511+ only */
+#define R511_SYS_USER          0x5E
+#define R511_SYS_CUST_ID       0x5F
+
+/* OmniCE (compression) registers */
+#define R511_COMP_PHY          0x70
+#define R511_COMP_PHUV         0x71
+#define R511_COMP_PVY          0x72
+#define R511_COMP_PVUV         0x73
+#define R511_COMP_QHY          0x74
+#define R511_COMP_QHUV         0x75
+#define R511_COMP_QVY          0x76
+#define R511_COMP_QVUV         0x77
+#define R511_COMP_EN           0x78
+#define R511_COMP_LUT_EN       0x79            
+#define R511_COMP_LUT_BEGIN    0x80
+
+/* --------------------------------- */
+/*         ALTERNATE NUMBERS         */
+/* --------------------------------- */
+
+/* Alternate numbers for various max packet sizes (OV511 only) */
+#define OV511_ALT_SIZE_992     0
+#define OV511_ALT_SIZE_993     1
+#define OV511_ALT_SIZE_768     2
+#define OV511_ALT_SIZE_769     3
+#define OV511_ALT_SIZE_512     4
+#define OV511_ALT_SIZE_513     5
+#define OV511_ALT_SIZE_257     6
+#define OV511_ALT_SIZE_0       7
+
+/* Alternate numbers for various max packet sizes (OV511+ only) */
+#define OV511PLUS_ALT_SIZE_0   0
+#define OV511PLUS_ALT_SIZE_33  1
+#define OV511PLUS_ALT_SIZE_129 2
+#define OV511PLUS_ALT_SIZE_257 3
+#define OV511PLUS_ALT_SIZE_385 4
+#define OV511PLUS_ALT_SIZE_513 5
+#define OV511PLUS_ALT_SIZE_769 6
+#define OV511PLUS_ALT_SIZE_961 7
+
+/* Alternate numbers for various max packet sizes (OV518(+) only) */
+#define OV518_ALT_SIZE_0       0
+#define OV518_ALT_SIZE_128     1
+#define OV518_ALT_SIZE_256     2
+#define OV518_ALT_SIZE_384     3
+#define OV518_ALT_SIZE_512     4
+#define OV518_ALT_SIZE_640     5
+#define OV518_ALT_SIZE_768     6
+#define OV518_ALT_SIZE_896     7
+
+/* --------------------------------- */
+/*     OV7610 REGISTER MNEMONICS     */
+/* --------------------------------- */
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN          0x00  /* gain setting (5:0) */
+#define OV7610_REG_BLUE          0x01  /* blue channel balance */
+#define OV7610_REG_RED           0x02  /* red channel balance */
+#define OV7610_REG_SAT           0x03  /* saturation */
+                                       /* 04 reserved */
+#define OV7610_REG_CNT           0x05  /* Y contrast */
+#define OV7610_REG_BRT           0x06  /* Y brightness */
+                                       /* 08-0b reserved */
+#define OV7610_REG_BLUE_BIAS     0x0C  /* blue channel bias (5:0) */
+#define OV7610_REG_RED_BIAS      0x0D  /* read channel bias (5:0) */
+#define OV7610_REG_GAMMA_COEFF   0x0E  /* gamma settings */
+#define OV7610_REG_WB_RANGE      0x0F  /* AEC/ALC/S-AWB settings */
+#define OV7610_REG_EXP           0x10  /* manual exposure setting */
+#define OV7610_REG_CLOCK         0x11  /* polarity/clock prescaler */
+#define OV7610_REG_COM_A         0x12  /* misc common regs */
+#define OV7610_REG_COM_B         0x13  /* misc common regs */
+#define OV7610_REG_COM_C         0x14  /* misc common regs */
+#define OV7610_REG_COM_D         0x15  /* misc common regs */
+#define OV7610_REG_FIELD_DIVIDE  0x16  /* field interval/mode settings */
+#define OV7610_REG_HWIN_START    0x17  /* horizontal window start */
+#define OV7610_REG_HWIN_END      0x18  /* horizontal window end */
+#define OV7610_REG_VWIN_START    0x19  /* vertical window start */
+#define OV7610_REG_VWIN_END      0x1A  /* vertical window end */
+#define OV7610_REG_PIXEL_SHIFT   0x1B  /* pixel shift */
+#define OV7610_REG_ID_HIGH       0x1C  /* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW        0x1D  /* manufacturer ID LSB */
+                                       /* 0e-0f reserved */
+#define OV7610_REG_COM_E         0x20  /* misc common regs */
+#define OV7610_REG_YOFFSET       0x21  /* Y channel offset */
+#define OV7610_REG_UOFFSET       0x22  /* U channel offset */
+                                       /* 23 reserved */
+#define OV7610_REG_ECW           0x24  /* Exposure white level for AEC */
+#define OV7610_REG_ECB           0x25  /* Exposure black level for AEC */
+#define OV7610_REG_COM_F         0x26  /* misc settings */
+#define OV7610_REG_COM_G         0x27  /* misc settings */
+#define OV7610_REG_COM_H         0x28  /* misc settings */
+#define OV7610_REG_COM_I         0x29  /* misc settings */
+#define OV7610_REG_FRAMERATE_H   0x2A  /* frame rate MSB + misc */
+#define OV7610_REG_FRAMERATE_L   0x2B  /* frame rate LSB */
+#define OV7610_REG_ALC           0x2C  /* Auto Level Control settings */
+#define OV7610_REG_COM_J         0x2D  /* misc settings */
+#define OV7610_REG_VOFFSET       0x2E  /* V channel offset adjustment */
+#define OV7610_REG_ARRAY_BIAS   0x2F   /* Array bias -- don't change */
+                                       /* 30-32 reserved */
+#define OV7610_REG_YGAMMA        0x33  /* misc gamma settings (7:6) */
+#define OV7610_REG_BIAS_ADJUST   0x34  /* misc bias settings */
+#define OV7610_REG_COM_L         0x35  /* misc settings */
+                                       /* 36-37 reserved */
+#define OV7610_REG_COM_K         0x38  /* misc registers */
+
+/* --------------------------------- */
+/*           I2C ADDRESSES           */
+/* --------------------------------- */
+
+#define OV7xx0_SID   0x42
+#define OV6xx0_SID   0xC0
+#define OV8xx0_SID   0xA0
+#define KS0127_SID   0xD8
+#define SAA7111A_SID 0x48
+
+/* --------------------------------- */
+/*       MISCELLANEOUS DEFINES       */
+/* --------------------------------- */
+
+#define I2C_CLOCK_PRESCALER    0x03
+
+#define FRAMES_PER_DESC                10      /* FIXME - What should this be? */
+#define MAX_FRAME_SIZE_PER_DESC        993     /* For statically allocated stuff */
+#define PIXELS_PER_SEG         256     /* Pixels per segment */
+
+#define OV511_ENDPOINT_ADDRESS 1       /* Isoc endpoint number */
+
+#define OV511_NUMFRAMES        2
+#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
+       #error "OV511_NUMFRAMES is too high"
+#endif
+
+#define OV511_NUMSBUF          2
+
+/* Control transfers use up to 4 bytes */
+#define OV511_CBUF_SIZE                4
+
+/* Size of usb_make_path() buffer */
+#define OV511_USB_PATH_LEN     64
+
+/* Bridge types */
+enum {
+       BRG_UNKNOWN,
+       BRG_OV511,
+       BRG_OV511PLUS,
+       BRG_OV518,
+       BRG_OV518PLUS,
+};
+
+/* Bridge classes */
+enum {
+       BCL_UNKNOWN,
+       BCL_OV511,
+       BCL_OV518,
+};
+
+/* Sensor types */
+enum {
+       SEN_UNKNOWN,
+       SEN_OV76BE,
+       SEN_OV7610,
+       SEN_OV7620,
+       SEN_OV7620AE,
+       SEN_OV6620,
+       SEN_OV6630,
+       SEN_OV6630AE,
+       SEN_OV6630AF,
+       SEN_OV8600,
+       SEN_KS0127,
+       SEN_KS0127B,
+       SEN_SAA7111A,
+};
+
+enum {
+       STATE_SCANNING,         /* Scanning for start */
+       STATE_HEADER,           /* Parsing header */
+       STATE_LINES,            /* Parsing lines */
+};
+
+/* Buffer states */
+enum {
+       BUF_NOT_ALLOCATED,
+       BUF_ALLOCATED,
+};
+
+/* --------- Definition of ioctl interface --------- */
+
+#define OV511_INTERFACE_VER 101
+
+/* LED options */
+enum {
+       LED_OFF,
+       LED_ON,
+       LED_AUTO,
+};
+
+/* Raw frame formats */
+enum {
+       RAWFMT_INVALID,
+       RAWFMT_YUV400,
+       RAWFMT_YUV420,
+       RAWFMT_YUV422,
+       RAWFMT_GBR422,
+};
+
+struct ov511_i2c_struct {
+       unsigned char slave; /* Write slave ID (read ID - 1) */
+       unsigned char reg;   /* Index of register */
+       unsigned char value; /* User sets this w/ write, driver does w/ read */
+       unsigned char mask;  /* Bits to be changed. Not used with read ops */
+};
+
+/* ioctls */
+#define OV511IOC_WI2C     _IOW('v', BASE_VIDIOCPRIVATE + 5, \
+                              struct ov511_i2c_struct)
+#define OV511IOC_RI2C    _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
+                              struct ov511_i2c_struct)
+/* ------------- End IOCTL interface -------------- */
+
+struct usb_ov511;              /* Forward declaration */
+
+struct ov511_sbuf {
+       struct usb_ov511 *ov;
+       unsigned char *data;
+       struct urb *urb;
+       spinlock_t lock;
+       int n;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+struct ov511_regvals {
+       enum {
+               OV511_DONE_BUS,
+               OV511_REG_BUS,
+               OV511_I2C_BUS,
+       } bus;
+       unsigned char reg;
+       unsigned char val;
+};
+
+struct ov511_frame {
+       int framenum;           /* Index of this frame */
+       unsigned char *data;    /* Frame buffer */
+       unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
+       unsigned char *rawdata; /* Raw camera data buffer */
+       unsigned char *compbuf; /* Temp buffer for decompressor */
+
+       int depth;              /* Bytes per pixel */
+       int width;              /* Width application is expecting */
+       int height;             /* Height application is expecting */
+
+       int rawwidth;           /* Actual width of frame sent from camera */
+       int rawheight;          /* Actual height of frame sent from camera */
+
+       int sub_flag;           /* Sub-capture mode for this frame? */
+       unsigned int format;    /* Format for this frame */
+       int compressed;         /* Is frame compressed? */
+
+       volatile int grabstate; /* State of grabbing */
+       int scanstate;          /* State of scanning */
+
+       int bytes_recvd;        /* Number of image bytes received from camera */
+
+       long bytes_read;        /* Amount that has been read() */
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int snapshot;           /* True if frame was a snapshot */
+};
+
+#define DECOMP_INTERFACE_VER 4
+
+/* Compression module operations */
+struct ov51x_decomp_ops {
+       int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
+                         int, int, int);
+       int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
+                         int, int, int);
+       int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
+                         int, int, int);
+       struct module *owner;
+};
+
+struct usb_ov511 {
+       struct video_device *vdev;
+       struct usb_device *dev;
+
+       int customid;
+       char *desc;
+       unsigned char iface;
+       char usb_path[OV511_USB_PATH_LEN];
+
+       /* Determined by sensor type */
+       int maxwidth;
+       int maxheight;
+       int minwidth;
+       int minheight;
+
+       int brightness;
+       int colour;
+       int contrast;
+       int hue;
+       int whiteness;
+       int exposure;
+       int auto_brt;           /* Auto brightness enabled flag */
+       int auto_gain;          /* Auto gain control enabled flag */
+       int auto_exp;           /* Auto exposure enabled flag */
+       int backlight;          /* Backlight exposure algorithm flag */
+       int mirror;             /* Image is reversed horizontally */
+
+       int led_policy;         /* LED: off|on|auto; OV511+ only */
+
+       struct mutex lock;      /* Serializes user-accessible operations */
+       int user;               /* user count for exclusive use */
+
+       int streaming;          /* Are we streaming Isochronous? */
+       int grabbing;           /* Are we grabbing? */
+
+       int compress;           /* Should the next frame be compressed? */
+       int compress_inited;    /* Are compression params uploaded? */
+
+       int lightfreq;          /* Power (lighting) frequency */
+       int bandfilt;           /* Banding filter enabled flag */
+
+       unsigned char *fbuf;    /* Videodev buffer area */
+       unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
+       unsigned char *rawfbuf; /* Raw camera data buffer area */
+
+       int sub_flag;           /* Pix Array subcapture on flag */
+       int subx;               /* Pix Array subcapture x offset */
+       int suby;               /* Pix Array subcapture y offset */
+       int subw;               /* Pix Array subcapture width */
+       int subh;               /* Pix Array subcapture height */
+
+       int curframe;           /* Current receiving sbuf */
+       struct ov511_frame frame[OV511_NUMFRAMES];      
+
+       struct ov511_sbuf sbuf[OV511_NUMSBUF];
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int snap_enabled;       /* Snapshot mode enabled */
+       
+       int bridge;             /* Type of bridge (BRG_*) */
+       int bclass;             /* Class of bridge (BCL_*) */
+       int sensor;             /* Type of image sensor chip (SEN_*) */
+
+       int packet_size;        /* Frame size per isoc desc */
+       int packet_numbering;   /* Is ISO frame numbering enabled? */
+
+       /* Framebuffer/sbuf management */
+       int buf_state;
+       struct mutex buf_lock;
+
+       struct ov51x_decomp_ops *decomp_ops;
+
+       /* Stop streaming while changing picture settings */
+       int stop_during_set;
+
+       int stopped;            /* Streaming is temporarily paused */
+
+       /* Video decoder stuff */
+       int input;              /* Composite, S-VIDEO, etc... */
+       int num_inputs;         /* Number of inputs */
+       int norm;               /* NTSC / PAL / SECAM */
+       int has_decoder;        /* Device has a video decoder */
+       int pal;                /* Device is designed for PAL resolution */
+
+       /* I2C interface */
+       struct mutex i2c_lock;    /* Protect I2C controller regs */
+       unsigned char primary_i2c_slave;  /* I2C write id of sensor */
+
+       /* Control transaction stuff */
+       unsigned char *cbuf;            /* Buffer for payload */
+       struct mutex cbuf_lock;
+};
+
+/* Used to represent a list of values and their respective symbolic names */
+struct symbolic_list {
+       int num;
+       char *name;
+};
+
+#define NOT_DEFINED_STR "Unknown"
+
+/* Returns the name of the matching element in the symbolic_list array. The
+ * end of the list must be marked with an element that has a NULL name.
+ */
+static inline char * 
+symbolic(struct symbolic_list list[], int num)
+{
+       int i;
+
+       for (i = 0; list[i].name != NULL; i++)
+                       if (list[i].num == num)
+                               return (list[i].name);
+
+       return (NOT_DEFINED_STR);
+}
+
+/* Compression stuff */
+
+#define OV511_QUANTABLESIZE    64
+#define OV518_QUANTABLESIZE    32
+
+#define OV511_YQUANTABLE { \
+       0, 1, 1, 2, 2, 3, 3, 4, \
+       1, 1, 1, 2, 2, 3, 4, 4, \
+       1, 1, 2, 2, 3, 4, 4, 4, \
+       2, 2, 2, 3, 4, 4, 4, 4, \
+       2, 2, 3, 4, 4, 5, 5, 5, \
+       3, 3, 4, 4, 5, 5, 5, 5, \
+       3, 4, 4, 4, 5, 5, 5, 5, \
+       4, 4, 4, 4, 5, 5, 5, 5  \
+}
+
+#define OV511_UVQUANTABLE { \
+       0, 2, 2, 3, 4, 4, 4, 4, \
+       2, 2, 2, 4, 4, 4, 4, 4, \
+       2, 2, 3, 4, 4, 4, 4, 4, \
+       3, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4, \
+       4, 4, 4, 4, 4, 4, 4, 4  \
+}
+
+#define OV518_YQUANTABLE { \
+       5, 4, 5, 6, 6, 7, 7, 7, \
+       5, 5, 5, 5, 6, 7, 7, 7, \
+       6, 6, 6, 6, 7, 7, 7, 8, \
+       7, 7, 6, 7, 7, 7, 8, 8  \
+}
+
+#define OV518_UVQUANTABLE { \
+       6, 6, 6, 7, 7, 7, 7, 7, \
+       6, 6, 6, 7, 7, 7, 7, 7, \
+       6, 6, 6, 7, 7, 7, 7, 8, \
+       7, 7, 7, 7, 7, 7, 8, 8  \
+}
+
+#endif
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
new file mode 100644 (file)
index 0000000..2d93a77
--- /dev/null
@@ -0,0 +1,20 @@
+ifneq ($(KERNELRELEASE),)
+
+pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+
+obj-$(CONFIG_USB_PWC) += pwc.o
+
+else
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default:
+       $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+
+endif
+
+clean:
+       rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c 
+       rm -rf .tmp_versions
+
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
new file mode 100644 (file)
index 0000000..04a640d
--- /dev/null
@@ -0,0 +1,236 @@
+This file contains some additional information for the Philips and OEM webcams.
+E-mail: webcam@smcc.demon.nl                        Last updated: 2004-01-19
+Site: http://www.smcc.demon.nl/webcam/
+
+As of this moment, the following cameras are supported:
+ * Philips PCA645
+ * Philips PCA646
+ * Philips PCVC675
+ * Philips PCVC680
+ * Philips PCVC690
+ * Philips PCVC720/40
+ * Philips PCVC730
+ * Philips PCVC740
+ * Philips PCVC750
+ * Askey VC010
+ * Creative Labs Webcam 5
+ * Creative Labs Webcam Pro Ex
+ * Logitech QuickCam 3000 Pro
+ * Logitech QuickCam 4000 Pro
+ * Logitech QuickCam Notebook Pro
+ * Logitech QuickCam Zoom
+ * Logitech QuickCam Orbit
+ * Logitech QuickCam Sphere
+ * Samsung MPC-C10
+ * Samsung MPC-C30
+ * Sotec Afina Eye
+ * AME CU-001
+ * Visionite VCS-UM100
+ * Visionite VCS-UC300
+
+The main webpage for the Philips driver is at the address above. It contains
+a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
+contains decompression routines that allow you to use higher image sizes and
+framerates; in addition the webcam uses less bandwidth on the USB bus (handy
+if you want to run more than 1 camera simultaneously). These routines fall
+under a NDA, and may therefor not be distributed as source; however, its use
+is completely optional.
+
+You can build this code either into your kernel, or as a module. I recommend
+the latter, since it makes troubleshooting a lot easier. The built-in
+microphone is supported through the USB Audio class.
+
+When you load the module you can set some default settings for the
+camera; some programs depend on a particular image-size or -format and
+don't know how to set it properly in the driver. The options are:
+
+size
+   Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
+   'vga', for an image size of resp. 128x96, 160x120, 176x144,
+   320x240, 352x288 and 640x480 (of course, only for those cameras that 
+   support these resolutions).
+
+fps
+   Specifies the desired framerate. Is an integer in the range of 4-30.
+
+fbufs
+   This paramter specifies the number of internal buffers to use for storing 
+   frames from the cam. This will help if the process that reads images from 
+   the cam is a bit slow or momentarely busy. However, on slow machines it 
+   only introduces lag, so choose carefully. The default is 3, which is 
+   reasonable. You can set it between 2 and 5.
+
+mbufs
+   This is an integer between 1 and 10. It will tell the module the number of
+   buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends.
+   The default is 2, which is adequate for most applications (double
+   buffering).
+      
+   Should you experience a lot of 'Dumping frame...' messages during
+   grabbing with a tool that uses mmap(), you might want to increase if. 
+   However, it doesn't really buffer images, it just gives you a bit more
+   slack when your program is behind. But you need a multi-threaded or
+   forked program to really take advantage of these buffers.
+
+   The absolute maximum is 10, but don't set it too high!  Every buffer takes
+   up 460 KB of RAM, so unless you have a lot of memory setting this to
+   something more than 4 is an absolute waste.  This memory is only
+   allocated during open(), so nothing is wasted when the camera is not in
+   use.
+
+power_save
+   When power_save is enabled (set to 1), the module will try to shut down
+   the cam on close() and re-activate on open(). This will save power and
+   turn off the LED. Not all cameras support this though (the 645 and 646
+   don't have power saving at all), and some models don't work either (they
+   will shut down, but never wake up). Consider this experimental. By
+   default this option is disabled.
+
+compression (only useful with the plugin)
+   With this option you can control the compression factor that the camera
+   uses to squeeze the image through the USB bus. You can set the 
+   parameter between 0 and 3:
+     0 = prefer uncompressed images; if the requested mode is not available
+         in an uncompressed format, the driver will silently switch to low
+         compression.
+     1 = low compression.
+     2 = medium compression.
+     3 = high compression.
+      
+   High compression takes less bandwidth of course, but it could also
+   introduce some unwanted artefacts. The default is 2, medium compression.
+   See the FAQ on the website for an overview of which modes require
+   compression.
+
+   The compression parameter does not apply to the 645 and 646 cameras
+   and OEM models derived from those (only a few). Most cams honour this
+   parameter.
+
+leds
+   This settings takes 2 integers, that define the on/off time for the LED
+   (in milliseconds). One of the interesting things that you can do with
+   this is let the LED blink while the camera is in use. This:
+
+     leds=500,500
+      
+   will blink the LED once every second. But with:
+
+     leds=0,0
+
+   the LED never goes on, making it suitable for silent surveillance.
+
+   By default the camera's LED is on solid while in use, and turned off
+   when the camera is not used anymore.
+
+   This parameter works only with the ToUCam range of cameras (720, 730, 740,
+   750) and OEMs. For other cameras this command is silently ignored, and 
+   the LED cannot be controlled.
+
+   Finally: this parameters does not take effect UNTIL the first time you
+   open the camera device. Until then, the LED remains on.
+
+dev_hint
+   A long standing problem with USB devices is their dynamic nature: you
+   never know what device a camera gets assigned; it depends on module load
+   order, the hub configuration, the order in which devices are plugged in,
+   and the phase of the moon (i.e. it can be random). With this option you
+   can give the driver a hint as to what video device node (/dev/videoX) it
+   should use with a specific camera. This is also handy if you have two
+   cameras of the same model.
+
+   A camera is specified by its type (the number from the camera model,
+   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
+   in /proc/bus/usb/devices). A hint consists of a string with the following
+   format:
+
+      [type[.serialnumber]:]node
+      
+   The square brackets mean that both the type and the serialnumber are
+   optional, but a serialnumber cannot be specified without a type (which
+   would be rather pointless). The serialnumber is separated from the type
+   by a '.'; the node number by a ':'.
+   
+   This somewhat cryptic syntax is best explained by a few examples:
+
+     dev_hint=3,5              The first detected cam gets assigned
+                               /dev/video3, the second /dev/video5. Any
+                               other cameras will get the first free 
+                               available slot (see below).
+
+     dev_hint=645:1,680:2      The PCA645 camera will get /dev/video1,
+                               and a PCVC680 /dev/video2.
+                               
+     dev_hint=645.0123:3,645.4567:0    The PCA645 camera with serialnumber 
+                                        0123 goes to /dev/video3, the same
+                                        camera model with the 4567 serial
+                                        gets /dev/video0.
+
+     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the 
+                                next 3 Philips cams will use /dev/video4 
+                                through /dev/video6.
+
+   Some points worth knowing:
+   - Serialnumbers are case sensitive and must be written full, including 
+     leading zeroes (it's treated as a string).
+   - If a device node is already occupied, registration will fail and 
+     the webcam is not available.
+   - You can have up to 64 video devices; be sure to make enough device
+     nodes in /dev if you want to spread the numbers (this does not apply
+     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
+   - If a camera does not match any dev_hint, it will simply get assigned
+     the first available device node, just as it used to be.
+
+trace
+   In order to better detect problems, it is now possible to turn on a
+   'trace' of some of the calls the module makes; it logs all items in your
+   kernel log at debug level.
+
+   The trace variable is a bitmask; each bit represents a certain feature.
+   If you want to trace something, look up the bit value(s) in the table 
+   below, add the values together and supply that to the trace variable.
+
+   Value  Value   Description                                     Default
+   (dec)  (hex)
+       1    0x1   Module initialization; this will log messages       On
+                  while loading and unloading the module
+
+       2    0x2   probe() and disconnect() traces                     On
+
+       4    0x4   Trace open() and close() calls                      Off
+
+       8    0x8   read(), mmap() and associated ioctl() calls         Off
+
+      16   0x10   Memory allocation of buffers, etc.                  Off
+
+      32   0x20   Showing underflow, overflow and Dumping frame       On
+                  messages
+
+      64   0x40   Show viewport and image sizes                       Off
+
+     128   0x80   PWCX debugging                                      Off
+
+   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+   so you would supply trace=12 during insmod or modprobe. If
+   you want to turn the initialization and probing tracing off, set trace=0.
+   The default value for trace is 35 (0x23).
+
+
+
+Example:
+     
+     # modprobe pwc size=cif fps=15 power_save=1
+
+The fbufs, mbufs and trace parameters are global and apply to all connected
+cameras. Each camera has its own set of buffers.
+
+size and fps only specify defaults when you open() the device; this is to
+accommodate some tools that don't set the size. You can change these
+settings after open() with the Video4Linux ioctl() calls. The default of
+defaults is QCIF size at 10 fps.
+
+The compression parameter is semiglobal; it sets the initial compression
+preference for all camera's, but this parameter can be set per camera with
+the VIDIOCPWCSCQUAL ioctl() call.
+
+All parameters are optional.
+
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
new file mode 100644 (file)
index 0000000..0398b81
--- /dev/null
@@ -0,0 +1,1541 @@
+/* Driver for Philips webcam
+   Functions that send various control messages to the webcam, including
+   video modes.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added methods for changing white balance and 
+                          red/green gains
+ */
+
+/* Control functions for the cam; brightness, contrast, video mode, etc. */
+
+#ifdef __KERNEL__
+#include <asm/uaccess.h> 
+#endif
+#include <asm/errno.h>
+#include "pwc.h"
+#include "pwc-ioctl.h"
+#include "pwc-uncompress.h"
+#include "pwc-kiara.h"
+#include "pwc-timon.h"
+
+/* Request types: video */
+#define SET_LUM_CTL                    0x01
+#define GET_LUM_CTL                    0x02
+#define SET_CHROM_CTL                  0x03
+#define GET_CHROM_CTL                  0x04
+#define SET_STATUS_CTL                 0x05
+#define GET_STATUS_CTL                 0x06
+#define SET_EP_STREAM_CTL              0x07
+#define GET_EP_STREAM_CTL              0x08
+#define SET_MPT_CTL                    0x0D
+#define GET_MPT_CTL                    0x0E
+
+/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
+#define AGC_MODE_FORMATTER                     0x2000
+#define PRESET_AGC_FORMATTER                   0x2100
+#define SHUTTER_MODE_FORMATTER                 0x2200
+#define PRESET_SHUTTER_FORMATTER               0x2300
+#define PRESET_CONTOUR_FORMATTER               0x2400
+#define AUTO_CONTOUR_FORMATTER                 0x2500
+#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
+#define CONTRAST_FORMATTER                     0x2700
+#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
+#define FLICKERLESS_MODE_FORMATTER             0x2900
+#define AE_CONTROL_SPEED                       0x2A00
+#define BRIGHTNESS_FORMATTER                   0x2B00
+#define GAMMA_FORMATTER                                0x2C00
+
+/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
+#define WB_MODE_FORMATTER                      0x1000
+#define AWB_CONTROL_SPEED_FORMATTER            0x1100
+#define AWB_CONTROL_DELAY_FORMATTER            0x1200
+#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
+#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
+#define COLOUR_MODE_FORMATTER                  0x1500
+#define SATURATION_MODE_FORMATTER1             0x1600
+#define SATURATION_MODE_FORMATTER2             0x1700
+
+/* Selectors for the Status controls [GS]ET_STATUS_CTL */
+#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
+#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
+#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
+#define READ_AGC_FORMATTER                     0x0500
+#define READ_SHUTTER_FORMATTER                 0x0600
+#define READ_RED_GAIN_FORMATTER                        0x0700
+#define READ_BLUE_GAIN_FORMATTER               0x0800
+#define SENSOR_TYPE_FORMATTER1                 0x0C00
+#define READ_RAW_Y_MEAN_FORMATTER              0x3100
+#define SET_POWER_SAVE_MODE_FORMATTER          0x3200
+#define MIRROR_IMAGE_FORMATTER                 0x3300
+#define LED_FORMATTER                          0x3400
+#define SENSOR_TYPE_FORMATTER2                 0x3700
+
+/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
+#define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
+
+/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
+#define PT_RELATIVE_CONTROL_FORMATTER          0x01
+#define PT_RESET_CONTROL_FORMATTER             0x02
+#define PT_STATUS_FORMATTER                    0x03
+
+static const char *size2name[PSZ_MAX] =
+{
+       "subQCIF",
+       "QSIF",
+       "QCIF",
+       "SIF",
+       "CIF",
+       "VGA",
+};  
+
+/********/
+
+/* Entries for the Nala (645/646) camera; the Nala doesn't have compression 
+   preferences, so you either get compressed or non-compressed streams.
+   
+   An alternate value of 0 means this mode is not available at all.
+ */
+
+struct Nala_table_entry {
+       char alternate;                 /* USB alternate setting */
+       int compressed;                 /* Compressed yes/no */
+
+       unsigned char mode[3];          /* precomputed mode table */
+};
+
+static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
+{
+#include "pwc-nala.h"
+};
+
+
+/****************************************************************************/
+
+
+#define SendControlMsg(request, value, buflen) \
+       usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
+               request, \
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+               value, \
+               pdev->vcinterface, \
+               &buf, buflen, 500)
+
+#define RecvControlMsg(request, value, buflen) \
+       usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
+               request, \
+               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
+               value, \
+               pdev->vcinterface, \
+               &buf, buflen, 500)
+
+
+#if PWC_DEBUG
+void pwc_hexdump(void *p, int len)
+{
+       int i;
+       unsigned char *s;
+       char buf[100], *d;
+
+       s = (unsigned char *)p;
+       d = buf;
+       *d = '\0';
+       Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
+       for (i = 0; i < len; i++) {
+               d += sprintf(d, "%02X ", *s++);
+               if ((i & 0xF) == 0xF) {
+                       Debug("%s\n", buf);
+                       d = buf;
+                       *d = '\0';
+               }
+       }
+       if ((i & 0xF) != 0)
+               Debug("%s\n", buf);
+}
+#endif
+
+static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+{
+       return usb_control_msg(udev,
+               usb_sndctrlpipe(udev, 0),
+               SET_EP_STREAM_CTL,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               VIDEO_OUTPUT_CONTROL_FORMATTER,
+               index,
+               buf, buflen, 1000);
+}
+
+
+
+static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+{
+       unsigned char buf[3];
+       int ret, fps;
+       struct Nala_table_entry *pEntry;
+       int frames2frames[31] =
+       { /* closest match of framerate */
+          0,  0,  0,  0,  4,  /*  0-4  */
+          5,  5,  7,  7, 10,  /*  5-9  */
+          10, 10, 12, 12, 15,  /* 10-14 */
+          15, 15, 15, 20, 20,  /* 15-19 */
+          20, 20, 20, 24, 24,  /* 20-24 */
+          24, 24, 24, 24, 24,  /* 25-29 */
+          24                   /* 30    */
+       };
+       int frames2table[31] = 
+       { 0, 0, 0, 0, 0, /*  0-4  */
+         1, 1, 1, 2, 2, /*  5-9  */
+         3, 3, 4, 4, 4, /* 10-14 */
+         5, 5, 5, 5, 5, /* 15-19 */
+         6, 6, 6, 6, 7, /* 20-24 */
+         7, 7, 7, 7, 7, /* 25-29 */
+         7              /* 30    */
+       };
+       
+       if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
+               return -EINVAL;
+       frames = frames2frames[frames];
+       fps = frames2table[frames];
+       pEntry = &Nala_table[size][fps];
+       if (pEntry->alternate == 0)
+               return -EINVAL;
+
+       if (pEntry->compressed)
+               return -ENOENT; /* Not supported. */
+
+       memcpy(buf, pEntry->mode, 3);   
+       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
+       if (ret < 0) {
+               Debug("Failed to send video command... %d\n", ret);
+               return ret;
+       }
+       if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
+        {
+          switch(pdev->type) {
+            case 645:
+            case 646:
+/*            pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+              break;
+
+            case 675:
+            case 680:
+            case 690:
+            case 720:
+            case 730:
+            case 740:
+            case 750:
+/*            pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+              break;
+          }
+       }
+       pdev->cmd_len = 3;
+       memcpy(pdev->cmd_buf, buf, 3);
+
+       /* Set various parameters */
+       pdev->vframes = frames;
+       pdev->vsize = size;
+       pdev->valternate = pEntry->alternate;
+       pdev->image = pwc_image_sizes[size];
+       pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
+       if (pEntry->compressed) {
+               if (pdev->release < 5) { /* 4 fold compression */
+                       pdev->vbandlength = 528;
+                       pdev->frame_size /= 4;
+               }
+               else {
+                       pdev->vbandlength = 704;
+                       pdev->frame_size /= 3;
+               }
+       }
+       else
+               pdev->vbandlength = 0;
+       return 0;
+}
+
+
+static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+{
+       unsigned char buf[13];
+       const struct Timon_table_entry *pChoose;
+       int ret, fps;
+
+       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
+               return -EINVAL;
+       if (size == PSZ_VGA && frames > 15)
+               return -EINVAL;
+       fps = (frames / 5) - 1;
+
+       /* Find a supported framerate with progressively higher compression ratios
+          if the preferred ratio is not available.
+       */
+       pChoose = NULL;
+       while (compression <= 3) {
+          pChoose = &Timon_table[size][fps][compression];
+          if (pChoose->alternate != 0)
+            break;
+          compression++;
+       }
+       if (pChoose == NULL || pChoose->alternate == 0)
+               return -ENOENT; /* Not supported. */
+
+       memcpy(buf, pChoose->mode, 13);
+       if (snapshot)
+               buf[0] |= 0x80;
+       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
+       if (ret < 0)
+               return ret;
+
+/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+          pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+
+       pdev->cmd_len = 13;
+       memcpy(pdev->cmd_buf, buf, 13);
+
+       /* Set various parameters */
+       pdev->vframes = frames;
+       pdev->vsize = size;
+       pdev->vsnapshot = snapshot;
+       pdev->valternate = pChoose->alternate;
+       pdev->image = pwc_image_sizes[size];
+       pdev->vbandlength = pChoose->bandlength;
+       if (pChoose->bandlength > 0)
+               pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
+       else
+               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+       return 0;
+}
+
+
+static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+{
+       const struct Kiara_table_entry *pChoose = NULL;
+       int fps, ret;
+       unsigned char buf[12];
+       struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
+
+       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
+               return -EINVAL;
+       if (size == PSZ_VGA && frames > 15)
+               return -EINVAL;
+       fps = (frames / 5) - 1;
+
+       /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
+       if (size == PSZ_VGA && frames == 5 && snapshot)
+       {
+               /* Only available in case the raw palette is selected or 
+                  we have the decompressor available. This mode is 
+                  only available in compressed form 
+               */
+               if (pdev->vpalette == VIDEO_PALETTE_RAW)
+               {
+                       Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
+                       pChoose = &RawEntry;
+               }
+               else
+               {
+                       Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
+               }
+       }
+       else
+       {
+               /* Find a supported framerate with progressively higher compression ratios
+                  if the preferred ratio is not available.
+                   Skip this step when using RAW modes.
+               */
+               while (compression <= 3) {
+                       pChoose = &Kiara_table[size][fps][compression];
+                       if (pChoose->alternate != 0)
+                               break;
+                       compression++;
+               }
+       }
+       if (pChoose == NULL || pChoose->alternate == 0)
+               return -ENOENT; /* Not supported. */
+
+       Debug("Using alternate setting %d.\n", pChoose->alternate);
+       
+       /* usb_control_msg won't take staticly allocated arrays as argument?? */
+       memcpy(buf, pChoose->mode, 12);
+       if (snapshot)
+               buf[0] |= 0x80;
+
+       /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
+       ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
+       if (ret < 0)
+               return ret;
+
+/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+         pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+
+       pdev->cmd_len = 12;
+       memcpy(pdev->cmd_buf, buf, 12);
+       /* All set and go */
+       pdev->vframes = frames;
+       pdev->vsize = size;
+       pdev->vsnapshot = snapshot;
+       pdev->valternate = pChoose->alternate;
+       pdev->image = pwc_image_sizes[size];
+       pdev->vbandlength = pChoose->bandlength;
+       if (pdev->vbandlength > 0)
+               pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
+       else
+               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+       return 0;
+}
+
+
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+       int i, factor = 0, filler = 0;
+
+       /* for PALETTE_YUV420P */
+       switch(pdev->vpalette)
+       {
+       case VIDEO_PALETTE_YUV420P:
+               factor = 6;
+               filler = 128;
+               break;
+       case VIDEO_PALETTE_RAW:
+               factor = 6; /* can be uncompressed YUV420P */
+               filler = 0;
+               break;
+       }
+
+       /* Set sizes in bytes */
+       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
+
+       /* Align offset, or you'll get some very weird results in
+          YUV420 mode... x must be multiple of 4 (to get the Y's in
+          place), and y even (or you'll mixup U & V). This is less of a
+          problem for YUV420P.
+        */
+       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+       /* Fill buffers with gray or black */
+       for (i = 0; i < MAX_IMAGES; i++) {
+               if (pdev->image_ptr[i] != NULL)
+                       memset(pdev->image_ptr[i], filler, pdev->view.size);
+       }
+}
+
+
+
+/**
+   @pdev: device structure
+   @width: viewport width
+   @height: viewport height
+   @frame: framerate, in fps
+   @compression: preferred compression ratio
+   @snapshot: snapshot mode or streaming
+ */
+int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
+{
+        int ret, size;
+
+        Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+       size = pwc_decode_size(pdev, width, height);
+       if (size < 0) {
+               Debug("Could not find suitable size.\n");
+               return -ERANGE;
+       }
+       Debug("decode_size = %d.\n", size);
+
+        ret = -EINVAL;
+       switch(pdev->type) {
+       case 645:
+       case 646:
+               ret = set_video_mode_Nala(pdev, size, frames);
+               break;
+
+       case 675:
+       case 680:
+       case 690:
+               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
+               break;
+       
+       case 720:
+       case 730:
+       case 740:
+       case 750:
+               ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
+               break;
+       }
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
+               else {
+                       Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
+               }
+               return ret;
+       }
+       pdev->view.x = width;
+       pdev->view.y = height;
+       pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
+       pwc_set_image_buffer_size(pdev);
+       Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+       return 0;
+}
+
+
+/* BRIGHTNESS */
+
+int pwc_get_brightness(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);     
+       if (ret < 0)
+               return ret;
+       return buf << 9;
+}
+
+int pwc_set_brightness(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       buf = (value >> 9) & 0x7f;
+       return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
+}
+
+/* CONTRAST */
+
+int pwc_get_contrast(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return buf << 10;
+}
+
+int pwc_set_contrast(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       buf = (value >> 10) & 0x3f;
+       return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1);
+}
+
+/* GAMMA */
+
+int pwc_get_gamma(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       return buf << 11;
+}
+
+int pwc_set_gamma(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       buf = (value >> 11) & 0x1f;
+       return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1);
+}
+
+
+/* SATURATION */
+
+int pwc_get_saturation(struct pwc_device *pdev)
+{
+       char buf;
+       int ret;
+
+       if (pdev->type < 675)
+               return -1;
+       ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+       if (ret < 0)
+               return ret;
+       return 32768 + buf * 327;
+}
+
+int pwc_set_saturation(struct pwc_device *pdev, int value)
+{
+       char buf;
+
+       if (pdev->type < 675)
+               return -EINVAL;
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       /* saturation ranges from -100 to +100 */
+       buf = (value - 32768) / 327;
+       return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+}
+
+/* AGC */
+
+static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+{
+       char buf;
+       int ret;
+       
+       if (mode)
+               buf = 0x0; /* auto */
+       else
+               buf = 0xff; /* fixed */
+
+       ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1);
+       
+       if (!mode && ret >= 0) {
+               if (value < 0)
+                       value = 0;
+               if (value > 0xffff)
+                       value = 0xffff;
+               buf = (value >> 10) & 0x3F;
+               ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
+       }
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+
+       if (buf != 0) { /* fixed */
+               ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
+               if (ret < 0)
+                       return ret;
+               if (buf > 0x3F)
+                       buf = 0x3F;
+               *value = (buf << 10);           
+       }
+       else { /* auto */
+               ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1);
+               if (ret < 0)
+                       return ret;
+               /* Gah... this value ranges from 0x00 ... 0x9F */
+               if (buf > 0x9F)
+                       buf = 0x9F;
+               *value = -(48 + buf * 409);
+       }
+
+       return 0;
+}
+
+static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+{
+       char buf[2];
+       int speed, ret;
+
+
+       if (mode)
+               buf[0] = 0x0;   /* auto */
+       else
+               buf[0] = 0xff; /* fixed */
+       
+       ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1);
+
+       if (!mode && ret >= 0) {
+               if (value < 0)
+                       value = 0;
+               if (value > 0xffff)
+                       value = 0xffff;
+               switch(pdev->type) {
+               case 675:
+               case 680:
+               case 690:
+                       /* speed ranges from 0x0 to 0x290 (656) */
+                       speed = (value / 100);
+                       buf[1] = speed >> 8;
+                       buf[0] = speed & 0xff;
+                       break;
+               case 720:
+               case 730:
+               case 740:
+               case 750:
+                       /* speed seems to range from 0x0 to 0xff */
+                       buf[1] = 0;
+                       buf[0] = value >> 8;
+                       break;
+               }
+
+               ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
+       }
+       return ret;
+}      
+
+
+/* POWER */
+
+int pwc_camera_power(struct pwc_device *pdev, int power)
+{
+       char buf;
+
+       if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
+               return 0;       /* Not supported by Nala or Timon < release 6 */
+
+       if (power)
+               buf = 0x00; /* active */
+       else
+               buf = 0xFF; /* power save */
+       return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1);
+}
+
+
+
+/* private calls */
+
+static inline int pwc_restore_user(struct pwc_device *pdev)
+{
+       char buf; /* dummy */
+       return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
+}
+
+static inline int pwc_save_user(struct pwc_device *pdev)
+{
+       char buf; /* dummy */
+       return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
+}
+
+static inline int pwc_restore_factory(struct pwc_device *pdev)
+{
+       char buf; /* dummy */
+       return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
+}
+
+ /* ************************************************* */
+ /* Patch by Alvarado: (not in the original version   */
+
+ /*
+  * the camera recognizes modes from 0 to 4:
+  *
+  * 00: indoor (incandescant lighting)
+  * 01: outdoor (sunlight)
+  * 02: fluorescent lighting
+  * 03: manual
+  * 04: auto
+  */ 
+static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+{
+       char buf;
+       int ret;
+       
+       if (mode < 0)
+           mode = 0;
+       
+       if (mode > 4)
+           mode = 4;
+       
+       buf = mode & 0x07; /* just the lowest three bits */
+       
+       ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1);
+       
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static inline int pwc_get_awb(struct pwc_device *pdev)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1);
+
+       if (ret < 0) 
+               return ret;
+       return buf;
+}
+
+static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+{
+        unsigned char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       /* only the msb is considered */
+       buf = value >> 8;
+       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
+}
+
+static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
+       if (ret < 0)
+           return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+
+static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+{
+       unsigned char buf;
+
+       if (value < 0)
+               value = 0;
+       if (value > 0xffff)
+               value = 0xffff;
+       /* only the msb is considered */
+       buf = value >> 8;
+       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
+}
+
+static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
+       if (ret < 0)
+           return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+
+/* The following two functions are different, since they only read the
+   internal red/blue gains, which may be different from the manual 
+   gains set or read above.
+ */   
+static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf << 8;
+       return 0;
+}
+
+
+static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+{
+       unsigned char buf;
+       
+       /* useful range is 0x01..0x20 */
+       buf = speed / 0x7f0;
+       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
+}
+
+static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf * 0x7f0;
+       return 0;
+}
+
+
+static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+{
+       unsigned char buf;
+       
+       /* useful range is 0x01..0x3F */
+       buf = (delay >> 10);
+       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
+}
+
+static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *value = buf << 10;
+       return 0;
+}
+
+
+int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
+{
+       unsigned char buf[2];
+
+       if (pdev->type < 730)
+               return 0;
+       on_value /= 100;
+       off_value /= 100;
+       if (on_value < 0)
+               on_value = 0;
+       if (on_value > 0xff)
+               on_value = 0xff;
+       if (off_value < 0)
+               off_value = 0;
+       if (off_value > 0xff)
+               off_value = 0xff;
+
+       buf[0] = on_value;
+       buf[1] = off_value;
+
+       return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
+}
+
+static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
+{
+       unsigned char buf[2];
+       int ret;
+       
+       if (pdev->type < 730) {
+               *on_value = -1;
+               *off_value = -1;
+               return 0;
+       }
+
+       ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
+       if (ret < 0)
+               return ret;
+       *on_value = buf[0] * 100;
+       *off_value = buf[1] * 100;
+       return 0;
+}
+
+static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+{
+       unsigned char buf;
+       int ret;
+       
+       if (contour < 0)
+               buf = 0xff; /* auto contour on */
+       else
+               buf = 0x0; /* auto contour off */
+       ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       
+       if (contour < 0)
+               return 0;
+       if (contour > 0xffff)
+               contour = 0xffff;
+       
+       buf = (contour >> 10); /* contour preset is [0..3f] */
+       ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
+       if (ret < 0)    
+               return ret;     
+       return 0;
+}
+
+static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+{
+       unsigned char buf;
+       int ret;
+       
+       ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+
+       if (buf == 0) {
+               /* auto mode off, query current preset value */
+               ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
+               if (ret < 0)    
+                       return ret;
+               *contour = buf << 10;
+       }
+       else
+               *contour = -1;
+       return 0;
+}
+
+
+static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+{
+       unsigned char buf;
+       
+       if (backlight)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
+}
+
+static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+{
+       int ret;
+       unsigned char buf;
+       
+       ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *backlight = buf;
+       return 0;
+}
+
+
+static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+{
+       unsigned char buf;
+       
+       if (flicker)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+}
+
+static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+{
+       int ret;
+       unsigned char buf;
+       
+       ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *flicker = buf;
+       return 0;
+}
+
+
+static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+{
+       unsigned char buf;
+
+       if (noise < 0)
+               noise = 0;
+       if (noise > 3)
+               noise = 3;
+       buf = noise;
+       return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+{
+       int ret;
+       unsigned char buf;
+       
+       ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *noise = buf;
+       return 0;
+}
+
+static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+       unsigned char buf;
+       
+       buf = flags & 0x03; // only lower two bits are currently used
+       return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
+}
+
+static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+       unsigned char buf[4];
+       
+       /* set new relative angle; angles are expressed in degrees * 100,
+          but cam as .5 degree resolution, hence divide by 200. Also
+          the angle must be multiplied by 64 before it's send to
+          the cam (??)
+        */
+       pan  =  64 * pan  / 100;
+       tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
+       buf[0] = pan & 0xFF;
+       buf[1] = (pan >> 8) & 0xFF;
+       buf[2] = tilt & 0xFF;
+       buf[3] = (tilt >> 8) & 0xFF;
+       return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
+}
+
+static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+{
+       int ret;
+       unsigned char buf[5];
+       
+       ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5);
+       if (ret < 0)
+               return ret;
+       status->status = buf[0] & 0x7; // 3 bits are used for reporting
+       status->time_pan = (buf[1] << 8) + buf[2];
+       status->time_tilt = (buf[3] << 8) + buf[4];
+       return 0;
+}
+
+
+int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
+{
+       unsigned char buf;
+       int ret = -1, request;
+       
+       if (pdev->type < 675)
+               request = SENSOR_TYPE_FORMATTER1;
+       else if (pdev->type < 730)
+               return -1; /* The Vesta series doesn't have this call */
+       else
+               request = SENSOR_TYPE_FORMATTER2;
+       
+       ret = RecvControlMsg(GET_STATUS_CTL, request, 1);
+       if (ret < 0)
+               return ret;
+       if (pdev->type < 675)
+               *sensor = buf | 0x100;
+       else
+               *sensor = buf;
+       return 0;
+}
+
+
+ /* End of Add-Ons                                    */
+ /* ************************************************* */
+
+
+int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
+{
+       int ret = 0;
+
+       switch(cmd) {
+       case VIDIOCPWCRUSER:
+       {
+               if (pwc_restore_user(pdev))
+                       ret = -EINVAL;
+               break;
+       }
+       
+       case VIDIOCPWCSUSER:
+       {
+               if (pwc_save_user(pdev))
+                       ret = -EINVAL;
+               break;
+       }
+               
+       case VIDIOCPWCFACTORY:
+       {
+               if (pwc_restore_factory(pdev))
+                       ret = -EINVAL;
+               break;
+       }
+       
+       case VIDIOCPWCSCQUAL:
+       {       
+               int *qual = arg;
+
+               if (*qual < 0 || *qual > 3)
+                       ret = -EINVAL;
+               else
+                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+               if (ret >= 0)
+                       pdev->vcompression = *qual;
+               break;
+       }
+       
+       case VIDIOCPWCGCQUAL:
+       {
+               int *qual = arg;
+               *qual = pdev->vcompression;
+               break;
+       }
+       
+       case VIDIOCPWCPROBE:
+       {
+               struct pwc_probe *probe = arg;
+               strcpy(probe->name, pdev->vdev->name);
+               probe->type = pdev->type;
+               break;
+       }
+
+       case VIDIOCPWCGSERIAL:
+       {
+               struct pwc_serial *serial = arg;
+               strcpy(serial->serial, pdev->serial);
+               break;
+       }
+
+       case VIDIOCPWCSAGC:
+       {
+               int *agc = arg;
+               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+                       ret = -EINVAL;
+               break;
+       }
+       
+       case VIDIOCPWCGAGC:
+       {
+               int *agc = arg;
+               
+               if (pwc_get_agc(pdev, agc))
+                       ret = -EINVAL;
+               break;
+       }
+       
+       case VIDIOCPWCSSHUTTER:
+       {
+               int *shutter_speed = arg;
+               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+               break;
+       }
+       
+        case VIDIOCPWCSAWB:
+       {
+               struct pwc_whitebalance *wb = arg;
+               
+               ret = pwc_set_awb(pdev, wb->mode);
+               if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
+                       pwc_set_red_gain(pdev, wb->manual_red);
+                       pwc_set_blue_gain(pdev, wb->manual_blue);
+               }
+               break;
+       }
+
+       case VIDIOCPWCGAWB:
+       {
+               struct pwc_whitebalance *wb = arg;
+
+               memset(wb, 0, sizeof(struct pwc_whitebalance));
+               wb->mode = pwc_get_awb(pdev);
+               if (wb->mode < 0)
+                       ret = -EINVAL;
+               else {
+                       if (wb->mode == PWC_WB_MANUAL) {
+                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
+                               if (ret < 0)
+                                       break;
+                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+                               if (ret < 0)
+                                       break;
+                       }
+                       if (wb->mode == PWC_WB_AUTO) {
+                               ret = pwc_read_red_gain(pdev, &wb->read_red);
+                               if (ret < 0)
+                                       break;
+                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+                               if (ret < 0)
+                                       break;
+                       }
+               }
+               break;
+       }
+       
+       case VIDIOCPWCSAWBSPEED:
+       {
+               struct pwc_wb_speed *wbs = arg;
+               
+               if (wbs->control_speed > 0) {
+                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+               }
+               if (wbs->control_delay > 0) {
+                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+               }
+               break;
+       }
+       
+       case VIDIOCPWCGAWBSPEED:
+       {
+               struct pwc_wb_speed *wbs = arg;
+               
+               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+               if (ret < 0)
+                       break;
+               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+               if (ret < 0)
+                       break;
+               break;
+       }
+
+        case VIDIOCPWCSLED:
+       {
+               struct pwc_leds *leds = arg;
+               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
+               break;
+       }
+
+
+       case VIDIOCPWCGLED:
+       {
+               struct pwc_leds *leds = arg;
+               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+               break;
+       }
+
+       case VIDIOCPWCSCONTOUR:
+       {
+               int *contour = arg;
+               ret = pwc_set_contour(pdev, *contour);
+               break;
+       }
+                       
+       case VIDIOCPWCGCONTOUR:
+       {
+               int *contour = arg;
+               ret = pwc_get_contour(pdev, contour);
+               break;
+       }
+       
+       case VIDIOCPWCSBACKLIGHT:
+       {
+               int *backlight = arg;
+               ret = pwc_set_backlight(pdev, *backlight);
+               break;
+       }
+
+       case VIDIOCPWCGBACKLIGHT:
+       {
+               int *backlight = arg;
+               ret = pwc_get_backlight(pdev, backlight);
+               break;
+       }
+       
+       case VIDIOCPWCSFLICKER:
+       {
+               int *flicker = arg;
+               ret = pwc_set_flicker(pdev, *flicker);
+               break;
+       }
+
+       case VIDIOCPWCGFLICKER:
+       {
+               int *flicker = arg;
+               ret = pwc_get_flicker(pdev, flicker);
+               break;
+       }
+       
+       case VIDIOCPWCSDYNNOISE:
+       {
+               int *dynnoise = arg;
+               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+               break;
+       }
+       
+       case VIDIOCPWCGDYNNOISE:
+       {
+               int *dynnoise = arg;
+               ret = pwc_get_dynamic_noise(pdev, dynnoise);
+               break;
+       }
+
+       case VIDIOCPWCGREALSIZE:
+       {
+               struct pwc_imagesize *size = arg;
+               size->width = pdev->image.x;
+               size->height = pdev->image.y;
+               break;
+       }
+       
+       case VIDIOCPWCMPTRESET:
+       {
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       int *flags = arg;
+
+                       ret = pwc_mpt_reset(pdev, *flags);
+                       if (ret >= 0)
+                       {
+                               pdev->pan_angle = 0;
+                               pdev->tilt_angle = 0;
+                       }
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;          
+       }
+       
+       case VIDIOCPWCMPTGRANGE:
+       {
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_range *range = arg;
+                       *range = pdev->angle_range;
+               }
+               else
+               {       
+                       ret = -ENXIO;
+               }
+               break;
+       }
+       
+       case VIDIOCPWCMPTSANGLE:
+       {
+               int new_pan, new_tilt;
+               
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_angles *angles = arg;
+                       /* The camera can only set relative angles, so
+                          do some calculations when getting an absolute angle .
+                        */
+                       if (angles->absolute)
+                       {
+                               new_pan  = angles->pan;
+                               new_tilt = angles->tilt;
+                       }
+                       else
+                       {
+                               new_pan  = pdev->pan_angle  + angles->pan;
+                               new_tilt = pdev->tilt_angle + angles->tilt;
+                       }
+                       /* check absolute ranges */
+                       if (new_pan  < pdev->angle_range.pan_min  ||
+                           new_pan  > pdev->angle_range.pan_max  ||
+                           new_tilt < pdev->angle_range.tilt_min ||
+                           new_tilt > pdev->angle_range.tilt_max)
+                       {
+                               ret = -ERANGE;
+                       }
+                       else
+                       {
+                               /* go to relative range, check again */
+                               new_pan  -= pdev->pan_angle;
+                               new_tilt -= pdev->tilt_angle;
+                               /* angles are specified in degrees * 100, thus the limit = 36000 */
+                               if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
+                                       ret = -ERANGE;
+                       }
+                       if (ret == 0) /* no errors so far */
+                       {
+                               ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
+                               if (ret >= 0)
+                               {
+                                       pdev->pan_angle  += new_pan;
+                                       pdev->tilt_angle += new_tilt;
+                               }
+                               if (ret == -EPIPE) /* stall -> out of range */
+                                       ret = -ERANGE;                          
+                       }
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCMPTGANGLE:
+       {
+               
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_angles *angles = arg;
+
+                       angles->absolute = 1;
+                       angles->pan  = pdev->pan_angle;
+                       angles->tilt = pdev->tilt_angle;
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+       case VIDIOCPWCMPTSTATUS:
+       {
+               if (pdev->features & FEATURE_MOTOR_PANTILT)
+               {
+                       struct pwc_mpt_status *status = arg;
+                       ret = pwc_mpt_get_status(pdev, status);
+               }
+               else
+               {
+                       ret = -ENXIO;
+               }
+               break;
+       }
+
+       case VIDIOCPWCGVIDCMD:
+       {
+               struct pwc_video_command *cmd = arg;
+               
+                cmd->type = pdev->type;
+               cmd->release = pdev->release;
+               cmd->command_len = pdev->cmd_len;
+               memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
+               cmd->bandlength = pdev->vbandlength;
+               cmd->frame_size = pdev->frame_size;
+               break;
+       }
+       /*
+       case VIDIOCPWCGVIDTABLE:
+       {
+               struct pwc_table_init_buffer *table = arg;
+               table->len = pdev->cmd_len;
+               memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+               break;
+       }
+       */
+
+       default:
+               ret = -ENOIOCTLCMD;
+               break;
+       }
+       
+       if (ret > 0)
+               return 0;
+       return ret;
+}
+
+
+
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
new file mode 100644 (file)
index 0000000..90eb260
--- /dev/null
@@ -0,0 +1,2205 @@
+/* Linux driver for Philips webcam
+   USB and Video4Linux interface part.
+   (C) 1999-2004 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*  
+   This code forms the interface between the USB layers and the Philips
+   specific stuff. Some adanved stuff of the driver falls under an
+   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
+   is thus not distributed in source form. The binary pwcx.o module 
+   contains the code that falls under the NDA.
+   
+   In case you're wondering: 'pwc' stands for "Philips WebCam", but 
+   I really didn't want to type 'philips_web_cam' every time (I'm lazy as
+   any Linux kernel hacker, but I don't like uncomprehensible abbreviations
+   without explanation).
+   
+   Oh yes, convention: to disctinguish between all the various pointers to
+   device-structures, I use these names for the pointer variables:
+   udev: struct usb_device *
+   vdev: struct video_device *
+   pdev: struct pwc_devive *
+*/
+
+/* Contributors:
+   - Alvarado: adding whitebalance code
+   - Alistar Moire: QuickCam 3000 Pro device/product ID
+   - Tony Hoyle: Creative Labs Webcam 5 device/product ID
+   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
+   - Jk Fang: Sotec Afina Eye ID
+   - Xavier Roche: QuickCam Pro 4000 ID
+   - Jens Knudsen: QuickCam Zoom ID
+   - J. Debert: QuickCam for Notebooks ID
+*/
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+#include "pwc-ioctl.h"
+#include "pwc-kiara.h"
+#include "pwc-timon.h"
+#include "pwc-uncompress.h"
+
+/* Function prototypes and driver templates */
+
+/* hotplug device table support */
+static struct usb_device_id pwc_device_table [] = {
+       { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
+       { USB_DEVICE(0x0471, 0x0303) },
+       { USB_DEVICE(0x0471, 0x0304) },
+       { USB_DEVICE(0x0471, 0x0307) },
+       { USB_DEVICE(0x0471, 0x0308) },
+       { USB_DEVICE(0x0471, 0x030C) },
+       { USB_DEVICE(0x0471, 0x0310) },
+       { USB_DEVICE(0x0471, 0x0311) },
+       { USB_DEVICE(0x0471, 0x0312) },
+       { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+       { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
+       { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
+       { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
+       { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
+       { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
+       { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
+       { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
+       { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
+       { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
+       { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
+       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
+       { USB_DEVICE(0x055D, 0x9001) },
+       { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
+       { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
+       { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
+       { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
+       { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
+       { USB_DEVICE(0x0d81, 0x1900) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, pwc_device_table);
+
+static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
+static void usb_pwc_disconnect(struct usb_interface *intf);
+
+static struct usb_driver pwc_driver = {
+       .name =                 "Philips webcam",       /* name */
+       .id_table =             pwc_device_table,
+       .probe =                usb_pwc_probe,          /* probe() */
+       .disconnect =           usb_pwc_disconnect,     /* disconnect() */
+};
+
+#define MAX_DEV_HINTS  20
+#define MAX_ISOC_ERRORS        20
+
+static int default_size = PSZ_QCIF;
+static int default_fps = 10;
+static int default_fbufs = 3;   /* Default number of frame buffers */
+static int default_mbufs = 2;  /* Default number of mmap() buffers */
+       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+static int power_save = 0;
+static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
+static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static struct {
+       int type;
+       char serial_number[30];
+       int device_node;
+       struct pwc_device *pdev;
+} device_hint[MAX_DEV_HINTS];
+
+/***/
+
+static int pwc_video_open(struct inode *inode, struct file *file);
+static int pwc_video_close(struct inode *inode, struct file *file);
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
+                         size_t count, loff_t *ppos);
+static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
+static int  pwc_video_ioctl(struct inode *inode, struct file *file,
+                           unsigned int ioctlnr, unsigned long arg);
+static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
+
+static struct file_operations pwc_fops = {
+       .owner =        THIS_MODULE,
+       .open =         pwc_video_open,
+       .release =      pwc_video_close,
+       .read =         pwc_video_read,
+       .poll =         pwc_video_poll,
+       .mmap =         pwc_video_mmap,
+       .ioctl =        pwc_video_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+static struct video_device pwc_template = {
+       .owner =        THIS_MODULE,
+       .name =         "Philips Webcam",       /* Filled in later */
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_PWC,
+       .release =      video_device_release,
+       .fops =         &pwc_fops,
+       .minor =        -1,
+};
+
+/***************************************************************************/
+
+/* Okay, this is some magic that I worked out and the reasoning behind it...
+
+   The biggest problem with any USB device is of course: "what to do 
+   when the user unplugs the device while it is in use by an application?"
+   We have several options:
+   1) Curse them with the 7 plagues when they do (requires divine intervention)
+   2) Tell them not to (won't work: they'll do it anyway)
+   3) Oops the kernel (this will have a negative effect on a user's uptime)
+   4) Do something sensible.
+   
+   Of course, we go for option 4.
+
+   It happens that this device will be linked to two times, once from
+   usb_device and once from the video_device in their respective 'private'
+   pointers. This is done when the device is probed() and all initialization
+   succeeded. The pwc_device struct links back to both structures.
+
+   When a device is unplugged while in use it will be removed from the 
+   list of known USB devices; I also de-register it as a V4L device, but 
+   unfortunately I can't free the memory since the struct is still in use
+   by the file descriptor. This free-ing is then deferend until the first
+   opportunity. Crude, but it works.
+   
+   A small 'advantage' is that if a user unplugs the cam and plugs it back
+   in, it should get assigned the same video device minor, but unfortunately
+   it's non-trivial to re-link the cam back to the video device... (that 
+   would surely be magic! :))
+*/
+
+/***************************************************************************/
+/* Private functions */
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the area.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
+{
+        unsigned long kva, ret;
+
+       kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
+       kva |= adr & (PAGE_SIZE-1); /* restore the offset */
+       ret = __pa(kva);
+        return ret;
+}
+
+static void * rvmalloc(unsigned long size)
+{
+       void * mem;
+       unsigned long adr;
+
+       size=PAGE_ALIGN(size);
+        mem=vmalloc_32(size);
+       if (mem) 
+       {
+               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+               adr=(unsigned long) mem;
+               while (size > 0) 
+                {
+                       SetPageReserved(vmalloc_to_page((void *)adr));
+                       adr+=PAGE_SIZE;
+                       size-=PAGE_SIZE;
+               }
+       }
+       return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+        unsigned long adr;
+
+       if (mem) 
+       {
+               adr=(unsigned long) mem;
+               while ((long) size > 0) 
+                {
+                       ClearPageReserved(vmalloc_to_page((void *)adr));
+                       adr+=PAGE_SIZE;
+                       size-=PAGE_SIZE;
+               }
+               vfree(mem);
+       }
+}
+
+
+
+
+static int pwc_allocate_buffers(struct pwc_device *pdev)
+{
+       int i;
+       void *kbuf;
+
+       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+
+       if (pdev == NULL)
+               return -ENXIO;
+               
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("allocate_buffers(): magic failed.\n");
+               return -ENXIO;
+       }
+#endif 
+       /* Allocate Isochronous pipe buffers */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               if (pdev->sbuf[i].data == NULL) {
+                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+                       if (kbuf == NULL) {
+                               Err("Failed to allocate iso buffer %d.\n", i);
+                               return -ENOMEM;
+                       }
+                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+                       pdev->sbuf[i].data = kbuf;
+                       memset(kbuf, 0, ISO_BUFFER_SIZE);
+               }
+       }
+
+       /* Allocate frame buffer structure */
+       if (pdev->fbuf == NULL) {
+               kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+               if (kbuf == NULL) {
+                       Err("Failed to allocate frame buffer structure.\n");
+                       return -ENOMEM;
+               }
+               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+               pdev->fbuf = kbuf;
+               memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
+       }
+       /* create frame buffers, and make circular ring */
+       for (i = 0; i < default_fbufs; i++) {
+               if (pdev->fbuf[i].data == NULL) {
+                       kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
+                       if (kbuf == NULL) {
+                               Err("Failed to allocate frame buffer %d.\n", i);
+                               return -ENOMEM;
+                       }
+                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+                       pdev->fbuf[i].data = kbuf;
+                       memset(kbuf, 128, PWC_FRAME_SIZE);
+               }
+       }
+       
+       /* Allocate decompressor table space */
+       kbuf = NULL;
+       switch (pdev->type)
+        {
+         case 675:
+         case 680:
+         case 690:
+         case 720:
+         case 730:
+         case 740:
+         case 750:
+#if 0    
+           Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
+           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);       /* Timon & Kiara */
+           break;
+         case 645:
+         case 646:
+           /* TODO & FIXME */
+           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+           break;
+#endif  
+       ;
+        }
+       pdev->decompress_data = kbuf;
+       
+       /* Allocate image buffer; double buffer for mmap() */
+       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+       if (kbuf == NULL) {
+               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+               return -ENOMEM;
+       }
+       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+       pdev->image_data = kbuf;
+       for (i = 0; i < default_mbufs; i++)
+               pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
+       for (; i < MAX_IMAGES; i++)
+               pdev->image_ptr[i] = NULL;
+
+       kbuf = NULL;
+         
+       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+       return 0;
+}
+
+static void pwc_free_buffers(struct pwc_device *pdev)
+{
+       int i;
+
+       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+
+       if (pdev == NULL)
+               return;
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("free_buffers(): magic failed.\n");
+               return;
+       }
+#endif 
+
+       /* Release Iso-pipe buffers */
+       for (i = 0; i < MAX_ISO_BUFS; i++)
+               if (pdev->sbuf[i].data != NULL) {
+                       Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+                       kfree(pdev->sbuf[i].data);
+                       pdev->sbuf[i].data = NULL;
+               }
+
+       /* The same for frame buffers */
+       if (pdev->fbuf != NULL) {
+               for (i = 0; i < default_fbufs; i++) {
+                       if (pdev->fbuf[i].data != NULL) {
+                               Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+                               vfree(pdev->fbuf[i].data);
+                               pdev->fbuf[i].data = NULL;
+                       }
+               }
+               kfree(pdev->fbuf);
+               pdev->fbuf = NULL;
+       }
+
+       /* Intermediate decompression buffer & tables */
+       if (pdev->decompress_data != NULL) {
+               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+               kfree(pdev->decompress_data);
+               pdev->decompress_data = NULL;
+       }
+       pdev->decompressor = NULL;
+
+       /* Release image buffers */
+       if (pdev->image_data != NULL) {
+               Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
+               rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+       }
+       pdev->image_data = NULL;
+       
+       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+}
+
+/* The frame & image buffer mess. 
+
+   Yes, this is a mess. Well, it used to be simple, but alas...  In this
+   module, 3 buffers schemes are used to get the data from the USB bus to
+   the user program. The first scheme involves the ISO buffers (called thus
+   since they transport ISO data from the USB controller), and not really
+   interesting. Suffices to say the data from this buffer is quickly 
+   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
+   frame buffer.
+
+   The frame buffer is the second scheme, and is the central element here.
+   It collects the data from a single frame from the camera (hence, the
+   name). Frames are delimited by the USB camera with a short USB packet,
+   so that's easy to detect. The frame buffers form a list that is filled
+   by the camera+USB controller and drained by the user process through
+   either read() or mmap().
+
+   The image buffer is the third scheme, in which frames are decompressed
+   and converted into planar format. For mmap() there is more than
+   one image buffer available.
+
+   The frame buffers provide the image buffering. In case the user process
+   is a bit slow, this introduces lag and some undesired side-effects.
+   The problem arises when the frame buffer is full. I used to drop the last
+   frame, which makes the data in the queue stale very quickly. But dropping
+   the frame at the head of the queue proved to be a litte bit more difficult.
+   I tried a circular linked scheme, but this introduced more problems than
+   it solved.
+
+   Because filling and draining are completely asynchronous processes, this
+   requires some fiddling with pointers and mutexes.
+
+   Eventually, I came up with a system with 2 lists: an 'empty' frame list
+   and a 'full' frame list:
+     * Initially, all frame buffers but one are on the 'empty' list; the one
+       remaining buffer is our initial fill frame.
+     * If a frame is needed for filling, we try to take it from the 'empty' 
+       list, unless that list is empty, in which case we take the buffer at 
+       the head of the 'full' list.
+     * When our fill buffer has been filled, it is appended to the 'full'
+       list.
+     * If a frame is needed by read() or mmap(), it is taken from the head of
+       the 'full' list, handled, and then appended to the 'empty' list. If no
+       buffer is present on the 'full' list, we wait.
+   The advantage is that the buffer that is currently being decompressed/
+   converted, is on neither list, and thus not in our way (any other scheme
+   I tried had the problem of old data lingering in the queue).
+
+   Whatever strategy you choose, it always remains a tradeoff: with more
+   frame buffers the chances of a missed frame are reduced. On the other
+   hand, on slower machines it introduces lag because the queue will
+   always be full.
+ */
+
+/**
+  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
+ */
+static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+{
+       int ret;
+       unsigned long flags;
+
+       ret = 0;
+       spin_lock_irqsave(&pdev->ptrlock, flags);
+       if (pdev->fill_frame != NULL) {
+               /* append to 'full' list */
+               if (pdev->full_frames == NULL) {
+                       pdev->full_frames = pdev->fill_frame;
+                       pdev->full_frames_tail = pdev->full_frames;
+               }
+               else {
+                       pdev->full_frames_tail->next = pdev->fill_frame;
+                       pdev->full_frames_tail = pdev->fill_frame;
+               }
+       }
+       if (pdev->empty_frames != NULL) {
+               /* We have empty frames available. That's easy */
+               pdev->fill_frame = pdev->empty_frames;
+               pdev->empty_frames = pdev->empty_frames->next;
+       }
+       else {
+               /* Hmm. Take it from the full list */
+#if PWC_DEBUG
+               /* sanity check */
+               if (pdev->full_frames == NULL) {
+                       Err("Neither empty or full frames available!\n");
+                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+                       return -EINVAL;
+               }
+#endif
+               pdev->fill_frame = pdev->full_frames;
+               pdev->full_frames = pdev->full_frames->next;
+               ret = 1;
+       }
+       pdev->fill_frame->next = NULL;
+#if PWC_DEBUG
+       Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
+       pdev->fill_frame->sequence = pdev->sequence++;
+#endif
+       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+       return ret;
+}
+
+
+/**
+  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
+
+  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
+ */
+static void pwc_reset_buffers(struct pwc_device *pdev)
+{
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdev->ptrlock, flags);
+       pdev->full_frames = NULL;
+       pdev->full_frames_tail = NULL;
+       for (i = 0; i < default_fbufs; i++) {
+               pdev->fbuf[i].filled = 0;
+               if (i > 0)
+                       pdev->fbuf[i].next = &pdev->fbuf[i - 1];
+               else
+                       pdev->fbuf->next = NULL;
+       }
+       pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
+       pdev->empty_frames_tail = pdev->fbuf;
+       pdev->read_frame = NULL;
+       pdev->fill_frame = pdev->empty_frames;
+       pdev->empty_frames = pdev->empty_frames->next;
+
+       pdev->image_read_pos = 0;
+       pdev->fill_image = 0;
+       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+}
+
+
+/**
+  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
+ */
+static int pwc_handle_frame(struct pwc_device *pdev)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdev->ptrlock, flags);
+       /* First grab our read_frame; this is removed from all lists, so
+          we can release the lock after this without problems */
+       if (pdev->read_frame != NULL) {
+               /* This can't theoretically happen */
+               Err("Huh? Read frame still in use?\n");
+       }
+       else {
+               if (pdev->full_frames == NULL) {
+                       Err("Woops. No frames ready.\n");
+               }
+               else {
+                       pdev->read_frame = pdev->full_frames;
+                       pdev->full_frames = pdev->full_frames->next;
+                       pdev->read_frame->next = NULL;
+               }
+
+               if (pdev->read_frame != NULL) {
+#if PWC_DEBUG
+                       Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
+#endif
+                       /* Decompression is a lenghty process, so it's outside of the lock.
+                          This gives the isoc_handler the opportunity to fill more frames
+                          in the mean time.
+                       */
+                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+                       ret = pwc_decompress(pdev);
+                       spin_lock_irqsave(&pdev->ptrlock, flags);
+
+                       /* We're done with read_buffer, tack it to the end of the empty buffer list */
+                       if (pdev->empty_frames == NULL) {
+                               pdev->empty_frames = pdev->read_frame;
+                               pdev->empty_frames_tail = pdev->empty_frames;
+                       }
+                       else {
+                               pdev->empty_frames_tail->next = pdev->read_frame;
+                               pdev->empty_frames_tail = pdev->read_frame;
+                       }
+                       pdev->read_frame = NULL;
+               }
+       }
+       spin_unlock_irqrestore(&pdev->ptrlock, flags);
+       return ret;
+}
+
+/**
+  \brief Advance pointers of image buffer (after each user request)
+*/
+static inline void pwc_next_image(struct pwc_device *pdev)
+{
+       pdev->image_used[pdev->fill_image] = 0;
+       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+}
+
+
+/* This gets called for the Isochronous pipe (video). This is done in
+ * interrupt time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
+{
+       struct pwc_device *pdev;
+       int i, fst, flen;
+       int awake;
+       struct pwc_frame_buf *fbuf;
+       unsigned char *fillptr = NULL, *iso_buf = NULL;
+
+       awake = 0;
+       pdev = (struct pwc_device *)urb->context;
+       if (pdev == NULL) {
+               Err("isoc_handler() called with NULL device?!\n");
+               return;
+       }
+#ifdef PWC_MAGIC
+       if (pdev->magic != PWC_MAGIC) {
+               Err("isoc_handler() called with bad magic!\n");
+               return;
+       }
+#endif
+       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
+               Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+               return;
+       }
+       if (urb->status != -EINPROGRESS && urb->status != 0) {
+               const char *errmsg;
+
+               errmsg = "Unknown";
+               switch(urb->status) {
+                       case -ENOSR:            errmsg = "Buffer error (overrun)"; break;
+                       case -EPIPE:            errmsg = "Stalled (device not responding)"; break;
+                       case -EOVERFLOW:        errmsg = "Babble (bad cable?)"; break;
+                       case -EPROTO:           errmsg = "Bit-stuff error (bad cable?)"; break;
+                       case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
+                       case -ETIMEDOUT:        errmsg = "NAK (device does not respond)"; break;
+               }
+               Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+               /* Give up after a number of contiguous errors on the USB bus. 
+                  Appearantly something is wrong so we simulate an unplug event.
+                */
+               if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
+               {
+                       Info("Too many ISOC errors, bailing out.\n");
+                       pdev->error_status = EIO;
+                       awake = 1;
+                       wake_up_interruptible(&pdev->frameq);
+               }
+               goto handler_end; // ugly, but practical
+       }
+
+       fbuf = pdev->fill_frame;
+       if (fbuf == NULL) {
+               Err("pwc_isoc_handler without valid fill frame.\n");
+               awake = 1;
+               goto handler_end;
+       }
+       else {
+               fillptr = fbuf->data + fbuf->filled;
+       }
+
+       /* Reset ISOC error counter. We did get here, after all. */
+       pdev->visoc_errors = 0;
+
+       /* vsync: 0 = don't copy data
+                 1 = sync-hunt
+                 2 = synched
+        */
+       /* Compact data */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               fst  = urb->iso_frame_desc[i].status;
+               flen = urb->iso_frame_desc[i].actual_length;
+               iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               if (fst == 0) {
+                       if (flen > 0) { /* if valid data... */
+                               if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
+                                       pdev->vsync = 2;
+
+                                       /* ...copy data to frame buffer, if possible */
+                                       if (flen + fbuf->filled > pdev->frame_total_size) {
+                                               Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+                                               pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
+                                               pdev->vframes_error++;
+                                       }
+                                       else {
+                                               memmove(fillptr, iso_buf, flen);
+                                               fillptr += flen;
+                                       }
+                               }
+                               fbuf->filled += flen;
+                       } /* ..flen > 0 */
+
+                       if (flen < pdev->vlast_packet_size) {
+                               /* Shorter packet... We probably have the end of an image-frame; 
+                                  wake up read() process and let select()/poll() do something.
+                                  Decompression is done in user time over there.
+                                */
+                               if (pdev->vsync == 2) {
+                                       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus 
+                                          frames on the USB wire after an exposure change. This conditition is 
+                                          however detected  in the cam and a bit is set in the header.
+                                        */
+                                       if (pdev->type == 730) {
+                                               unsigned char *ptr = (unsigned char *)fbuf->data;
+                                               
+                                               if (ptr[1] == 1 && ptr[0] & 0x10) {
+#if PWC_DEBUG
+                                                       Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
+#endif
+                                                       pdev->drop_frames += 2;
+                                                       pdev->vframes_error++;
+                                               }
+                                               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                                                       if (ptr[0] & 0x01)
+                                                               Info("Snapshot button pressed.\n");
+                                                       else
+                                                               Info("Snapshot button released.\n");
+                                               }
+                                               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+                                                       if (ptr[0] & 0x02)
+                                                               Info("Image is mirrored.\n");
+                                                       else
+                                                               Info("Image is normal.\n");
+                                               }
+                                               pdev->vmirror = ptr[0] & 0x03;
+                                               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
+                                                  after a short frame; this condition is filtered out specifically. A 4 byte
+                                                  frame doesn't make sense anyway.
+                                                  So we get either this sequence: 
+                                                       drop_bit set -> 4 byte frame -> short frame -> good frame
+                                                  Or this one:
+                                                       drop_bit set -> short frame -> good frame
+                                                  So we drop either 3 or 2 frames in all!
+                                                */
+                                               if (fbuf->filled == 4)
+                                                       pdev->drop_frames++;
+                                       }
+
+                                       /* In case we were instructed to drop the frame, do so silently.
+                                          The buffer pointers are not updated either (but the counters are reset below).
+                                        */
+                                       if (pdev->drop_frames > 0)
+                                               pdev->drop_frames--;
+                                       else {
+                                               /* Check for underflow first */
+                                               if (fbuf->filled < pdev->frame_total_size) {
+                                                       Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
+                                                       pdev->vframes_error++;
+                                               }
+                                               else {
+                                                       /* Send only once per EOF */
+                                                       awake = 1; /* delay wake_ups */
+
+                                                       /* Find our next frame to fill. This will always succeed, since we
+                                                        * nick a frame from either empty or full list, but if we had to
+                                                        * take it from the full list, it means a frame got dropped.
+                                                        */
+                                                       if (pwc_next_fill_frame(pdev)) {
+                                                               pdev->vframes_dumped++;
+                                                               if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
+                                                                       if (pdev->vframes_dumped < 20)
+                                                                               Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
+                                                                       if (pdev->vframes_dumped == 20)
+                                                                               Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
+                                                               }
+                                                       }
+                                                       fbuf = pdev->fill_frame;
+                                               }
+                                       } /* !drop_frames */
+                                       pdev->vframe_count++;
+                               }
+                               fbuf->filled = 0;
+                               fillptr = fbuf->data;
+                               pdev->vsync = 1;
+                       } /* .. flen < last_packet_size */
+                       pdev->vlast_packet_size = flen;
+               } /* ..status == 0 */
+#if PWC_DEBUG
+               /* This is normally not interesting to the user, unless you are really debugging something */
+               else {
+                       static int iso_error = 0;
+                       iso_error++;
+                       if (iso_error < 20)
+                               Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+               }
+#endif
+       }
+
+handler_end:
+       if (awake)
+               wake_up_interruptible(&pdev->frameq);
+
+       urb->dev = pdev->udev;
+       i = usb_submit_urb(urb, GFP_ATOMIC);
+       if (i != 0)
+               Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+}
+
+
+static int pwc_isoc_init(struct pwc_device *pdev)
+{
+       struct usb_device *udev;
+       struct urb *urb;
+       int i, j, ret;
+
+       struct usb_interface *intf;
+       struct usb_host_interface *idesc = NULL;
+
+       if (pdev == NULL)
+               return -EFAULT;
+       if (pdev->iso_init)
+               return 0;
+       pdev->vsync = 0;
+       udev = pdev->udev;
+
+       /* Get the current alternate interface, adjust packet size */
+       if (!udev->actconfig)
+               return -EFAULT;
+
+       intf = usb_ifnum_to_if(udev, 0);
+       if (intf)
+               idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
+               
+       if (!idesc)
+               return -EFAULT;
+
+       /* Search video endpoint */
+       pdev->vmax_packet_size = -1;
+       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+               if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
+                       pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
+                       break;
+               }
+       
+       if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
+               Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+               return -ENFILE; /* Odd error, that should be noticeable */
+       }
+
+       /* Set alternate interface */
+       ret = 0;
+       Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+       ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
+               if (urb == NULL) {
+                       Err("Failed to allocate urb %d\n", i);
+                       ret = -ENOMEM;
+                       break;
+               }
+               pdev->sbuf[i].urb = urb;
+               Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+       }
+       if (ret) {
+               /* De-allocate in reverse order */
+               while (i >= 0) {
+                       if (pdev->sbuf[i].urb != NULL)
+                               usb_free_urb(pdev->sbuf[i].urb);
+                       pdev->sbuf[i].urb = NULL;
+                       i--;
+               }
+               return ret;
+       }
+
+       /* init URB structure */        
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               urb = pdev->sbuf[i].urb;
+
+               urb->interval = 1; // devik
+               urb->dev = udev;
+               urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = pdev->sbuf[i].data;
+               urb->transfer_buffer_length = ISO_BUFFER_SIZE;
+               urb->complete = pwc_isoc_handler;
+               urb->context = pdev;
+               urb->start_frame = 0;
+               urb->number_of_packets = ISO_FRAMES_PER_DESC;
+               for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
+                       urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
+                       urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
+               }
+       }
+
+       /* link */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
+               if (ret)
+                       Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+               else
+                       Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+       }
+
+       /* All is done... */
+       pdev->iso_init = 1;
+       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+       return 0;
+}
+
+static void pwc_isoc_cleanup(struct pwc_device *pdev)
+{
+       int i;
+
+       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+       if (pdev == NULL)
+               return;
+
+       /* Unlinking ISOC buffers one by one */
+       for (i = 0; i < MAX_ISO_BUFS; i++) {
+               struct urb *urb;
+
+               urb = pdev->sbuf[i].urb;
+               if (urb != 0) {
+                       if (pdev->iso_init) {
+                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+                               usb_kill_urb(urb);
+                       }
+                       Trace(TRACE_MEMORY, "Freeing URB\n");
+                       usb_free_urb(urb);
+                       pdev->sbuf[i].urb = NULL;
+               }
+       }
+
+       /* Stop camera, but only if we are sure the camera is still there (unplug
+          is signalled by EPIPE) 
+        */
+       if (pdev->error_status && pdev->error_status != EPIPE) {
+               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+               usb_set_interface(pdev->udev, 0, 0);
+       }
+
+       pdev->iso_init = 0;
+       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+}
+
+int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
+{
+       int ret, start;
+
+       /* Stop isoc stuff */
+       pwc_isoc_cleanup(pdev);
+       /* Reset parameters */
+       pwc_reset_buffers(pdev);
+       /* Try to set video mode... */
+       start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
+       if (ret) { 
+               Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+               /* That failed... restore old mode (we know that worked) */
+               start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+               if (start) {
+                       Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+               }
+       }
+       if (start == 0)
+       {
+               if (pwc_isoc_init(pdev) < 0)
+               {
+                       Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+                       ret = -EAGAIN; /* let's try again, who knows if it works a second time */
+               }
+       }
+       pdev->drop_frames++; /* try to avoid garbage during switch */
+       return ret; /* Return original error code */
+}
+
+
+/***************************************************************************/
+/* Video4Linux functions */
+
+static int pwc_video_open(struct inode *inode, struct file *file)
+{
+       int i;
+       struct video_device *vdev = video_devdata(file);
+       struct pwc_device *pdev;
+
+       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+       
+       pdev = (struct pwc_device *)vdev->priv;
+       if (pdev == NULL)
+               BUG();
+       if (pdev->vopen)
+               return -EBUSY;
+       
+       down(&pdev->modlock);
+       if (!pdev->usb_init) {
+               Trace(TRACE_OPEN, "Doing first time initialization.\n");
+               pdev->usb_init = 1;
+               
+               if (pwc_trace & TRACE_OPEN)
+               {
+                       /* Query sensor type */
+                       const char *sensor_type = NULL;
+                       int ret;
+
+                       ret = pwc_get_cmos_sensor(pdev, &i);
+                       if (ret >= 0)
+                       {
+                               switch(i) {
+                               case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
+                               case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
+                               case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
+                               case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
+                               case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
+                               case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
+                               case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
+                               case 0x40:  sensor_type = "UPA 1021 sensor"; break;
+                               case 0x100: sensor_type = "VGA sensor"; break;
+                               case 0x101: sensor_type = "PAL MR sensor"; break;
+                               default:    sensor_type = "unknown type of sensor"; break;
+                               }
+                       }
+                       if (sensor_type != NULL)
+                               Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+               }
+       }
+
+       /* Turn on camera */
+       if (power_save) {
+               i = pwc_camera_power(pdev, 1);
+               if (i < 0)
+                       Info("Failed to restore power to the camera! (%d)\n", i);
+       }
+       /* Set LED on/off time */
+       if (pwc_set_leds(pdev, led_on, led_off) < 0)
+               Info("Failed to set LED on/off time.\n");
+       
+       pwc_construct(pdev); /* set min/max sizes correct */
+
+       /* So far, so good. Allocate memory. */
+       i = pwc_allocate_buffers(pdev);
+       if (i < 0) {
+               Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+               up(&pdev->modlock);
+               return i;
+       }
+       
+       /* Reset buffers & parameters */
+       pwc_reset_buffers(pdev);
+       for (i = 0; i < default_mbufs; i++)
+               pdev->image_used[i] = 0;
+       pdev->vframe_count = 0;
+       pdev->vframes_dumped = 0;
+       pdev->vframes_error = 0;
+       pdev->visoc_errors = 0;
+       pdev->error_status = 0;
+#if PWC_DEBUG
+       pdev->sequence = 0;
+#endif
+       pwc_construct(pdev); /* set min/max sizes correct */
+
+       /* Set some defaults */
+       pdev->vsnapshot = 0;
+
+       /* Start iso pipe for video; first try the last used video size
+          (or the default one); if that fails try QCIF/10 or QSIF/10;
+          it that fails too, give up.
+        */
+       i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
+       if (i)  {
+               Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
+               if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
+                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+               else
+                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+       }
+       if (i) {
+               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+               up(&pdev->modlock);
+               return i;
+       }
+       
+       i = pwc_isoc_init(pdev);
+       if (i) {
+               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+               up(&pdev->modlock);
+               return i;
+       }
+
+       pdev->vopen++;
+       file->private_data = vdev;
+       up(&pdev->modlock);
+       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+       return 0;
+}
+
+/* Note that all cleanup is done in the reverse order as in _open */
+static int pwc_video_close(struct inode *inode, struct file *file)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       int i;
+
+       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+
+       pdev = (struct pwc_device *)vdev->priv;
+       if (pdev->vopen == 0)
+               Info("video_close() called on closed device?\n");
+
+       /* Dump statistics, but only if a reasonable amount of frames were
+          processed (to prevent endless log-entries in case of snap-shot
+          programs)
+        */
+       if (pdev->vframe_count > 20)
+               Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+
+       switch (pdev->type)
+        {
+         case 675:
+         case 680:
+         case 690:
+         case 720:
+         case 730:
+         case 740:
+         case 750:
+/*         pwc_dec23_exit();   *//* Timon & Kiara */
+           break;
+         case 645:
+         case 646:
+/*         pwc_dec1_exit(); */
+           break;
+        }
+
+       pwc_isoc_cleanup(pdev);
+       pwc_free_buffers(pdev);
+
+       /* Turn off LEDS and power down camera, but only when not unplugged */
+       if (pdev->error_status != EPIPE) {
+               /* Turn LEDs off */
+               if (pwc_set_leds(pdev, 0, 0) < 0)
+                       Info("Failed to set LED on/off time.\n");
+               if (power_save) {
+                       i = pwc_camera_power(pdev, 0);
+                       if (i < 0)
+                               Err("Failed to power down camera (%d)\n", i);
+               }
+       }
+       pdev->vopen = 0;
+       Trace(TRACE_OPEN, "<< video_close()\n");
+       return 0;
+}
+
+/*
+ *     FIXME: what about two parallel reads ????
+ *      ANSWER: Not supported. You can't open the device more than once,
+                despite what the V4L1 interface says. First, I don't see
+                the need, second there's no mechanism of alerting the
+                2nd/3rd/... process of events like changing image size.
+                And I don't see the point of blocking that for the
+                2nd/3rd/... process.
+                In multi-threaded environments reading parallel from any
+                device is tricky anyhow.
+ */
+
+static ssize_t pwc_video_read(struct file *file, char __user * buf,
+                         size_t count, loff_t *ppos)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       int noblock = file->f_flags & O_NONBLOCK;
+       DECLARE_WAITQUEUE(wait, current);
+        int bytes_to_read;
+
+       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+       if (pdev->error_status)
+               return -pdev->error_status; /* Something happened, report what. */
+
+       /* In case we're doing partial reads, we don't have to wait for a frame */
+       if (pdev->image_read_pos == 0) {
+               /* Do wait queueing according to the (doc)book */
+               add_wait_queue(&pdev->frameq, &wait);
+               while (pdev->full_frames == NULL) {
+                       /* Check for unplugged/etc. here */
+                       if (pdev->error_status) {
+                               remove_wait_queue(&pdev->frameq, &wait);
+                               set_current_state(TASK_RUNNING);
+                               return -pdev->error_status ;
+                       }
+                       if (noblock) {
+                               remove_wait_queue(&pdev->frameq, &wait);
+                               set_current_state(TASK_RUNNING);
+                               return -EWOULDBLOCK;
+                       }
+                       if (signal_pending(current)) {
+                               remove_wait_queue(&pdev->frameq, &wait);
+                               set_current_state(TASK_RUNNING);
+                               return -ERESTARTSYS;
+                       }
+                       schedule();
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+               remove_wait_queue(&pdev->frameq, &wait);
+               set_current_state(TASK_RUNNING);
+                                                                                                                                                                                
+               /* Decompress and release frame */
+               if (pwc_handle_frame(pdev))
+                       return -EFAULT;
+       }
+
+       Trace(TRACE_READ, "Copying data to user space.\n");
+       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+               bytes_to_read = pdev->frame_size;
+       else
+               bytes_to_read = pdev->view.size;
+
+       /* copy bytes to user space; we allow for partial reads */
+       if (count + pdev->image_read_pos > bytes_to_read)
+               count = bytes_to_read - pdev->image_read_pos;
+       if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+               return -EFAULT;
+       pdev->image_read_pos += count;
+       if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
+               pdev->image_read_pos = 0;
+               pwc_next_image(pdev);
+       }
+       return count;
+}
+
+static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+       poll_wait(file, &pdev->frameq, wait);
+       if (pdev->error_status)
+               return POLLERR;
+       if (pdev->full_frames != NULL) /* we have frames waiting */
+               return (POLLIN | POLLRDNORM);
+
+       return 0;
+}
+
+static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+       switch (cmd) {
+               /* Query cabapilities */
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *caps = arg;
+
+                       strcpy(caps->name, vdev->name);
+                       caps->type = VID_TYPE_CAPTURE;
+                       caps->channels = 1;
+                       caps->audios = 1;
+                       caps->minwidth  = pdev->view_min.x;
+                       caps->minheight = pdev->view_min.y;
+                       caps->maxwidth  = pdev->view_max.x;
+                       caps->maxheight = pdev->view_max.y;
+                       break;
+               }
+
+               /* Channel functions (simulate 1 channel) */
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy(v->name, "Webcam");
+                       return 0;
+               }
+
+               case VIDIOCSCHAN:
+               {
+                       /* The spec says the argument is an integer, but
+                          the bttv driver uses a video_channel arg, which
+                          makes sense becasue it also has the norm flag.
+                        */
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+
+
+               /* Picture functions; contrast etc. */
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *p = arg;
+                       int val;
+
+                       val = pwc_get_brightness(pdev);
+                       if (val >= 0)
+                               p->brightness = val;
+                       else
+                               p->brightness = 0xffff;
+                       val = pwc_get_contrast(pdev);
+                       if (val >= 0)
+                               p->contrast = val;
+                       else
+                               p->contrast = 0xffff;
+                       /* Gamma, Whiteness, what's the difference? :) */
+                       val = pwc_get_gamma(pdev);
+                       if (val >= 0)
+                               p->whiteness = val;
+                       else
+                               p->whiteness = 0xffff;
+                       val = pwc_get_saturation(pdev);
+                       if (val >= 0)
+                               p->colour = val;
+                       else
+                               p->colour = 0xffff;
+                       p->depth = 24;
+                       p->palette = pdev->vpalette;
+                       p->hue = 0xFFFF; /* N/A */
+                       break;
+               }
+
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *p = arg;
+                       /*
+                        *      FIXME:  Suppose we are mid read
+                               ANSWER: No problem: the firmware of the camera
+                                       can handle brightness/contrast/etc
+                                       changes at _any_ time, and the palette
+                                       is used exactly once in the uncompress
+                                       routine.
+                        */
+                       pwc_set_brightness(pdev, p->brightness);
+                       pwc_set_contrast(pdev, p->contrast);
+                       pwc_set_gamma(pdev, p->whiteness);
+                       pwc_set_saturation(pdev, p->colour);
+                       if (p->palette && p->palette != pdev->vpalette) {
+                               switch (p->palette) {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               pdev->vpalette = p->palette;
+                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+                       break;
+               }
+
+               /* Window/size parameters */            
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+                       
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = pdev->view.x;
+                       vw->height = pdev->view.y;
+                       vw->chromakey = 0;
+                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | 
+                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+                       break;
+               }
+               
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+                       int fps, snapshot, ret;
+
+                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+                       if (fps == 0)
+                               fps = pdev->vframes;
+                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+                               return 0;
+                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+                       if (ret)
+                               return ret;
+                       break;          
+               }
+               
+               /* We don't have overlay support (yet) */
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb,0,sizeof(*vb));
+                       break;
+               }
+
+               /* mmap() functions */
+               case VIDIOCGMBUF:
+               {
+                       /* Tell the user program how much memory is needed for a mmap() */
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset(vm, 0, sizeof(*vm));
+                       vm->size = default_mbufs * pdev->len_per_image;
+                       vm->frames = default_mbufs; /* double buffering should be enough for most applications */
+                       for (i = 0; i < default_mbufs; i++)
+                               vm->offsets[i] = i * pdev->len_per_image;
+                       break;
+               }
+
+               case VIDIOCMCAPTURE:
+               {
+                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+                       struct video_mmap *vm = arg;
+
+                       Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+                       if (vm->frame < 0 || vm->frame >= default_mbufs)
+                               return -EINVAL;
+
+                       /* xawtv is nasty. It probes the available palettes
+                          by setting a very small image size and trying
+                          various palettes... The driver doesn't support
+                          such small images, so I'm working around it.
+                        */
+                       if (vm->format)
+                       {
+                               switch (vm->format)
+                               {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+
+                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+                               int ret;
+
+                               Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                               if (ret)
+                                       return ret;
+                       } /* ... size mismatch */
+
+                       /* FIXME: should we lock here? */
+                       if (pdev->image_used[vm->frame])
+                               return -EBUSY;  /* buffer wasn't available. Bummer */
+                       pdev->image_used[vm->frame] = 1;
+
+                       /* Okay, we're done here. In the SYNC call we wait until a 
+                          frame comes available, then expand image into the given 
+                          buffer.
+                          In contrast to the CPiA cam the Philips cams deliver a
+                          constant stream, almost like a grabber card. Also,
+                          we have separate buffers for the rawdata and the image,
+                          meaning we can nearly always expand into the requested buffer.
+                        */
+                       Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
+                       break;
+               }
+
+               case VIDIOCSYNC:
+               {
+                       /* The doc says: "Whenever a buffer is used it should
+                          call VIDIOCSYNC to free this frame up and continue."
+                          
+                          The only odd thing about this whole procedure is 
+                          that MCAPTURE flags the buffer as "in use", and
+                          SYNC immediately unmarks it, while it isn't 
+                          after SYNC that you know that the buffer actually
+                          got filled! So you better not start a CAPTURE in
+                          the same frame immediately (use double buffering). 
+                          This is not a problem for this cam, since it has 
+                          extra intermediate buffers, but a hardware 
+                          grabber card will then overwrite the buffer 
+                          you're working on.
+                        */
+                       int *mbuf = arg;
+                       int ret;
+
+                       Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
+
+                       /* bounds check */
+                       if (*mbuf < 0 || *mbuf >= default_mbufs)
+                               return -EINVAL;
+                       /* check if this buffer was requested anyway */
+                       if (pdev->image_used[*mbuf] == 0)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+                          
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+                       
+                               if (signal_pending(current)) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -ERESTARTSYS;
+                               }
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+                               
+                       /* The frame is ready. Expand in the image buffer 
+                          requested by the user. I don't care if you 
+                          mmap() 5 buffers and request data in this order: 
+                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+                          Grabber hardware may not be so forgiving.
+                        */
+                       Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
+                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+                       /* Decompress, etc */
+                       ret = pwc_handle_frame(pdev);
+                       pdev->image_used[*mbuf] = 0;
+                       if (ret)
+                               return -EFAULT;
+                       break;
+               }
+               
+               case VIDIOCGAUDIO:
+               {
+                       struct video_audio *v = arg;
+                       
+                       strcpy(v->name, "Microphone");
+                       v->audio = -1; /* unknown audio minor */
+                       v->flags = 0;
+                       v->mode = VIDEO_SOUND_MONO;
+                       v->volume = 0;
+                       v->bass = 0;
+                       v->treble = 0;
+                       v->balance = 0x8000;
+                       v->step = 1;
+                       break;  
+               }
+               
+               case VIDIOCSAUDIO:
+               {
+                       /* Dummy: nothing can be set */
+                       break;
+               }
+               
+               case VIDIOCGUNIT:
+               {
+                       struct video_unit *vu = arg;
+                       
+                       vu->video = pdev->vdev->minor & 0x3F;
+                       vu->audio = -1; /* not known yet */
+                       vu->vbi = -1;
+                       vu->radio = -1;
+                       vu->teletext = -1;
+                       break;
+               }
+               default:
+                       return pwc_ioctl(pdev, cmd, arg);
+       } /* ..switch */
+       return 0;
+}      
+
+static int pwc_video_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+}
+
+
+static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *vdev = file->private_data;
+       struct pwc_device *pdev;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+       
+       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+       pdev = vdev->priv;
+       
+       vma->vm_flags |= VM_IO;
+
+       pos = (unsigned long)pdev->image_data;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+/***************************************************************************/
+/* USB functions */
+
+/* This function gets called when a new device is plugged in or the usb core
+ * is loaded.
+ */
+
+static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct pwc_device *pdev = NULL;
+       int vendor_id, product_id, type_id;
+       int i, hint;
+       int features = 0;
+       int video_nr = -1; /* default: use next available device */
+       char serial_number[30], *name;
+
+       /* Check if we can handle this device */
+       Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", 
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct),
+               intf->altsetting->desc.bInterfaceNumber);
+
+       /* the interfaces are probed one by one. We are only interested in the
+          video interface (0) now.
+          Interface 1 is the Audio Control, and interface 2 Audio itself.
+        */
+       if (intf->altsetting->desc.bInterfaceNumber > 0)
+               return -ENODEV;
+
+       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+       product_id = le16_to_cpu(udev->descriptor.idProduct);
+
+       if (vendor_id == 0x0471) {
+               switch (product_id) {
+               case 0x0302:
+                       Info("Philips PCA645VC USB webcam detected.\n");
+                       name = "Philips 645 webcam";
+                       type_id = 645;
+                       break;
+               case 0x0303:
+                       Info("Philips PCA646VC USB webcam detected.\n");
+                       name = "Philips 646 webcam";
+                       type_id = 646;
+                       break;
+               case 0x0304:
+                       Info("Askey VC010 type 2 USB webcam detected.\n");
+                       name = "Askey VC010 webcam";
+                       type_id = 646;
+                       break;
+               case 0x0307:
+                       Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+                       name = "Philips 675 webcam";
+                       type_id = 675;
+                       break;
+               case 0x0308:
+                       Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+                       name = "Philips 680 webcam";
+                       type_id = 680;
+                       break;
+               case 0x030C:
+                       Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+                       name = "Philips 690 webcam";
+                       type_id = 690;
+                       break;
+               case 0x0310:
+                       Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+                       name = "Philips 730 webcam";
+                       type_id = 730;
+                       break;
+               case 0x0311:
+                       Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+                       name = "Philips 740 webcam";
+                       type_id = 740;
+                       break;
+               case 0x0312:
+                       Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+                       name = "Philips 750 webcam";
+                       type_id = 750;
+                       break;
+               case 0x0313:
+                       Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+                       name = "Philips 720K/40 webcam";
+                       type_id = 720;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x069A) {
+               switch(product_id) {
+               case 0x0001:
+                       Info("Askey VC010 type 1 USB webcam detected.\n");
+                       name = "Askey VC010 webcam";
+                       type_id = 645;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x046d) {
+               switch(product_id) {
+               case 0x08b0:
+                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+                       name = "Logitech QuickCam Pro 3000";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b1:
+                       Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+                       name = "Logitech QuickCam Notebook Pro";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b2:
+                       Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+                       name = "Logitech QuickCam Pro 4000";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b3:
+                       Info("Logitech QuickCam Zoom USB webcam detected.\n");
+                       name = "Logitech QuickCam Zoom";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08B4:
+                       Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+                       name = "Logitech QuickCam Zoom";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x08b5:
+                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+                       name = "Logitech QuickCam Orbit";
+                       type_id = 740; /* CCD sensor */
+                       features |= FEATURE_MOTOR_PANTILT;
+                       break;
+               case 0x08b6:
+               case 0x08b7:
+               case 0x08b8:
+                       Info("Logitech QuickCam detected (reserved ID).\n");
+                       name = "Logitech QuickCam (res.)";
+                       type_id = 730; /* Assuming CMOS */
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+        }
+       else if (vendor_id == 0x055d) {
+               /* I don't know the difference between the C10 and the C30;
+                  I suppose the difference is the sensor, but both cameras
+                  work equally well with a type_id of 675
+                */
+               switch(product_id) {
+               case 0x9000:
+                       Info("Samsung MPC-C10 USB webcam detected.\n");
+                       name = "Samsung MPC-C10";
+                       type_id = 675;
+                       break;
+               case 0x9001:
+                       Info("Samsung MPC-C30 USB webcam detected.\n");
+                       name = "Samsung MPC-C30";
+                       type_id = 675;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x041e) {
+               switch(product_id) {
+               case 0x400c:
+                       Info("Creative Labs Webcam 5 detected.\n");
+                       name = "Creative Labs Webcam 5";
+                       type_id = 730;
+                       break;
+               case 0x4011:
+                       Info("Creative Labs Webcam Pro Ex detected.\n");
+                       name = "Creative Labs Webcam Pro Ex";
+                       type_id = 740;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x04cc) {
+               switch(product_id) {
+               case 0x8116:
+                       Info("Sotec Afina Eye USB webcam detected.\n");
+                       name = "Sotec Afina Eye";
+                       type_id = 730;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else if (vendor_id == 0x06be) {
+               switch(product_id) {
+               case 0x8116:
+                       /* This is essentially the same cam as the Sotec Afina Eye */
+                       Info("AME Co. Afina Eye USB webcam detected.\n");
+                       name = "AME Co. Afina Eye";
+                       type_id = 750;
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       
+       }
+       else if (vendor_id == 0x0d81) {
+               switch(product_id) {
+               case 0x1900:
+                       Info("Visionite VCS-UC300 USB webcam detected.\n");
+                       name = "Visionite VCS-UC300";
+                       type_id = 740; /* CCD sensor */
+                       break;
+               case 0x1910:
+                       Info("Visionite VCS-UM100 USB webcam detected.\n");
+                       name = "Visionite VCS-UM100";
+                       type_id = 730; /* CMOS sensor */
+                       break;
+               default:
+                       return -ENODEV;
+                       break;
+               }
+       }
+       else 
+               return -ENODEV; /* Not any of the know types; but the list keeps growing. */
+
+       memset(serial_number, 0, 30);
+       usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
+       Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+
+       if (udev->descriptor.bNumConfigurations > 1)
+               Info("Warning: more than 1 configuration available.\n");
+
+       /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
+       pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
+       if (pdev == NULL) {
+               Err("Oops, could not allocate memory for pwc_device.\n");
+               return -ENOMEM;
+       }
+       pdev->type = type_id;
+       pdev->vsize = default_size;
+       pdev->vframes = default_fps;
+       strcpy(pdev->serial, serial_number);
+       pdev->features = features;
+       if (vendor_id == 0x046D && product_id == 0x08B5)
+       {
+               /* Logitech QuickCam Orbit
+                  The ranges have been determined experimentally; they may differ from cam to cam.
+                  Also, the exact ranges left-right and up-down are different for my cam
+                 */
+               pdev->angle_range.pan_min  = -7000;
+               pdev->angle_range.pan_max  =  7000;
+               pdev->angle_range.tilt_min = -3000;
+               pdev->angle_range.tilt_max =  2500;
+       }
+
+       init_MUTEX(&pdev->modlock);
+       spin_lock_init(&pdev->ptrlock);
+
+       pdev->udev = udev;
+       init_waitqueue_head(&pdev->frameq);
+       pdev->vcompression = pwc_preferred_compression;
+
+       /* Allocate video_device structure */
+       pdev->vdev = video_device_alloc();
+       if (pdev->vdev == 0)
+       {
+               Err("Err, cannot allocate video_device struture. Failing probe.");
+               kfree(pdev);
+               return -ENOMEM;
+       }
+       memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+       strcpy(pdev->vdev->name, name);
+       pdev->vdev->owner = THIS_MODULE;
+       video_set_drvdata(pdev->vdev, pdev);
+
+       pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
+       Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+
+       /* Now search device_hint[] table for a match, so we can hint a node number. */
+       for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
+               if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
+                    (device_hint[hint].pdev == NULL)) {
+                       /* so far, so good... try serial number */
+                       if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
+                               /* match! */
+                               video_nr = device_hint[hint].device_node;
+                               Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+                               break;
+                       }
+               }
+       }
+
+       pdev->vdev->release = video_device_release;
+       i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (i < 0) {
+               Err("Failed to register as video device (%d).\n", i);
+               video_device_release(pdev->vdev); /* Drip... drip... drip... */
+               kfree(pdev); /* Oops, no memory leaks please */
+               return -EIO;
+       }
+       else {
+               Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+       }
+
+       /* occupy slot */
+       if (hint < MAX_DEV_HINTS) 
+               device_hint[hint].pdev = pdev;
+
+       Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+       usb_set_intfdata (intf, pdev);
+       return 0;
+}
+
+/* The user janked out the cable... */
+static void usb_pwc_disconnect(struct usb_interface *intf)
+{
+       struct pwc_device *pdev;
+       int hint;
+
+       lock_kernel();
+       pdev = usb_get_intfdata (intf);
+       usb_set_intfdata (intf, NULL);
+       if (pdev == NULL) {
+               Err("pwc_disconnect() Called without private pointer.\n");
+               goto disconnect_out;
+       }
+       if (pdev->udev == NULL) {
+               Err("pwc_disconnect() already called for %p\n", pdev);
+               goto disconnect_out;
+       }
+       if (pdev->udev != interface_to_usbdev(intf)) {
+               Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
+               goto disconnect_out;
+       }
+#ifdef PWC_MAGIC       
+       if (pdev->magic != PWC_MAGIC) {
+               Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+               goto disconnect_out;
+       }
+#endif
+       
+       /* We got unplugged; this is signalled by an EPIPE error code */
+       if (pdev->vopen) {
+               Info("Disconnected while webcam is in use!\n");
+               pdev->error_status = EPIPE;
+       }
+
+       /* Alert waiting processes */
+       wake_up_interruptible(&pdev->frameq);
+       /* Wait until device is closed */
+       while (pdev->vopen)
+               schedule();
+       /* Device is now closed, so we can safely unregister it */
+       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+       video_unregister_device(pdev->vdev);
+
+       /* Free memory (don't set pdev to 0 just yet) */
+       kfree(pdev);
+
+disconnect_out:
+       /* search device_hint[] table if we occupy a slot, by any chance */
+       for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+               if (device_hint[hint].pdev == pdev)
+                       device_hint[hint].pdev = NULL;
+
+       unlock_kernel();
+}
+
+
+/* *grunt* We have to do atoi ourselves :-( */
+static int pwc_atoi(const char *s)
+{
+       int k = 0;
+
+       k = 0;
+       while (*s != '\0' && *s >= '0' && *s <= '9') {
+               k = 10 * k + (*s - '0');
+               s++;
+       }
+       return k;
+}
+
+
+/* 
+ * Initialization code & module stuff 
+ */
+
+static char size[10];
+static int fps = 0;
+static int fbufs = 0;
+static int mbufs = 0;
+static int trace = -1;
+static int compression = -1;
+static int leds[2] = { -1, -1 };
+static char *dev_hint[MAX_DEV_HINTS] = { };
+
+module_param_string(size, size, sizeof(size), 0);
+MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
+module_param(fps, int, 0000);
+MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
+module_param(fbufs, int, 0000);
+MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
+module_param(mbufs, int, 0000);
+MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
+module_param(trace, int, 0000);
+MODULE_PARM_DESC(trace, "For debugging purposes");
+module_param(power_save, bool, 0000);
+MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
+module_param(compression, int, 0000);
+MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
+module_param_array(leds, int, NULL, 0000);
+MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
+module_param_array(dev_hint, charp, NULL, 0000);
+MODULE_PARM_DESC(dev_hint, "Device node hints");
+
+MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
+MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
+MODULE_LICENSE("GPL");
+
+static int __init usb_pwc_init(void)
+{
+       int i, sz;
+       char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
+
+       Info("Philips webcam module version " PWC_VERSION " loaded.\n");
+       Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+       Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+       Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+
+       if (fps) {
+               if (fps < 4 || fps > 30) {
+                       Err("Framerate out of bounds (4-30).\n");
+                       return -EINVAL;
+               }
+               default_fps = fps;
+               Info("Default framerate set to %d.\n", default_fps);
+       }
+
+       if (size[0]) {
+               /* string; try matching with array */
+               for (sz = 0; sz < PSZ_MAX; sz++) {
+                       if (!strcmp(sizenames[sz], size)) { /* Found! */
+                               default_size = sz;
+                               break;
+                       }
+               }
+               if (sz == PSZ_MAX) {
+                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+                       return -EINVAL;
+               }
+               Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+       }
+       if (mbufs) {
+               if (mbufs < 1 || mbufs > MAX_IMAGES) {
+                       Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+                       return -EINVAL;
+               }
+               default_mbufs = mbufs;
+               Info("Number of image buffers set to %d.\n", default_mbufs);
+       }
+       if (fbufs) {
+               if (fbufs < 2 || fbufs > MAX_FRAMES) {
+                       Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+                       return -EINVAL;
+               }
+               default_fbufs = fbufs;
+               Info("Number of frame buffers set to %d.\n", default_fbufs);
+       }
+       if (trace >= 0) {
+               Info("Trace options: 0x%04x\n", trace);
+               pwc_trace = trace;
+       }
+       if (compression >= 0) {
+               if (compression > 3) {
+                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+                       return -EINVAL;
+               }
+               pwc_preferred_compression = compression;
+               Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+       }
+       if (power_save)
+               Info("Enabling power save on open/close.\n");
+       if (leds[0] >= 0)
+               led_on = leds[0];
+       if (leds[1] >= 0)
+               led_off = leds[1];
+
+       /* Big device node whoopla. Basically, it allows you to assign a
+          device node (/dev/videoX) to a camera, based on its type
+          & serial number. The format is [type[.serialnumber]:]node.
+
+          Any camera that isn't matched by these rules gets the next
+          available free device node.
+        */
+       for (i = 0; i < MAX_DEV_HINTS; i++) {
+               char *s, *colon, *dot;
+
+               /* This loop also initializes the array */
+               device_hint[i].pdev = NULL;
+               s = dev_hint[i];
+               if (s != NULL && *s != '\0') {
+                       device_hint[i].type = -1; /* wildcard */
+                       strcpy(device_hint[i].serial_number, "*");
+
+                       /* parse string: chop at ':' & '/' */
+                       colon = dot = s;
+                       while (*colon != '\0' && *colon != ':')
+                               colon++;
+                       while (*dot != '\0' && *dot != '.')
+                               dot++;
+                       /* Few sanity checks */
+                       if (*dot != '\0' && dot > colon) {
+                               Err("Malformed camera hint: the colon must be after the dot.\n");
+                               return -EINVAL;
+                       }
+
+                       if (*colon == '\0') {
+                               /* No colon */
+                               if (*dot != '\0') {
+                                       Err("Malformed camera hint: no colon + device node given.\n");
+                                       return -EINVAL;
+                               }
+                               else {
+                                       /* No type or serial number specified, just a number. */
+                                       device_hint[i].device_node = pwc_atoi(s);
+                               }
+                       }
+                       else {
+                               /* There's a colon, so we have at least a type and a device node */
+                               device_hint[i].type = pwc_atoi(s);
+                               device_hint[i].device_node = pwc_atoi(colon + 1);
+                               if (*dot != '\0') {
+                                       /* There's a serial number as well */
+                                       int k;
+                                       
+                                       dot++;
+                                       k = 0;
+                                       while (*dot != ':' && k < 29) {
+                                               device_hint[i].serial_number[k++] = *dot;
+                                               dot++;
+                                       }
+                                       device_hint[i].serial_number[k] = '\0';
+                               }
+                       }
+#if PWC_DEBUG          
+                       Debug("device_hint[%d]:\n", i);
+                       Debug("  type    : %d\n", device_hint[i].type);
+                       Debug("  serial# : %s\n", device_hint[i].serial_number);
+                       Debug("  node    : %d\n", device_hint[i].device_node);
+#endif                 
+               }
+               else
+                       device_hint[i].type = 0; /* not filled */
+       } /* ..for MAX_DEV_HINTS */
+
+       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+       return usb_register(&pwc_driver);
+}
+
+static void __exit usb_pwc_exit(void)
+{
+       Trace(TRACE_MODULE, "Deregistering driver.\n");
+       usb_deregister(&pwc_driver);
+       Info("Philips webcam module removed.\n");
+}
+
+module_init(usb_pwc_init);
+module_exit(usb_pwc_exit);
+
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h
new file mode 100644 (file)
index 0000000..5f9cb08
--- /dev/null
@@ -0,0 +1,292 @@
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 8.12.1
+   It contains structures and defines to communicate from user space
+   directly to the driver.
+ */
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added ioctl constants to access methods for
+                          changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
+   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
+               PWCX easier
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+   They contain functions not found in other webcams, and settings not
+   specified in the Video4Linux API.
+
+   The #define names are built up like follows:
+   VIDIOC              VIDeo IOCtl prefix
+         PWC           Philps WebCam
+            G           optional: Get
+            S           optional: Set
+             ...       the function
+ */
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF      0x00
+#define PSZ_QSIF       0x01
+#define PSZ_QCIF       0x02
+#define PSZ_SIF                0x03
+#define PSZ_CIF                0x04
+#define PSZ_VGA                0x05
+#define PSZ_MAX                6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+   the upper 16 bits, since some flags are defined nowadays. The following
+   defines provide a mask and shift to filter out this value.
+
+   In 'Snapshot' mode the camera freezes its automatic exposure and colour
+   balance controls.
+ */
+#define PWC_FPS_SHIFT          16
+#define PWC_FPS_MASK           0x00FF0000
+#define PWC_FPS_FRMASK         0x003F0000
+#define PWC_FPS_SNAPSHOT       0x00400000
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+       int x, y;               /* guess what */
+       int size;               /* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+       char name[32];
+       int type;
+};
+
+struct pwc_serial
+{
+       char serial[30];        /* String with serial number. Contains terminating 0 */
+};
+       
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR          0
+#define PWC_WB_OUTDOOR         1
+#define PWC_WB_FL              2
+#define PWC_WB_MANUAL          3
+#define PWC_WB_AUTO            4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). 
+   Set mode to one of the PWC_WB_* values above.
+   *red and *blue are the respective gains of these colour components inside 
+   the camera; range 0..65535
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
+   otherwise undefined.
+   'read_red' and 'read_blue' are read-only.
+*/   
+struct pwc_whitebalance
+{
+       int mode;
+       int manual_red, manual_blue;    /* R/W */
+       int read_red, read_blue;        /* R/O */
+};
+
+/* 
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and 
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+       int control_speed;
+       int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+       int led_on;                     /* Led on-time; range = 0..25000 */
+       int led_off;                    /* Led off-time; range = 0..25000  */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+       int width;
+       int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN            0x01
+#define PWC_MPT_TILT           0x02
+#define PWC_MPT_TIMEOUT                0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the 
+   driver calculates the relative offset for you. This can only
+   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+   absolute angles.
+ */   
+struct pwc_mpt_angles
+{
+       int absolute;           /* write-only */
+       int pan;                /* degrees * 100 */
+       int tilt;               /* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+       int pan_min, pan_max;           /* degrees * 100 */
+       int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+       int status;
+       int time_pan;
+       int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+   all the necessary information to initialize and use the decompressor
+   routines in standalone applications.
+ */   
+struct pwc_video_command
+{
+       int type;               /* camera type (645, 675, 730, etc.) */
+       int release;            /* release number */
+
+        int size;              /* one of PSZ_* */
+        int alternate;
+       int command_len;        /* length of USB video command */
+       unsigned char command_buf[13];  /* Actual USB video command */
+       int bandlength;         /* >0 = compressed */
+       int frame_size;         /* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR       0x0001
+#define PWCX_FLAG_BAYER                0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER         _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER         _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY       _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+    means use uncompressed modes when available; 1 is low compression, 2 is
+    medium and 3 is high compression preferred. Of course, the higher the
+    compression, the lower the bandwidth used but more chance of artefacts
+    in the image. The driver automatically chooses a higher compression when
+    the preferred mode is not available.
+  */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */
+#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC          _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC          _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)  
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */ 
+#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+   int len;
+   char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
+
+#endif
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c
new file mode 100644 (file)
index 0000000..c498c68
--- /dev/null
@@ -0,0 +1,318 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/* This tables contains entries for the 730/740/750 (Kiara) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+
+#include "pwc-kiara.h"
+#include "pwc-uncompress.h"
+
+const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
+{
+   /* SQCIF */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+   /* QSIF */
+   {
+      /* 5 fps */
+      {
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
+      },
+      /* 10 fps */
+      {
+         {2, 291,    0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}},
+         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
+      },
+      /* 15 fps */
+      {
+         {3, 437,    0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}},
+         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
+         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
+         {1, 192,  420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
+      },
+      /* 20 fps */
+      {
+         {4, 589,    0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}},
+         {3, 448,  730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}},
+         {2, 292,  476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}},
+         {1, 192,  312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
+      },
+      /* 25 fps */
+      {
+         {5, 703,    0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}},
+         {3, 447,  610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}},
+         {2, 292,  398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}},
+         {1, 193,  262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}},
+      },
+      /* 30 fps */
+      {
+         {8, 874,    0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}},
+         {5, 704,  730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}},
+         {3, 448,  492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}},
+         {2, 292,  320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}},
+      },
+   },
+   /* QCIF */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+   /* SIF */
+   {
+      /* 5 fps */
+      {
+         {4, 582,    0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}},
+         {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}},
+         {2, 291,  960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}},
+         {1, 191,  630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}},
+         {3, 447,  736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}},
+         {2, 292,  480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}},
+         {4, 592,  650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}},
+         {3, 448,  492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {9, 958,  782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}},
+         {5, 703,  574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}},
+         {3, 446,  364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}},
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {9, 958,  654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}},
+         {6, 776,  530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}},
+         {4, 592,  404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}},
+         {6, 775,  426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}},
+         {4, 590,  324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}},
+      },
+   },
+   /* CIF */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+   /* VGA */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}},
+         {4, 592,  976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}},
+         {3, 448,  738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {9, 956,  788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}},
+         {6, 776,  640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}},
+         {4, 592,  488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
+         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
+         {8, 895,  492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+};
+
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
new file mode 100644 (file)
index 0000000..12929ab
--- /dev/null
@@ -0,0 +1,45 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* Entries for the Kiara (730/740/750) camera */
+
+#ifndef PWC_KIARA_H
+#define PWC_KIARA_H
+
+#include "pwc-ioctl.h"
+
+struct Kiara_table_entry
+{
+       char alternate;                 /* USB alternate interface */
+       unsigned short packetsize;      /* Normal packet size */
+       unsigned short bandlength;      /* Bandlength when decompressing */
+       unsigned char mode[12];         /* precomputed mode settings for cam */
+};
+
+const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+const extern unsigned int KiaraRomTable[8][2][16][8];
+
+#endif
+
+
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
new file mode 100644 (file)
index 0000000..b7a4bd3
--- /dev/null
@@ -0,0 +1,140 @@
+/* Linux driver for Philips webcam 
+   Various miscellaneous functions and tables.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/slab.h>
+
+#include "pwc.h"
+
+struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+{
+       { 128,  96, 0 },
+       { 160, 120, 0 },
+       { 176, 144, 0 },
+       { 320, 240, 0 },
+       { 352, 288, 0 },
+       { 640, 480, 0 },
+};
+
+/* x,y -> PSZ_ */
+int pwc_decode_size(struct pwc_device *pdev, int width, int height)
+{
+       int i, find;
+
+       /* Make sure we don't go beyond our max size.
+           NB: we have different limits for RAW and normal modes. In case
+           you don't have the decompressor loaded or use RAW mode, 
+           the maximum viewable size is smaller.
+        */
+       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       {
+               if (width > pdev->abs_max.x || height > pdev->abs_max.y)
+               {
+                       Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+                       return -1;
+                }
+       }
+       else
+       {
+               if (width > pdev->view_max.x || height > pdev->view_max.y)
+               {
+                       Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+                       return -1;
+               }
+       }
+
+       /* Find the largest size supported by the camera that fits into the
+          requested size.
+        */
+       find = -1;
+       for (i = 0; i < PSZ_MAX; i++) {
+               if (pdev->image_mask & (1 << i)) {
+                       if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
+                               find = i;
+               }
+       }
+       return find;
+}
+
+/* initialize variables depending on type and decompressor*/
+void pwc_construct(struct pwc_device *pdev)
+{
+       switch(pdev->type) {
+       case 645:
+       case 646:
+               pdev->view_min.x = 128;
+               pdev->view_min.y =  96;
+               pdev->view_max.x = 352;
+               pdev->view_max.y = 288;
+                pdev->abs_max.x  = 352;
+                pdev->abs_max.y  = 288;
+               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
+               pdev->vcinterface = 2;
+               pdev->vendpoint = 4;
+               pdev->frame_header_size = 0;
+               pdev->frame_trailer_size = 0;
+               break;
+       case 675:
+       case 680:
+       case 690:
+               pdev->view_min.x = 128;
+               pdev->view_min.y =  96;
+               /* Anthill bug #38: PWC always reports max size, even without PWCX */
+               pdev->view_max.x = 640;
+               pdev->view_max.y = 480;
+               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
+                pdev->abs_max.x = 640;
+                pdev->abs_max.y = 480;
+               pdev->vcinterface = 3;
+               pdev->vendpoint = 4;
+               pdev->frame_header_size = 0;
+               pdev->frame_trailer_size = 0;
+               break;
+       case 720:
+       case 730:
+       case 740:
+       case 750:
+               pdev->view_min.x = 160;
+               pdev->view_min.y = 120;
+               pdev->view_max.x = 640;
+               pdev->view_max.y = 480;
+               pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+                pdev->abs_max.x = 640;
+                pdev->abs_max.y = 480;
+               pdev->vcinterface = 3;
+               pdev->vendpoint = 5;
+               pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+               pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+               break;
+       }
+       Debug("type = %d\n",pdev->type);
+       pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
+       pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
+       pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
+       /* length of image, in YUV format; always allocate enough memory. */
+       pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+}
+
+
diff --git a/drivers/media/video/pwc/pwc-nala.h b/drivers/media/video/pwc/pwc-nala.h
new file mode 100644 (file)
index 0000000..e6c5cb6
--- /dev/null
@@ -0,0 +1,66 @@
+   /* SQCIF */
+   {
+      {0, 0, {0x04, 0x01, 0x03}},
+      {8, 0, {0x05, 0x01, 0x03}},
+      {7, 0, {0x08, 0x01, 0x03}},
+      {7, 0, {0x0A, 0x01, 0x03}},
+      {6, 0, {0x0C, 0x01, 0x03}},
+      {5, 0, {0x0F, 0x01, 0x03}},
+      {4, 0, {0x14, 0x01, 0x03}},
+      {3, 0, {0x18, 0x01, 0x03}},
+   },
+   /* QSIF */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
+   /* QCIF */
+   {
+      {0, 0, {0x04, 0x01, 0x02}},
+      {8, 0, {0x05, 0x01, 0x02}},
+      {7, 0, {0x08, 0x01, 0x02}},
+      {6, 0, {0x0A, 0x01, 0x02}},
+      {5, 0, {0x0C, 0x01, 0x02}},
+      {4, 0, {0x0F, 0x01, 0x02}},
+      {1, 0, {0x14, 0x01, 0x02}},
+      {1, 0, {0x18, 0x01, 0x02}},
+   },
+   /* SIF */
+   {
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
+   /* CIF */
+   {
+      {4, 0, {0x04, 0x01, 0x01}},
+      {7, 1, {0x05, 0x03, 0x01}},
+      {6, 1, {0x08, 0x03, 0x01}},
+      {4, 1, {0x0A, 0x03, 0x01}},
+      {3, 1, {0x0C, 0x03, 0x01}},
+      {2, 1, {0x0F, 0x03, 0x01}},
+      {0},
+      {0},
+   },
+   /* VGA */
+   {  
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+      {0},
+   },
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c
new file mode 100644 (file)
index 0000000..dee9671
--- /dev/null
@@ -0,0 +1,316 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/* This tables contains entries for the 675/680/690 (Timon) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+#include "pwc-timon.h"
+
+const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
+{
+   /* SQCIF */
+   {
+      /* 5 fps */
+      {
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
+      },
+   },
+   /* QSIF */
+   {
+      /* 5 fps */
+      {
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {2, 291,    0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}},
+         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {3, 437,    0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}},
+         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {1, 191,  420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {4, 588,    0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}},
+         {3, 447,  730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+         {1, 192,  312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {5, 703,    0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}},
+         {3, 447,  610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+         {1, 192,  262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {8, 873,    0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}},
+         {5, 704,  774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}},
+         {3, 448,  492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}},
+         {2, 291,  320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
+      },
+   },
+   /* QCIF */
+   {
+      /* 5 fps */
+      {
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {3, 385,    0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}},
+         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
+         {1, 194,  532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {4, 577,    0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}},
+         {3, 447,  818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}},
+         {1, 195,  356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {6, 776,    0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}},
+         {4, 591,  804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}},
+         {3, 447,  608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 291,  396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {9, 928,    0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}},
+         {5, 703,  800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}},
+         {3, 447,  508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
+         {2, 292,  332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 956,  876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}},
+         {4, 592,  542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}},
+         {2, 291,  266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}},
+      },
+   },
+   /* SIF */
+   {
+      /* 5 fps */
+      {
+         {4, 582,    0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}},
+         {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}},
+         {2, 291,  960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}},
+         {1, 191,  630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}},
+         {3, 447,  736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}},
+         {2, 291,  480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}},
+         {4, 591,  650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}},
+         {3, 448,  492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {9, 958,  782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}},
+         {5, 703,  574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}},
+         {3, 446,  364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}},
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {9, 958,  654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}},
+         {6, 776,  530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}},
+         {4, 592,  404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}},
+         {6, 775,  426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}},
+         {4, 590,  324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}},
+      },
+   },
+   /* CIF */
+   {
+      /* 5 fps */
+      {
+         {6, 771,    0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}},
+         {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}},
+         {2, 291,  800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}},
+         {1, 193,  528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}},
+         {4, 591,  812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}},
+         {2, 291,  400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 956,  876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}},
+         {5, 703,  644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}},
+         {3, 448,  410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {9, 956,  650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}},
+         {6, 776,  528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}},
+         {4, 591,  402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}},
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {9, 956,  544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}},
+         {7, 840,  478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}},
+         {5, 703,  400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}},
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {9, 956,  438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}},
+         {7, 838,  384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}},
+         {6, 773,  354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}},
+      },
+   },
+   /* VGA */
+   {
+      /* 5 fps */
+      {
+         {0, },
+         {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}},
+         {4, 592,  976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}},
+         {3, 448,  738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}},
+      },
+      /* 10 fps */
+      {
+         {0, },
+         {9, 956,  788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}},
+         {6, 776,  640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}},
+         {4, 592,  488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}},
+      },
+      /* 15 fps */
+      {
+         {0, },
+         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
+         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
+         {8, 895,  492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}},
+      },
+      /* 20 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 25 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+      /* 30 fps */
+      {
+         {0, },
+         {0, },
+         {0, },
+         {0, },
+      },
+   },
+};
+
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
new file mode 100644 (file)
index 0000000..a86b378
--- /dev/null
@@ -0,0 +1,61 @@
+/* Linux driver for Philips webcam
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+
+/* This tables contains entries for the 675/680/690 (Timon) camera, with
+   4 different qualities (no compression, low, medium, high).
+   It lists the bandwidth requirements for said mode by its alternate interface
+   number. An alternate of 0 means that the mode is unavailable.
+
+   There are 6 * 4 * 4 entries:
+     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
+     6 framerates: 5, 10, 15, 20, 25, 30
+     4 compression modi: none, low, medium, high
+
+   When an uncompressed mode is not available, the next available compressed mode
+   will be chosen (unless the decompressor is absent). Sometimes there are only
+   1 or 2 compressed modes available; in that case entries are duplicated.
+*/
+
+#ifndef PWC_TIMON_H
+#define PWC_TIMON_H
+
+#include "pwc-ioctl.h"
+
+struct Timon_table_entry
+{
+       char alternate;                 /* USB alternate interface */
+       unsigned short packetsize;      /* Normal packet size */
+       unsigned short bandlength;      /* Bandlength when decompressing */
+       unsigned char mode[13];         /* precomputed mode settings for cam */
+};
+
+const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+const extern unsigned int TimonRomTable [16][2][16][8];
+
+
+#endif
+
+
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
new file mode 100644 (file)
index 0000000..ef4204e
--- /dev/null
@@ -0,0 +1,146 @@
+/* Linux driver for Philips webcam
+   Decompression frontend.
+   (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <asm/current.h>
+#include <asm/types.h>
+
+#include "pwc.h"
+#include "pwc-uncompress.h"
+
+int pwc_decompress(struct pwc_device *pdev)
+{
+       struct pwc_frame_buf *fbuf;
+       int n, line, col, stride;
+       void *yuv, *image;
+       u16 *src;
+       u16 *dsty, *dstu, *dstv;
+
+       if (pdev == NULL)
+               return -EFAULT;
+#if defined(__KERNEL__) && defined(PWC_MAGIC)
+       if (pdev->magic != PWC_MAGIC) {
+               Err("pwc_decompress(): magic failed.\n");
+               return -EFAULT;
+       }
+#endif
+
+       fbuf = pdev->read_frame;
+       if (fbuf == NULL)
+               return -EFAULT;
+       image = pdev->image_ptr[pdev->fill_image];
+       if (!image)
+               return -EFAULT;
+
+       yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
+
+       /* Raw format; that's easy... */
+       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+       {
+               memcpy(image, yuv, pdev->frame_size);
+               return 0;
+       }
+
+       if (pdev->vbandlength == 0) {
+               /* Uncompressed mode. We copy the data into the output buffer,
+                  using the viewport size (which may be larger than the image
+                  size). Unfortunately we have to do a bit of byte stuffing
+                  to get the desired output format/size.
+                */
+                       /*
+                        * We do some byte shuffling here to go from the
+                        * native format to YUV420P.
+                        */
+                       src = (u16 *)yuv;
+                       n = pdev->view.x * pdev->view.y;
+
+                       /* offset in Y plane */
+                       stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+                       dsty = (u16 *)(image + stride);
+
+                       /* offsets in U/V planes */
+                       stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+                       dstu = (u16 *)(image + n +         stride);
+                       dstv = (u16 *)(image + n + n / 4 + stride);
+
+                       /* increment after each line */
+                       stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+                       for (line = 0; line < pdev->image.y; line++) {
+                               for (col = 0; col < pdev->image.x; col += 4) {
+                                       *dsty++ = *src++;
+                                       *dsty++ = *src++;
+                                       if (line & 1)
+                                               *dstv++ = *src++;
+                                       else
+                                               *dstu++ = *src++;
+                               }
+                               dsty += stride;
+                               if (line & 1)
+                                       dstv += (stride >> 1);
+                               else
+                                       dstu += (stride >> 1);
+                       }
+       }
+       else {
+               /* Compressed; the decompressor routines will write the data
+                  in planar format immediately.
+                */
+               int flags;
+                
+                flags = PWCX_FLAG_PLANAR;
+                if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
+                {
+                  printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
+                  flags |= PWCX_FLAG_BAYER;
+                  return -ENXIO; /* No such device or address: missing decompressor */
+                }
+
+#if 0
+               switch (pdev->type)
+                {
+                 case 675:
+                 case 680:
+                 case 690:
+                 case 720:
+                 case 730:
+                 case 740:
+                 case 750:
+                   pwc_dec23_decompress(&pdev->image, &pdev->view,
+                               &pdev->offset, yuv, image, flags,
+                               pdev->decompress_data, pdev->vbandlength);
+                   break;
+                 case 645:
+                 case 646:
+                   /* TODO & FIXME */
+                   return -ENXIO; /* Missing decompressor */
+                   break;
+                }
+#endif
+       }
+       return 0;
+}
+
+
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
new file mode 100644 (file)
index 0000000..d3b9250
--- /dev/null
@@ -0,0 +1,41 @@
+/* (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This file is the bridge between the kernel module and the plugin; it
+   describes the structures and datatypes used in both modules. Any
+   significant change should be reflected by increasing the 
+   pwc_decompressor_version major number.
+ */
+#ifndef PWC_UNCOMPRESS_H
+#define PWC_UNCOMPRESS_H
+
+#include <linux/config.h>
+
+#include "pwc-ioctl.h"
+
+/* from pwc-dec.h */
+#define PWCX_FLAG_PLANAR        0x0001
+/* */
+
+#endif
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
new file mode 100644 (file)
index 0000000..6dd76bb
--- /dev/null
@@ -0,0 +1,272 @@
+/* (C) 1999-2003 Nemosoft Unv.
+   (C) 2004      Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef PWC_H
+#define PWC_H
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <linux/videodev.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+#include "pwc-uncompress.h"
+#include "pwc-ioctl.h"
+
+/* Defines and structures for the Philips webcam */
+/* Used for checking memory corruption/pointer validation */
+#define PWC_MAGIC 0x89DC10ABUL
+#undef PWC_MAGIC
+
+/* Turn some debugging options on/off */
+#define PWC_DEBUG 0
+
+/* Trace certain actions in the driver */
+#define TRACE_MODULE   0x0001
+#define TRACE_PROBE    0x0002
+#define TRACE_OPEN     0x0004
+#define TRACE_READ     0x0008
+#define TRACE_MEMORY   0x0010
+#define TRACE_FLOW     0x0020
+#define TRACE_SIZE     0x0040
+#define TRACE_PWCX     0x0080
+#define TRACE_SEQUENCE 0x1000
+
+#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
+#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
+#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
+#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
+
+
+/* Defines for ToUCam cameras */
+#define TOUCAM_HEADER_SIZE             8
+#define TOUCAM_TRAILER_SIZE            4
+
+#define FEATURE_MOTOR_PANTILT          0x0001
+
+/* Version block */
+#define PWC_MAJOR      9
+#define PWC_MINOR      0
+#define PWC_VERSION    "9.0.2-unofficial"
+#define PWC_NAME       "pwc"
+
+/* Turn certain features on/off */
+#define PWC_INT_PIPE 0
+
+/* Ignore errors in the first N frames, to allow for startup delays */
+#define FRAME_LOWMARK 5
+
+/* Size and number of buffers for the ISO pipe. */
+#define MAX_ISO_BUFS           2
+#define ISO_FRAMES_PER_DESC    10
+#define ISO_MAX_FRAME_SIZE     960
+#define ISO_BUFFER_SIZE        (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
+
+/* Frame buffers: contains compressed or uncompressed video data. */
+#define MAX_FRAMES             5
+/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
+#define PWC_FRAME_SIZE                 (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
+
+/* Absolute maximum number of buffers available for mmap() */
+#define MAX_IMAGES             10
+
+/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
+struct pwc_iso_buf
+{
+       void *data;
+       int  length;
+       int  read;
+       struct urb *urb;
+};
+
+/* intermediate buffers with raw data from the USB cam */
+struct pwc_frame_buf
+{
+   void *data;
+   volatile int filled;                /* number of bytes filled */
+   struct pwc_frame_buf *next; /* list */
+#if PWC_DEBUG
+   int sequence;               /* Sequence number */
+#endif
+};
+
+struct pwc_device
+{
+   struct video_device *vdev;
+#ifdef PWC_MAGIC
+   int magic;
+#endif
+   /* Pointer to our usb_device */
+   struct usb_device *udev;
+   
+   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
+   int release;                        /* release number */
+   int features;               /* feature bits */
+   char serial[30];            /* serial number (string) */
+   int error_status;           /* set when something goes wrong with the cam (unplugged, USB errors) */
+   int usb_init;               /* set when the cam has been initialized over USB */
+
+   /*** Video data ***/
+   int vopen;                  /* flag */
+   int vendpoint;              /* video isoc endpoint */
+   int vcinterface;            /* video control interface */
+   int valternate;             /* alternate interface needed */
+   int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
+   int vpalette;               /* palette: 420P, RAW or RGBBAYER */
+   int vframe_count;           /* received frames */
+   int vframes_dumped;                 /* counter for dumped frames */
+   int vframes_error;          /* frames received in error */
+   int vmax_packet_size;       /* USB maxpacket size */
+   int vlast_packet_size;      /* for frame synchronisation */
+   int visoc_errors;           /* number of contiguous ISOC errors */
+   int vcompression;           /* desired compression factor */
+   int vbandlength;            /* compressed band length; 0 is uncompressed */
+   char vsnapshot;             /* snapshot mode */
+   char vsync;                 /* used by isoc handler */
+   char vmirror;               /* for ToUCaM series */
+   
+   int cmd_len;
+   unsigned char cmd_buf[13];
+
+   /* The image acquisition requires 3 to 4 steps:
+      1. data is gathered in short packets from the USB controller
+      2. data is synchronized and packed into a frame buffer
+      3a. in case data is compressed, decompress it directly into image buffer
+      3b. in case data is uncompressed, copy into image buffer with viewport
+      4. data is transferred to the user process
+
+      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
+      We have in effect a back-to-back-double-buffer system.
+    */
+   /* 1: isoc */
+   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
+   char iso_init;
+
+   /* 2: frame */
+   struct pwc_frame_buf *fbuf; /* all frames */
+   struct pwc_frame_buf *empty_frames, *empty_frames_tail;     /* all empty frames */
+   struct pwc_frame_buf *full_frames, *full_frames_tail;       /* all filled frames */
+   struct pwc_frame_buf *fill_frame;   /* frame currently being filled */
+   struct pwc_frame_buf *read_frame;   /* frame currently read by user process */
+   int frame_header_size, frame_trailer_size;
+   int frame_size;
+   int frame_total_size; /* including header & trailer */
+   int drop_frames;
+#if PWC_DEBUG
+   int sequence;                       /* Debugging aid */
+#endif
+
+   /* 3: decompression */
+   struct pwc_decompressor *decompressor;      /* function block with decompression routines */
+   void *decompress_data;              /* private data for decompression engine */
+
+   /* 4: image */
+   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
+      as delivered by the camera, and 'view' is the size requested by the
+      program. The camera image is centered in this viewport, laced with
+      a gray or black border. view_min <= image <= view <= view_max;
+    */
+   int image_mask;                     /* bitmask of supported sizes */
+   struct pwc_coord view_min, view_max;        /* minimum and maximum viewable sizes */
+   struct pwc_coord abs_max;            /* maximum supported size with compression */
+   struct pwc_coord image, view;       /* image and viewport size */
+   struct pwc_coord offset;            /* offset within the viewport */
+
+   void *image_data;                   /* total buffer, which is subdivided into ... */
+   void *image_ptr[MAX_IMAGES];                /* ...several images... */
+   int fill_image;                     /* ...which are rotated. */
+   int len_per_image;                  /* length per image */
+   int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
+   int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
+
+   struct semaphore modlock;           /* to prevent races in video_open(), etc */
+   spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
+
+   /*** motorized pan/tilt feature */
+   struct pwc_mpt_range angle_range;
+   int pan_angle;                      /* in degrees * 100 */
+   int tilt_angle;                     /* absolute angle; 0,0 is home position */
+
+   /*** Misc. data ***/
+   wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
+#if PWC_INT_PIPE
+   void *usb_int_handler;              /* for the interrupt endpoint */
+#endif
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Global variable */
+extern int pwc_trace;
+
+/** functions in pwc-if.c */
+int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+
+/** Functions in pwc-misc.c */
+/* sizes in pixels */
+extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+
+int pwc_decode_size(struct pwc_device *pdev, int width, int height);
+void pwc_construct(struct pwc_device *pdev);
+
+/** Functions in pwc-ctrl.c */
+/* Request a certain video mode. Returns < 0 if not possible */
+extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+
+/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
+extern int pwc_get_brightness(struct pwc_device *pdev);
+extern int pwc_set_brightness(struct pwc_device *pdev, int value);
+extern int pwc_get_contrast(struct pwc_device *pdev);
+extern int pwc_set_contrast(struct pwc_device *pdev, int value);
+extern int pwc_get_gamma(struct pwc_device *pdev);
+extern int pwc_set_gamma(struct pwc_device *pdev, int value);
+extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_set_saturation(struct pwc_device *pdev, int value);
+extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
+extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+
+/* Power down or up the camera; not supported by all models */
+extern int pwc_camera_power(struct pwc_device *pdev, int power);
+
+/* Private ioctl()s; see pwc-ioctl.h */
+extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+
+
+/** pwc-uncompress.c */
+/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
+extern int pwc_decompress(struct pwc_device *pdev);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
new file mode 100644 (file)
index 0000000..f03ea7f
--- /dev/null
@@ -0,0 +1,1435 @@
+/*
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
+ * their chipset available and supporting me while writing this driver.
+ *     - Jeroen Vreeken
+ */
+
+static const char version[] = "0.24";
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/usb.h>
+#include "se401.h"
+
+static int flickerless=0;
+static int video_nr = -1;
+
+static struct usb_device_id device_table [] = {
+       { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
+       { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
+       { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
+       { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
+       { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("SE401 USB Camera Driver");
+MODULE_LICENSE("GPL");
+module_param(flickerless, int, 0);
+MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+module_param(video_nr, int, 0);
+
+static struct usb_driver se401_driver;
+
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ **********************************************************************/
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+
+
+/****************************************************************************
+ *
+ * se401 register read/write functions
+ *
+ ***************************************************************************/
+
+static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
+                        unsigned short value, unsigned char *cp, int size)
+{
+       return usb_control_msg (
+                se401->dev,
+                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
+                req,
+                (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                value,
+                0,
+                cp,
+                size,
+                1000
+        );
+}
+
+static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
+                            unsigned short param)
+{
+       /* specs say that the selector (address) should go in the value field
+          and the param in index, but in the logs of the windows driver they do
+          this the other way around...
+        */
+       return usb_control_msg (
+               se401->dev,
+               usb_sndctrlpipe(se401->dev, 0),
+               SE401_REQ_SET_EXT_FEATURE,
+               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               param,
+               selector,
+                NULL,
+                0,
+                1000
+        );
+}
+
+static unsigned short se401_get_feature(struct usb_se401 *se401, 
+                                       unsigned short selector)
+{
+       /* For 'set' the selecetor should be in index, not sure if the spec is
+          wrong here to....
+        */
+       unsigned char cp[2];
+        usb_control_msg (
+                se401->dev,
+                usb_rcvctrlpipe(se401->dev, 0),
+                SE401_REQ_GET_EXT_FEATURE,
+                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+               0,
+                selector,
+                cp,
+                2,
+                1000
+        );
+       return cp[0]+cp[1]*256;
+}
+
+/****************************************************************************
+ *
+ * Camera control
+ *
+ ***************************************************************************/
+
+
+static int se401_send_pict(struct usb_se401 *se401)
+{
+       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
+       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
+       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
+       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
+       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
+       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+               
+       return 0;
+}
+
+static void se401_set_exposure(struct usb_se401 *se401, int brightness)
+{
+       int integration=brightness<<5;
+       
+       if (flickerless==50) {
+               integration=integration-integration%106667;
+       }
+       if (flickerless==60) {
+               integration=integration-integration%88889;
+       }
+       se401->brightness=integration>>5;
+       se401->expose_h=(integration>>16)&0xff;
+       se401->expose_m=(integration>>8)&0xff;
+       se401->expose_l=integration&0xff;
+}
+
+static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+       p->brightness=se401->brightness;
+       if (se401->enhance) {
+               p->whiteness=32768;
+       } else {
+               p->whiteness=0;
+       }
+       p->colour=65535;
+       p->contrast=65535;
+       p->hue=se401->rgain<<10;
+       p->palette=se401->palette;
+       p->depth=3; /* rgb24 */
+       return 0;
+}
+
+
+static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+       if (p->palette != VIDEO_PALETTE_RGB24)
+               return 1;
+       se401->palette=p->palette;
+       if (p->hue!=se401->hue) {
+               se401->rgain= p->hue>>10;
+               se401->bgain= 0x40-(p->hue>>10);
+               se401->hue=p->hue;
+       }
+       if (p->brightness!=se401->brightness) {
+               se401_set_exposure(se401, p->brightness);
+       }
+       if (p->whiteness>=32768) {
+               se401->enhance=1;
+       } else {
+               se401->enhance=0;
+       }
+       se401_send_pict(se401);
+       se401_send_pict(se401);
+       return 0;
+}
+
+/*
+       Hyundai have some really nice docs about this and other sensor related
+       stuff on their homepage: www.hei.co.kr
+*/
+static void se401_auto_resetlevel(struct usb_se401 *se401)
+{
+       unsigned int ahrc, alrc;
+       int oldreset=se401->resetlevel;
+
+       /* For some reason this normally read-only register doesn't get reset
+          to zero after reading them just once...
+        */
+       se401_get_feature(se401, HV7131_REG_HIREFNOH); 
+       se401_get_feature(se401, HV7131_REG_HIREFNOL);
+       se401_get_feature(se401, HV7131_REG_LOREFNOH);
+       se401_get_feature(se401, HV7131_REG_LOREFNOL);
+       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + 
+           se401_get_feature(se401, HV7131_REG_HIREFNOL);
+       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+           se401_get_feature(se401, HV7131_REG_LOREFNOL);
+
+       /* Not an exact science, but it seems to work pretty well... */
+       if (alrc > 10) {
+               while (alrc>=10 && se401->resetlevel < 63) {
+                       se401->resetlevel++;
+                       alrc /=2;
+               }
+       } else if (ahrc > 20) {
+               while (ahrc>=20 && se401->resetlevel > 0) {
+                       se401->resetlevel--;
+                       ahrc /=2;
+               }
+       }
+       if (se401->resetlevel!=oldreset)
+               se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+
+       return;
+}
+
+/* irq handler for snapshot button */
+static void se401_button_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_se401 *se401 = urb->context;
+       int status;
+       
+       if (!se401->dev) {
+               info("ohoh: device vapourished");
+               return;
+       }
+       
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       if (urb->actual_length >=2) {
+               if (se401->button)
+                       se401->buttonpressed=1;
+       }
+exit:
+       status = usb_submit_urb (urb, GFP_ATOMIC);
+       if (status)
+               err ("%s - usb_submit_urb failed with result %d",
+                    __FUNCTION__, status);
+}
+
+static void se401_video_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_se401 *se401 = urb->context;
+       int length = urb->actual_length;
+
+       /* ohoh... */
+       if (!se401->streaming)
+               return;
+
+       if (!se401->dev) {
+               info ("ohoh: device vapourished");
+               return;
+       }
+
+       /* 0 sized packets happen if we are to fast, but sometimes the camera
+          keeps sending them forever...
+        */
+       if (length && !urb->status) {
+               se401->nullpackets=0;
+               switch(se401->scratch[se401->scratch_next].state) {
+                       case BUFFER_READY:
+                       case BUFFER_BUSY: {
+                               se401->dropped++;
+                               break;
+                       }
+                       case BUFFER_UNUSED: {
+                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
+                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
+                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
+                               se401->scratch[se401->scratch_next].length=length;
+                               if (waitqueue_active(&se401->wq)) {
+                                       wake_up_interruptible(&se401->wq);
+                               }
+                               se401->scratch_overflow=0;
+                               se401->scratch_next++;
+                               if (se401->scratch_next>=SE401_NUMSCRATCH)
+                                       se401->scratch_next=0;
+                               break;
+                       }
+               }
+               se401->bayeroffset+=length;
+               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
+                       se401->bayeroffset=0;
+               }
+       } else {
+               se401->nullpackets++;
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+                       if (waitqueue_active(&se401->wq)) {
+                               wake_up_interruptible(&se401->wq);
+                       }               
+               }
+       }
+
+       /* Resubmit urb for new data */
+       urb->status=0;
+       urb->dev=se401->dev;
+       if(usb_submit_urb(urb, GFP_KERNEL))
+               info("urb burned down");
+       return;
+}
+
+static void se401_send_size(struct usb_se401 *se401, int width, int height)
+{
+       int i=0;
+       int mode=0x03; /* No compression */
+       int sendheight=height;
+       int sendwidth=width;
+
+       /* JangGu compression can only be used with the camera supported sizes,
+          but bayer seems to work with any size that fits on the sensor.
+          We check if we can use compression with the current size with either
+          4 or 16 times subcapturing, if not we use uncompressed bayer data
+          but this will result in cutouts of the maximum size....
+        */
+       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+               i++;
+       while (i<se401->sizes) {
+               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
+                       sendheight=se401->height[i];
+                       sendwidth=se401->width[i];
+                       mode=0x40;
+               }
+               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
+                       sendheight=se401->height[i];
+                       sendwidth=se401->width[i];
+                       mode=0x42;
+               }
+               i++;
+       }
+
+       se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
+       se401_set_feature(se401, SE401_OPERATINGMODE, mode);
+
+       if (mode==0x03) {
+               se401->format=FMT_BAYER;
+       } else {
+               se401->format=FMT_JANGGU;
+       }
+
+       return;
+}
+
+/*
+       In this function se401_send_pict is called several times,
+       for some reason (depending on the state of the sensor and the phase of
+       the moon :) doing this only in either place doesn't always work...
+*/
+static int se401_start_stream(struct usb_se401 *se401)
+{
+       struct urb *urb;
+       int err=0, i;
+       se401->streaming=1;
+
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+       /* Set picture settings */
+       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+       se401_send_pict(se401);
+
+       se401_send_size(se401, se401->cwidth, se401->cheight);
+
+       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+       /* Do some memory allocation */
+       for (i=0; i<SE401_NUMFRAMES; i++) {
+               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
+               se401->frame[i].curpix=0;
+       }
+       for (i=0; i<SE401_NUMSBUF; i++) {
+               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       }
+
+       se401->bayeroffset=0;
+       se401->scratch_next=0;
+       se401->scratch_use=0;
+       se401->scratch_overflow=0;
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+               se401->scratch[i].state=BUFFER_UNUSED;
+       }
+
+       for (i=0; i<SE401_NUMSBUF; i++) {
+               urb=usb_alloc_urb(0, GFP_KERNEL);
+               if(!urb)
+                       return -ENOMEM;
+
+               usb_fill_bulk_urb(urb, se401->dev,
+                       usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
+                       se401->sbuf[i].data, SE401_PACKETSIZE,
+                       se401_video_irq,
+                       se401);
+
+               se401->urb[i]=urb;
+
+               err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
+               if(err)
+                       err("urb burned down");
+       }
+
+       se401->framecount=0;
+
+       return 0;
+}
+
+static int se401_stop_stream(struct usb_se401 *se401)
+{
+       int i;
+
+       if (!se401->streaming || !se401->dev)
+               return 1;
+
+       se401->streaming=0;
+
+       se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+
+       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+               usb_kill_urb(se401->urb[i]);
+               usb_free_urb(se401->urb[i]);
+               se401->urb[i]=NULL;
+               kfree(se401->sbuf[i].data);
+       }
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               kfree(se401->scratch[i].data);
+               se401->scratch[i].data=NULL;
+       }
+
+       return 0;
+}
+
+static int se401_set_size(struct usb_se401 *se401, int width, int height)
+{
+       int wasstreaming=se401->streaming;
+       /* Check to see if we need to change */
+       if (se401->cwidth==width && se401->cheight==height)
+               return 0;
+
+       /* Check for a valid mode */
+       if (!width || !height)
+               return 1;
+       if ((width & 1) || (height & 1))
+               return 1;
+       if (width>se401->width[se401->sizes-1])
+               return 1;
+       if (height>se401->height[se401->sizes-1])
+               return 1;
+
+       /* Stop a current stream and start it again at the new size */
+       if (wasstreaming)
+               se401_stop_stream(se401);
+       se401->cwidth=width;
+       se401->cheight=height;
+       if (wasstreaming)
+               se401_start_stream(se401);
+       return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video Decoding
+ *
+ ***************************************************************************/
+
+/*
+       This shouldn't really be done in a v4l driver....
+       But it does make the image look a lot more usable.
+       Basically it lifts the dark pixels more than the light pixels.
+*/
+static inline void enhance_picture(unsigned char *frame, int len)
+{
+       while (len--) {
+               *frame=(((*frame^255)*(*frame^255))/255)^255;
+               frame++;
+       }
+}
+
+static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
+{
+       struct se401_frame *frame=&se401->frame[se401->curframe];
+       int linelength=se401->cwidth*3;
+
+       if (frame->curlinepix >= linelength) {
+               frame->curlinepix=0;
+               frame->curline+=linelength;
+       }
+
+       /* First three are absolute, all others relative.
+        * Format is rgb from right to left (mirrorred image), 
+        * we flip it to get bgr from left to right. */
+       if (frame->curlinepix < 3) {
+               *(frame->curline-frame->curlinepix)=1+data*4;
+       } else {
+               *(frame->curline-frame->curlinepix)=
+                   *(frame->curline-frame->curlinepix+3)+data*4;
+       }
+       frame->curlinepix++;
+}
+
+static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+{
+       int pos=0;
+       int vlc_cod=0;
+       int vlc_size=0;
+       int vlc_data=0;
+       int bit_cur;
+       int bit;
+       data+=4;
+       while (pos < packetlength) {
+               bit_cur=8;
+               while (bit_cur && bit_exp) {
+                       bit=((*data)>>(bit_cur-1))&1;
+                       if (!vlc_cod) {
+                               if (bit) {
+                                       vlc_size++;
+                               } else {
+                                       if (!vlc_size) {
+                                               decode_JangGu_integrate(se401, 0);
+                                       } else {
+                                               vlc_cod=2;
+                                               vlc_data=0;
+                                       }
+                               }
+                       } else {
+                               if (vlc_cod==2) {
+                                       if (!bit)
+                                               vlc_data =  -(1<<vlc_size) + 1;
+                                       vlc_cod--;
+                               }
+                               vlc_size--;
+                               vlc_data+=bit<<vlc_size;
+                               if (!vlc_size) {
+                                       decode_JangGu_integrate(se401, vlc_data);
+                                       vlc_cod=0;
+                               }
+                       }
+                       bit_cur--;
+                       bit_exp--;
+               }
+               pos++;
+               data++;
+       }
+}
+
+static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+       unsigned char *data=buffer->data;
+       int len=buffer->length;
+       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
+       int datapos=0;
+
+       /* New image? */
+       if (!se401->frame[se401->curframe].curpix) {
+               se401->frame[se401->curframe].curlinepix=0;
+               se401->frame[se401->curframe].curline=
+                   se401->frame[se401->curframe].data+
+                   se401->cwidth*3-1;
+               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
+                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
+               se401->vlcdatapos=0;
+       }
+       while (datapos < len) {
+               size=1024-se401->vlcdatapos;
+               if (size+datapos > len)
+                       size=len-datapos;
+               memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
+               se401->vlcdatapos+=size;
+               packetlength=0;
+               if (se401->vlcdatapos >= 4) {
+                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
+                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
+                       frameinfo=se401->vlcdata[0]&0xc0;
+                       packetlength=((bit_exp+47)>>4)<<1;
+                       if (packetlength > 1024) {
+                               se401->vlcdatapos=0;
+                               datapos=len;
+                               packetlength=0;
+                               se401->error++;
+                               se401->frame[se401->curframe].curpix=0;
+                       }
+               }
+               if (packetlength && se401->vlcdatapos >= packetlength) {
+                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
+                       se401->frame[se401->curframe].curpix+=pix_exp*3;
+                       datapos+=size-(se401->vlcdatapos-packetlength);
+                       se401->vlcdatapos=0;
+                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
+                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
+                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
+                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
+                                               se401->framecount++;
+                                               se401->readcount++;
+                                       }
+                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+                                       }
+                               } else {
+                                       se401->error++;
+                               }
+                               se401->frame[se401->curframe].curpix=0;
+                               datapos=len;
+                       }
+               } else {
+                       datapos+=size;
+               }
+       }
+}
+
+static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+       unsigned char *data=buffer->data;
+       int len=buffer->length;
+       int offset=buffer->offset;
+       int datasize=se401->cwidth*se401->cheight;
+       struct se401_frame *frame=&se401->frame[se401->curframe];
+
+       unsigned char *framedata=frame->data, *curline, *nextline;
+       int width=se401->cwidth;
+       int blineoffset=0, bline;
+       int linelength=width*3, i;
+       
+
+       if (frame->curpix==0) {
+               if (frame->grabstate==FRAME_READY) {
+                       frame->grabstate=FRAME_GRABBING;
+               }
+               frame->curline=framedata+linelength;
+               frame->curlinepix=0;
+       }
+
+       if (offset!=frame->curpix) {
+               /* Regard frame as lost :( */
+               frame->curpix=0;
+               se401->error++;
+               return;
+       }
+
+       /* Check if we have to much data */
+       if (frame->curpix+len > datasize) {
+               len=datasize-frame->curpix;
+       }
+       if (se401->cheight%4)
+               blineoffset=1;
+       bline=frame->curpix/se401->cwidth+blineoffset;
+
+       curline=frame->curline;
+       nextline=curline+linelength;
+       if (nextline >= framedata+datasize*3)
+               nextline=curline;
+       while (len) {
+               if (frame->curlinepix>=width) {
+                       frame->curlinepix-=width;
+                       bline=frame->curpix/width+blineoffset;
+                       curline+=linelength*2;
+                       nextline+=linelength*2;
+                       if (curline >= framedata+datasize*3) {
+                               frame->curlinepix++;
+                               curline-=3;
+                               nextline-=3;
+                               len--;
+                               data++;
+                               frame->curpix++;
+                       }
+                       if (nextline >= framedata+datasize*3)
+                               nextline=curline;
+               }
+               if ((bline&1)) {
+                       if ((frame->curlinepix&1)) {
+                               *(curline+2)=*data;
+                               *(curline-1)=*data;
+                               *(nextline+2)=*data;
+                               *(nextline-1)=*data;
+                       } else {
+                               *(curline+1)=
+                                       (*(curline+1)+*data)/2;
+                               *(curline-2)=
+                                       (*(curline-2)+*data)/2;
+                               *(nextline+1)=*data;
+                               *(nextline-2)=*data;
+                       }
+               } else {
+                       if ((frame->curlinepix&1)) {
+                               *(curline+1)=
+                                       (*(curline+1)+*data)/2;
+                               *(curline-2)=
+                                       (*(curline-2)+*data)/2;
+                               *(nextline+1)=*data;
+                               *(nextline-2)=*data;
+                       } else {
+                               *curline=*data;
+                               *(curline-3)=*data;
+                               *nextline=*data;
+                               *(nextline-3)=*data;
+                       }
+               }
+               frame->curlinepix++;
+               curline-=3;
+               nextline-=3;
+               len--;
+               data++;
+               frame->curpix++;
+       }
+       frame->curline=curline;
+
+       if (frame->curpix>=datasize) {
+               /* Fix the top line */
+               framedata+=linelength;
+               for (i=0; i<linelength; i++) {
+                       framedata--;
+                       *framedata=*(framedata+linelength);
+               }
+               /* Fix the left side (green is already present) */
+               for (i=0; i<se401->cheight; i++) {
+                       *framedata=*(framedata+3);
+                       *(framedata+1)=*(framedata+4);
+                       *(framedata+2)=*(framedata+5);
+                       framedata+=linelength;
+               }
+               frame->curpix=0;
+               frame->grabstate=FRAME_DONE;
+               se401->framecount++;
+               se401->readcount++;
+               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+               }
+       }
+}
+
+static int se401_newframe(struct usb_se401 *se401, int framenr)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int errors=0;
+
+       while (se401->streaming &&
+           (se401->frame[framenr].grabstate==FRAME_READY ||
+            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
+               if(!se401->frame[framenr].curpix) {
+                       errors++;
+               }
+               wait_interruptible(
+                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
+                   &se401->wq,
+                   &wait
+               );
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+                       se401->nullpackets=0;
+                       info("to many null length packets, restarting capture");
+                       se401_stop_stream(se401);
+                       se401_start_stream(se401);                      
+               } else {
+                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
+                               se401->frame[framenr].grabstate=FRAME_ERROR;
+                               return -EIO;
+                       }
+                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
+                       if (se401->format==FMT_JANGGU) {
+                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
+                       } else {
+                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
+                       }
+                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+                       se401->scratch_use++;
+                       if (se401->scratch_use>=SE401_NUMSCRATCH)
+                               se401->scratch_use=0;
+                       if (errors > SE401_MAX_ERRORS) {
+                               errors=0;
+                               info("to much errors, restarting capture");
+                               se401_stop_stream(se401);
+                               se401_start_stream(se401);
+                       }
+               }
+       }
+
+       if (se401->frame[framenr].grabstate==FRAME_DONE)
+               if (se401->enhance)
+                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+       return 0;
+}
+
+static void usb_se401_remove_disconnected (struct usb_se401 *se401)
+{
+       int i;
+
+        se401->dev = NULL;
+
+       for (i=0; i<SE401_NUMSBUF; i++)
+               if (se401->urb[i]) {
+                       usb_kill_urb(se401->urb[i]);
+                       usb_free_urb(se401->urb[i]);
+                       se401->urb[i] = NULL;
+                       kfree(se401->sbuf[i].data);
+               }
+       for (i=0; i<SE401_NUMSCRATCH; i++) {
+               kfree(se401->scratch[i].data);
+       }
+       if (se401->inturb) {
+               usb_kill_urb(se401->inturb);
+               usb_free_urb(se401->inturb);
+       }
+        info("%s disconnected", se401->camera_name);
+
+        /* Free the memory */
+       kfree(se401->width);
+       kfree(se401->height);
+       kfree(se401);
+}
+
+
+
+/****************************************************************************
+ *
+ * Video4Linux
+ *
+ ***************************************************************************/
+
+
+static int se401_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       int err = 0;
+
+       if (se401->user)
+               return -EBUSY;
+       se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
+       if (se401->fbuf)
+               file->private_data = dev;
+       else 
+               err = -ENOMEM;
+       se401->user = !err;
+
+       return err;
+}
+
+static int se401_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = file->private_data;
+        struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       int i;
+
+       rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
+        if (se401->removed) {
+               usb_se401_remove_disconnected(se401);
+               info("device unregistered");
+       } else {
+               for (i=0; i<SE401_NUMFRAMES; i++)
+                       se401->frame[i].grabstate=FRAME_UNUSED;
+               if (se401->streaming)
+                       se401_stop_stream(se401);
+               se401->user=0;
+       }
+       file->private_data = NULL;
+       return 0;
+}
+
+static int se401_do_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+        struct usb_se401 *se401 = (struct usb_se401 *)vdev;
+
+        if (!se401->dev)
+                return -EIO;
+
+        switch (cmd) {
+       case VIDIOCGCAP:
+       {
+               struct video_capability *b = arg;
+               strcpy(b->name, se401->camera_name);
+               b->type = VID_TYPE_CAPTURE;
+               b->channels = 1;
+               b->audios = 0;
+               b->maxwidth = se401->width[se401->sizes-1];
+               b->maxheight = se401->height[se401->sizes-1];
+               b->minwidth = se401->width[0];
+               b->minheight = se401->height[0];
+               return 0;
+       }
+       case VIDIOCGCHAN:
+       {
+               struct video_channel *v = arg;
+
+               if (v->channel != 0)
+                       return -EINVAL;
+               v->flags = 0;
+               v->tuners = 0;
+               v->type = VIDEO_TYPE_CAMERA;
+               strcpy(v->name, "Camera");
+               return 0;
+       }
+       case VIDIOCSCHAN:
+       {
+               struct video_channel *v = arg;
+
+               if (v->channel != 0)
+                       return -EINVAL;
+               return 0;
+       }
+        case VIDIOCGPICT:
+        {
+               struct video_picture *p = arg;
+
+               se401_get_pict(se401, p);
+               return 0;
+       }
+       case VIDIOCSPICT:
+       {
+               struct video_picture *p = arg;
+
+               if (se401_set_pict(se401, p))
+                       return -EINVAL;
+               return 0;
+       }
+       case VIDIOCSWIN:
+       {
+               struct video_window *vw = arg;
+
+               if (vw->flags)
+                       return -EINVAL;
+               if (vw->clipcount)
+                       return -EINVAL;
+               if (se401_set_size(se401, vw->width, vw->height))
+                       return -EINVAL;
+               return 0;
+        }
+       case VIDIOCGWIN:
+       {
+               struct video_window *vw = arg;
+
+               vw->x = 0;               /* FIXME */
+               vw->y = 0;
+               vw->chromakey = 0;
+               vw->flags = 0;
+               vw->clipcount = 0;
+               vw->width = se401->cwidth;
+               vw->height = se401->cheight;
+               return 0;
+       }
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf *vm = arg;
+               int i;
+
+               memset(vm, 0, sizeof(*vm));
+               vm->size = SE401_NUMFRAMES * se401->maxframesize;
+               vm->frames = SE401_NUMFRAMES;
+               for (i=0; i<SE401_NUMFRAMES; i++)
+                       vm->offsets[i] = se401->maxframesize * i;
+               return 0;
+       }
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap *vm = arg;
+
+               if (vm->format != VIDEO_PALETTE_RGB24)
+                       return -EINVAL;
+               if (vm->frame >= SE401_NUMFRAMES)
+                       return -EINVAL;
+               if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
+                       return -EBUSY;
+
+               /* Is this according to the v4l spec??? */
+               if (se401_set_size(se401, vm->width, vm->height))
+                       return -EINVAL;
+               se401->frame[vm->frame].grabstate=FRAME_READY;
+
+               if (!se401->streaming)
+                       se401_start_stream(se401);
+
+               /* Set the picture properties */
+               if (se401->framecount==0)
+                       se401_send_pict(se401);
+               /* Calibrate the reset level after a few frames. */
+               if (se401->framecount%20==1)
+                       se401_auto_resetlevel(se401);
+
+               return 0;
+       }
+       case VIDIOCSYNC:
+       {
+               int *frame = arg;
+               int ret=0;
+
+               if(*frame <0 || *frame >= SE401_NUMFRAMES)
+                       return -EINVAL;
+
+               ret=se401_newframe(se401, *frame);
+               se401->frame[*frame].grabstate=FRAME_UNUSED;
+               return ret;
+       }
+       case VIDIOCGFBUF:
+       {
+               struct video_buffer *vb = arg;
+
+               memset(vb, 0, sizeof(*vb));
+               return 0;
+       }
+       case VIDIOCKEY:
+               return 0;
+       case VIDIOCCAPTURE:
+               return -EINVAL;
+       case VIDIOCSFBUF:
+               return -EINVAL;
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+               return -EINVAL;
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+               return -EINVAL;
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return -EINVAL;
+        default:
+                return -ENOIOCTLCMD;
+        } /* end switch */
+
+        return 0;
+}
+
+static int se401_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);
+}
+
+static ssize_t se401_read(struct file *file, char __user *buf,
+                    size_t count, loff_t *ppos)
+{
+       int realcount=count, ret=0;
+       struct video_device *dev = file->private_data;
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+
+
+       if (se401->dev == NULL)
+               return -EIO;
+       if (realcount > se401->cwidth*se401->cheight*3)
+               realcount=se401->cwidth*se401->cheight*3;
+
+       /* Shouldn't happen: */
+       if (se401->frame[0].grabstate==FRAME_GRABBING)
+               return -EBUSY;
+       se401->frame[0].grabstate=FRAME_READY;
+       se401->frame[1].grabstate=FRAME_UNUSED;
+       se401->curframe=0;
+
+       if (!se401->streaming)
+               se401_start_stream(se401);
+
+       /* Set the picture properties */
+       if (se401->framecount==0)
+               se401_send_pict(se401);
+       /* Calibrate the reset level after a few frames. */
+       if (se401->framecount%20==1)
+               se401_auto_resetlevel(se401);
+
+       ret=se401_newframe(se401, 0);
+
+       se401->frame[0].grabstate=FRAME_UNUSED;
+       if (ret)
+               return ret;     
+       if (copy_to_user(buf, se401->frame[0].data, realcount))
+               return -EFAULT;
+
+       return realcount;
+}
+
+static int se401_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_se401 *se401 = (struct usb_se401 *)dev;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       mutex_lock(&se401->lock);
+
+       if (se401->dev == NULL) {
+               mutex_unlock(&se401->lock);
+               return -EIO;
+       }
+       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+               mutex_unlock(&se401->lock);
+               return -EINVAL;
+       }
+       pos = (unsigned long)se401->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       mutex_unlock(&se401->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       mutex_unlock(&se401->lock);
+
+        return 0;
+}
+
+static struct file_operations se401_fops = {
+       .owner =        THIS_MODULE,
+        .open =         se401_open,
+        .release =      se401_close,
+        .read =         se401_read,
+        .mmap =         se401_mmap,
+       .ioctl =        se401_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+static struct video_device se401_template = {
+       .owner =        THIS_MODULE,
+        .name =         "se401 USB camera",
+        .type =         VID_TYPE_CAPTURE,
+        .hardware =     VID_HARDWARE_SE401,
+       .fops =         &se401_fops,
+};
+
+
+
+/***************************/
+static int se401_init(struct usb_se401 *se401, int button)
+{
+        int i=0, rc;
+        unsigned char cp[0x40];
+       char temp[200];
+
+       /* led on */
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+       /* get camera descriptor */
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
+       if (cp[1]!=0x41) {
+               err("Wrong descriptor type");
+               return 1;
+       }
+       sprintf (temp, "ExtraFeatures: %d", cp[3]);
+
+       se401->sizes=cp[4]+cp[5]*256;
+       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       if (!se401->width)
+               return 1;
+       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       if (!se401->height) {
+               kfree(se401->width);
+               return 1;
+       }
+       for (i=0; i<se401->sizes; i++) {
+                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
+                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+       }
+       sprintf (temp, "%s Sizes:", temp);
+       for (i=0; i<se401->sizes; i++) {
+               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+       }
+       info("%s", temp);
+       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+       se401->cwidth=cp[0]+cp[1]*256;
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+       se401->cheight=cp[0]+cp[1]*256;
+
+       if (!cp[2] && SE401_FORMAT_BAYER) {
+               err("Bayer format not supported!");
+               return 1;
+       }
+       /* set output mode (BAYER) */
+        se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+
+       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+       se401->brightness=cp[0]+cp[1]*256;
+       /* some default values */
+       se401->resetlevel=0x2d;
+       se401->rgain=0x20;
+       se401->ggain=0x20;
+       se401->bgain=0x20;
+       se401_set_exposure(se401, 20000);
+       se401->palette=VIDEO_PALETTE_RGB24;
+       se401->enhance=1;
+       se401->dropped=0;
+       se401->error=0;
+       se401->framecount=0;
+       se401->readcount=0;
+
+       /* Start interrupt transfers for snapshot button */
+       if (button) {
+               se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
+               if (!se401->inturb) {
+                       info("Allocation of inturb failed");
+                       return 1;
+               }
+               usb_fill_int_urb(se401->inturb, se401->dev,
+                   usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
+                   &se401->button, sizeof(se401->button),
+                   se401_button_irq,
+                   se401,
+                   8
+               );
+               if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
+                       info("int urb burned down");
+                       return 1;
+               }
+       } else
+               se401->inturb=NULL;
+
+        /* Flash the led */
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+
+        return 0;
+}
+
+static int se401_probe(struct usb_interface *intf,
+       const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+        struct usb_interface_descriptor *interface;
+        struct usb_se401 *se401;
+        char *camera_name=NULL;
+       int button=1;
+
+        /* We don't handle multi-config cameras */
+        if (dev->descriptor.bNumConfigurations != 1)
+                return -ENODEV;
+
+        interface = &intf->cur_altsetting->desc;
+
+        /* Is it an se401? */
+        if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
+            le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
+                camera_name="Endpoints/Aox SE401";
+        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
+            le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
+                camera_name="Philips PCVC665K";
+        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
+               camera_name="Kensington VideoCAM 67014";
+        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
+               camera_name="Kensington VideoCAM 6701(5/7)";
+        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
+               camera_name="Kensington VideoCAM 67016";
+               button=0;
+       } else
+               return -ENODEV;
+
+        /* Checking vendor/product should be enough, but what the hell */
+        if (interface->bInterfaceClass != 0x00)
+               return -ENODEV;
+        if (interface->bInterfaceSubClass != 0x00)
+               return -ENODEV;
+
+        /* We found one */
+        info("SE401 camera found: %s", camera_name);
+
+        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+                err("couldn't kmalloc se401 struct");
+               return -ENOMEM;
+        }
+
+        se401->dev = dev;
+        se401->iface = interface->bInterfaceNumber;
+        se401->camera_name = camera_name;
+
+       info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
+
+        if (se401_init(se401, button)) {
+               kfree(se401);
+               return -EIO;
+       }
+
+       memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
+       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+       init_waitqueue_head(&se401->wq);
+       mutex_init(&se401->lock);
+       wmb();
+
+       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               kfree(se401);
+               err("video_register_device failed");
+               return -EIO;
+       }
+       info("registered new video device: video%d", se401->vdev.minor);
+
+       usb_set_intfdata (intf, se401);
+        return 0;
+}
+
+static void se401_disconnect(struct usb_interface *intf)
+{
+       struct usb_se401 *se401 = usb_get_intfdata (intf);
+
+       usb_set_intfdata (intf, NULL);
+       if (se401) {
+               video_unregister_device(&se401->vdev);
+               if (!se401->user){
+                       usb_se401_remove_disconnected(se401);
+               } else {
+                       se401->frame[0].grabstate = FRAME_ERROR;
+                       se401->frame[0].grabstate = FRAME_ERROR;
+
+                       se401->streaming = 0;
+
+                       wake_up_interruptible(&se401->wq);
+                       se401->removed = 1;
+               }
+       }
+}
+
+static struct usb_driver se401_driver = {
+        .name          = "se401",
+        .id_table      = device_table,
+       .probe          = se401_probe,
+        .disconnect    = se401_disconnect,
+};
+
+
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init usb_se401_init(void)
+{
+       info("SE401 usb camera driver version %s registering", version);
+       if (flickerless)
+               if (flickerless!=50 && flickerless!=60) {
+                       info("Invallid flickerless value, use 0, 50 or 60.");
+                       return -1;
+       }
+       return usb_register(&se401_driver);
+}
+
+static void __exit usb_se401_exit(void)
+{
+       usb_deregister(&se401_driver);
+       info("SE401 driver deregistered");
+}
+
+module_init(usb_se401_init);
+module_exit(usb_se401_exit);
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
new file mode 100644 (file)
index 0000000..e88a40d
--- /dev/null
@@ -0,0 +1,234 @@
+
+#ifndef __LINUX_se401_H
+#define __LINUX_se401_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+#include <linux/mutex.h>
+
+#define se401_DEBUG    /* Turn on debug messages */
+
+#ifdef se401_DEBUG
+#  define PDEBUG(level, fmt, args...) \
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+#else
+#  define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* An almost drop-in replacement for sleep_on_interruptible */
+#define wait_interruptible(test, queue, wait) \
+{ \
+       add_wait_queue(queue, wait); \
+       set_current_state(TASK_INTERRUPTIBLE); \
+       if (test) \
+               schedule(); \
+       remove_wait_queue(queue, wait); \
+       set_current_state(TASK_RUNNING); \
+       if (signal_pending(current)) \
+               break; \
+}
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
+#define SE401_REQ_CAPTURE_FRAME                        0x43
+#define SE401_REQ_GET_BRT                      0x44
+#define SE401_REQ_SET_BRT                      0x45
+#define SE401_REQ_GET_WIDTH                    0x4c
+#define SE401_REQ_SET_WIDTH                    0x4d
+#define SE401_REQ_GET_HEIGHT                   0x4e
+#define SE401_REQ_SET_HEIGHT                   0x4f
+#define SE401_REQ_GET_OUTPUT_MODE              0x50
+#define SE401_REQ_SET_OUTPUT_MODE              0x51
+#define SE401_REQ_GET_EXT_FEATURE              0x52
+#define SE401_REQ_SET_EXT_FEATURE              0x53
+#define SE401_REQ_CAMERA_POWER                 0x56
+#define SE401_REQ_LED_CONTROL                  0x57
+#define SE401_REQ_BIOS                         0xff
+
+#define SE401_BIOS_READ                                0x07
+
+#define SE401_FORMAT_BAYER     0x40
+
+/* Hyundai hv7131b registers
+   7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A              0x00
+#define HV7131_REG_MODE_B              0x01
+#define HV7131_REG_MODE_C              0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU                0x10
+#define HV7131_REG_FRSL                0x11
+#define HV7131_REG_FCSU                0x12
+#define HV7131_REG_FCSL                0x13
+#define HV7131_REG_FWHU                0x14
+#define HV7131_REG_FWHL                0x15
+#define HV7131_REG_FWWU                0x16
+#define HV7131_REG_FWWL                0x17
+/* Timing registers: */
+#define HV7131_REG_THBU                0x20
+#define HV7131_REG_THBL                0x21
+#define HV7131_REG_TVBU                0x22
+#define HV7131_REG_TVBL                0x23
+#define HV7131_REG_TITU                0x25
+#define HV7131_REG_TITM                0x26
+#define HV7131_REG_TITL                0x27
+#define HV7131_REG_TMCD                0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV                0x30
+#define HV7131_REG_ARCG                0x31
+#define HV7131_REG_AGCG                0x32
+#define HV7131_REG_ABCG                0x33
+#define HV7131_REG_APBV                0x34
+#define HV7131_REG_ASLP                0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR                0x50
+#define HV7131_REG_OFSG                0x51
+#define HV7131_REG_OFSB                0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH    0x57
+#define HV7131_REG_LOREFNOL    0x58
+#define HV7131_REG_HIREFNOH    0x59
+#define HV7131_REG_HIREFNOL    0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE    0x2000
+
+
+/* size of usb transfers */
+#define SE401_PACKETSIZE       4096
+/* number of queued bulk transfers to use, should be about 8 */
+#define SE401_NUMSBUF          1
+/* read the usb specs for this one :) */
+#define SE401_VIDEO_ENDPOINT   1
+#define SE401_BUTTON_ENDPOINT  2
+/* number of frames supported by the v4l part */
+#define SE401_NUMFRAMES                2
+/* scratch buffers for passing data to the decoders */
+#define SE401_NUMSCRATCH       32
+/* maximum amount of data in a JangGu packet */
+#define SE401_VLCDATALEN       1024
+/* number of nul sized packets to receive before kicking the camera */
+#define SE401_MAX_NULLPACKETS  4000
+/* number of decoding errors before kicking the camera */
+#define SE401_MAX_ERRORS       200
+
+struct usb_device;
+
+struct se401_sbuf {
+       unsigned char *data;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+enum {
+       FMT_BAYER,
+       FMT_JANGGU,
+};
+
+enum {
+       BUFFER_UNUSED,
+       BUFFER_READY,
+       BUFFER_BUSY,
+       BUFFER_DONE,
+};
+
+struct se401_scratch {
+       unsigned char *data;
+       volatile int state;
+       int offset;
+       int length;
+};
+
+struct se401_frame {
+       unsigned char *data;            /* Frame buffer */
+
+       volatile int grabstate; /* State of grabbing */
+
+       unsigned char *curline;
+       int curlinepix;
+       int curpix;
+};
+
+struct usb_se401 {
+       struct video_device vdev;
+
+       /* Device structure */
+       struct usb_device *dev;
+
+       unsigned char iface;
+
+       char *camera_name;
+
+       int change;
+       int brightness;
+       int hue;
+       int rgain;
+       int ggain;
+       int bgain;
+       int expose_h;
+       int expose_m;
+       int expose_l;
+       int resetlevel;
+       
+       int enhance;
+
+       int format;
+       int sizes;
+       int *width;
+       int *height;
+       int cwidth;             /* current width */
+       int cheight;            /* current height */
+       int palette;
+       int maxframesize;
+       int cframesize;         /* current framesize */
+
+       struct mutex lock;
+       int user;               /* user count for exclusive use */
+       int removed;            /* device disconnected */
+
+       int streaming;          /* Are we streaming video? */
+
+       char *fbuf;             /* Videodev buffer area */
+
+       struct urb *urb[SE401_NUMSBUF];
+       struct urb *inturb;
+       
+       int button;
+       int buttonpressed;
+
+       int curframe;           /* Current receiving frame */
+       struct se401_frame frame[SE401_NUMFRAMES];      
+       int readcount;
+       int framecount;
+       int error;
+       int dropped;
+
+       int scratch_next;
+       int scratch_use;
+       int scratch_overflow;
+       struct se401_scratch scratch[SE401_NUMSCRATCH];
+
+       /* Decoder specific data: */
+       unsigned char vlcdata[SE401_VLCDATALEN];
+       int vlcdatapos;
+       int bayeroffset;
+
+       struct se401_sbuf sbuf[SE401_NUMSBUF];
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int nullpackets;
+};
+
+
+
+#endif
+
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
new file mode 100644 (file)
index 0000000..8bcb0f7
--- /dev/null
@@ -0,0 +1,7 @@
+sn9c102-objs    := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
+                   sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
+                   sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
+                   sn9c102_tas5130d1b.o
+
+obj-$(CONFIG_USB_SN9C102)       += sn9c102.o
+
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
new file mode 100644 (file)
index 0000000..1d70a62
--- /dev/null
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _SN9C102_H_
+#define _SN9C102_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
+
+#include "sn9c102_sensor.h"
+
+/*****************************************************************************/
+
+#define SN9C102_DEBUG
+#define SN9C102_DEBUG_LEVEL       2
+#define SN9C102_MAX_DEVICES       64
+#define SN9C102_PRESERVE_IMGSCALE 0
+#define SN9C102_FORCE_MUNMAP      0
+#define SN9C102_MAX_FRAMES        32
+#define SN9C102_URBS              2
+#define SN9C102_ISO_PACKETS       7
+#define SN9C102_ALTERNATE_SETTING 8
+#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
+#define SN9C102_CTRL_TIMEOUT      300
+#define SN9C102_FRAME_TIMEOUT     2
+
+/*****************************************************************************/
+
+enum sn9c102_bridge {
+       BRIDGE_SN9C101 = 0x01,
+       BRIDGE_SN9C102 = 0x02,
+       BRIDGE_SN9C103 = 0x04,
+};
+
+SN9C102_ID_TABLE
+SN9C102_SENSOR_TABLE
+
+enum sn9c102_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct sn9c102_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum sn9c102_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum sn9c102_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum sn9c102_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum sn9c102_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+typedef char sn9c103_sof_header_t[18];
+typedef char sn9c102_sof_header_t[12];
+typedef char sn9c102_eof_header_t[4];
+
+struct sn9c102_sysfs_attr {
+       u8 reg, i2c_reg;
+       sn9c103_sof_header_t frame_header;
+};
+
+struct sn9c102_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DEFINE_MUTEX(sn9c102_sysfs_lock);
+static DECLARE_RWSEM(sn9c102_disconnect);
+
+struct sn9c102_device {
+       struct video_device* v4ldev;
+
+       enum sn9c102_bridge bridge;
+       struct sn9c102_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[SN9C102_URBS];
+       void* transfer_buffer[SN9C102_URBS];
+       u8* control_buffer;
+
+       struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum sn9c102_io_method io;
+       enum sn9c102_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct sn9c102_sysfs_attr sysfs;
+       sn9c103_sof_header_t sof_header;
+       u16 reg[63];
+
+       struct sn9c102_module_param module_param;
+
+       enum sn9c102_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
+{
+       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
+               return cam;
+
+       return NULL;
+}
+
+
+void
+sn9c102_attach_sensor(struct sn9c102_device* cam,
+                      struct sn9c102_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef SN9C102_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("sn9c102: " fmt "\n", ## args);               \
+               else if ((level) == 3)                                        \
+                       pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _SN9C102_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
new file mode 100644 (file)
index 0000000..4c6cc63
--- /dev/null
@@ -0,0 +1,2919 @@
+/***************************************************************************
+ * V4L2 driver for SN9C10x PC Camera Controllers                           *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "sn9c102.h"
+
+/*****************************************************************************/
+
+#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
+#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
+#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
+#define SN9C102_MODULE_LICENSE  "GPL"
+#define SN9C102_MODULE_VERSION  "1:1.27"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
+
+MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
+MODULE_VERSION(SN9C102_MODULE_VERSION);
+MODULE_LICENSE(SN9C102_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
+                 " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+
+static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = 
+                               SN9C102_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
+                 "\ndetected camera."
+                 "\n 0 = do not force memory unmapping"
+                 "\n 1 = force memory unmapping (save memory)"
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                 "\n");
+
+static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
+                                       SN9C102_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
+                 "\n");
+
+#ifdef SN9C102_DEBUG
+static unsigned short debug = SN9C102_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 3:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = more verbose messages"
+                 "\nLevel 3 is useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
+                 "\n");
+#endif
+
+/*****************************************************************************/
+
+static sn9c102_sof_header_t sn9c102_sof_header[] = {
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
+};
+
+static sn9c103_sof_header_t sn9c103_sof_header[] = {
+       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
+};
+
+static sn9c102_eof_header_t sn9c102_eof_header[] = {
+       {0x00, 0x00, 0x00, 0x00},
+       {0x40, 0x00, 0x00, 0x00},
+       {0x80, 0x00, 0x00, 0x00},
+       {0xc0, 0x00, 0x00, 0x00},
+};
+
+/*****************************************************************************/
+
+static u32 
+sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
+                        enum sn9c102_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > SN9C102_MAX_FRAMES)
+               count = SN9C102_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void sn9c102_release_buffers(struct sn9c102_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
+{
+       struct sn9c102_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       int i, res;
+
+       if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             index, 0, buff, sizeof(buff),
+                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
+       if (res < 0) {
+               DBG(3, "Failed to write registers (index 0x%02X, error %d)",
+                   index, res);
+               return -1;
+       }
+
+       for (i = 0; i < sizeof(buff); i++)
+               cam->reg[index+i] = buff[i];
+
+       return 0;
+}
+
+
+int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       if (index >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       *buff = value;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (value 0x%02X, index "
+                      "0x%02X, error %d)", value, index, res);
+               return -1;
+       }
+
+       cam->reg[index] = value;
+
+       return 0;
+}
+
+
+/* NOTE: reading some registers always returns 0 */
+static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
+                   index, res);
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
+{
+       if (index >= ARRAY_SIZE(cam->reg))
+               return -1;
+
+       return cam->reg[index];
+}
+
+
+static int
+sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
+{
+       int i, r;
+
+       for (i = 1; i <= 5; i++) {
+               r = sn9c102_read_reg(cam, 0x08);
+               if (r < 0)
+                       return -EIO;
+               if (r & 0x04)
+                       return 0;
+               if (sensor->frequency & SN9C102_I2C_400KHZ)
+                       udelay(5*16);
+               else
+                       udelay(16*16);
+       }
+       return -EBUSY;
+}
+
+
+static int
+sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, 
+                              struct sn9c102_sensor* sensor)
+{
+       int r;
+       r = sn9c102_read_reg(cam, 0x08);
+       return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
+}
+
+
+static int
+sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, 
+                               struct sn9c102_sensor* sensor)
+{
+       int r;
+       r = sn9c102_read_reg(cam, 0x08);
+       return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
+}
+
+
+int 
+sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
+                         struct sn9c102_sensor* sensor, u8 data0, u8 data1,
+                         u8 n, u8 buffer[])
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       /* Write cycle */
+       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
+       data[1] = data0; /* I2C slave id */
+       data[2] = data1; /* address */
+       data[7] = 0x10;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_wait(cam, sensor);
+
+       /* Read cycle - n bytes */
+       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
+                 (n << 4) | 0x02;
+       data[1] = data0;
+       data[7] = 0x10;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_wait(cam, sensor);
+
+       /* The first read byte will be placed in data[4] */
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+                             0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_detect_read_error(cam, sensor);
+
+       PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
+             data[4]);
+
+       if (err) {
+               DBG(3, "I2C read failed for %s image sensor", sensor->name);
+               return -1;
+       }
+
+       if (buffer)
+               memcpy(buffer, data, sizeof(buffer));
+
+       return (int)data[4];
+}
+
+
+int 
+sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
+                          struct sn9c102_sensor* sensor, u8 n, u8 data0,
+                          u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* data = cam->control_buffer;
+       int err = 0, res;
+
+       /* Write cycle. It usually is address + value */
+       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
+                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
+                 | ((n - 1) << 4);
+       data[1] = data0;
+       data[2] = data1;
+       data[3] = data2;
+       data[4] = data3;
+       data[5] = data4;
+       data[6] = data5;
+       data[7] = 0x14;
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
+                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
+       if (res < 0)
+               err += res;
+
+       err += sn9c102_i2c_wait(cam, sensor);
+       err += sn9c102_i2c_detect_write_error(cam, sensor);
+
+       if (err)
+               DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+       PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
+             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
+             n, data0, data1, data2, data3, data4, data5);
+
+       return err ? -1 : 0;
+}
+
+
+int
+sn9c102_i2c_try_read(struct sn9c102_device* cam,
+                     struct sn9c102_sensor* sensor, u8 address)
+{
+       return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
+                                       address, 1, NULL);
+}
+
+
+int
+sn9c102_i2c_try_write(struct sn9c102_device* cam,
+                      struct sn9c102_sensor* sensor, u8 address, u8 value)
+{
+       return sn9c102_i2c_try_raw_write(cam, sensor, 3, 
+                                        sensor->i2c_slave_id, address,
+                                        value, 0, 0, 0);
+}
+
+
+int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
+{
+       return sn9c102_i2c_try_read(cam, &cam->sensor, address);
+}
+
+
+int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
+{
+       return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
+}
+
+/*****************************************************************************/
+
+static void*
+sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+       size_t soflen = 0, i;
+       u8 j, n = 0;
+
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               soflen = sizeof(sn9c102_sof_header_t);
+               n = sizeof(sn9c102_sof_header) / soflen;
+               break;
+       case BRIDGE_SN9C103:
+               soflen = sizeof(sn9c103_sof_header_t);
+               n = sizeof(sn9c103_sof_header) / soflen;
+       }
+
+       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
+               for (j = 0; j < n; j++)
+                       /* The invariable part of the header is 6 bytes long */
+                       if ((cam->bridge != BRIDGE_SN9C103 &&
+                           !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
+                           (cam->bridge == BRIDGE_SN9C103 &&
+                           !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
+                               memcpy(cam->sof_header, mem + i, soflen);
+                               /* Skip the header */
+                               return mem + i + soflen;
+                       }
+
+       return NULL;
+}
+
+
+static void*
+sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
+{
+       size_t eoflen = sizeof(sn9c102_eof_header_t), i;
+       unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
+
+       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+               return NULL; /* EOF header does not exist in compressed data */
+
+       for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
+               for (j = 0; j < n; j++)
+                       if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
+                               return mem + i;
+
+       return NULL;
+}
+
+
+static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct sn9c102_device* cam = urb->context;
+       struct sn9c102_frame_t** f;
+       size_t imagesize, soflen;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       soflen = (cam->bridge) == BRIDGE_SN9C103 ?
+                                 sizeof(sn9c103_sof_header_t) :
+                                 sizeof(sn9c102_sof_header_t);
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int img, len, status;
+               void *pos, *sof, *eof;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               PDBGG("Isochrnous frame: length %u, #%u i", len, i);
+
+redo:
+               sof = sn9c102_find_sof_header(cam, pos, len);
+               if (likely(!sof)) {
+                       eof = sn9c102_find_eof_header(cam, pos, len);
+                       if ((*f)->state == F_GRABBING) {
+end_of_frame:
+                               img = len;
+
+                               if (eof)
+                                       img = (eof > pos) ? eof - pos - 1 : 0;
+
+                               if ((*f)->buf.bytesused+img > imagesize) {
+                                       u32 b;
+                                       b = (*f)->buf.bytesused + img -
+                                           imagesize;
+                                       img = imagesize - (*f)->buf.bytesused;
+                                       DBG(3, "Expected EOF not found: "
+                                              "video frame cut");
+                                       if (eof)
+                                               DBG(3, "Exceeded limit: +%u "
+                                                      "bytes", (unsigned)(b));
+                               }
+
+                               memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
+                                      img);
+
+                               if ((*f)->buf.bytesused == 0)
+                                       do_gettimeofday(&(*f)->buf.timestamp);
+
+                               (*f)->buf.bytesused += img;
+
+                               if ((*f)->buf.bytesused == imagesize ||
+                                   (cam->sensor.pix_format.pixelformat ==
+                                               V4L2_PIX_FMT_SN9C10X && eof)) {
+                                       u32 b;
+                                       b = (*f)->buf.bytesused;
+                                       (*f)->state = F_DONE;
+                                       (*f)->buf.sequence= ++cam->frame_count;
+                                       spin_lock(&cam->queue_lock);
+                                       list_move_tail(&(*f)->frame,
+                                                      &cam->outqueue);
+                                       if (!list_empty(&cam->inqueue))
+                                               (*f) = list_entry(
+                                                       cam->inqueue.next,
+                                                       struct sn9c102_frame_t,
+                                                       frame );
+                                       else
+                                               (*f) = NULL;
+                                       spin_unlock(&cam->queue_lock);
+                                       memcpy(cam->sysfs.frame_header,
+                                              cam->sof_header, soflen);
+                                       DBG(3, "Video frame captured: %lu "
+                                              "bytes", (unsigned long)(b));
+
+                                       if (!(*f))
+                                               goto resubmit_urb;
+
+                               } else if (eof) {
+                                       (*f)->state = F_ERROR;
+                                       DBG(3, "Not expected EOF after %lu "
+                                              "bytes of image data", 
+                                           (unsigned long)
+                                           ((*f)->buf.bytesused));
+                               }
+
+                               if (sof) /* (1) */
+                                       goto start_of_frame;
+
+                       } else if (eof) {
+                               DBG(3, "EOF without SOF");
+                               continue;
+
+                       } else {
+                               PDBGG("Ignoring pointless isochronous frame");
+                               continue;
+                       }
+
+               } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
+start_of_frame:
+                       (*f)->state = F_GRABBING;
+                       (*f)->buf.bytesused = 0;
+                       len -= (sof - pos);
+                       pos = sof;
+                       DBG(3, "SOF detected: new video frame");
+                       if (len)
+                               goto redo;
+
+               } else if ((*f)->state == F_GRABBING) {
+                       eof = sn9c102_find_eof_header(cam, pos, len);
+                       if (eof && eof < sof)
+                               goto end_of_frame; /* (1) */
+                       else {
+                               if (cam->sensor.pix_format.pixelformat ==
+                                   V4L2_PIX_FMT_SN9C10X) {
+                                       eof = sof - soflen;
+                                       goto end_of_frame;
+                               } else {
+                                       DBG(3, "SOF before expected EOF after "
+                                              "%lu bytes of image data", 
+                                           (unsigned long)
+                                           ((*f)->buf.bytesused));
+                                       goto start_of_frame;
+                               }
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int sn9c102_start_transfer(struct sn9c102_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+                                                      680, 800, 900, 1023};
+       const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
+                                                      680, 800, 900, 1003};
+       const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
+                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
+                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < SN9C102_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < SN9C102_URBS; i++) {
+               urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = SN9C102_ISO_PACKETS;
+               urb->complete = sn9c102_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       /* Enable video */
+       if (!(cam->reg[0x01] & 0x04)) {
+               err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
+               if (err) {
+                       err = -EIO;
+                       DBG(1, "I/O hardware error");
+                       goto free_urbs;
+               }
+       }
+
+       err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < SN9C102_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < SN9C102_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int sn9c102_stop_transfer(struct sn9c102_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = SN9C102_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    SN9C102_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. "
+                      "To use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
+{
+       char str[5];
+       char* endp;
+       unsigned long val;
+
+       if (len < 4) {
+               strncpy(str, buff, len);
+               str[len+1] = '\0';
+       } else {
+               strncpy(str, buff, 4);
+               str[4] = '\0';
+       }
+
+       val = simple_strtoul(str, &endp, 0);
+
+       *count = 0;
+       if (val <= 0xff)
+               *count = (ssize_t)(endp - str);
+       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
+               *count += 1;
+
+       return (u8)val;
+}
+
+/*
+   NOTE 1: being inside one of the following methods implies that the v4l
+           device exists for sure (see kobjects and reference counters)
+   NOTE 2: buffers are PAGE_SIZE long
+*/
+
+static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.reg);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+} 
+
+
+static ssize_t 
+sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = sn9c102_strtou8(buf, len, &count);
+       if (index > 0x1f || !count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.reg = index;
+
+       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+} 
+
+
+static ssize_t
+sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
+       if (err) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t 
+sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 index;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       index = sn9c102_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       cam->sysfs.i2c_reg = index;
+
+       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+       int val;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       count = sprintf(buf, "%d\n", val);
+
+       DBG(3, "Read bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+} 
+
+
+static ssize_t
+sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       u8 value;
+       ssize_t count;
+       int err;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENOSYS;
+       }
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EINVAL;
+       }
+
+       err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
+       if (err) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -EIO;
+       }
+
+       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
+           cam->sysfs.i2c_reg, value);
+       DBG(3, "Written bytes: %zd", count);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       return count;
+}
+
+
+static ssize_t
+sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
+{
+       struct sn9c102_device* cam;
+       enum sn9c102_bridge bridge;
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam) {
+               mutex_unlock(&sn9c102_sysfs_lock);
+               return -ENODEV;
+       }
+
+       bridge = cam->bridge;
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count)
+               return -EINVAL;
+
+       switch (bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               if (value > 0x0f)
+                       return -EINVAL;
+               if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
+                       res = sn9c102_store_val(cd, buf, len);
+               break;
+       case BRIDGE_SN9C103:
+               if (value > 0x7f)
+                       return -EINVAL;
+               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
+                       res = sn9c102_store_val(cd, buf, len);
+               break;
+       }
+
+       return res;
+}
+
+
+static ssize_t
+sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+{
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count || value > 0x7f)
+               return -EINVAL;
+
+       if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
+               res = sn9c102_store_val(cd, buf, len);
+
+       return res;
+}
+
+
+static ssize_t
+sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+{
+       ssize_t res = 0;
+       u8 value;
+       ssize_t count;
+
+       value = sn9c102_strtou8(buf, len, &count);
+       if (!count || value > 0x7f)
+               return -EINVAL;
+
+       if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
+               res = sn9c102_store_val(cd, buf, len);
+
+       return res;
+}
+
+
+static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
+{
+       struct sn9c102_device* cam;
+       ssize_t count;
+
+       cam = video_get_drvdata(to_video_device(cd));
+       if (!cam)
+               return -ENODEV;
+
+       count = sizeof(cam->sysfs.frame_header);
+       memcpy(buf, cam->sysfs.frame_header, count);
+
+       DBG(3, "Frame header, read bytes: %zd", count);
+
+       return count;
+} 
+
+
+static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+                         sn9c102_show_reg, sn9c102_store_reg);
+static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+                         sn9c102_show_val, sn9c102_store_val);
+static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+                         sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
+static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+                         sn9c102_show_i2c_val, sn9c102_store_i2c_val);
+static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
+static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
+                         sn9c102_show_frame_header, NULL);
+
+
+static void sn9c102_create_sysfs(struct sn9c102_device* cam)
+{
+       struct video_device *v4ldev = cam->v4ldev;
+
+       video_device_create_file(v4ldev, &class_device_attr_reg);
+       video_device_create_file(v4ldev, &class_device_attr_val);
+       video_device_create_file(v4ldev, &class_device_attr_frame_header);
+       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
+               video_device_create_file(v4ldev, &class_device_attr_green);
+       else if (cam->bridge == BRIDGE_SN9C103) {
+               video_device_create_file(v4ldev, &class_device_attr_blue);
+               video_device_create_file(v4ldev, &class_device_attr_red);
+       }
+       if (cam->sensor.sysfs_ops) {
+               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+       }
+}
+#endif /* CONFIG_VIDEO_ADV_DEBUG */
+
+/*****************************************************************************/
+
+static int
+sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
+       else
+               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
+
+       return err ? -EIO : 0;
+}
+
+
+static int
+sn9c102_set_compression(struct sn9c102_device* cam,
+                        struct v4l2_jpegcompression* compression)
+{
+       int err = 0;
+
+       if (compression->quality == 0)
+               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
+       else if (compression->quality == 1)
+               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
+
+       return err ? -EIO : 0;
+}
+
+
+static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
+{
+       u8 r = 0;
+       int err = 0;
+
+       if (scale == 1)
+               r = cam->reg[0x18] & 0xcf;
+       else if (scale == 2) {
+               r = cam->reg[0x18] & 0xcf;
+               r |= 0x10;
+       } else if (scale == 4)
+               r = cam->reg[0x18] | 0x20;
+
+       err += sn9c102_write_reg(cam, r, 0x18);
+       if (err)
+               return -EIO;
+
+       PDBGG("Scaling factor: %u", scale);
+
+       return 0;
+}
+
+
+static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
+          v_start = (u8)(rect->top - s->cropcap.bounds.top),
+          h_size = (u8)(rect->width / 16),
+          v_size = (u8)(rect->height / 16);
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+       err += sn9c102_write_reg(cam, h_size, 0x15);
+       err += sn9c102_write_reg(cam, v_size, 0x16);
+       if (err)
+               return -EIO;
+
+       PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
+             "%u %u %u %u", h_start, v_start, h_size, v_size);
+
+       return 0;
+}
+
+
+static int sn9c102_init(struct sn9c102_device* cam)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
+       err += sn9c102_set_crop(cam, rect);
+       if (err)
+               return err;
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED))
+               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
+       else
+               err += sn9c102_set_compression(cam, &cam->compression);
+       err += sn9c102_set_pix_format(cam, &s->pix_format);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, &s->pix_format);
+       if (err)
+               return err;
+
+       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
+               DBG(3, "Compressed video format is active, quality %d",
+                   cam->compression.quality);
+       else
+               DBG(3, "Uncompressed video format is active");
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void sn9c102_release_resources(struct sn9c102_device* cam)
+{
+       mutex_lock(&sn9c102_sysfs_lock);
+
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+
+       usb_put_dev(cam->usbdev);
+
+       mutex_unlock(&sn9c102_sysfs_lock);
+
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int sn9c102_open(struct inode* inode, struct file* filp)
+{
+       struct sn9c102_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&sn9c102_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&sn9c102_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&sn9c102_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&sn9c102_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = sn9c102_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = sn9c102_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       sn9c102_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&sn9c102_disconnect);
+       return err;
+}
+
+
+static int sn9c102_release(struct inode* inode, struct file* filp)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       sn9c102_stop_transfer(cam);
+
+       sn9c102_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               sn9c102_release_resources(cam);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose "
+                      "the read method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       sn9c102_empty_framequeues(cam);
+               sn9c102_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       sn9c102_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return count;
+}
+
+
+static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       struct sn9c102_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
+                                            IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               sn9c102_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void sn9c102_vm_open(struct vm_area_struct* vma)
+{
+       struct sn9c102_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void sn9c102_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct sn9c102_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct sn9c102_vm_ops = {
+       .open = sn9c102_vm_open,
+       .close = sn9c102_vm_close,
+};
+
+
+static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &sn9c102_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       sn9c102_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "sn9c102",
+               .version = SN9C102_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id && ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
+             (unsigned long)ctrl.id, (unsigned long)ctrl.value);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_pix_format* pix_format = &(s->pix_format);
+       u8 scale;
+       const enum sn9c102_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       /* Preserve R,G or B origin */
+       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
+       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
+
+       if (rect->width < 16)
+               rect->width = 16;
+       if (rect->height < 16)
+               rect->height = 16;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+
+       rect->width &= ~15L;
+       rect->height &= ~15L;
+
+       if (SN9C102_PRESERVE_IMGSCALE) {
+               /* Calculate the actual scaling factor */
+               u32 a, b;
+               a = rect->width * rect->height;
+               b = pix_format->width * pix_format->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       } else
+               scale = 1;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               sn9c102_release_buffers(cam);
+
+       err = sn9c102_set_crop(cam, rect);
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+       err += sn9c102_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width/scale;
+       s->pix_format.height = rect->height/scale;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
+           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               sn9c102_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               sn9c102_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "bayer rgb");
+               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
+       } else if (fmtd.index == 1) {
+               strcpy(fmtd.description, "compressed");
+               fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
+                            ? 0 : (pfmt->width * pfmt->priv) / 8;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
+                         void __user * arg)
+{
+       struct sn9c102_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       u8 scale;
+       const enum sn9c102_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       { /* calculate the actual scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       }
+
+       rect.width = scale * pix->width;
+       rect.height = scale * pix->height;
+
+       if (rect.width < 16)
+               rect.width = 16;
+       if (rect.height < 16)
+               rect.height = 16;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+
+       rect.width &= ~15L;
+       rect.height &= ~15L;
+
+       { /* adjust the scaling factor */
+               u32 a, b;
+               a = rect.width * rect.height;
+               b = pix->width * pix->height;
+               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
+       }
+
+       pix->width = rect.width / scale;
+       pix->height = rect.height / scale;
+
+       if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
+           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
+               pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv; /* bpp */
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+                           ? 0 : (pix->width * pix->priv) / 8;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. Unmap the "
+                                      "buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap  || cam->io == IO_READ)
+               sn9c102_release_buffers(cam);
+
+       err += sn9c102_set_pix_format(cam, pix);
+       err += sn9c102_set_crop(cam, &rect);
+       if (s->set_pix_format)
+               err += s->set_pix_format(cam, pix);
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+       err += sn9c102_set_scale(cam, scale);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               sn9c102_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               sn9c102_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression,
+                        sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum sn9c102_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0 && jc.quality != 1)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       err += sn9c102_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
+                              "still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       sn9c102_empty_framequeues(cam);
+
+       sn9c102_release_buffers(cam);
+       if (rb.count)
+               rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               sn9c102_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
+                     void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct sn9c102_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = sn9c102_stream_interrupt(cam)))
+                       return err;
+
+       sn9c102_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
+               sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
+                              unsigned int cmd, void __user * arg)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return sn9c102_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return sn9c102_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return sn9c102_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return sn9c102_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return sn9c102_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return sn9c102_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return sn9c102_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return sn9c102_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return sn9c102_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return sn9c102_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return sn9c102_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return sn9c102_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return sn9c102_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return sn9c102_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return sn9c102_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return sn9c102_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return sn9c102_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return sn9c102_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return sn9c102_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return sn9c102_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return sn9c102_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return sn9c102_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int sn9c102_ioctl(struct inode* inode, struct file* filp,
+                         unsigned int cmd, unsigned long arg)
+{
+       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "sn9c102", cmd);
+
+       err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+/*****************************************************************************/
+
+static struct file_operations sn9c102_fops = {
+       .owner = THIS_MODULE,
+       .open =    sn9c102_open,
+       .release = sn9c102_release,
+       .ioctl =   sn9c102_ioctl,
+       .read =    sn9c102_read,
+       .poll =    sn9c102_poll,
+       .mmap =    sn9c102_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+/* It exists a single interface only. We do not need to validate anything. */
+static int
+sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct sn9c102_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0, r;
+
+       if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       r = sn9c102_read_reg(cam, 0x00);
+       if (r < 0 || r != 0x10) {
+               DBG(1, "Sorry, this is not a SN9C10x based camera "
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+               err = -ENODEV;
+               goto fail;
+       }
+
+       cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
+                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
+       switch (cam->bridge) {
+       case BRIDGE_SN9C101:
+       case BRIDGE_SN9C102:
+               DBG(2, "SN9C10[12] PC Camera Controller detected "
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+               break;
+       case BRIDGE_SN9C103:
+               DBG(2, "SN9C103 PC Camera Controller detected "
+                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
+               break;
+       }
+
+       for  (i = 0; sn9c102_sensor_table[i]; i++) {
+               err = sn9c102_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err) {
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+               DBG(3, "Support for %s maintained by %s",
+                   cam->sensor.name, cam->sensor.maintainer);
+       } else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (sn9c102_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &sn9c102_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       sn9c102_create_sysfs(cam);
+       DBG(2, "Optional device control through 'sysfs' interface ready");
+#endif
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void sn9c102_usb_disconnect(struct usb_interface* intf)
+{
+       struct sn9c102_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&sn9c102_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               sn9c102_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               sn9c102_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&sn9c102_disconnect);
+}
+
+
+static struct usb_driver sn9c102_usb_driver = {
+       .name =       "sn9c102",
+       .id_table =   sn9c102_id_table,
+       .probe =      sn9c102_usb_probe,
+       .disconnect = sn9c102_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init sn9c102_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
+       KDBG(3, SN9C102_MODULE_AUTHOR);
+
+       if ((err = usb_register(&sn9c102_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit sn9c102_module_exit(void)
+{
+       usb_deregister(&sn9c102_usb_driver);
+}
+
+
+module_init(sn9c102_module_init);
+module_exit(sn9c102_module_exit);
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c
new file mode 100644 (file)
index 0000000..46c12ec
--- /dev/null
@@ -0,0 +1,271 @@
+/***************************************************************************
+ * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor hv7131d;
+
+
+static int hv7131d_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x0e, 0x18);
+       err += sn9c102_write_reg(cam, 0xf2, 0x19);
+
+       err += sn9c102_i2c_write(cam, 0x01, 0x04);
+       err += sn9c102_i2c_write(cam, 0x02, 0x00);
+       err += sn9c102_i2c_write(cam, 0x28, 0x00);
+
+       return err;
+}
+
+
+static int hv7131d_get_ctrl(struct sn9c102_device* cam, 
+                            struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x26),
+                           r2 = sn9c102_i2c_read(cam, 0x27);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 8) | (r2 & 0xff);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
+                       return -EIO;
+               ctrl->value = 0x3f - (ctrl->value & 0x3f);
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
+                       return -EIO;
+               ctrl->value = 0x3f - (ctrl->value & 0x3f);
+               return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
+                       return -EIO;
+               ctrl->value = 0x3f - (ctrl->value & 0x3f);
+               return 0;
+       case SN9C102_V4L2_CID_RESET_LEVEL:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x3f;
+               return 0;
+       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x07;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int hv7131d_set_ctrl(struct sn9c102_device* cam, 
+                            const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
+               err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_RESET_LEVEL:
+               err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
+               err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int hv7131d_set_crop(struct sn9c102_device* cam, 
+                            const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &hv7131d;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int hv7131d_set_pix_format(struct sn9c102_device* cam, 
+                                  const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x42, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0xf2, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor hv7131d = {
+       .name = "HV7131D",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x11,
+       .init = &hv7131d_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x0250,
+                       .maximum = 0xffff,
+                       .step = 0x0001,
+                       .default_value = 0x0250,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x1e,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_RESET_LEVEL,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "reset level",
+                       .minimum = 0x19,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x30,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "pixel bias voltage",
+                       .minimum = 0x00,
+                       .maximum = 0x07,
+                       .step = 0x01,
+                       .default_value = 0x02,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &hv7131d_get_ctrl,
+       .set_ctrl = &hv7131d_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &hv7131d_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &hv7131d_set_pix_format
+};
+
+
+int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       if (r0 != 0x00 && r1 != 0x04)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &hv7131d);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c
new file mode 100644 (file)
index 0000000..d9aa7a6
--- /dev/null
@@ -0,0 +1,363 @@
+/***************************************************************************
+ * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor mi0343;
+static u8 mi0343_i2c_data[5+1];
+
+
+static int mi0343_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x0a, 0x14);
+       err += sn9c102_write_reg(cam, 0x40, 0x01);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x07, 0x18);
+       err += sn9c102_write_reg(cam, 0xa0, 0x19);
+
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x0d, 0x00, 0x01, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x0d, 0x00, 0x00, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x03, 0x01, 0xe1, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x04, 0x02, 0x81, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x05, 0x00, 0x17, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x06, 0x00, 0x11, 0, 0);
+       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
+                                        0x62, 0x04, 0x9a, 0, 0);
+
+       return err;
+}
+
+
+static int mi0343_get_ctrl(struct sn9c102_device* cam, 
+                           struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x09, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               ctrl->value = mi0343_i2c_data[2];
+               return 0;
+       case V4L2_CID_GAIN:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x35, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_HFLIP:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x20, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
+               return 0;
+       case V4L2_CID_VFLIP:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x20, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x2d, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x2c, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
+                                            0x2e, 2+1, mi0343_i2c_data) < 0)
+                       return -EIO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+       case V4L2_CID_RED_BALANCE:
+       case V4L2_CID_BLUE_BALANCE:
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
+               if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
+                       ctrl->value -= 0x10;
+               else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
+                       ctrl->value -= 0x60;
+               else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
+                       ctrl->value -= 0xe0;
+       }
+
+       return 0;
+}
+
+
+static int mi0343_set_ctrl(struct sn9c102_device* cam, 
+                           const struct v4l2_control* ctrl)
+{
+       u16 reg = 0;
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+       case V4L2_CID_RED_BALANCE:
+       case V4L2_CID_BLUE_BALANCE:
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if (ctrl->value <= (0x3f-0x10))
+                       reg = 0x10 + ctrl->value;
+               else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
+                       reg = 0x60 + (ctrl->value - (0x3f-0x10));
+               else
+                       reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
+               break;
+       }
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x09, ctrl->value, 0x00,
+                                                0, 0);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x35, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       case V4L2_CID_HFLIP:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x20, ctrl->value ? 0x40:0x00,
+                                                ctrl->value ? 0x20:0x00,
+                                                0, 0);
+               break;
+       case V4L2_CID_VFLIP:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x20, ctrl->value ? 0x80:0x00,
+                                                ctrl->value ? 0x80:0x00,
+                                                0, 0);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2d, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2c, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2b, reg >> 8, reg & 0xff,
+                                                0, 0);
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x2e, reg >> 8, reg & 0xff,
+                                                0, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int mi0343_set_crop(struct sn9c102_device* cam, 
+                            const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &mi0343;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int mi0343_set_pix_format(struct sn9c102_device* cam, 
+                                 const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x0a, 0x00, 0x03, 0, 0);
+               err += sn9c102_write_reg(cam, 0x20, 0x19);
+       } else {
+               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
+                                                mi0343.i2c_slave_id,
+                                                0x0a, 0x00, 0x05, 0, 0);
+               err += sn9c102_write_reg(cam, 0xa0, 0x19);
+       }
+
+       return err;
+}
+
+
+static struct sn9c102_sensor mi0343 = {
+       .name = "MI-0343",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x5d,
+       .init = &mi0343_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x06,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_HFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "horizontal mirror",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical mirror",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &mi0343_get_ctrl,
+       .set_ctrl = &mi0343_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &mi0343_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &mi0343_set_pix_format
+};
+
+
+int sn9c102_probe_mi0343(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
+                                    2, mi0343_i2c_data) < 0)
+               return -EIO;
+
+       if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &mi0343);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
new file mode 100644 (file)
index 0000000..42852b7
--- /dev/null
@@ -0,0 +1,401 @@
+/***************************************************************************
+ * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor ov7630;
+
+
+static int ov7630_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x0f, 0x18);
+       err += sn9c102_write_reg(cam, 0x50, 0x19);
+
+       err += sn9c102_i2c_write(cam, 0x12, 0x80);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+       err += sn9c102_i2c_write(cam, 0x15, 0x34);
+       err += sn9c102_i2c_write(cam, 0x16, 0x03);
+       err += sn9c102_i2c_write(cam, 0x17, 0x1c);
+       err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+       err += sn9c102_i2c_write(cam, 0x19, 0x06);
+       err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+       err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+       err += sn9c102_i2c_write(cam, 0x20, 0xf6);
+       err += sn9c102_i2c_write(cam, 0x23, 0xee);
+       err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+       err += sn9c102_i2c_write(cam, 0x28, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x29, 0x30);
+       err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
+       err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
+       err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+       err += sn9c102_i2c_write(cam, 0x30, 0x24);
+       err += sn9c102_i2c_write(cam, 0x32, 0x86);
+       err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x61, 0x42);
+       err += sn9c102_i2c_write(cam, 0x65, 0x00);
+       err += sn9c102_i2c_write(cam, 0x69, 0x38);
+       err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+       err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+       err += sn9c102_i2c_write(cam, 0x71, 0x00);
+       err += sn9c102_i2c_write(cam, 0x74, 0x21);
+       err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+
+       return err;
+}
+
+
+static int ov7630_set_ctrl(struct sn9c102_device* cam,
+                           const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
+               err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+               break;
+       case V4L2_CID_CONTRAST:
+               err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
+                                                      (ctrl->value-1) | 0x20)
+                                  : sn9c102_i2c_write(cam, 0x05, 0x00);
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
+               break;
+       case V4L2_CID_SATURATION:
+               err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
+               break;
+       case V4L2_CID_HUE:
+               err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
+                                                      (ctrl->value-1) | 0x20)
+                                  : sn9c102_i2c_write(cam, 0x04, 0x00);
+               break;
+       case V4L2_CID_DO_WHITE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       case V4L2_CID_WHITENESS:
+               err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
+               break;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
+               break;
+       case V4L2_CID_AUTOGAIN:
+               err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
+               break;
+       case V4L2_CID_VFLIP:
+               err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
+               break;
+       case V4L2_CID_BLACK_LEVEL:
+               err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_BRIGHT_LEVEL:
+               err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GAMMA:
+               err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
+               break;
+       case SN9C102_V4L2_CID_BAND_FILTER:
+               err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int ov7630_set_crop(struct sn9c102_device* cam,
+                           const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &ov7630;
+       int err = 0;
+       u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int ov7630_set_pix_format(struct sn9c102_device* cam,
+                                 const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x20, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0x50, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor ov7630 = {
+       .name = "OV7630",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x21,
+       .init = &ov7630_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x14,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_HUE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "hue",
+                       .minimum = 0x00,
+                       .maximum = 0x1f+1,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_SATURATION,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "saturation",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x08,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_CONTRAST,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "contrast",
+                       .minimum = 0x00,
+                       .maximum = 0x1f+1,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x000,
+                       .maximum = 0x3ff,
+                       .step = 0x001,
+                       .default_value = 0x83<<2,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x3a,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x77,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BRIGHTNESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "brightness",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0xa0,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_DO_WHITE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "white balance background: blue",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_WHITENESS,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "white balance background: red",
+                       .minimum = 0x00,
+                       .maximum = 0x3f,
+                       .step = 0x01,
+                       .default_value = 0x20,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "auto white balance",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_AUTOGAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "gain & exposure mode",
+                       .minimum = 0x00,
+                       .maximum = 0x03,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical flip",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLACK_LEVEL,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "black pixel ratio",
+                       .minimum = 0x01,
+                       .maximum = 0x9a,
+                       .step = 0x01,
+                       .default_value = 0x8a,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "bright pixel ratio",
+                       .minimum = 0x01,
+                       .maximum = 0x9a,
+                       .step = 0x01,
+                       .default_value = 0x10,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_BAND_FILTER,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "band filter",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GAMMA,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "rgb gamma",
+                       .minimum = 0x00,
+                       .maximum = 0x01,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &ov7630_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &ov7630_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &ov7630_set_pix_format
+};
+
+
+int sn9c102_probe_ov7630(struct sn9c102_device* cam)
+{
+       const struct usb_device_id ov7630_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x602c), },
+               { USB_DEVICE(0x0c45, 0x602d), },
+               { USB_DEVICE(0x0c45, 0x608f), },
+               { USB_DEVICE(0x0c45, 0x60b0), },
+               { }
+       };
+       int err = 0;
+
+       if (!sn9c102_match_id(cam, ov7630_id_table))
+               return -ENODEV;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
+       if (err)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &ov7630);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c
new file mode 100644 (file)
index 0000000..b1dee78
--- /dev/null
@@ -0,0 +1,307 @@
+/***************************************************************************
+ * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas106b;
+
+
+static int pas106b_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x20, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x0c);
+       err += sn9c102_i2c_write(cam, 0x05, 0x5a);
+       err += sn9c102_i2c_write(cam, 0x06, 0x88);
+       err += sn9c102_i2c_write(cam, 0x07, 0x80);
+       err += sn9c102_i2c_write(cam, 0x10, 0x06);
+       err += sn9c102_i2c_write(cam, 0x11, 0x06);
+       err += sn9c102_i2c_write(cam, 0x12, 0x00);
+       err += sn9c102_i2c_write(cam, 0x14, 0x02);
+       err += sn9c102_i2c_write(cam, 0x13, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas106b_get_ctrl(struct sn9c102_device* cam, 
+                            struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x03),
+                           r2 = sn9c102_i2c_read(cam, 0x04);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 4) | (r2 & 0x0f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case V4L2_CID_CONTRAST:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x07;
+               return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
+                       return -EIO;
+               ctrl->value = (ctrl->value & 0x1f) << 1;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+                       return -EIO;
+               ctrl->value &= 0xf8;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas106b_set_ctrl(struct sn9c102_device* cam, 
+                            const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
+               break;
+       case V4L2_CID_CONTRAST:
+               err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
+               err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x13, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas106b_set_crop(struct sn9c102_device* cam, 
+                            const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas106b;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static int pas106b_set_pix_format(struct sn9c102_device* cam, 
+                                  const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x2c, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas106b = {
+       .name = "PAS106B",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas106b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x125,
+                       .maximum = 0xfff,
+                       .step = 0x001,
+                       .default_value = 0x140,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0d,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_CONTRAST,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "contrast",
+                       .minimum = 0x00,
+                       .maximum = 0x07,
+                       .step = 0x01,
+                       .default_value = 0x00, /* 0x00~0x03 have same effect */
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x06,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x3e,
+                       .step = 0x02,
+                       .default_value = 0x02,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &pas106b_get_ctrl,
+       .set_ctrl = &pas106b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+       },
+       .set_crop = &pas106b_set_crop,
+       .pix_format = {
+               .width = 352,
+               .height = 288,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8, /* we use this field as 'bits per pixel' */
+       },
+       .set_pix_format = &pas106b_set_pix_format
+};
+
+
+int sn9c102_probe_pas106b(struct sn9c102_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       /*
+          Minimal initialization to enable the I2C communication
+          NOTE: do NOT change the values!
+       */
+       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
+       err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
+       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
+
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x007)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas106b);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/drivers/media/video/sn9c102/sn9c102_pas202bca.c
new file mode 100644 (file)
index 0000000..3453237
--- /dev/null
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bca;
+
+
+static int pas202bca_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x30, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x14);
+       err += sn9c102_i2c_write(cam, 0x03, 0x40);
+       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x10, 0x08);
+       err += sn9c102_i2c_write(cam, 0x13, 0x63);
+       err += sn9c102_i2c_write(cam, 0x15, 0x70);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas202bca_set_pix_format(struct sn9c102_device* cam,
+                                    const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x24, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static int pas202bca_set_ctrl(struct sn9c102_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas202bca_set_crop(struct sn9c102_device* cam,
+                              const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas202bca;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas202bca = {
+       .name = "PAS202BCA",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas202bca_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &pas202bca_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &pas202bca_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &pas202bca_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
+{
+       const struct usb_device_id pas202bca_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x60af), },
+               { }
+       };
+       int err = 0;
+
+       if (!sn9c102_match_id(cam,pas202bca_id_table))
+               return -ENODEV;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x40, 0x01);
+       err += sn9c102_write_reg(cam, 0x28, 0x17);
+       if (err)
+               return -EIO;
+
+       if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas202bca);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
new file mode 100644 (file)
index 0000000..d068616
--- /dev/null
@@ -0,0 +1,293 @@
+/***************************************************************************
+ * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera   *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
+ *                       <medaglia@undl.org.br>                            *
+ *                       http://cadu.homelinux.com:8080/                   *
+ *                                                                         *
+ * DAC Magnitude, exposure and green gain controls added by                *
+ * Luca Risolia <luca.risolia@studio.unibo.it>                             *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x30, 0x19);
+       err += sn9c102_write_reg(cam, 0x09, 0x18);
+
+       err += sn9c102_i2c_write(cam, 0x02, 0x14);
+       err += sn9c102_i2c_write(cam, 0x03, 0x40);
+       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
+       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
+       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
+       err += sn9c102_i2c_write(cam, 0x10, 0x08);
+       err += sn9c102_i2c_write(cam, 0x13, 0x63);
+       err += sn9c102_i2c_write(cam, 0x15, 0x70);
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       msleep(400);
+
+       return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct sn9c102_device* cam, 
+                              struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = sn9c102_i2c_read(cam, 0x04),
+                           r2 = sn9c102_i2c_read(cam, 0x05);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
+                       return -EIO;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas202bcb_set_pix_format(struct sn9c102_device* cam, 
+                                    const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x24, 0x17);
+       else
+               err += sn9c102_write_reg(cam, 0x20, 0x17);
+
+       return err;
+}
+
+
+static int pas202bcb_set_ctrl(struct sn9c102_device* cam, 
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_GREEN_BALANCE:
+               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
+               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += sn9c102_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static int pas202bcb_set_crop(struct sn9c102_device* cam, 
+                              const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &pas202bcb;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor pas202bcb = {
+       .name = "PAS202BCB",
+       .maintainer = "Carlos Eduardo Medaglia Dyonisio "
+                     "<medaglia@undl.org.br>",
+       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_2WIRES,
+       .i2c_slave_id = 0x40,
+       .init = &pas202bcb_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x04,
+                       .flags = 0,
+               },
+       },
+       .get_ctrl = &pas202bcb_get_ctrl,
+       .set_ctrl = &pas202bcb_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &pas202bcb_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &pas202bcb_set_pix_format
+};
+
+
+int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       /*
+        *  Minimal initialization to enable the I2C communication
+        *  NOTE: do NOT change the values!
+        */
+       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
+       err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
+       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
+       if (err)
+               return -EIO;
+
+       r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
+       r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
+
+       if (r0 < 0 || r1 < 0)
+               return -EIO;
+
+       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x017)
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &pas202bcb);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
new file mode 100644 (file)
index 0000000..2afd9e9
--- /dev/null
@@ -0,0 +1,389 @@
+/***************************************************************************
+ * API for image sensors connected to the SN9C10x PC Camera Controllers    *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _SN9C102_SENSOR_H_
+#define _SN9C102_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct sn9c102_device;
+struct sn9c102_sensor;
+
+/*****************************************************************************/
+
+/*
+   OVERVIEW.
+   This is a small interface that allows you to add support for any CCD/CMOS
+   image sensors connected to the SN9C10X bridges. The entire API is documented
+   below. In the most general case, to support a sensor there are three steps
+   you have to follow:
+   1) define the main "sn9c102_sensor" structure by setting the basic fields;
+   2) write a probing function to be called by the core module when the USB
+      camera is recognized, then add both the USB ids and the name of that
+      function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
+      below);
+   3) implement the methods that you want/need (and fill the rest of the main
+      structure accordingly).
+   "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
+   NOT need to touch the source code of the core module for the things to work
+   properly, unless you find bugs or flaws in it. Finally, do not forget to
+   read the V4L2 API for completeness.
+*/
+
+/*****************************************************************************/
+
+/*
+   Probing functions: on success, you must attach the sensor to the camera
+   by calling sn9c102_attach_sensor() provided below.
+   To enable the I2C communication, you might need to perform a really basic
+   initialization of the SN9C10X chip by using the write function declared 
+   ahead.
+   Functions must return 0 on success, the appropriate error otherwise.
+*/
+extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
+extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
+extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
+
+/*
+   Add the above entries to this table. Be sure to add the entry in the right
+   place, since, on failure, the next probing routine is called according to 
+   the order of the list below, from top to bottom.
+*/
+#define SN9C102_SENSOR_TABLE                                                  \
+static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
+       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */     \
+       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
+       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
+       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
+       &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
+       &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
+       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
+       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
+       NULL,                                                                 \
+};
+
+/* Device identification */
+extern struct sn9c102_device*
+sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
+
+/* Attach a probed sensor to the camera. */
+extern void 
+sn9c102_attach_sensor(struct sn9c102_device* cam,
+                      struct sn9c102_sensor* sensor);
+
+/*
+   Each SN9C10x camera has proper PID/VID identifiers.
+   SN9C103 supports multiple interfaces, but we only handle the video class
+   interface.
+*/
+#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = (intclass)
+
+#define SN9C102_ID_TABLE                                                      \
+static const struct usb_device_id sn9c102_id_table[] = {                      \
+       { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
+       { USB_DEVICE(0x0c45, 0x6007), },                                      \
+       { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x6024), },                                      \
+       { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */      \
+       { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */                      \
+       { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */                        \
+       { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */                        \
+       { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
+       { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
+       { USB_DEVICE(0x0c45, 0x602d), },                                      \
+       { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
+       { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
+       { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
+       { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
+       { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
+       { }                                                                   \
+};
+
+/*****************************************************************************/
+
+/*
+   Read/write routines: they always return -1 on error, 0 or the read value
+   otherwise. NOTE that a real read operation is not supported by the SN9C10X
+   chip for some of its registers. To work around this problem, a pseudo-read
+   call is provided instead: it returns the last successfully written value 
+   on the register (0 if it has never been written), the usual -1 on error.
+*/
+
+/* The "try" I2C I/O versions are used when probing the sensor */
+extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*,
+                                 u8 address, u8 value);
+extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
+                                u8 address);
+
+/*
+   These must be used if and only if the sensor doesn't implement the standard
+   I2C protocol. There are a number of good reasons why you must use the 
+   single-byte versions of these functions: do not abuse. The first function
+   writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
+   chip. The second one programs the registers 0x09 and 0x10 with data0 and
+   data1, and places the n bytes read from the sensor register table in the
+   buffer pointed by 'buffer'. Both the functions return -1 on error; the write
+   version returns 0 on success, while the read version returns the first read
+   byte.
+*/
+extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
+                                     struct sn9c102_sensor* sensor, u8 n, 
+                                     u8 data0, u8 data1, u8 data2, u8 data3,
+                                     u8 data4, u8 data5);
+extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
+                                    struct sn9c102_sensor* sensor, u8 data0,
+                                    u8 data1, u8 n, u8 buffer[]);
+
+/* To be used after the sensor struct has been attached to the camera struct */
+extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
+extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
+
+/* I/O on registers in the bridge. Could be used by the sensor methods too */
+extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
+extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
+extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
+
+/*
+   NOTE: there are no exported debugging functions. To uniform the output you
+   must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
+   already included here, the argument being the struct device '&usbdev->dev'
+   of the sensor structure. Do NOT use these macros before the sensor is
+   attached or the kernel will crash! However, you should not need to notify
+   the user about common errors or other messages, since this is done by the
+   master module.
+*/
+
+/*****************************************************************************/
+
+enum sn9c102_i2c_sysfs_ops {
+       SN9C102_I2C_READ = 0x01,
+       SN9C102_I2C_WRITE = 0x02,
+};
+
+enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */
+       SN9C102_I2C_100KHZ = 0x01,
+       SN9C102_I2C_400KHZ = 0x02,
+};
+
+enum sn9c102_i2c_interface {
+       SN9C102_I2C_2WIRES,
+       SN9C102_I2C_3WIRES,
+};
+
+#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+
+struct sn9c102_sensor {
+       char name[32], /* sensor name */
+            maintainer[64]; /* name of the mantainer <email> */
+
+       /* Supported operations through the 'sysfs' interface */
+       enum sn9c102_i2c_sysfs_ops sysfs_ops;
+
+       /*
+          These sensor capabilities must be provided if the SN9C10X controller
+          needs to communicate through the sensor serial interface by using
+          at least one of the i2c functions available.
+       */
+       enum sn9c102_i2c_frequency frequency;
+       enum sn9c102_i2c_interface interface;
+
+       /*
+          This identifier must be provided if the image sensor implements
+          the standard I2C protocol.
+       */
+       u8 i2c_slave_id; /* reg. 0x09 */
+
+       /*
+          NOTE: Where not noted,most of the functions below are not mandatory.
+                Set to null if you do not implement them. If implemented,
+                they must return 0 on success, the proper error otherwise.
+       */
+
+       int (*init)(struct sn9c102_device* cam);
+       /*
+          This function will be called after the sensor has been attached. 
+          It should be used to initialize the sensor only, but may also
+          configure part of the SN9C10X chip if necessary. You don't need to
+          setup picture settings like brightness, contrast, etc.. here, if
+          the corrisponding controls are implemented (see below), since 
+          they are adjusted in the core driver by calling the set_ctrl()
+          method after init(), where the arguments are the default values
+          specified in the v4l2_queryctrl list of supported controls;
+          Same suggestions apply for other settings, _if_ the corresponding
+          methods are present; if not, the initialization must configure the
+          sensor according to the default configuration structures below.
+       */
+
+       struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
+       /*
+          Optional list of default controls, defined as indicated in the 
+          V4L2 API. Menu type controls are not handled by this interface.
+       */
+
+       int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct sn9c102_device* cam,
+                       const struct v4l2_control* ctrl);
+       /*
+          You must implement at least the set_ctrl method if you have defined
+          the list above. The returned value must follow the V4L2
+          specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
+          are not supported by this driver, so do not implement them. Also,
+          you don't have to check whether the passed values are out of bounds,
+          given that this is done by the core module.
+       */
+
+       struct v4l2_cropcap cropcap;
+       /*
+          Think the image sensor as a grid of R,G,B monochromatic pixels
+          disposed according to a particular Bayer pattern, which describes
+          the complete array of pixels, from (0,0) to (xmax, ymax). We will
+          use this coordinate system from now on. It is assumed the sensor
+          chip can be programmed to capture/transmit a subsection of that
+          array of pixels: we will call this subsection "active window".
+          It is not always true that the largest achievable active window can
+          cover the whole array of pixels. The V4L2 API defines another
+          area called "source rectangle", which, in turn, is a subrectangle of
+          the active window. The SN9C10X chip is always programmed to read the
+          source rectangle.
+          The bounds of both the active window and the source rectangle are
+          specified in the cropcap substructures 'bounds' and 'defrect'.
+          By default, the source rectangle should cover the largest possible
+          area. Again, it is not always true that the largest source rectangle
+          can cover the entire active window, although it is a rare case for 
+          the hardware we have. The bounds of the source rectangle _must_ be
+          multiple of 16 and must use the same coordinate system as indicated
+          before; their centers shall align initially.
+          If necessary, the sensor chip must be initialized during init() to
+          set the bounds of the active sensor window; however, by default, it
+          usually covers the largest achievable area (maxwidth x maxheight)
+          of pixels, so no particular initialization is needed, if you have
+          defined the correct default bounds in the structures.
+          See the V4L2 API for further details.
+          NOTE: once you have defined the bounds of the active window
+                (struct cropcap.bounds) you must not change them.anymore.
+          Only 'bounds' and 'defrect' fields are mandatory, other fields
+          will be ignored.
+       */
+
+       int (*set_crop)(struct sn9c102_device* cam,
+                       const struct v4l2_rect* rect);
+       /*
+          To be called on VIDIOC_C_SETCROP. The core module always calls a
+          default routine which configures the appropriate SN9C10X regs (also
+          scaling), but you may need to override/adjust specific stuff.
+          'rect' contains width and height values that are multiple of 16: in
+          case you override the default function, you always have to program
+          the chip to match those values; on error return the corresponding
+          error code without rolling back.
+          NOTE: in case, you must program the SN9C10X chip to get rid of 
+                blank pixels or blank lines at the _start_ of each line or
+                frame after each HSYNC or VSYNC, so that the image starts with
+                real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
+                V_SIZE you don't have to care about blank pixels or blank
+                lines at the end of each line or frame).
+       */
+
+       struct v4l2_pix_format pix_format;
+       /*
+          What you have to define here are: 1) initial 'width' and 'height' of
+          the target rectangle 2) the initial 'pixelformat', which can be
+          either V4L2_PIX_FMT_SN9C10X (for compressed video) or
+          V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
+          number of bits per pixel for uncompressed video, 8 or 9 (despite the
+          current value of 'pixelformat').
+          NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
+                  of cropcap.defrect.width and cropcap.defrect.height. I
+                  suggest 1/1.
+          NOTE 2: The initial compression quality is defined by the first bit
+                  of reg 0x17 during the initialization of the image sensor.
+          NOTE 3: as said above, you have to program the SN9C10X chip to get
+                  rid of any blank pixels, so that the output of the sensor
+                  matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
+       */
+
+       int (*set_pix_format)(struct sn9c102_device* cam,
+                             const struct v4l2_pix_format* pix);
+       /*
+          To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
+          SN9C10X pixel format or viceversa. On error return the corresponding
+          error code without rolling back.
+       */
+
+       /*
+          Do NOT write to the data below, it's READ ONLY. It is used by the
+          core module to store successfully updated values of the above
+          settings, for rollbacks..etc..in case of errors during atomic I/O
+       */
+       struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+/*****************************************************************************/
+
+/* Private ioctl's for control settings supported by some image sensors */
+#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
+#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
+#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
+#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
+#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
+
+#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c
new file mode 100644 (file)
index 0000000..2e08c55
--- /dev/null
@@ -0,0 +1,159 @@
+/***************************************************************************
+ * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor tas5110c1b;
+
+
+static int tas5110c1b_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x44, 0x01);
+       err += sn9c102_write_reg(cam, 0x00, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x0a, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x06, 0x18);
+       err += sn9c102_write_reg(cam, 0xfb, 0x19);
+
+       err += sn9c102_i2c_write(cam, 0xc0, 0x80);
+
+       return err;
+}
+
+
+static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, 
+                               const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int tas5110c1b_set_crop(struct sn9c102_device* cam, 
+                               const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &tas5110c1b;
+       int err = 0;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       /* Don't change ! */
+       err += sn9c102_write_reg(cam, 0x14, 0x1a);
+       err += sn9c102_write_reg(cam, 0x0a, 0x1b);
+       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
+
+       return err;
+}
+
+
+static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, 
+                                     const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x2b, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0xfb, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor tas5110c1b = {
+       .name = "TAS5110C1B",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_3WIRES,
+       .init = &tas5110c1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x01,
+                       .default_value = 0x40,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5110c1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 352,
+                       .height = 288,
+               },
+       },
+       .set_crop = &tas5110c1b_set_crop,
+       .pix_format = {
+               .width = 352,
+               .height = 288,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &tas5110c1b_set_pix_format
+};
+
+
+int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
+{
+       const struct usb_device_id tas5110c1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6001), },
+               { USB_DEVICE(0x0c45, 0x6005), },
+               { USB_DEVICE(0x0c45, 0x60ab), },
+               { }
+       };
+
+       /* Sensor detection is based on USB pid/vid */
+       if (!sn9c102_match_id(cam, tas5110c1b_id_table))
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &tas5110c1b);
+
+       return 0;
+}
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c
new file mode 100644 (file)
index 0000000..c7b3397
--- /dev/null
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor tas5130d1b;
+
+
+static int tas5130d1b_init(struct sn9c102_device* cam)
+{
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, 0x01, 0x01);
+       err += sn9c102_write_reg(cam, 0x20, 0x17);
+       err += sn9c102_write_reg(cam, 0x04, 0x01);
+       err += sn9c102_write_reg(cam, 0x01, 0x10);
+       err += sn9c102_write_reg(cam, 0x00, 0x11);
+       err += sn9c102_write_reg(cam, 0x00, 0x14);
+       err += sn9c102_write_reg(cam, 0x60, 0x17);
+       err += sn9c102_write_reg(cam, 0x07, 0x18);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, 
+                               const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_GAIN:
+               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err ? -EIO : 0;
+}
+
+
+static int tas5130d1b_set_crop(struct sn9c102_device* cam, 
+                               const struct v4l2_rect* rect)
+{
+       struct sn9c102_sensor* s = &tas5130d1b;
+       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
+          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
+       int err = 0;
+
+       err += sn9c102_write_reg(cam, h_start, 0x12);
+       err += sn9c102_write_reg(cam, v_start, 0x13);
+
+       /* Do NOT change! */
+       err += sn9c102_write_reg(cam, 0x1f, 0x1a);
+       err += sn9c102_write_reg(cam, 0x1a, 0x1b);
+       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
+
+       return err;
+}
+
+
+static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, 
+                                     const struct v4l2_pix_format* pix)
+{
+       int err = 0;
+
+       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+               err += sn9c102_write_reg(cam, 0x63, 0x19);
+       else
+               err += sn9c102_write_reg(cam, 0xf3, 0x19);
+
+       return err;
+}
+
+
+static struct sn9c102_sensor tas5130d1b = {
+       .name = "TAS5130D1B",
+       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+       .sysfs_ops = SN9C102_I2C_WRITE,
+       .frequency = SN9C102_I2C_100KHZ,
+       .interface = SN9C102_I2C_3WIRES,
+       .init = &tas5130d1b_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0xf6,
+                       .step = 0x02,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x00,
+                       .maximum = 0x47,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = 0,
+               },
+       },
+       .set_ctrl = &tas5130d1b_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .set_crop = &tas5130d1b_set_crop,
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_SBGGR8,
+               .priv = 8,
+       },
+       .set_pix_format = &tas5130d1b_set_pix_format
+};
+
+
+int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
+{
+       const struct usb_device_id tas5130d1b_id_table[] = {
+               { USB_DEVICE(0x0c45, 0x6025), },
+               { USB_DEVICE(0x0c45, 0x60aa), },
+               { }
+       };
+
+       /* Sensor detection is based on USB pid/vid */
+       if (!sn9c102_match_id(cam, tas5130d1b_id_table))
+               return -ENODEV;
+
+       sn9c102_attach_sensor(cam, &tas5130d1b);
+
+       return 0;
+}
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
new file mode 100644 (file)
index 0000000..9636da2
--- /dev/null
@@ -0,0 +1,1508 @@
+/*
+ *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
+ *  
+ * Thanks to STMicroelectronics for information on the usb commands, and 
+ * to Steve Miller at STM for his help and encouragement while I was 
+ * writing this driver.
+ *
+ * This driver is based heavily on the 
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History: 
+ * ver 0.1 October, 2001. Initial attempt. 
+ *
+ * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
+ *                         function, made more stable (?)
+ *
+ * ver 0.21 Nov, 2001.     Added gamma correction and white balance, 
+ *                         due to Alexander Schwartz. Still trying to 
+ *                         improve stablility. Moved stuff into stv680.h
+ *
+ * ver 0.22 Nov, 2001.    Added sharpen function (by Michael Sweet, 
+ *                         mike@easysw.com) from GIMP, also used in pencam. 
+ *                         Simple, fast, good integer math routine.
+ *
+ * ver 0.23 Dec, 2001 (gkh)
+ *                        Took out sharpen function, ran code through
+ *                        Lindent, and did other minor tweaks to get
+ *                        things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
+ *
+ * ver 0.25 Jan, 2002 (kjs)
+ *                        Fixed a bug in which the driver sometimes attempted
+ *                        to set to a non-supported size. This allowed
+ *                        gnomemeeting to work.
+ *                        Fixed proc entry removal bug.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/errno.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+#include "stv680.h"
+
+static int video_nr = -1;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
+
+static unsigned int debug = 0;
+
+#define PDEBUG(level, fmt, args...) \
+       do { \
+       if (debug >= level)     \
+               info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \
+       } while (0)
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.25"
+#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
+#define DRIVER_DESC "STV0680 USB Camera Driver"
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE ("GPL");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC (debug, "Debug enabled or not");
+module_param(swapRGB_on, int, 0);
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
+module_param(video_nr, int, 0);
+
+/********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ *
+ * And the STV0680 driver - Kevin
+ ********************************************************************/
+static void *rvmalloc (unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32 (size);
+       if (!mem)
+               return NULL;
+
+       memset (mem, 0, size);  /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       return mem;
+}
+
+static void rvfree (void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree (mem);
+}
+
+
+/*********************************************************************
+ * pencam read/write functions
+ ********************************************************************/
+
+static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
+{
+       int ret = -1;
+
+       switch (set) {
+       case 0:         /*  0xc1  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_rcvctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       case 1:         /*  0x41  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_sndctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       case 2:         /*  0x80  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_rcvctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_IN | USB_RECIP_DEVICE),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       case 3:         /*  0x40  */
+               ret = usb_control_msg (stv680->udev,
+                                      usb_sndctrlpipe (stv680->udev, 0),
+                                      req,
+                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
+                                      value, 0, buffer, size, PENCAM_TIMEOUT);
+               break;
+
+       }
+       if ((ret < 0) && (req != 0x0a)) {
+               PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
+       }
+       return ret;
+}
+
+static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
+{
+
+       if (configuration != dev->udev->actconfig->desc.bConfigurationValue
+                       || usb_reset_configuration (dev->udev) < 0) {
+               PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
+               return -1;
+       }
+       if (usb_set_interface (dev->udev, interface, alternate) < 0) {
+               PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
+               return -1;
+       }
+       return 0;
+}
+
+static int stv_stop_video (struct usb_stv *dev)
+{
+       int i;
+       unsigned char *buf;
+
+       buf = kmalloc (40, GFP_KERNEL);
+       if (buf == NULL) {
+               PDEBUG (0, "STV(e): Out of (small buf) memory");
+               return -1;
+       }
+
+       /* this is a high priority command; it stops all lower order commands */
+       if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
+               i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);   /* Get Last Error; 2 = busy */
+               PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
+       } else {
+               PDEBUG (1, "STV(i): Camera reset to idle mode.");
+       }
+
+       if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
+               PDEBUG (1, "STV(e): Reset config during exit failed");
+
+       /*  get current mode  */
+       buf[0] = 0xf0;
+       if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)     /* get mode */
+               PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
+       if (dev->origMode != buf[0]) {
+               memset (buf, 0, 8);
+               buf[0] = (unsigned char) dev->origMode;
+               if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
+                       PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
+                       i = -1;
+               }
+               buf[0] = 0xf0;
+               i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
+               if ((i != 0x08) || (buf[0] != dev->origMode)) {
+                       PDEBUG (0, "STV(e): camera NOT set to original resolution.");
+                       i = -1;
+               } else
+                       PDEBUG (0, "STV(i): Camera set to original resolution");
+       }
+       /* origMode */
+       kfree(buf);
+       return i;
+}
+
+static int stv_set_video_mode (struct usb_stv *dev)
+{
+       int i, stop_video = 1;
+       unsigned char *buf;
+
+       buf = kmalloc (40, GFP_KERNEL);
+       if (buf == NULL) {
+               PDEBUG (0, "STV(e): Out of (small buf) memory");
+               return -1;
+       }
+
+       if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
+               kfree(buf);
+               return i;
+       }
+
+       i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
+       if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
+               PDEBUG (1, "STV(e): Could not get descriptor 0100.");
+               goto error;
+       }
+
+       /*  set alternate interface 1 */
+       if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
+               goto error;
+
+       if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
+               goto error;
+       PDEBUG (1, "STV(i): Setting video mode.");
+       /*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
+       if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
+               stop_video = 0;
+               goto error;
+       }
+       goto exit;
+
+error:
+       kfree(buf);
+       if (stop_video == 1)
+               stv_stop_video (dev);
+       return -1;
+
+exit:
+       kfree(buf);
+       return 0;
+}
+
+static int stv_init (struct usb_stv *stv680)
+{
+       int i = 0;
+       unsigned char *buffer;
+       unsigned long int bufsize;
+
+       buffer = kzalloc (40, GFP_KERNEL);
+       if (buffer == NULL) {
+               PDEBUG (0, "STV(e): Out of (small buf) memory");
+               return -1;
+       }
+       udelay (100);
+
+       /* set config 1, interface 0, alternate 0 */
+       if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
+               kfree(buffer);
+               PDEBUG (0, "STV(e): set config 1,0,0 failed");
+               return -1;
+       }
+       /* ping camera to be sure STV0680 is present */
+       if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
+               goto error;
+       if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
+               PDEBUG (1, "STV(e): camera ping failed!!");
+               goto error;
+       }
+
+       /* get camera descriptor */
+       if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
+               goto error;
+       i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
+       if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
+               PDEBUG (1, "STV(e): Could not get descriptor 0200.");
+               goto error;
+       }
+       if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
+               goto error;
+       if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
+               goto error;
+       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+               goto error;
+
+       stv680->SupportedModes = buffer[7];
+       i = stv680->SupportedModes;
+       stv680->CIF = 0;
+       stv680->VGA = 0;
+       stv680->QVGA = 0;
+       if (i & 1)
+               stv680->CIF = 1;
+       if (i & 2)
+               stv680->VGA = 1;
+       if (i & 8)
+               stv680->QVGA = 1;
+       if (stv680->SupportedModes == 0) {
+               PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
+               i = -1;
+               goto error;
+       } else {
+               if (stv680->CIF)
+                       PDEBUG (0, "STV(i): CIF is supported");
+               if (stv680->QVGA)
+                       PDEBUG (0, "STV(i): QVGA is supported");
+       }
+       /* FW rev, ASIC rev, sensor ID  */
+       PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
+       PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
+       PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
+
+       /*  set alternate interface 1 */
+       if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
+               goto error;
+
+       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
+               goto error;
+       if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
+               goto error;
+       i = buffer[3];
+       PDEBUG (0, "STV(i): Camera has %i pictures.", i);
+
+       /*  get current mode */
+       if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
+               goto error;
+       stv680->origMode = buffer[0];   /* 01 = VGA, 03 = QVGA, 00 = CIF */
+
+       /* This will attemp CIF mode, if supported. If not, set to QVGA  */
+       memset (buffer, 0, 8);
+       if (stv680->CIF)
+               buffer[0] = 0x00;
+       else if (stv680->QVGA)
+               buffer[0] = 0x03;
+       if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
+               PDEBUG (0, "STV(i): Set_Camera_Mode failed");
+               i = -1;
+               goto error;
+       }
+       buffer[0] = 0xf0;
+       stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
+       if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
+               PDEBUG (0, "STV(e): Error setting camera video mode!");
+               i = -1;
+               goto error;
+       } else {
+               if (buffer[0] == 0) {
+                       stv680->VideoMode = 0x0000;
+                       PDEBUG (0, "STV(i): Video Mode set to CIF");
+               }
+               if (buffer[0] == 0x03) {
+                       stv680->VideoMode = 0x0300;
+                       PDEBUG (0, "STV(i): Video Mode set to QVGA");
+               }
+       }
+       if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
+               goto error;
+       bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
+       stv680->cwidth = (buffer[4] << 8) | (buffer[5]);        /* ->camera = 322, 356, 644  */
+       stv680->cheight = (buffer[6] << 8) | (buffer[7]);       /* ->camera = 242, 292, 484  */
+       stv680->origGain = buffer[12];
+
+       goto exit;
+
+error:
+       i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);     /* Get Last Error */
+       PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
+       kfree(buffer);
+       return -1;
+
+exit:
+       kfree(buffer);
+
+       /* video = 320x240, 352x288 */
+       if (stv680->CIF == 1) {
+               stv680->maxwidth = 352;
+               stv680->maxheight = 288;
+               stv680->vwidth = 352;
+               stv680->vheight = 288;
+       }
+       if (stv680->QVGA == 1) {
+               stv680->maxwidth = 320;
+               stv680->maxheight = 240;
+               stv680->vwidth = 320;
+               stv680->vheight = 240;
+       }
+
+       stv680->rawbufsize = bufsize;   /* must be ./. by 8 */
+       stv680->maxframesize = bufsize * 3;     /* RGB size */
+       PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
+       PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
+
+       /* some default values */
+       stv680->bulk_in_endpointAddr = 0x82;
+       stv680->dropped = 0;
+       stv680->error = 0;
+       stv680->framecount = 0;
+       stv680->readcount = 0;
+       stv680->streaming = 0;
+       /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
+       stv680->brightness = 32767;
+       stv680->chgbright = 0;
+       stv680->whiteness = 0;  /* only for greyscale */
+       stv680->colour = 32767;
+       stv680->contrast = 32767;
+       stv680->hue = 32767;
+       stv680->palette = STV_VIDEO_PALETTE;
+       stv680->depth = 24;     /* rgb24 bits */
+       if ((swapRGB_on == 0) && (swapRGB == 0))
+               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+       else if ((swapRGB_on == 0) && (swapRGB == 1))
+               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+       else if (swapRGB_on == 1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+       else if (swapRGB_on == -1)
+               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+       
+       if (stv_set_video_mode (stv680) < 0) {
+               PDEBUG (0, "STV(e): Could not set video mode in stv_init");
+               return -1;
+       }
+
+       return 0;
+}
+
+/***************** last of pencam  routines  *******************/
+
+/****************************************************************************
+ *  sysfs
+ ***************************************************************************/
+#define stv680_file(name, variable, field)                             \
+static ssize_t show_##name(struct class_device *class_dev, char *buf)  \
+{                                                                      \
+       struct video_device *vdev = to_video_device(class_dev);         \
+       struct usb_stv *stv = video_get_drvdata(vdev);                  \
+       return sprintf(buf, field, stv->variable);                      \
+}                                                                      \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+stv680_file(model, camera_name, "%s\n");
+stv680_file(in_use, user, "%d\n");
+stv680_file(streaming, streaming, "%d\n");
+stv680_file(palette, palette, "%i\n");
+stv680_file(frames_total, readcount, "%d\n");
+stv680_file(frames_read, framecount, "%d\n");
+stv680_file(packets_dropped, dropped, "%d\n");
+stv680_file(decoding_errors, error, "%d\n");
+
+static void stv680_create_sysfs_files(struct video_device *vdev)
+{
+       video_device_create_file(vdev, &class_device_attr_model);
+       video_device_create_file(vdev, &class_device_attr_in_use);
+       video_device_create_file(vdev, &class_device_attr_streaming);
+       video_device_create_file(vdev, &class_device_attr_palette);
+       video_device_create_file(vdev, &class_device_attr_frames_total);
+       video_device_create_file(vdev, &class_device_attr_frames_read);
+       video_device_create_file(vdev, &class_device_attr_packets_dropped);
+       video_device_create_file(vdev, &class_device_attr_decoding_errors);
+}
+
+static void stv680_remove_sysfs_files(struct video_device *vdev)
+{
+       video_device_remove_file(vdev, &class_device_attr_model);
+       video_device_remove_file(vdev, &class_device_attr_in_use);
+       video_device_remove_file(vdev, &class_device_attr_streaming);
+       video_device_remove_file(vdev, &class_device_attr_palette);
+       video_device_remove_file(vdev, &class_device_attr_frames_total);
+       video_device_remove_file(vdev, &class_device_attr_frames_read);
+       video_device_remove_file(vdev, &class_device_attr_packets_dropped);
+       video_device_remove_file(vdev, &class_device_attr_decoding_errors);
+}
+
+/********************************************************************
+ * Camera control
+ *******************************************************************/
+
+static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+       /* This sets values for v4l interface. max/min = 65535/0  */
+
+       p->brightness = stv680->brightness;
+       p->whiteness = stv680->whiteness;       /* greyscale */
+       p->colour = stv680->colour;
+       p->contrast = stv680->contrast;
+       p->hue = stv680->hue;
+       p->palette = stv680->palette;
+       p->depth = stv680->depth;
+       return 0;
+}
+
+static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
+{
+       /* See above stv680_get_pict  */
+
+       if (p->palette != STV_VIDEO_PALETTE) {
+               PDEBUG (2, "STV(e): Palette set error in _set_pic");
+               return 1;
+       }
+
+       if (stv680->brightness != p->brightness) {
+               stv680->chgbright = 1;
+               stv680->brightness = p->brightness;
+       } 
+
+       stv680->whiteness = p->whiteness;       /* greyscale */
+       stv680->colour = p->colour;
+       stv680->contrast = p->contrast;
+       stv680->hue = p->hue;
+       stv680->palette = p->palette;
+       stv680->depth = p->depth;
+
+       return 0;
+}
+
+static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
+{
+       struct usb_stv *stv680 = urb->context;
+       int length = urb->actual_length;
+
+       if (length < stv680->rawbufsize)
+               PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
+
+       /* ohoh... */
+       if (!stv680->streaming)
+               return;
+
+       if (!stv680->udev) {
+               PDEBUG (0, "STV(e): device vapourished in video_irq");
+               return;
+       }
+
+       /* 0 sized packets happen if we are to fast, but sometimes the camera
+          keeps sending them forever...
+        */
+       if (length && !urb->status) {
+               stv680->nullpackets = 0;
+               switch (stv680->scratch[stv680->scratch_next].state) {
+               case BUFFER_READY:
+               case BUFFER_BUSY:
+                       stv680->dropped++;
+                       break;
+
+               case BUFFER_UNUSED:
+                       memcpy (stv680->scratch[stv680->scratch_next].data,
+                               (unsigned char *) urb->transfer_buffer, length);
+                       stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
+                       stv680->scratch[stv680->scratch_next].length = length;
+                       if (waitqueue_active (&stv680->wq)) {
+                               wake_up_interruptible (&stv680->wq);
+                       }
+                       stv680->scratch_overflow = 0;
+                       stv680->scratch_next++;
+                       if (stv680->scratch_next >= STV680_NUMSCRATCH)
+                               stv680->scratch_next = 0;
+                       break;
+               }               /* switch  */
+       } else {
+               stv680->nullpackets++;
+               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+                       if (waitqueue_active (&stv680->wq)) {
+                               wake_up_interruptible (&stv680->wq);
+                       }
+               }
+       }                       /*  if - else */
+
+       /* Resubmit urb for new data */
+       urb->status = 0;
+       urb->dev = stv680->udev;
+       if (usb_submit_urb (urb, GFP_ATOMIC))
+               PDEBUG (0, "STV(e): urb burned down in video irq");
+       return;
+}                              /*  _video_irq  */
+
+static int stv680_start_stream (struct usb_stv *stv680)
+{
+       struct urb *urb;
+       int err = 0, i;
+
+       stv680->streaming = 1;
+
+       /* Do some memory allocation */
+       for (i = 0; i < STV680_NUMFRAMES; i++) {
+               stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
+               stv680->frame[i].curpix = 0;
+       }
+       /* packet size = 4096  */
+       for (i = 0; i < STV680_NUMSBUF; i++) {
+               stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+               if (stv680->sbuf[i].data == NULL) {
+                       PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
+                       return -1;
+               }
+       }
+
+       stv680->scratch_next = 0;
+       stv680->scratch_use = 0;
+       stv680->scratch_overflow = 0;
+       for (i = 0; i < STV680_NUMSCRATCH; i++) {
+               stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
+               if (stv680->scratch[i].data == NULL) {
+                       PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
+                       return -1;
+               }
+               stv680->scratch[i].state = BUFFER_UNUSED;
+       }
+
+       for (i = 0; i < STV680_NUMSBUF; i++) {
+               urb = usb_alloc_urb (0, GFP_KERNEL);
+               if (!urb)
+                       return -ENOMEM;
+
+               /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
+               usb_fill_bulk_urb (urb, stv680->udev,
+                                  usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
+                                  stv680->sbuf[i].data, stv680->rawbufsize,
+                                  stv680_video_irq, stv680);
+               stv680->urb[i] = urb;
+               err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
+               if (err)
+                       PDEBUG (0, "STV(e): urb burned down in start stream");
+       }                       /* i STV680_NUMSBUF */
+
+       stv680->framecount = 0;
+       return 0;
+}
+
+static int stv680_stop_stream (struct usb_stv *stv680)
+{
+       int i;
+
+       if (!stv680->streaming || !stv680->udev)
+               return 1;
+
+       stv680->streaming = 0;
+
+       for (i = 0; i < STV680_NUMSBUF; i++)
+               if (stv680->urb[i]) {
+                       usb_kill_urb (stv680->urb[i]);
+                       usb_free_urb (stv680->urb[i]);
+                       stv680->urb[i] = NULL;
+                       kfree(stv680->sbuf[i].data);
+               }
+       for (i = 0; i < STV680_NUMSCRATCH; i++) {
+               kfree(stv680->scratch[i].data);
+               stv680->scratch[i].data = NULL;
+       }
+
+       return 0;
+}
+
+static int stv680_set_size (struct usb_stv *stv680, int width, int height)
+{
+       int wasstreaming = stv680->streaming;
+
+       /* Check to see if we need to change */
+       if ((stv680->vwidth == width) && (stv680->vheight == height))
+               return 0;
+
+       PDEBUG (1, "STV(i): size request for %i x %i", width, height);
+       /* Check for a valid mode */
+       if ((!width || !height) || ((width & 1) || (height & 1))) {
+               PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+               return 1;
+       }
+
+       if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
+               width = stv680->maxwidth / 2;
+               height = stv680->maxheight / 2;
+       } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
+               width = 160;
+               height = 120;
+       } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
+               width = 176;
+               height = 144;
+       } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
+               width = 320;
+               height = 240;
+       } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
+               width = 352;
+               height = 288;
+       } else {
+               PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
+               return 1;
+       }
+       
+       /* Stop a current stream and start it again at the new size */
+       if (wasstreaming)
+               stv680_stop_stream (stv680);
+       stv680->vwidth = width;
+       stv680->vheight = height;
+       PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
+       if (wasstreaming)
+               stv680_start_stream (stv680);
+
+       return 0;
+}
+
+/**********************************************************************
+ * Video Decoding
+ **********************************************************************/
+
+/*******  routines from the pencam program; hey, they work!  ********/
+
+/*
+ * STV0680 Vision Camera Chipset Driver
+ * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
+*/
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define AD(x, y, w) (((y)*(w)+(x))*3)
+
+static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
+{
+       int x, y, i;
+       int w = stv680->cwidth;
+       int vw = stv680->cwidth, vh = stv680->cheight;
+       unsigned int p = 0;
+       int colour = 0, bayer = 0;
+       unsigned char *raw = buffer->data;
+       struct stv680_frame *frame = &stv680->frame[stv680->curframe];
+       unsigned char *output = frame->data;
+       unsigned char *temp = frame->data;
+       int offset = buffer->offset;
+
+       if (frame->curpix == 0) {
+               if (frame->grabstate == FRAME_READY) {
+                       frame->grabstate = FRAME_GRABBING;
+               }
+       }
+       if (offset != frame->curpix) {  /* Regard frame as lost :( */
+               frame->curpix = 0;
+               stv680->error++;
+               return;
+       }
+
+       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
+               vw = 320;
+               vh = 240;
+       }
+       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
+               vw = 352;
+               vh = 288;
+       }
+
+       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
+
+       for (y = 0; y < vh; y++) {
+               for (x = 0; x < vw; x++) {
+                       if (x & 1)
+                               p = *(raw + y * w + (x >> 1));
+                       else
+                               p = *(raw + y * w + (x >> 1) + (w >> 1));
+
+                       if (y & 1)
+                               bayer = 2;
+                       else
+                               bayer = 0;
+                       if (x & 1)
+                               bayer++;
+
+                       switch (bayer) {
+                       case 0:
+                       case 3:
+                               colour = 1;
+                               break;
+                       case 1:
+                               colour = 0;
+                               break;
+                       case 2:
+                               colour = 2;
+                               break;
+                       }
+                       i = (y * vw + x) * 3;   
+                       *(output + i + colour) = (unsigned char) p;
+               }               /* for x */
+
+       }                       /* for y */
+
+       /****** gamma correction plus hardcoded white balance */
+       /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
+          Correction values red[], green[], blue[], are generated by 
+          (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
+          White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
+          converted to unsigned char. Values are in stv680.h  */
+
+       for (y = 0; y < vh; y++) {
+               for (x = 0; x < vw; x++) {
+                       i = (y * vw + x) * 3;
+                       *(output + i) = red[*(output + i)];
+                       *(output + i + 1) = green[*(output + i + 1)];
+                       *(output + i + 2) = blue[*(output + i + 2)];
+               }
+       }
+
+       /******  bayer demosaic  ******/
+       for (y = 1; y < (vh - 1); y++) {
+               for (x = 1; x < (vw - 1); x++) {        /* work out pixel type */
+                       if (y & 1)
+                               bayer = 0;
+                       else
+                               bayer = 2;
+                       if (!(x & 1))
+                               bayer++;
+
+                       switch (bayer) {
+                       case 0: /* green. blue lr, red tb */
+                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
+                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
+                               break;
+
+                       case 1: /* blue. green lrtb, red diagonals */
+                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
+                               break;
+
+                       case 2: /* red. green lrtb, blue diagonals */
+                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
+                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
+                               break;
+
+                       case 3: /* green. red lr, blue tb */
+                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
+                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
+                               break;
+                       }       /* switch */
+               }               /* for x */
+       }                       /* for y  - end demosaic  */
+
+       /* fix top and bottom row, left and right side */
+       i = vw * 3;
+       memcpy (output, (output + i), i);
+       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+       for (y = 0; y < vh; y++) {
+               i = y * vw * 3;
+               memcpy ((output + i), (output + i + 3), 3);
+               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+       }
+
+       /*  process all raw data, then trim to size if necessary */
+       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+               i = 0;
+               for (y = 0; y < vh; y++) {
+                       if (!(y & 1)) {
+                               for (x = 0; x < vw; x++) {
+                                       p = (y * vw + x) * 3;
+                                       if (!(x & 1)) {
+                                               *(output + i) = *(output + p);
+                                               *(output + i + 1) = *(output + p + 1);
+                                               *(output + i + 2) = *(output + p + 2);
+                                               i += 3;
+                                       }
+                               }  /* for x */
+                       }
+               }  /* for y */
+       }
+       /* reset to proper width */
+       if ((stv680->vwidth == 160)) {
+               vw = 160;
+               vh = 120;
+       }
+       if ((stv680->vwidth == 176)) {
+               vw = 176;
+               vh = 144;
+       }
+
+       /* output is RGB; some programs want BGR  */
+       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+       /* swapRGB_on=-1, never swap */
+       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
+               for (y = 0; y < vh; y++) {
+                       for (x = 0; x < vw; x++) {
+                               i = (y * vw + x) * 3;
+                               *(temp) = *(output + i);
+                               *(output + i) = *(output + i + 2);
+                               *(output + i + 2) = *(temp);
+                       }
+               }
+       }
+       /* brightness */
+       if (stv680->chgbright == 1) {
+               if (stv680->brightness >= 32767) {
+                       p = (stv680->brightness - 32767) / 256;
+                       for (x = 0; x < (vw * vh * 3); x++) {
+                               if ((*(output + x) + (unsigned char) p) > 255)
+                                       *(output + x) = 255;
+                               else
+                                       *(output + x) += (unsigned char) p;
+                       }       /* for */
+               } else {
+                       p = (32767 - stv680->brightness) / 256;
+                       for (x = 0; x < (vw * vh * 3); x++) {
+                               if ((unsigned char) p > *(output + x))
+                                       *(output + x) = 0;
+                               else
+                                       *(output + x) -= (unsigned char) p;
+                       }       /* for */
+               }               /* else */
+       }
+       /* if */
+       frame->curpix = 0;
+       frame->curlinepix = 0;
+       frame->grabstate = FRAME_DONE;
+       stv680->framecount++;
+       stv680->readcount++;
+       if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+               stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
+       }
+
+}                              /* bayer_unshuffle */
+
+/*******  end routines from the pencam program  *********/
+
+static int stv680_newframe (struct usb_stv *stv680, int framenr)
+{
+       int errors = 0;
+
+       while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
+               if (!stv680->frame[framenr].curpix) {
+                       errors++;
+               }
+               wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
+
+               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
+                       stv680->nullpackets = 0;
+                       PDEBUG (2, "STV(i): too many null length packets, restarting capture");
+                       stv680_stop_stream (stv680);
+                       stv680_start_stream (stv680);
+               } else {
+                       if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
+                               stv680->frame[framenr].grabstate = FRAME_ERROR;
+                               PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
+                               return -EIO;
+                       }
+                       stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
+
+                       bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
+
+                       stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
+                       stv680->scratch_use++;
+                       if (stv680->scratch_use >= STV680_NUMSCRATCH)
+                               stv680->scratch_use = 0;
+                       if (errors > STV680_MAX_ERRORS) {
+                               errors = 0;
+                               PDEBUG (2, "STV(i): too many errors, restarting capture");
+                               stv680_stop_stream (stv680);
+                               stv680_start_stream (stv680);
+                       }
+               }               /* else */
+       }                       /* while */
+       return 0;
+}
+
+/*********************************************************************
+ * Video4Linux
+ *********************************************************************/
+
+static int stv_open (struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       int err = 0;
+
+       /* we are called with the BKL held */
+       stv680->user = 1;
+       err = stv_init (stv680);        /* main initialization routine for camera */
+
+       if (err >= 0) {
+               stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
+               if (!stv680->fbuf) {
+                       PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
+                       err = -ENOMEM;
+               }
+               file->private_data = dev;
+       }
+       if (err)
+               stv680->user = 0;
+
+       return err;
+}
+
+static int stv_close (struct inode *inode, struct file *file)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < STV680_NUMFRAMES; i++)
+               stv680->frame[i].grabstate = FRAME_UNUSED;
+       if (stv680->streaming)
+               stv680_stop_stream (stv680);
+
+       if ((i = stv_stop_video (stv680)) < 0)
+               PDEBUG (1, "STV(e): stop_video failed in stv_close");
+
+       rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
+       stv680->user = 0;
+
+       if (stv680->removed) {
+               kfree(stv680);
+               stv680 = NULL;
+               PDEBUG (0, "STV(i): device unregistered");
+       }
+       file->private_data = NULL;
+       return 0;
+}
+
+static int stv680_do_ioctl (struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = file->private_data;
+       struct usb_stv *stv680 = video_get_drvdata(vdev);
+
+       if (!stv680->udev)
+               return -EIO;
+
+       switch (cmd) {
+       case VIDIOCGCAP:{
+                       struct video_capability *b = arg;
+
+                       strcpy (b->name, stv680->camera_name);
+                       b->type = VID_TYPE_CAPTURE;
+                       b->channels = 1;
+                       b->audios = 0;
+                       b->maxwidth = stv680->maxwidth;
+                       b->maxheight = stv680->maxheight;
+                       b->minwidth = stv680->maxwidth / 2;
+                       b->minheight = stv680->maxheight / 2;
+                       return 0;
+               }
+       case VIDIOCGCHAN:{
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy (v->name, "STV Camera");
+                       return 0;
+               }
+       case VIDIOCSCHAN:{
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+       case VIDIOCGPICT:{
+                       struct video_picture *p = arg;
+
+                       stv680_get_pict (stv680, p);
+                       return 0;
+               }
+       case VIDIOCSPICT:{
+                       struct video_picture *p = arg;
+
+                       if (stv680_set_pict (stv680, p))
+                               return -EINVAL;
+                       return 0;
+               }
+       case VIDIOCSWIN:{
+                       struct video_window *vw = arg;
+
+                       if (vw->flags)
+                               return -EINVAL;
+                       if (vw->clipcount)
+                               return -EINVAL;
+                       if (vw->width != stv680->vwidth) {
+                               if (stv680_set_size (stv680, vw->width, vw->height)) {
+                                       PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
+                                       return -EINVAL;
+                               }
+                       }
+                       return 0;
+               }
+       case VIDIOCGWIN:{
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;      /* FIXME */
+                       vw->y = 0;
+                       vw->chromakey = 0;
+                       vw->flags = 0;
+                       vw->clipcount = 0;
+                       vw->width = stv680->vwidth;
+                       vw->height = stv680->vheight;
+                       return 0;
+               }
+       case VIDIOCGMBUF:{
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset (vm, 0, sizeof (*vm));
+                       vm->size = STV680_NUMFRAMES * stv680->maxframesize;
+                       vm->frames = STV680_NUMFRAMES;
+                       for (i = 0; i < STV680_NUMFRAMES; i++)
+                               vm->offsets[i] = stv680->maxframesize * i;
+                       return 0;
+               }
+       case VIDIOCMCAPTURE:{
+                       struct video_mmap *vm = arg;
+
+                       if (vm->format != STV_VIDEO_PALETTE) {
+                               PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
+                                       vm->format, STV_VIDEO_PALETTE);
+                               if ((vm->format == 3) && (swapRGB_on == 0))  {
+                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
+                                       /* this may fix those apps (e.g., xawtv) that want BGR */
+                                       swapRGB = 1;
+                               }
+                               return -EINVAL;
+                       }
+                       if (vm->frame >= STV680_NUMFRAMES) {
+                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
+                               return -EINVAL;
+                       }
+                       if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
+                           || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
+                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+                                       stv680->frame[vm->frame].grabstate);
+                               return -EBUSY;
+                       }
+                       /* Is this according to the v4l spec??? */
+                       if (stv680->vwidth != vm->width) {
+                               if (stv680_set_size (stv680, vm->width, vm->height)) {
+                                       PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
+                                       return -EINVAL;
+                               }
+                       }
+                       stv680->frame[vm->frame].grabstate = FRAME_READY;
+
+                       if (!stv680->streaming)
+                               stv680_start_stream (stv680);
+
+                       return 0;
+               }
+       case VIDIOCSYNC:{
+                       int *frame = arg;
+                       int ret = 0;
+
+                       if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
+                               PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
+                               return -EINVAL;
+                       }
+                       ret = stv680_newframe (stv680, *frame);
+                       stv680->frame[*frame].grabstate = FRAME_UNUSED;
+                       return ret;
+               }
+       case VIDIOCGFBUF:{
+                       struct video_buffer *vb = arg;
+
+                       memset (vb, 0, sizeof (*vb));
+                       return 0;
+               }
+       case VIDIOCKEY:
+               return 0;
+       case VIDIOCCAPTURE:
+               {
+                       PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
+                       return -EINVAL;
+               }
+       case VIDIOCSFBUF:
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               return -EINVAL;
+       default:
+               return -ENOIOCTLCMD;
+       }                       /* end switch */
+
+       return 0;
+}
+
+static int stv680_ioctl(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl);
+}
+
+static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
+{
+       struct video_device *dev = file->private_data;
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       mutex_lock(&stv680->lock);
+
+       if (stv680->udev == NULL) {
+               mutex_unlock(&stv680->lock);
+               return -EIO;
+       }
+       if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
+                   & ~(PAGE_SIZE - 1))) {
+               mutex_unlock(&stv680->lock);
+               return -EINVAL;
+       }
+       pos = (unsigned long) stv680->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       mutex_unlock(&stv680->lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       mutex_unlock(&stv680->lock);
+
+       return 0;
+}
+
+static ssize_t stv680_read (struct file *file, char __user *buf,
+                       size_t count, loff_t *ppos)
+{
+       struct video_device *dev = file->private_data;
+       unsigned long int realcount = count;
+       int ret = 0;
+       struct usb_stv *stv680 = video_get_drvdata(dev);
+       unsigned long int i;
+
+       if (STV680_NUMFRAMES != 2) {
+               PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
+               return -1;
+       }
+       if (stv680->udev == NULL)
+               return -EIO;
+       if (realcount > (stv680->vwidth * stv680->vheight * 3))
+               realcount = stv680->vwidth * stv680->vheight * 3;
+
+       /* Shouldn't happen: */
+       if (stv680->frame[0].grabstate == FRAME_GRABBING) {
+               PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
+               return -EBUSY;
+       }
+       stv680->frame[0].grabstate = FRAME_READY;
+       stv680->frame[1].grabstate = FRAME_UNUSED;
+       stv680->curframe = 0;
+
+       if (!stv680->streaming)
+               stv680_start_stream (stv680);
+
+       if (!stv680->streaming) {
+               ret = stv680_newframe (stv680, 0);      /* ret should = 0 */
+       }
+
+       ret = stv680_newframe (stv680, 0);
+
+       if (!ret) {
+               if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
+                       PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
+                       return -EFAULT;
+               }
+       } else {
+               realcount = ret;
+       }
+       stv680->frame[0].grabstate = FRAME_UNUSED;
+       return realcount;
+}                              /* stv680_read */
+
+static struct file_operations stv680_fops = {
+       .owner =        THIS_MODULE,
+       .open =         stv_open,
+       .release =      stv_close,
+       .read =         stv680_read,
+       .mmap =         stv680_mmap,
+       .ioctl =        stv680_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek =       no_llseek,
+};
+static struct video_device stv680_template = {
+       .owner =        THIS_MODULE,
+       .name =         "STV0680 USB camera",
+       .type =         VID_TYPE_CAPTURE,
+       .hardware =     VID_HARDWARE_SE401,
+       .fops =         &stv680_fops,
+       .release =      video_device_release,
+       .minor =        -1,
+};
+
+static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface;
+       struct usb_stv *stv680 = NULL;
+       char *camera_name = NULL;
+       int retval = 0;
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1) {
+               PDEBUG (0, "STV(e): Number of Configurations != 1");
+               return -ENODEV;
+       }
+
+       interface = &intf->altsetting[0];
+       /* Is it a STV680? */
+       if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
+           (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
+               camera_name = "STV0680";
+               PDEBUG (0, "STV(i): STV0680 camera found.");
+       } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
+                  (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
+               camera_name = "Creative WebCam Go Mini";
+               PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
+       } else {
+               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
+               PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
+               retval = -ENODEV;
+               goto error;
+       }
+       /* We found one */
+       if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
+               PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       stv680->udev = dev;
+       stv680->camera_name = camera_name;
+
+       stv680->vdev = video_device_alloc();
+       if (!stv680->vdev) {
+               retval = -ENOMEM;
+               goto error;
+       }
+       memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
+       stv680->vdev->dev = &intf->dev;
+       video_set_drvdata(stv680->vdev, stv680);
+
+       memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
+       init_waitqueue_head (&stv680->wq);
+       mutex_init (&stv680->lock);
+       wmb ();
+
+       if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               PDEBUG (0, "STV(e): video_register_device failed");
+               retval = -EIO;
+               goto error_vdev;
+       }
+       PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
+
+       usb_set_intfdata (intf, stv680);
+       stv680_create_sysfs_files(stv680->vdev);
+       return 0;
+
+error_vdev:
+       video_device_release(stv680->vdev);
+error:
+       kfree(stv680);
+       return retval;
+}
+
+static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
+{
+       int i;
+
+       stv680->udev = NULL;
+       stv680->frame[0].grabstate = FRAME_ERROR;
+       stv680->frame[1].grabstate = FRAME_ERROR;
+       stv680->streaming = 0;
+
+       wake_up_interruptible (&stv680->wq);
+
+       for (i = 0; i < STV680_NUMSBUF; i++)
+               if (stv680->urb[i]) {
+                       usb_kill_urb (stv680->urb[i]);
+                       usb_free_urb (stv680->urb[i]);
+                       stv680->urb[i] = NULL;
+                       kfree(stv680->sbuf[i].data);
+               }
+       for (i = 0; i < STV680_NUMSCRATCH; i++)
+               kfree(stv680->scratch[i].data);
+       PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
+
+       /* Free the memory */
+       kfree(stv680);
+}
+
+static void stv680_disconnect (struct usb_interface *intf)
+{
+       struct usb_stv *stv680 = usb_get_intfdata (intf);
+
+       usb_set_intfdata (intf, NULL);
+
+       if (stv680) {
+               /* We don't want people trying to open up the device */
+               if (stv680->vdev) {
+                       stv680_remove_sysfs_files(stv680->vdev);
+                       video_unregister_device(stv680->vdev);
+                       stv680->vdev = NULL;
+               }
+               if (!stv680->user) {
+                       usb_stv680_remove_disconnected (stv680);
+               } else {
+                       stv680->removed = 1;
+               }
+       }
+}
+
+static struct usb_driver stv680_driver = {
+       .name =         "stv680",
+       .probe =        stv680_probe,
+       .disconnect =   stv680_disconnect,
+       .id_table =     device_table
+};
+
+/********************************************************************
+ *  Module routines
+ ********************************************************************/
+
+static int __init usb_stv680_init (void)
+{
+       if (usb_register (&stv680_driver) < 0) {
+               PDEBUG (0, "STV(e): Could not setup STV0680 driver");
+               return -1;
+       }
+       PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
+
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+}
+
+static void __exit usb_stv680_exit (void)
+{
+       usb_deregister (&stv680_driver);
+       PDEBUG (0, "STV(i): driver deregistered");
+}
+
+module_init (usb_stv680_init);
+module_exit (usb_stv680_exit);
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h
new file mode 100644 (file)
index 0000000..ea46e00
--- /dev/null
@@ -0,0 +1,227 @@
+/****************************************************************************
+ *
+ *  Filename: stv680.h
+ *
+ *  Description:
+ *     This is a USB driver for STV0680 based usb video cameras.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ ****************************************************************************/
+
+/* size of usb transfers */
+#define STV680_PACKETSIZE      4096
+
+/* number of queued bulk transfers to use, may have problems if > 1 */
+#define STV680_NUMSBUF         1
+
+/* number of frames supported by the v4l part */
+#define STV680_NUMFRAMES       2
+
+/* scratch buffers for passing data to the decoders: 2 or 4 are good */
+#define STV680_NUMSCRATCH      2
+
+/* number of nul sized packets to receive before kicking the camera */
+#define STV680_MAX_NULLPACKETS 200
+
+/* number of decoding errors before kicking the camera */
+#define STV680_MAX_ERRORS      100
+
+#define USB_PENCAM_VENDOR_ID   0x0553
+#define USB_PENCAM_PRODUCT_ID  0x0202
+
+#define USB_CREATIVEGOMINI_VENDOR_ID   0x041e
+#define USB_CREATIVEGOMINI_PRODUCT_ID  0x4007
+
+#define PENCAM_TIMEOUT          1000
+/* fmt 4 */
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
+
+static struct usb_device_id device_table[] = {
+       {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+       {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
+       {}
+};
+MODULE_DEVICE_TABLE (usb, device_table);
+
+struct stv680_sbuf {
+       unsigned char *data;
+};
+
+enum {
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+       FRAME_READY,            /* Ready to start grabbing */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_ERROR,            /* Something bad happened while processing */
+};
+
+enum {
+       BUFFER_UNUSED,
+       BUFFER_READY,
+       BUFFER_BUSY,
+       BUFFER_DONE,
+};
+
+/* raw camera data <- sbuf (urb transfer buf) */
+struct stv680_scratch {
+       unsigned char *data;
+       volatile int state;
+       int offset;
+       int length;
+};
+
+/* processed data for display ends up here, after bayer */
+struct stv680_frame {
+       unsigned char *data;    /* Frame buffer */
+       volatile int grabstate; /* State of grabbing */
+       unsigned char *curline;
+       int curlinepix;
+       int curpix;
+};
+
+/* this is almost the video structure uvd_t, with extra parameters for stv */
+struct usb_stv {
+       struct video_device *vdev;
+
+       struct usb_device *udev;
+
+       unsigned char bulk_in_endpointAddr;     /* __u8  the address of the bulk in endpoint */
+       char *camera_name;
+
+       unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
+       int SupportedModes;
+       int CIF;
+       int VGA;
+       int QVGA;
+       int cwidth;             /* camera width */
+       int cheight;            /* camera height */
+       int maxwidth;           /* max video width */
+       int maxheight;          /* max video height */
+       int vwidth;             /* current width for video window */
+       int vheight;            /* current height for video window */
+       unsigned long int rawbufsize;
+       unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
+
+       int origGain;
+       int origMode;           /* original camera mode */
+
+       struct mutex lock;      /* to lock the structure */
+       int user;               /* user count for exclusive use */
+       int removed;            /* device disconnected */
+       int streaming;          /* Are we streaming video? */
+       char *fbuf;             /* Videodev buffer area */
+       struct urb *urb[STV680_NUMSBUF];        /* # of queued bulk transfers */
+       int curframe;           /* Current receiving frame */
+       struct stv680_frame frame[STV680_NUMFRAMES];    /* # frames supported by v4l part */
+       int readcount;
+       int framecount;
+       int error;
+       int dropped;
+       int scratch_next;
+       int scratch_use;
+       int scratch_overflow;
+       struct stv680_scratch scratch[STV680_NUMSCRATCH];       /* for decoders */
+       struct stv680_sbuf sbuf[STV680_NUMSBUF];
+
+       unsigned int brightness;
+       unsigned int chgbright;
+       unsigned int whiteness;
+       unsigned int colour;
+       unsigned int contrast;
+       unsigned int hue;
+       unsigned int palette;
+       unsigned int depth;     /* rgb24 in bits */
+
+       wait_queue_head_t wq;   /* Processes waiting */
+
+       int nullpackets;
+};
+
+
+static const unsigned char red[256] = {
+       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+       220, 220, 221, 221 
+}; 
+
+static const unsigned char green[256] = {
+       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+       245, 245, 246, 246 
+}; 
+
+static const unsigned char blue[256] = {
+       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+       249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+       255, 255, 255, 255 
+}; 
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
new file mode 100644 (file)
index 0000000..ed410a5
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_USB_IBMCAM)        += ibmcam.o usbvideo.o ultracam.o
+obj-$(CONFIG_USB_KONICAWC)      += konicawc.o usbvideo.o
+obj-$(CONFIG_USB_VICAM)         += vicam.o usbvideo.o
+
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
new file mode 100644 (file)
index 0000000..a42c222
--- /dev/null
@@ -0,0 +1,3932 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports Xirlink C-It Video Camera, IBM PC Camera,
+ * IBM NetCamera and Veo Stingray.
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * 5/24/00 Removed optional (and unnecessary) locking of the driver while
+ * the device remains plugged in. Corrected race conditions in ibmcam_open
+ * and ibmcam_probe() routines using this as a guideline:
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "usbvideo.h"
+
+#define IBMCAM_VENDOR_ID       0x0545
+#define IBMCAM_PRODUCT_ID      0x8080
+#define NETCAM_PRODUCT_ID      0x8002  /* IBM NetCamera, close to model 2 */
+#define VEO_800C_PRODUCT_ID    0x800C  /* Veo Stingray, repackaged Model 2 */
+#define VEO_800D_PRODUCT_ID    0x800D  /* Veo Stingray, repackaged Model 4 */
+
+#define MAX_IBMCAM             4       /* How many devices we allow to connect */
+#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
+
+/* Header signatures */
+
+/* Model 1 header: 00 FF 00 xx */
+#define HDRSIG_MODEL1_128x96   0x06    /* U Y V Y ... */
+#define HDRSIG_MODEL1_176x144  0x0e    /* U Y V Y ... */
+#define HDRSIG_MODEL1_352x288  0x00    /* V Y U Y ... */
+
+#define        IBMCAM_MODEL_1  1       /* XVP-501, 3 interfaces, rev. 0.02 */
+#define IBMCAM_MODEL_2 2       /* KSX-X9903, 2 interfaces, rev. 3.0a */
+#define IBMCAM_MODEL_3 3       /* KSX-X9902, 2 interfaces, rev. 3.01 */
+#define        IBMCAM_MODEL_4  4       /* IBM NetCamera, 0545/8002/3.0a */
+
+/* Video sizes supported */
+#define        VIDEOSIZE_128x96        VIDEOSIZE(128, 96)
+#define        VIDEOSIZE_176x144       VIDEOSIZE(176,144)
+#define        VIDEOSIZE_352x288       VIDEOSIZE(352,288)
+#define        VIDEOSIZE_320x240       VIDEOSIZE(320,240)
+#define        VIDEOSIZE_352x240       VIDEOSIZE(352,240)
+#define        VIDEOSIZE_640x480       VIDEOSIZE(640,480)
+#define        VIDEOSIZE_160x120       VIDEOSIZE(160,120)
+
+/* Video sizes supported */
+enum {
+       SIZE_128x96 = 0,
+       SIZE_160x120,
+       SIZE_176x144,
+       SIZE_320x240,
+       SIZE_352x240,
+       SIZE_352x288,
+       SIZE_640x480,
+       /* Add/remove/rearrange items before this line */
+       SIZE_LastItem
+};
+
+/*
+ * This structure lives in uvd->user field.
+ */
+typedef struct {
+       int initialized;        /* Had we already sent init sequence? */
+       int camera_model;       /* What type of IBM camera we got? */
+       int has_hdr;
+} ibmcam_t;
+#define        IBMCAM_T(uvd)   ((ibmcam_t *)((uvd)->user_data))
+
+static struct usbvideo *cams;
+
+static int debug;
+
+static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+static const int min_canvasWidth  = 8;
+static const int min_canvasHeight = 4;
+
+static int lighting = 1; /* Medium */
+
+#define SHARPNESS_MIN  0
+#define SHARPNESS_MAX  6
+static int sharpness = 4; /* Low noise, good details */
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  6
+static int framerate = -1;
+
+static int size = SIZE_352x288;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+static int hue_correction = 128;
+
+/* Settings for camera model 2 */
+static int init_model2_rg2 = -1;
+static int init_model2_sat = -1;
+static int init_model2_yb = -1;
+
+/* 01.01.08 - Added for RCA video in support -LO */
+/* Settings for camera model 3 */
+static int init_model3_input = 0;
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+module_param(flags, int, 0);
+MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
+module_param(framerate, int, 0);
+MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
+module_param(lighting, int, 0);
+MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
+module_param(sharpness, int, 0);
+MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480  (default=5)");
+module_param(init_brightness, int, 0);
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
+module_param(init_contrast, int, 0);
+MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
+module_param(init_color, int, 0);
+MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
+module_param(init_hue, int, 0);
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
+module_param(hue_correction, int, 0);
+MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
+
+module_param(init_model2_rg2, int, 0);
+MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
+module_param(init_model2_sat, int, 0);
+MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
+module_param(init_model2_yb, int, 0);
+MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
+
+/* 01.01.08 - Added for RCA video in support -LO */
+module_param(init_model3_input, int, 0);
+MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
+
+MODULE_AUTHOR ("Dmitri");
+MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
+MODULE_LICENSE("GPL");
+
+/* Still mysterious i2c commands */
+static const unsigned short unknown_88 = 0x0088;
+static const unsigned short unknown_89 = 0x0089;
+static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
+static const unsigned short contrast_14 = 0x0014;
+static const unsigned short light_27 = 0x0027;
+static const unsigned short sharp_13 = 0x0013;
+
+/* i2c commands for Model 2 cameras */
+static const unsigned short mod2_brightness = 0x001a;          /* $5b .. $ee; default=$5a */
+static const unsigned short mod2_set_framerate = 0x001c;       /* 0 (fast).. $1F (slow) */
+static const unsigned short mod2_color_balance_rg2 = 0x001e;   /* 0 (red) .. $7F (green) */
+static const unsigned short mod2_saturation = 0x0020;          /* 0 (b/w) - $7F (full color) */
+static const unsigned short mod2_color_balance_yb = 0x0022;    /* 0..$7F, $50 is about right */
+static const unsigned short mod2_hue = 0x0024;                 /* 0..$7F, $70 is about right */
+static const unsigned short mod2_sensitivity = 0x0028;         /* 0 (min) .. $1F (max) */
+
+struct struct_initData {
+       unsigned char req;
+       unsigned short value;
+       unsigned short index;
+};
+
+/*
+ * ibmcam_size_to_videosize()
+ *
+ * This procedure converts module option 'size' into the actual
+ * videosize_t that defines the image size in pixels. We need
+ * simplified 'size' because user wants a simple enumerated list
+ * of choices, not an infinite set of possibilities.
+ */
+static videosize_t ibmcam_size_to_videosize(int size)
+{
+       videosize_t vs = VIDEOSIZE_352x288;
+       RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
+       switch (size) {
+       case SIZE_128x96:
+               vs = VIDEOSIZE_128x96;
+               break;
+       case SIZE_160x120:
+               vs = VIDEOSIZE_160x120;
+               break;
+       case SIZE_176x144:
+               vs = VIDEOSIZE_176x144;
+               break;
+       case SIZE_320x240:
+               vs = VIDEOSIZE_320x240;
+               break;
+       case SIZE_352x240:
+               vs = VIDEOSIZE_352x240;
+               break;
+       case SIZE_352x288:
+               vs = VIDEOSIZE_352x288;
+               break;
+       case SIZE_640x480:
+               vs = VIDEOSIZE_640x480;
+               break;
+       default:
+               err("size=%d. is not valid", size);
+               break;
+       }
+       return vs;
+}
+
+/*
+ * ibmcam_find_header()
+ *
+ * Locate one of supported header markers in the queue.
+ * Once found, remove all preceding bytes AND the marker (4 bytes)
+ * from the data pump queue. Whatever follows must be video lines.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
+{
+       struct usbvideo_frame *frame;
+       ibmcam_t *icam;
+
+       if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
+               err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
+               return scan_EndParse;
+       }
+       icam = IBMCAM_T(uvd);
+       assert(icam != NULL);
+       frame = &uvd->frame[uvd->curframe];
+       icam->has_hdr = 0;
+       switch (icam->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int marker_len = 4;
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
+                       {
+#if 0                          /* This code helps to detect new frame markers */
+                               info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
+#endif
+                               frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               if ((frame->header == HDRSIG_MODEL1_128x96) ||
+                                   (frame->header == HDRSIG_MODEL1_176x144) ||
+                                   (frame->header == HDRSIG_MODEL1_352x288))
+                               {
+#if 0
+                                       info("Header found.");
+#endif
+                                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                                       icam->has_hdr = 1;
+                                       break;
+                               }
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+case IBMCAM_MODEL_4:
+       {
+               int marker_len = 0;
+               switch (uvd->videosize) {
+               case VIDEOSIZE_176x144:
+                       marker_len = 10;
+                       break;
+               default:
+                       marker_len = 2;
+                       break;
+               }
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
+                       {
+#if 0
+                               info("Header found.");
+#endif
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                               icam->has_hdr = 1;
+                               frame->header = HDRSIG_MODEL1_176x144;
+                               break;
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {       /*
+                * Headers: (one precedes every frame). nc=no compression,
+                * bq=best quality bf=best frame rate.
+                *
+                * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
+                * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
+                * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
+                *
+                * Bytes '00 FF' seem to indicate header. Other two bytes
+                * encode the frame type. This is a set of bit fields that
+                * encode image size, compression type etc. These fields
+                * do NOT contain frame number because all frames carry
+                * the same header.
+                */
+               const int marker_len = 4;
+               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
+                       {
+                               /*
+                                * Combine 2 bytes of frame type into one
+                                * easy to use value
+                                */
+                               unsigned long byte3, byte4;
+
+                               byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
+                               byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               frame->header = (byte3 << 8) | byte4;
+#if 0
+                               info("Header found.");
+#endif
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
+                               icam->has_hdr = 1;
+                               break;
+                       }
+                       /* If we are still here then this doesn't look like a header */
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+               }
+               break;
+       }
+       default:
+               break;
+       }
+       if (!icam->has_hdr) {
+               if (uvd->debug > 2)
+                       info("Skipping frame, no header");
+               return scan_EndParse;
+       }
+
+       /* Header found */
+       icam->has_hdr = 1;
+       uvd->stats.header_count++;
+       frame->scanstate = ScanState_Lines;
+       frame->curline = 0;
+
+       if (flags & FLAGS_FORCE_TESTPATTERN) {
+               usbvideo_TestPattern(uvd, 1, 1);
+               return scan_NextFrame;
+       }
+       return scan_Continue;
+}
+
+/*
+ * ibmcam_parse_lines()
+ *
+ * Parse one line (interlaced) from the buffer, put
+ * decoded RGB value into the current frame buffer
+ * and add the written number of bytes (RGB) to
+ * the *pcopylen.
+ *
+ * History:
+ * 21-Jan-2000 Created.
+ * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
+ */
+static enum ParseState ibmcam_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       unsigned char *f;
+       ibmcam_t *icam;
+       unsigned int len, scanLength, scanHeight, order_uv, order_yc;
+       int v4l_linesize; /* V4L line offset */
+       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
+       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
+       const int ccm = 128; /* Color correction median - see below */
+       int y, u, v, i, frame_done=0, color_corr;
+       static unsigned char lineBuffer[640*3];
+       unsigned const char *chromaLine, *lumaLine;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+       icam = IBMCAM_T(uvd);
+       assert(icam != NULL);
+       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
+
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
+               /* Model 4 frame markers do not carry image size identification */
+               switch (uvd->videosize) {
+               case VIDEOSIZE_128x96:
+               case VIDEOSIZE_160x120:
+               case VIDEOSIZE_176x144:
+                       scanLength = VIDEOSIZE_X(uvd->videosize);
+                       scanHeight = VIDEOSIZE_Y(uvd->videosize);
+                       break;
+               default:
+                       err("ibmcam_parse_lines: Wrong mode.");
+                       return scan_Out;
+               }
+               order_yc = 1;   /* order_yc: true=Yc false=cY ('c'=either U or V) */
+               order_uv = 1;   /* Always true in this algorithm */
+       } else {
+               switch (frame->header) {
+               case HDRSIG_MODEL1_128x96:
+                       scanLength = 128;
+                       scanHeight = 96;
+                       order_uv = 1;   /* U Y V Y ... */
+                       break;
+               case HDRSIG_MODEL1_176x144:
+                       scanLength = 176;
+                       scanHeight = 144;
+                       order_uv = 1;   /* U Y V Y ... */
+                       break;
+               case HDRSIG_MODEL1_352x288:
+                       scanLength = 352;
+                       scanHeight = 288;
+                       order_uv = 0;   /* Y V Y V ... */
+                       break;
+               default:
+                       err("Unknown header signature 00 FF 00 %02lX", frame->header);
+                       return scan_NextFrame;
+               }
+               /* order_yc: true=Yc false=cY ('c'=either U or V) */
+               order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
+       }
+
+       len = scanLength * 3;
+       assert(len <= sizeof(lineBuffer));
+
+       /*
+        * Lines are organized this way:
+        *
+        * I420:
+        * ~~~~
+        * <scanLength->
+        * ___________________________________
+        * |-----Y-----|---UVUVUV...UVUV-----| \
+        * |-----------+---------------------|  \
+        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. lines (interlaced)
+        * |...    ... |        ...          |  /
+        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. lines (interlaced)
+        * |___________|_____________________| /
+        *  \           \
+        *   lumaLine    chromaLine
+        */
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Mind that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
+               return scan_NextFrame;
+
+       /*
+        * Now we are sure that entire line (representing all 'scanLength'
+        * pixels from the camera) is available in the buffer. We
+        * start copying the line left-aligned to the V4L buffer.
+        * If the camera line is shorter then we should pad the V4L
+        * buffer with something (black) to complete the line.
+        */
+       assert(frame->data != NULL);
+       f = frame->data + (v4l_linesize * frame->curline);
+
+       /*
+        * To obtain chrominance data from the 'chromaLine' use this:
+        *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
+        *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
+        *
+        * Indices must be calculated this way:
+        * v_index = (i >> 1) << 2;
+        * u_index = (i >> 1) << 2 + 2;
+        *
+        * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
+        */
+       lumaLine = lineBuffer;
+       chromaLine = lineBuffer + scanLength;
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
+       {
+               unsigned char rv, gv, bv;       /* RGB components */
+
+               /* Check for various visual debugging hints (colorized pixels) */
+               if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
+                       /*
+                        * This is bad and should not happen. This means that
+                        * we somehow overshoot the line and encountered new
+                        * frame! Obviously our camera/V4L frame size is out
+                        * of whack. This cyan dot will help you to figure
+                        * out where exactly the new frame arrived.
+                        */
+                       if (icam->has_hdr == 1) {
+                               bv = 0; /* Yellow marker */
+                               gv = 0xFF;
+                               rv = 0xFF;
+                       } else {
+                               bv = 0xFF; /* Cyan marker */
+                               gv = 0xFF;
+                               rv = 0;
+                       }
+                       icam->has_hdr = 0;
+                       goto make_pixel;
+               }
+
+               /*
+                * Check if we are still in range. We may be out of range if our
+                * V4L canvas is wider or taller than the camera "native" image.
+                * Then we quickly fill the remainder of the line with zeros to
+                * make black color and quit the horizontal scanning loop.
+                */
+               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
+                       const int j = i * V4L_BYTES_PER_PIXEL;
+#if USES_IBMCAM_PUTPIXEL
+                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
+                       f = frame->data + (v4l_linesize * frame->curline) + j;
+#endif
+                       memset(f, 0, v4l_linesize - j);
+                       break;
+               }
+
+               y = lumaLine[i];
+               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+                       rv = gv = bv = y;
+               else {
+                       int off_0, off_2;
+
+                       off_0 = (i >> 1) << 2;
+                       off_2 = off_0 + 2;
+
+                       if (order_yc) {
+                               off_0++;
+                               off_2++;
+                       }
+                       if (!order_uv) {
+                               off_0 += 2;
+                               off_2 -= 2;
+                       }
+                       u = chromaLine[off_0] + hue_corr;
+                       v = chromaLine[off_2] + hue2_corr;
+
+                       /* Apply color correction */
+                       if (color_corr != 0) {
+                               /* Magnify up to 2 times, reduce down to zero saturation */
+                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
+                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
+                       }
+                       YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+               }
+
+       make_pixel:
+               /*
+                * The purpose of creating the pixel here, in one,
+                * dedicated place is that we may need to make the
+                * pixel wider and taller than it actually is. This
+                * may be used if camera generates small frames for
+                * sake of frame rate (or any other reason.)
+                *
+                * The output data consists of B, G, R bytes
+                * (in this order).
+                */
+#if USES_IBMCAM_PUTPIXEL
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+#else
+               *f++ = bv;
+               *f++ = gv;
+               *f++ = rv;
+#endif
+               /*
+                * Typically we do not decide within a legitimate frame
+                * that we want to end the frame. However debugging code
+                * may detect marker of new frame within the data. Then
+                * this condition activates. The 'data' pointer is already
+                * pointing at the new marker, so we'd better leave it as is.
+                */
+               if (frame_done)
+                       break;  /* End scanning of lines */
+       }
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       if (pcopylen != NULL)
+               *pcopylen += 2 * v4l_linesize;
+       frame->deinterlace = Deinterlace_FillOddLines;
+
+       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
+               return scan_NextFrame;
+       else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_model2_320x240_parse_lines()
+ *
+ * This procedure deals with a weird RGB format that is produced by IBM
+ * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
+ * depending on horizontal size of the picture:
+ *
+ * <--- 160 or 176 pairs of RA,RB bytes ----->
+ * *-----------------------------------------* \
+ * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \   This is pair of horizontal lines,
+ * |-----+-----+-----+-----+ ... +-----+-----|   *- or one interlaced line, total
+ * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   120 or 144 such pairs which yield
+ * |=====+=====+=====+=====+ ... +=====+=====| /    240 or 288 lines after deinterlacing.
+ *
+ * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
+ * defines ONE pixel. Therefore this format yields 176x144 "decoded"
+ * resolution at best. I do not know why camera sends such format - the
+ * previous model (1) just used interlaced I420 and everyone was happy.
+ *
+ * I do not know what is the difference between RAi and RBi bytes. Both
+ * seemingly represent R component, but slightly vary in value (so that
+ * the picture looks a bit colored if one or another is used). I use
+ * them both as R component in attempt to at least partially recover the
+ * lost resolution.
+ */
+static enum ParseState ibmcam_model2_320x240_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       unsigned char *f, *la, *lb;
+       unsigned int len;
+       int v4l_linesize; /* V4L line offset */
+       int i, j, frame_done=0, color_corr;
+       int scanLength, scanHeight;
+       static unsigned char lineBuffer[352*2];
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_320x240:
+       case VIDEOSIZE_352x240:
+       case VIDEOSIZE_352x288:
+               scanLength = VIDEOSIZE_X(uvd->videosize);
+               scanHeight = VIDEOSIZE_Y(uvd->videosize);
+               break;
+       default:
+               err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
+               return scan_Out;
+       }
+
+       color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       len = scanLength * 2; /* See explanation above */
+       assert(len <= sizeof(lineBuffer));
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Mind that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
+               return scan_NextFrame;
+
+       la = lineBuffer;
+       lb = lineBuffer + scanLength;
+
+       /*
+        * Now we are sure that entire line (representing all
+        *         VIDEOSIZE_X(frame->request)
+        * pixels from the camera) is available in the scratch buffer. We
+        * start copying the line left-aligned to the V4L buffer (which
+        * might be larger - not smaller, hopefully). If the camera
+        * line is shorter then we should pad the V4L buffer with something
+        * (black in this case) to complete the line.
+        */
+       f = frame->data + (v4l_linesize * frame->curline);
+
+       /* Fill the 2-line strip */
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int y, rv, gv, bv;      /* RGB components */
+
+               j = i & (~1);
+
+               /* Check for various visual debugging hints (colorized pixels) */
+               if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
+                       if (IBMCAM_T(uvd)->has_hdr == 1) {
+                               bv = 0; /* Yellow marker */
+                               gv = 0xFF;
+                               rv = 0xFF;
+                       } else {
+                               bv = 0xFF; /* Cyan marker */
+                               gv = 0xFF;
+                               rv = 0;
+                       }
+                       IBMCAM_T(uvd)->has_hdr = 0;
+                       goto make_pixel;
+               }
+
+               /*
+                * Check if we are still in range. We may be out of range if our
+                * V4L canvas is wider or taller than the camera "native" image.
+                * Then we quickly fill the remainder of the line with zeros to
+                * make black color and quit the horizontal scanning loop.
+                */
+               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
+                       const int j = i * V4L_BYTES_PER_PIXEL;
+#if USES_IBMCAM_PUTPIXEL
+                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
+                       f = frame->data + (v4l_linesize * frame->curline) + j;
+#endif
+                       memset(f, 0, v4l_linesize - j);
+                       break;
+               }
+
+               /*
+                * Here I use RA and RB components, one per physical pixel.
+                * This causes fine vertical grid on the picture but may improve
+                * horizontal resolution. If you prefer replicating, use this:
+                *   rv = la[j + 0];   ... or ... rv = la[j + 1];
+                * then the pixel will be replicated.
+                */
+               rv = la[i];
+               gv = lb[j + 1];
+               bv = lb[j + 0];
+
+               y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
+
+               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+                       rv = gv = bv = y;
+               else if (color_corr != 128) {
+
+                       /* Calculate difference between color and brightness */
+                       rv -= y;
+                       gv -= y;
+                       bv -= y;
+
+                       /* Scale differences */
+                       rv = (rv * color_corr) / 128;
+                       gv = (gv * color_corr) / 128;
+                       bv = (bv * color_corr) / 128;
+
+                       /* Reapply brightness */
+                       rv += y;
+                       gv += y;
+                       bv += y;
+
+                       /* Watch for overflows */
+                       RESTRICT_TO_RANGE(rv, 0, 255);
+                       RESTRICT_TO_RANGE(gv, 0, 255);
+                       RESTRICT_TO_RANGE(bv, 0, 255);
+               }
+
+       make_pixel:
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+       }
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       *pcopylen += v4l_linesize * 2;
+       frame->deinterlace = Deinterlace_FillOddLines;
+
+       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
+               return scan_NextFrame;
+       else
+               return scan_Continue;
+}
+
+static enum ParseState ibmcam_model3_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       unsigned char *data;
+       const unsigned char *color;
+       unsigned int len;
+       int v4l_linesize; /* V4L line offset */
+       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
+       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
+       const int ccm = 128; /* Color correction median - see below */
+       int i, u, v, rw, data_w=0, data_h=0, color_corr;
+       static unsigned char lineBuffer[640*3];
+
+       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
+
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       /* The header tells us what sort of data is in this frame */
+       switch (frame->header) {
+               /*
+                * Uncompressed modes (that are easy to decode).
+                */
+       case 0x0308:
+               data_w = 640;
+               data_h = 480;
+               break;
+       case 0x0208:
+               data_w = 320;
+               data_h = 240;
+               break;
+       case 0x020A:
+               data_w = 160;
+               data_h = 120;
+               break;
+               /*
+                * Compressed modes (ViCE - that I don't know how to decode).
+                */
+       case 0x0328:    /* 640x480, best quality compression */
+       case 0x0368:    /* 640x480, best frame rate compression */
+       case 0x0228:    /* 320x240, best quality compression */
+       case 0x0268:    /* 320x240, best frame rate compression */
+       case 0x02CA:    /* 160x120, best quality compression */
+       case 0x02EA:    /* 160x120, best frame rate compression */
+               /* Do nothing with this - not supported */
+               err("Unsupported mode $%04lx", frame->header);
+               return scan_NextFrame;
+       default:
+               /* Catch unknown headers, may help in learning new headers */
+               err("Strange frame->header=$%08lx", frame->header);
+               return scan_NextFrame;
+       }
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Note that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= data_h) {
+               if (uvd->debug >= 3)
+                       info("Reached line %d. (frame is done)", frame->curline);
+               return scan_NextFrame;
+       }
+
+       /* Make sure there's enough data for the entire line */
+       len = 3 * data_w; /* <y-data> <uv-data> */
+       assert(len <= sizeof(lineBuffer));
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       data = lineBuffer;
+       color = data + data_w;          /* Point to where color planes begin */
+
+       /* Bottom-to-top scanning */
+       rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
+       RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
+
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int y, rv, gv, bv;      /* RGB components */
+
+               if (i < data_w) {
+                       y = data[i];    /* Luminosity is the first line */
+
+                       /* Apply static color correction */
+                       u = color[i*2] + hue_corr;
+                       v = color[i*2 + 1] + hue2_corr;
+
+                       /* Apply color correction */
+                       if (color_corr != 0) {
+                               /* Magnify up to 2 times, reduce down to zero saturation */
+                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
+                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
+                       }
+               } else
+                       y = 0, u = v = 128;
+
+               YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+               RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
+       }
+       frame->deinterlace = Deinterlace_FillEvenLines;
+
+       /*
+        * Account for number of bytes that we wrote into output V4L frame.
+        * We do it here, after we are done with the scanline, because we
+        * may fill more than one output scanline if we do vertical
+        * enlargement.
+        */
+       frame->curline += 2;
+       *pcopylen += 2 * v4l_linesize;
+
+       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
+               if (uvd->debug >= 3) {
+                       info("All requested lines (%ld.) done.",
+                            VIDEOSIZE_Y(frame->request));
+               }
+               return scan_NextFrame;
+       } else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_model4_128x96_parse_lines()
+ *
+ * This decoder is for one strange data format that is produced by Model 4
+ * camera only in 128x96 mode. This is RGB format and here is its description.
+ * First of all, this is non-interlaced stream, meaning that all scan lines
+ * are present in the datastream. There are 96 consecutive blocks of data
+ * that describe all 96 lines of the image. Each block is 5*128 bytes long
+ * and carries R, G, B components. The format of the block is shown in the
+ * code below. First 128*2 bytes are interleaved R and G components. Then
+ * we have a gap (junk data) 64 bytes long. Then follow B and something
+ * else, also interleaved (this makes another 128*2 bytes). After that
+ * probably another 64 bytes of junk follow.
+ *
+ * History:
+ * 10-Feb-2001 Created.
+ */
+static enum ParseState ibmcam_model4_128x96_parse_lines(
+       struct uvd *uvd,
+       struct usbvideo_frame *frame,
+       long *pcopylen)
+{
+       const unsigned char *data_rv, *data_gv, *data_bv;
+       unsigned int len;
+       int i, v4l_linesize; /* V4L line offset */
+       const int data_w=128, data_h=96;
+       static unsigned char lineBuffer[128*5];
+
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+
+       /*
+        * Make sure that our writing into output buffer
+        * will not exceed the buffer. Note that we may write
+        * not into current output scanline but in several after
+        * it as well (if we enlarge image vertically.)
+        */
+       if ((frame->curline + 1) >= data_h) {
+               if (uvd->debug >= 3)
+                       info("Reached line %d. (frame is done)", frame->curline);
+               return scan_NextFrame;
+       }
+
+       /*
+        * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
+        * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
+        */
+
+       /* Make sure there's enough data for the entire line */
+       len = 5 * data_w;
+       assert(len <= sizeof(lineBuffer));
+
+       /* Make sure there's enough data for the entire line */
+       if (RingQueue_GetLength(&uvd->dp) < len)
+               return scan_Out;
+
+       /* Suck one line out of the ring queue */
+       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
+
+       data_rv = lineBuffer;
+       data_gv = lineBuffer + 1;
+       data_bv = lineBuffer + data_w*2 + data_w/2;
+       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+               int rv, gv, bv; /* RGB components */
+               if (i < data_w) {
+                       const int j = i * 2;
+                       gv = data_rv[j];
+                       rv = data_gv[j];
+                       bv = data_bv[j];
+                       if (flags & FLAGS_MONOCHROME) {
+                               unsigned long y;
+                               y = rv + gv + bv;
+                               y /= 3;
+                               if (y > 0xFF)
+                                       y = 0xFF;
+                               rv = gv = bv = (unsigned char) y;
+                       }
+               } else {
+                       rv = gv = bv = 0;
+               }
+               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+       }
+       frame->deinterlace = Deinterlace_None;
+       frame->curline++;
+       *pcopylen += v4l_linesize;
+
+       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
+               if (uvd->debug >= 3) {
+                       info("All requested lines (%ld.) done.",
+                            VIDEOSIZE_Y(frame->request));
+               }
+               return scan_NextFrame;
+       } else
+               return scan_Continue;
+}
+
+/*
+ * ibmcam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ibmcam_find_header() or ibmcam_parse_lines() to do most
+ * of work.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static void ibmcam_ProcessIsocData(struct uvd *uvd,
+                                  struct usbvideo_frame *frame)
+{
+       enum ParseState newstate;
+       long copylen = 0;
+       int mod = IBMCAM_T(uvd)->camera_model;
+
+       while (1) {
+               newstate = scan_Out;
+               if (RingQueue_GetLength(&uvd->dp) > 0) {
+                       if (frame->scanstate == ScanState_Scanning) {
+                               newstate = ibmcam_find_header(uvd);
+                       } else if (frame->scanstate == ScanState_Lines) {
+                               if ((mod == IBMCAM_MODEL_2) &&
+                                   ((uvd->videosize == VIDEOSIZE_352x288) ||
+                                    (uvd->videosize == VIDEOSIZE_320x240) ||
+                                    (uvd->videosize == VIDEOSIZE_352x240)))
+                               {
+                                       newstate = ibmcam_model2_320x240_parse_lines(
+                                               uvd, frame, &copylen);
+                               } else if (mod == IBMCAM_MODEL_4) {
+                                       /*
+                                        * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
+                                        * for 320x240 and above; 160x120 and 176x144 uses Model 1
+                                        * decoder (YUV), and 128x96 mode uses ???
+                                        */
+                                       if ((uvd->videosize == VIDEOSIZE_352x288) ||
+                                           (uvd->videosize == VIDEOSIZE_320x240) ||
+                                           (uvd->videosize == VIDEOSIZE_352x240))
+                                       {
+                                               newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
+                                       } else if (uvd->videosize == VIDEOSIZE_128x96) {
+                                               newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
+                                       } else {
+                                               newstate = ibmcam_parse_lines(uvd, frame, &copylen);
+                                       }
+                               } else if (mod == IBMCAM_MODEL_3) {
+                                       newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
+                               } else {
+                                       newstate = ibmcam_parse_lines(uvd, frame, &copylen);
+                               }
+                       }
+               }
+               if (newstate == scan_Continue)
+                       continue;
+               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
+                       break;
+               else
+                       return; /* scan_EndParse */
+       }
+
+       if (newstate == scan_NextFrame) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+               if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
+                       /* Need software contrast adjustment for those cameras */
+                       frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
+               }
+       }
+
+       /* Update the frame's uncompressed length. */
+       frame->seqRead_Length += copylen;
+
+#if 0
+       {
+               static unsigned char j=0;
+               memset(frame->data, j++, uvd->max_frame_size);
+               frame->frameState = FrameState_Ready;
+       }
+#endif
+}
+
+/*
+ * ibmcam_veio()
+ *
+ * History:
+ * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
+ */
+static int ibmcam_veio(
+       struct uvd *uvd,
+       unsigned char req,
+       unsigned short value,
+       unsigned short index)
+{
+       static const char proc[] = "ibmcam_veio";
+       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+       int i;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return 0;
+
+       if (req == 1) {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_rcvctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value,
+                       index,
+                       cp,
+                       sizeof(cp),
+                       1000);
+#if 0
+               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x)",
+                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                      req, value, index);
+#endif
+       } else {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_sndctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       1000);
+       }
+       if (i < 0) {
+               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
+                   proc, i);
+               uvd->last_error = i;
+       }
+       return i;
+}
+
+/*
+ * ibmcam_calculate_fps()
+ *
+ * This procedure roughly calculates the real frame rate based
+ * on FPS code (framerate=NNN option). Actual FPS differs
+ * slightly depending on lighting conditions, so that actual frame
+ * rate is determined by the camera. Since I don't know how to ask
+ * the camera what FPS is now I have to use the FPS code instead.
+ *
+ * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
+ * Corresponding real FPS should be in range [3..30] frames per second.
+ * The conversion formula is obvious:
+ *
+ * real_fps = 3 + (fps_code * 4.5)
+ *
+ * History:
+ * 1/18/00  Created.
+ */
+static int ibmcam_calculate_fps(struct uvd *uvd)
+{
+       return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * ibmcam_send_FF_04_02()
+ *
+ * This procedure sends magic 3-command prefix to the camera.
+ * The purpose of this prefix is not known.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void ibmcam_send_FF_04_02(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
+       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+}
+
+static void ibmcam_send_00_04_06(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0006, 0x0124);
+}
+
+static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+}
+
+static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_send_x_00(uvd, x);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+}
+
+static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+}
+
+static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+}
+
+static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+}
+
+static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
+{
+       ibmcam_veio(uvd, 0, x,      0x0127);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0008, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
+}
+
+static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
+{
+       ibmcam_send_x_01_00_05(uvd, unknown_88);
+       ibmcam_send_x_00_05(uvd, fkey);
+       ibmcam_send_x_00_05_02_08_01(uvd, val);
+       ibmcam_send_x_00_05(uvd, unknown_88);
+       ibmcam_send_x_00_05_02_01(uvd, fkey);
+       ibmcam_send_x_00_05(uvd, unknown_89);
+       ibmcam_send_x_00(uvd, fkey);
+       ibmcam_send_00_04_06(uvd);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0126);
+       ibmcam_send_FF_04_02(uvd);
+}
+
+static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
+{
+       ibmcam_send_x_01_00_05  (uvd, unknown_88);
+       ibmcam_send_x_00_05     (uvd, fkey);
+       ibmcam_send_x_00_05_02  (uvd, val);
+}
+
+static void ibmcam_model2_Packet2(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
+       ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
+}
+
+static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
+{
+       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
+       ibmcam_veio(uvd, 0, v1,     0x012f);
+       ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
+       ibmcam_veio(uvd, 0, 0xc719, 0x0124);
+       ibmcam_veio(uvd, 0, v2,     0x0127);
+
+       ibmcam_model2_Packet2(uvd);
+}
+
+/*
+ * ibmcam_model3_Packet1()
+ *
+ * 00_0078_012d        
+ * 00_0097_012f
+ * 00_d141_0124        
+ * 00_0096_0127
+ * 00_fea8_0124        
+*/
+static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
+{
+       ibmcam_veio(uvd, 0, 0x0078, 0x012d);
+       ibmcam_veio(uvd, 0, v1,     0x012f);
+       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+       ibmcam_veio(uvd, 0, v2,     0x0127);
+       ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+}
+
+static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
+{
+       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+       ibmcam_veio(uvd, 0, 0x0026, 0x012f);
+       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+       ibmcam_veio(uvd, 0, i,      0x0127);
+       ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+       ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+       ibmcam_veio(uvd, 0, 0x0038, 0x012d);
+       ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+       ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+       ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+}
+
+/*
+ * ibmcam_adjust_contrast()
+ *
+ * The contrast value changes from 0 (high contrast) to 15 (low contrast).
+ * This is in reverse to usual order of things (such as TV controls), so
+ * we reverse it again here.
+ *
+ * TODO: we probably don't need to send the setup 5 times...
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void ibmcam_adjust_contrast(struct uvd *uvd)
+{
+       unsigned char a_contrast = uvd->vpic.contrast >> 12;
+       unsigned char new_contrast;
+
+       if (a_contrast >= 16)
+               a_contrast = 15;
+       new_contrast = 15 - a_contrast;
+       if (new_contrast == uvd->vpic_old.contrast)
+               return;
+       uvd->vpic_old.contrast = new_contrast;
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int ntries = 5;
+               int i;
+               for (i=0; i < ntries; i++) {
+                       ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
+                       ibmcam_send_FF_04_02(uvd);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       case IBMCAM_MODEL_4:
+               /* Models 2, 4 do not have this control; implemented in software. */
+               break;
+       case IBMCAM_MODEL_3:
+       {       /* Preset hardware values */
+               static const struct {
+                       unsigned short cv1;
+                       unsigned short cv2;
+                       unsigned short cv3;
+               } cv[7] = {
+                       { 0x05, 0x05, 0x0f },   /* Minimum */
+                       { 0x04, 0x04, 0x16 },
+                       { 0x02, 0x03, 0x16 },
+                       { 0x02, 0x08, 0x16 },
+                       { 0x01, 0x0c, 0x16 },
+                       { 0x01, 0x0e, 0x16 },
+                       { 0x01, 0x10, 0x16 }    /* Maximum */
+               };
+               int i = a_contrast / 2;
+               RESTRICT_TO_RANGE(i, 0, 6);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
+               ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
+               ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_change_lighting_conditions()
+ *
+ * Camera model 1:
+ * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
+ *
+ * Camera model 2:
+ * We have 16 levels of lighting, 0 for bright light and up to 15 for
+ * low light. But values above 5 or so are useless because camera is
+ * not really capable to produce anything worth viewing at such light.
+ * This setting may be altered only in certain camera state.
+ *
+ * Low lighting forces slower FPS. Lighting is set as a module parameter.
+ *
+ * History:
+ * 1/5/00   Created.
+ * 2/20/00  Added support for Model 2 cameras.
+ */
+static void ibmcam_change_lighting_conditions(struct uvd *uvd)
+{
+       static const char proc[] = "ibmcam_change_lighting_conditions";
+
+       if (debug > 0)
+               info("%s: Set lighting to %hu.", proc, lighting);
+
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               const int ntries = 5;
+               int i;
+               for (i=0; i < ntries; i++)
+                       ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
+               break;
+       }
+       case IBMCAM_MODEL_2:
+#if 0
+               /*
+                * This command apparently requires camera to be stopped. My
+                * experiments showed that it -is- possible to alter the lighting
+                * conditions setting "on the fly", but why bother? This setting does
+                * not work reliably in all cases, so I decided simply to leave the
+                * setting where Xirlink put it - in the camera setup phase. This code
+                * is commented out because it does not work at -any- moment, so its
+                * presence makes no sense. You may use it for experiments.
+                */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop camera */
+               ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Start camera */
+#endif
+               break;
+       case IBMCAM_MODEL_3:
+       case IBMCAM_MODEL_4:
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_set_sharpness()
+ *
+ * Cameras model 1 have internal smoothing feature. It is controlled by value in
+ * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
+ * Recommended value is 4. Cameras model 2 do not have this feature at all.
+ */
+static void ibmcam_set_sharpness(struct uvd *uvd)
+{
+       static const char proc[] = "ibmcam_set_sharpness";
+
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
+               unsigned short i, sv;
+
+               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+               if (debug > 0)
+                       info("%s: Set sharpness to %hu.", proc, sharpness);
+
+               sv = sa[sharpness - SHARPNESS_MIN];
+               for (i=0; i < 2; i++) {
+                       ibmcam_send_x_01_00_05  (uvd, unknown_88);
+                       ibmcam_send_x_00_05             (uvd, sharp_13);
+                       ibmcam_send_x_00_05_02  (uvd, sv);
+               }
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       case IBMCAM_MODEL_4:
+               /* Models 2, 4 do not have this control */
+               break;
+       case IBMCAM_MODEL_3:
+       {       /*
+                * "Use a table of magic numbers.
+                *  This setting doesn't really change much.
+                *  But that's how Windows does it."
+                */
+               static const struct {
+                       unsigned short sv1;
+                       unsigned short sv2;
+                       unsigned short sv3;
+                       unsigned short sv4;
+               } sv[7] = {
+                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
+                       { 0x01, 0x04, 0x05, 0x14 },
+                       { 0x02, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x04, 0x05, 0x14 },
+                       { 0x03, 0x05, 0x05, 0x14 },
+                       { 0x03, 0x06, 0x05, 0x14 },
+                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
+               };
+               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+               RESTRICT_TO_RANGE(sharpness, 0, 6);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
+               ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
+               ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
+               ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_set_brightness()
+ *
+ * This procedure changes brightness of the picture.
+ */
+static void ibmcam_set_brightness(struct uvd *uvd)
+{
+       static const char proc[] = "ibmcam_set_brightness";
+       static const unsigned short n = 1;
+
+       if (debug > 0)
+               info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
+
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+       {
+               unsigned short i, j, bv[3];
+               bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
+               if (bv[0] == (uvd->vpic_old.brightness >> 10))
+                       return;
+               uvd->vpic_old.brightness = bv[0];
+               for (j=0; j < 3; j++)
+                       for (i=0; i < n; i++)
+                               ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
+               break;
+       }
+       case IBMCAM_MODEL_2:
+       {
+               unsigned short i, j;
+               i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
+               j = 0x60 + i * ((0xee - 0x60) / 16);    /* 0x60 .. 0xee or so */
+               if (uvd->vpic_old.brightness == j)
+                       break;
+               uvd->vpic_old.brightness = j;
+               ibmcam_model2_Packet1(uvd, mod2_brightness, j);
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {
+               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
+               unsigned short i =
+                       0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
+               RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
+               if (uvd->vpic_old.brightness == i)
+                       break;
+               uvd->vpic_old.brightness = i;
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x0036, i);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+               break;
+       }
+       case IBMCAM_MODEL_4:
+       {
+               /* Model 4: Brightness range 'i' in [0x04..0xb4] */
+               unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
+               RESTRICT_TO_RANGE(i, 0x04, 0xb4);
+               if (uvd->vpic_old.brightness == i)
+                       break;
+               uvd->vpic_old.brightness = i;
+               ibmcam_model4_BrightnessPacket(uvd, i);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static void ibmcam_set_hue(struct uvd *uvd)
+{
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_2:
+       {
+               unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
+               if (uvd->vpic_old.hue == hue)
+                       return;
+               uvd->vpic_old.hue = hue;
+               ibmcam_model2_Packet1(uvd, mod2_hue, hue);
+               /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
+               break;
+       }
+       case IBMCAM_MODEL_3:
+       {
+#if 0 /* This seems not to work. No problem, will fix programmatically */
+               unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
+               RESTRICT_TO_RANGE(hue, 0x05, 0x37);
+               if (uvd->vpic_old.hue == hue)
+                       return;
+               uvd->vpic_old.hue = hue;
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
+               ibmcam_model3_Packet1(uvd, 0x007e, hue);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
+#endif
+               break;
+       }
+       case IBMCAM_MODEL_4:
+       {
+               unsigned short r_gain, g_gain, b_gain, hue;
+
+               /*
+                * I am not sure r/g/b_gain variables exactly control gain
+                * of those channels. Most likely they subtly change some
+                * very internal image processing settings in the camera.
+                * In any case, here is what they do, and feel free to tweak:
+                *
+                * r_gain: seriously affects red gain
+                * g_gain: seriously affects green gain
+                * b_gain: seriously affects blue gain
+                * hue: changes average color from violet (0) to red (0xFF)
+                *
+                * These settings are preset for a decent white balance in
+                * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
+                * and therefore may need different values here.
+                */
+               hue = 20 + (uvd->vpic.hue >> 9);
+               switch (uvd->videosize) {
+               case VIDEOSIZE_128x96:
+                       r_gain = 90;
+                       g_gain = 166;
+                       b_gain = 175;
+                       break;
+               case VIDEOSIZE_160x120:
+                       r_gain = 70;
+                       g_gain = 166;
+                       b_gain = 185;
+                       break;
+               case VIDEOSIZE_176x144:
+                       r_gain = 160;
+                       g_gain = 175;
+                       b_gain = 185;
+                       break;
+               default:
+                       r_gain = 120;
+                       g_gain = 166;
+                       b_gain = 175;
+                       break;
+               }
+               RESTRICT_TO_RANGE(hue, 1, 0x7f);
+
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, g_gain, 0x0127);    /* Green gain */
+               ibmcam_veio(uvd, 0, r_gain, 0x012e);    /* Red gain */
+               ibmcam_veio(uvd, 0, b_gain, 0x0130);    /* Blue gain */
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, hue,    0x012d);    /* Hue */
+               ibmcam_veio(uvd, 0, 0xf545, 0x0124);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+/*
+ * ibmcam_adjust_picture()
+ *
+ * This procedure gets called from V4L interface to update picture settings.
+ * Here we change brightness and contrast.
+ */
+static void ibmcam_adjust_picture(struct uvd *uvd)
+{
+       ibmcam_adjust_contrast(uvd);
+       ibmcam_set_brightness(uvd);
+       ibmcam_set_hue(uvd);
+}
+
+static int ibmcam_model1_setup(struct uvd *uvd)
+{
+       const int ntries = 5;
+       int i;
+
+       ibmcam_veio(uvd, 1, 0x00, 0x0128);
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
+       ibmcam_veio(uvd, 1, 0x00, 0x0100);
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 0, 0x01, 0x0108);
+
+       ibmcam_veio(uvd, 0, 0x03, 0x0112);
+       ibmcam_veio(uvd, 1, 0x00, 0x0115);
+       ibmcam_veio(uvd, 0, 0x06, 0x0115);
+       ibmcam_veio(uvd, 1, 0x00, 0x0116);
+       ibmcam_veio(uvd, 0, 0x44, 0x0116);
+       ibmcam_veio(uvd, 1, 0x00, 0x0116);
+       ibmcam_veio(uvd, 0, 0x40, 0x0116);
+       ibmcam_veio(uvd, 1, 0x00, 0x0115);
+       ibmcam_veio(uvd, 0, 0x0e, 0x0115);
+       ibmcam_veio(uvd, 0, 0x19, 0x012c);
+
+       ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x09);
+       ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
+       ibmcam_Packet_Format1(uvd, 0x28, 0x22);
+       ibmcam_Packet_Format1(uvd, light_27, 0);
+       ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
+
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
+
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x30, 0x14);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
+       ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
+       ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
+       ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
+       ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
+       ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
+       ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
+       ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
+       ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
+       ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
+       ibmcam_PacketFormat2(uvd, 0x11, 0xba);
+       ibmcam_PacketFormat2(uvd, 0x12, 0x53);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
+       ibmcam_PacketFormat2(uvd, 0x16, 0x00);
+       ibmcam_PacketFormat2(uvd, 0x17, 0x28);
+       ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
+       ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
+       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
+       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
+
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x00, 0x18);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x13, 0x18);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x14, 0x06);
+
+       /* This is default brightness */
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x31, 0x37);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x32, 0x46);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x33, 0x55);
+
+       ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x29, 0x80);
+       ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
+       ibmcam_Packet_Format1(uvd, 0x30, 0x17);
+       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x34, 0x00);
+
+       ibmcam_veio(uvd, 0, 0x00, 0x0101);
+       ibmcam_veio(uvd, 0, 0x00, 0x010a);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_veio(uvd, 0, 0x80, 0x0103);
+               ibmcam_veio(uvd, 0, 0x60, 0x0105);
+               ibmcam_veio(uvd, 0, 0x0c, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x0b, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x00, 0x0129);
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
+               ibmcam_veio(uvd, 0, 0x8f, 0x0105);
+               ibmcam_veio(uvd, 0, 0x06, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x0d, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x03, 0x0129);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
+               ibmcam_veio(uvd, 0, 0x90, 0x0105);
+               ibmcam_veio(uvd, 0, 0x02, 0x010b);
+               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x05, 0x011d);
+               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x00, 0x0129);
+               break;
+       }
+
+       ibmcam_veio(uvd, 0, 0xff, 0x012b);
+
+       /* This is another brightness - don't know why */
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
+
+       /* Default contrast */
+       for (i=0; i < ntries; i++)
+               ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
+
+       /* Default sharpness */
+       for (i=0; i < 2; i++)
+               ibmcam_PacketFormat2(uvd, sharp_13, 0x1a);      /* Level 4 FIXME */
+
+       /* Default lighting conditions */
+       ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
+
+       /* Assorted init */
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x36, 0x0102);
+               ibmcam_veio(uvd, 0, 0x1a, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+#if 0
+               ibmcam_veio(uvd, 0, 0x00, 0x0106);
+               ibmcam_veio(uvd, 0, 0x38, 0x0107);
+#else
+               ibmcam_veio(uvd, 0, 0x02, 0x0106);
+               ibmcam_veio(uvd, 0, 0x2a, 0x0107);
+#endif
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x04, 0x0102);
+               ibmcam_veio(uvd, 0, 0x02, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x01, 0x0106);
+               ibmcam_veio(uvd, 0, 0xca, 0x0107);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
+               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x08, 0x0102);
+               ibmcam_veio(uvd, 0, 0x01, 0x0104);
+               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x2f, 0x011c);
+               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
+               ibmcam_veio(uvd, 0, 0x03, 0x0106);
+               ibmcam_veio(uvd, 0, 0xf6, 0x0107);
+               break;
+       }
+       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
+}
+
+static int ibmcam_model2_setup(struct uvd *uvd)
+{
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
+       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
+       ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+       ibmcam_veio(uvd, 0, 0x0008, 0x012b);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0090, 0x0107);    /* Unique to every mode*/
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);    /* Unique to this mode */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0098, 0x0107);    /* Unique to every mode*/
+               break;
+       case VIDEOSIZE_352x240:
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x00da, 0x0107);    /* Unique to every mode*/
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
+               ibmcam_veio(uvd, 0, 0x00fe, 0x0107);    /* Unique to every mode*/
+               break;
+       }
+       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
+}
+
+/*
+ * ibmcam_model1_setup_after_video_if()
+ *
+ * This code adds finishing touches to the video data interface.
+ * Here we configure the frame rate and turn on the LED.
+ */
+static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
+{
+       unsigned short internal_frame_rate;
+
+       RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+       internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
+       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
+       ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
+       ibmcam_veio(uvd, 0, 0x01, 0x0114);
+       ibmcam_veio(uvd, 0, 0xc0, 0x010c);
+}
+
+static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
+{
+       unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
+
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x0050, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               break;
+       case VIDEOSIZE_320x240:
+       case VIDEOSIZE_352x240:
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x0040, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               break;
+       }
+       ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+       ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+
+       /*
+        * Hardware settings, may affect CMOS sensor; not user controls!
+        * -------------------------------------------------------------
+        * 0x0004: no effect
+        * 0x0006: hardware effect
+        * 0x0008: no effect
+        * 0x000a: stops video stream, probably important h/w setting
+        * 0x000c: changes color in hardware manner (not user setting)
+        * 0x0012: changes number of colors (does not affect speed)
+        * 0x002a: no effect
+        * 0x002c: hardware setting (related to scan lines)
+        * 0x002e: stops video stream, probably important h/w setting
+        */
+       ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
+       ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
+       ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
+       ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
+       ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
+       ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
+
+       /*
+        * Function 0x0030 pops up all over the place. Apparently
+        * it is a hardware control register, with every bit assigned to
+        * do something.
+        */
+       ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
+
+       /*
+        * Magic control of CMOS sensor. Only lower values like
+        * 0-3 work, and picture shifts left or right. Don't change.
+        */
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
+               break;
+       case VIDEOSIZE_352x240:
+               /* This mode doesn't work as Windows programs it; changed to work */
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
+               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
+               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
+               break;
+       }
+
+       ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
+
+       /*
+        * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
+        * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
+        * slowest setting. However for all practical reasons high settings make no
+        * sense because USB is not fast enough to support high FPS. Be aware that
+        * the picture datastream will be severely disrupted if you ask for
+        * frame rate faster than allowed for the video size - see below:
+        *
+        * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
+        * -----------------------------------------------------------------
+        * 176x144: [6..31]
+        * 320x240: [8..31]
+        * 352x240: [10..31]
+        * 352x288: [16..31] I have to raise lower threshold for stability...
+        *
+        * As usual, slower FPS provides better sensitivity.
+        */
+       {
+               short hw_fps=31, i_framerate;
+
+               RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+               i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
+               switch (uvd->videosize) {
+               case VIDEOSIZE_176x144:
+                       hw_fps = 6 + i_framerate*4;
+                       break;
+               case VIDEOSIZE_320x240:
+                       hw_fps = 8 + i_framerate*3;
+                       break;
+               case VIDEOSIZE_352x240:
+                       hw_fps = 10 + i_framerate*2;
+                       break;
+               case VIDEOSIZE_352x288:
+                       hw_fps = 28 + i_framerate/2;
+                       break;
+               }
+               if (uvd->debug > 0)
+                       info("Framerate (hardware): %hd.", hw_fps);
+               RESTRICT_TO_RANGE(hw_fps, 0, 31);
+               ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
+       }
+
+       /*
+        * This setting does not visibly affect pictures; left it here
+        * because it was present in Windows USB data stream. This function
+        * does not allow arbitrary values and apparently is a bit mask, to
+        * be activated only at appropriate time. Don't change it randomly!
+        */
+       switch (uvd->videosize) {
+       case VIDEOSIZE_176x144:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
+               break;
+       case VIDEOSIZE_352x240:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
+               break;
+       }
+
+       ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
+
+       if (init_model2_rg2 >= 0) {
+               RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
+               setup_model2_rg2 = init_model2_rg2;
+       } else
+               setup_model2_rg2 = 0x002f;
+
+       if (init_model2_sat >= 0) {
+               RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
+               setup_model2_sat = init_model2_sat;
+       } else
+               setup_model2_sat = 0x0034;
+
+       if (init_model2_yb >= 0) {
+               RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
+               setup_model2_yb = init_model2_yb;
+       } else
+               setup_model2_yb = 0x00a0;
+
+       ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
+       ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
+       ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
+       ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
+
+       /* Hardware control command */
+       ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
+
+       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go camera, go! */
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+}
+
+static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
+{
+       switch (uvd->videosize) {
+       case VIDEOSIZE_128x96:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000b, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0025, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0048, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0035, 0x012e);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0048, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0090, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_176x144:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0018, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0007, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0001, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x002a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
+               ibmcam_veio(uvd, 0, 0x006d, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break;
+       case VIDEOSIZE_352x288:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
+               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
+               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
+               ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x008c, 0x0107);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
+               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0006, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0002, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
+               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
+               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
+               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
+               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
+               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
+               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
+               ibmcam_veio(uvd, 0, 0x0025, 0x0130);
+               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0048, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
+               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
+               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
+               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               break; 
+       }
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+}
+
+static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
+{
+       int i;
+       /*
+        * 01.01.08 - Added for RCA video in support -LO
+        * This struct is used to init the Model3 cam to use the RCA video in port
+        * instead of the CCD sensor.
+        */
+       static const struct struct_initData initData[] = {
+               {0, 0x0000, 0x010c},
+               {0, 0x0006, 0x012c},
+               {0, 0x0078, 0x012d},
+               {0, 0x0046, 0x012f},
+               {0, 0xd141, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfea8, 0x0124},
+               {1, 0x0000, 0x0116},
+               {0, 0x0064, 0x0116},
+               {1, 0x0000, 0x0115},
+               {0, 0x0003, 0x0115},
+               {0, 0x0008, 0x0123},
+               {0, 0x0000, 0x0117},
+               {0, 0x0000, 0x0112},
+               {0, 0x0080, 0x0100},
+               {0, 0x0000, 0x0100},
+               {1, 0x0000, 0x0116},
+               {0, 0x0060, 0x0116},
+               {0, 0x0002, 0x0112},
+               {0, 0x0000, 0x0123},
+               {0, 0x0001, 0x0117},
+               {0, 0x0040, 0x0108},
+               {0, 0x0019, 0x012c},
+               {0, 0x0040, 0x0116},
+               {0, 0x000a, 0x0115},
+               {0, 0x000b, 0x0115},
+               {0, 0x0078, 0x012d},
+               {0, 0x0046, 0x012f},
+               {0, 0xd141, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfea8, 0x0124},
+               {0, 0x0064, 0x0116},
+               {0, 0x0000, 0x0115},
+               {0, 0x0001, 0x0115},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00aa, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f2, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x000f, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f8, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00fc, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f9, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x003c, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xffff, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0027, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0019, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0021, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0006, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0045, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002a, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x000e, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002b, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00f4, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002c, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0004, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002d, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0014, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002e, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0003, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x002f, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0003, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0014, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0053, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0x0000, 0x0101},
+               {0, 0x00a0, 0x0103},
+               {0, 0x0078, 0x0105},
+               {0, 0x0000, 0x010a},
+               {0, 0x0024, 0x010b},
+               {0, 0x0028, 0x0119},
+               {0, 0x0088, 0x011b},
+               {0, 0x0002, 0x011d},
+               {0, 0x0003, 0x011e},
+               {0, 0x0000, 0x0129},
+               {0, 0x00fc, 0x012b},
+               {0, 0x0008, 0x0102},
+               {0, 0x0000, 0x0104},
+               {0, 0x0008, 0x011a},
+               {0, 0x0028, 0x011c},
+               {0, 0x0021, 0x012a},
+               {0, 0x0000, 0x0118},
+               {0, 0x0000, 0x0132},
+               {0, 0x0000, 0x0109},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0031, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x00dc, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0032, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0020, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0001, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0040, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0037, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0030, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0xfff9, 0x0124},
+               {0, 0x0086, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0038, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0008, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0x0000, 0x0127},
+               {0, 0xfff8, 0x0124},
+               {0, 0xfffd, 0x0124},
+               {0, 0xfffa, 0x0124},
+               {0, 0x0003, 0x0106},
+               {0, 0x0062, 0x0107},
+               {0, 0x0003, 0x0111},
+       };
+#define NUM_INIT_DATA 
+
+       unsigned short compression = 0; /* 0=none, 7=best frame rate  */
+       int f_rate; /* 0=Fastest 7=slowest */
+
+       if (IBMCAM_T(uvd)->initialized)
+               return;
+
+       /* Internal frame rate is controlled by f_rate value */
+       f_rate = 7 - framerate;
+       RESTRICT_TO_RANGE(f_rate, 0, 7);
+
+       ibmcam_veio(uvd, 0, 0x0000, 0x0100);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
+       ibmcam_veio(uvd, 0, 0x0000, 0x0123);
+       ibmcam_veio(uvd, 0, 0x0001, 0x0117);
+       ibmcam_veio(uvd, 0, 0x0040, 0x0108);
+       ibmcam_veio(uvd, 0, 0x0019, 0x012c);
+       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
+       ibmcam_veio(uvd, 0, 0x0002, 0x0115);
+       ibmcam_veio(uvd, 0, 0x0003, 0x0115);
+       ibmcam_veio(uvd, 1, 0x0000, 0x0115);
+       ibmcam_veio(uvd, 0, 0x000b, 0x0115);
+       ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
+       ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
+       ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
+       ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
+       ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
+       ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
+       ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
+       ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
+       ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
+       ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
+       ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
+       ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
+       ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
+       ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
+       ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
+       ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
+       ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
+       ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
+       ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
+       ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
+       ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
+       ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
+       ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
+       ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
+       ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
+       ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
+       ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
+       ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
+       ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
+       ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
+       ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
+       ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
+       ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
+       ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
+       ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
+       ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
+       ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
+               ibmcam_veio(uvd, 0, 0x0016, 0x011b);
+               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               ibmcam_veio(uvd, 0, 0x0018, 0x0102);
+               ibmcam_veio(uvd, 0, 0x0004, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
+               ibmcam_veio(uvd, 0, 0x0028, 0x011c);
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0118);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
+               ibmcam_veio(uvd, 0, 0x0000, 0x011e);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               /* 4 commands from 160x120 skipped */
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
+               ibmcam_veio(uvd, 0, 0x0006, 0x011b);
+               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0010, 0x0104);
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
+               ibmcam_veio(uvd, 0, 0x003f, 0x011c);
+               ibmcam_veio(uvd, 0, 0x001c, 0x0118);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
+               break;
+       case VIDEOSIZE_640x480:
+               ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
+               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
+               ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
+               ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
+               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
+               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
+               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
+               ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
+               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
+               ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
+               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
+               ibmcam_veio(uvd, 0, compression, 0x0109);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0101);
+               ibmcam_veio(uvd, 0, 0x0040, 0x0103);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
+               break;
+       }
+       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);     /* Hue */
+       ibmcam_model3_Packet1(uvd, 0x0036, 0x0011);     /* Brightness */
+       ibmcam_model3_Packet1(uvd, 0x0060, 0x0002);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0061, 0x0004);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0062, 0x0005);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0063, 0x0014);     /* Sharpness */
+       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
+       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
+       ibmcam_model3_Packet1(uvd, 0x0067, 0x0001);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x005b, 0x000c);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x005c, 0x0016);     /* Contrast */
+       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x002c, 0x0003);     /* Was 1, broke 640x480 */
+       ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
+       ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
+       ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
+       ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
+       ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
+       ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
+       ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
+       ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
+       ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
+       ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
+       ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
+       ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
+       ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
+       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
+       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
+       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
+       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
+
+       switch (uvd->videosize) {
+       case VIDEOSIZE_160x120:
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0107);
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
+               break;
+       case VIDEOSIZE_320x240:
+               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
+               ibmcam_veio(uvd, 0, 0x0062, 0x0107);
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
+               break;
+       case VIDEOSIZE_640x480:
+               ibmcam_veio(uvd, 0, 0x0002, 0x0106);    /* Adjustments */
+               ibmcam_veio(uvd, 0, 0x00b4, 0x0107);    /* Adjustments */
+               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
+               ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
+               ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
+               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
+               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
+               break;
+       }
+
+       /* 01.01.08 - Added for RCA video in support -LO */
+       if(init_model3_input) {
+               if (debug > 0)
+                       info("Setting input to RCA.");
+               for (i=0; i < ARRAY_SIZE(initData); i++) {
+                       ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
+               }
+       }
+
+       ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+}
+
+/*
+ * ibmcam_video_stop()
+ *
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
+ */
+static void ibmcam_video_stop(struct uvd *uvd)
+{
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_veio(uvd, 0, 0x01, 0x0114);
+               ibmcam_veio(uvd, 0, 0xc0, 0x010c);
+               ibmcam_veio(uvd, 0, 0x00, 0x010c);
+               ibmcam_send_FF_04_02(uvd);
+               ibmcam_veio(uvd, 1, 0x00, 0x0100);
+               ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
+               break;
+       case IBMCAM_MODEL_2:
+case IBMCAM_MODEL_4:
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop the camera */
+
+               ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
+
+               ibmcam_veio(uvd, 0, 0x0080, 0x0100);    /* LED Off */
+               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
+               ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
+
+               ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
+
+               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
+               break;
+       case IBMCAM_MODEL_3:
+#if 1
+               ibmcam_veio(uvd, 0, 0x0000, 0x010c);
+
+               /* Here we are supposed to select video interface alt. setting 0 */
+               ibmcam_veio(uvd, 0, 0x0006, 0x012c);
+
+               ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
+
+               ibmcam_veio(uvd, 1, 0x0000, 0x0116);
+               ibmcam_veio(uvd, 0, 0x0064, 0x0116);
+               ibmcam_veio(uvd, 1, 0x0000, 0x0115);
+               ibmcam_veio(uvd, 0, 0x0003, 0x0115);
+               ibmcam_veio(uvd, 0, 0x0008, 0x0123);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0117);
+               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
+               ibmcam_veio(uvd, 0, 0x0080, 0x0100);
+               IBMCAM_T(uvd)->initialized = 0;
+#endif
+               break;
+       } /* switch */
+}
+
+/*
+ * ibmcam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
+{
+       switch (IBMCAM_T(uvd)->camera_model) {
+       case IBMCAM_MODEL_1:
+               if (do_stop)
+                       ibmcam_video_stop(uvd);
+               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
+               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
+               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
+               ibmcam_model1_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_2:
+               ibmcam_model2_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_3:
+               ibmcam_video_stop(uvd);
+               ibmcam_model3_setup_after_video_if(uvd);
+               break;
+       case IBMCAM_MODEL_4:
+               ibmcam_model4_setup_after_video_if(uvd);
+               break;
+       }
+}
+
+static void ibmcam_video_start(struct uvd *uvd)
+{
+       ibmcam_change_lighting_conditions(uvd);
+       ibmcam_set_sharpness(uvd);
+       ibmcam_reinit_iso(uvd, 0);
+}
+
+/*
+ * Return negative code on failure, 0 on success.
+ */
+static int ibmcam_setup_on_open(struct uvd *uvd)
+{
+       int setup_ok = 0; /* Success by default */
+       /* Send init sequence only once, it's large! */
+       if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
+               switch (IBMCAM_T(uvd)->camera_model) {
+               case IBMCAM_MODEL_1:
+                       setup_ok = ibmcam_model1_setup(uvd);
+                       break;
+               case IBMCAM_MODEL_2:
+                       setup_ok = ibmcam_model2_setup(uvd);
+                       break;
+               case IBMCAM_MODEL_3:
+               case IBMCAM_MODEL_4:
+                       /* We do all setup when Isoc stream is requested */
+                       break;
+               }
+               IBMCAM_T(uvd)->initialized = (setup_ok != 0);
+       }
+       return setup_ok;
+}
+
+static void ibmcam_configure_video(struct uvd *uvd)
+{
+       if (uvd == NULL)
+               return;
+
+       RESTRICT_TO_RANGE(init_brightness, 0, 255);
+       RESTRICT_TO_RANGE(init_contrast, 0, 255);
+       RESTRICT_TO_RANGE(init_color, 0, 255);
+       RESTRICT_TO_RANGE(init_hue, 0, 255);
+       RESTRICT_TO_RANGE(hue_correction, 0, 255);
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = init_color << 8;
+       uvd->vpic.hue = init_hue << 8;
+       uvd->vpic.brightness = init_brightness << 8;
+       uvd->vpic.contrast = init_contrast << 8;
+       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "IBM USB Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
+       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
+       uvd->vcap.minwidth = min_canvasWidth;
+       uvd->vcap.minheight = min_canvasHeight;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+}
+
+/*
+ * ibmcam_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like IBM C-it camera.
+ *
+ * History:
+ * 22-Jan-2000 Moved camera init code to ibmcam_open()
+ * 27=Jan-2000 Changed to use static structures, added locking.
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ * 03-Jul-2000 Fixed endianness bug.
+ * 12-Nov-2000 Reworked to comply with new probe() signature.
+ * 23-Jan-2001 Added compatibility with 2.2.x kernels.
+ */
+static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct uvd *uvd = NULL;
+       int ix, i, nas, model=0, canvasX=0, canvasY=0;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
+       unsigned char video_ep = 0;
+
+       if (debug >= 1)
+               info("ibmcam_probe(%p,%u.)", intf, ifnum);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       /* Check the version/revision */
+       switch (le16_to_cpu(dev->descriptor.bcdDevice)) {
+       case 0x0002:
+               if (ifnum != 2)
+                       return -ENODEV;
+               model = IBMCAM_MODEL_1;
+               break;
+       case 0x030A:
+               if (ifnum != 0)
+                       return -ENODEV;
+               if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) ||
+                   (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID))
+                       model = IBMCAM_MODEL_4;
+               else
+                       model = IBMCAM_MODEL_2;
+               break;
+       case 0x0301:
+               if (ifnum != 0)
+                       return -ENODEV;
+               model = IBMCAM_MODEL_3;
+               break;
+       default:
+               err("IBM camera with revision 0x%04x is not supported.",
+                       le16_to_cpu(dev->descriptor.bcdDevice));
+               return -ENODEV;
+       }
+
+       /* Print detailed info on what we found so far */
+       do {
+               char *brand = NULL;
+               switch (le16_to_cpu(dev->descriptor.idProduct)) {
+               case NETCAM_PRODUCT_ID:
+                       brand = "IBM NetCamera";
+                       break;
+               case VEO_800C_PRODUCT_ID:
+                       brand = "Veo Stingray [800C]";
+                       break;
+               case VEO_800D_PRODUCT_ID:
+                       brand = "Veo Stingray [800D]";
+                       break;
+               case IBMCAM_PRODUCT_ID:
+               default:
+                       brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
+                       break;
+               }
+               info("%s USB camera found (model %d, rev. 0x%04x)",
+                    brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
+       } while (0);
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = intf->num_altsetting;
+       if (debug > 0)
+               info("Number of alternate settings=%d.", nas);
+       if (nas < 2) {
+               err("Too few alternate settings for this camera!");
+               return -ENODEV;
+       }
+       /* Validate all alternate settings */
+       for (ix=0; ix < nas; ix++) {
+               const struct usb_host_interface *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &intf->altsetting[ix];
+               i = interface->desc.bAlternateSetting;
+               if (interface->desc.bNumEndpoints != 1) {
+                       err("Interface %d. has %u. endpoints!",
+                           ifnum, (unsigned)(interface->desc.bNumEndpoints));
+                       return -ENODEV;
+               }
+               endpoint = &interface->endpoint[0].desc;
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return -ENODEV;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!", ifnum);
+                       return -ENODEV;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!", ifnum);
+                       return -ENODEV;
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return -ENODEV;
+                       }
+               } else {
+                       if (actInterface < 0) {
+                               actInterface = i;
+                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+                               if (debug > 0)
+                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                       } else
+                               err("More than one active alt. setting! Ignoring #%d.", i);
+               }
+       }
+       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
+               err("Failed to recognize the camera!");
+               return -ENODEV;
+       }
+
+       /* Validate options */
+       switch (model) {
+       case IBMCAM_MODEL_1:
+               RESTRICT_TO_RANGE(lighting, 0, 2);
+               RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
+               if (framerate < 0)
+                       framerate = 2;
+               canvasX = 352;
+               canvasY = 288;
+               break;
+       case IBMCAM_MODEL_2:
+               RESTRICT_TO_RANGE(lighting, 0, 15);
+               RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
+               if (framerate < 0)
+                       framerate = 2;
+               canvasX = 352;
+               canvasY = 240;
+               break;
+       case IBMCAM_MODEL_3:
+               RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
+               switch (size) {
+               case SIZE_160x120:
+                       canvasX = 160;
+                       canvasY = 120;
+                       if (framerate < 0)
+                               framerate = 2;
+                       RESTRICT_TO_RANGE(framerate, 0, 5);
+                       break;
+               default:
+                       info("IBM camera: using 320x240");
+                       size = SIZE_320x240;
+                       /* No break here */
+               case SIZE_320x240:
+                       canvasX = 320;
+                       canvasY = 240;
+                       if (framerate < 0)
+                               framerate = 3;
+                       RESTRICT_TO_RANGE(framerate, 0, 5);
+                       break;
+               case SIZE_640x480:
+                       canvasX = 640;
+                       canvasY = 480;
+                       framerate = 0;  /* Slowest, and maybe even that is too fast */
+                       break;
+               }
+               break;
+       case IBMCAM_MODEL_4:
+               RESTRICT_TO_RANGE(lighting, 0, 2);
+               switch (size) {
+               case SIZE_128x96:
+                       canvasX = 128;
+                       canvasY = 96;
+                       break;
+               case SIZE_160x120:
+                       canvasX = 160;
+                       canvasY = 120;
+                       break;
+               default:
+                       info("IBM NetCamera: using 176x144");
+                       size = SIZE_176x144;
+                       /* No break here */
+               case SIZE_176x144:
+                       canvasX = 176;
+                       canvasY = 144;
+                       break;
+               case SIZE_320x240:
+                       canvasX = 320;
+                       canvasY = 240;
+                       break;
+               case SIZE_352x288:
+                       canvasX = 352;
+                       canvasY = 288;
+                       break;
+               }
+               break;
+       default:
+               err("IBM camera: Model %d. not supported!", model);
+               return -ENODEV;
+       }
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               /* Here uvd is a fully allocated uvd object */
+               uvd->flags = flags;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = ifnum;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+               uvd->canvas = VIDEOSIZE(canvasX, canvasY);
+               uvd->videosize = ibmcam_size_to_videosize(size);
+
+               /* Initialize ibmcam-specific data */
+               assert(IBMCAM_T(uvd) != NULL);
+               IBMCAM_T(uvd)->camera_model = model;
+               IBMCAM_T(uvd)->initialized = 0;
+
+               ibmcam_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+       }
+       usb_set_intfdata (intf, uvd);
+       return 0;
+}
+
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },        /* Model 1 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 2 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },        /* Model 3 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 4 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 2 */
+       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 4 */
+       { }  /* Terminating entry */
+};
+
+/*
+ * ibmcam_init()
+ *
+ * This code is run to initialize the driver.
+ *
+ * History:
+ * 1/27/00  Reworked to use statically allocated ibmcam structures.
+ * 21/10/00 Completely redesigned to use usbvideo services.
+ */
+static int __init ibmcam_init(void)
+{
+       struct usbvideo_cb cbTbl;
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = ibmcam_probe;
+       cbTbl.setupOnOpen = ibmcam_setup_on_open;
+       cbTbl.videoStart = ibmcam_video_start;
+       cbTbl.videoStop = ibmcam_video_stop;
+       cbTbl.processData = ibmcam_ProcessIsocData;
+       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+       cbTbl.adjustPicture = ibmcam_adjust_picture;
+       cbTbl.getFPS = ibmcam_calculate_fps;
+       return usbvideo_register(
+               &cams,
+               MAX_IBMCAM,
+               sizeof(ibmcam_t),
+               "ibmcam",
+               &cbTbl,
+               THIS_MODULE,
+               id_table);
+}
+
+static void __exit ibmcam_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+module_init(ibmcam_init);
+module_exit(ibmcam_cleanup);
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
new file mode 100644 (file)
index 0000000..e2ede58
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ * konicawc.c - konica webcam driver
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ * Driver for USB webcams based on Konica chipset. This
+ * chipset is used in Intel YC76 camera.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb_input.h>
+
+#include "usbvideo.h"
+
+#define MAX_BRIGHTNESS 108
+#define MAX_CONTRAST   108
+#define MAX_SATURATION 108
+#define MAX_SHARPNESS  108
+#define MAX_WHITEBAL   372
+#define MAX_SPEED      6
+
+
+#define MAX_CAMERAS    1
+
+#define DRIVER_VERSION "v1.4"
+#define DRIVER_DESC    "Konica Webcam driver"
+
+enum ctrl_req {
+       SetWhitebal     = 0x01,
+       SetBrightness   = 0x02,
+        SetSharpness   = 0x03,
+       SetContrast     = 0x04,
+       SetSaturation   = 0x05,
+};
+
+
+enum frame_sizes {
+       SIZE_160X120    = 0,
+       SIZE_160X136    = 1,
+       SIZE_176X144    = 2,
+       SIZE_320X240    = 3,
+       
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+static struct usbvideo *cams;
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+       if (n <= debug) {        \
+               printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+       }
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+
+/* Some default values for initial camera settings,
+   can be set by modprobe */
+
+static int size;       
+static int speed = 6;          /* Speed (fps) 0 (slowest) to 6 (fastest) */
+static int brightness =        MAX_BRIGHTNESS/2;
+static int contrast =  MAX_CONTRAST/2;
+static int saturation =        MAX_SATURATION/2;
+static int sharpness = MAX_SHARPNESS/2;
+static int whitebal =  3*(MAX_WHITEBAL/4);
+
+static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
+
+/* These FPS speeds are from the windows config box. They are
+ * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
+ * real fps.
+ */
+
+static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+                              { 24, 40, 48, 60, 72, 80, 100 },
+                              { 18, 30, 36, 45, 54, 60, 75  },
+                              { 6,  10, 12, 15, 18, 21, 25  } };
+
+struct cam_size {
+       u16     width;
+       u16     height;
+       u8      cmd;
+};
+
+static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
+                                         { 160, 136, 0xa },
+                                         { 176, 144, 0x4 },
+                                         { 320, 240, 0x5 } };
+
+struct konicawc {
+       u8 brightness;          /* camera uses 0 - 9, x11 for real value */
+       u8 contrast;            /* as above */
+       u8 saturation;          /* as above */
+       u8 sharpness;           /* as above */
+       u8 white_bal;           /* 0 - 33, x11 for real value */
+       u8 speed;               /* Stored as 0 - 6, used as index in spd_to_* (above) */
+       u8 size;                /* Frame Size */
+       int height;
+       int width;
+       struct urb *sts_urb[USBVIDEO_NUMSBUF];
+       u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
+       struct urb *last_data_urb;
+       int lastframe;
+       int cur_frame_size;     /* number of bytes in current frame size */
+       int maxline;            /* number of lines per frame */
+       int yplanesz;           /* Number of bytes in the Y plane */
+       unsigned int buttonsts:1;
+#ifdef CONFIG_INPUT
+       struct input_dev *input;
+       char input_physname[64];
+#endif
+};
+
+
+#define konicawc_set_misc(uvd, req, value, index)              konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
+#define konicawc_get_misc(uvd, req, value, index, buf, sz)     konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
+#define konicawc_set_value(uvd, value, index)                  konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
+
+
+static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
+{
+        int retval = usb_control_msg(uvd->dev,
+               dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
+                   request, 0x40 | dir, value, index, buf, len, 1000);
+        return retval < 0 ? retval : 0;
+}
+
+
+static inline void konicawc_camera_on(struct uvd *uvd)
+{
+        DEBUG(0, "camera on");
+        konicawc_set_misc(uvd, 0x2, 1, 0x0b);
+}
+
+
+static inline void konicawc_camera_off(struct uvd *uvd)
+{
+        DEBUG(0, "camera off");
+        konicawc_set_misc(uvd, 0x2, 0, 0x0b);
+}
+
+
+static void konicawc_set_camera_size(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
+       cam->width = camera_sizes[cam->size].width;
+       cam->height = camera_sizes[cam->size].height;
+       cam->yplanesz = cam->height * cam->width;
+       cam->cur_frame_size = (cam->yplanesz * 3) / 2;
+       cam->maxline = cam->yplanesz / 256;
+       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+}
+
+
+static int konicawc_setup_on_open(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+           cam->brightness * 11);
+       konicawc_set_value(uvd, cam->brightness, SetBrightness);
+       DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
+           cam->white_bal * 11);
+       konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
+       DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+           cam->contrast * 11);
+       konicawc_set_value(uvd, cam->contrast, SetContrast);
+       DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
+           cam->saturation * 11);
+       konicawc_set_value(uvd, cam->saturation, SetSaturation);
+       DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
+           cam->sharpness * 11);
+       konicawc_set_value(uvd, cam->sharpness, SetSharpness);
+       konicawc_set_camera_size(uvd);
+       cam->lastframe = -2;
+       cam->buttonsts = 0;
+       return 0;
+}
+
+
+static void konicawc_adjust_picture(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       konicawc_camera_off(uvd);
+       DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
+       uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
+       if(cam->brightness != uvd->vpic.brightness / 11) {
+          cam->brightness = uvd->vpic.brightness / 11;
+          DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
+              cam->brightness * 11);
+          konicawc_set_value(uvd, cam->brightness, SetBrightness);
+       }
+
+       DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
+       uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
+       if(cam->contrast != uvd->vpic.contrast / 11) {
+               cam->contrast = uvd->vpic.contrast / 11;
+               DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
+                   cam->contrast * 11);
+               konicawc_set_value(uvd, cam->contrast, SetContrast);
+       }
+       konicawc_camera_on(uvd);
+}
+
+#ifdef CONFIG_INPUT
+
+static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
+{
+       struct input_dev *input_dev;
+
+       usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+       strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+
+       cam->input = input_dev = input_allocate_device();
+       if (!input_dev) {
+               warn("Not enough memory for camera's input device\n");
+               return;
+       }
+
+       input_dev->name = "Konicawc snapshot button";
+       input_dev->phys = cam->input_physname;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->cdev.dev = &dev->dev;
+
+       input_dev->evbit[0] = BIT(EV_KEY);
+       input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+       input_dev->private = cam;
+
+       input_register_device(cam->input);
+}
+
+static void konicawc_unregister_input(struct konicawc *cam)
+{
+       if (cam->input) {
+               input_unregister_device(cam->input);
+               cam->input = NULL;
+       }
+}
+
+static void konicawc_report_buttonstat(struct konicawc *cam)
+{
+       if (cam->input) {
+               input_report_key(cam->input, BTN_0, cam->buttonsts);
+               input_sync(cam->input);
+       }
+}
+
+#else
+
+static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }
+static inline void konicawc_unregister_input(struct konicawc *cam) { }
+static inline void konicawc_report_buttonstat(struct konicawc *cam) { }
+
+#endif /* CONFIG_INPUT */
+
+static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
+{
+       char *cdata;
+       int i, totlen = 0;
+       unsigned char *status = stsurb->transfer_buffer;
+       int keep = 0, discard = 0, bad = 0;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       for (i = 0; i < dataurb->number_of_packets; i++) {
+               int button = cam->buttonsts;
+               unsigned char sts;
+               int n = dataurb->iso_frame_desc[i].actual_length;
+               int st = dataurb->iso_frame_desc[i].status;
+               cdata = dataurb->transfer_buffer +
+                       dataurb->iso_frame_desc[i].offset;
+
+               /* Detect and ignore errored packets */
+               if (st < 0) {
+                       DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
+                             i, n, st);
+                       uvd->stats.iso_err_count++;
+                       continue;
+               }
+
+               /* Detect and ignore empty packets */
+               if (n <= 0) {
+                       uvd->stats.iso_skip_count++;
+                       continue;
+               }
+
+               /* See what the status data said about the packet */
+               sts = *(status+stsurb->iso_frame_desc[i].offset);
+
+               /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
+                * otherwise:
+                * bit 0 0: keep packet
+                *       1: drop packet (padding data)
+                *
+                * bit 4 0 button not clicked
+                *       1 button clicked
+                * button is used to `take a picture' (in software)
+                */
+
+               if(sts < 0x80) {
+                       button = !!(sts & 0x40);
+                       sts &= ~0x40;
+               }
+               
+               /* work out the button status, but don't do
+                  anything with it for now */
+
+               if(button != cam->buttonsts) {
+                       DEBUG(2, "button: %sclicked", button ? "" : "un");
+                       cam->buttonsts = button;
+                       konicawc_report_buttonstat(cam);
+               }
+
+               if(sts == 0x01) { /* drop frame */
+                       discard++;
+                       continue;
+               }
+               
+               if((sts > 0x01) && (sts < 0x80)) {
+                       info("unknown status %2.2x", sts);
+                       bad++;
+                       continue;
+               }
+               if(!sts && cam->lastframe == -2) {
+                       DEBUG(2, "dropping frame looking for image start");
+                       continue;
+               }
+
+               keep++;
+               if(sts & 0x80) { /* frame start */
+                       unsigned char marker[] = { 0, 0xff, 0, 0x00 };
+
+                       if(cam->lastframe == -2) {
+                               DEBUG(2, "found initial image");
+                               cam->lastframe = -1;
+                       }
+                               
+                       marker[3] = sts & 0x7F;
+                       RingQueue_Enqueue(&uvd->dp, marker, 4);
+                       totlen += 4;
+               }
+
+               totlen += n;    /* Little local accounting */
+               RingQueue_Enqueue(&uvd->dp, cdata, n);
+       }
+       DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
+                   keep, discard, bad, totlen);
+       return totlen;
+}
+
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+        int i, ret;
+        for (i = 0; i < FRAMES_PER_DESC; i++) {
+                urb->iso_frame_desc[i].status = 0;
+        }
+        urb->dev = uvd->dev;
+        urb->status = 0;
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
+        if(ret)
+                err("usb_submit_urb error (%d)", ret);
+
+}
+
+
+static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+       struct uvd *uvd = urb->context;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       /* We don't want to do anything if we are about to be removed! */
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return;
+
+       if (!uvd->streaming) {
+               DEBUG(1, "Not streaming, but interrupt!");
+               return;
+       }
+
+       DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
+
+       uvd->stats.urb_count++;
+
+       if (urb->transfer_buffer_length > 32) {
+               cam->last_data_urb = urb;
+               return;
+       }
+       /* Copy the data received into ring queue */
+       if(cam->last_data_urb) {
+               int len = 0;
+               if(urb->start_frame != cam->last_data_urb->start_frame)
+                       err("Lost sync on frames");
+               else if (!urb->status && !cam->last_data_urb->status)
+                       len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
+
+               resubmit_urb(uvd, cam->last_data_urb);
+               resubmit_urb(uvd, urb);
+               cam->last_data_urb = NULL;
+               uvd->stats.urb_length = len;
+               uvd->stats.data_count += len;
+               if(len)
+                       RingQueue_WakeUpInterruptible(&uvd->dp);
+               return;
+       }
+       return;
+}
+
+
+static int konicawc_start_data(struct uvd *uvd)
+{
+       struct usb_device *dev = uvd->dev;
+       int i, errFlag;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       int pktsz;
+       struct usb_interface *intf;
+       struct usb_host_interface *interface = NULL;
+
+       intf = usb_ifnum_to_if(dev, uvd->iface);
+       if (intf)
+               interface = usb_altnum_to_altsetting(intf,
+                               spd_to_iface[cam->speed]);
+       if (!interface)
+               return -ENXIO;
+       pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize);
+       DEBUG(1, "pktsz = %d", pktsz);
+       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+               err("Camera is not operational");
+               return -EFAULT;
+       }
+       uvd->curframe = -1;
+       konicawc_camera_on(uvd);
+       /* Alternate interface 1 is is the biggest frame size */
+       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
+       if (i < 0) {
+               err("usb_set_interface error");
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+
+       /* We double buffer the Iso lists */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               int j, k;
+               struct urb *urb = uvd->sbuf[i].urb;
+               urb->dev = dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = uvd->sbuf[i].data;
+               urb->complete = konicawc_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+               for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = pktsz;
+               }
+
+               urb = cam->sts_urb[i];
+               urb->dev = dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = cam->sts_buf[i];
+               urb->complete = konicawc_isoc_irq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = FRAMES_PER_DESC;
+               for (j=0; j < FRAMES_PER_DESC; j++) {
+                       urb->iso_frame_desc[j].offset = j;
+                       urb->iso_frame_desc[j].length = 1;
+               }
+       }
+
+       cam->last_data_urb = NULL;
+       
+       /* Submit all URBs */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
+               if (errFlag)
+                       err("usb_submit_isoc(%d) ret %d", i, errFlag);
+
+               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+               if (errFlag)
+                       err ("usb_submit_isoc(%d) ret %d", i, errFlag);
+       }
+
+       uvd->streaming = 1;
+       DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
+       return 0;
+}
+
+
+static void konicawc_stop_data(struct uvd *uvd)
+{
+       int i, j;
+       struct konicawc *cam;
+
+       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+               return;
+
+       konicawc_camera_off(uvd);
+       uvd->streaming = 0;
+       cam = (struct konicawc *)uvd->user_data;
+       cam->last_data_urb = NULL;
+
+       /* Unschedule all of the iso td's */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               usb_kill_urb(uvd->sbuf[i].urb);
+               usb_kill_urb(cam->sts_urb[i]);
+       }
+
+       if (!uvd->remove_pending) {
+               /* Set packet size to 0 */
+               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
+               if (j < 0) {
+                       err("usb_set_interface() error %d.", j);
+                       uvd->last_error = j;
+               }
+       }
+}
+
+
+static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{      
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       int maxline = cam->maxline;
+       int yplanesz = cam->yplanesz;
+
+       assert(frame != NULL);
+
+       DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
+       DEBUG(3, "Frame state = %d", frame->scanstate);
+
+       if(frame->scanstate == ScanState_Scanning) {
+               int drop = 0;
+               int curframe;
+               int fdrops = 0;
+               DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
+               while(RingQueue_GetLength(&uvd->dp) >= 4) {
+                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+                           (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
+                               curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
+                               if(cam->lastframe >= 0) {
+                                       fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
+                                       fdrops--;
+                                       if(fdrops) {
+                                               info("Dropped %d frames (%d -> %d)", fdrops,
+                                                    cam->lastframe, curframe);
+                                       }
+                               }
+                               cam->lastframe = curframe;
+                               frame->curline = 0;
+                               frame->scanstate = ScanState_Lines;
+                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+                               break;
+                       }
+                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+                       drop++;
+               }
+               if(drop)
+                       DEBUG(2, "dropped %d bytes looking for new frame", drop);
+       }
+
+       if(frame->scanstate == ScanState_Scanning)
+               return;
+               
+       /* Try to move data from queue into frame buffer
+        * We get data in blocks of 384 bytes made up of:
+        * 256 Y, 64 U, 64 V.
+        * This needs to be written out as a Y plane, a U plane and a V plane.
+        */
+               
+       while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
+               /* Y */
+               RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
+               /* U */
+               RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
+               /* V */
+               RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
+               frame->seqRead_Length += 384;
+               frame->curline++;
+       }
+       /* See if we filled the frame */
+       if (frame->curline == maxline) {
+               DEBUG(5, "got whole frame");
+
+               frame->frameState = FrameState_Done_Hold;
+               frame->curline = 0;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+
+static int konicawc_find_fps(int size, int fps)
+{
+       int i;
+
+       fps *= 3;
+       DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
+       if(fps <= spd_to_fps[size][0])
+               return 0;
+
+       if(fps >= spd_to_fps[size][MAX_SPEED])
+               return MAX_SPEED;
+
+       for(i = 0; i < MAX_SPEED; i++) {
+               if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
+                       DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
+                       if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
+                               return i;
+                       else
+                               return i+1;
+               }
+       }
+       return MAX_SPEED+1;
+}
+
+
+static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       int newspeed = cam->speed;
+       int newsize;
+       int x = vw->width;
+       int y = vw->height;
+       int fps = vw->flags;
+
+       if(x > 0 && y > 0) {
+               DEBUG(2, "trying to find size %d,%d", x, y);
+               for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+                       if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
+                               break;
+               }
+       } else {
+               newsize = cam->size;
+       }
+
+       if(newsize > MAX_FRAME_SIZE) {
+               DEBUG(1, "couldn't find size %d,%d", x, y);
+               return -EINVAL;
+       }
+
+       if(fps > 0) {
+               DEBUG(1, "trying to set fps to %d", fps);
+               newspeed = konicawc_find_fps(newsize, fps);
+               DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
+       }
+
+       if(newspeed > MAX_SPEED)
+               return -EINVAL;
+
+       DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
+       if((newsize == cam->size) && (newspeed == cam->speed)) {
+               DEBUG(1, "Nothing to do");
+               return 0;
+       }
+       DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
+            camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
+
+       konicawc_stop_data(uvd);
+       uvd->ifaceAltActive = spd_to_iface[newspeed];
+       DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
+       cam->speed = newspeed;
+
+       if(cam->size != newsize) {
+               cam->size = newsize;
+               konicawc_set_camera_size(uvd);
+       }
+
+       /* Flush the input queue and clear any current frame in progress */
+
+       RingQueue_Flush(&uvd->dp);
+       cam->lastframe = -2;
+       if(uvd->curframe != -1) {
+               uvd->frame[uvd->curframe].curline = 0;
+               uvd->frame[uvd->curframe].seqRead_Length = 0;
+               uvd->frame[uvd->curframe].seqRead_Index = 0;
+       }
+
+       konicawc_start_data(uvd);
+       return 0;
+}
+
+
+static int konicawc_calculate_fps(struct uvd *uvd)
+{
+       struct konicawc *cam = uvd->user_data;
+       return spd_to_fps[cam->size][cam->speed]/3;
+}
+
+
+static void konicawc_configure_video(struct uvd *uvd)
+{
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+       u8 buf[2];
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
+       RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
+       RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
+       RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
+       RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
+
+       cam->brightness = brightness / 11;
+       cam->contrast = contrast / 11;
+       cam->saturation = saturation / 11;
+       cam->sharpness = sharpness / 11;
+       cam->white_bal = whitebal / 11;
+
+       uvd->vpic.colour = 108;
+       uvd->vpic.hue = 108;
+       uvd->vpic.brightness = brightness;
+       uvd->vpic.contrast = contrast;
+       uvd->vpic.whiteness = whitebal;
+       uvd->vpic.depth = 6;
+       uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "Konica Webcam");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+       uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+       uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+       uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0 ;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+
+       /* Talk to device */
+       DEBUG(1, "device init");
+       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
+               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
+       if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
+               DEBUG(2, "2,0,d failed");
+       DEBUG(1, "setting initial values");
+}
+
+static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct uvd *uvd = NULL;
+       int ix, i, nas;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       unsigned char video_ep = 0;
+
+       DEBUG(1, "konicawc_probe(%p)", intf);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice));
+       RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = intf->num_altsetting;
+       if (nas != 8) {
+               err("Incorrect number of alternate settings (%d) for this camera!", nas);
+               return -ENODEV;
+       }
+       /* Validate all alternate settings */
+       for (ix=0; ix < nas; ix++) {
+               const struct usb_host_interface *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &intf->altsetting[ix];
+               i = interface->desc.bAlternateSetting;
+               if (interface->desc.bNumEndpoints != 2) {
+                       err("Interface %d. has %u. endpoints!",
+                           interface->desc.bInterfaceNumber,
+                           (unsigned)(interface->desc.bNumEndpoints));
+                       return -ENODEV;
+               }
+               endpoint = &interface->endpoint[1].desc;
+               DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
+                   endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize));
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return -ENODEV;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return -ENODEV;
+                       }
+               } else {
+                       if (i == spd_to_iface[speed]) {
+                               /* This one is the requested one */
+                               actInterface = i;
+                       }
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS)
+                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+       }
+       if(actInterface == -1) {
+               err("Cant find required endpoint");
+               return -ENODEV;
+       }
+
+       DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               struct konicawc *cam = (struct konicawc *)(uvd->user_data);
+               /* Here uvd is a fully allocated uvd object */
+               for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
+                       cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+                       if(cam->sts_urb[i] == NULL) {
+                               while(i--) {
+                                       usb_free_urb(cam->sts_urb[i]);
+                               }
+                               err("can't allocate urbs");
+                               return -ENOMEM;
+                       }
+               }
+               cam->speed = speed;
+               RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+               cam->width = camera_sizes[size].width;
+               cam->height = camera_sizes[size].height;
+               cam->size = size;
+
+               uvd->flags = 0;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
+               uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
+               uvd->canvas = VIDEOSIZE(320, 240);
+               uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+               /* Initialize konicawc specific data */
+               konicawc_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               uvd->max_frame_size = (320 * 240 * 3)/2;
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+
+               konicawc_register_input(cam, dev);
+       }
+
+       if (uvd) {
+               usb_set_intfdata (intf, uvd);
+               return 0;
+       }
+       return -EIO;
+}
+
+
+static void konicawc_free_uvd(struct uvd *uvd)
+{
+       int i;
+       struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+       konicawc_unregister_input(cam);
+
+       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
+               usb_free_urb(cam->sts_urb[i]);
+               cam->sts_urb[i] = NULL;
+       }
+}
+
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
+       { }  /* Terminating entry */
+};
+
+
+static int __init konicawc_init(void)
+{
+       struct usbvideo_cb cbTbl;
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = konicawc_probe;
+       cbTbl.setupOnOpen = konicawc_setup_on_open;
+       cbTbl.processData = konicawc_process_isoc;
+       cbTbl.getFPS = konicawc_calculate_fps;
+       cbTbl.setVideoMode = konicawc_set_video_mode;
+       cbTbl.startDataPump = konicawc_start_data;
+       cbTbl.stopDataPump = konicawc_stop_data;
+       cbTbl.adjustPicture = konicawc_adjust_picture;
+       cbTbl.userFree = konicawc_free_uvd;
+       return usbvideo_register(
+               &cams,
+               MAX_CAMERAS,
+               sizeof(struct konicawc),
+               "konicawc",
+               &cbTbl,
+               THIS_MODULE,
+               id_table);
+}
+
+
+static void __exit konicawc_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+module_param(speed, int, 0);
+MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
+module_param(saturation, int, 0);
+MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
+module_param(sharpness, int, 0);
+MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
+module_param(whitebal, int, 0);
+MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(konicawc_init);
+module_exit(konicawc_cleanup);
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
new file mode 100644 (file)
index 0000000..75ff755
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * USB NB Camera driver
+ *
+ * HISTORY:
+ * 25-Dec-2002 Dmitri      Removed lighting, sharpness parameters, methods.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include "usbvideo.h"
+
+#define        ULTRACAM_VENDOR_ID      0x0461
+#define        ULTRACAM_PRODUCT_ID     0x0813
+
+#define MAX_CAMERAS            4       /* How many devices we allow to connect */
+
+/*
+ * This structure lives in uvd_t->user field.
+ */
+typedef struct {
+       int initialized;        /* Had we already sent init sequence? */
+       int camera_model;       /* What type of IBM camera we got? */
+        int has_hdr;
+} ultracam_t;
+#define        ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
+
+static struct usbvideo *cams = NULL;
+
+static int debug = 0;
+
+static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+static const int min_canvasWidth  = 8;
+static const int min_canvasHeight = 4;
+
+#define FRAMERATE_MIN  0
+#define FRAMERATE_MAX  6
+static int framerate = -1;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+static int hue_correction = 128;
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+module_param(flags, int, 0);
+MODULE_PARM_DESC(flags,
+               "Bitfield: 0=VIDIOCSYNC, "
+               "1=B/W, "
+               "2=show hints, "
+               "3=show stats, "
+               "4=test pattern, "
+               "5=separate frames, "
+               "6=clean frames");
+module_param(framerate, int, 0);
+MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
+
+module_param(init_brightness, int, 0);
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
+module_param(init_contrast, int, 0);
+MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
+module_param(init_color, int, 0);
+MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
+module_param(init_hue, int, 0);
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
+module_param(hue_correction, int, 0);
+MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
+
+/*
+ * ultracam_ProcessIsocData()
+ *
+ * Generic routine to parse the ring queue data. It employs either
+ * ultracam_find_header() or ultracam_parse_lines() to do most
+ * of work.
+ *
+ * 02-Nov-2000 First (mostly dummy) version.
+ * 06-Nov-2000 Rewrote to dump all data into frame.
+ */
+static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       int n;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+
+       /* Try to move data from queue into frame buffer */
+       n = RingQueue_GetLength(&uvd->dp);
+       if (n > 0) {
+               int m;
+               /* See how much spare we have left */
+               m = uvd->max_frame_size - frame->seqRead_Length;
+               if (n > m)
+                       n = m;
+               /* Now move that much data into frame buffer */
+               RingQueue_Dequeue(
+                       &uvd->dp,
+                       frame->data + frame->seqRead_Length,
+                       m);
+               frame->seqRead_Length += m;
+       }
+       /* See if we filled the frame */
+       if (frame->seqRead_Length >= uvd->max_frame_size) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+/*
+ * ultracam_veio()
+ *
+ * History:
+ * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
+ */
+static int ultracam_veio(
+       struct uvd *uvd,
+       unsigned char req,
+       unsigned short value,
+       unsigned short index,
+       int is_out)
+{
+       static const char proc[] = "ultracam_veio";
+       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+       int i;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return 0;
+
+       if (!is_out) {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_rcvctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       cp,
+                       sizeof(cp),
+                       1000);
+#if 1
+               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+                      "(req=$%02x val=$%04x ind=$%04x)",
+                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+                      req, value, index);
+#endif
+       } else {
+               i = usb_control_msg(
+                       uvd->dev,
+                       usb_sndctrlpipe(uvd->dev, 0),
+                       req,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value,
+                       index,
+                       NULL,
+                       0,
+                       1000);
+       }
+       if (i < 0) {
+               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
+                   proc, i);
+               uvd->last_error = i;
+       }
+       return i;
+}
+
+/*
+ * ultracam_calculate_fps()
+ */
+static int ultracam_calculate_fps(struct uvd *uvd)
+{
+       return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * ultracam_adjust_contrast()
+ */
+static void ultracam_adjust_contrast(struct uvd *uvd)
+{
+}
+
+/*
+ * ultracam_set_brightness()
+ *
+ * This procedure changes brightness of the picture.
+ */
+static void ultracam_set_brightness(struct uvd *uvd)
+{
+}
+
+static void ultracam_set_hue(struct uvd *uvd)
+{
+}
+
+/*
+ * ultracam_adjust_picture()
+ *
+ * This procedure gets called from V4L interface to update picture settings.
+ * Here we change brightness and contrast.
+ */
+static void ultracam_adjust_picture(struct uvd *uvd)
+{
+       ultracam_adjust_contrast(uvd);
+       ultracam_set_brightness(uvd);
+       ultracam_set_hue(uvd);
+}
+
+/*
+ * ultracam_video_stop()
+ *
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
+ */
+static void ultracam_video_stop(struct uvd *uvd)
+{
+}
+
+/*
+ * ultracam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ */
+static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
+{
+}
+
+static void ultracam_video_start(struct uvd *uvd)
+{
+       ultracam_reinit_iso(uvd, 0);
+}
+
+static int ultracam_resetPipe(struct uvd *uvd)
+{
+       usb_clear_halt(uvd->dev, uvd->video_endp);
+       return 0;
+}
+
+static int ultracam_alternateSetting(struct uvd *uvd, int setting)
+{
+       static const char proc[] = "ultracam_alternateSetting";
+       int i;
+       i = usb_set_interface(uvd->dev, uvd->iface, setting);
+       if (i < 0) {
+               err("%s: usb_set_interface error", proc);
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+       return 0;
+}
+
+/*
+ * Return negative code on failure, 0 on success.
+ */
+static int ultracam_setup_on_open(struct uvd *uvd)
+{
+       int setup_ok = 0; /* Success by default */
+       /* Send init sequence only once, it's large! */
+       if (!ULTRACAM_T(uvd)->initialized) {
+               ultracam_alternateSetting(uvd, 0x04);
+               ultracam_alternateSetting(uvd, 0x00);
+               ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
+               ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
+               ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
+               ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
+               ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
+               ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
+               ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
+               ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
+               ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
+               ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
+               ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
+               ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
+               ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
+               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
+               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
+               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
+               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
+               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
+               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
+               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
+               ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
+               ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
+               ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
+               ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
+               ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
+               ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
+               ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
+               ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
+               ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
+               ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
+               ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
+               ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
+               ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
+               ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
+               ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
+               ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
+               ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
+               ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
+               ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
+               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
+               ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
+               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
+               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
+               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
+               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
+               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
+               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
+               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
+               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
+               ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
+               ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
+               ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
+               ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
+               ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
+               ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
+               ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
+               ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
+               ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
+               ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
+               ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
+               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
+               ultracam_alternateSetting(uvd, 0x04);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
+               ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
+               ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
+               ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
+               ultracam_resetPipe(uvd);
+               ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
+       }
+       return setup_ok;
+}
+
+static void ultracam_configure_video(struct uvd *uvd)
+{
+       if (uvd == NULL)
+               return;
+
+       RESTRICT_TO_RANGE(init_brightness, 0, 255);
+       RESTRICT_TO_RANGE(init_contrast, 0, 255);
+       RESTRICT_TO_RANGE(init_color, 0, 255);
+       RESTRICT_TO_RANGE(init_hue, 0, 255);
+       RESTRICT_TO_RANGE(hue_correction, 0, 255);
+
+       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+       uvd->vpic.colour = init_color << 8;
+       uvd->vpic.hue = init_hue << 8;
+       uvd->vpic.brightness = init_brightness << 8;
+       uvd->vpic.contrast = init_contrast << 8;
+       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
+       uvd->vpic.depth = 24;
+       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+       strcpy(uvd->vcap.name, "IBM Ultra Camera");
+       uvd->vcap.type = VID_TYPE_CAPTURE;
+       uvd->vcap.channels = 1;
+       uvd->vcap.audios = 0;
+       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
+       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
+       uvd->vcap.minwidth = min_canvasWidth;
+       uvd->vcap.minheight = min_canvasHeight;
+
+       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+       uvd->vchan.flags = 0;
+       uvd->vchan.tuners = 0;
+       uvd->vchan.channel = 0;
+       uvd->vchan.type = VIDEO_TYPE_CAMERA;
+       strcpy(uvd->vchan.name, "Camera");
+}
+
+/*
+ * ultracam_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like our camera.
+ *
+ * History:
+ * 12-Nov-2000 Reworked to comply with new probe() signature.
+ * 23-Jan-2001 Added compatibility with 2.2.x kernels.
+ */
+static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct uvd *uvd = NULL;
+       int ix, i, nas;
+       int actInterface=-1, inactInterface=-1, maxPS=0;
+       unsigned char video_ep = 0;
+
+       if (debug >= 1)
+               info("ultracam_probe(%p)", intf);
+
+       /* We don't handle multi-config cameras */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -ENODEV;
+
+       info("IBM Ultra camera found (rev. 0x%04x)",
+               le16_to_cpu(dev->descriptor.bcdDevice));
+
+       /* Validate found interface: must have one ISO endpoint */
+       nas = intf->num_altsetting;
+       if (debug > 0)
+               info("Number of alternate settings=%d.", nas);
+       if (nas < 8) {
+               err("Too few alternate settings for this camera!");
+               return -ENODEV;
+       }
+       /* Validate all alternate settings */
+       for (ix=0; ix < nas; ix++) {
+               const struct usb_host_interface *interface;
+               const struct usb_endpoint_descriptor *endpoint;
+
+               interface = &intf->altsetting[ix];
+               i = interface->desc.bAlternateSetting;
+               if (interface->desc.bNumEndpoints != 1) {
+                       err("Interface %d. has %u. endpoints!",
+                           interface->desc.bInterfaceNumber,
+                           (unsigned)(interface->desc.bNumEndpoints));
+                       return -ENODEV;
+               }
+               endpoint = &interface->endpoint[0].desc;
+               if (video_ep == 0)
+                       video_ep = endpoint->bEndpointAddress;
+               else if (video_ep != endpoint->bEndpointAddress) {
+                       err("Alternate settings have different endpoint addresses!");
+                       return -ENODEV;
+               }
+               if ((endpoint->bmAttributes & 0x03) != 0x01) {
+                       err("Interface %d. has non-ISO endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if ((endpoint->bEndpointAddress & 0x80) == 0) {
+                       err("Interface %d. has ISO OUT endpoint!",
+                           interface->desc.bInterfaceNumber);
+                       return -ENODEV;
+               }
+               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
+                       if (inactInterface < 0)
+                               inactInterface = i;
+                       else {
+                               err("More than one inactive alt. setting!");
+                               return -ENODEV;
+                       }
+               } else {
+                       if (actInterface < 0) {
+                               actInterface = i;
+                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+                               if (debug > 0)
+                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
+                       } else {
+                               /* Got another active alt. setting */
+                               if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
+                                       /* This one is better! */
+                                       actInterface = i;
+                                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
+                                       if (debug > 0) {
+                                               info("Even better ctive setting=%d. maxPS=%d.",
+                                                    i, maxPS);
+                                       }
+                               }
+                       }
+               }
+       }
+       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
+               err("Failed to recognize the camera!");
+               return -ENODEV;
+       }
+
+       uvd = usbvideo_AllocateDevice(cams);
+       if (uvd != NULL) {
+               /* Here uvd is a fully allocated uvd object */
+               uvd->flags = flags;
+               uvd->debug = debug;
+               uvd->dev = dev;
+               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+               uvd->ifaceAltInactive = inactInterface;
+               uvd->ifaceAltActive = actInterface;
+               uvd->video_endp = video_ep;
+               uvd->iso_packet_len = maxPS;
+               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+               uvd->canvas = VIDEOSIZE(640, 480);      /* FIXME */
+               uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
+
+               /* Initialize ibmcam-specific data */
+               assert(ULTRACAM_T(uvd) != NULL);
+               ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
+               ULTRACAM_T(uvd)->initialized = 0;
+
+               ultracam_configure_video(uvd);
+
+               i = usbvideo_RegisterVideoDevice(uvd);
+               if (i != 0) {
+                       err("usbvideo_RegisterVideoDevice() failed.");
+                       uvd = NULL;
+               }
+       }
+
+       if (uvd) {
+               usb_set_intfdata (intf, uvd);
+               return 0;
+       }
+       return -EIO;
+}
+
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
+       { }  /* Terminating entry */
+};
+
+/*
+ * ultracam_init()
+ *
+ * This code is run to initialize the driver.
+ */
+static int __init ultracam_init(void)
+{
+       struct usbvideo_cb cbTbl;
+       memset(&cbTbl, 0, sizeof(cbTbl));
+       cbTbl.probe = ultracam_probe;
+       cbTbl.setupOnOpen = ultracam_setup_on_open;
+       cbTbl.videoStart = ultracam_video_start;
+       cbTbl.videoStop = ultracam_video_stop;
+       cbTbl.processData = ultracam_ProcessIsocData;
+       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
+       cbTbl.adjustPicture = ultracam_adjust_picture;
+       cbTbl.getFPS = ultracam_calculate_fps;
+       return usbvideo_register(
+               &cams,
+               MAX_CAMERAS,
+               sizeof(ultracam_t),
+               "ultracam",
+               &cbTbl,
+               THIS_MODULE,
+               id_table);
+}
+
+static void __exit ultracam_cleanup(void)
+{
+       usbvideo_Deregister(&cams);
+}
+
+MODULE_DEVICE_TABLE(usb, id_table);
+MODULE_LICENSE("GPL");
+
+module_init(ultracam_init);
+module_exit(ultracam_cleanup);
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
new file mode 100644 (file)
index 0000000..0b51fae
--- /dev/null
@@ -0,0 +1,2190 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+
+#include "usbvideo.h"
+
+#if defined(MAP_NR)
+#define        virt_to_page(v) MAP_NR(v)       /* Kernels 2.2.x */
+#endif
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+
+/*
+ * Local prototypes.
+ */
+static void usbvideo_Disconnect(struct usb_interface *intf);
+static void usbvideo_CameraRelease(struct uvd *uvd);
+
+static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, unsigned long arg);
+static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
+static int usbvideo_v4l_open(struct inode *inode, struct file *file);
+static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
+                            size_t count, loff_t *ppos);
+static int usbvideo_v4l_close(struct inode *inode, struct file *file);
+
+static int usbvideo_StartDataPump(struct uvd *uvd);
+static void usbvideo_StopDataPump(struct uvd *uvd);
+static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
+static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
+static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
+                                               struct usbvideo_frame *frame);
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+static void *usbvideo_rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void usbvideo_rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+static void RingQueue_Initialize(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       init_waitqueue_head(&rq->wqh);
+}
+
+static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
+{
+       /* Make sure the requested size is a power of 2 and
+          round up if necessary. This allows index wrapping
+          using masks rather than modulo */
+
+       int i = 1;
+       assert(rq != NULL);
+       assert(rqLen > 0);
+
+       while(rqLen >> i)
+               i++;
+       if(rqLen != 1 << (i-1))
+               rqLen = 1 << i;
+
+       rq->length = rqLen;
+       rq->ri = rq->wi = 0;
+       rq->queue = usbvideo_rvmalloc(rq->length);
+       assert(rq->queue != NULL);
+}
+
+static int RingQueue_IsAllocated(const struct RingQueue *rq)
+{
+       if (rq == NULL)
+               return 0;
+       return (rq->queue != NULL) && (rq->length > 0);
+}
+
+static void RingQueue_Free(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       if (RingQueue_IsAllocated(rq)) {
+               usbvideo_rvfree(rq->queue, rq->length);
+               rq->queue = NULL;
+               rq->length = 0;
+       }
+}
+
+int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
+{
+       int rql, toread;
+
+       assert(rq != NULL);
+       assert(dst != NULL);
+
+       rql = RingQueue_GetLength(rq);
+       if(!rql)
+               return 0;
+
+       /* Clip requested length to available data */
+       if(len > rql)
+               len = rql;
+
+       toread = len;
+       if(rq->ri > rq->wi) {
+               /* Read data from tail */
+               int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
+               memcpy(dst, rq->queue + rq->ri, read);
+               toread -= read;
+               dst += read;
+               rq->ri = (rq->ri + read) & (rq->length-1);
+       }
+       if(toread) {
+               /* Read data from head */
+               memcpy(dst, rq->queue + rq->ri, toread);
+               rq->ri = (rq->ri + toread) & (rq->length-1);
+       }
+       return len;
+}
+
+EXPORT_SYMBOL(RingQueue_Dequeue);
+
+int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
+{
+       int enqueued = 0;
+
+       assert(rq != NULL);
+       assert(cdata != NULL);
+       assert(rq->length > 0);
+       while (n > 0) {
+               int m, q_avail;
+
+               /* Calculate the largest chunk that fits the tail of the ring */
+               q_avail = rq->length - rq->wi;
+               if (q_avail <= 0) {
+                       rq->wi = 0;
+                       q_avail = rq->length;
+               }
+               m = n;
+               assert(q_avail > 0);
+               if (m > q_avail)
+                       m = q_avail;
+
+               memcpy(rq->queue + rq->wi, cdata, m);
+               RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
+               cdata += m;
+               enqueued += m;
+               n -= m;
+       }
+       return enqueued;
+}
+
+EXPORT_SYMBOL(RingQueue_Enqueue);
+
+static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       interruptible_sleep_on(&rq->wqh);
+}
+
+void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       if (waitqueue_active(&rq->wqh))
+               wake_up_interruptible(&rq->wqh);
+}
+
+EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
+
+void RingQueue_Flush(struct RingQueue *rq)
+{
+       assert(rq != NULL);
+       rq->ri = 0;
+       rq->wi = 0;
+}
+
+EXPORT_SYMBOL(RingQueue_Flush);
+
+
+/*
+ * usbvideo_VideosizeToString()
+ *
+ * This procedure converts given videosize value to readable string.
+ *
+ * History:
+ * 07-Aug-2000 Created.
+ * 19-Oct-2000 Reworked for usbvideo module.
+ */
+static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
+{
+       char tmp[40];
+       int n;
+
+       n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));
+       assert(n < sizeof(tmp));
+       if ((buf == NULL) || (bufLen < n))
+               err("usbvideo_VideosizeToString: buffer is too small.");
+       else
+               memmove(buf, tmp, n);
+}
+
+/*
+ * usbvideo_OverlayChar()
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
+                                int x, int y, int ch)
+{
+       static const unsigned short digits[16] = {
+               0xF6DE, /* 0 */
+               0x2492, /* 1 */
+               0xE7CE, /* 2 */
+               0xE79E, /* 3 */
+               0xB792, /* 4 */
+               0xF39E, /* 5 */
+               0xF3DE, /* 6 */
+               0xF492, /* 7 */
+               0xF7DE, /* 8 */
+               0xF79E, /* 9 */
+               0x77DA, /* a */
+               0xD75C, /* b */
+               0xF24E, /* c */
+               0xD6DC, /* d */
+               0xF34E, /* e */
+               0xF348  /* f */
+       };
+       unsigned short digit;
+       int ix, iy;
+
+       if ((uvd == NULL) || (frame == NULL))
+               return;
+
+       if (ch >= '0' && ch <= '9')
+               ch -= '0';
+       else if (ch >= 'A' && ch <= 'F')
+               ch = 10 + (ch - 'A');
+       else if (ch >= 'a' && ch <= 'f')
+               ch = 10 + (ch - 'a');
+       else
+               return;
+       digit = digits[ch];
+
+       for (iy=0; iy < 5; iy++) {
+               for (ix=0; ix < 3; ix++) {
+                       if (digit & 0x8000) {
+                               if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {
+/* TODO */                             RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
+                               }
+                       }
+                       digit = digit << 1;
+               }
+       }
+}
+
+/*
+ * usbvideo_OverlayString()
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
+                                  int x, int y, const char *str)
+{
+       while (*str) {
+               usbvideo_OverlayChar(uvd, frame, x, y, *str);
+               str++;
+               x += 4; /* 3 pixels character + 1 space */
+       }
+}
+
+/*
+ * usbvideo_OverlayStats()
+ *
+ * Overlays important debugging information.
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       const int y_diff = 8;
+       char tmp[16];
+       int x = 10, y=10;
+       long i, j, barLength;
+       const int qi_x1 = 60, qi_y1 = 10;
+       const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;
+
+       /* Call the user callback, see if we may proceed after that */
+       if (VALID_CALLBACK(uvd, overlayHook)) {
+               if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)
+                       return;
+       }
+
+       /*
+        * We draw a (mostly) hollow rectangle with qi_xxx coordinates.
+        * Left edge symbolizes the queue index 0; right edge symbolizes
+        * the full capacity of the queue.
+        */
+       barLength = qi_x2 - qi_x1 - 2;
+       if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {
+/* TODO */     long u_lo, u_hi, q_used;
+               long m_ri, m_wi, m_lo, m_hi;
+
+               /*
+                * Determine fill zones (used areas of the queue):
+                * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length
+                *
+                * if u_lo < 0 then there is no first filler.
+                */
+
+               q_used = RingQueue_GetLength(&uvd->dp);
+               if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
+                       u_hi = uvd->dp.length;
+                       u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
+               } else {
+                       u_hi = (q_used + uvd->dp.ri);
+                       u_lo = -1;
+               }
+
+               /* Convert byte indices into screen units */
+               m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);
+               m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);
+               m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;
+               m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);
+
+               for (j=qi_y1; j < (qi_y1 + qi_h); j++) {
+                       for (i=qi_x1; i < qi_x2; i++) {
+                               /* Draw border lines */
+                               if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||
+                                   (i == qi_x1) || (i == (qi_x2 - 1))) {
+                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);
+                                       continue;
+                               }
+                               /* For all other points the Y coordinate does not matter */
+                               if ((i >= m_ri) && (i <= (m_ri + 3))) {
+                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);
+                               } else if ((i >= m_wi) && (i <= (m_wi + 3))) {
+                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);
+                               } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))
+                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);
+                       }
+               }
+       }
+
+       sprintf(tmp, "%8lx", uvd->stats.frame_num);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.urb_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.urb_length);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.data_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.header_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.colour);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.hue);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+
+       sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
+       usbvideo_OverlayString(uvd, frame, x, y, tmp);
+       y += y_diff;
+}
+
+/*
+ * usbvideo_ReportStatistics()
+ *
+ * This procedure prints packet and transfer statistics.
+ *
+ * History:
+ * 14-Jan-2000 Corrected default multiplier.
+ */
+static void usbvideo_ReportStatistics(const struct uvd *uvd)
+{
+       if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
+               unsigned long allPackets, badPackets, goodPackets, percent;
+               allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;
+               badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;
+               goodPackets = allPackets - badPackets;
+               /* Calculate percentage wisely, remember integer limits */
+               assert(allPackets != 0);
+               if (goodPackets < (((unsigned long)-1)/100))
+                       percent = (100 * goodPackets) / allPackets;
+               else
+                       percent = goodPackets / (allPackets / 100);
+               info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",
+                    allPackets, badPackets, percent);
+               if (uvd->iso_packet_len > 0) {
+                       unsigned long allBytes, xferBytes;
+                       char multiplier = ' ';
+                       allBytes = allPackets * uvd->iso_packet_len;
+                       xferBytes = uvd->stats.data_count;
+                       assert(allBytes != 0);
+                       if (xferBytes < (((unsigned long)-1)/100))
+                               percent = (100 * xferBytes) / allBytes;
+                       else
+                               percent = xferBytes / (allBytes / 100);
+                       /* Scale xferBytes for easy reading */
+                       if (xferBytes > 10*1024) {
+                               xferBytes /= 1024;
+                               multiplier = 'K';
+                               if (xferBytes > 10*1024) {
+                                       xferBytes /= 1024;
+                                       multiplier = 'M';
+                                       if (xferBytes > 10*1024) {
+                                               xferBytes /= 1024;
+                                               multiplier = 'G';
+                                               if (xferBytes > 10*1024) {
+                                                       xferBytes /= 1024;
+                                                       multiplier = 'T';
+                                               }
+                                       }
+                               }
+                       }
+                       info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",
+                            xferBytes, multiplier, percent);
+               }
+       }
+}
+
+/*
+ * usbvideo_TestPattern()
+ *
+ * Procedure forms a test pattern (yellow grid on blue background).
+ *
+ * Parameters:
+ * fullframe: if TRUE then entire frame is filled, otherwise the procedure
+ *           continues from the current scanline.
+ * pmode      0: fill the frame with solid blue color (like on VCR or TV)
+ *           1: Draw a colored grid
+ *
+ * History:
+ * 01-Feb-2000 Created.
+ */
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
+{
+       struct usbvideo_frame *frame;
+       int num_cell = 0;
+       int scan_length = 0;
+       static int num_pass = 0;
+
+       if (uvd == NULL) {
+               err("%s: uvd == NULL", __FUNCTION__);
+               return;
+       }
+       if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
+               err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
+               return;
+       }
+
+       /* Grab the current frame */
+       frame = &uvd->frame[uvd->curframe];
+
+       /* Optionally start at the beginning */
+       if (fullframe) {
+               frame->curline = 0;
+               frame->seqRead_Length = 0;
+       }
+#if 0
+       {       /* For debugging purposes only */
+               char tmp[20];
+               usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
+               info("testpattern: frame=%s", tmp);
+       }
+#endif
+       /* Form every scan line */
+       for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) {
+               int i;
+               unsigned char *f = frame->data +
+                       (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline);
+               for (i=0; i < VIDEOSIZE_X(frame->request); i++) {
+                       unsigned char cb=0x80;
+                       unsigned char cg = 0;
+                       unsigned char cr = 0;
+
+                       if (pmode == 1) {
+                               if (frame->curline % 32 == 0)
+                                       cb = 0, cg = cr = 0xFF;
+                               else if (i % 32 == 0) {
+                                       if (frame->curline % 32 == 1)
+                                               num_cell++;
+                                       cb = 0, cg = cr = 0xFF;
+                               } else {
+                                       cb = ((num_cell*7) + num_pass) & 0xFF;
+                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
+                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
+                               }
+                       } else {
+                               /* Just the blue screen */
+                       }
+                               
+                       *f++ = cb;
+                       *f++ = cg;
+                       *f++ = cr;
+                       scan_length += 3;
+               }
+       }
+
+       frame->frameState = FrameState_Done;
+       frame->seqRead_Length += scan_length;
+       ++num_pass;
+
+       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
+       usbvideo_OverlayStats(uvd, frame);
+}
+
+EXPORT_SYMBOL(usbvideo_TestPattern);
+
+
+#ifdef DEBUG
+/*
+ * usbvideo_HexDump()
+ *
+ * A debugging tool. Prints hex dumps.
+ *
+ * History:
+ * 29-Jul-2000 Added printing of offsets.
+ */
+void usbvideo_HexDump(const unsigned char *data, int len)
+{
+       const int bytes_per_line = 32;
+       char tmp[128]; /* 32*3 + 5 */
+       int i, k;
+
+       for (i=k=0; len > 0; i++, len--) {
+               if (i > 0 && ((i % bytes_per_line) == 0)) {
+                       printk("%s\n", tmp);
+                       k=0;
+               }
+               if ((i % bytes_per_line) == 0)
+                       k += sprintf(&tmp[k], "%04x: ", i);
+               k += sprintf(&tmp[k], "%02x ", data[i]);
+       }
+       if (k > 0)
+               printk("%s\n", tmp);
+}
+
+EXPORT_SYMBOL(usbvideo_HexDump);
+
+#endif
+
+/* ******************************************************************** */
+
+/* XXX: this piece of crap really wants some error handling.. */
+static void usbvideo_ClientIncModCount(struct uvd *uvd)
+{
+       if (uvd == NULL) {
+               err("%s: uvd == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle == NULL) {
+               err("%s: uvd->handle == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle->md_module == NULL) {
+               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+               return;
+       }
+       if (!try_module_get(uvd->handle->md_module)) {
+               err("%s: try_module_get() == 0", __FUNCTION__);
+               return;
+       }
+}
+
+static void usbvideo_ClientDecModCount(struct uvd *uvd)
+{
+       if (uvd == NULL) {
+               err("%s: uvd == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle == NULL) {
+               err("%s: uvd->handle == NULL", __FUNCTION__);
+               return;
+       }
+       if (uvd->handle->md_module == NULL) {
+               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+               return;
+       }
+       module_put(uvd->handle->md_module);
+}
+
+int usbvideo_register(
+       struct usbvideo **pCams,
+       const int num_cams,
+       const int num_extra,
+       const char *driverName,
+       const struct usbvideo_cb *cbTbl,
+       struct module *md,
+       const struct usb_device_id *id_table)
+{
+       struct usbvideo *cams;
+       int i, base_size, result;
+
+       /* Check parameters for sanity */
+       if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
+               err("%s: Illegal call", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       /* Check registration callback - must be set! */
+       if (cbTbl->probe == NULL) {
+               err("%s: probe() is required!", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
+       cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
+       if (cams == NULL) {
+               err("Failed to allocate %d. bytes for usbvideo struct", base_size);
+               return -ENOMEM;
+       }
+       dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
+           __FUNCTION__, cams, base_size, num_cams);
+
+       /* Copy callbacks, apply defaults for those that are not set */
+       memmove(&cams->cb, cbTbl, sizeof(cams->cb));
+       if (cams->cb.getFrame == NULL)
+               cams->cb.getFrame = usbvideo_GetFrame;
+       if (cams->cb.disconnect == NULL)
+               cams->cb.disconnect = usbvideo_Disconnect;
+       if (cams->cb.startDataPump == NULL)
+               cams->cb.startDataPump = usbvideo_StartDataPump;
+       if (cams->cb.stopDataPump == NULL)
+               cams->cb.stopDataPump = usbvideo_StopDataPump;
+
+       cams->num_cameras = num_cams;
+       cams->cam = (struct uvd *) &cams[1];
+       cams->md_module = md;
+       if (cams->md_module == NULL)
+               warn("%s: module == NULL!", __FUNCTION__);
+       mutex_init(&cams->lock);        /* to 1 == available */
+
+       for (i = 0; i < num_cams; i++) {
+               struct uvd *up = &cams->cam[i];
+
+               up->handle = cams;
+
+               /* Allocate user_data separately because of kmalloc's limits */
+               if (num_extra > 0) {
+                       up->user_size = num_cams * num_extra;
+                       up->user_data = kmalloc(up->user_size, GFP_KERNEL);
+                       if (up->user_data == NULL) {
+                               err("%s: Failed to allocate user_data (%d. bytes)",
+                                   __FUNCTION__, up->user_size);
+                               while (i) {
+                                       up = &cams->cam[--i];
+                                       kfree(up->user_data);
+                               }
+                               kfree(cams);
+                               return -ENOMEM;
+                       }
+                       dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
+                            __FUNCTION__, i, up->user_data, up->user_size);
+               }
+       }
+
+       /*
+        * Register ourselves with USB stack.
+        */
+       strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown");
+       cams->usbdrv.name = cams->drvName;
+       cams->usbdrv.probe = cams->cb.probe;
+       cams->usbdrv.disconnect = cams->cb.disconnect;
+       cams->usbdrv.id_table = id_table;
+
+       /*
+        * Update global handle to usbvideo. This is very important
+        * because probe() can be called before usb_register() returns.
+        * If the handle is not yet updated then the probe() will fail.
+        */
+       *pCams = cams;
+       result = usb_register(&cams->usbdrv);
+       if (result) {
+               for (i = 0; i < num_cams; i++) {
+                       struct uvd *up = &cams->cam[i];
+                       kfree(up->user_data);
+               }
+               kfree(cams);
+       }
+
+       return result;
+}
+
+EXPORT_SYMBOL(usbvideo_register);
+
+/*
+ * usbvideo_Deregister()
+ *
+ * Procedure frees all usbvideo and user data structures. Be warned that
+ * if you had some dynamically allocated components in ->user field then
+ * you should free them before calling here.
+ */
+void usbvideo_Deregister(struct usbvideo **pCams)
+{
+       struct usbvideo *cams;
+       int i;
+
+       if (pCams == NULL) {
+               err("%s: pCams == NULL", __FUNCTION__);
+               return;
+       }
+       cams = *pCams;
+       if (cams == NULL) {
+               err("%s: cams == NULL", __FUNCTION__);
+               return;
+       }
+
+       dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
+       usb_deregister(&cams->usbdrv);
+
+       dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
+       for (i=0; i < cams->num_cameras; i++) {
+               struct uvd *up = &cams->cam[i];
+               int warning = 0;
+
+               if (up->user_data != NULL) {
+                       if (up->user_size <= 0)
+                               ++warning;
+               } else {
+                       if (up->user_size > 0)
+                               ++warning;
+               }
+               if (warning) {
+                       err("%s: Warning: user_data=$%p user_size=%d.",
+                           __FUNCTION__, up->user_data, up->user_size);
+               } else {
+                       dbg("%s: Freeing %d. $%p->user_data=$%p",
+                           __FUNCTION__, i, up, up->user_data);
+                       kfree(up->user_data);
+               }
+       }
+       /* Whole array was allocated in one chunk */
+       dbg("%s: Freed %d uvd structures",
+           __FUNCTION__, cams->num_cameras);
+       kfree(cams);
+       *pCams = NULL;
+}
+
+EXPORT_SYMBOL(usbvideo_Deregister);
+
+/*
+ * usbvideo_Disconnect()
+ *
+ * This procedure stops all driver activity. Deallocation of
+ * the interface-private structure (pointed by 'ptr') is done now
+ * (if we don't have any open files) or later, when those files
+ * are closed. After that driver should be removable.
+ *
+ * This code handles surprise removal. The uvd->user is a counter which
+ * increments on open() and decrements on close(). If we see here that
+ * this counter is not 0 then we have a client who still has us opened.
+ * We set uvd->remove_pending flag as early as possible, and after that
+ * all access to the camera will gracefully fail. These failures should
+ * prompt client to (eventually) close the video device, and then - in
+ * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter.
+ *
+ * History:
+ * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone.
+ * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close()
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ * 19-Oct-2000 Moved to usbvideo module.
+ */
+static void usbvideo_Disconnect(struct usb_interface *intf)
+{
+       struct uvd *uvd = usb_get_intfdata (intf);
+       int i;
+
+       if (uvd == NULL) {
+               err("%s($%p): Illegal call.", __FUNCTION__, intf);
+               return;
+       }
+
+       usb_set_intfdata (intf, NULL);
+
+       usbvideo_ClientIncModCount(uvd);
+       if (uvd->debug > 0)
+               info("%s(%p.)", __FUNCTION__, intf);
+
+       mutex_lock(&uvd->lock);
+       uvd->remove_pending = 1; /* Now all ISO data will be ignored */
+
+       /* At this time we ask to cancel outstanding URBs */
+       GET_CALLBACK(uvd, stopDataPump)(uvd);
+
+       for (i=0; i < USBVIDEO_NUMSBUF; i++)
+               usb_free_urb(uvd->sbuf[i].urb);
+
+       usb_put_dev(uvd->dev);
+       uvd->dev = NULL;            /* USB device is no more */
+
+       video_unregister_device(&uvd->vdev);
+       if (uvd->debug > 0)
+               info("%s: Video unregistered.", __FUNCTION__);
+
+       if (uvd->user)
+               info("%s: In use, disconnect pending.", __FUNCTION__);
+       else
+               usbvideo_CameraRelease(uvd);
+       mutex_unlock(&uvd->lock);
+       info("USB camera disconnected.");
+
+       usbvideo_ClientDecModCount(uvd);
+}
+
+/*
+ * usbvideo_CameraRelease()
+ *
+ * This code does final release of uvd. This happens
+ * after the device is disconnected -and- all clients
+ * closed their files.
+ *
+ * History:
+ * 27-Jan-2000 Created.
+ */
+static void usbvideo_CameraRelease(struct uvd *uvd)
+{
+       if (uvd == NULL) {
+               err("%s: Illegal call", __FUNCTION__);
+               return;
+       }
+
+       RingQueue_Free(&uvd->dp);
+       if (VALID_CALLBACK(uvd, userFree))
+               GET_CALLBACK(uvd, userFree)(uvd);
+       uvd->uvd_used = 0;      /* This is atomic, no need to take mutex */
+}
+
+/*
+ * usbvideo_find_struct()
+ *
+ * This code searches the array of preallocated (static) structures
+ * and returns index of the first one that isn't in use. Returns -1
+ * if there are no free structures.
+ *
+ * History:
+ * 27-Jan-2000 Created.
+ */
+static int usbvideo_find_struct(struct usbvideo *cams)
+{
+       int u, rv = -1;
+
+       if (cams == NULL) {
+               err("No usbvideo handle?");
+               return -1;
+       }
+       mutex_lock(&cams->lock);
+       for (u = 0; u < cams->num_cameras; u++) {
+               struct uvd *uvd = &cams->cam[u];
+               if (!uvd->uvd_used) /* This one is free */
+               {
+                       uvd->uvd_used = 1;      /* In use now */
+                       mutex_init(&uvd->lock); /* to 1 == available */
+                       uvd->dev = NULL;
+                       rv = u;
+                       break;
+               }
+       }
+       mutex_unlock(&cams->lock);
+       return rv;
+}
+
+static struct file_operations usbvideo_fops = {
+       .owner =  THIS_MODULE,
+       .open =   usbvideo_v4l_open,
+       .release =usbvideo_v4l_close,
+       .read =   usbvideo_v4l_read,
+       .mmap =   usbvideo_v4l_mmap,
+       .ioctl =  usbvideo_v4l_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .llseek = no_llseek,
+};
+static const struct video_device usbvideo_template = {
+       .owner =      THIS_MODULE,
+       .type =       VID_TYPE_CAPTURE,
+       .hardware =   VID_HARDWARE_CPIA,
+       .fops =       &usbvideo_fops,
+};
+
+struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
+{
+       int i, devnum;
+       struct uvd *uvd = NULL;
+
+       if (cams == NULL) {
+               err("No usbvideo handle?");
+               return NULL;
+       }
+
+       devnum = usbvideo_find_struct(cams);
+       if (devnum == -1) {
+               err("IBM USB camera driver: Too many devices!");
+               return NULL;
+       }
+       uvd = &cams->cam[devnum];
+       dbg("Device entry #%d. at $%p", devnum, uvd);
+
+       /* Not relying upon caller we increase module counter ourselves */
+       usbvideo_ClientIncModCount(uvd);
+
+       mutex_lock(&uvd->lock);
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+               if (uvd->sbuf[i].urb == NULL) {
+                       err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC);
+                       uvd->uvd_used = 0;
+                       uvd = NULL;
+                       goto allocate_done;
+               }
+       }
+       uvd->user=0;
+       uvd->remove_pending = 0;
+       uvd->last_error = 0;
+       RingQueue_Initialize(&uvd->dp);
+
+       /* Initialize video device structure */
+       uvd->vdev = usbvideo_template;
+       sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
+       /*
+        * The client is free to overwrite those because we
+        * return control to the client's probe function right now.
+        */
+allocate_done:
+       mutex_unlock(&uvd->lock);
+       usbvideo_ClientDecModCount(uvd);
+       return uvd;
+}
+
+EXPORT_SYMBOL(usbvideo_AllocateDevice);
+
+int usbvideo_RegisterVideoDevice(struct uvd *uvd)
+{
+       char tmp1[20], tmp2[20];        /* Buffers for printing */
+
+       if (uvd == NULL) {
+               err("%s: Illegal call.", __FUNCTION__);
+               return -EINVAL;
+       }
+       if (uvd->video_endp == 0) {
+               info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
+       }
+       if (uvd->paletteBits == 0) {
+               err("%s: No palettes specified!", __FUNCTION__);
+               return -EINVAL;
+       }
+       if (uvd->defaultPalette == 0) {
+               info("%s: No default palette!", __FUNCTION__);
+       }
+
+       uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
+               VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL;
+       usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize);
+       usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
+
+       if (uvd->debug > 0) {
+               info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
+                    __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+       }
+       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+               err("%s: video_register_device failed", __FUNCTION__);
+               return -EPIPE;
+       }
+       if (uvd->debug > 1) {
+               info("%s: video_register_device() successful", __FUNCTION__);
+       }
+       if (uvd->dev == NULL) {
+               err("%s: uvd->dev == NULL", __FUNCTION__);
+               return -EINVAL;
+       }
+
+       info("%s on /dev/video%d: canvas=%s videosize=%s",
+            (uvd->handle != NULL) ? uvd->handle->drvName : "???",
+            uvd->vdev.minor, tmp2, tmp1);
+
+       usb_get_dev(uvd->dev);
+       return 0;
+}
+
+EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
+
+/* ******************************************************************** */
+
+static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct uvd *uvd = file->private_data;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       unsigned long page, pos;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return -EFAULT;
+
+       if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+               return -EINVAL;
+
+       pos = (unsigned long) uvd->fbuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+/*
+ * usbvideo_v4l_open()
+ *
+ * This is part of Video 4 Linux API. The driver can be opened by one
+ * client only (checks internal counter 'uvdser'). The procedure
+ * then allocates buffers needed for video processing.
+ *
+ * History:
+ * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the
+ *             camera is also initialized here (once per connect), at
+ *             expense of V4L client (it waits on open() call).
+ * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
+ * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ */
+static int usbvideo_v4l_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct uvd *uvd = (struct uvd *) dev;
+       const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
+       int i, errCode = 0;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, dev);
+
+       usbvideo_ClientIncModCount(uvd);
+       mutex_lock(&uvd->lock);
+
+       if (uvd->user) {
+               err("%s: Someone tried to open an already opened device!", __FUNCTION__);
+               errCode = -EBUSY;
+       } else {
+               /* Clear statistics */
+               memset(&uvd->stats, 0, sizeof(uvd->stats));
+
+               /* Clean pointers so we know if we allocated something */
+               for (i=0; i < USBVIDEO_NUMSBUF; i++)
+                       uvd->sbuf[i].data = NULL;
+
+               /* Allocate memory for the frame buffers */
+               uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
+               uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
+               RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
+               if ((uvd->fbuf == NULL) ||
+                   (!RingQueue_IsAllocated(&uvd->dp))) {
+                       err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
+                       errCode = -ENOMEM;
+               } else {
+                       /* Allocate all buffers */
+                       for (i=0; i < USBVIDEO_NUMFRAMES; i++) {
+                               uvd->frame[i].frameState = FrameState_Unused;
+                               uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);
+                               /*
+                                * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
+                                * is not used (using read() instead).
+                                */
+                               uvd->frame[i].canvas = uvd->canvas;
+                               uvd->frame[i].seqRead_Index = 0;
+                       }
+                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+                               uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
+                               if (uvd->sbuf[i].data == NULL) {
+                                       errCode = -ENOMEM;
+                                       break;
+                               }
+                       }
+               }
+               if (errCode != 0) {
+                       /* Have to free all that memory */
+                       if (uvd->fbuf != NULL) {
+                               usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
+                               uvd->fbuf = NULL;
+                       }
+                       RingQueue_Free(&uvd->dp);
+                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+                               kfree(uvd->sbuf[i].data);
+                               uvd->sbuf[i].data = NULL;
+                       }
+               }
+       }
+
+       /* If so far no errors then we shall start the camera */
+       if (errCode == 0) {
+               /* Start data pump if we have valid endpoint */
+               if (uvd->video_endp != 0)
+                       errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
+               if (errCode == 0) {
+                       if (VALID_CALLBACK(uvd, setupOnOpen)) {
+                               if (uvd->debug > 1)
+                                       info("%s: setupOnOpen callback", __FUNCTION__);
+                               errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
+                               if (errCode < 0) {
+                                       err("%s: setupOnOpen callback failed (%d.).",
+                                           __FUNCTION__, errCode);
+                               } else if (uvd->debug > 1) {
+                                       info("%s: setupOnOpen callback successful", __FUNCTION__);
+                               }
+                       }
+                       if (errCode == 0) {
+                               uvd->settingsAdjusted = 0;
+                               if (uvd->debug > 1)
+                                       info("%s: Open succeeded.", __FUNCTION__);
+                               uvd->user++;
+                               file->private_data = uvd;
+                       }
+               }
+       }
+       mutex_unlock(&uvd->lock);
+       if (errCode != 0)
+               usbvideo_ClientDecModCount(uvd);
+       if (uvd->debug > 0)
+               info("%s: Returning %d.", __FUNCTION__, errCode);
+       return errCode;
+}
+
+/*
+ * usbvideo_v4l_close()
+ *
+ * This is part of Video 4 Linux API. The procedure
+ * stops streaming and deallocates all buffers that were earlier
+ * allocated in usbvideo_v4l_open().
+ *
+ * History:
+ * 22-Jan-2000 Moved scratch buffer deallocation here.
+ * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
+ * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
+ */
+static int usbvideo_v4l_close(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = file->private_data;
+       struct uvd *uvd = (struct uvd *) dev;
+       int i;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, dev);
+
+       mutex_lock(&uvd->lock);
+       GET_CALLBACK(uvd, stopDataPump)(uvd);
+       usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
+       uvd->fbuf = NULL;
+       RingQueue_Free(&uvd->dp);
+
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               kfree(uvd->sbuf[i].data);
+               uvd->sbuf[i].data = NULL;
+       }
+
+#if USBVIDEO_REPORT_STATS
+       usbvideo_ReportStatistics(uvd);
+#endif    
+
+       uvd->user--;
+       if (uvd->remove_pending) {
+               if (uvd->debug > 0)
+                       info("usbvideo_v4l_close: Final disconnect.");
+               usbvideo_CameraRelease(uvd);
+       }
+       mutex_unlock(&uvd->lock);
+       usbvideo_ClientDecModCount(uvd);
+
+       if (uvd->debug > 1)
+               info("%s: Completed.", __FUNCTION__);
+       file->private_data = NULL;
+       return 0;
+}
+
+/*
+ * usbvideo_v4l_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ * History:
+ * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
+ */
+static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
+                                unsigned int cmd, void *arg)
+{
+       struct uvd *uvd = file->private_data;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return -EIO;
+
+       switch (cmd) {
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *b = arg;
+                       *b = uvd->vcap;
+                       return 0;
+               }
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+                       *v = uvd->vchan;
+                       return 0;
+               }
+               case VIDIOCSCHAN:
+               {       
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *pic = arg;
+                       *pic = uvd->vpic;
+                       return 0;
+               }
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *pic = arg;
+                       /*
+                        * Use temporary 'video_picture' structure to preserve our
+                        * own settings (such as color depth, palette) that we
+                        * aren't allowing everyone (V4L client) to change.
+                        */
+                       uvd->vpic.brightness = pic->brightness;
+                       uvd->vpic.hue = pic->hue;
+                       uvd->vpic.colour = pic->colour;
+                       uvd->vpic.contrast = pic->contrast;
+                       uvd->settingsAdjusted = 0;      /* Will force new settings */
+                       return 0;
+               }
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       if(VALID_CALLBACK(uvd, setVideoMode)) {
+                               return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
+                       }
+
+                       if (vw->flags)
+                               return -EINVAL;
+                       if (vw->clipcount)
+                               return -EINVAL;
+                       if (vw->width != VIDEOSIZE_X(uvd->canvas))
+                               return -EINVAL;
+                       if (vw->height != VIDEOSIZE_Y(uvd->canvas))
+                               return -EINVAL;
+
+                       return 0;
+               }
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = VIDEOSIZE_X(uvd->videosize);
+                       vw->height = VIDEOSIZE_Y(uvd->videosize);
+                       vw->chromakey = 0;
+                       if (VALID_CALLBACK(uvd, getFPS))
+                               vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
+                       else 
+                               vw->flags = 10; /* FIXME: do better! */
+                       return 0;
+               }
+               case VIDIOCGMBUF:
+               {
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset(vm, 0, sizeof(*vm));
+                       vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
+                       vm->frames = USBVIDEO_NUMFRAMES;
+                       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) 
+                         vm->offsets[i] = i * uvd->max_frame_size;
+
+                       return 0;
+               }
+               case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap *vm = arg;
+
+                       if (uvd->debug >= 1) {
+                               info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
+                                    vm->frame, vm->width, vm->height, vm->format);
+                       }
+                       /*
+                        * Check if the requested size is supported. If the requestor
+                        * requests too big a frame then we may be tricked into accessing
+                        * outside of own preallocated frame buffer (in uvd->frame).
+                        * This will cause oops or a security hole. Theoretically, we
+                        * could only clamp the size down to acceptable bounds, but then
+                        * we'd need to figure out how to insert our smaller buffer into
+                        * larger caller's buffer... this is not an easy question. So we
+                        * here just flatly reject too large requests, assuming that the
+                        * caller will resubmit with smaller size. Callers should know
+                        * what size we support (returned by VIDIOCGCAP). However vidcat,
+                        * for one, does not care and allows to ask for any size.
+                        */
+                       if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
+                           (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
+                               if (uvd->debug > 0) {
+                                       info("VIDIOCMCAPTURE: Size=%dx%d too large; "
+                                            "allowed only up to %ldx%ld", vm->width, vm->height,
+                                            VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
+                               }
+                               return -EINVAL;
+                       }
+                       /* Check if the palette is supported */
+                       if (((1L << vm->format) & uvd->paletteBits) == 0) {
+                               if (uvd->debug > 0) {
+                                       info("VIDIOCMCAPTURE: format=%d. not supported"
+                                            " (paletteBits=$%08lx)",
+                                            vm->format, uvd->paletteBits);
+                               }
+                               return -EINVAL;
+                       }
+                       if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
+                               err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
+                               return -EINVAL;
+                       }
+                       if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
+                               /* Not an error - can happen */
+                       }
+                       uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
+                       uvd->frame[vm->frame].palette = vm->format;
+
+                       /* Mark it as ready */
+                       uvd->frame[vm->frame].frameState = FrameState_Ready;
+
+                       return usbvideo_NewFrame(uvd, vm->frame);
+               }
+               case VIDIOCSYNC:
+               {
+                       int *frameNum = arg;
+                       int ret;
+
+                       if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
+                               return -EINVAL;
+                               
+                       if (uvd->debug >= 1)
+                               info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
+                       if (uvd->flags & FLAGS_NO_DECODING)
+                               ret = usbvideo_GetFrame(uvd, *frameNum);
+                       else if (VALID_CALLBACK(uvd, getFrame)) {
+                               ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
+                               if ((ret < 0) && (uvd->debug >= 1)) {
+                                       err("VIDIOCSYNC: getFrame() returned %d.", ret);
+                               }
+                       } else {
+                               err("VIDIOCSYNC: getFrame is not set");
+                               ret = -EFAULT;
+                       }
+
+                       /*
+                        * The frame is in FrameState_Done_Hold state. Release it
+                        * right now because its data is already mapped into
+                        * the user space and it's up to the application to
+                        * make use of it until it asks for another frame.
+                        */
+                       uvd->frame[*frameNum].frameState = FrameState_Unused;
+                       return ret;
+               }
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb, 0, sizeof(*vb));
+                       return 0;
+               }
+               case VIDIOCKEY:
+                       return 0;
+
+               case VIDIOCCAPTURE:
+                       return -EINVAL;
+
+               case VIDIOCSFBUF:
+
+               case VIDIOCGTUNER:
+               case VIDIOCSTUNER:
+
+               case VIDIOCGFREQ:
+               case VIDIOCSFREQ:
+
+               case VIDIOCGAUDIO:
+               case VIDIOCSAUDIO:
+                       return -EINVAL;
+
+               default:
+                       return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
+}
+
+/*
+ * usbvideo_v4l_read()
+ *
+ * This is mostly boring stuff. We simply ask for a frame and when it
+ * arrives copy all the video data from it into user space. There is
+ * no obvious need to override this method.
+ *
+ * History:
+ * 20-Oct-2000 Created.
+ * 01-Nov-2000 Added mutex (uvd->lock).
+ */
+static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
+                     size_t count, loff_t *ppos)
+{
+       struct uvd *uvd = file->private_data;
+       int noblock = file->f_flags & O_NONBLOCK;
+       int frmx = -1, i;
+       struct usbvideo_frame *frame;
+
+       if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
+               return -EFAULT;
+
+       if (uvd->debug >= 1)
+               info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
+
+       mutex_lock(&uvd->lock);
+
+       /* See if a frame is completed, then use it. */
+       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+               if ((uvd->frame[i].frameState == FrameState_Done) ||
+                   (uvd->frame[i].frameState == FrameState_Done_Hold) ||
+                   (uvd->frame[i].frameState == FrameState_Error)) {
+                       frmx = i;
+                       break;
+               }
+       }
+
+       /* FIXME: If we don't start a frame here then who ever does? */
+       if (noblock && (frmx == -1)) {
+               count = -EAGAIN;
+               goto read_done;
+       }
+
+       /*
+        * If no FrameState_Done, look for a FrameState_Grabbing state.
+        * See if a frame is in process (grabbing), then use it.
+        * We will need to wait until it becomes cooked, of course.
+        */
+       if (frmx == -1) {
+               for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
+                       if (uvd->frame[i].frameState == FrameState_Grabbing) {
+                               frmx = i;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If no frame is active, start one. We don't care which one
+        * it will be, so #0 is as good as any.
+        * In read access mode we don't have convenience of VIDIOCMCAPTURE
+        * to specify the requested palette (video format) on per-frame
+        * basis. This means that we have to return data in -some- format
+        * and just hope that the client knows what to do with it.
+        * The default format is configured in uvd->defaultPalette field
+        * as one of VIDEO_PALETTE_xxx values. We stuff it into the new
+        * frame and initiate the frame filling process.
+        */
+       if (frmx == -1) {
+               if (uvd->defaultPalette == 0) {
+                       err("%s: No default palette; don't know what to do!", __FUNCTION__);
+                       count = -EFAULT;
+                       goto read_done;
+               }
+               frmx = 0;
+               /*
+                * We have no per-frame control over video size.
+                * Therefore we only can use whatever size was
+                * specified as default.
+                */
+               uvd->frame[frmx].request = uvd->videosize;
+               uvd->frame[frmx].palette = uvd->defaultPalette;
+               uvd->frame[frmx].frameState = FrameState_Ready;
+               usbvideo_NewFrame(uvd, frmx);
+               /* Now frame 0 is supposed to start filling... */
+       }
+
+       /*
+        * Get a pointer to the active frame. It is either previously
+        * completed frame or frame in progress but not completed yet.
+        */
+       frame = &uvd->frame[frmx];
+
+       /*
+        * Sit back & wait until the frame gets filled and postprocessed.
+        * If we fail to get the picture [in time] then return the error.
+        * In this call we specify that we want the frame to be waited for,
+        * postprocessed and switched into FrameState_Done_Hold state. This
+        * state is used to hold the frame as "fully completed" between
+        * subsequent partial reads of the same frame.
+        */
+       if (frame->frameState != FrameState_Done_Hold) {
+               long rv = -EFAULT;
+               if (uvd->flags & FLAGS_NO_DECODING)
+                       rv = usbvideo_GetFrame(uvd, frmx);
+               else if (VALID_CALLBACK(uvd, getFrame))
+                       rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);
+               else
+                       err("getFrame is not set");
+               if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {
+                       count = rv;
+                       goto read_done;
+               }
+       }
+
+       /*
+        * Copy bytes to user space. We allow for partial reads, which
+        * means that the user application can request read less than
+        * the full frame size. It is up to the application to issue
+        * subsequent calls until entire frame is read.
+        *
+        * First things first, make sure we don't copy more than we
+        * have - even if the application wants more. That would be
+        * a big security embarassment!
+        */
+       if ((count + frame->seqRead_Index) > frame->seqRead_Length)
+               count = frame->seqRead_Length - frame->seqRead_Index;
+
+       /*
+        * Copy requested amount of data to user space. We start
+        * copying from the position where we last left it, which
+        * will be zero for a new frame (not read before).
+        */
+       if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {
+               count = -EFAULT;
+               goto read_done;
+       }
+
+       /* Update last read position */
+       frame->seqRead_Index += count;
+       if (uvd->debug >= 1) {
+               err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
+                       __FUNCTION__, count, frame->seqRead_Index);
+       }
+
+       /* Finally check if the frame is done with and "release" it */
+       if (frame->seqRead_Index >= frame->seqRead_Length) {
+               /* All data has been read */
+               frame->seqRead_Index = 0;
+
+               /* Mark it as available to be used again. */
+               uvd->frame[frmx].frameState = FrameState_Unused;
+               if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
+                       err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
+               }
+       }
+read_done:
+       mutex_unlock(&uvd->lock);
+       return count;
+}
+
+/*
+ * Make all of the blocks of data contiguous
+ */
+static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
+{
+       char *cdata;
+       int i, totlen = 0;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               int n = urb->iso_frame_desc[i].actual_length;
+               int st = urb->iso_frame_desc[i].status;
+
+               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+               /* Detect and ignore errored packets */
+               if (st < 0) {
+                       if (uvd->debug >= 1)
+                               err("Data error: packet=%d. len=%d. status=%d.", i, n, st);
+                       uvd->stats.iso_err_count++;
+                       continue;
+               }
+
+               /* Detect and ignore empty packets */
+               if (n <= 0) {
+                       uvd->stats.iso_skip_count++;
+                       continue;
+               }
+               totlen += n;    /* Little local accounting */
+               RingQueue_Enqueue(&uvd->dp, cdata, n);
+       }
+       return totlen;
+}
+
+static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs)
+{
+       int i, ret, len;
+       struct uvd *uvd = urb->context;
+
+       /* We don't want to do anything if we are about to be removed! */
+       if (!CAMERA_IS_OPERATIONAL(uvd))
+               return;
+#if 0
+       if (urb->actual_length > 0) {
+               info("urb=$%p status=%d. errcount=%d. length=%d.",
+                    urb, urb->status, urb->error_count, urb->actual_length);
+       } else {
+               static int c = 0;
+               if (c++ % 100 == 0)
+                       info("No Isoc data");
+       }
+#endif
+
+       if (!uvd->streaming) {
+               if (uvd->debug >= 1)
+                       info("Not streaming, but interrupt!");
+               return;
+       }
+       
+       uvd->stats.urb_count++;
+       if (urb->actual_length <= 0)
+               goto urb_done_with;
+
+       /* Copy the data received into ring queue */
+       len = usbvideo_CompressIsochronous(uvd, urb);
+       uvd->stats.urb_length = len;
+       if (len <= 0)
+               goto urb_done_with;
+
+       /* Here we got some data */
+       uvd->stats.data_count += len;
+       RingQueue_WakeUpInterruptible(&uvd->dp);
+
+urb_done_with:
+       for (i = 0; i < FRAMES_PER_DESC; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+       urb->status = 0;
+       urb->dev = uvd->dev;
+       ret = usb_submit_urb (urb, GFP_KERNEL);
+       if(ret)
+               err("usb_submit_urb error (%d)", ret);
+       return;
+}
+
+/*
+ * usbvideo_StartDataPump()
+ *
+ * History:
+ * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead
+ *             of hardcoded values. Simplified by using for loop,
+ *             allowed any number of URBs.
+ */
+static int usbvideo_StartDataPump(struct uvd *uvd)
+{
+       struct usb_device *dev = uvd->dev;
+       int i, errFlag;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, uvd);
+
+       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+               err("%s: Camera is not operational", __FUNCTION__);
+               return -EFAULT;
+       }
+       uvd->curframe = -1;
+
+       /* Alternate interface 1 is is the biggest frame size */
+       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
+       if (i < 0) {
+               err("%s: usb_set_interface error", __FUNCTION__);
+               uvd->last_error = i;
+               return -EBUSY;
+       }
+       if (VALID_CALLBACK(uvd, videoStart))
+               GET_CALLBACK(uvd, videoStart)(uvd);
+       else 
+               err("%s: videoStart not set", __FUNCTION__);
+
+       /* We double buffer the Iso lists */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               int j, k;
+               struct urb *urb = uvd->sbuf[i].urb;
+               urb->dev = dev;
+               urb->context = uvd;
+               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+               urb->interval = 1;
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->transfer_buffer = uvd->sbuf[i].data;
+               urb->complete = usbvideo_IsocIrq;
+               urb->number_of_packets = FRAMES_PER_DESC;
+               urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
+               for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = uvd->iso_packet_len;
+               }
+       }
+
+       /* Submit all URBs */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+               if (errFlag)
+                       err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
+       }
+
+       uvd->streaming = 1;
+       if (uvd->debug > 1)
+               info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
+       return 0;
+}
+
+/*
+ * usbvideo_StopDataPump()
+ *
+ * This procedure stops streaming and deallocates URBs. Then it
+ * activates zero-bandwidth alt. setting of the video interface.
+ *
+ * History:
+ * 22-Jan-2000 Corrected order of actions to work after surprise removal.
+ * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
+ */
+static void usbvideo_StopDataPump(struct uvd *uvd)
+{
+       int i, j;
+
+       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+               return;
+
+       if (uvd->debug > 1)
+               info("%s($%p)", __FUNCTION__, uvd);
+
+       /* Unschedule all of the iso td's */
+       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+               usb_kill_urb(uvd->sbuf[i].urb);
+       }
+       if (uvd->debug > 1)
+               info("%s: streaming=0", __FUNCTION__);
+       uvd->streaming = 0;
+
+       if (!uvd->remove_pending) {
+               /* Invoke minidriver's magic to stop the camera */
+               if (VALID_CALLBACK(uvd, videoStop))
+                       GET_CALLBACK(uvd, videoStop)(uvd);
+               else 
+                       err("%s: videoStop not set", __FUNCTION__);
+
+               /* Set packet size to 0 */
+               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
+               if (j < 0) {
+                       err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
+                       uvd->last_error = j;
+               }
+       }
+}
+
+/*
+ * usbvideo_NewFrame()
+ *
+ * History:
+ * 29-Mar-00 Added copying of previous frame into the current one.
+ * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
+ */
+static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
+{
+       struct usbvideo_frame *frame;
+       int n;
+
+       if (uvd->debug > 1)
+               info("usbvideo_NewFrame($%p,%d.)", uvd, framenum);
+
+       /* If we're not grabbing a frame right now and the other frame is */
+       /*  ready to be grabbed into, then use it instead */
+       if (uvd->curframe != -1)
+               return 0;
+
+       /* If necessary we adjust picture settings between frames */
+       if (!uvd->settingsAdjusted) {
+               if (VALID_CALLBACK(uvd, adjustPicture))
+                       GET_CALLBACK(uvd, adjustPicture)(uvd);
+               uvd->settingsAdjusted = 1;
+       }
+
+       n = (framenum + 1) % USBVIDEO_NUMFRAMES;
+       if (uvd->frame[n].frameState == FrameState_Ready)
+               framenum = n;
+
+       frame = &uvd->frame[framenum];
+
+       frame->frameState = FrameState_Grabbing;
+       frame->scanstate = ScanState_Scanning;
+       frame->seqRead_Length = 0;      /* Accumulated in xxx_parse_data() */
+       frame->deinterlace = Deinterlace_None;
+       frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */
+       uvd->curframe = framenum;
+
+       /*
+        * Normally we would want to copy previous frame into the current one
+        * before we even start filling it with data; this allows us to stop
+        * filling at any moment; top portion of the frame will be new and
+        * bottom portion will stay as it was in previous frame. If we don't
+        * do that then missing chunks of video stream will result in flickering
+        * portions of old data whatever it was before.
+        *
+        * If we choose not to copy previous frame (to, for example, save few
+        * bus cycles - the frame can be pretty large!) then we have an option
+        * to clear the frame before using. If we experience losses in this
+        * mode then missing picture will be black (no flickering).
+        *
+        * Finally, if user chooses not to clean the current frame before
+        * filling it with data then the old data will be visible if we fail
+        * to refill entire frame with new data.
+        */
+       if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
+               /* This copies previous frame into this one to mask losses */
+               int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
+               memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
+       } else {
+               if (uvd->flags & FLAGS_CLEAN_FRAMES) {
+                       /* This provides a "clean" frame but slows things down */
+                       memset(frame->data, 0, uvd->max_frame_size);
+               }
+       }
+       return 0;
+}
+
+/*
+ * usbvideo_CollectRawData()
+ *
+ * This procedure can be used instead of 'processData' callback if you
+ * only want to dump the raw data from the camera into the output
+ * device (frame buffer). You can look at it with V4L client, but the
+ * image will be unwatchable. The main purpose of this code and of the
+ * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from
+ * new, unknown cameras. This procedure will be automatically invoked
+ * instead of the specified callback handler when uvd->flags has bit
+ * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
+ * based on usbvideo can use this feature at any time.
+ */
+static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       int n;
+
+       assert(uvd != NULL);
+       assert(frame != NULL);
+
+       /* Try to move data from queue into frame buffer */
+       n = RingQueue_GetLength(&uvd->dp);
+       if (n > 0) {
+               int m;
+               /* See how much space we have left */
+               m = uvd->max_frame_size - frame->seqRead_Length;
+               if (n > m)
+                       n = m;
+               /* Now move that much data into frame buffer */
+               RingQueue_Dequeue(
+                       &uvd->dp,
+                       frame->data + frame->seqRead_Length,
+                       m);
+               frame->seqRead_Length += m;
+       }
+       /* See if we filled the frame */
+       if (frame->seqRead_Length >= uvd->max_frame_size) {
+               frame->frameState = FrameState_Done;
+               uvd->curframe = -1;
+               uvd->stats.frame_num++;
+       }
+}
+
+static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
+{
+       struct usbvideo_frame *frame = &uvd->frame[frameNum];
+
+       if (uvd->debug >= 2)
+               info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
+
+       switch (frame->frameState) {
+        case FrameState_Unused:
+               if (uvd->debug >= 2)
+                       info("%s: FrameState_Unused", __FUNCTION__);
+               return -EINVAL;
+        case FrameState_Ready:
+        case FrameState_Grabbing:
+        case FrameState_Error:
+        {
+               int ntries, signalPending;
+       redo:
+               if (!CAMERA_IS_OPERATIONAL(uvd)) {
+                       if (uvd->debug >= 2)
+                               info("%s: Camera is not operational (1)", __FUNCTION__);
+                       return -EIO;
+               }
+               ntries = 0; 
+               do {
+                       RingQueue_InterruptibleSleepOn(&uvd->dp);
+                       signalPending = signal_pending(current);
+                       if (!CAMERA_IS_OPERATIONAL(uvd)) {
+                               if (uvd->debug >= 2)
+                                       info("%s: Camera is not operational (2)", __FUNCTION__);
+                               return -EIO;
+                       }
+                       assert(uvd->fbuf != NULL);
+                       if (signalPending) {
+                               if (uvd->debug >= 2)
+                                       info("%s: Signal=$%08x", __FUNCTION__, signalPending);
+                               if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
+                                       usbvideo_TestPattern(uvd, 1, 0);
+                                       uvd->curframe = -1;
+                                       uvd->stats.frame_num++;
+                                       if (uvd->debug >= 2)
+                                               info("%s: Forced test pattern screen", __FUNCTION__);
+                                       return 0;
+                               } else {
+                                       /* Standard answer: Interrupted! */
+                                       if (uvd->debug >= 2)
+                                               info("%s: Interrupted!", __FUNCTION__);
+                                       return -EINTR;
+                               }
+                       } else {
+                               /* No signals - we just got new data in dp queue */
+                               if (uvd->flags & FLAGS_NO_DECODING)
+                                       usbvideo_CollectRawData(uvd, frame);
+                               else if (VALID_CALLBACK(uvd, processData))
+                                       GET_CALLBACK(uvd, processData)(uvd, frame);
+                               else 
+                                       err("%s: processData not set", __FUNCTION__);
+                       }
+               } while (frame->frameState == FrameState_Grabbing);
+               if (uvd->debug >= 2) {
+                       info("%s: Grabbing done; state=%d. (%lu. bytes)",
+                            __FUNCTION__, frame->frameState, frame->seqRead_Length);
+               }
+               if (frame->frameState == FrameState_Error) {
+                       int ret = usbvideo_NewFrame(uvd, frameNum);
+                       if (ret < 0) {
+                               err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
+                               return ret;
+                       }
+                       goto redo;
+               }
+               /* Note that we fall through to meet our destiny below */
+        }
+        case FrameState_Done:
+               /*
+                * Do all necessary postprocessing of data prepared in
+                * "interrupt" code and the collecting code above. The
+                * frame gets marked as FrameState_Done by queue parsing code.
+                * This status means that we collected enough data and
+                * most likely processed it as we went through. However
+                * the data may need postprocessing, such as deinterlacing
+                * or picture adjustments implemented in software (horror!)
+                *
+                * As soon as the frame becomes "final" it gets promoted to
+                * FrameState_Done_Hold status where it will remain until the
+                * caller consumed all the video data from the frame. Then
+                * the empty shell of ex-frame is thrown out for dogs to eat.
+                * But we, worried about pets, will recycle the frame!
+                */
+               uvd->stats.frame_num++;
+               if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
+                       if (VALID_CALLBACK(uvd, postProcess))
+                               GET_CALLBACK(uvd, postProcess)(uvd, frame);
+                       if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
+                               usbvideo_SoftwareContrastAdjustment(uvd, frame);
+               }
+               frame->frameState = FrameState_Done_Hold;
+               if (uvd->debug >= 2)
+                       info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
+               return 0;
+
+       case FrameState_Done_Hold:
+               /*
+                * We stay in this state indefinitely until someone external,
+                * like ioctl() or read() call finishes digesting the frame
+                * data. Then it will mark the frame as FrameState_Unused and
+                * it will be released back into the wild to roam freely.
+                */
+               if (uvd->debug >= 2)
+                       info("%s: FrameState_Done_Hold state.", __FUNCTION__);
+               return 0;
+       }
+
+       /* Catch-all for other cases. We shall not be here. */
+       err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
+       frame->frameState = FrameState_Unused;
+       return 0;
+}
+
+/*
+ * usbvideo_DeinterlaceFrame()
+ *
+ * This procedure deinterlaces the given frame. Some cameras produce
+ * only half of scanlines - sometimes only even lines, sometimes only
+ * odd lines. The deinterlacing method is stored in frame->deinterlace
+ * variable.
+ *
+ * Here we scan the frame vertically and replace missing scanlines with
+ * average between surrounding ones - before and after. If we have no
+ * line above then we just copy next line. Similarly, if we need to
+ * create a last line then preceding line is used.
+ */
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+       if ((uvd == NULL) || (frame == NULL))
+               return;
+
+       if ((frame->deinterlace == Deinterlace_FillEvenLines) ||
+           (frame->deinterlace == Deinterlace_FillOddLines))
+       {
+               const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+               int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1;
+
+               for (; i < VIDEOSIZE_Y(frame->request); i += 2) {
+                       const unsigned char *fs1, *fs2;
+                       unsigned char *fd;
+                       int ip, in, j;  /* Previous and next lines */
+
+                       /*
+                        * Need to average lines before and after 'i'.
+                        * If we go out of bounds seeking those lines then
+                        * we point back to existing line.
+                        */
+                       ip = i - 1;     /* First, get rough numbers */
+                       in = i + 1;
+
+                       /* Now validate */
+                       if (ip < 0)
+                               ip = in;
+                       if (in >= VIDEOSIZE_Y(frame->request))
+                               in = ip;
+
+                       /* Sanity check */
+                       if ((ip < 0) || (in < 0) ||
+                           (ip >= VIDEOSIZE_Y(frame->request)) ||
+                           (in >= VIDEOSIZE_Y(frame->request)))
+                       {
+                               err("Error: ip=%d. in=%d. req.height=%ld.",
+                                   ip, in, VIDEOSIZE_Y(frame->request));
+                               break;
+                       }
+
+                       /* Now we need to average lines 'ip' and 'in' to produce line 'i' */
+                       fs1 = frame->data + (v4l_linesize * ip);
+                       fs2 = frame->data + (v4l_linesize * in);
+                       fd = frame->data + (v4l_linesize * i);
+
+                       /* Average lines around destination */
+                       for (j=0; j < v4l_linesize; j++) {
+                               fd[j] = (unsigned char)((((unsigned) fs1[j]) +
+                                                        ((unsigned)fs2[j])) >> 1);
+                       }
+               }
+       }
+
+       /* Optionally display statistics on the screen */
+       if (uvd->flags & FLAGS_OVERLAY_STATS)
+               usbvideo_OverlayStats(uvd, frame);
+}
+
+EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
+
+/*
+ * usbvideo_SoftwareContrastAdjustment()
+ *
+ * This code adjusts the contrast of the frame, assuming RGB24 format.
+ * As most software image processing, this job is CPU-intensive.
+ * Get a camera that supports hardware adjustment!
+ *
+ * History:
+ * 09-Feb-2001  Created.
+ */
+static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, 
+                                               struct usbvideo_frame *frame)
+{
+       int i, j, v4l_linesize;
+       signed long adj;
+       const int ccm = 128; /* Color correction median - see below */
+
+       if ((uvd == NULL) || (frame == NULL)) {
+               err("%s: Illegal call.", __FUNCTION__);
+               return;
+       }
+       adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+       RESTRICT_TO_RANGE(adj, -ccm, ccm+1);
+       if (adj == 0) {
+               /* In rare case of no adjustment */
+               return;
+       }
+       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
+       for (i=0; i < VIDEOSIZE_Y(frame->request); i++) {
+               unsigned char *fd = frame->data + (v4l_linesize * i);
+               for (j=0; j < v4l_linesize; j++) {
+                       signed long v = (signed long) fd[j];
+                       /* Magnify up to 2 times, reduce down to zero */
+                       v = 128 + ((ccm + adj) * (v - 128)) / ccm;
+                       RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */
+                       fd[j] = (unsigned char) v;
+               }
+       }
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h
new file mode 100644 (file)
index 0000000..135433c
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef usbvideo_h
+#define        usbvideo_h
+
+#include <linux/config.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+
+/* Most helpful debugging aid */
+#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
+
+#define USBVIDEO_REPORT_STATS  1       /* Set to 0 to block statistics on close */
+
+/* Bit flags (options) */
+#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
+#define        FLAGS_MONOCHROME                (1 << 1)
+#define FLAGS_DISPLAY_HINTS            (1 << 2)
+#define FLAGS_OVERLAY_STATS            (1 << 3)
+#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
+#define FLAGS_SEPARATE_FRAMES          (1 << 5)
+#define FLAGS_CLEAN_FRAMES             (1 << 6)
+#define        FLAGS_NO_DECODING               (1 << 7)
+
+/* Bit flags for frames (apply to the frame where they are specified) */
+#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST  (1 << 0)
+
+/* Camera capabilities (maximum) */
+#define CAMERA_URB_FRAMES       32
+#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
+#define FRAMES_PER_DESC                (CAMERA_URB_FRAMES)
+#define FRAME_SIZE_PER_DESC    (CAMERA_MAX_ISO_PACKET)
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+
+#define V4L_BYTES_PER_PIXEL     3      /* Because we produce RGB24 */
+
+/*
+ * Use this macro to construct constants for different video sizes.
+ * We have to deal with different video sizes that have to be
+ * configured in the device or compared against when we receive
+ * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y
+ * #defines and that's the end of story. However this solution
+ * does not allow to convert between real pixel sizes and the
+ * constant (integer) value that may be used to tag a frame or
+ * whatever. The set of macros below constructs videosize constants
+ * from the pixel size and allows to reconstruct the pixel size
+ * from the combined value later.
+ */
+#define        VIDEOSIZE(x,y)  (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16))
+#define        VIDEOSIZE_X(vs) ((vs) & 0xFFFFL)
+#define        VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL)
+typedef unsigned long videosize_t;
+
+/*
+ * This macro checks if the camera is still operational. The 'uvd'
+ * pointer must be valid, uvd->dev must be valid, we are not
+ * removing the device and the device has not erred on us.
+ */
+#define CAMERA_IS_OPERATIONAL(uvd) (\
+       (uvd != NULL) && \
+       ((uvd)->dev != NULL) && \
+       ((uvd)->last_error == 0) && \
+       (!(uvd)->remove_pending))
+
+/*
+ * We use macros to do YUV -> RGB conversion because this is
+ * very important for speed and totally unimportant for size.
+ *
+ * YUV -> RGB Conversion
+ * ---------------------
+ *
+ * B = 1.164*(Y-16)                + 2.018*(V-128)
+ * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
+ * R = 1.164*(Y-16) + 1.596*(U-128)
+ *
+ * If you fancy integer arithmetics (as you should), hear this:
+ *
+ * 65536*B = 76284*(Y-16)                + 132252*(V-128)
+ * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
+ * 65536*R = 76284*(Y-16) + 104595*(U-128)
+ *
+ * Make sure the output values are within [0..255] range.
+ */
+#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
+#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
+    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+    mm_y = (my) - 16;  \
+    mm_u = (mu) - 128; \
+    mm_v = (mv) - 128; \
+    mm_yc= mm_y * 76284; \
+    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
+    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
+    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
+    mb = LIMIT_RGB(mm_b); \
+    mg = LIMIT_RGB(mm_g); \
+    mr = LIMIT_RGB(mm_r); \
+}
+
+#define        RING_QUEUE_SIZE         (128*1024)      /* Must be a power of 2 */
+#define        RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
+#define        RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
+#define        RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
+
+struct RingQueue {
+       unsigned char *queue;   /* Data from the Isoc data pump */
+       int length;             /* How many bytes allocated for the queue */
+       int wi;                 /* That's where we write */
+       int ri;                 /* Read from here until you hit write index */
+       wait_queue_head_t wqh;  /* Processes waiting */
+};
+
+enum ScanState {
+       ScanState_Scanning,     /* Scanning for header */
+       ScanState_Lines         /* Parsing lines */
+};
+
+/* Completion states of the data parser */
+enum ParseState {
+       scan_Continue,          /* Just parse next item */
+       scan_NextFrame,         /* Frame done, send it to V4L */
+       scan_Out,               /* Not enough data for frame */
+       scan_EndParse           /* End parsing */
+};
+
+enum FrameState {
+       FrameState_Unused,      /* Unused (no MCAPTURE) */
+       FrameState_Ready,       /* Ready to start grabbing */
+       FrameState_Grabbing,    /* In the process of being grabbed into */
+       FrameState_Done,        /* Finished grabbing, but not been synced yet */
+       FrameState_Done_Hold,   /* Are syncing or reading */
+       FrameState_Error,       /* Something bad happened while processing */
+};
+
+/*
+ * Some frames may contain only even or odd lines. This type
+ * specifies what type of deinterlacing is required.
+ */
+enum Deinterlace {
+       Deinterlace_None=0,
+       Deinterlace_FillOddLines,
+       Deinterlace_FillEvenLines
+};
+
+#define USBVIDEO_NUMFRAMES     2       /* How many frames we work with */
+#define USBVIDEO_NUMSBUF       2       /* How many URBs linked in a ring */
+
+/* This structure represents one Isoc request - URB and buffer */
+struct usbvideo_sbuf {
+       char *data;
+       struct urb *urb;
+};
+
+struct usbvideo_frame {
+       char *data;             /* Frame buffer */
+       unsigned long header;   /* Significant bits from the header */
+
+       videosize_t canvas;     /* The canvas (max. image) allocated */
+       videosize_t request;    /* That's what the application asked for */
+       unsigned short palette; /* The desired format */
+
+       enum FrameState frameState;/* State of grabbing */
+       enum ScanState scanstate;       /* State of scanning */
+       enum Deinterlace deinterlace;
+       int flags;              /* USBVIDEO_FRAME_FLAG_xxx bit flags */
+
+       int curline;            /* Line of frame we're working on */
+
+       long seqRead_Length;    /* Raw data length of frame */
+       long seqRead_Index;     /* Amount of data that has been already read */
+
+       void *user;             /* Additional data that user may need */
+};
+
+/* Statistics that can be overlaid on screen */
+struct usbvideo_statistics {
+        unsigned long frame_num;       /* Sequential number of the frame */
+        unsigned long urb_count;        /* How many URBs we received so far */
+        unsigned long urb_length;       /* Length of last URB */
+        unsigned long data_count;       /* How many bytes we received */
+        unsigned long header_count;     /* How many frame headers we found */
+       unsigned long iso_skip_count;   /* How many empty ISO packets received */
+       unsigned long iso_err_count;    /* How many bad ISO packets received */
+};
+
+struct usbvideo;
+
+struct uvd {
+       struct video_device vdev;       /* Must be the first field! */
+       struct usb_device *dev;
+       struct usbvideo *handle;        /* Points back to the struct usbvideo */
+       void *user_data;                /* Camera-dependent data */
+       int user_size;                  /* Size of that camera-dependent data */
+       int debug;                      /* Debug level for usbvideo */
+       unsigned char iface;            /* Video interface number */
+       unsigned char video_endp;
+       unsigned char ifaceAltActive;
+       unsigned char ifaceAltInactive; /* Alt settings */
+       unsigned long flags;            /* FLAGS_USBVIDEO_xxx */
+       unsigned long paletteBits;      /* Which palettes we accept? */
+       unsigned short defaultPalette;  /* What palette to use for read() */
+       struct mutex lock;
+       int user;               /* user count for exclusive use */
+
+       videosize_t videosize;  /* Current setting */
+       videosize_t canvas;     /* This is the width,height of the V4L canvas */
+       int max_frame_size;     /* Bytes in one video frame */
+
+       int uvd_used;           /* Is this structure in use? */
+       int streaming;          /* Are we streaming Isochronous? */
+       int grabbing;           /* Are we grabbing? */
+       int settingsAdjusted;   /* Have we adjusted contrast etc.? */
+       int last_error;         /* What calamity struck us? */
+
+       char *fbuf;             /* Videodev buffer area */
+       int fbuf_size;          /* Videodev buffer size */
+
+       int curframe;
+       int iso_packet_len;     /* Videomode-dependent, saves bus bandwidth */
+
+       struct RingQueue dp;    /* Isoc data pump */
+       struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
+       struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
+
+       volatile int remove_pending;    /* If set then about to exit */
+
+       struct video_picture vpic, vpic_old;    /* Picture settings */
+       struct video_capability vcap;           /* Video capabilities */
+       struct video_channel vchan;     /* May be used for tuner support */
+       struct usbvideo_statistics stats;
+       char videoName[32];             /* Holds name like "video7" */
+};
+
+/*
+ * usbvideo callbacks (virtual methods). They are set when usbvideo
+ * services are registered. All of these default to NULL, except those
+ * that default to usbvideo-provided methods.
+ */
+struct usbvideo_cb {
+       int (*probe)(struct usb_interface *, const struct usb_device_id *);
+       void (*userFree)(struct uvd *);
+       void (*disconnect)(struct usb_interface *);
+       int (*setupOnOpen)(struct uvd *);
+       void (*videoStart)(struct uvd *);
+       void (*videoStop)(struct uvd *);
+       void (*processData)(struct uvd *, struct usbvideo_frame *);
+       void (*postProcess)(struct uvd *, struct usbvideo_frame *);
+       void (*adjustPicture)(struct uvd *);
+       int (*getFPS)(struct uvd *);
+       int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
+       int (*getFrame)(struct uvd *, int);
+       int (*startDataPump)(struct uvd *uvd);
+       void (*stopDataPump)(struct uvd *uvd);
+       int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
+};
+
+struct usbvideo {
+       int num_cameras;                /* As allocated */
+       struct usb_driver usbdrv;       /* Interface to the USB stack */
+       char drvName[80];               /* Driver name */
+       struct mutex lock;              /* Mutex protecting camera structures */
+       struct usbvideo_cb cb;          /* Table of callbacks (virtual methods) */
+       struct video_device vdt;        /* Video device template */
+       struct uvd *cam;                        /* Array of camera structures */
+       struct module *md_module;       /* Minidriver module */
+};
+
+
+/*
+ * This macro retrieves callback address from the struct uvd object.
+ * No validity checks are done here, so be sure to check the
+ * callback beforehand with VALID_CALLBACK.
+ */
+#define        GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName)
+
+/*
+ * This macro returns either callback pointer or NULL. This is safe
+ * macro, meaning that most of components of data structures involved
+ * may be NULL - this only results in NULL being returned. You may
+ * wish to use this macro to make sure that the callback is callable.
+ * However keep in mind that those checks take time.
+ */
+#define        VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
+               ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
+
+int  RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
+int  RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
+void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
+void RingQueue_Flush(struct RingQueue *rq);
+
+static inline int RingQueue_GetLength(const struct RingQueue *rq)
+{
+       return (rq->wi - rq->ri + rq->length) & (rq->length-1);
+}
+
+static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
+{
+       return rq->length - RingQueue_GetLength(rq);
+}
+
+void usbvideo_DrawLine(
+       struct usbvideo_frame *frame,
+       int x1, int y1,
+       int x2, int y2,
+       unsigned char cr, unsigned char cg, unsigned char cb);
+void usbvideo_HexDump(const unsigned char *data, int len);
+void usbvideo_SayAndWait(const char *what);
+void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
+
+/* Memory allocation routines */
+unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
+
+int usbvideo_register(
+       struct usbvideo **pCams,
+       const int num_cams,
+       const int num_extra,
+       const char *driverName,
+       const struct usbvideo_cb *cbTable,
+       struct module *md,
+       const struct usb_device_id *id_table);
+struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
+int usbvideo_RegisterVideoDevice(struct uvd *uvd);
+void usbvideo_Deregister(struct usbvideo **uvt);
+
+int usbvideo_v4l_initialize(struct video_device *dev);
+
+void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
+
+/*
+ * This code performs bounds checking - use it when working with
+ * new formats, or else you may get oopses all over the place.
+ * If pixel falls out of bounds then it gets shoved back (as close
+ * to place of offence as possible) and is painted bright red.
+ *
+ * There are two important concepts: frame width, height and
+ * V4L canvas width, height. The former is the area requested by
+ * the application -for this very frame-. The latter is the largest
+ * possible frame that we can serve (we advertise that via V4L ioctl).
+ * The frame data is expected to be formatted as lines of length
+ * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
+ */
+static inline void RGB24_PUTPIXEL(
+       struct usbvideo_frame *fr,
+       int ix, int iy,
+       unsigned char vr,
+       unsigned char vg,
+       unsigned char vb)
+{
+       register unsigned char *pf;
+       int limiter = 0, mx, my;
+       mx = ix;
+       my = iy;
+       if (mx < 0) {
+               mx=0;
+               limiter++;
+       } else if (mx >= VIDEOSIZE_X((fr)->request)) {
+               mx= VIDEOSIZE_X((fr)->request) - 1;
+               limiter++;
+       }
+       if (my < 0) {
+               my = 0;
+               limiter++;
+       } else if (my >= VIDEOSIZE_Y((fr)->request)) {
+               my = VIDEOSIZE_Y((fr)->request) - 1;
+               limiter++;
+       }
+       pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix));
+       if (limiter) {
+               *pf++ = 0;
+               *pf++ = 0;
+               *pf++ = 0xFF;
+       } else {
+               *pf++ = (vb);
+               *pf++ = (vg);
+               *pf++ = (vr);
+       }
+}
+
+#endif /* usbvideo_h */
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
new file mode 100644 (file)
index 0000000..1d06e53
--- /dev/null
@@ -0,0 +1,1411 @@
+/*
+ * USB ViCam WebCam driver
+ * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
+ *                    Christopher L Cheney (ccheney@cheney.cx),
+ *                    Pavel Machek (pavel@suse.cz),
+ *                    John Tyner (jtyner@cs.ucr.edu),
+ *                    Monroe Williams (monroe@pobox.com)
+ *
+ * Supports 3COM HomeConnect PC Digital WebCam
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This source code is based heavily on the CPiA webcam driver which was
+ * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
+ *
+ * Portions of this code were also copied from usbvideo.c
+ *
+ * Special thanks to the the whole team at Sourceforge for help making
+ * this driver become a reality.  Notably:
+ * Andy Armstrong who reverse engineered the color encoding and
+ * Pavel Machek and Chris Cheney who worked on reverse engineering the
+ *    camera controls and wrote the first generation driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include "usbvideo.h"
+
+// #define VICAM_DEBUG
+
+#ifdef VICAM_DEBUG
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
+#define DRIVER_DESC             "ViCam WebCam Driver"
+
+/* Define these values to match your device */
+#define USB_VICAM_VENDOR_ID    0x04c1
+#define USB_VICAM_PRODUCT_ID   0x009d
+
+#define VICAM_BYTES_PER_PIXEL   3
+#define VICAM_MAX_READ_SIZE     (512*242+128)
+#define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
+#define VICAM_FRAMES            2
+
+#define VICAM_HEADER_SIZE       64
+
+#define clamp( x, l, h )        max_t( __typeof__( x ),         \
+                                       ( l ),                   \
+                                       min_t( __typeof__( x ),  \
+                                              ( h ),            \
+                                              ( x ) ) )
+
+/* Not sure what all the bytes in these char
+ * arrays do, but they're necessary to make
+ * the camera work.
+ */
+
+static unsigned char setup1[] = {
+       0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
+       0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
+       0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
+       0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
+       0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
+};
+
+static unsigned char setup2[] = {
+       0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
+       0x00, 0x00
+};
+
+static unsigned char setup3[] = {
+       0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
+};
+
+static unsigned char setup4[] = {
+       0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
+       0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+       0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
+       0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
+       0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
+       0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
+       0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
+       0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
+       0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
+       0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
+       0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
+       0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
+       0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
+       0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
+       0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
+       0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
+       0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
+       0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
+       0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
+       0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
+       0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
+       0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
+       0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
+       0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
+       0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
+       0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
+       0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
+       0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
+       0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
+       0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
+       0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
+       0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
+       0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+       0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
+       0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
+       0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
+       0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
+       0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
+       0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
+       0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
+       0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
+       0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
+       0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+       0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
+       0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
+       0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
+       0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
+       0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
+       0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
+       0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
+       0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
+       0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
+       0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
+       0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
+       0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+       0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
+       0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
+       0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+       0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
+       0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
+       0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
+       0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
+       0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
+       0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
+       0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
+       0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+       0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+       0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
+       0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+       0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
+       0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
+       0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+       0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+       0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
+       0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
+       0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
+       0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
+       0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
+       0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
+       0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
+       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
+       0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
+       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+       0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
+       0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
+       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
+       0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
+       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+       0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
+       0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
+       0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
+       0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+       0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
+       0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+       0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
+       0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
+       0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
+       0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
+       0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
+       0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
+       0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
+       0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
+       0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
+       0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
+       0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
+       0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
+       0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
+       0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
+       0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
+       0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
+       0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+       0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+       0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+       0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
+       0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
+       0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
+       0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
+       0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
+       0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+       0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
+       0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
+       0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
+       0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
+       0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+       0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+       0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
+       0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
+       0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
+       0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
+       0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+       0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
+       0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
+       0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
+       0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+       0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
+       0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
+       0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
+       0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
+       0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
+       0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
+       0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
+       0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
+       0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+       0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
+       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
+       0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
+       0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
+       0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+       0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
+       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
+       0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+       0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
+       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
+       0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+       0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
+       0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
+       0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
+       0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
+       0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
+       0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
+       0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
+       0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
+       0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
+       0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+       0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
+       0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+       0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+       0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
+       0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+       0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+       0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+       0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
+       0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
+       0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+       0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+       0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
+       0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+       0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
+       0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
+       0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+       0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+       0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
+       0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
+       0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+       0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static unsigned char setup5[] = {
+       0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
+       0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
+       0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
+       0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
+       0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
+       0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
+       0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
+       0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
+       0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
+       0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
+       0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
+       0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
+       0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
+       0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
+       0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
+       0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
+       0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
+       0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
+       0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
+       0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
+       0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
+       0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
+       0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
+       0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
+       0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
+       0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
+       0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
+       0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
+       0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
+       0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
+       0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
+       0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
+       0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
+       0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
+       0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
+       0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
+       0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
+       0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
+       0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
+
+/* rvmalloc / rvfree copied from usbvideo.c
+ *
+ * Not sure why these are not yet non-statics which I can reference through
+ * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
+ * in the future.
+ * 
+*/
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+struct vicam_camera {
+       u16 shutter_speed;      // capture shutter speed
+       u16 gain;               // capture gain
+
+       u8 *raw_image;          // raw data captured from the camera
+       u8 *framebuf;           // processed data in RGB24 format
+       u8 *cntrlbuf;           // area used to send control msgs
+
+       struct video_device vdev;       // v4l video device
+       struct usb_device *udev;        // usb device
+
+       /* guard against simultaneous accesses to the camera */
+       struct mutex cam_lock;
+
+       int is_initialized;
+       u8 open_count;
+       u8 bulkEndpoint;
+       int needsDummyRead;
+
+#if defined(CONFIG_VIDEO_PROC_FS)
+       struct proc_dir_entry *proc_dir;
+#endif
+
+};
+
+static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
+static void vicam_disconnect(struct usb_interface *intf);
+static void read_frame(struct vicam_camera *cam, int framenum);
+static void vicam_decode_color(const u8 *, u8 *);
+
+static int __send_control_msg(struct vicam_camera *cam,
+                             u8 request,
+                             u16 value,
+                             u16 index,
+                             unsigned char *cp,
+                             u16 size)
+{
+       int status;
+
+       /* cp must be memory that has been allocated by kmalloc */
+
+       status = usb_control_msg(cam->udev,
+                                usb_sndctrlpipe(cam->udev, 0),
+                                request,
+                                USB_DIR_OUT | USB_TYPE_VENDOR |
+                                USB_RECIP_DEVICE, value, index,
+                                cp, size, 1000);
+
+       status = min(status, 0);
+
+       if (status < 0) {
+               printk(KERN_INFO "Failed sending control message, error %d.\n",
+                      status);
+       }
+
+       return status;
+}
+
+static int send_control_msg(struct vicam_camera *cam,
+                           u8 request,
+                           u16 value,
+                           u16 index,
+                           unsigned char *cp,
+                           u16 size)
+{
+       int status = -ENODEV;
+       mutex_lock(&cam->cam_lock);
+       if (cam->udev) {
+               status = __send_control_msg(cam, request, value,
+                                           index, cp, size);
+       }
+       mutex_unlock(&cam->cam_lock);
+       return status;
+}
+static int
+initialize_camera(struct vicam_camera *cam)
+{
+       const struct {
+               u8 *data;
+               u32 size;
+       } firmware[] = {
+               { .data = setup1, .size = sizeof(setup1) },
+               { .data = setup2, .size = sizeof(setup2) },
+               { .data = setup3, .size = sizeof(setup3) },
+               { .data = setup4, .size = sizeof(setup4) },
+               { .data = setup5, .size = sizeof(setup5) },
+               { .data = setup3, .size = sizeof(setup3) },
+               { .data = NULL, .size = 0 }
+       };
+
+       int err, i;
+
+       for (i = 0, err = 0; firmware[i].data && !err; i++) {
+               memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
+
+               err = send_control_msg(cam, 0xff, 0, 0,
+                                      cam->cntrlbuf, firmware[i].size);
+       }
+
+       return err;
+}
+
+static int
+set_camera_power(struct vicam_camera *cam, int state)
+{
+       int status;
+
+       if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
+               return status;
+
+       if (state) {
+               send_control_msg(cam, 0x55, 1, 0, NULL, 0);
+       }
+
+       return 0;
+}
+
+static int
+vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
+{
+       void __user *user_arg = (void __user *)arg;
+       struct vicam_camera *cam = file->private_data;
+       int retval = 0;
+
+       if (!cam)
+               return -ENODEV;
+
+       switch (ioctlnr) {
+               /* query capabilities */
+       case VIDIOCGCAP:
+               {
+                       struct video_capability b;
+
+                       DBG("VIDIOCGCAP\n");
+                       memset(&b, 0, sizeof(b));
+                       strcpy(b.name, "ViCam-based Camera");
+                       b.type = VID_TYPE_CAPTURE;
+                       b.channels = 1;
+                       b.audios = 0;
+                       b.maxwidth = 320;       /* VIDEOSIZE_CIF */
+                       b.maxheight = 240;
+                       b.minwidth = 320;       /* VIDEOSIZE_48_48 */
+                       b.minheight = 240;
+
+                       if (copy_to_user(user_arg, &b, sizeof(b)))
+                               retval = -EFAULT;
+
+                       break;
+               }
+               /* get/set video source - we are a camera and nothing else */
+       case VIDIOCGCHAN:
+               {
+                       struct video_channel v;
+
+                       DBG("VIDIOCGCHAN\n");
+                       if (copy_from_user(&v, user_arg, sizeof(v))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+                       if (v.channel != 0) {
+                               retval = -EINVAL;
+                               break;
+                       }
+
+                       v.channel = 0;
+                       strcpy(v.name, "Camera");
+                       v.tuners = 0;
+                       v.flags = 0;
+                       v.type = VIDEO_TYPE_CAMERA;
+                       v.norm = 0;
+
+                       if (copy_to_user(user_arg, &v, sizeof(v)))
+                               retval = -EFAULT;
+                       break;
+               }
+
+       case VIDIOCSCHAN:
+               {
+                       int v;
+
+                       if (copy_from_user(&v, user_arg, sizeof(v)))
+                               retval = -EFAULT;
+                       DBG("VIDIOCSCHAN %d\n", v);
+
+                       if (retval == 0 && v != 0)
+                               retval = -EINVAL;
+
+                       break;
+               }
+
+               /* image properties */
+       case VIDIOCGPICT:
+               {
+                       struct video_picture vp;
+                       DBG("VIDIOCGPICT\n");
+                       memset(&vp, 0, sizeof (struct video_picture));
+                       vp.brightness = cam->gain << 8;
+                       vp.depth = 24;
+                       vp.palette = VIDEO_PALETTE_RGB24;
+                       if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
+                               retval = -EFAULT;
+                       break;
+               }
+
+       case VIDIOCSPICT:
+               {
+                       struct video_picture vp;
+                       
+                       if (copy_from_user(&vp, user_arg, sizeof(vp))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+                       
+                       DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
+                           vp.palette);
+
+                       cam->gain = vp.brightness >> 8;
+
+                       if (vp.depth != 24
+                           || vp.palette != VIDEO_PALETTE_RGB24)
+                               retval = -EINVAL;
+
+                       break;
+               }
+
+               /* get/set capture window */
+       case VIDIOCGWIN:
+               {
+                       struct video_window vw;
+                       vw.x = 0;
+                       vw.y = 0;
+                       vw.width = 320;
+                       vw.height = 240;
+                       vw.chromakey = 0;
+                       vw.flags = 0;
+                       vw.clips = NULL;
+                       vw.clipcount = 0;
+
+                       DBG("VIDIOCGWIN\n");
+
+                       if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
+                               retval = -EFAULT;
+
+                       // I'm not sure what the deal with a capture window is, it is very poorly described
+                       // in the doc.  So I won't support it now.
+                       break;
+               }
+
+       case VIDIOCSWIN:
+               {
+
+                       struct video_window vw;
+
+                       if (copy_from_user(&vw, user_arg, sizeof(vw))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+
+                       DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
+                       
+                       if ( vw.width != 320 || vw.height != 240 )
+                               retval = -EFAULT;
+
+                       break;
+               }
+
+               /* mmap interface */
+       case VIDIOCGMBUF:
+               {
+                       struct video_mbuf vm;
+                       int i;
+
+                       DBG("VIDIOCGMBUF\n");
+                       memset(&vm, 0, sizeof (vm));
+                       vm.size =
+                           VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
+                       vm.frames = VICAM_FRAMES;
+                       for (i = 0; i < VICAM_FRAMES; i++)
+                               vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
+
+                       if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
+                               retval = -EFAULT;
+
+                       break;
+               }
+
+       case VIDIOCMCAPTURE:
+               {
+                       struct video_mmap vm;
+                       // int video_size;
+
+                       if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+
+                       DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
+
+                       if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
+                               retval = -EINVAL;
+
+                       // in theory right here we'd start the image capturing
+                       // (fill in a bulk urb and submit it asynchronously)
+                       //
+                       // Instead we're going to do a total hack job for now and
+                       // retrieve the frame in VIDIOCSYNC
+
+                       break;
+               }
+
+       case VIDIOCSYNC:
+               {
+                       int frame;
+
+                       if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
+                               retval = -EFAULT;
+                               break;
+                       }
+                       DBG("VIDIOCSYNC: %d\n", frame);
+
+                       read_frame(cam, frame);
+                       vicam_decode_color(cam->raw_image,
+                                          cam->framebuf +
+                                          frame * VICAM_MAX_FRAME_SIZE );
+
+                       break;
+               }
+
+               /* pointless to implement overlay with this camera */
+       case VIDIOCCAPTURE:
+       case VIDIOCGFBUF:
+       case VIDIOCSFBUF:
+       case VIDIOCKEY:
+               retval = -EINVAL;
+               break;
+
+               /* tuner interface - we have none */
+       case VIDIOCGTUNER:
+       case VIDIOCSTUNER:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+               retval = -EINVAL;
+               break;
+
+               /* audio interface - we have none */
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+               retval = -EINVAL;
+               break;
+       default:
+               retval = -ENOIOCTLCMD;
+               break;
+       }
+
+       return retval;
+}
+
+static int
+vicam_open(struct inode *inode, struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct vicam_camera *cam =
+           (struct vicam_camera *) dev->priv;
+       DBG("open\n");
+
+       if (!cam) {
+               printk(KERN_ERR
+                      "vicam video_device improperly initialized");
+               return -EINVAL;
+       }
+
+       /* the videodev_lock held above us protects us from
+        * simultaneous opens...for now. we probably shouldn't
+        * rely on this fact forever.
+        */
+
+       if (cam->open_count > 0) {
+               printk(KERN_INFO
+                      "vicam_open called on already opened camera");
+               return -EBUSY;
+       }
+
+       cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
+       if (!cam->raw_image) {
+               return -ENOMEM;
+       }
+
+       cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+       if (!cam->framebuf) {
+               kfree(cam->raw_image);
+               return -ENOMEM;
+       }
+
+       cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!cam->cntrlbuf) {
+               kfree(cam->raw_image);
+               rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+               return -ENOMEM;
+       }
+
+       // First upload firmware, then turn the camera on
+
+       if (!cam->is_initialized) {
+               initialize_camera(cam);
+
+               cam->is_initialized = 1;
+       }
+
+       set_camera_power(cam, 1);
+
+       cam->needsDummyRead = 1;
+       cam->open_count++;
+
+       file->private_data = cam;       
+       
+       return 0;
+}
+
+static int 
+vicam_close(struct inode *inode, struct file *file)
+{
+       struct vicam_camera *cam = file->private_data;
+       int open_count;
+       struct usb_device *udev;
+
+       DBG("close\n");
+
+       /* it's not the end of the world if
+        * we fail to turn the camera off.
+        */
+
+       set_camera_power(cam, 0);
+
+       kfree(cam->raw_image);
+       rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+       kfree(cam->cntrlbuf);
+
+       mutex_lock(&cam->cam_lock);
+
+       cam->open_count--;
+       open_count = cam->open_count;
+       udev = cam->udev;
+
+       mutex_unlock(&cam->cam_lock);
+
+       if (!open_count && !udev) {
+               kfree(cam);
+       }
+
+       return 0;
+}
+
+static void vicam_decode_color(const u8 *data, u8 *rgb)
+{
+       /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
+        * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
+        */
+
+       int i, prevY, nextY;
+
+       prevY = 512;
+       nextY = 512;
+
+       data += VICAM_HEADER_SIZE;
+
+       for( i = 0; i < 240; i++, data += 512 ) {
+               const int y = ( i * 242 ) / 240;
+
+               int j, prevX, nextX;
+               int Y, Cr, Cb;
+
+               if ( y == 242 - 1 ) {
+                       nextY = -512;
+               }
+
+               prevX = 1;
+               nextX = 1;
+
+               for ( j = 0; j < 320; j++, rgb += 3 ) {
+                       const int x = ( j * 512 ) / 320;
+                       const u8 * const src = &data[x];
+
+                       if ( x == 512 - 1 ) {
+                               nextX = -1;
+                       }
+
+                       Cr = ( src[prevX] - src[0] ) +
+                               ( src[nextX] - src[0] );
+                       Cr /= 2;
+
+                       Cb = ( src[prevY] - src[prevX + prevY] ) +
+                               ( src[prevY] - src[nextX + prevY] ) +
+                               ( src[nextY] - src[prevX + nextY] ) +
+                               ( src[nextY] - src[nextX + nextY] );
+                       Cb /= 4;
+
+                       Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
+
+                       if ( i & 1 ) {
+                               int Ct = Cr;
+                               Cr = Cb;
+                               Cb = Ct;
+                       }
+
+                       if ( ( x ^ i ) & 1 ) {
+                               Cr = -Cr;
+                               Cb = -Cb;
+                       }
+
+                       rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
+                                       500 ) / 900, 0, 255 );
+                       rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
+                                         ( 813 * Cr ) ) +
+                                         500 ) / 1000, 0, 255 );
+                       rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
+                                       500 ) / 1300, 0, 255 );
+
+                       prevX = -1;
+               }
+
+               prevY = -512;
+       }
+}
+
+static void
+read_frame(struct vicam_camera *cam, int framenum)
+{
+       unsigned char *request = cam->cntrlbuf;
+       int realShutter;
+       int n;
+       int actual_length;
+
+       if (cam->needsDummyRead) {
+               cam->needsDummyRead = 0;
+               read_frame(cam, framenum);
+       }
+
+       memset(request, 0, 16);
+       request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
+
+       request[1] = 0; // 512x242 capture
+
+       request[2] = 0x90;      // the function of these two bytes
+       request[3] = 0x07;      // is not yet understood
+
+       if (cam->shutter_speed > 60) {
+               // Short exposure
+               realShutter =
+                   ((-15631900 / cam->shutter_speed) + 260533) / 1000;
+               request[4] = realShutter & 0xFF;
+               request[5] = (realShutter >> 8) & 0xFF;
+               request[6] = 0x03;
+               request[7] = 0x01;
+       } else {
+               // Long exposure
+               realShutter = 15600 / cam->shutter_speed - 1;
+               request[4] = 0;
+               request[5] = 0;
+               request[6] = realShutter & 0xFF;
+               request[7] = realShutter >> 8;
+       }
+
+       // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
+       request[8] = 0;
+       // bytes 9-15 do not seem to affect exposure or image quality
+
+       mutex_lock(&cam->cam_lock);
+
+       if (!cam->udev) {
+               goto done;
+       }
+
+       n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
+
+       if (n < 0) {
+               printk(KERN_ERR
+                      " Problem sending frame capture control message");
+               goto done;
+       }
+
+       n = usb_bulk_msg(cam->udev,
+                        usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
+                        cam->raw_image,
+                        512 * 242 + 128, &actual_length, 10000);
+
+       if (n < 0) {
+               printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
+                      n);
+       }
+
+ done:
+       mutex_unlock(&cam->cam_lock);
+}
+
+static ssize_t
+vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
+{
+       struct vicam_camera *cam = file->private_data;
+
+       DBG("read %d bytes.\n", (int) count);
+
+       if (*ppos >= VICAM_MAX_FRAME_SIZE) {
+               *ppos = 0;
+               return 0;
+       }
+
+       if (*ppos == 0) {
+               read_frame(cam, 0);
+               vicam_decode_color(cam->raw_image,
+                                  cam->framebuf +
+                                  0 * VICAM_MAX_FRAME_SIZE);
+       }
+
+       count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
+
+       if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
+               count = -EFAULT;
+       } else {
+               *ppos += count;
+       }
+
+       if (count == VICAM_MAX_FRAME_SIZE) {
+               *ppos = 0;
+       }
+
+       return count;
+}
+
+
+static int
+vicam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       // TODO: allocate the raw frame buffer if necessary
+       unsigned long page, pos;
+       unsigned long start = vma->vm_start;
+       unsigned long size  = vma->vm_end-vma->vm_start;
+       struct vicam_camera *cam = file->private_data;
+
+       if (!cam)
+               return -ENODEV;
+
+       DBG("vicam_mmap: %ld\n", size);
+
+       /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
+        * to the size the application requested for mmap and it was screwing apps up.
+        if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
+        return -EINVAL;
+        */
+
+       pos = (unsigned long)cam->framebuf;
+       while (size > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+                       return -EAGAIN;
+
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *vicam_proc_root = NULL;
+
+static int vicam_read_helper(char *page, char **start, off_t off,
+                               int count, int *eof, int value)
+{
+       char *out = page;
+       int len;
+
+       out += sprintf(out, "%d",value);
+
+       len = out - page;
+       len -= off;
+       if (len < count) {
+               *eof = 1;
+               if (len <= 0)
+                       return 0;
+       } else
+               len = count;
+
+       *start = page + off;
+       return len;
+}
+
+static int vicam_read_proc_shutter(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       return vicam_read_helper(page,start,off,count,eof,
+                               ((struct vicam_camera *)data)->shutter_speed);
+}
+
+static int vicam_read_proc_gain(char *page, char **start, off_t off,
+                               int count, int *eof, void *data)
+{
+       return vicam_read_helper(page,start,off,count,eof,
+                               ((struct vicam_camera *)data)->gain);
+}
+
+static int
+vicam_write_proc_shutter(struct file *file, const char *buffer,
+                        unsigned long count, void *data)
+{
+       u16 stmp;
+       char kbuf[8];
+       struct vicam_camera *cam = (struct vicam_camera *) data;
+
+       if (count > 6)
+               return -EINVAL;
+
+       if (copy_from_user(kbuf, buffer, count))
+               return -EFAULT;
+
+       stmp = (u16) simple_strtoul(kbuf, NULL, 10);
+       if (stmp < 4 || stmp > 32000)
+               return -EINVAL;
+
+       cam->shutter_speed = stmp;
+
+       return count;
+}
+
+static int
+vicam_write_proc_gain(struct file *file, const char *buffer,
+                     unsigned long count, void *data)
+{
+       u16 gtmp;
+       char kbuf[8];
+
+       struct vicam_camera *cam = (struct vicam_camera *) data;
+
+       if (count > 4)
+               return -EINVAL;
+
+       if (copy_from_user(kbuf, buffer, count))
+               return -EFAULT;
+
+       gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
+       if (gtmp > 255)
+               return -EINVAL;
+       cam->gain = gtmp;
+
+       return count;
+}
+
+static void
+vicam_create_proc_root(void)
+{
+       vicam_proc_root = proc_mkdir("video/vicam", NULL);
+
+       if (vicam_proc_root)
+               vicam_proc_root->owner = THIS_MODULE;
+       else
+               printk(KERN_ERR
+                      "could not create /proc entry for vicam!");
+}
+
+static void
+vicam_destroy_proc_root(void)
+{
+       if (vicam_proc_root)
+               remove_proc_entry("video/vicam", 0);
+}
+
+static void
+vicam_create_proc_entry(struct vicam_camera *cam)
+{
+       char name[64];
+       struct proc_dir_entry *ent;
+
+       DBG(KERN_INFO "vicam: creating proc entry\n");
+
+       if (!vicam_proc_root || !cam) {
+               printk(KERN_INFO
+                      "vicam: could not create proc entry, %s pointer is null.\n",
+                      (!cam ? "camera" : "root"));
+               return;
+       }
+
+       sprintf(name, "video%d", cam->vdev.minor);
+
+       cam->proc_dir = proc_mkdir(name, vicam_proc_root);
+
+       if ( !cam->proc_dir )
+               return; // FIXME: We should probably return an error here
+       
+       ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
+                               cam->proc_dir);
+       if (ent) {
+               ent->data = cam;
+               ent->read_proc = vicam_read_proc_shutter;
+               ent->write_proc = vicam_write_proc_shutter;
+               ent->size = 64;
+       }
+
+       ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
+                               cam->proc_dir);
+       if (ent) {
+               ent->data = cam;
+               ent->read_proc = vicam_read_proc_gain;
+               ent->write_proc = vicam_write_proc_gain;
+               ent->size = 64;
+       }
+}
+
+static void
+vicam_destroy_proc_entry(void *ptr)
+{
+       struct vicam_camera *cam = (struct vicam_camera *) ptr;
+       char name[16];
+
+       if ( !cam->proc_dir )
+               return;
+
+       sprintf(name, "video%d", cam->vdev.minor);
+       remove_proc_entry("shutter", cam->proc_dir);
+       remove_proc_entry("gain", cam->proc_dir);
+       remove_proc_entry(name,vicam_proc_root);
+       cam->proc_dir = NULL;
+
+}
+
+#else
+static inline void vicam_create_proc_root(void) { }
+static inline void vicam_destroy_proc_root(void) { }
+static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
+static inline void vicam_destroy_proc_entry(void *ptr) { }
+#endif
+
+static struct file_operations vicam_fops = {
+       .owner          = THIS_MODULE,
+       .open           = vicam_open,
+       .release        = vicam_close,
+       .read           = vicam_read,
+       .mmap           = vicam_mmap,
+       .ioctl          = vicam_ioctl,
+       .compat_ioctl   = v4l_compat_ioctl32,
+       .llseek         = no_llseek,
+};
+
+static struct video_device vicam_template = {
+       .owner          = THIS_MODULE,
+       .name           = "ViCam-based USB Camera",
+       .type           = VID_TYPE_CAPTURE,
+       .hardware       = VID_HARDWARE_VICAM,
+       .fops           = &vicam_fops,
+       .minor          = -1,
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table[] = {
+       {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, vicam_table);
+
+static struct usb_driver vicam_driver = {
+       .name           = "vicam",
+       .probe          = vicam_probe,
+       .disconnect     = vicam_disconnect,
+       .id_table       = vicam_table
+};
+
+/**
+ *     vicam_probe
+ *     @intf: the interface
+ *     @id: the device id
+ *
+ *     Called by the usb core when a new device is connected that it thinks
+ *     this driver might be interested in.
+ */
+static int
+vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       int bulkEndpoint = 0;
+       const struct usb_host_interface *interface;
+       const struct usb_endpoint_descriptor *endpoint;
+       struct vicam_camera *cam;
+       
+       printk(KERN_INFO "ViCam based webcam connected\n");
+
+       interface = intf->cur_altsetting;
+
+       DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
+              interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
+       endpoint = &interface->endpoint[0].desc;
+
+       if ((endpoint->bEndpointAddress & 0x80) &&
+           ((endpoint->bmAttributes & 3) == 0x02)) {
+               /* we found a bulk in endpoint */
+               bulkEndpoint = endpoint->bEndpointAddress;
+       } else {
+               printk(KERN_ERR
+                      "No bulk in endpoint was found ?! (this is bad)\n");
+       }
+
+       if ((cam =
+            kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+               printk(KERN_WARNING
+                      "could not allocate kernel memory for vicam_camera struct\n");
+               return -ENOMEM;
+       }
+
+       memset(cam, 0, sizeof (struct vicam_camera));
+
+       cam->shutter_speed = 15;
+
+       mutex_init(&cam->cam_lock);
+
+       memcpy(&cam->vdev, &vicam_template,
+              sizeof (vicam_template));
+       cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
+
+       cam->udev = dev;
+       cam->bulkEndpoint = bulkEndpoint;
+
+       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+               kfree(cam);
+               printk(KERN_WARNING "video_register_device failed\n");
+               return -EIO;
+       }
+
+       vicam_create_proc_entry(cam);
+
+       printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
+
+       usb_set_intfdata (intf, cam);
+       
+       return 0;
+}
+
+static void
+vicam_disconnect(struct usb_interface *intf)
+{
+       int open_count;
+       struct vicam_camera *cam = usb_get_intfdata (intf);
+       usb_set_intfdata (intf, NULL);
+
+       /* we must unregister the device before taking its
+        * cam_lock. This is because the video open call
+        * holds the same lock as video unregister. if we
+        * unregister inside of the cam_lock and open also
+        * uses the cam_lock, we get deadlock.
+        */
+
+       video_unregister_device(&cam->vdev);
+
+       /* stop the camera from being used */
+
+       mutex_lock(&cam->cam_lock);
+
+       /* mark the camera as gone */
+
+       cam->udev = NULL;
+
+       vicam_destroy_proc_entry(cam);
+
+       /* the only thing left to do is synchronize with
+        * our close/release function on who should release
+        * the camera memory. if there are any users using the
+        * camera, it's their job. if there are no users,
+        * it's ours.
+        */
+
+       open_count = cam->open_count;
+
+       mutex_unlock(&cam->cam_lock);
+
+       if (!open_count) {
+               kfree(cam);
+       }
+
+       printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
+}
+
+/*
+ */
+static int __init
+usb_vicam_init(void)
+{
+       int retval;
+       DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
+       vicam_create_proc_root();
+       retval = usb_register(&vicam_driver);
+       if (retval)
+               printk(KERN_WARNING "usb_register failed!\n");
+       return retval;
+}
+
+static void __exit
+usb_vicam_exit(void)
+{
+       DBG(KERN_INFO
+              "ViCam-based WebCam driver shutdown\n");
+
+       usb_deregister(&vicam_driver);
+       vicam_destroy_proc_root();
+}
+
+module_init(usb_vicam_init);
+module_exit(usb_vicam_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
new file mode 100644 (file)
index 0000000..b57dec3
--- /dev/null
@@ -0,0 +1,3691 @@
+/***************************************************************************
+ * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
+ *                                                                         *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * - Memory management code from bttv driver by Ralph Metzler,             *
+ *   Marcus Metzler and Gerd Knorr.                                        *
+ * - I2C interface to kernel, high-level image sensor control routines and *
+ *   some symbolic names from OV511 driver by Mark W. McClelland.          *
+ * - Low-level I2C fast write function by Piotr Czerczak.                  *
+ * - Low-level I2C read function by Frederic Jouault.                      *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <linux/page-flags.h>
+#include <linux/moduleparam.h>
+
+#include "w9968cf.h"
+#include "w9968cf_decoder.h"
+
+static struct w9968cf_vpp_t* w9968cf_vpp;
+static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
+
+static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
+static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
+
+static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
+
+
+/****************************************************************************
+ * Module macros and parameters                                             *
+ ****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, winbond_id_table);
+
+MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
+MODULE_VERSION(W9968CF_MODULE_VERSION);
+MODULE_LICENSE(W9968CF_MODULE_LICENSE);
+MODULE_SUPPORTED_DEVICE("Video");
+
+static int ovmod_load = W9968CF_OVMOD_LOAD;
+static unsigned short simcams = W9968CF_SIMCAMS;
+static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
+static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                     W9968CF_PACKET_SIZE};
+static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                       W9968CF_BUFFERS};
+static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                              W9968CF_DOUBLE_BUFFER};
+static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
+static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                      W9968CF_FILTER_TYPE};
+static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
+static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                         W9968CF_DECOMPRESSION};
+static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
+static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
+static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
+static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
+static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
+static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                     W9968CF_LIGHTFREQ};
+static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
+                              W9968CF_BANDINGFILTER};
+static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
+static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
+static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
+static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
+static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                    W9968CF_BRIGHTNESS};
+static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
+static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
+static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                  W9968CF_CONTRAST};
+static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
+                                   W9968CF_WHITENESS};
+#ifdef W9968CF_DEBUG
+static unsigned short debug = W9968CF_DEBUG_LEVEL;
+static int specific_debug = W9968CF_SPECIFIC_DEBUG;
+#endif
+
+static unsigned int param_nv[24]; /* number of values per parameter */
+
+#ifdef CONFIG_KMOD
+module_param(ovmod_load, bool, 0644);
+#endif
+module_param(simcams, ushort, 0644);
+module_param_array(video_nr, short, &param_nv[0], 0444);
+module_param_array(packet_size, uint, &param_nv[1], 0444);
+module_param_array(max_buffers, ushort, &param_nv[2], 0444);
+module_param_array(double_buffer, bool, &param_nv[3], 0444);
+module_param_array(clamping, bool, &param_nv[4], 0444);
+module_param_array(filter_type, ushort, &param_nv[5], 0444);
+module_param_array(largeview, bool, &param_nv[6], 0444);
+module_param_array(decompression, ushort, &param_nv[7], 0444);
+module_param_array(upscaling, bool, &param_nv[8], 0444);
+module_param_array(force_palette, ushort, &param_nv[9], 0444);
+module_param_array(force_rgb, ushort, &param_nv[10], 0444);
+module_param_array(autobright, bool, &param_nv[11], 0444);
+module_param_array(autoexp, bool, &param_nv[12], 0444);
+module_param_array(lightfreq, ushort, &param_nv[13], 0444);
+module_param_array(bandingfilter, bool, &param_nv[14], 0444);
+module_param_array(clockdiv, short, &param_nv[15], 0444);
+module_param_array(backlight, bool, &param_nv[16], 0444);
+module_param_array(mirror, bool, &param_nv[17], 0444);
+module_param_array(monochrome, bool, &param_nv[18], 0444);
+module_param_array(brightness, uint, &param_nv[19], 0444);
+module_param_array(hue, uint, &param_nv[20], 0444);
+module_param_array(colour, uint, &param_nv[21], 0444);
+module_param_array(contrast, uint, &param_nv[22], 0444);
+module_param_array(whiteness, uint, &param_nv[23], 0444);
+#ifdef W9968CF_DEBUG
+module_param(debug, ushort, 0644);
+module_param(specific_debug, bool, 0644);
+#endif
+
+#ifdef CONFIG_KMOD
+MODULE_PARM_DESC(ovmod_load, 
+                 "\n<0|1> Automatic 'ovcamchip' module loading."
+                 "\n0 disabled, 1 enabled."
+                 "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
+                 "\nmodule in the system, according to its configuration, and"
+                 "\nattempts to load that module automatically. This action is"
+                 "\nperformed once as soon as the 'w9968cf' module is loaded"
+                 "\ninto memory."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
+                 "\n");
+#endif
+MODULE_PARM_DESC(simcams, 
+                 "\n<n> Number of cameras allowed to stream simultaneously."
+                 "\nn may vary from 0 to "
+                 __MODULE_STRING(W9968CF_MAX_DEVICES)"."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
+                 "\n");
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
+                 " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+MODULE_PARM_DESC(packet_size,
+                 "\n<n[,...]> Specify the maximum data payload"
+                 "\nsize in bytes for alternate settings, for each device."
+                 "\nn is scaled between 63 and 1023 "
+                 "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
+                 "\n");
+MODULE_PARM_DESC(max_buffers,
+                 "\n<n[,...]> For advanced users."
+                 "\nSpecify the maximum number of video frame buffers"
+                 "\nto allocate for each device, from 2 to "
+                 __MODULE_STRING(W9968CF_MAX_BUFFERS)
+                 ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
+                 "\n");
+MODULE_PARM_DESC(double_buffer, 
+                 "\n<0|1[,...]> "
+                 "Hardware double buffering: 0 disabled, 1 enabled."
+                 "\nIt should be enabled if you want smooth video output: if"
+                 "\nyou obtain out of sync. video, disable it, or try to"
+                 "\ndecrease the 'clockdiv' module parameter value."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(clamping, 
+                 "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(filter_type, 
+                 "\n<0|1|2[,...]> Video filter type."
+                 "\n0 none, 1 (1-2-1) 3-tap filter, "
+                 "2 (2-3-6-3-2) 5-tap filter."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
+                 " for every device."
+                 "\nThe filter is used to reduce noise and aliasing artifacts"
+                 "\nproduced by the CCD or CMOS image sensor, and the scaling"
+                 " process."
+                 "\n");
+MODULE_PARM_DESC(largeview, 
+                 "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(upscaling, 
+                 "\n<0|1[,...]> Software scaling (for non-compressed video):"
+                 "\n0 disabled, 1 enabled."
+                 "\nDisable it if you have a slow CPU or you don't have"
+                 " enough memory."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
+                 " for every device."
+                 "\nIf 'w9968cf-vpp' is not present, this parameter is"
+                 " set to 0."
+                 "\n");
+MODULE_PARM_DESC(decompression,
+                 "\n<0|1|2[,...]> Software video decompression:"
+                 "\n- 0 disables decompression (doesn't allow formats needing"
+                 " decompression)"
+                 "\n- 1 forces decompression (allows formats needing"
+                 " decompression only);"
+                 "\n- 2 allows any permitted formats."
+                 "\nFormats supporting compressed video are YUV422P and"
+                 " YUV420P/YUV420 "
+                 "\nin any resolutions where both width and height are "
+                 "a multiple of 16."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
+                 " for every device."
+                 "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
+                 "\nnot allowed; in this case this parameter is set to 2."
+                 "\n");
+MODULE_PARM_DESC(force_palette,
+                 "\n<0"
+                 "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
+                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
+                 "[,...]>"
+                 " Force picture palette."
+                 "\nIn order:"
+                 "\n- 0 allows any of the following formats:"
+                 "\n- UYVY    16 bpp - Original video, compression disabled"
+                 "\n- YUV420  12 bpp - Original video, compression enabled"
+                 "\n- YUV422P 16 bpp - Original video, compression enabled"
+                 "\n- YUV420P 12 bpp - Original video, compression enabled"
+                 "\n- YUVY    16 bpp - Software conversion from UYVY"
+                 "\n- YUV422  16 bpp - Software conversion from UYVY"
+                 "\n- GREY     8 bpp - Software conversion from UYVY"
+                 "\n- RGB555  16 bpp - Software conversion from UYVY"
+                 "\n- RGB565  16 bpp - Software conversion from UYVY"
+                 "\n- RGB24   24 bpp - Software conversion from UYVY"
+                 "\n- RGB32   32 bpp - Software conversion from UYVY"
+                 "\nWhen not 0, this parameter will override 'decompression'."
+                 "\nDefault value is 0 for every device."
+                 "\nInitial palette is "
+                 __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
+                 "\nIf 'w9968cf-vpp' is not present, this parameter is"
+                 " set to 9 (UYVY)."
+                 "\n");
+MODULE_PARM_DESC(force_rgb, 
+                 "\n<0|1[,...]> Read RGB video data instead of BGR:"
+                 "\n 1 = use RGB component ordering."
+                 "\n 0 = use BGR component ordering."
+                 "\nThis parameter has effect when using RGBX palettes only."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(autobright,
+                 "\n<0|1[,...]> Image sensor automatically changes brightness:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(autoexp,
+                 "\n<0|1[,...]> Image sensor automatically changes exposure:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(lightfreq,
+                 "\n<50|60[,...]> Light frequency in Hz:"
+                 "\n 50 for European and Asian lighting,"
+                 " 60 for American lighting."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(bandingfilter,
+                 "\n<0|1[,...]> Banding filter to reduce effects of"
+                 " fluorescent lighting:"
+                 "\n 0 disabled, 1 enabled."
+                 "\nThis filter tries to reduce the pattern of horizontal"
+                 "\nlight/dark bands caused by some (usually fluorescent)"
+                 " lighting."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(clockdiv,
+                 "\n<-1|n[,...]> "
+                 "Force pixel clock divisor to a specific value (for experts):"
+                 "\n  n may vary from 0 to 127."
+                 "\n -1 for automatic value."
+                 "\nSee also the 'double_buffer' module parameter."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(backlight,
+                 "\n<0|1[,...]> Objects are lit from behind:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(mirror,
+                 "\n<0|1[,...]> Reverse image horizontally:"
+                 "\n 0 = no, 1 = yes"
+                 "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(monochrome,
+                 "\n<0|1[,...]> Use image sensor as monochrome sensor:"
+                 "\n 0 = no, 1 = yes"
+                 "\nNot all the sensors support monochrome color."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(brightness, 
+                 "\n<n[,...]> Set picture brightness (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
+                 " for every device."
+                 "\nThis parameter has no effect if 'autobright' is enabled."
+                 "\n");
+MODULE_PARM_DESC(hue, 
+                 "\n<n[,...]> Set picture hue (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(colour, 
+                 "\n<n[,...]> Set picture saturation (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(contrast, 
+                 "\n<n[,...]> Set picture contrast (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
+                 " for every device."
+                 "\n");
+MODULE_PARM_DESC(whiteness, 
+                 "\n<n[,...]> Set picture whiteness (0-65535)."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
+                 " for every device."
+                 "\n");
+#ifdef W9968CF_DEBUG
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 6:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = configuration or general messages"
+                 "\n4 = warnings"
+                 "\n5 = called functions"
+                 "\n6 = function internals"
+                 "\nLevel 5 and 6 are useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
+                 "\n");
+MODULE_PARM_DESC(specific_debug,
+                 "\n<0|1> Enable or disable specific debugging messages:"
+                 "\n0 = print messages concerning every level"
+                 " <= 'debug' level."
+                 "\n1 = print messages concerning the level"
+                 " indicated by 'debug'."
+                 "\nDefault value is "
+                 __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
+                 "\n");
+#endif /* W9968CF_DEBUG */
+
+
+
+/****************************************************************************
+ * Some prototypes                                                          *
+ ****************************************************************************/
+
+/* Video4linux interface */
+static struct file_operations w9968cf_fops;
+static int w9968cf_open(struct inode*, struct file*);
+static int w9968cf_release(struct inode*, struct file*);
+static int w9968cf_mmap(struct file*, struct vm_area_struct*);
+static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
+static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);
+static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int,
+                             void __user *);
+
+/* USB-specific */
+static int w9968cf_start_transfer(struct w9968cf_device*);
+static int w9968cf_stop_transfer(struct w9968cf_device*);
+static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
+static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
+static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
+static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
+static int w9968cf_read_sb(struct w9968cf_device*);
+static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
+static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
+
+/* Low-level I2C (SMBus) I/O */
+static int w9968cf_smbus_start(struct w9968cf_device*);
+static int w9968cf_smbus_stop(struct w9968cf_device*);
+static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
+static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
+static int w9968cf_smbus_write_ack(struct w9968cf_device*);
+static int w9968cf_smbus_read_ack(struct w9968cf_device*);
+static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
+static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
+                                      u16 address, u8* value);
+static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, 
+                                           u8 subaddress, u8* value);
+static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
+                                       u16 address, u8 subaddress);
+static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
+                                                u16 address, u8 subaddress,
+                                                u8 value);
+
+/* I2C interface to kernel */
+static int w9968cf_i2c_init(struct w9968cf_device*);
+static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, 
+                                  unsigned short flags, char read_write, 
+                                  u8 command, int size, union i2c_smbus_data*);
+static u32 w9968cf_i2c_func(struct i2c_adapter*);
+static int w9968cf_i2c_attach_inform(struct i2c_client*);
+static int w9968cf_i2c_detach_inform(struct i2c_client*);
+static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
+                               unsigned long arg);
+
+/* Memory management */
+static void* rvmalloc(unsigned long size);
+static void rvfree(void *mem, unsigned long size);
+static void w9968cf_deallocate_memory(struct w9968cf_device*);
+static int  w9968cf_allocate_memory(struct w9968cf_device*);
+
+/* High-level image sensor control functions */
+static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
+static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
+static int w9968cf_sensor_cmd(struct w9968cf_device*,
+                              unsigned int cmd, void *arg);
+static int w9968cf_sensor_init(struct w9968cf_device*);
+static int w9968cf_sensor_update_settings(struct w9968cf_device*);
+static int w9968cf_sensor_get_picture(struct w9968cf_device*);
+static int w9968cf_sensor_update_picture(struct w9968cf_device*, 
+                                         struct video_picture pict);
+
+/* Other helper functions */
+static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
+                                     enum w9968cf_model_id, 
+                                     const unsigned short dev_nr);
+static void w9968cf_adjust_configuration(struct w9968cf_device*);
+static int w9968cf_turn_on_led(struct w9968cf_device*);
+static int w9968cf_init_chip(struct w9968cf_device*);
+static inline u16 w9968cf_valid_palette(u16 palette);
+static inline u16 w9968cf_valid_depth(u16 palette);
+static inline u8 w9968cf_need_decompression(u16 palette);
+static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
+static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
+static int w9968cf_postprocess_frame(struct w9968cf_device*, 
+                                     struct w9968cf_frame_t*);
+static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
+static void w9968cf_init_framelist(struct w9968cf_device*);
+static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
+static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
+static void w9968cf_release_resources(struct w9968cf_device*);
+
+
+
+/****************************************************************************
+ * Symbolic names                                                           *
+ ****************************************************************************/
+
+/* Used to represent a list of values and their respective symbolic names */
+struct w9968cf_symbolic_list {
+       const int num;
+       const char *name;
+};
+
+/*-------------------------------------------------------------------------- 
+  Returns the name of the matching element in the symbolic_list array. The
+  end of the list must be marked with an element that has a NULL name.
+  --------------------------------------------------------------------------*/
+static inline const char * 
+symbolic(struct w9968cf_symbolic_list list[], const int num)
+{
+       int i;
+
+       for (i = 0; list[i].name != NULL; i++)
+               if (list[i].num == num)
+                       return (list[i].name);
+
+       return "Unknown";
+}
+
+static struct w9968cf_symbolic_list camlist[] = {
+       { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
+       { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
+
+       /* Other cameras (having the same descriptors as Generic W996[87]CF) */
+       { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
+       { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
+       { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
+       { W9968CF_MOD_LL, "Lebon LDC-035A" },
+       { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
+       { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
+       { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
+       { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
+       { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
+
+       {  -1, NULL }
+};
+
+static struct w9968cf_symbolic_list senlist[] = {
+       { CC_OV76BE,   "OV76BE" },
+       { CC_OV7610,   "OV7610" },
+       { CC_OV7620,   "OV7620" },
+       { CC_OV7620AE, "OV7620AE" },
+       { CC_OV6620,   "OV6620" },
+       { CC_OV6630,   "OV6630" },
+       { CC_OV6630AE, "OV6630AE" },
+       { CC_OV6630AF, "OV6630AF" },
+       { -1, NULL }
+};
+
+/* Video4Linux1 palettes */
+static struct w9968cf_symbolic_list v4l1_plist[] = {
+       { VIDEO_PALETTE_GREY,    "GREY" },
+       { VIDEO_PALETTE_HI240,   "HI240" },
+       { VIDEO_PALETTE_RGB565,  "RGB565" },
+       { VIDEO_PALETTE_RGB24,   "RGB24" },
+       { VIDEO_PALETTE_RGB32,   "RGB32" },
+       { VIDEO_PALETTE_RGB555,  "RGB555" },
+       { VIDEO_PALETTE_YUV422,  "YUV422" },
+       { VIDEO_PALETTE_YUYV,    "YUYV" },
+       { VIDEO_PALETTE_UYVY,    "UYVY" },
+       { VIDEO_PALETTE_YUV420,  "YUV420" },
+       { VIDEO_PALETTE_YUV411,  "YUV411" },
+       { VIDEO_PALETTE_RAW,     "RAW" },
+       { VIDEO_PALETTE_YUV422P, "YUV422P" },
+       { VIDEO_PALETTE_YUV411P, "YUV411P" },
+       { VIDEO_PALETTE_YUV420P, "YUV420P" },
+       { VIDEO_PALETTE_YUV410P, "YUV410P" },
+       { -1, NULL }
+};
+
+/* Decoder error codes: */
+static struct w9968cf_symbolic_list decoder_errlist[] = {
+       { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
+       { W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
+       { W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },     
+       { W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
+       { W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
+       { W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
+       { -1, NULL }
+};
+
+/* URB error codes: */
+static struct w9968cf_symbolic_list urb_errlist[] = {
+       { -ENOMEM,    "No memory for allocation of internal structures" },
+       { -ENOSPC,    "The host controller's bandwidth is already consumed" },
+       { -ENOENT,    "URB was canceled by unlink_urb" },
+       { -EXDEV,     "ISO transfer only partially completed" },
+       { -EAGAIN,    "Too match scheduled for the future" },
+       { -ENXIO,     "URB already queued" },
+       { -EFBIG,     "Too much ISO frames requested" },
+       { -ENOSR,     "Buffer error (overrun)" },
+       { -EPIPE,     "Specified endpoint is stalled (device not responding)"},
+       { -EOVERFLOW, "Babble (bad cable?)" },
+       { -EPROTO,    "Bit-stuff error (bad cable?)" },
+       { -EILSEQ,    "CRC/Timeout" },
+       { -ETIMEDOUT, "NAK (device does not respond)" },
+       { -1, NULL }
+};
+
+
+
+/****************************************************************************
+ * Memory management functions                                              *
+ ****************************************************************************/
+static void* rvmalloc(unsigned long size)
+{
+       void* mem;
+       unsigned long adr;
+
+       size = PAGE_ALIGN(size);
+       mem = vmalloc_32(size);
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               SetPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       return mem;
+}
+
+
+static void rvfree(void* mem, unsigned long size)
+{
+       unsigned long adr;
+
+       if (!mem)
+               return;
+
+       adr = (unsigned long) mem;
+       while ((long) size > 0) {
+               ClearPageReserved(vmalloc_to_page((void *)adr));
+               adr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+       vfree(mem);
+}
+
+
+/*--------------------------------------------------------------------------
+  Deallocate previously allocated memory.
+  --------------------------------------------------------------------------*/
+static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
+{
+       u8 i;
+
+       /* Free the isochronous transfer buffers */
+       for (i = 0; i < W9968CF_URBS; i++) {
+               kfree(cam->transfer_buffer[i]);
+               cam->transfer_buffer[i] = NULL;
+       }
+
+       /* Free temporary frame buffer */
+       if (cam->frame_tmp.buffer) {
+               rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
+               cam->frame_tmp.buffer = NULL;
+       }
+
+       /* Free helper buffer */
+       if (cam->frame_vpp.buffer) {
+               rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
+               cam->frame_vpp.buffer = NULL;
+       }
+
+       /* Free video frame buffers */
+       if (cam->frame[0].buffer) {
+               rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
+               cam->frame[0].buffer = NULL;
+       }
+
+       cam->nbuffers = 0;
+
+       DBG(5, "Memory successfully deallocated")
+}
+
+
+/*--------------------------------------------------------------------------
+  Allocate memory buffers for USB transfers and video frames.
+  This function is called by open() only.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_allocate_memory(struct w9968cf_device* cam)
+{
+       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
+       void* buff = NULL;
+       unsigned long hw_bufsize, vpp_bufsize;
+       u8 i, bpp;
+
+       /* NOTE: Deallocation is done elsewhere in case of error */
+
+       /* Calculate the max amount of raw data per frame from the device */
+       hw_bufsize = cam->maxwidth*cam->maxheight*2;
+
+       /* Calculate the max buf. size needed for post-processing routines */
+       bpp = (w9968cf_vpp) ? 4 : 2;
+       if (cam->upscaling)
+               vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
+                                 cam->maxwidth*cam->maxheight*bpp);
+       else
+               vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
+
+       /* Allocate memory for the isochronous transfer buffers */
+       for (i = 0; i < W9968CF_URBS; i++) {
+               if (!(cam->transfer_buffer[i] =
+                     kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
+                       DBG(1, "Couldn't allocate memory for the isochronous "
+                              "transfer buffers (%u bytes)", 
+                           p_size * W9968CF_ISO_PACKETS)
+                       return -ENOMEM;
+               }
+       }
+
+       /* Allocate memory for the temporary frame buffer */
+       if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
+               DBG(1, "Couldn't allocate memory for the temporary "
+                      "video frame buffer (%lu bytes)", hw_bufsize)
+               return -ENOMEM;
+       }
+       cam->frame_tmp.size = hw_bufsize;
+       cam->frame_tmp.number = -1;
+
+       /* Allocate memory for the helper buffer */
+       if (w9968cf_vpp) {
+               if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
+                       DBG(1, "Couldn't allocate memory for the helper buffer"
+                              " (%lu bytes)", vpp_bufsize)
+                       return -ENOMEM;
+               }
+               cam->frame_vpp.size = vpp_bufsize;
+       } else
+               cam->frame_vpp.buffer = NULL;
+
+       /* Allocate memory for video frame buffers */
+       cam->nbuffers = cam->max_buffers;
+       while (cam->nbuffers >= 2) {
+               if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
+                       break;
+               else
+                       cam->nbuffers--;
+       }
+
+       if (!buff) {
+               DBG(1, "Couldn't allocate memory for the video frame buffers")
+               cam->nbuffers = 0;
+               return -ENOMEM;
+       }
+
+       if (cam->nbuffers != cam->max_buffers)
+               DBG(2, "Couldn't allocate memory for %u video frame buffers. "
+                      "Only memory for %u buffers has been allocated",
+                   cam->max_buffers, cam->nbuffers)
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].buffer = buff + i*vpp_bufsize;
+               cam->frame[i].size = vpp_bufsize;
+               cam->frame[i].number = i;
+               /* Circular list */
+               if (i != cam->nbuffers-1)
+                       cam->frame[i].next = &cam->frame[i+1];
+               else
+                       cam->frame[i].next = &cam->frame[0];
+               cam->frame[i].status = F_UNUSED;
+       }
+
+       DBG(5, "Memory successfully allocated")
+       return 0;
+}
+
+
+
+/****************************************************************************
+ * USB-specific functions                                                   *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  This is an handler function which is called after the URBs are completed.
+  It collects multiple data packets coming from the camera by putting them
+  into frame buffers: one or more zero data length data packets are used to
+  mark the end of a video frame; the first non-zero data packet is the start
+  of the next video frame; if an error is encountered in a packet, the entire
+  video frame is discarded and grabbed again.
+  If there are no requested frames in the FIFO list, packets are collected into
+  a temporary buffer. 
+  --------------------------------------------------------------------------*/
+static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
+{
+       struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
+       struct w9968cf_frame_t** f;
+       unsigned int len, status;
+       void* pos;
+       u8 i;
+       int err = 0;
+
+       if ((!cam->streaming) || cam->disconnected) {
+               DBG(4, "Got interrupt, but not streaming")
+               return;
+       }
+
+       /* "(*f)" will be used instead of "cam->frame_current" */
+       f = &cam->frame_current;
+
+       /* If a frame has been requested and we are grabbing into  
+          the temporary frame, we'll switch to that requested frame */
+       if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
+               if (cam->frame_tmp.status == F_GRABBING) {
+                       w9968cf_pop_frame(cam, &cam->frame_current);
+                       (*f)->status = F_GRABBING;
+                       (*f)->length = cam->frame_tmp.length;
+                       memcpy((*f)->buffer, cam->frame_tmp.buffer,
+                              (*f)->length);
+                       DBG(6, "Switched from temp. frame to frame #%d", 
+                           (*f)->number)
+               }
+       }
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status && len != 0) {
+                       DBG(4, "URB failed, error in data packet "
+                              "(error #%u, %s)",
+                           status, symbolic(urb_errlist, status))
+                       (*f)->status = F_ERROR;
+                       continue;
+               }
+
+               if (len) { /* start of frame */
+
+                       if ((*f)->status == F_UNUSED) {
+                               (*f)->status = F_GRABBING;
+                               (*f)->length = 0;
+                       }
+
+                       /* Buffer overflows shouldn't happen, however...*/
+                       if ((*f)->length + len > (*f)->size) {
+                               DBG(4, "Buffer overflow: bad data packets")
+                               (*f)->status = F_ERROR;
+                       }
+
+                       if ((*f)->status == F_GRABBING) {
+                               memcpy((*f)->buffer + (*f)->length, pos, len);
+                               (*f)->length += len;
+                       }
+
+               } else if ((*f)->status == F_GRABBING) { /* end of frame */
+
+                       DBG(6, "Frame #%d successfully grabbed", (*f)->number)
+
+                       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+                               err = w9968cf_vpp->check_headers((*f)->buffer,
+                                                                (*f)->length);
+                               if (err) {
+                                       DBG(4, "Skip corrupted frame: %s",
+                                           symbolic(decoder_errlist, err))
+                                       (*f)->status = F_UNUSED;
+                                       continue; /* grab this frame again */
+                               }
+                       }
+
+                       (*f)->status = F_READY;
+                       (*f)->queued = 0;
+
+                       /* Take a pointer to the new frame from the FIFO list.
+                          If the list is empty,we'll use the temporary frame*/
+                       if (*cam->requested_frame)
+                               w9968cf_pop_frame(cam, &cam->frame_current);
+                       else {
+                               cam->frame_current = &cam->frame_tmp;
+                               (*f)->status = F_UNUSED;
+                       }
+
+               } else if ((*f)->status == F_ERROR)
+                       (*f)->status = F_UNUSED; /* grab it again */
+
+               PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
+                     (unsigned long)(*f)->length, i, len, (*f)->status)
+
+       } /* end for */
+
+       /* Resubmit this URB */
+       urb->dev = cam->usbdev;
+       urb->status = 0;
+       spin_lock(&cam->urb_lock);
+       if (cam->streaming)
+               if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
+                       cam->misconfigured = 1;
+                       DBG(1, "Couldn't resubmit the URB: error %d, %s",
+                           err, symbolic(urb_errlist, err))
+               }
+       spin_unlock(&cam->urb_lock);
+
+       /* Wake up the user process */
+       wake_up_interruptible(&cam->wait_queue);
+}
+
+
+/*---------------------------------------------------------------------------
+  Setup the URB structures for the isochronous transfer.
+  Submit the URBs so that the data transfer begins.
+  Return 0 on success, a negative number otherwise.
+  ---------------------------------------------------------------------------*/
+static int w9968cf_start_transfer(struct w9968cf_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
+       u16 w, h, d;
+       int vidcapt;
+       u32 t_size;
+       int err = 0;
+       s8 i, j;
+
+       for (i = 0; i < W9968CF_URBS; i++) {
+               urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       for (j = 0; j < i; j++)
+                               usb_free_urb(cam->urb[j]);
+                       DBG(1, "Couldn't allocate the URB structures")
+                       return -ENOMEM;
+               }
+
+               urb->dev = udev;
+               urb->context = (void*)cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = W9968CF_ISO_PACKETS;
+               urb->complete = w9968cf_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = p_size*j;
+                       urb->iso_frame_desc[j].length = p_size;
+               }
+       }
+
+       /* Transfer size per frame, in WORD ! */
+       d = cam->hw_depth;
+       w = cam->hw_width;
+       h = cam->hw_height;
+
+       t_size = (w*h*d)/16;
+
+       err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
+       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
+
+       /* Transfer size */
+       err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
+       err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
+
+       if (cam->vpp_flag & VPP_DECOMPRESSION)
+               err += w9968cf_upload_quantizationtables(cam);
+
+       vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
+       err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
+
+       err += usb_set_interface(udev, 0, cam->altsetting);
+       err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
+
+       if (err || (vidcapt < 0)) {
+               for (i = 0; i < W9968CF_URBS; i++)
+                       usb_free_urb(cam->urb[i]);
+               DBG(1, "Couldn't tell the camera to start the data transfer")
+               return err;
+       }
+
+       w9968cf_init_framelist(cam);
+
+       /* Begin to grab into the temporary buffer */
+       cam->frame_tmp.status = F_UNUSED;
+       cam->frame_tmp.queued = 0;
+       cam->frame_current = &cam->frame_tmp;
+
+       if (!(cam->vpp_flag & VPP_DECOMPRESSION))
+               DBG(5, "Isochronous transfer size: %lu bytes/frame", 
+                   (unsigned long)t_size*2)
+
+       DBG(5, "Starting the isochronous transfer...")
+
+       cam->streaming = 1;
+
+       /* Submit the URBs */
+       for (i = 0; i < W9968CF_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       cam->streaming = 0;
+                       for (j = i-1; j >= 0; j--) {
+                               usb_kill_urb(cam->urb[j]);
+                               usb_free_urb(cam->urb[j]);
+                       }
+                       DBG(1, "Couldn't send a transfer request to the "
+                              "USB core (error #%d, %s)", err, 
+                           symbolic(urb_errlist, err))
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_stop_transfer(struct w9968cf_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       unsigned long lock_flags;
+       int err = 0;
+       s8 i;
+
+       if (!cam->streaming)
+               return 0;
+
+       /* This avoids race conditions with usb_submit_urb() 
+          in the URB completition handler */
+       spin_lock_irqsave(&cam->urb_lock, lock_flags);
+       cam->streaming = 0;
+       spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
+
+       for (i = W9968CF_URBS-1; i >= 0; i--)
+               if (cam->urb[i]) {
+                       usb_kill_urb(cam->urb[i]);
+                       usb_free_urb(cam->urb[i]);
+                       cam->urb[i] = NULL;
+               }
+
+       if (cam->disconnected)
+               goto exit;
+
+       err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
+       err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
+       err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
+
+       if (err) {
+               DBG(2, "Failed to tell the camera to stop the isochronous "
+                      "transfer. However this is not a critical error.")
+               return -EIO;
+       }
+
+exit:
+       DBG(5, "Isochronous transfer stopped")
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write a W9968CF register. 
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       int res;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+                             value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
+
+       if (res < 0)
+               DBG(4, "Failed to write a register "
+                      "(value 0x%04X, index 0x%02X, error #%d, %s)",
+                   value, index, res, symbolic(urb_errlist, res))
+
+       return (res >= 0) ? 0 : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read a W9968CF register. 
+  Return the register value on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u16* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
+                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                             0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
+
+       if (res < 0)
+               DBG(4, "Failed to read a register "
+                      "(index 0x%02X, error #%d, %s)",
+                   index, res, symbolic(urb_errlist, res))
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write 64-bit data to the fast serial bus registers.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
+{
+       struct usb_device* udev = cam->usbdev;
+       u16 value;
+       int res;
+
+       value = *data++;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+                             value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
+
+       if (res < 0)
+               DBG(4, "Failed to write the FSB registers "
+                      "(error #%d, %s)", res, symbolic(urb_errlist, res))
+
+       return (res >= 0) ? 0 : -1;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write data to the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
+{
+       int err = 0;
+
+       err = w9968cf_write_reg(cam, value, 0x01);
+       udelay(W9968CF_I2C_BUS_DELAY);
+
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Read data from the serial bus control register.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_read_sb(struct w9968cf_device* cam)
+{
+       int v = 0;
+
+       v = w9968cf_read_reg(cam, 0x01);
+       udelay(W9968CF_I2C_BUS_DELAY);
+
+       return v;
+}
+
+
+/*--------------------------------------------------------------------------
+  Upload quantization tables for the JPEG compression.
+  This function is called by w9968cf_start_transfer().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
+{
+       u16 a, b;
+       int err = 0, i, j;
+
+       err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
+
+       for (i = 0, j = 0; i < 32; i++, j += 2) {
+               a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
+               b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
+               err += w9968cf_write_reg(cam, a, 0x40+i);
+               err += w9968cf_write_reg(cam, b, 0x60+i);
+       }
+       err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
+
+       return err;
+}
+
+
+
+/****************************************************************************
+ * Low-level I2C I/O functions.                                             *
+ * The adapter supports the following I2C transfer functions:               *
+ * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
+ * i2c_adap_read_byte_data()                                                *
+ * i2c_adap_read_byte()                                                     *
+ ****************************************************************************/
+
+static int w9968cf_smbus_start(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+       return err;
+}
+
+
+static int w9968cf_smbus_stop(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+
+       return err;
+}
+
+
+static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
+{
+       u8 bit;
+       int err = 0, sda;
+
+       for (bit = 0 ; bit < 8 ; bit++) {
+               sda = (v & 0x80) ? 2 : 0;
+               v <<= 1;
+               /* SDE=1, SDA=sda, SCL=0 */
+               err += w9968cf_write_sb(cam, 0x10 | sda);
+               /* SDE=1, SDA=sda, SCL=1 */
+               err += w9968cf_write_sb(cam, 0x11 | sda);
+               /* SDE=1, SDA=sda, SCL=0 */
+               err += w9968cf_write_sb(cam, 0x10 | sda);
+       }
+
+       return err;
+}
+
+
+static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
+{
+       u8 bit;
+       int err = 0;
+
+       *v = 0;
+       for (bit = 0 ; bit < 8 ; bit++) {
+               *v <<= 1;
+               err += w9968cf_write_sb(cam, 0x0013);
+               *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
+               err += w9968cf_write_sb(cam, 0x0012);
+       }
+
+       return err;
+}
+
+
+static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+
+       return err;
+}
+
+
+static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
+{
+       int err = 0, sda;
+
+       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+       sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
+       err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+       if (sda < 0)
+               err += sda;
+       if (sda == 1) {
+               DBG(6, "Couldn't receive the ACK")
+               err += -1;
+       }
+
+       return err;
+}
+
+
+/* This seems to refresh the communication through the serial bus */
+static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
+{
+       int err = 0, j;
+
+       for (j = 1; j <= 10; j++) {
+               err = w9968cf_write_reg(cam, 0x0020, 0x01);
+               err += w9968cf_write_reg(cam, 0x0000, 0x01);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
+static int 
+w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, 
+                                     u16 address, u8 subaddress,u8 value)
+{
+       u16* data = cam->data_buffer;
+       int err = 0;
+
+       err += w9968cf_smbus_refresh_bus(cam);
+
+       /* Enable SBUS outputs */
+       err += w9968cf_write_sb(cam, 0x0020);
+
+       data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
+       data[0] |= (address & 0x40) ? 0x4000 : 0x0;
+       data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
+       data[1] |= (address & 0x20) ? 0x0150 : 0x0;
+       data[1] |= (address & 0x10) ? 0x5400 : 0x0;
+       data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
+       data[2] |= (address & 0x04) ? 0x0540 : 0x0;
+       data[2] |= (address & 0x02) ? 0x5000 : 0x0;
+       data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
+       data[3] |= (address & 0x01) ? 0x0054 : 0x0;
+
+       err += w9968cf_write_fsb(cam, data);
+
+       data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
+       data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
+       data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
+       data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
+       data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
+       data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
+       data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
+       data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
+       data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
+       data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
+       data[3] = 0x001d;
+
+       err += w9968cf_write_fsb(cam, data);
+
+       data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
+       data[0] |= (value & 0x40) ? 0x0540 : 0x0;
+       data[0] |= (value & 0x20) ? 0x5000 : 0x0;
+       data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
+       data[1] |= (value & 0x10) ? 0x0054 : 0x0;
+       data[1] |= (value & 0x08) ? 0x1500 : 0x0;
+       data[1] |= (value & 0x04) ? 0x4000 : 0x0;
+       data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
+       data[2] |= (value & 0x02) ? 0x0150 : 0x0;
+       data[2] |= (value & 0x01) ? 0x5400 : 0x0;
+       data[3] = 0xfe1d;
+
+       err += w9968cf_write_fsb(cam, data);
+
+       /* Disable SBUS outputs */
+       err += w9968cf_write_sb(cam, 0x0000);
+
+       if (!err)
+               DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
+                      "value 0x%02X", address, subaddress, value)
+       else
+               DBG(5, "I2C write byte data failed, addr.0x%04X, "
+                      "subaddr.0x%02X, value 0x%02X", 
+                   address, subaddress, value)
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
+static int 
+w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, 
+                                u16 address, u8 subaddress, 
+                                u8* value)
+{
+       int err = 0;
+
+       /* Serial data enable */
+       err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
+
+       err += w9968cf_smbus_start(cam);
+       err += w9968cf_smbus_write_byte(cam, address);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_write_byte(cam, subaddress);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_stop(cam);
+       err += w9968cf_smbus_start(cam);
+       err += w9968cf_smbus_write_byte(cam, address + 1);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_read_byte(cam, value);
+       err += w9968cf_smbus_write_ack(cam);
+       err += w9968cf_smbus_stop(cam);
+
+       /* Serial data disable */
+       err += w9968cf_write_sb(cam, 0x0000);
+
+       if (!err)
+               DBG(5, "I2C read byte data done, addr.0x%04X, "
+                      "subaddr.0x%02X, value 0x%02X", 
+                   address, subaddress, *value)
+       else
+               DBG(5, "I2C read byte data failed, addr.0x%04X, "
+                      "subaddr.0x%02X, wrong value 0x%02X",
+                   address, subaddress, *value)
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
+static int 
+w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
+                           u16 address, u8* value)
+{
+       int err = 0;
+
+       /* Serial data enable */
+       err += w9968cf_write_sb(cam, 0x0013);
+
+       err += w9968cf_smbus_start(cam);
+       err += w9968cf_smbus_write_byte(cam, address + 1);
+       err += w9968cf_smbus_read_ack(cam);
+       err += w9968cf_smbus_read_byte(cam, value);
+       err += w9968cf_smbus_write_ack(cam);
+       err += w9968cf_smbus_stop(cam);
+       /* Serial data disable */
+       err += w9968cf_write_sb(cam, 0x0000);
+
+       if (!err)
+               DBG(5, "I2C read byte done, addr.0x%04X, "
+                      "value 0x%02X", address, *value)
+       else
+               DBG(5, "I2C read byte failed, addr.0x%04X, "
+                      "wrong value 0x%02X", address, *value)
+
+       return err;
+}
+
+
+/* SMBus protocol: S Addr Wr [A] Value [A] P */
+static int 
+w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
+                            u16 address, u8 value)
+{
+       DBG(4, "i2c_write_byte() is an unsupported transfer mode")
+       return -EINVAL;
+}
+
+
+
+/****************************************************************************
+ * I2C interface to kernel                                                  *
+ ****************************************************************************/
+
+static int
+w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 
+                       unsigned short flags, char read_write, u8 command,
+                       int size, union i2c_smbus_data *data)
+{
+       struct w9968cf_device* cam = i2c_get_adapdata(adapter);
+       u8 i;
+       int err = 0; 
+
+       switch (addr) {
+               case OV6xx0_SID:
+               case OV7xx0_SID:
+                       break;
+               default:
+                       DBG(4, "Rejected slave ID 0x%04X", addr)
+                       return -EINVAL;
+       }
+
+       if (size == I2C_SMBUS_BYTE) {
+               /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
+               addr <<= 1;
+
+               if (read_write == I2C_SMBUS_WRITE)
+                       err = w9968cf_i2c_adap_write_byte(cam, addr, command);
+               else if (read_write == I2C_SMBUS_READ) 
+                       err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
+
+       } else if (size == I2C_SMBUS_BYTE_DATA) {
+               addr <<= 1;
+
+               if (read_write == I2C_SMBUS_WRITE)
+                       err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
+                                                         command, data->byte);
+               else if (read_write == I2C_SMBUS_READ) {
+                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
+                               err = w9968cf_i2c_adap_read_byte_data(cam,addr,
+                                                        command, &data->byte);
+                               if (err) {
+                                       if (w9968cf_smbus_refresh_bus(cam)) {
+                                               err = -EIO;
+                                               break;
+                                       }
+                               } else
+                                       break;
+                       }
+
+               } else
+                       return -EINVAL;
+
+       } else {
+               DBG(4, "Unsupported I2C transfer mode (%d)", size)
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+
+static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
+{
+       return I2C_FUNC_SMBUS_READ_BYTE |
+              I2C_FUNC_SMBUS_READ_BYTE_DATA  |
+              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
+}
+
+
+static int w9968cf_i2c_attach_inform(struct i2c_client* client)
+{
+       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
+       int id = client->driver->id, err = 0;
+
+       if (id == I2C_DRIVERID_OVCAMCHIP) {
+               cam->sensor_client = client;
+               err = w9968cf_sensor_init(cam);
+               if (err) {
+                       cam->sensor_client = NULL;
+                       return err;
+               }
+       } else {
+               DBG(4, "Rejected client [%s] with driver [%s]", 
+                   client->name, client->driver->driver.name)
+               return -EINVAL;
+       }
+
+       DBG(5, "I2C attach client [%s] with driver [%s]",
+           client->name, client->driver->driver.name)
+
+       return 0;
+}
+
+
+static int w9968cf_i2c_detach_inform(struct i2c_client* client)
+{
+       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
+
+       if (cam->sensor_client == client)
+               cam->sensor_client = NULL;
+
+       DBG(5, "I2C detach client [%s]", client->name)
+
+       return 0;
+}
+
+
+static int 
+w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
+                    unsigned long arg)
+{
+       return 0;
+}
+
+
+static int w9968cf_i2c_init(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       static struct i2c_algorithm algo = {
+               .smbus_xfer =    w9968cf_i2c_smbus_xfer,
+               .algo_control =  w9968cf_i2c_control,
+               .functionality = w9968cf_i2c_func,
+       };
+
+       static struct i2c_adapter adap = {
+               .id =                I2C_HW_SMBUS_W9968CF,
+               .class =             I2C_CLASS_CAM_DIGITAL,
+               .owner =             THIS_MODULE,
+               .client_register =   w9968cf_i2c_attach_inform,
+               .client_unregister = w9968cf_i2c_detach_inform,
+               .algo =              &algo,
+       };
+
+       memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
+       strcpy(cam->i2c_adapter.name, "w9968cf");
+       i2c_set_adapdata(&cam->i2c_adapter, cam);
+
+       DBG(6, "Registering I2C adapter with kernel...")
+
+       err = i2c_add_adapter(&cam->i2c_adapter);
+       if (err)
+               DBG(1, "Failed to register the I2C adapter")
+       else
+               DBG(5, "I2C adapter registered")
+
+       return err;
+}
+
+
+
+/****************************************************************************
+ * Helper functions                                                         *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  Turn on the LED on some webcams. A beep should be heard too.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_turn_on_led(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
+       err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
+       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
+       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
+       err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
+       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
+
+       if (err)
+               DBG(2, "Couldn't turn on the LED")
+
+       DBG(5, "LED turned on")
+
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Write some registers for the device initialization.
+  This function is called once on open().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_init_chip(struct w9968cf_device* cam)
+{
+       unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
+                     y0 = 0x0000,
+                     u0 = y0 + hw_bufsize/2,
+                     v0 = u0 + hw_bufsize/4,
+                     y1 = v0 + hw_bufsize/4,
+                     u1 = y1 + hw_bufsize/2,
+                     v1 = u1 + hw_bufsize/4;
+       int err = 0;
+
+       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
+       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
+
+       err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
+       err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
+
+       err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
+       err += w9968cf_write_reg(cam, y0 >> 16, 0x21);    /* Y buf.0, high */
+       err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
+       err += w9968cf_write_reg(cam, u0 >> 16, 0x25);    /* U buf.0, high */
+       err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
+       err += w9968cf_write_reg(cam, v0 >> 16, 0x29);    /* V buf.0, high */
+
+       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
+       err += w9968cf_write_reg(cam, y1 >> 16, 0x23);    /* Y buf.1, high */
+       err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
+       err += w9968cf_write_reg(cam, u1 >> 16, 0x27);    /* U buf.1, high */
+       err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
+       err += w9968cf_write_reg(cam, v1 >> 16, 0x2b);    /* V buf.1, high */
+
+       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
+       err += w9968cf_write_reg(cam, y1 >> 16, 0x33);    /* JPEG buf 0 high */
+
+       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
+       err += w9968cf_write_reg(cam, y1 >> 16, 0x35);    /* JPEG bug 1 high */
+
+       err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
+       err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
+       err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
+       err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
+
+       err += w9968cf_set_picture(cam, cam->picture); /* this before */
+       err += w9968cf_set_window(cam, cam->window);
+
+       if (err)
+               DBG(1, "Chip initialization failed")
+       else
+               DBG(5, "Chip successfully initialized")
+
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return non-zero if the palette is supported, 0 otherwise.
+  --------------------------------------------------------------------------*/
+static inline u16 w9968cf_valid_palette(u16 palette)
+{
+       u8 i = 0;
+       while (w9968cf_formatlist[i].palette != 0) {
+               if (palette == w9968cf_formatlist[i].palette)
+                       return palette;
+               i++;
+       }
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return the depth corresponding to the given palette.
+  Palette _must_ be supported !
+  --------------------------------------------------------------------------*/
+static inline u16 w9968cf_valid_depth(u16 palette)
+{
+       u8 i=0;
+       while (w9968cf_formatlist[i].palette != palette)
+               i++;
+
+       return w9968cf_formatlist[i].depth;
+}
+
+
+/*--------------------------------------------------------------------------
+  Return non-zero if the format requires decompression, 0 otherwise.
+  --------------------------------------------------------------------------*/
+static inline u8 w9968cf_need_decompression(u16 palette)
+{
+       u8 i = 0;
+       while (w9968cf_formatlist[i].palette != 0) {
+               if (palette == w9968cf_formatlist[i].palette)
+                       return w9968cf_formatlist[i].compression;
+               i++;
+       }
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change the picture settings of the camera.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
+{
+       u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
+       int err = 0;
+
+       /* Make sure we are using a valid depth */
+       pict.depth = w9968cf_valid_depth(pict.palette);
+
+       fmt = pict.palette;
+
+       hw_depth = pict.depth; /* depth used by the winbond chip */
+       hw_palette = pict.palette; /* palette used by the winbond chip */
+
+       /* VS & HS polarities */
+       reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
+
+       switch (fmt)
+       {
+               case VIDEO_PALETTE_UYVY:
+                       reg_v |= 0x0000;
+                       cam->vpp_flag = VPP_NONE;
+                       break;
+               case VIDEO_PALETTE_YUV422P:
+                       reg_v |= 0x0002;
+                       cam->vpp_flag = VPP_DECOMPRESSION;
+                       break;
+               case VIDEO_PALETTE_YUV420:
+               case VIDEO_PALETTE_YUV420P:
+                       reg_v |= 0x0003;
+                       cam->vpp_flag = VPP_DECOMPRESSION;
+                       break;
+               case VIDEO_PALETTE_YUYV:
+               case VIDEO_PALETTE_YUV422:
+                       reg_v |= 0x0000;
+                       cam->vpp_flag = VPP_SWAP_YUV_BYTES;
+                       hw_palette = VIDEO_PALETTE_UYVY;
+                       break;
+               /* Original video is used instead of RGBX palettes. 
+                  Software conversion later. */
+               case VIDEO_PALETTE_GREY:
+               case VIDEO_PALETTE_RGB555:
+               case VIDEO_PALETTE_RGB565:
+               case VIDEO_PALETTE_RGB24:
+               case VIDEO_PALETTE_RGB32:
+                       reg_v |= 0x0000; /* UYVY 16 bit is used */
+                       hw_depth = 16;
+                       hw_palette = VIDEO_PALETTE_UYVY;
+                       cam->vpp_flag = VPP_UYVY_TO_RGBX;
+                       break;
+       }
+
+       /* NOTE: due to memory issues, it is better to disable the hardware
+                double buffering during compression */
+       if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
+               reg_v |= 0x0080;
+
+       if (cam->clamping)
+               reg_v |= 0x0020;
+
+       if (cam->filter_type == 1)
+               reg_v |= 0x0008;
+       else if (cam->filter_type == 2)
+               reg_v |= 0x000c;
+
+       if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
+               goto error;
+
+       if ((err = w9968cf_sensor_update_picture(cam, pict)))
+               goto error;
+
+       /* If all went well, update the device data structure */
+       memcpy(&cam->picture, &pict, sizeof(pict));
+       cam->hw_depth = hw_depth;
+       cam->hw_palette = hw_palette;
+
+       /* Settings changed, so we clear the frame buffers */
+       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
+
+       DBG(4, "Palette is %s, depth is %u bpp",
+           symbolic(v4l1_plist, pict.palette), pict.depth)
+
+       return 0;
+
+error:
+       DBG(1, "Failed to change picture settings")
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Change the capture area size of the camera.
+  This function _must_ be called _after_ w9968cf_set_picture().
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
+{
+       u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
+       unsigned long fw, fh;
+       struct ovcamchip_window s_win;
+       int err = 0;
+
+       /* Work around to avoid FP arithmetics */
+       #define __SC(x) ((x) << 10)
+       #define __UNSC(x) ((x) >> 10)
+
+       /* Make sure we are using a supported resolution */
+       if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, 
+                                             (u16*)&win.height)))
+               goto error;
+
+       /* Scaling factors */
+       fw = __SC(win.width) / cam->maxwidth;
+       fh = __SC(win.height) / cam->maxheight;
+
+       /* Set up the width and height values used by the chip */
+       if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
+               cam->vpp_flag |= VPP_UPSCALE;
+               /* Calculate largest w,h mantaining the same w/h ratio */
+               w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
+               h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+               if (w < cam->minwidth) /* just in case */
+                       w = cam->minwidth;
+               if (h < cam->minheight) /* just in case */
+                       h = cam->minheight;
+       } else {
+               cam->vpp_flag &= ~VPP_UPSCALE;
+               w = win.width;
+               h = win.height;
+       }
+
+       /* x,y offsets of the cropped area */
+       scx = cam->start_cropx;
+       scy = cam->start_cropy;
+
+       /* Calculate cropped area manteining the right w/h ratio */
+       if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
+               cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
+               ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
+       } else {
+               cw = w;
+               ch = h;
+       }
+
+       /* Setup the window of the sensor */
+       s_win.format = VIDEO_PALETTE_UYVY;
+       s_win.width = cam->maxwidth;
+       s_win.height = cam->maxheight;
+       s_win.quarter = 0; /* full progressive video */
+
+       /* Center it */
+       s_win.x = (s_win.width - cw) / 2;
+       s_win.y = (s_win.height - ch) / 2;
+
+       /* Clock divisor */
+       if (cam->clockdiv >= 0)
+               s_win.clockdiv = cam->clockdiv; /* manual override */
+       else
+               switch (cam->sensor) {
+                       case CC_OV6620:
+                               s_win.clockdiv = 0;
+                               break;
+                       case CC_OV6630:
+                               s_win.clockdiv = 0;
+                               break;
+                       case CC_OV76BE:
+                       case CC_OV7610:
+                       case CC_OV7620:
+                               s_win.clockdiv = 0;
+                               break;
+                       default:
+                               s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
+               }
+
+       /* We have to scale win.x and win.y offsets */
+       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
+            || (cam->vpp_flag & VPP_UPSCALE) ) {
+               ax = __SC(win.x)/fw;
+               ay = __SC(win.y)/fh;
+       } else {
+               ax = win.x;
+               ay = win.y;
+       }
+
+       if ((ax + cw) > cam->maxwidth)
+               ax = cam->maxwidth - cw;
+
+       if ((ay + ch) > cam->maxheight)
+               ay = cam->maxheight - ch;
+
+       /* Adjust win.x, win.y */
+       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
+            || (cam->vpp_flag & VPP_UPSCALE) ) {
+               win.x = __UNSC(ax*fw);
+               win.y = __UNSC(ay*fh);
+       } else {
+               win.x = ax;
+               win.y = ay;
+       }
+
+       /* Offsets used by the chip */
+       x = ax + s_win.x;
+       y = ay + s_win.y;
+
+       /* Go ! */
+       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
+               goto error;
+
+       err += w9968cf_write_reg(cam, scx + x, 0x10);
+       err += w9968cf_write_reg(cam, scy + y, 0x11);
+       err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
+       err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
+       err += w9968cf_write_reg(cam, w, 0x14);
+       err += w9968cf_write_reg(cam, h, 0x15);
+
+       /* JPEG width & height */
+       err += w9968cf_write_reg(cam, w, 0x30);
+       err += w9968cf_write_reg(cam, h, 0x31);
+
+       /* Y & UV frame buffer strides (in WORD) */
+       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+               err += w9968cf_write_reg(cam, w/2, 0x2c);
+               err += w9968cf_write_reg(cam, w/4, 0x2d);
+       } else
+               err += w9968cf_write_reg(cam, w, 0x2c);
+
+       if (err)
+               goto error;
+
+       /* If all went well, update the device data structure */
+       memcpy(&cam->window, &win, sizeof(win));
+       cam->hw_width = w;
+       cam->hw_height = h;
+
+       /* Settings changed, so we clear the frame buffers */
+       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
+
+       DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", 
+           win.width, win.height, win.x, win.y)
+
+       PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
+             "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
+             x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
+             win.width, win.height)
+
+       return 0;
+
+error:
+       DBG(1, "Failed to change the capture area size")
+       return err;
+}
+
+
+/*-------------------------------------------------------------------------- 
+  Adjust the asked values for window width and height.
+  Return 0 on success, -1 otherwise.
+  --------------------------------------------------------------------------*/
+static int 
+w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
+{
+       u16 maxw, maxh;
+
+       if ((*width < cam->minwidth) || (*height < cam->minheight))
+               return -ERANGE;
+
+       maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
+              w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
+                          : cam->maxwidth;
+       maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
+              w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
+                          : cam->maxheight;
+
+       if (*width > maxw)
+               *width = maxw;
+       if (*height > maxh)
+               *height = maxh;
+
+       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+               *width  &= ~15L; /* multiple of 16 */
+               *height &= ~15L;
+       }
+
+       PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Initialize the FIFO list of requested frames.
+  --------------------------------------------------------------------------*/
+static void w9968cf_init_framelist(struct w9968cf_device* cam)
+{
+       u8 i;
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->requested_frame[i] = NULL;
+               cam->frame[i].queued = 0;
+               cam->frame[i].status = F_UNUSED;
+       }
+}
+
+
+/*--------------------------------------------------------------------------
+  Add a frame in the FIFO list of requested frames.
+  This function is called in process context.
+  --------------------------------------------------------------------------*/
+static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
+{
+       u8 f;
+       unsigned long lock_flags;
+
+       spin_lock_irqsave(&cam->flist_lock, lock_flags);
+
+       for (f=0; cam->requested_frame[f] != NULL; f++);
+       cam->requested_frame[f] = &cam->frame[f_num];
+       cam->frame[f_num].queued = 1;
+       cam->frame[f_num].status = F_UNUSED; /* clear the status */
+
+       spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
+
+       DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
+}
+
+
+/*--------------------------------------------------------------------------
+  Read, store and remove the first pointer in the FIFO list of requested
+  frames. This function is called in interrupt context.
+  --------------------------------------------------------------------------*/
+static void 
+w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
+{
+       u8 i;
+
+       spin_lock(&cam->flist_lock);
+
+       *framep = cam->requested_frame[0];
+
+       /* Shift the list of pointers */
+       for (i = 0; i < cam->nbuffers-1; i++)
+               cam->requested_frame[i] = cam->requested_frame[i+1];
+       cam->requested_frame[i] = NULL;
+
+       spin_unlock(&cam->flist_lock);
+
+       DBG(6,"Popped frame #%d from the list", (*framep)->number)
+}
+
+
+/*--------------------------------------------------------------------------
+  High-level video post-processing routine on grabbed frames.
+  Return 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int 
+w9968cf_postprocess_frame(struct w9968cf_device* cam, 
+                          struct w9968cf_frame_t* fr)
+{
+       void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
+       u16 w = cam->window.width,
+           h = cam->window.height,
+           d = cam->picture.depth,
+           fmt = cam->picture.palette,
+           rgb = cam->force_rgb,
+           hw_w = cam->hw_width,
+           hw_h = cam->hw_height,
+           hw_d = cam->hw_depth;
+       int err = 0;
+
+       #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
+
+       if (cam->vpp_flag & VPP_DECOMPRESSION) {
+               memcpy(pOut, pIn, fr->length);
+               _PSWAP(pIn, pOut)
+               err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
+               PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
+               fr->length = (hw_w*hw_h*hw_d)/8;
+               _PSWAP(pIn, pOut)
+               if (err) {
+                       DBG(4, "An error occurred while decoding the frame: "
+                              "%s", symbolic(decoder_errlist, err))
+                       return err;
+               } else
+                       DBG(6, "Frame decoded")
+       }
+
+       if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
+               w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
+               DBG(6, "Original UYVY component ordering changed")
+       }
+
+       if (cam->vpp_flag & VPP_UPSCALE) {
+               w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
+               fr->length = (w*h*hw_d)/8;
+               _PSWAP(pIn, pOut)
+               DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
+                   hw_w, hw_h, hw_d, w, h)
+       }
+
+       if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
+               w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
+               fr->length = (w*h*d)/8;
+               _PSWAP(pIn, pOut)
+               DBG(6, "UYVY-16bit to %s conversion done", 
+                   symbolic(v4l1_plist, fmt))
+       }
+
+       if (pOut == fr->buffer)
+               memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
+
+       return 0;
+}
+
+
+
+/****************************************************************************
+ * Image sensor control routines                                            *
+ ****************************************************************************/
+
+static int 
+w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
+{
+       struct ovcamchip_control ctl;
+       int err;
+
+       ctl.id = cid;
+       ctl.value = val;
+
+       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
+
+       return err;
+}
+
+
+static int 
+w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
+{
+       struct ovcamchip_control ctl;
+       int err;
+
+       ctl.id = cid;
+
+       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
+       if (!err)
+               *val = ctl.value;
+
+       return err;
+}
+
+
+static int
+w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
+{
+       struct i2c_client* c = cam->sensor_client;
+       int rc = 0;
+
+       if (!c || !c->driver || !c->driver->command)
+               return -EINVAL;
+
+       rc = c->driver->command(c, cmd, arg);
+       /* The I2C driver returns -EPERM on non-supported controls */
+       return (rc < 0 && rc != -EPERM) ? rc : 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Update some settings of the image sensor.
+  Returns: 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       /* Auto brightness */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, 
+                                        cam->auto_brt);
+       if (err)
+               return err;
+
+       /* Auto exposure */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, 
+                                        cam->auto_exp);
+       if (err)
+               return err;
+
+       /* Banding filter */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, 
+                                        cam->bandfilt);
+       if (err)
+               return err;
+
+       /* Light frequency */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
+                                        cam->lightfreq);
+       if (err)
+               return err;
+
+       /* Back light */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
+                                        cam->backlight);
+       if (err)
+               return err;
+
+       /* Mirror */
+       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
+                                        cam->mirror);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Get some current picture settings from the image sensor and update the
+  internal 'picture' structure of the camera.
+  Returns: 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
+{
+       int err, v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
+       if (err)
+               return err;
+       cam->picture.contrast = v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
+       if (err)
+               return err;
+       cam->picture.brightness = v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
+       if (err)
+               return err;
+       cam->picture.colour = v;
+
+       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
+       if (err)
+               return err;
+       cam->picture.hue = v;
+
+       DBG(5, "Got picture settings from the image sensor")
+
+       PDBGG("Brightness, contrast, hue, colour, whiteness are "
+             "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
+             cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
+
+       return 0;
+}
+
+
+/*--------------------------------------------------------------------------
+  Update picture settings of the image sensor.
+  Returns: 0 on success, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int
+w9968cf_sensor_update_picture(struct w9968cf_device* cam, 
+                              struct video_picture pict)
+{
+       int err = 0;
+
+       if ((!cam->sensor_initialized)
+           || pict.contrast != cam->picture.contrast) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
+                                                pict.contrast);
+               if (err)
+                       goto fail;
+               DBG(4, "Contrast changed from %u to %u",
+                   cam->picture.contrast, pict.contrast)
+               cam->picture.contrast = pict.contrast;
+       }
+
+       if (((!cam->sensor_initialized) || 
+           pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, 
+                                                pict.brightness);
+               if (err)
+                       goto fail;
+               DBG(4, "Brightness changed from %u to %u",
+                   cam->picture.brightness, pict.brightness)
+               cam->picture.brightness = pict.brightness;
+       }
+
+       if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, 
+                                                pict.colour);
+               if (err)
+                       goto fail;
+               DBG(4, "Colour changed from %u to %u",
+                   cam->picture.colour, pict.colour)
+               cam->picture.colour = pict.colour;
+       }
+
+       if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
+               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, 
+                                                pict.hue);
+               if (err)
+                       goto fail;
+               DBG(4, "Hue changed from %u to %u",
+                   cam->picture.hue, pict.hue)
+               cam->picture.hue = pict.hue;
+       }
+
+       return 0;
+
+fail:
+       DBG(4, "Failed to change sensor picture setting")
+       return err;
+}
+
+
+
+/****************************************************************************
+ * Camera configuration                                                     *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------------------
+  This function is called when a supported image sensor is detected.
+  Return 0 if the initialization succeeds, a negative number otherwise.
+  --------------------------------------------------------------------------*/
+static int w9968cf_sensor_init(struct w9968cf_device* cam)
+{
+       int err = 0;
+
+       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, 
+                                     &cam->monochrome)))
+               goto error;
+
+       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, 
+                                     &cam->sensor)))
+               goto error;
+
+       /* NOTE: Make sure width and height are a multiple of 16 */
+       switch (cam->sensor_client->addr) {
+               case OV6xx0_SID:
+                       cam->maxwidth = 352;
+                       cam->maxheight = 288;
+                       cam->minwidth = 64;
+                       cam->minheight = 48;
+                       break;
+               case OV7xx0_SID:
+                       cam->maxwidth = 640;
+                       cam->maxheight = 480;
+                       cam->minwidth = 64;
+                       cam->minheight = 48;
+                       break;
+               default:
+                       DBG(1, "Not supported image sensor detected for %s",
+                           symbolic(camlist, cam->id))
+                       return -EINVAL;
+       }
+
+       /* These values depend on the ones in the ovxxx0.c sources */
+       switch (cam->sensor) {
+               case CC_OV7620:
+                       cam->start_cropx = 287;
+                       cam->start_cropy = 35;
+                       /* Seems to work around a bug in the image sensor */
+                       cam->vs_polarity = 1;
+                       cam->hs_polarity = 1;
+                       break;
+               default:
+                       cam->start_cropx = 320;
+                       cam->start_cropy = 35;
+                       cam->vs_polarity = 1;
+                       cam->hs_polarity = 0;
+       }
+
+       if ((err = w9968cf_sensor_update_settings(cam)))
+               goto error;
+
+       if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
+               goto error;
+
+       cam->sensor_initialized = 1;
+
+       DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
+       return 0;
+
+error:
+       cam->sensor_initialized = 0;
+       cam->sensor = CC_UNKNOWN;
+       DBG(1, "Image sensor initialization failed for %s (/dev/video%d). "
+              "Try to detach and attach this device again",
+           symbolic(camlist, cam->id), cam->v4ldev->minor)
+       return err;
+}
+
+
+/*--------------------------------------------------------------------------
+  Fill some basic fields in the main device data structure.
+  This function is called once on w9968cf_usb_probe() for each recognized 
+  camera.
+  --------------------------------------------------------------------------*/
+static void
+w9968cf_configure_camera(struct w9968cf_device* cam,
+                         struct usb_device* udev,
+                         enum w9968cf_model_id mod_id,
+                         const unsigned short dev_nr)
+{
+       mutex_init(&cam->fileop_mutex);
+       init_waitqueue_head(&cam->open);
+       spin_lock_init(&cam->urb_lock);
+       spin_lock_init(&cam->flist_lock);
+
+       cam->users = 0;
+       cam->disconnected = 0;
+       cam->id = mod_id;
+       cam->sensor = CC_UNKNOWN;
+       cam->sensor_initialized = 0;
+
+       /* Calculate the alternate setting number (from 1 to 16)
+          according to the 'packet_size' module parameter */
+       if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
+               packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
+       for (cam->altsetting = 1;
+            packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
+            cam->altsetting++);
+
+       cam->max_buffers = (max_buffers[dev_nr] < 2 || 
+                           max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
+                          ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
+
+       cam->double_buffer = (double_buffer[dev_nr] == 0 || 
+                             double_buffer[dev_nr] == 1)
+                            ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
+
+       cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
+                       ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
+       
+       cam->filter_type = (filter_type[dev_nr] == 0 ||
+                           filter_type[dev_nr] == 1 ||
+                           filter_type[dev_nr] == 2)
+                          ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
+
+       cam->capture = 1;
+
+       cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
+                        ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
+
+       cam->decompression = (decompression[dev_nr] == 0 || 
+                             decompression[dev_nr] == 1 ||
+                             decompression[dev_nr] == 2)
+                            ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
+
+       cam->upscaling = (upscaling[dev_nr] == 0 || 
+                         upscaling[dev_nr] == 1)
+                        ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
+
+       cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
+                       ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
+
+       cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
+                       ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
+
+       cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
+                        ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
+
+       cam->bandfilt = (bandingfilter[dev_nr] == 0 || 
+                        bandingfilter[dev_nr] == 1)
+                       ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
+
+       cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
+                        ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
+
+       cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
+                       ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
+
+       cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
+                     ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
+
+       cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
+                         ? monochrome[dev_nr] : W9968CF_MONOCHROME;
+
+       cam->picture.brightness = (u16)brightness[dev_nr];
+       cam->picture.hue = (u16)hue[dev_nr];
+       cam->picture.colour = (u16)colour[dev_nr];
+       cam->picture.contrast = (u16)contrast[dev_nr];
+       cam->picture.whiteness = (u16)whiteness[dev_nr];
+       if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
+               cam->picture.palette = (u16)force_palette[dev_nr];
+               cam->force_palette = 1;
+       } else {
+               cam->force_palette = 0;
+               if (cam->decompression == 0)
+                       cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
+               else if (cam->decompression == 1)
+                       cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
+               else
+                       cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
+       }
+       cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
+
+       cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
+                        ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
+
+       cam->window.x = 0;
+       cam->window.y = 0;
+       cam->window.width = W9968CF_WIDTH;
+       cam->window.height = W9968CF_HEIGHT;
+       cam->window.chromakey = 0;
+       cam->window.clipcount = 0;
+       cam->window.flags = 0;
+
+       DBG(3, "%s configured with settings #%u:",
+           symbolic(camlist, cam->id), dev_nr)
+       
+       DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
+           wMaxPacketSize[cam->altsetting-1])
+       
+       DBG(3, "- Number of requested video frame buffers: %u",
+           cam->max_buffers)
+
+       if (cam->double_buffer)
+               DBG(3, "- Hardware double buffering enabled")
+       else 
+               DBG(3, "- Hardware double buffering disabled")
+
+       if (cam->filter_type == 0)
+               DBG(3, "- Video filtering disabled")
+       else if (cam->filter_type == 1)
+               DBG(3, "- Video filtering enabled: type 1-2-1")
+       else if (cam->filter_type == 2)
+               DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
+
+       if (cam->clamping)
+               DBG(3, "- Video data clamping (CCIR-601 format) enabled")
+       else
+               DBG(3, "- Video data clamping (CCIR-601 format) disabled")
+
+       if (cam->largeview)
+               DBG(3, "- Large view enabled")
+       else
+               DBG(3, "- Large view disabled")
+
+       if ((cam->decompression) == 0 && (!cam->force_palette))
+               DBG(3, "- Decompression disabled")
+       else if ((cam->decompression) == 1 && (!cam->force_palette))
+               DBG(3, "- Decompression forced")
+       else if ((cam->decompression) == 2 && (!cam->force_palette))
+               DBG(3, "- Decompression allowed")
+
+       if (cam->upscaling)
+               DBG(3, "- Software image scaling enabled")
+       else
+               DBG(3, "- Software image scaling disabled")
+
+       if (cam->force_palette)
+               DBG(3, "- Image palette forced to %s",
+                   symbolic(v4l1_plist, cam->picture.palette))
+
+       if (cam->force_rgb)
+               DBG(3, "- RGB component ordering will be used instead of BGR")
+
+       if (cam->auto_brt)
+               DBG(3, "- Auto brightness enabled")
+       else
+               DBG(3, "- Auto brightness disabled")
+
+       if (cam->auto_exp)
+               DBG(3, "- Auto exposure enabled")
+       else
+               DBG(3, "- Auto exposure disabled")
+
+       if (cam->backlight)
+               DBG(3, "- Backlight exposure algorithm enabled")
+       else
+               DBG(3, "- Backlight exposure algorithm disabled")
+
+       if (cam->mirror)
+               DBG(3, "- Mirror enabled")
+       else
+               DBG(3, "- Mirror disabled")
+
+       if (cam->bandfilt)
+               DBG(3, "- Banding filter enabled")
+       else
+               DBG(3, "- Banding filter disabled")
+
+       DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
+
+       if (cam->clockdiv == -1)
+               DBG(3, "- Automatic clock divisor enabled")
+       else
+               DBG(3, "- Clock divisor: %d", cam->clockdiv)
+
+       if (cam->monochrome)
+               DBG(3, "- Image sensor used as monochrome")
+       else
+               DBG(3, "- Image sensor not used as monochrome")
+}
+
+
+/*--------------------------------------------------------------------------
+  If the video post-processing module is not loaded, some parameters
+  must be overridden.
+  --------------------------------------------------------------------------*/
+static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
+{
+       if (!w9968cf_vpp) {
+               if (cam->decompression == 1) {
+                       cam->decompression = 2;
+                       DBG(2, "Video post-processing module not found: "
+                              "'decompression' parameter forced to 2")
+               }
+               if (cam->upscaling) {
+                       cam->upscaling = 0;
+                       DBG(2, "Video post-processing module not found: "
+                              "'upscaling' parameter forced to 0")
+               }
+               if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
+                       cam->force_palette = 0;
+                       DBG(2, "Video post-processing module not found: "
+                              "'force_palette' parameter forced to 0")
+               }
+               cam->picture.palette = VIDEO_PALETTE_UYVY;
+               cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
+       }
+}
+
+
+/*--------------------------------------------------------------------------
+  Release the resources used by the driver.
+  This function is called on disconnect 
+  (or on close if deallocation has been deferred)
+  --------------------------------------------------------------------------*/
+static void w9968cf_release_resources(struct w9968cf_device* cam)
+{
+       mutex_lock(&w9968cf_devlist_mutex);
+
+       DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
+
+       video_unregister_device(cam->v4ldev);
+       list_del(&cam->v4llist);
+       i2c_del_adapter(&cam->i2c_adapter);
+       w9968cf_deallocate_memory(cam);
+       kfree(cam->control_buffer);
+       kfree(cam->data_buffer);
+
+       mutex_unlock(&w9968cf_devlist_mutex);
+}
+
+
+
+/****************************************************************************
+ * Video4Linux interface                                                    *
+ ****************************************************************************/
+
+static int w9968cf_open(struct inode* inode, struct file* filp)
+{
+       struct w9968cf_device* cam;
+       int err;
+
+       /* This the only safe way to prevent race conditions with disconnect */
+       if (!down_read_trylock(&w9968cf_disconnect))
+               return -ERESTARTSYS;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex);
+
+       if (cam->sensor == CC_UNKNOWN) {
+               DBG(2, "No supported image sensor has been detected by the "
+                      "'ovcamchip' module for the %s (/dev/video%d). Make "
+                      "sure it is loaded *before* (re)connecting the camera.",
+                   symbolic(camlist, cam->id), cam->v4ldev->minor)
+               mutex_unlock(&cam->dev_mutex);
+               up_read(&w9968cf_disconnect);
+               return -ENODEV;
+       }
+
+       if (cam->users) {
+               DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
+                   symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
+               if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
+                       mutex_unlock(&cam->dev_mutex);
+                       up_read(&w9968cf_disconnect);
+                       return -EWOULDBLOCK;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                        cam->disconnected ||
+                                                        !cam->users);
+               if (err) {
+                       up_read(&w9968cf_disconnect);
+                       return err;
+               }
+               if (cam->disconnected) {
+                       up_read(&w9968cf_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+       DBG(5, "Opening '%s', /dev/video%d ...",
+           symbolic(camlist, cam->id), cam->v4ldev->minor)
+
+       cam->streaming = 0;
+       cam->misconfigured = 0;
+
+       w9968cf_adjust_configuration(cam);
+
+       if ((err = w9968cf_allocate_memory(cam)))
+               goto deallocate_memory;
+
+       if ((err = w9968cf_init_chip(cam)))
+               goto deallocate_memory;
+
+       if ((err = w9968cf_start_transfer(cam)))
+               goto deallocate_memory;
+
+       filp->private_data = cam;
+
+       cam->users++;
+       strcpy(cam->command, current->comm);
+
+       init_waitqueue_head(&cam->wait_queue);
+
+       DBG(5, "Video device is open")
+
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&w9968cf_disconnect);
+
+       return 0;
+
+deallocate_memory:
+       w9968cf_deallocate_memory(cam);
+       DBG(2, "Failed to open the video device")
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&w9968cf_disconnect);
+       return err;
+}
+
+
+static int w9968cf_release(struct inode* inode, struct file* filp)
+{
+       struct w9968cf_device* cam;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       w9968cf_stop_transfer(cam);
+
+       if (cam->disconnected) {
+               w9968cf_release_resources(cam);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       w9968cf_deallocate_memory(cam);
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(5, "Video device closed")
+       mutex_unlock(&cam->dev_mutex);
+       return 0;
+}
+
+
+static ssize_t
+w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct w9968cf_device* cam;
+       struct w9968cf_frame_t* fr;
+       int err = 0;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       if (filp->f_flags & O_NONBLOCK)
+               return -EWOULDBLOCK;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->disconnected) {
+               DBG(2, "Device not present")
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->misconfigured) {
+               DBG(2, "The camera is misconfigured. Close and open it again.")
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (!cam->frame[0].queued)
+               w9968cf_push_frame(cam, 0);
+
+       if (!cam->frame[1].queued)
+               w9968cf_push_frame(cam, 1);
+
+       err = wait_event_interruptible(cam->wait_queue,
+                                      cam->frame[0].status == F_READY ||
+                                      cam->frame[1].status == F_READY ||
+                                      cam->disconnected);
+       if (err) {
+               mutex_unlock(&cam->fileop_mutex);
+               return err;
+       }
+       if (cam->disconnected) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
+
+       if (w9968cf_vpp)
+               w9968cf_postprocess_frame(cam, fr);
+
+       if (count > fr->length)
+               count = fr->length;
+
+       if (copy_to_user(buf, fr->buffer, count)) {
+               fr->status = F_UNUSED;
+               mutex_unlock(&cam->fileop_mutex);
+               return -EFAULT;
+       }
+       *f_pos += count;
+
+       fr->status = F_UNUSED;
+
+       DBG(5, "%zu bytes read", count)
+
+       mutex_unlock(&cam->fileop_mutex);
+       return count;
+}
+
+
+static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct w9968cf_device* cam = (struct w9968cf_device*)
+                                    video_get_drvdata(video_devdata(filp));
+       unsigned long vsize = vma->vm_end - vma->vm_start,
+                     psize = cam->nbuffers * cam->frame[0].size,
+                     start = vma->vm_start,
+                     pos = (unsigned long)cam->frame[0].buffer,
+                     page;
+
+       if (cam->disconnected) {
+               DBG(2, "Device not present")
+               return -ENODEV;
+       }
+
+       if (cam->misconfigured) {
+               DBG(2, "The camera is misconfigured. Close and open it again")
+               return -EIO;
+       }
+
+       PDBGG("mmapping %lu bytes...", vsize)
+
+       if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
+               return -EINVAL;
+
+       while (vsize > 0) {
+               page = vmalloc_to_pfn((void *)pos);
+               if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
+                                               PAGE_SIZE, vma->vm_page_prot))
+                       return -EAGAIN;
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               vsize -= PAGE_SIZE;
+       }
+
+       DBG(5, "mmap method successfully called")
+       return 0;
+}
+
+
+static int
+w9968cf_ioctl(struct inode* inode, struct file* filp,
+              unsigned int cmd, unsigned long arg)
+{
+       struct w9968cf_device* cam;
+       int err;
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->disconnected) {
+               DBG(2, "Device not present")
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->misconfigured) {
+               DBG(2, "The camera is misconfigured. Close and open it again.")
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+       return err;
+}
+
+
+static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
+                             unsigned int cmd, void __user * arg)
+{
+       struct w9968cf_device* cam;
+       const char* v4l1_ioctls[] = {
+               "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", 
+               "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
+               "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
+               "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
+               "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", 
+               "GVBIFMT", "SVBIFMT" 
+       };
+
+       #define V4L1_IOCTL(cmd) \
+               ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
+               v4l1_ioctls[_IOC_NR((cmd))] : "?")
+
+       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOCGCAP: /* get video capability */
+       {
+               struct video_capability cap = {
+                       .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
+                       .channels = 1,
+                       .audios = 0,
+                       .minwidth = cam->minwidth,
+                       .minheight = cam->minheight,
+               };
+               sprintf(cap.name, "W996[87]CF USB Camera #%d", 
+                       cam->v4ldev->minor);
+               cap.maxwidth = (cam->upscaling && w9968cf_vpp)
+                              ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) 
+                                : cam->maxwidth;
+               cap.maxheight = (cam->upscaling && w9968cf_vpp)
+                               ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
+                                 : cam->maxheight;
+
+               if (copy_to_user(arg, &cap, sizeof(cap)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGCAP successfully called")
+               return 0;
+       }
+
+       case VIDIOCGCHAN: /* get video channel informations */
+       {
+               struct video_channel chan;
+               if (copy_from_user(&chan, arg, sizeof(chan)))
+                       return -EFAULT;
+
+               if (chan.channel != 0)
+                       return -EINVAL;
+
+               strcpy(chan.name, "Camera");
+               chan.tuners = 0;
+               chan.flags = 0;
+               chan.type = VIDEO_TYPE_CAMERA;
+               chan.norm = VIDEO_MODE_AUTO;
+
+               if (copy_to_user(arg, &chan, sizeof(chan)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGCHAN successfully called")
+               return 0;
+       }
+
+       case VIDIOCSCHAN: /* set active channel */
+       {
+               struct video_channel chan;
+
+               if (copy_from_user(&chan, arg, sizeof(chan)))
+                       return -EFAULT;
+
+               if (chan.channel != 0)
+                       return -EINVAL;
+
+               DBG(5, "VIDIOCSCHAN successfully called")
+               return 0;
+       }
+
+       case VIDIOCGPICT: /* get image properties of the picture */
+       {
+               if (w9968cf_sensor_get_picture(cam))
+                       return -EIO;
+
+               if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGPICT successfully called")
+               return 0;
+       }
+
+       case VIDIOCSPICT: /* change picture settings */
+       {
+               struct video_picture pict;
+               int err = 0;
+
+               if (copy_from_user(&pict, arg, sizeof(pict)))
+                       return -EFAULT;
+
+               if ( (cam->force_palette || !w9968cf_vpp) 
+                    && pict.palette != cam->picture.palette ) {
+                       DBG(4, "Palette %s rejected: only %s is allowed",
+                           symbolic(v4l1_plist, pict.palette),
+                           symbolic(v4l1_plist, cam->picture.palette))
+                       return -EINVAL;
+               }
+
+               if (!w9968cf_valid_palette(pict.palette)) {
+                       DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
+                           symbolic(v4l1_plist, pict.palette))
+                       return -EINVAL;
+               }
+
+               if (!cam->force_palette) {
+                  if (cam->decompression == 0) {
+                     if (w9968cf_need_decompression(pict.palette)) {
+                        DBG(4, "Decompression disabled: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, pict.palette))
+                        return -EINVAL;
+                     }
+                  } else if (cam->decompression == 1) {
+                     if (!w9968cf_need_decompression(pict.palette)) {
+                        DBG(4, "Decompression forced: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, pict.palette))
+                        return -EINVAL;
+                     }
+                  }
+               }
+
+               if (pict.depth != w9968cf_valid_depth(pict.palette)) {
+                       DBG(4, "Requested depth %u bpp is not valid for %s "
+                              "palette: ignored and changed to %u bpp", 
+                           pict.depth, symbolic(v4l1_plist, pict.palette),
+                           w9968cf_valid_depth(pict.palette))
+                       pict.depth = w9968cf_valid_depth(pict.palette);
+               }
+
+               if (pict.palette != cam->picture.palette) {
+                       if(*cam->requested_frame
+                          || cam->frame_current->queued) {
+                               err = wait_event_interruptible
+                                     ( cam->wait_queue,
+                                       cam->disconnected ||
+                                       (!*cam->requested_frame &&
+                                        !cam->frame_current->queued) );
+                               if (err)
+                                       return err;
+                               if (cam->disconnected)
+                                       return -ENODEV;
+                       }
+
+                       if (w9968cf_stop_transfer(cam))
+                               goto ioctl_fail;
+
+                       if (w9968cf_set_picture(cam, pict))
+                               goto ioctl_fail;
+
+                       if (w9968cf_start_transfer(cam))
+                               goto ioctl_fail;
+
+               } else if (w9968cf_sensor_update_picture(cam, pict))
+                       return -EIO;
+
+
+               DBG(5, "VIDIOCSPICT successfully called")
+               return 0;
+       }
+
+       case VIDIOCSWIN: /* set capture area */
+       {
+               struct video_window win;
+               int err = 0;
+
+               if (copy_from_user(&win, arg, sizeof(win)))
+                       return -EFAULT;
+
+               DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
+                      "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
+                   win.x, win.y, win.width, win.height)
+
+               if (win.clipcount != 0 || win.flags != 0)
+                       return -EINVAL;
+
+               if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
+                                                     (u16*)&win.height))) {
+                       DBG(4, "Resolution not supported (%ux%u). "
+                              "VIDIOCSWIN failed", win.width, win.height)
+                       return err;
+               }
+
+               if (win.x != cam->window.x ||
+                   win.y != cam->window.y ||
+                   win.width != cam->window.width ||
+                   win.height != cam->window.height) {
+                       if(*cam->requested_frame
+                          || cam->frame_current->queued) {
+                               err = wait_event_interruptible
+                                     ( cam->wait_queue,
+                                       cam->disconnected ||
+                                       (!*cam->requested_frame &&
+                                        !cam->frame_current->queued) );
+                               if (err)
+                                       return err;
+                               if (cam->disconnected)
+                                       return -ENODEV;
+                       }
+
+                       if (w9968cf_stop_transfer(cam))
+                               goto ioctl_fail;
+
+                       /* This _must_ be called before set_window() */
+                       if (w9968cf_set_picture(cam, cam->picture))
+                               goto ioctl_fail;
+
+                       if (w9968cf_set_window(cam, win))
+                               goto ioctl_fail;
+
+                       if (w9968cf_start_transfer(cam))
+                               goto ioctl_fail;
+               }
+
+               DBG(5, "VIDIOCSWIN successfully called. ")
+               return 0;
+       }
+
+       case VIDIOCGWIN: /* get current window properties */
+       {
+               if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGWIN successfully called")
+               return 0;
+       }
+
+       case VIDIOCGMBUF: /* request for memory (mapped) buffer */
+       {
+               struct video_mbuf mbuf;
+               u8 i;
+
+               mbuf.size = cam->nbuffers * cam->frame[0].size;
+               mbuf.frames = cam->nbuffers;
+               for (i = 0; i < cam->nbuffers; i++)
+                       mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
+                                         (unsigned long)cam->frame[0].buffer;
+
+               if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGMBUF successfully called")
+               return 0;
+       }
+
+       case VIDIOCMCAPTURE: /* start the capture to a frame */
+       {
+               struct video_mmap mmap;
+               struct w9968cf_frame_t* fr;
+               int err = 0;
+
+               if (copy_from_user(&mmap, arg, sizeof(mmap)))
+                       return -EFAULT;
+
+               DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
+                   mmap.frame, symbolic(v4l1_plist, mmap.format), 
+                   mmap.width, mmap.height)
+
+               if (mmap.frame >= cam->nbuffers) {
+                       DBG(4, "Invalid frame number (%u). "
+                              "VIDIOCMCAPTURE failed", mmap.frame)
+                       return -EINVAL;
+               }
+
+               if (mmap.format!=cam->picture.palette && 
+                   (cam->force_palette || !w9968cf_vpp)) {
+                       DBG(4, "Palette %s rejected: only %s is allowed",
+                           symbolic(v4l1_plist, mmap.format),
+                           symbolic(v4l1_plist, cam->picture.palette))
+                       return -EINVAL;
+               }
+
+               if (!w9968cf_valid_palette(mmap.format)) {
+                       DBG(4, "Palette %s not supported. "
+                              "VIDIOCMCAPTURE failed", 
+                           symbolic(v4l1_plist, mmap.format))
+                       return -EINVAL;
+               }
+
+               if (!cam->force_palette) {
+                  if (cam->decompression == 0) {
+                     if (w9968cf_need_decompression(mmap.format)) {
+                        DBG(4, "Decompression disabled: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, mmap.format))
+                        return -EINVAL;
+                     }
+                  } else if (cam->decompression == 1) {
+                     if (!w9968cf_need_decompression(mmap.format)) {
+                        DBG(4, "Decompression forced: palette %s is not "
+                               "allowed. VIDIOCSPICT failed",
+                            symbolic(v4l1_plist, mmap.format))
+                        return -EINVAL;
+                     }
+                  }
+               }
+
+               if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
+                                                     (u16*)&mmap.height))) {
+                       DBG(4, "Resolution not supported (%dx%d). "
+                              "VIDIOCMCAPTURE failed",
+                           mmap.width, mmap.height)
+                       return err;
+               }
+
+               fr = &cam->frame[mmap.frame];
+
+               if (mmap.width  != cam->window.width ||
+                   mmap.height != cam->window.height ||
+                   mmap.format != cam->picture.palette) {
+
+                       struct video_window win;
+                       struct video_picture pict;
+
+                       if(*cam->requested_frame
+                          || cam->frame_current->queued) {
+                               DBG(6, "VIDIOCMCAPTURE. Change settings for "
+                                      "frame #%u: %dx%d, format %s. Wait...",
+                                   mmap.frame, mmap.width, mmap.height,
+                                   symbolic(v4l1_plist, mmap.format))
+                               err = wait_event_interruptible
+                                     ( cam->wait_queue,
+                                       cam->disconnected ||
+                                       (!*cam->requested_frame &&
+                                        !cam->frame_current->queued) );
+                               if (err)
+                                       return err;
+                               if (cam->disconnected)
+                                       return -ENODEV;
+                       }
+
+                       memcpy(&win, &cam->window, sizeof(win));
+                       memcpy(&pict, &cam->picture, sizeof(pict));
+                       win.width = mmap.width;
+                       win.height = mmap.height;
+                       pict.palette = mmap.format;
+
+                       if (w9968cf_stop_transfer(cam))
+                               goto ioctl_fail;
+
+                       /* This before set_window */
+                       if (w9968cf_set_picture(cam, pict)) 
+                               goto ioctl_fail;
+
+                       if (w9968cf_set_window(cam, win))
+                               goto ioctl_fail;
+
+                       if (w9968cf_start_transfer(cam))
+                               goto ioctl_fail;
+
+               } else  if (fr->queued) {
+
+                       DBG(6, "Wait until frame #%u is free", mmap.frame)
+                       
+                       err = wait_event_interruptible(cam->wait_queue, 
+                                                      cam->disconnected ||
+                                                      (!fr->queued));
+                       if (err)
+                               return err;
+                       if (cam->disconnected)
+                               return -ENODEV;
+               }
+
+               w9968cf_push_frame(cam, mmap.frame);
+               DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
+               return 0;
+       }
+
+       case VIDIOCSYNC: /* wait until the capture of a frame is finished */
+       {
+               unsigned int f_num;
+               struct w9968cf_frame_t* fr;
+               int err = 0;
+
+               if (copy_from_user(&f_num, arg, sizeof(f_num)))
+                       return -EFAULT;
+
+               if (f_num >= cam->nbuffers) {
+                       DBG(4, "Invalid frame number (%u). "
+                              "VIDIOCMCAPTURE failed", f_num)
+                       return -EINVAL;
+               }
+
+               DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
+
+               fr = &cam->frame[f_num];
+
+               switch (fr->status) {
+               case F_UNUSED:
+                       if (!fr->queued) {
+                               DBG(4, "VIDIOSYNC: Frame #%u not requested!",
+                                   f_num)
+                               return -EFAULT;
+                       }
+               case F_ERROR:
+               case F_GRABBING:
+                       err = wait_event_interruptible(cam->wait_queue, 
+                                                      (fr->status == F_READY)
+                                                      || cam->disconnected);
+                       if (err)
+                               return err;
+                       if (cam->disconnected)
+                               return -ENODEV;
+                       break;
+               case F_READY:
+                       break;
+               }
+
+               if (w9968cf_vpp)
+                       w9968cf_postprocess_frame(cam, fr);
+
+               fr->status = F_UNUSED;
+
+               DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
+               return 0;
+       }
+
+       case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
+       {
+               struct video_unit unit = {
+                       .video = cam->v4ldev->minor,
+                       .vbi = VIDEO_NO_UNIT,
+                       .radio = VIDEO_NO_UNIT,
+                       .audio = VIDEO_NO_UNIT,
+                       .teletext = VIDEO_NO_UNIT,
+               };
+
+               if (copy_to_user(arg, &unit, sizeof(unit)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGUNIT successfully called")
+               return 0;
+       }
+
+       case VIDIOCKEY:
+               return 0;
+
+       case VIDIOCGFBUF:
+       {
+               if (clear_user(arg, sizeof(struct video_buffer)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGFBUF successfully called")
+               return 0;
+       }
+
+       case VIDIOCGTUNER:
+       {
+               struct video_tuner tuner;
+               if (copy_from_user(&tuner, arg, sizeof(tuner)))
+                       return -EFAULT;
+
+               if (tuner.tuner != 0)
+                       return -EINVAL;
+
+               strcpy(tuner.name, "no_tuner");
+               tuner.rangelow = 0;
+               tuner.rangehigh = 0;
+               tuner.flags = VIDEO_TUNER_NORM;
+               tuner.mode = VIDEO_MODE_AUTO;
+               tuner.signal = 0xffff;
+
+               if (copy_to_user(arg, &tuner, sizeof(tuner)))
+                       return -EFAULT;
+
+               DBG(5, "VIDIOCGTUNER successfully called")
+               return 0;
+       }
+
+       case VIDIOCSTUNER:
+       {
+               struct video_tuner tuner;
+               if (copy_from_user(&tuner, arg, sizeof(tuner)))
+                       return -EFAULT;
+
+               if (tuner.tuner != 0)
+                       return -EINVAL;
+
+               if (tuner.mode != VIDEO_MODE_AUTO)
+                       return -EINVAL;
+
+               DBG(5, "VIDIOCSTUNER successfully called")
+               return 0;
+       }
+
+       case VIDIOCSFBUF:
+       case VIDIOCCAPTURE:
+       case VIDIOCGFREQ:
+       case VIDIOCSFREQ:
+       case VIDIOCGAUDIO:
+       case VIDIOCSAUDIO:
+       case VIDIOCSPLAYMODE:
+       case VIDIOCSWRITEMODE:
+       case VIDIOCGPLAYINFO:
+       case VIDIOCSMICROCODE:
+       case VIDIOCGVBIFMT:
+       case VIDIOCSVBIFMT:
+               DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
+                      "(type 0x%01X, "
+                      "n. 0x%01X, "
+                      "dir. 0x%01X, " 
+                      "size 0x%02X)",
+                   V4L1_IOCTL(cmd),
+                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
+
+               return -EINVAL;
+
+       default:
+               DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
+                      "type 0x%01X, "
+                      "n. 0x%01X, "
+                      "dir. 0x%01X, "
+                      "size 0x%02X",
+                   V4L1_IOCTL(cmd),
+                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
+
+               return -ENOIOCTLCMD;
+
+       } /* end of switch */
+
+ioctl_fail:
+       cam->misconfigured = 1;
+       DBG(1, "VIDIOC%s failed because of hardware problems. "
+              "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
+       return -EFAULT;
+}
+
+
+static struct file_operations w9968cf_fops = {
+       .owner =   THIS_MODULE,
+       .open =    w9968cf_open,
+       .release = w9968cf_release,
+       .read =    w9968cf_read,
+       .ioctl =   w9968cf_ioctl,
+       .compat_ioctl = v4l_compat_ioctl32,
+       .mmap =    w9968cf_mmap,
+       .llseek =  no_llseek,
+};
+
+
+
+/****************************************************************************
+ * USB probe and V4L registration, disconnect and id_table[] definition     *
+ ****************************************************************************/
+
+static int
+w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct w9968cf_device* cam;
+       int err = 0;
+       enum w9968cf_model_id mod_id;
+       struct list_head* ptr;
+       u8 sc = 0; /* number of simultaneous cameras */
+       static unsigned short dev_nr = 0; /* we are handling device number n */
+
+       if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
+           le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
+               mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
+       else if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[1].idVendor &&
+                le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
+               mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
+       else
+               return -ENODEV;
+
+       cam = (struct w9968cf_device*)
+                 kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
+       if (!cam)
+               return -ENOMEM;
+
+       mutex_init(&cam->dev_mutex);
+       mutex_lock(&cam->dev_mutex);
+
+       cam->usbdev = udev;
+       /* NOTE: a local copy is used to avoid possible race conditions */
+       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
+
+       DBG(2, "%s detected", symbolic(camlist, mod_id))
+
+       if (simcams > W9968CF_MAX_DEVICES)
+               simcams = W9968CF_SIMCAMS;
+
+       /* How many cameras are connected ? */
+       mutex_lock(&w9968cf_devlist_mutex);
+       list_for_each(ptr, &w9968cf_dev_list)
+               sc++;
+       mutex_unlock(&w9968cf_devlist_mutex);
+
+       if (sc >= simcams) {
+               DBG(2, "Device rejected: too many connected cameras "
+                      "(max. %u)", simcams)
+               err = -EPERM;
+               goto fail;
+       }
+
+
+       /* Allocate 2 bytes of memory for camera control USB transfers */
+       if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
+               DBG(1,"Couldn't allocate memory for camera control transfers")
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Allocate 8 bytes of memory for USB data transfers to the FSB */
+       if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
+               DBG(1, "Couldn't allocate memory for data "
+                      "transfers to the FSB")
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Register the V4L device */
+       cam->v4ldev = video_device_alloc();
+       if (!cam->v4ldev) {
+               DBG(1, "Could not allocate memory for a V4L structure")
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
+       cam->v4ldev->fops = &w9968cf_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+       cam->v4ldev->dev = &cam->dev;
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L device registration failed")
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(2, "Couldn't find a free /dev/videoX node")
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               goto fail;
+       }
+
+       DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
+
+       /* Set some basic constants */
+       w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
+
+       /* Add a new entry into the list of V4L registered devices */
+       mutex_lock(&w9968cf_devlist_mutex);
+       list_add(&cam->v4llist, &w9968cf_dev_list);
+       mutex_unlock(&w9968cf_devlist_mutex);
+       dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+       w9968cf_turn_on_led(cam);
+
+       w9968cf_i2c_init(cam);
+
+       usb_set_intfdata(intf, cam);
+       mutex_unlock(&cam->dev_mutex);
+       return 0;
+
+fail: /* Free unused memory */
+       kfree(cam->control_buffer);
+       kfree(cam->data_buffer);
+       if (cam->v4ldev)
+               video_device_release(cam->v4ldev);
+       mutex_unlock(&cam->dev_mutex);
+       kfree(cam);
+       return err;
+}
+
+
+static void w9968cf_usb_disconnect(struct usb_interface* intf)
+{
+       struct w9968cf_device* cam = 
+          (struct w9968cf_device*)usb_get_intfdata(intf);
+
+       down_write(&w9968cf_disconnect);
+
+       if (cam) {
+               /* Prevent concurrent accesses to data */
+               mutex_lock(&cam->dev_mutex);
+
+               cam->disconnected = 1;
+
+               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
+
+               wake_up_interruptible_all(&cam->open);
+
+               if (cam->users) {
+                       DBG(2, "The device is open (/dev/video%d)! "
+                              "Process name: %s. Deregistration and memory "
+                              "deallocation are deferred on close.",
+                           cam->v4ldev->minor, cam->command)
+                       cam->misconfigured = 1;
+                       w9968cf_stop_transfer(cam);
+                       wake_up_interruptible(&cam->wait_queue);
+               } else
+                       w9968cf_release_resources(cam);
+
+               mutex_unlock(&cam->dev_mutex);
+
+               if (!cam->users)
+                       kfree(cam);
+       }
+
+       up_write(&w9968cf_disconnect);
+}
+
+
+static struct usb_driver w9968cf_usb_driver = {
+       .name =       "w9968cf",
+       .id_table =   winbond_id_table,
+       .probe =      w9968cf_usb_probe,
+       .disconnect = w9968cf_usb_disconnect,
+};
+
+
+
+/****************************************************************************
+ * Module init, exit and intermodule communication                          *
+ ****************************************************************************/
+
+static int __init w9968cf_module_init(void)
+{
+       int err;
+
+       KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
+       KDBG(3, W9968CF_MODULE_AUTHOR)
+
+       if (ovmod_load)
+               request_module("ovcamchip");
+
+       if ((err = usb_register(&w9968cf_usb_driver)))
+               return err;
+
+       return 0;
+}
+
+
+static void __exit w9968cf_module_exit(void)
+{
+       /* w9968cf_usb_disconnect() will be called */
+       usb_deregister(&w9968cf_usb_driver);
+
+       KDBG(2, W9968CF_MODULE_NAME" deregistered")
+}
+
+
+module_init(w9968cf_module_init);
+module_exit(w9968cf_module_exit);
+
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
new file mode 100644 (file)
index 0000000..a87be71
--- /dev/null
@@ -0,0 +1,330 @@
+/***************************************************************************
+ * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
+ *                                                                         *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_H_
+#define _W9968CF_H_
+
+#include <linux/videodev.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/config.h>
+#include <linux/param.h>
+#include <linux/types.h>
+#include <linux/rwsem.h>
+#include <linux/mutex.h>
+
+#include <media/ovcamchip.h>
+
+#include "w9968cf_vpp.h"
+
+
+/****************************************************************************
+ * Default values                                                           *
+ ****************************************************************************/
+
+#define W9968CF_OVMOD_LOAD      1  /* automatic 'ovcamchip' module loading */
+#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
+
+/* Comment/uncomment the following line to enable/disable debugging messages */
+#define W9968CF_DEBUG
+
+/* These have effect only if W9968CF_DEBUG is defined */
+#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
+#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
+
+#define W9968CF_MAX_DEVICES    32
+#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
+
+#define W9968CF_MAX_BUFFERS   32
+#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
+
+/* Maximum data payload sizes in bytes for alternate settings */
+static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
+                                      511, 447, 383, 319, 255, 191, 127,  63};
+#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
+#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
+#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
+#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
+#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
+
+#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
+#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
+
+/* Available video formats */
+struct w9968cf_format {
+       const u16 palette;
+       const u16 depth;
+       const u8 compression;
+};
+
+static const struct w9968cf_format w9968cf_formatlist[] = {
+       { VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
+       { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
+       { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
+       { VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
+       { VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
+       { VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
+       { 0,                      0, 0 }  /* 0 is a terminating entry */
+};
+
+#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
+#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
+#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
+#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
+
+#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
+
+#define W9968CF_MAX_WIDTH      800 /* Has effect if up-scaling is on */
+#define W9968CF_MAX_HEIGHT     600 /* Has effect if up-scaling is on */
+#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
+#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
+
+#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
+#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
+#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
+#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
+#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
+
+#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
+#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
+#define W9968CF_HUE            32768 /* from 0 to 65535 */
+#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
+#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
+#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
+
+#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
+#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
+#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
+#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
+#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
+#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
+
+#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
+#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
+
+
+/****************************************************************************
+ * Globals                                                                  *
+ ****************************************************************************/
+
+#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
+                                "Dual Mode Camera Chip"
+#define W9968CF_MODULE_VERSION  "1:1.33-basic"
+#define W9968CF_MODULE_AUTHOR   "(C) 2002-2004 Luca Risolia"
+#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
+#define W9968CF_MODULE_LICENSE  "GPL"
+
+static const struct usb_device_id winbond_id_table[] = {
+       {
+               /* Creative Labs Video Blaster WebCam Go Plus */
+               USB_DEVICE(0x041e, 0x4003),
+               .driver_info = (unsigned long)"w9968cf",
+       },
+       {
+               /* Generic W996[87]CF JPEG USB Dual Mode Camera */
+               USB_DEVICE(0x1046, 0x9967),
+               .driver_info = (unsigned long)"w9968cf",
+       },
+       { } /* terminating entry */
+};
+
+/* W996[87]CF camera models, internal ids: */
+enum w9968cf_model_id {
+       W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
+       W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
+       W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
+       W9986CF_MOD_AAU = 31,     /* AVerMedia AVerTV USB */
+       W9968CF_MOD_CLVBWG = 34,  /* Creative Labs Video Blaster WebCam Go */
+       W9968CF_MOD_LL = 37,      /* Lebon LDC-035A */
+       W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
+       W9968CF_MOD_OOE = 42,     /* OmniVision OV8610-EDE */
+       W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
+       W9968CF_MOD_PDPII = 46,   /* Pretec Digi Pen-II */
+       W9968CF_MOD_PDP480 = 49,  /* Pretec DigiPen-480 */
+};
+
+enum w9968cf_frame_status {
+       F_READY,            /* finished grabbing & ready to be read/synced */
+       F_GRABBING,         /* in the process of being grabbed into */
+       F_ERROR,            /* something bad happened while processing */
+       F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
+};
+
+struct w9968cf_frame_t {
+       void* buffer;
+       unsigned long size;
+       u32 length;
+       int number;
+       enum w9968cf_frame_status status;
+       struct w9968cf_frame_t* next;
+       u8 queued;
+};
+
+enum w9968cf_vpp_flag {
+       VPP_NONE = 0x00,
+       VPP_UPSCALE = 0x01,
+       VPP_SWAP_YUV_BYTES = 0x02,
+       VPP_DECOMPRESSION = 0x04,
+       VPP_UYVY_TO_RGBX = 0x08,
+};
+
+/* Main device driver structure */
+struct w9968cf_device {
+       struct device dev; /* device structure */
+
+       enum w9968cf_model_id id;   /* private device identifier */
+
+       struct video_device* v4ldev; /* -> V4L structure */
+       struct list_head v4llist;    /* entry of the list of V4L cameras */
+
+       struct usb_device* usbdev;           /* -> main USB structure */
+       struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
+       void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
+       u16* control_buffer;                 /* -> buffer for control req.*/
+       u16* data_buffer;                    /* -> data to send to the FSB */
+
+       struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
+       struct w9968cf_frame_t frame_tmp; /* temporary frame */
+       struct w9968cf_frame_t frame_vpp; /* helper frame.*/
+       struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
+       struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
+
+       u8 max_buffers,   /* number of requested buffers */
+          force_palette, /* yes=1/no=0 */
+          force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
+          double_buffer, /* hardware double buffering yes=1/no=0 */
+          clamping,      /* video data clamping yes=1/no=0 */
+          filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
+          capture,       /* 0=disabled, 1=enabled */
+          largeview,     /* 0=disabled, 1=enabled */
+          decompression, /* 0=disabled, 1=forced, 2=allowed */
+          upscaling;     /* software image scaling, 0=enabled, 1=disabled */
+
+       struct video_picture picture; /* current picture settings */
+       struct video_window window;   /* current window settings */
+
+       u16 hw_depth,    /* depth (used by the chip) */
+           hw_palette,  /* palette (used by the chip) */
+           hw_width,    /* width (used by the chip) */
+           hw_height,   /* height (used by the chip) */
+           hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
+           vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
+           start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
+           start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
+
+       enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
+
+       u8 nbuffers,      /* number of allocated frame buffers */
+          altsetting,    /* camera alternate setting */
+          disconnected,  /* flag: yes=1, no=0 */
+          misconfigured, /* flag: yes=1, no=0 */
+          users,         /* flag: number of users holding the device */
+          streaming;     /* flag: yes=1, no=0 */
+
+       u8 sensor_initialized; /* flag: yes=1, no=0 */
+
+       /* Determined by the image sensor type: */
+       int sensor,       /* type of image sensor chip (CC_*) */
+           monochrome;   /* image sensor is (probably) monochrome */
+       u16 maxwidth,     /* maximum width supported by the image sensor */
+           maxheight,    /* maximum height supported by the image sensor */
+           minwidth,     /* minimum width supported by the image sensor */
+           minheight;    /* minimum height supported by the image sensor */
+       u8  auto_brt,     /* auto brightness enabled flag */
+           auto_exp,     /* auto exposure enabled flag */
+           backlight,    /* backlight exposure algorithm flag */
+           mirror,       /* image is reversed horizontally */
+           lightfreq,    /* power (lighting) frequency */
+           bandfilt;     /* banding filter enabled flag */
+       s8  clockdiv;     /* clock divisor */
+
+       /* I2C interface to kernel */
+       struct i2c_adapter i2c_adapter;
+       struct i2c_client* sensor_client;
+
+       /* Locks */
+       struct mutex dev_mutex,    /* for probe, disconnect,open and close */
+                        fileop_mutex; /* for read and ioctl */
+       spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
+                  flist_lock; /* for requested frame list accesses */
+       wait_queue_head_t open, wait_queue;
+
+       char command[16]; /* name of the program holding the device */
+};
+
+
+/****************************************************************************
+ * Macros for debugging                                                     *
+ ****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef W9968CF_DEBUG
+/* For device specific debugging messages */
+#      define DBG(level, fmt, args...)                                       \
+{                                                                             \
+       if ( ((specific_debug) && (debug == (level))) ||                      \
+            ((!specific_debug) && (debug >= (level))) ) {                    \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->dev, fmt "\n", ## args);                \
+               else if ((level) == 2 || (level) == 3)                        \
+                       dev_info(&cam->dev, fmt "\n", ## args);               \
+               else if ((level) == 4)                                        \
+                       dev_warn(&cam->dev, fmt "\n", ## args);               \
+               else if ((level) >= 5)                                        \
+                       dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+}
+/* For generic kernel (not device specific) messages */
+#      define KDBG(level, fmt, args...)                                      \
+{                                                                             \
+       if ( ((specific_debug) && (debug == (level))) ||                      \
+            ((!specific_debug) && (debug >= (level))) ) {                    \
+               if ((level) >= 1 && (level) <= 4)                             \
+                       pr_info("w9968cf: " fmt "\n", ## args);               \
+               else if ((level) >= 5)                                        \
+                       pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__,  \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+}
+#else
+       /* Not debugging: nothing */
+#      define DBG(level, fmt, args...) do {;} while(0);
+#      define KDBG(level, fmt, args...) do {;} while(0);
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
+
+#endif /* _W9968CF_H_ */
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h
new file mode 100644 (file)
index 0000000..31faccb
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Video decoder for the W996[87]CF driver for Linux.                      *
+ *                                                                         *
+ * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_DECODER_H_
+#define _W9968CF_DECODER_H_
+
+/* Comment/uncomment this for high/low quality of compressed video */
+#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
+
+#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
+static const unsigned char Y_QUANTABLE[64] = {
+       16,  11,  10,  16,  24,  40,  51,  61,
+       12,  12,  14,  19,  26,  58,  60,  55,
+       14,  13,  16,  24,  40,  57,  69,  56,
+       14,  17,  22,  29,  51,  87,  80,  62,
+       18,  22,  37,  56,  68, 109, 103,  77,
+       24,  35,  55,  64,  81, 104, 113,  92,
+       49,  64,  78,  87, 103, 121, 120, 101,
+       72,  92,  95,  98, 112, 100, 103,  99
+};
+
+static const unsigned char UV_QUANTABLE[64] = {
+       17,  18,  24,  47,  99,  99,  99,  99,
+       18,  21,  26,  66,  99,  99,  99,  99,
+       24,  26,  56,  99,  99,  99,  99,  99,
+       47,  66,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99,
+       99,  99,  99,  99,  99,  99,  99,  99
+};
+#else
+static const unsigned char Y_QUANTABLE[64] = {
+        8,   5,   5,   8,  12,  20,  25,  30,
+        6,   6,   7,   9,  13,  29,  30,  27,
+        7,   6,   8,  12,  20,  28,  34,  28,
+        7,   8,  11,  14,  25,  43,  40,  31,
+        9,  11,  18,  28,  34,  54,  51,  38,
+       12,  17,  27,  32,  40,  52,  56,  46,
+       24,  32,  39,  43,  51,  60,  60,  50,
+       36,  46,  47,  49,  56,  50,  51,  49
+};
+
+static const unsigned char UV_QUANTABLE[64] = {
+        8,   9,  12,  23,  49,  49,  49,  49,
+        9,  10,  13,  33,  49,  49,  49,  49,
+       12,  13,  28,  49,  49,  49,  49,  49,
+       23,  33,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49,
+       49,  49,  49,  49,  49,  49,  49,  49
+};
+#endif
+
+#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
+#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
+#define W9968CF_DEC_ERR_NO_SOI          -3
+#define W9968CF_DEC_ERR_NO_SOF0         -4
+#define W9968CF_DEC_ERR_NO_SOS          -5
+#define W9968CF_DEC_ERR_NO_EOI          -6
+
+extern void w9968cf_init_decoder(void);
+extern int w9968cf_check_headers(const unsigned char* Pin, 
+                                 const unsigned long BUF_SIZE);
+extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, 
+                          const unsigned W, const unsigned H, char* Pout);
+
+#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h
new file mode 100644 (file)
index 0000000..f3b91b7
--- /dev/null
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Interface for video post-processing functions for the W996[87]CF driver *
+ * for Linux.                                                              *
+ *                                                                         *
+ * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _W9968CF_VPP_H_
+#define _W9968CF_VPP_H_
+
+#include <linux/module.h>
+#include <asm/types.h>
+
+struct w9968cf_vpp_t {
+       struct module* owner;
+       int (*check_headers)(const unsigned char*, const unsigned long);
+       int (*decode)(const char*, const unsigned long, const unsigned,
+                     const unsigned, char*);
+       void (*swap_yuvbytes)(void*, unsigned long);
+       void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
+       void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
+
+       u8 busy; /* read-only flag: module is/is not in use */
+};
+
+#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
new file mode 100644 (file)
index 0000000..d749199
--- /dev/null
@@ -0,0 +1,3 @@
+zc0301-objs     := zc0301_core.o zc0301_pas202bcb.o
+
+obj-$(CONFIG_USB_ZC0301)        += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
new file mode 100644 (file)
index 0000000..8e06551
--- /dev/null
@@ -0,0 +1,192 @@
+/***************************************************************************
+ * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ZC0301_H_
+#define _ZC0301_H_
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+
+#include "zc0301_sensor.h"
+
+/*****************************************************************************/
+
+#define ZC0301_DEBUG
+#define ZC0301_DEBUG_LEVEL         2
+#define ZC0301_MAX_DEVICES         64
+#define ZC0301_FORCE_MUNMAP        0
+#define ZC0301_MAX_FRAMES          32
+#define ZC0301_COMPRESSION_QUALITY 0
+#define ZC0301_URBS                2
+#define ZC0301_ISO_PACKETS         7
+#define ZC0301_ALTERNATE_SETTING   7
+#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
+#define ZC0301_CTRL_TIMEOUT        100
+#define ZC0301_FRAME_TIMEOUT       2
+
+/*****************************************************************************/
+
+ZC0301_ID_TABLE
+ZC0301_SENSOR_TABLE
+
+enum zc0301_frame_state {
+       F_UNUSED,
+       F_QUEUED,
+       F_GRABBING,
+       F_DONE,
+       F_ERROR,
+};
+
+struct zc0301_frame_t {
+       void* bufmem;
+       struct v4l2_buffer buf;
+       enum zc0301_frame_state state;
+       struct list_head frame;
+       unsigned long vma_use_count;
+};
+
+enum zc0301_dev_state {
+       DEV_INITIALIZED = 0x01,
+       DEV_DISCONNECTED = 0x02,
+       DEV_MISCONFIGURED = 0x04,
+};
+
+enum zc0301_io_method {
+       IO_NONE,
+       IO_READ,
+       IO_MMAP,
+};
+
+enum zc0301_stream_state {
+       STREAM_OFF,
+       STREAM_INTERRUPT,
+       STREAM_ON,
+};
+
+struct zc0301_module_param {
+       u8 force_munmap;
+       u16 frame_timeout;
+};
+
+static DECLARE_RWSEM(zc0301_disconnect);
+
+struct zc0301_device {
+       struct video_device* v4ldev;
+
+       struct zc0301_sensor sensor;
+
+       struct usb_device* usbdev;
+       struct urb* urb[ZC0301_URBS];
+       void* transfer_buffer[ZC0301_URBS];
+       u8* control_buffer;
+
+       struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
+       struct list_head inqueue, outqueue;
+       u32 frame_count, nbuffers, nreadbuffers;
+
+       enum zc0301_io_method io;
+       enum zc0301_stream_state stream;
+
+       struct v4l2_jpegcompression compression;
+
+       struct zc0301_module_param module_param;
+
+       enum zc0301_dev_state state;
+       u8 users;
+
+       struct mutex dev_mutex, fileop_mutex;
+       spinlock_t queue_lock;
+       wait_queue_head_t open, wait_frame, wait_stream;
+};
+
+/*****************************************************************************/
+
+struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
+{
+       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
+}
+
+void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
+{
+       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
+}
+
+/*****************************************************************************/
+
+#undef DBG
+#undef KDBG
+#ifdef ZC0301_DEBUG
+#      define DBG(level, fmt, args...)                                       \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1)                                             \
+                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
+               else if ((level) == 2)                                        \
+                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
+               else if ((level) >= 3)                                        \
+                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
+                                __FUNCTION__, __LINE__ , ## args);           \
+       }                                                                     \
+} while (0)
+#      define KDBG(level, fmt, args...)                                      \
+do {                                                                          \
+       if (debug >= (level)) {                                               \
+               if ((level) == 1 || (level) == 2)                             \
+                       pr_info("zc0301: " fmt "\n", ## args);                \
+               else if ((level) == 3)                                        \
+                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
+                                __LINE__ , ## args);                         \
+       }                                                                     \
+} while (0)
+#      define V4LDBG(level, name, cmd)                                       \
+do {                                                                          \
+       if (debug >= (level))                                                 \
+               v4l_print_ioctl(name, cmd);                                   \
+} while (0)
+#else
+#      define DBG(level, fmt, args...) do {;} while(0)
+#      define KDBG(level, fmt, args...) do {;} while(0)
+#      define V4LDBG(level, name, cmd) do {;} while(0)
+#endif
+
+#undef PDBG
+#define PDBG(fmt, args...)                                                    \
+dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
+         __FUNCTION__, __LINE__ , ## args)
+
+#undef PDBGG
+#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+
+#endif /* _ZC0301_H_ */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
new file mode 100644 (file)
index 0000000..4036c62
--- /dev/null
@@ -0,0 +1,2055 @@
+/***************************************************************************
+ * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Informations about the chip internals needed to enable the I2C protocol *
+ * have been taken from the documentation of the ZC030x Video4Linux1       *
+ * driver written by Andrew Birkett <andy@nobugs.org>                      *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/compiler.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/page-flags.h>
+#include <linux/byteorder/generic.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+
+#include "zc0301.h"
+
+/*****************************************************************************/
+
+#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
+                              "Image Processor and Control Chip"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
+#define ZC0301_MODULE_LICENSE "GPL"
+#define ZC0301_MODULE_VERSION "1:1.03"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
+
+/*****************************************************************************/
+
+MODULE_DEVICE_TABLE(usb, zc0301_id_table);
+
+MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
+MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
+MODULE_VERSION(ZC0301_MODULE_VERSION);
+MODULE_LICENSE(ZC0301_MODULE_LICENSE);
+
+static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
+module_param_array(video_nr, short, NULL, 0444);
+MODULE_PARM_DESC(video_nr,
+                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
+                 "\n -1 = use next available (default)"
+                 "\n  n = use minor number n (integer >= 0)"
+                 "\nYou can specify up to "
+                 __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
+                 "\nFor example:"
+                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
+                 "\nthe second registered camera and use auto for the first"
+                 "\none and for every other camera."
+                 "\n");
+
+static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                               ZC0301_FORCE_MUNMAP};
+module_param_array(force_munmap, bool, NULL, 0444);
+MODULE_PARM_DESC(force_munmap,
+                 "\n<0|1[,...]> Force the application to unmap previously"
+                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
+                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
+                 "\nthis feature. This parameter is specific for each"
+                 "\ndetected camera."
+                 "\n 0 = do not force memory unmapping"
+                 "\n 1 = force memory unmapping (save memory)"
+                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
+                 "\n");
+
+static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                                       ZC0301_FRAME_TIMEOUT};
+module_param_array(frame_timeout, uint, NULL, 0644);
+MODULE_PARM_DESC(frame_timeout,
+                 "\n<n[,...]> Timeout for a video frame in seconds."
+                 "\nThis parameter is specific for each detected camera."
+                 "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
+                 "\n");
+
+#ifdef ZC0301_DEBUG
+static unsigned short debug = ZC0301_DEBUG_LEVEL;
+module_param(debug, ushort, 0644);
+MODULE_PARM_DESC(debug,
+                 "\n<n> Debugging information level, from 0 to 3:"
+                 "\n0 = none (use carefully)"
+                 "\n1 = critical errors"
+                 "\n2 = significant informations"
+                 "\n3 = more verbose messages"
+                 "\nLevel 3 is useful for testing only, when only "
+                 "one device is used."
+                 "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
+                 "\n");
+#endif
+
+/*****************************************************************************/
+
+static u32
+zc0301_request_buffers(struct zc0301_device* cam, u32 count,
+                       enum zc0301_io_method io)
+{
+       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
+       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+       const size_t imagesize = cam->module_param.force_munmap ||
+                                io == IO_READ ?
+                                (p->width * p->height * p->priv) / 8 :
+                                (r->width * r->height * p->priv) / 8;
+       void* buff = NULL;
+       u32 i;
+
+       if (count > ZC0301_MAX_FRAMES)
+               count = ZC0301_MAX_FRAMES;
+
+       cam->nbuffers = count;
+       while (cam->nbuffers > 0) {
+               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
+                       break;
+               cam->nbuffers--;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.index = i;
+               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
+               cam->frame[i].buf.length = imagesize;
+               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               cam->frame[i].buf.sequence = 0;
+               cam->frame[i].buf.field = V4L2_FIELD_NONE;
+               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
+               cam->frame[i].buf.flags = 0;
+       }
+
+       return cam->nbuffers;
+}
+
+
+static void zc0301_release_buffers(struct zc0301_device* cam)
+{
+       if (cam->nbuffers) {
+               vfree(cam->frame[0].bufmem);
+               cam->nbuffers = 0;
+       }
+       cam->frame_current = NULL;
+}
+
+
+static void zc0301_empty_framequeues(struct zc0301_device* cam)
+{
+       u32 i;
+
+       INIT_LIST_HEAD(&cam->inqueue);
+       INIT_LIST_HEAD(&cam->outqueue);
+
+       for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
+               cam->frame[i].state = F_UNUSED;
+               cam->frame[i].buf.bytesused = 0;
+       }
+}
+
+
+static void zc0301_requeue_outqueue(struct zc0301_device* cam)
+{
+       struct zc0301_frame_t *i;
+
+       list_for_each_entry(i, &cam->outqueue, frame) {
+               i->state = F_QUEUED;
+               list_add(&i->frame, &cam->inqueue);
+       }
+
+       INIT_LIST_HEAD(&cam->outqueue);
+}
+
+
+static void zc0301_queue_unusedframes(struct zc0301_device* cam)
+{
+       unsigned long lock_flags;
+       u32 i;
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].state == F_UNUSED) {
+                       cam->frame[i].state = F_QUEUED;
+                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
+                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               }
+}
+
+/*****************************************************************************/
+
+int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
+{
+       struct usb_device* udev = cam->usbdev;
+       int res;
+
+       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
+                             value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
+       if (res < 0) {
+               DBG(3, "Failed to write a register (index 0x%04X, "
+                      "value 0x%02X, error %d)",index, value, res);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int zc0301_read_reg(struct zc0301_device* cam, u16 index)
+{
+       struct usb_device* udev = cam->usbdev;
+       u8* buff = cam->control_buffer;
+       int res;
+
+       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
+                             0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
+       if (res < 0)
+               DBG(3, "Failed to read a register (index 0x%04X, error %d)",
+                   index, res);
+
+       PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
+
+       return (res >= 0) ? (int)(*buff) : -1;
+}
+
+
+int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
+{
+       int err = 0, res, r0, r1;
+
+       err += zc0301_write_reg(cam, 0x0092, address);
+       err += zc0301_write_reg(cam, 0x0090, 0x02);
+
+       msleep(1);
+
+       res = zc0301_read_reg(cam, 0x0091);
+       if (res < 0)
+               err += res;
+       r0 = zc0301_read_reg(cam, 0x0095);
+       if (r0 < 0)
+               err += r0;
+       r1 = zc0301_read_reg(cam, 0x0096);
+       if (r1 < 0)
+               err += r1;
+
+       res = (length <= 1) ? r0 : r0 | (r1 << 8);
+
+       if (err)
+               DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
+                   address, res);
+
+
+       PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
+
+       return err ? -1 : res;
+}
+
+
+int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
+{
+       int err = 0, res;
+
+       err += zc0301_write_reg(cam, 0x0092, address);
+       err += zc0301_write_reg(cam, 0x0093, value & 0xff);
+       err += zc0301_write_reg(cam, 0x0094, value >> 8);
+       err += zc0301_write_reg(cam, 0x0090, 0x01);
+
+       msleep(1);
+
+       res = zc0301_read_reg(cam, 0x0091);
+       if (res < 0)
+               err += res;
+
+       if (err)
+               DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
+                   address, value);
+
+       PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
+
+       return err ? -1 : 0;
+}
+
+/*****************************************************************************/
+
+static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
+{
+       struct zc0301_device* cam = urb->context;
+       struct zc0301_frame_t** f;
+       size_t imagesize;
+       u8 i;
+       int err = 0;
+
+       if (urb->status == -ENOENT)
+               return;
+
+       f = &cam->frame_current;
+
+       if (cam->stream == STREAM_INTERRUPT) {
+               cam->stream = STREAM_OFF;
+               if ((*f))
+                       (*f)->state = F_QUEUED;
+               DBG(3, "Stream interrupted");
+               wake_up(&cam->wait_stream);
+       }
+
+       if (cam->state & DEV_DISCONNECTED)
+               return;
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               wake_up_interruptible(&cam->wait_frame);
+               return;
+       }
+
+       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
+               goto resubmit_urb;
+
+       if (!(*f))
+               (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
+                                 frame);
+
+       imagesize = (cam->sensor.pix_format.width *
+                    cam->sensor.pix_format.height *
+                    cam->sensor.pix_format.priv) / 8;
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               unsigned int len, status;
+               void *pos;
+               u16* soi;
+               u8 sof;
+
+               len = urb->iso_frame_desc[i].actual_length;
+               status = urb->iso_frame_desc[i].status;
+               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
+
+               if (status) {
+                       DBG(3, "Error in isochronous frame");
+                       (*f)->state = F_ERROR;
+                       continue;
+               }
+
+               sof = (*(soi = pos) == 0xd8ff);
+
+               PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
+
+               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
+start_of_frame:
+                       if (sof) {
+                               (*f)->state = F_GRABBING;
+                               (*f)->buf.bytesused = 0;
+                               do_gettimeofday(&(*f)->buf.timestamp);
+                               DBG(3, "SOF detected: new video frame");
+                       }
+
+               if ((*f)->state == F_GRABBING) {
+                       if (sof && (*f)->buf.bytesused)
+                                       goto end_of_frame;
+
+                       if ((*f)->buf.bytesused + len > imagesize) {
+                               DBG(3, "Video frame size exceeded");
+                               (*f)->state = F_ERROR;
+                               continue;
+                       }
+
+                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
+                       (*f)->buf.bytesused += len;
+
+                       if ((*f)->buf.bytesused == imagesize) {
+                               u32 b;
+end_of_frame:
+                               b = (*f)->buf.bytesused;
+                               (*f)->state = F_DONE;
+                               (*f)->buf.sequence= ++cam->frame_count;
+                               spin_lock(&cam->queue_lock);
+                               list_move_tail(&(*f)->frame, &cam->outqueue);
+                               if (!list_empty(&cam->inqueue))
+                                       (*f) = list_entry(cam->inqueue.next,
+                                                      struct zc0301_frame_t,
+                                                         frame);
+                               else
+                                       (*f) = NULL;
+                               spin_unlock(&cam->queue_lock);
+                               DBG(3, "Video frame captured: : %lu bytes",
+                                      (unsigned long)(b));
+
+                               if (!(*f))
+                                       goto resubmit_urb;
+
+                               if (sof)
+                                       goto start_of_frame;
+                       }
+               }
+       }
+
+resubmit_urb:
+       urb->dev = cam->usbdev;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err < 0 && err != -EPERM) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "usb_submit_urb() failed");
+       }
+
+       wake_up_interruptible(&cam->wait_frame);
+}
+
+
+static int zc0301_start_transfer(struct zc0301_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       struct urb* urb;
+       const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
+                                              512, 768, 1023};
+       const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
+       s8 i, j;
+       int err = 0;
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
+                                                 GFP_KERNEL);
+               if (!cam->transfer_buffer[i]) {
+                       err = -ENOMEM;
+                       DBG(1, "Not enough memory");
+                       goto free_buffers;
+               }
+       }
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
+               cam->urb[i] = urb;
+               if (!urb) {
+                       err = -ENOMEM;
+                       DBG(1, "usb_alloc_urb() failed");
+                       goto free_urbs;
+               }
+               urb->dev = udev;
+               urb->context = cam;
+               urb->pipe = usb_rcvisocpipe(udev, 1);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->number_of_packets = ZC0301_ISO_PACKETS;
+               urb->complete = zc0301_urb_complete;
+               urb->transfer_buffer = cam->transfer_buffer[i];
+               urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
+               urb->interval = 1;
+               for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
+                       urb->iso_frame_desc[j].offset = psz * j;
+                       urb->iso_frame_desc[j].length = psz;
+               }
+       }
+
+       err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
+       if (err) {
+               DBG(1, "usb_set_interface() failed");
+               goto free_urbs;
+       }
+
+       cam->frame_current = NULL;
+
+       for (i = 0; i < ZC0301_URBS; i++) {
+               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
+               if (err) {
+                       for (j = i-1; j >= 0; j--)
+                               usb_kill_urb(cam->urb[j]);
+                       DBG(1, "usb_submit_urb() failed, error %d", err);
+                       goto free_urbs;
+               }
+       }
+
+       return 0;
+
+free_urbs:
+       for (i = 0; (i < ZC0301_URBS) &&  cam->urb[i]; i++)
+               usb_free_urb(cam->urb[i]);
+
+free_buffers:
+       for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
+               kfree(cam->transfer_buffer[i]);
+
+       return err;
+}
+
+
+static int zc0301_stop_transfer(struct zc0301_device* cam)
+{
+       struct usb_device *udev = cam->usbdev;
+       s8 i;
+       int err = 0;
+
+       if (cam->state & DEV_DISCONNECTED)
+               return 0;
+
+       for (i = ZC0301_URBS-1; i >= 0; i--) {
+               usb_kill_urb(cam->urb[i]);
+               usb_free_urb(cam->urb[i]);
+               kfree(cam->transfer_buffer[i]);
+       }
+
+       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
+       if (err)
+               DBG(3, "usb_set_interface() failed");
+
+       return err;
+}
+
+
+static int zc0301_stream_interrupt(struct zc0301_device* cam)
+{
+       long timeout;
+
+       cam->stream = STREAM_INTERRUPT;
+       timeout = wait_event_timeout(cam->wait_stream,
+                                    (cam->stream == STREAM_OFF) ||
+                                    (cam->state & DEV_DISCONNECTED),
+                                    ZC0301_URB_TIMEOUT);
+       if (cam->state & DEV_DISCONNECTED)
+               return -ENODEV;
+       else if (cam->stream != STREAM_OFF) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "URB timeout reached. The camera is misconfigured. To "
+                      "use it, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_set_compression(struct zc0301_device* cam,
+                       struct v4l2_jpegcompression* compression)
+{
+       int r, err = 0;
+
+       if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
+               err += r;
+       err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
+
+       return err ? -EIO : 0;
+}
+
+
+static int zc0301_init(struct zc0301_device* cam)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       struct v4l2_queryctrl *qctrl;
+       struct v4l2_rect* rect;
+       u8 i = 0;
+       int err = 0;
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               init_waitqueue_head(&cam->open);
+               qctrl = s->qctrl;
+               rect = &(s->cropcap.defrect);
+               cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
+       } else { /* use current values */
+               qctrl = s->_qctrl;
+               rect = &(s->_rect);
+       }
+
+       if (s->init) {
+               err = s->init(cam);
+               if (err) {
+                       DBG(3, "Sensor initialization failed");
+                       return err;
+               }
+       }
+
+       if ((err = zc0301_set_compression(cam, &cam->compression))) {
+               DBG(3, "set_compression() failed");
+               return err;
+       }
+
+       if (s->set_crop)
+               if ((err = s->set_crop(cam, rect))) {
+                       DBG(3, "set_crop() failed");
+                       return err;
+               }
+
+       if (s->set_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (s->qctrl[i].id != 0 &&
+                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
+                               ctrl.id = s->qctrl[i].id;
+                               ctrl.value = qctrl[i].default_value;
+                               err = s->set_ctrl(cam, &ctrl);
+                               if (err) {
+                                       DBG(3, "Set %s control failed",
+                                           s->qctrl[i].name);
+                                       return err;
+                               }
+                               DBG(3, "Image sensor supports '%s' control",
+                                   s->qctrl[i].name);
+                       }
+       }
+
+       if (!(cam->state & DEV_INITIALIZED)) {
+               mutex_init(&cam->fileop_mutex);
+               spin_lock_init(&cam->queue_lock);
+               init_waitqueue_head(&cam->wait_frame);
+               init_waitqueue_head(&cam->wait_stream);
+               cam->nreadbuffers = 2;
+               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
+               memcpy(&(s->_rect), &(s->cropcap.defrect),
+                      sizeof(struct v4l2_rect));
+               cam->state |= DEV_INITIALIZED;
+       }
+
+       DBG(2, "Initialization succeeded");
+       return 0;
+}
+
+
+static void zc0301_release_resources(struct zc0301_device* cam)
+{
+       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
+       video_set_drvdata(cam->v4ldev, NULL);
+       video_unregister_device(cam->v4ldev);
+       kfree(cam->control_buffer);
+}
+
+/*****************************************************************************/
+
+static int zc0301_open(struct inode* inode, struct file* filp)
+{
+       struct zc0301_device* cam;
+       int err = 0;
+
+       /*
+          This is the only safe way to prevent race conditions with
+          disconnect
+       */
+       if (!down_read_trylock(&zc0301_disconnect))
+               return -ERESTARTSYS;
+
+       cam = video_get_drvdata(video_devdata(filp));
+
+       if (mutex_lock_interruptible(&cam->dev_mutex)) {
+               up_read(&zc0301_disconnect);
+               return -ERESTARTSYS;
+       }
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+               if ((filp->f_flags & O_NONBLOCK) ||
+                   (filp->f_flags & O_NDELAY)) {
+                       err = -EWOULDBLOCK;
+                       goto out;
+               }
+               mutex_unlock(&cam->dev_mutex);
+               err = wait_event_interruptible_exclusive(cam->open,
+                                                 cam->state & DEV_DISCONNECTED
+                                                        || !cam->users);
+               if (err) {
+                       up_read(&zc0301_disconnect);
+                       return err;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       up_read(&zc0301_disconnect);
+                       return -ENODEV;
+               }
+               mutex_lock(&cam->dev_mutex);
+       }
+
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               err = zc0301_init(cam);
+               if (err) {
+                       DBG(1, "Initialization failed again. "
+                              "I will retry on next open().");
+                       goto out;
+               }
+               cam->state &= ~DEV_MISCONFIGURED;
+       }
+
+       if ((err = zc0301_start_transfer(cam)))
+               goto out;
+
+       filp->private_data = cam;
+       cam->users++;
+       cam->io = IO_NONE;
+       cam->stream = STREAM_OFF;
+       cam->nbuffers = 0;
+       cam->frame_count = 0;
+       zc0301_empty_framequeues(cam);
+
+       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
+
+out:
+       mutex_unlock(&cam->dev_mutex);
+       up_read(&zc0301_disconnect);
+       return err;
+}
+
+
+static int zc0301_release(struct inode* inode, struct file* filp)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+
+       zc0301_stop_transfer(cam);
+
+       zc0301_release_buffers(cam);
+
+       if (cam->state & DEV_DISCONNECTED) {
+               zc0301_release_resources(cam);
+               usb_put_dev(cam->usbdev);
+               mutex_unlock(&cam->dev_mutex);
+               kfree(cam);
+               return 0;
+       }
+
+       cam->users--;
+       wake_up_interruptible_nr(&cam->open, 1);
+
+       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+}
+
+
+static ssize_t
+zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_frame_t* f, * i;
+       unsigned long lock_flags;
+       long timeout;
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io == IO_MMAP) {
+               DBG(3, "Close and open the device again to choose the read "
+                      "method");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "read() failed, not enough memory");
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENOMEM;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (list_empty(&cam->inqueue)) {
+               if (!list_empty(&cam->outqueue))
+                       zc0301_empty_framequeues(cam);
+               zc0301_queue_unusedframes(cam);
+       }
+
+       if (!count) {
+               mutex_unlock(&cam->fileop_mutex);
+               return 0;
+       }
+
+       if (list_empty(&cam->outqueue)) {
+               if (filp->f_flags & O_NONBLOCK) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return timeout;
+               }
+               if (cam->state & DEV_DISCONNECTED) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -ENODEV;
+               }
+               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EIO;
+               }
+       }
+
+       f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
+
+       if (count > f->buf.bytesused)
+               count = f->buf.bytesused;
+
+       if (copy_to_user(buf, f->bufmem, count)) {
+               err = -EFAULT;
+               goto exit;
+       }
+       *f_pos += count;
+
+exit:
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_for_each_entry(i, &cam->outqueue, frame)
+               i->state = F_UNUSED;
+       INIT_LIST_HEAD(&cam->outqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       zc0301_queue_unusedframes(cam);
+
+       PDBGG("Frame #%lu, bytes read: %zu",
+             (unsigned long)f->buf.index, count);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err ? err : count;
+}
+
+
+static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       struct zc0301_frame_t* f;
+       unsigned long lock_flags;
+       unsigned int mask = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return POLLERR;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               goto error;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               goto error;
+       }
+
+       if (cam->io == IO_NONE) {
+               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
+                       DBG(1, "poll() failed, not enough memory");
+                       goto error;
+               }
+               cam->io = IO_READ;
+               cam->stream = STREAM_ON;
+       }
+
+       if (cam->io == IO_READ) {
+               spin_lock_irqsave(&cam->queue_lock, lock_flags);
+               list_for_each_entry(f, &cam->outqueue, frame)
+                       f->state = F_UNUSED;
+               INIT_LIST_HEAD(&cam->outqueue);
+               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+               zc0301_queue_unusedframes(cam);
+       }
+
+       poll_wait(filp, &cam->wait_frame, wait);
+
+       if (!list_empty(&cam->outqueue))
+               mask |= POLLIN | POLLRDNORM;
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return mask;
+
+error:
+       mutex_unlock(&cam->fileop_mutex);
+       return POLLERR;
+}
+
+
+static void zc0301_vm_open(struct vm_area_struct* vma)
+{
+       struct zc0301_frame_t* f = vma->vm_private_data;
+       f->vma_use_count++;
+}
+
+
+static void zc0301_vm_close(struct vm_area_struct* vma)
+{
+       /* NOTE: buffers are not freed here */
+       struct zc0301_frame_t* f = vma->vm_private_data;
+       f->vma_use_count--;
+}
+
+
+static struct vm_operations_struct zc0301_vm_ops = {
+       .open = zc0301_vm_open,
+       .close = zc0301_vm_close,
+};
+
+
+static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       unsigned long size = vma->vm_end - vma->vm_start,
+                     start = vma->vm_start;
+       void *pos;
+       u32 i;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++) {
+               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (i == cam->nbuffers) {
+               mutex_unlock(&cam->fileop_mutex);
+               return -EINVAL;
+       }
+
+       vma->vm_flags |= VM_IO;
+       vma->vm_flags |= VM_RESERVED;
+
+       pos = cam->frame[i].bufmem;
+       while (size > 0) { /* size is page-aligned */
+               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
+                       mutex_unlock(&cam->fileop_mutex);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       vma->vm_ops = &zc0301_vm_ops;
+       vma->vm_private_data = &cam->frame[i];
+
+       zc0301_vm_open(vma);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return 0;
+}
+
+/*****************************************************************************/
+
+static int
+zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_capability cap = {
+               .driver = "zc0301",
+               .version = ZC0301_MODULE_VERSION_CODE,
+               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING,
+       };
+
+       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
+       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
+               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
+                       sizeof(cap.bus_info));
+
+       if (copy_to_user(arg, &cap, sizeof(cap)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_input i;
+
+       if (copy_from_user(&i, arg, sizeof(i)))
+               return -EFAULT;
+
+       if (i.index)
+               return -EINVAL;
+
+       memset(&i, 0, sizeof(i));
+       strcpy(i.name, "Camera");
+       i.type = V4L2_INPUT_TYPE_CAMERA;
+
+       if (copy_to_user(arg, &i, sizeof(i)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
+{
+       int index = 0;
+
+       if (copy_to_user(arg, &index, sizeof(index)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
+{
+       int index;
+
+       if (copy_from_user(&index, arg, sizeof(index)))
+               return -EFAULT;
+
+       if (index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_queryctrl qc;
+       u8 i;
+
+       if (copy_from_user(&qc, arg, sizeof(qc)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (qc.id && qc.id == s->qctrl[i].id) {
+                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
+                       if (copy_to_user(arg, &qc, sizeof(qc)))
+                               return -EFAULT;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+
+static int
+zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       int err = 0;
+       u8 i;
+
+       if (!s->get_ctrl && !s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       if (!s->get_ctrl) {
+               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+                       if (ctrl.id == s->qctrl[i].id) {
+                               ctrl.value = s->_qctrl[i].default_value;
+                               goto exit;
+                       }
+               return -EINVAL;
+       } else
+               err = s->get_ctrl(cam, &ctrl);
+
+exit:
+       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
+               return -EFAULT;
+
+       return err;
+}
+
+
+static int
+zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_control ctrl;
+       u8 i;
+       int err = 0;
+
+       if (!s->set_ctrl)
+               return -EINVAL;
+
+       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
+               return -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
+               if (ctrl.id == s->qctrl[i].id) {
+                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
+                               return -EINVAL;
+                       if (ctrl.value < s->qctrl[i].minimum ||
+                           ctrl.value > s->qctrl[i].maximum)
+                               return -ERANGE;
+                       ctrl.value -= ctrl.value % s->qctrl[i].step;
+                       break;
+               }
+
+       if ((err = s->set_ctrl(cam, &ctrl)))
+               return err;
+
+       s->_qctrl[i].default_value = ctrl.value;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+
+       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       cc->pixelaspect.numerator = 1;
+       cc->pixelaspect.denominator = 1;
+
+       if (copy_to_user(arg, cc, sizeof(*cc)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_crop crop = {
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+       };
+
+       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
+
+       if (copy_to_user(arg, &crop, sizeof(crop)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_crop crop;
+       struct v4l2_rect* rect;
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       const enum zc0301_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&crop, arg, sizeof(crop)))
+               return -EFAULT;
+
+       rect = &(crop.c);
+
+       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_CROP failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (!s->set_crop) {
+               memcpy(rect, &(s->_rect), sizeof(*rect));
+               if (copy_to_user(arg, &crop, sizeof(crop)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       rect->left &= ~7L;
+       rect->top &= ~7L;
+       if (rect->width < 8)
+               rect->width = 8;
+       if (rect->height < 8)
+               rect->height = 8;
+       if (rect->width > bounds->width)
+               rect->width = bounds->width;
+       if (rect->height > bounds->height)
+               rect->height = bounds->height;
+       if (rect->left < bounds->left)
+               rect->left = bounds->left;
+       if (rect->top < bounds->top)
+               rect->top = bounds->top;
+       if (rect->left + rect->width > bounds->left + bounds->width)
+               rect->left = bounds->left+bounds->width - rect->width;
+       if (rect->top + rect->height > bounds->top + bounds->height)
+               rect->top = bounds->top+bounds->height - rect->height;
+       rect->width &= ~7L;
+       rect->height &= ~7L;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &crop, sizeof(crop))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               zc0301_release_buffers(cam);
+
+       if (s->set_crop)
+               err += s->set_crop(cam, rect);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       s->pix_format.width = rect->width;
+       s->pix_format.height = rect->height;
+       memcpy(&(s->_rect), rect, sizeof(*rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               zc0301_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               zc0301_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_fmtdesc fmtd;
+
+       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
+               return -EFAULT;
+
+       if (fmtd.index == 0) {
+               strcpy(fmtd.description, "JPEG");
+               fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
+               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
+       } else
+               return -EINVAL;
+
+       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
+
+       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_format format;
+       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       pfmt->bytesperline = 0;
+       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
+       pfmt->field = V4L2_FIELD_NONE;
+       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
+
+       if (copy_to_user(arg, &format, sizeof(format)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
+                        void __user * arg)
+{
+       struct zc0301_sensor* s = &cam->sensor;
+       struct v4l2_format format;
+       struct v4l2_pix_format* pix;
+       struct v4l2_pix_format* pfmt = &(s->pix_format);
+       struct v4l2_rect* bounds = &(s->cropcap.bounds);
+       struct v4l2_rect rect;
+       const enum zc0301_stream_state stream = cam->stream;
+       const u32 nbuffers = cam->nbuffers;
+       u32 i;
+       int err = 0;
+
+       if (copy_from_user(&format, arg, sizeof(format)))
+               return -EFAULT;
+
+       pix = &(format.fmt.pix);
+
+       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memcpy(&rect, &(s->_rect), sizeof(rect));
+
+       if (!s->set_crop) {
+               pix->width = rect.width;
+               pix->height = rect.height;
+       } else {
+               rect.width = pix->width;
+               rect.height = pix->height;
+       }
+
+       if (rect.width < 8)
+               rect.width = 8;
+       if (rect.height < 8)
+               rect.height = 8;
+       if (rect.width > bounds->left + bounds->width - rect.left)
+               rect.width = bounds->left + bounds->width - rect.left;
+       if (rect.height > bounds->top + bounds->height - rect.top)
+               rect.height = bounds->top + bounds->height - rect.top;
+       rect.width &= ~7L;
+       rect.height &= ~7L;
+
+       pix->width = rect.width;
+       pix->height = rect.height;
+       pix->pixelformat = pfmt->pixelformat;
+       pix->priv = pfmt->priv;
+       pix->colorspace = pfmt->colorspace;
+       pix->bytesperline = 0;
+       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
+       pix->field = V4L2_FIELD_NONE;
+
+       if (cmd == VIDIOC_TRY_FMT) {
+               if (copy_to_user(arg, &format, sizeof(format)))
+                       return -EFAULT;
+               return 0;
+       }
+
+       if (cam->module_param.force_munmap)
+               for (i = 0; i < cam->nbuffers; i++)
+                       if (cam->frame[i].vma_use_count) {
+                               DBG(3, "VIDIOC_S_FMT failed. "
+                                      "Unmap the buffers first.");
+                               return -EINVAL;
+                       }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       if (copy_to_user(arg, &format, sizeof(format))) {
+               cam->stream = stream;
+               return -EFAULT;
+       }
+
+       if (cam->module_param.force_munmap || cam->io == IO_READ)
+               zc0301_release_buffers(cam);
+
+       if (s->set_crop)
+               err += s->set_crop(cam, &rect);
+
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       memcpy(pfmt, pix, sizeof(*pix));
+       memcpy(&(s->_rect), &rect, sizeof(rect));
+
+       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
+           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
+                      "use the camera, close and open /dev/video%d again.",
+                   cam->v4ldev->minor);
+               return -ENOMEM;
+       }
+
+       if (cam->io == IO_READ)
+               zc0301_empty_framequeues(cam);
+       else if (cam->module_param.force_munmap)
+               zc0301_requeue_outqueue(cam);
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_jpegcompression jc;
+       const enum zc0301_stream_state stream = cam->stream;
+       int err = 0;
+
+       if (copy_from_user(&jc, arg, sizeof(jc)))
+               return -EFAULT;
+
+       if (jc.quality != 0)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       err += zc0301_set_compression(cam, &jc);
+       if (err) { /* atomic, no rollback in ioctl() */
+               cam->state |= DEV_MISCONFIGURED;
+               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
+                      "problems. To use the camera, close and open "
+                      "/dev/video%d again.", cam->v4ldev->minor);
+               return -EIO;
+       }
+
+       cam->compression.quality = jc.quality;
+
+       cam->stream = stream;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_requestbuffers rb;
+       u32 i;
+       int err;
+
+       if (copy_from_user(&rb, arg, sizeof(rb)))
+               return -EFAULT;
+
+       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           rb.memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+
+       if (cam->io == IO_READ) {
+               DBG(3, "Close and open the device again to choose the mmap "
+                      "I/O method");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cam->nbuffers; i++)
+               if (cam->frame[i].vma_use_count) {
+                       DBG(3, "VIDIOC_REQBUFS failed. "
+                              "Previous buffers are still mapped.");
+                       return -EINVAL;
+               }
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       zc0301_empty_framequeues(cam);
+
+       zc0301_release_buffers(cam);
+       if (rb.count)
+               rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
+
+       if (copy_to_user(arg, &rb, sizeof(rb))) {
+               zc0301_release_buffers(cam);
+               cam->io = IO_NONE;
+               return -EFAULT;
+       }
+
+       cam->io = rb.count ? IO_MMAP : IO_NONE;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
+
+       if (cam->frame[b.index].vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (cam->frame[b.index].state == F_DONE)
+               b.flags |= V4L2_BUF_FLAG_DONE;
+       else if (cam->frame[b.index].state != F_UNUSED)
+               b.flags |= V4L2_BUF_FLAG_QUEUED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_buffer b;
+       unsigned long lock_flags;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+           b.index >= cam->nbuffers || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->frame[b.index].state != F_UNUSED)
+               return -EINVAL;
+
+       cam->frame[b.index].state = F_QUEUED;
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       PDBGG("Frame #%lu queued", (unsigned long)b.index);
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
+                    void __user * arg)
+{
+       struct v4l2_buffer b;
+       struct zc0301_frame_t *f;
+       unsigned long lock_flags;
+       long timeout;
+
+       if (copy_from_user(&b, arg, sizeof(b)))
+               return -EFAULT;
+
+       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->outqueue)) {
+               if (cam->stream == STREAM_OFF)
+                       return -EINVAL;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+               timeout = wait_event_interruptible_timeout
+                         ( cam->wait_frame,
+                           (!list_empty(&cam->outqueue)) ||
+                           (cam->state & DEV_DISCONNECTED) ||
+                           (cam->state & DEV_MISCONFIGURED),
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
+               if (timeout < 0)
+                       return timeout;
+               if (cam->state & DEV_DISCONNECTED)
+                       return -ENODEV;
+               if (!timeout || (cam->state & DEV_MISCONFIGURED))
+                       return -EIO;
+       }
+
+       spin_lock_irqsave(&cam->queue_lock, lock_flags);
+       f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
+       list_del(cam->outqueue.next);
+       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
+
+       f->state = F_UNUSED;
+
+       memcpy(&b, &f->buf, sizeof(b));
+       if (f->vma_use_count)
+               b.flags |= V4L2_BUF_FLAG_MAPPED;
+
+       if (copy_to_user(arg, &b, sizeof(b)))
+               return -EFAULT;
+
+       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
+{
+       int type;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (list_empty(&cam->inqueue))
+               return -EINVAL;
+
+       cam->stream = STREAM_ON;
+
+       DBG(3, "Stream on");
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
+{
+       int type, err;
+
+       if (copy_from_user(&type, arg, sizeof(type)))
+               return -EFAULT;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
+               return -EINVAL;
+
+       if (cam->stream == STREAM_ON)
+               if ((err = zc0301_stream_interrupt(cam)))
+                       return err;
+
+       zc0301_empty_framequeues(cam);
+
+       DBG(3, "Stream off");
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+       sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       return 0;
+}
+
+
+static int
+zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
+{
+       struct v4l2_streamparm sp;
+
+       if (copy_from_user(&sp, arg, sizeof(sp)))
+               return -EFAULT;
+
+       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       sp.parm.capture.extendedmode = 0;
+
+       if (sp.parm.capture.readbuffers == 0)
+               sp.parm.capture.readbuffers = cam->nreadbuffers;
+
+       if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
+               sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
+
+       if (copy_to_user(arg, &sp, sizeof(sp)))
+               return -EFAULT;
+
+       cam->nreadbuffers = sp.parm.capture.readbuffers;
+
+       return 0;
+}
+
+
+static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
+                             unsigned int cmd, void __user * arg)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+
+       switch (cmd) {
+
+       case VIDIOC_QUERYCAP:
+               return zc0301_vidioc_querycap(cam, arg);
+
+       case VIDIOC_ENUMINPUT:
+               return zc0301_vidioc_enuminput(cam, arg);
+
+       case VIDIOC_G_INPUT:
+               return zc0301_vidioc_g_input(cam, arg);
+
+       case VIDIOC_S_INPUT:
+               return zc0301_vidioc_s_input(cam, arg);
+
+       case VIDIOC_QUERYCTRL:
+               return zc0301_vidioc_query_ctrl(cam, arg);
+
+       case VIDIOC_G_CTRL:
+               return zc0301_vidioc_g_ctrl(cam, arg);
+
+       case VIDIOC_S_CTRL_OLD:
+       case VIDIOC_S_CTRL:
+               return zc0301_vidioc_s_ctrl(cam, arg);
+
+       case VIDIOC_CROPCAP_OLD:
+       case VIDIOC_CROPCAP:
+               return zc0301_vidioc_cropcap(cam, arg);
+
+       case VIDIOC_G_CROP:
+               return zc0301_vidioc_g_crop(cam, arg);
+
+       case VIDIOC_S_CROP:
+               return zc0301_vidioc_s_crop(cam, arg);
+
+       case VIDIOC_ENUM_FMT:
+               return zc0301_vidioc_enum_fmt(cam, arg);
+
+       case VIDIOC_G_FMT:
+               return zc0301_vidioc_g_fmt(cam, arg);
+
+       case VIDIOC_TRY_FMT:
+       case VIDIOC_S_FMT:
+               return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
+
+       case VIDIOC_G_JPEGCOMP:
+               return zc0301_vidioc_g_jpegcomp(cam, arg);
+
+       case VIDIOC_S_JPEGCOMP:
+               return zc0301_vidioc_s_jpegcomp(cam, arg);
+
+       case VIDIOC_REQBUFS:
+               return zc0301_vidioc_reqbufs(cam, arg);
+
+       case VIDIOC_QUERYBUF:
+               return zc0301_vidioc_querybuf(cam, arg);
+
+       case VIDIOC_QBUF:
+               return zc0301_vidioc_qbuf(cam, arg);
+
+       case VIDIOC_DQBUF:
+               return zc0301_vidioc_dqbuf(cam, filp, arg);
+
+       case VIDIOC_STREAMON:
+               return zc0301_vidioc_streamon(cam, arg);
+
+       case VIDIOC_STREAMOFF:
+               return zc0301_vidioc_streamoff(cam, arg);
+
+       case VIDIOC_G_PARM:
+               return zc0301_vidioc_g_parm(cam, arg);
+
+       case VIDIOC_S_PARM_OLD:
+       case VIDIOC_S_PARM:
+               return zc0301_vidioc_s_parm(cam, arg);
+
+       case VIDIOC_G_STD:
+       case VIDIOC_S_STD:
+       case VIDIOC_QUERYSTD:
+       case VIDIOC_ENUMSTD:
+       case VIDIOC_QUERYMENU:
+               return -EINVAL;
+
+       default:
+               return -EINVAL;
+
+       }
+}
+
+
+static int zc0301_ioctl(struct inode* inode, struct file* filp,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+       int err = 0;
+
+       if (mutex_lock_interruptible(&cam->fileop_mutex))
+               return -ERESTARTSYS;
+
+       if (cam->state & DEV_DISCONNECTED) {
+               DBG(1, "Device not present");
+               mutex_unlock(&cam->fileop_mutex);
+               return -ENODEV;
+       }
+
+       if (cam->state & DEV_MISCONFIGURED) {
+               DBG(1, "The camera is misconfigured. Close and open it "
+                      "again.");
+               mutex_unlock(&cam->fileop_mutex);
+               return -EIO;
+       }
+
+       V4LDBG(3, "zc0301", cmd);
+
+       err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
+
+       mutex_unlock(&cam->fileop_mutex);
+
+       return err;
+}
+
+
+static struct file_operations zc0301_fops = {
+       .owner =   THIS_MODULE,
+       .open =    zc0301_open,
+       .release = zc0301_release,
+       .ioctl =   zc0301_ioctl,
+       .read =    zc0301_read,
+       .poll =    zc0301_poll,
+       .mmap =    zc0301_mmap,
+       .llseek =  no_llseek,
+};
+
+/*****************************************************************************/
+
+static int
+zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct zc0301_device* cam;
+       static unsigned int dev_nr = 0;
+       unsigned int i;
+       int err = 0;
+
+       if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
+               return -ENOMEM;
+
+       cam->usbdev = udev;
+
+       if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
+               DBG(1, "kmalloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       if (!(cam->v4ldev = video_device_alloc())) {
+               DBG(1, "video_device_alloc() failed");
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       mutex_init(&cam->dev_mutex);
+
+       DBG(2, "ZC0301 Image Processor and Control Chip detected "
+              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
+
+       for  (i = 0; zc0301_sensor_table[i]; i++) {
+               err = zc0301_sensor_table[i](cam);
+               if (!err)
+                       break;
+       }
+
+       if (!err)
+               DBG(2, "%s image sensor detected", cam->sensor.name);
+       else {
+               DBG(1, "No supported image sensor detected");
+               err = -ENODEV;
+               goto fail;
+       }
+
+       if (zc0301_init(cam)) {
+               DBG(1, "Initialization failed. I will retry on open().");
+               cam->state |= DEV_MISCONFIGURED;
+       }
+
+       strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+       cam->v4ldev->owner = THIS_MODULE;
+       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
+       cam->v4ldev->hardware = 0;
+       cam->v4ldev->fops = &zc0301_fops;
+       cam->v4ldev->minor = video_nr[dev_nr];
+       cam->v4ldev->release = video_device_release;
+       video_set_drvdata(cam->v4ldev, cam);
+
+       mutex_lock(&cam->dev_mutex);
+
+       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
+                                   video_nr[dev_nr]);
+       if (err) {
+               DBG(1, "V4L2 device registration failed");
+               if (err == -ENFILE && video_nr[dev_nr] == -1)
+                       DBG(1, "Free /dev/videoX node not found");
+               video_nr[dev_nr] = -1;
+               dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+               mutex_unlock(&cam->dev_mutex);
+               goto fail;
+       }
+
+       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
+
+       cam->module_param.force_munmap = force_munmap[dev_nr];
+       cam->module_param.frame_timeout = frame_timeout[dev_nr];
+
+       dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
+
+       usb_set_intfdata(intf, cam);
+
+       mutex_unlock(&cam->dev_mutex);
+
+       return 0;
+
+fail:
+       if (cam) {
+               kfree(cam->control_buffer);
+               if (cam->v4ldev)
+                       video_device_release(cam->v4ldev);
+               kfree(cam);
+       }
+       return err;
+}
+
+
+static void zc0301_usb_disconnect(struct usb_interface* intf)
+{
+       struct zc0301_device* cam = usb_get_intfdata(intf);
+
+       if (!cam)
+               return;
+
+       down_write(&zc0301_disconnect);
+
+       mutex_lock(&cam->dev_mutex);
+
+       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
+
+       wake_up_interruptible_all(&cam->open);
+
+       if (cam->users) {
+               DBG(2, "Device /dev/video%d is open! Deregistration and "
+                      "memory deallocation are deferred on close.",
+                   cam->v4ldev->minor);
+               cam->state |= DEV_MISCONFIGURED;
+               zc0301_stop_transfer(cam);
+               cam->state |= DEV_DISCONNECTED;
+               wake_up_interruptible(&cam->wait_frame);
+               wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
+       } else {
+               cam->state |= DEV_DISCONNECTED;
+               zc0301_release_resources(cam);
+       }
+
+       mutex_unlock(&cam->dev_mutex);
+
+       if (!cam->users)
+               kfree(cam);
+
+       up_write(&zc0301_disconnect);
+}
+
+
+static struct usb_driver zc0301_usb_driver = {
+       .name =       "zc0301",
+       .id_table =   zc0301_id_table,
+       .probe =      zc0301_usb_probe,
+       .disconnect = zc0301_usb_disconnect,
+};
+
+/*****************************************************************************/
+
+static int __init zc0301_module_init(void)
+{
+       int err = 0;
+
+       KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
+       KDBG(3, ZC0301_MODULE_AUTHOR);
+
+       if ((err = usb_register(&zc0301_usb_driver)))
+               KDBG(1, "usb_register() failed");
+
+       return err;
+}
+
+
+static void __exit zc0301_module_exit(void)
+{
+       usb_deregister(&zc0301_usb_driver);
+}
+
+
+module_init(zc0301_module_init);
+module_exit(zc0301_module_exit);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
new file mode 100644 (file)
index 0000000..9d282a2
--- /dev/null
@@ -0,0 +1,361 @@
+/***************************************************************************
+ * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
+ * Processor and Control Chip                                              *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+/*
+   NOTE: Sensor controls are disabled for now, becouse changing them while
+         streaming sometimes results in out-of-sync video frames. We'll use
+         the default initialization, until we know how to stop and start video
+         in the chip. However, the image quality still looks good under various
+         light conditions.
+*/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pas202bcb;
+
+
+static int pas202bcb_init(struct zc0301_device* cam)
+{
+       int err = 0;
+
+       err += zc0301_write_reg(cam, 0x0002, 0x00);
+       err += zc0301_write_reg(cam, 0x0003, 0x02);
+       err += zc0301_write_reg(cam, 0x0004, 0x80);
+       err += zc0301_write_reg(cam, 0x0005, 0x01);
+       err += zc0301_write_reg(cam, 0x0006, 0xE0);
+       err += zc0301_write_reg(cam, 0x0098, 0x00);
+       err += zc0301_write_reg(cam, 0x009A, 0x03);
+       err += zc0301_write_reg(cam, 0x011A, 0x00);
+       err += zc0301_write_reg(cam, 0x011C, 0x03);
+       err += zc0301_write_reg(cam, 0x009B, 0x01);
+       err += zc0301_write_reg(cam, 0x009C, 0xE6);
+       err += zc0301_write_reg(cam, 0x009D, 0x02);
+       err += zc0301_write_reg(cam, 0x009E, 0x86);
+
+       err += zc0301_i2c_write(cam, 0x02, 0x02);
+       err += zc0301_i2c_write(cam, 0x0A, 0x01);
+       err += zc0301_i2c_write(cam, 0x0B, 0x01);
+       err += zc0301_i2c_write(cam, 0x0D, 0x00);
+       err += zc0301_i2c_write(cam, 0x12, 0x05);
+       err += zc0301_i2c_write(cam, 0x13, 0x63);
+       err += zc0301_i2c_write(cam, 0x15, 0x70);
+
+       err += zc0301_write_reg(cam, 0x0101, 0xB7);
+       err += zc0301_write_reg(cam, 0x0100, 0x0D);
+       err += zc0301_write_reg(cam, 0x0189, 0x06);
+       err += zc0301_write_reg(cam, 0x01AD, 0x00);
+       err += zc0301_write_reg(cam, 0x01C5, 0x03);
+       err += zc0301_write_reg(cam, 0x01CB, 0x13);
+       err += zc0301_write_reg(cam, 0x0250, 0x08);
+       err += zc0301_write_reg(cam, 0x0301, 0x08);
+       err += zc0301_write_reg(cam, 0x018D, 0x70);
+       err += zc0301_write_reg(cam, 0x0008, 0x03);
+       err += zc0301_write_reg(cam, 0x01C6, 0x04);
+       err += zc0301_write_reg(cam, 0x01CB, 0x07);
+       err += zc0301_write_reg(cam, 0x0120, 0x11);
+       err += zc0301_write_reg(cam, 0x0121, 0x37);
+       err += zc0301_write_reg(cam, 0x0122, 0x58);
+       err += zc0301_write_reg(cam, 0x0123, 0x79);
+       err += zc0301_write_reg(cam, 0x0124, 0x91);
+       err += zc0301_write_reg(cam, 0x0125, 0xA6);
+       err += zc0301_write_reg(cam, 0x0126, 0xB8);
+       err += zc0301_write_reg(cam, 0x0127, 0xC7);
+       err += zc0301_write_reg(cam, 0x0128, 0xD3);
+       err += zc0301_write_reg(cam, 0x0129, 0xDE);
+       err += zc0301_write_reg(cam, 0x012A, 0xE6);
+       err += zc0301_write_reg(cam, 0x012B, 0xED);
+       err += zc0301_write_reg(cam, 0x012C, 0xF3);
+       err += zc0301_write_reg(cam, 0x012D, 0xF8);
+       err += zc0301_write_reg(cam, 0x012E, 0xFB);
+       err += zc0301_write_reg(cam, 0x012F, 0xFF);
+       err += zc0301_write_reg(cam, 0x0130, 0x26);
+       err += zc0301_write_reg(cam, 0x0131, 0x23);
+       err += zc0301_write_reg(cam, 0x0132, 0x20);
+       err += zc0301_write_reg(cam, 0x0133, 0x1C);
+       err += zc0301_write_reg(cam, 0x0134, 0x16);
+       err += zc0301_write_reg(cam, 0x0135, 0x13);
+       err += zc0301_write_reg(cam, 0x0136, 0x10);
+       err += zc0301_write_reg(cam, 0x0137, 0x0D);
+       err += zc0301_write_reg(cam, 0x0138, 0x0B);
+       err += zc0301_write_reg(cam, 0x0139, 0x09);
+       err += zc0301_write_reg(cam, 0x013A, 0x07);
+       err += zc0301_write_reg(cam, 0x013B, 0x06);
+       err += zc0301_write_reg(cam, 0x013C, 0x05);
+       err += zc0301_write_reg(cam, 0x013D, 0x04);
+       err += zc0301_write_reg(cam, 0x013E, 0x03);
+       err += zc0301_write_reg(cam, 0x013F, 0x02);
+       err += zc0301_write_reg(cam, 0x010A, 0x4C);
+       err += zc0301_write_reg(cam, 0x010B, 0xF5);
+       err += zc0301_write_reg(cam, 0x010C, 0xFF);
+       err += zc0301_write_reg(cam, 0x010D, 0xF9);
+       err += zc0301_write_reg(cam, 0x010E, 0x51);
+       err += zc0301_write_reg(cam, 0x010F, 0xF5);
+       err += zc0301_write_reg(cam, 0x0110, 0xFB);
+       err += zc0301_write_reg(cam, 0x0111, 0xED);
+       err += zc0301_write_reg(cam, 0x0112, 0x5F);
+       err += zc0301_write_reg(cam, 0x0180, 0x00);
+       err += zc0301_write_reg(cam, 0x0019, 0x00);
+       err += zc0301_write_reg(cam, 0x0087, 0x20);
+       err += zc0301_write_reg(cam, 0x0088, 0x21);
+
+       err += zc0301_i2c_write(cam, 0x20, 0x02);
+       err += zc0301_i2c_write(cam, 0x21, 0x1B);
+       err += zc0301_i2c_write(cam, 0x03, 0x44);
+       err += zc0301_i2c_write(cam, 0x0E, 0x01);
+       err += zc0301_i2c_write(cam, 0x0F, 0x00);
+
+       err += zc0301_write_reg(cam, 0x01A9, 0x14);
+       err += zc0301_write_reg(cam, 0x01AA, 0x24);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0191, 0x02);
+       err += zc0301_write_reg(cam, 0x0192, 0x1B);
+       err += zc0301_write_reg(cam, 0x0195, 0x00);
+       err += zc0301_write_reg(cam, 0x0196, 0x00);
+       err += zc0301_write_reg(cam, 0x0197, 0x4D);
+       err += zc0301_write_reg(cam, 0x018C, 0x10);
+       err += zc0301_write_reg(cam, 0x018F, 0x20);
+       err += zc0301_write_reg(cam, 0x001D, 0x44);
+       err += zc0301_write_reg(cam, 0x001E, 0x6F);
+       err += zc0301_write_reg(cam, 0x001F, 0xAD);
+       err += zc0301_write_reg(cam, 0x0020, 0xEB);
+       err += zc0301_write_reg(cam, 0x0087, 0x0F);
+       err += zc0301_write_reg(cam, 0x0088, 0x0E);
+       err += zc0301_write_reg(cam, 0x0180, 0x40);
+       err += zc0301_write_reg(cam, 0x0192, 0x1B);
+       err += zc0301_write_reg(cam, 0x0191, 0x02);
+       err += zc0301_write_reg(cam, 0x0190, 0x00);
+       err += zc0301_write_reg(cam, 0x0116, 0x1D);
+       err += zc0301_write_reg(cam, 0x0117, 0x40);
+       err += zc0301_write_reg(cam, 0x0118, 0x99);
+       err += zc0301_write_reg(cam, 0x0180, 0x42);
+       err += zc0301_write_reg(cam, 0x0116, 0x1D);
+       err += zc0301_write_reg(cam, 0x0117, 0x40);
+       err += zc0301_write_reg(cam, 0x0118, 0x99);
+       err += zc0301_write_reg(cam, 0x0007, 0x00);
+
+       err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+       msleep(100);
+
+       return err;
+}
+
+
+static int pas202bcb_get_ctrl(struct zc0301_device* cam,
+                              struct v4l2_control* ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               {
+                       int r1 = zc0301_i2c_read(cam, 0x04, 1),
+                           r2 = zc0301_i2c_read(cam, 0x05, 1);
+                       if (r1 < 0 || r2 < 0)
+                               return -EIO;
+                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
+               }
+               return 0;
+       case V4L2_CID_RED_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_BLUE_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case V4L2_CID_GAIN:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x1f;
+               return 0;
+       case ZC0301_V4L2_CID_GREEN_BALANCE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
+                       return -EIO;
+               ctrl->value &= 0x0f;
+               return 0;
+       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+               if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
+                       return -EIO;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+
+static int pas202bcb_set_ctrl(struct zc0301_device* cam,
+                              const struct v4l2_control* ctrl)
+{
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE:
+               err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
+               err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               err += zc0301_i2c_write(cam, 0x09, ctrl->value);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               err += zc0301_i2c_write(cam, 0x07, ctrl->value);
+               break;
+       case V4L2_CID_GAIN:
+               err += zc0301_i2c_write(cam, 0x10, ctrl->value);
+               break;
+       case ZC0301_V4L2_CID_GREEN_BALANCE:
+               err += zc0301_i2c_write(cam, 0x08, ctrl->value);
+               break;
+       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
+               err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
+               break;
+       default:
+               return -EINVAL;
+       }
+       err += zc0301_i2c_write(cam, 0x11, 0x01);
+
+       return err ? -EIO : 0;
+}
+
+
+static struct zc0301_sensor pas202bcb = {
+       .name = "PAS202BCB",
+       .init = &pas202bcb_init,
+       .qctrl = {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "exposure",
+                       .minimum = 0x01e5,
+                       .maximum = 0x3fff,
+                       .step = 0x0001,
+                       .default_value = 0x01e5,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "global gain",
+                       .minimum = 0x00,
+                       .maximum = 0x1f,
+                       .step = 0x01,
+                       .default_value = 0x0c,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "red balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x01,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "blue balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x05,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_GREEN_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "green balance",
+                       .minimum = 0x00,
+                       .maximum = 0x0f,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+       },
+       .get_ctrl = &pas202bcb_get_ctrl,
+       .set_ctrl = &pas202bcb_set_ctrl,
+       .cropcap = {
+               .bounds = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+               .defrect = {
+                       .left = 0,
+                       .top = 0,
+                       .width = 640,
+                       .height = 480,
+               },
+       },
+       .pix_format = {
+               .width = 640,
+               .height = 480,
+               .pixelformat = V4L2_PIX_FMT_JPEG,
+               .priv = 8,
+       },
+};
+
+
+int zc0301_probe_pas202bcb(struct zc0301_device* cam)
+{
+       int r0 = 0, r1 = 0, err = 0;
+       unsigned int pid = 0;
+
+       err += zc0301_write_reg(cam, 0x0000, 0x01);
+       err += zc0301_write_reg(cam, 0x0010, 0x0e);
+       err += zc0301_write_reg(cam, 0x0001, 0x01);
+       err += zc0301_write_reg(cam, 0x0012, 0x03);
+       err += zc0301_write_reg(cam, 0x0012, 0x01);
+       err += zc0301_write_reg(cam, 0x008d, 0x08);
+
+       msleep(10);
+
+       r0 = zc0301_i2c_read(cam, 0x00, 1);
+       r1 = zc0301_i2c_read(cam, 0x01, 1);
+
+       if (r0 < 0 || r1 < 0 || err)
+               return -EIO;
+
+       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
+       if (pid != 0x017)
+               return -ENODEV;
+
+       zc0301_attach_sensor(cam, &pas202bcb);
+
+       return 0;
+}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
new file mode 100644 (file)
index 0000000..cf0965a
--- /dev/null
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * API for image sensors connected to the ZC030! Image Processor and       *
+ * Control Chip                                                            *
+ *                                                                         *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
+ *                                                                         *
+ * This program is free software; you can redistribute it and/or modify    *
+ * it under the terms of the GNU General Public License as published by    *
+ * the Free Software Foundation; either version 2 of the License, or       *
+ * (at your option) any later version.                                     *
+ *                                                                         *
+ * This program is distributed in the hope that it will be useful,         *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
+ * GNU General Public License for more details.                            *
+ *                                                                         *
+ * You should have received a copy of the GNU General Public License       *
+ * along with this program; if not, write to the Free Software             *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
+ ***************************************************************************/
+
+#ifndef _ZC0301_SENSOR_H_
+#define _ZC0301_SENSOR_H_
+
+#include <linux/usb.h>
+#include <linux/videodev.h>
+#include <linux/device.h>
+#include <linux/stddef.h>
+#include <linux/errno.h>
+#include <asm/types.h>
+
+struct zc0301_device;
+struct zc0301_sensor;
+
+/*****************************************************************************/
+
+extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+
+#define ZC0301_SENSOR_TABLE                                                   \
+/* Weak detections must go at the end of the list */                          \
+static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
+       &zc0301_probe_pas202bcb,                                              \
+       NULL,                                                                 \
+};
+
+extern struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
+
+extern void
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
+
+#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
+                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
+       .idVendor = (vend),                                                   \
+       .idProduct = (prod),                                                  \
+       .bInterfaceClass = (intclass)
+
+#define ZC0301_ID_TABLE                                                       \
+static const struct usb_device_id zc0301_id_table[] =  {                      \
+       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
+       { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+       { }                                                                   \
+};
+
+/*****************************************************************************/
+
+extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
+extern int zc0301_read_reg(struct zc0301_device*, u16 index);
+extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
+extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
+
+/*****************************************************************************/
+
+#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
+#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
+
+struct zc0301_sensor {
+       char name[32];
+
+       struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
+       struct v4l2_cropcap cropcap;
+       struct v4l2_pix_format pix_format;
+
+       int (*init)(struct zc0301_device*);
+       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct zc0301_device*,
+                       const struct v4l2_control* ctrl);
+       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
+
+       /* Private */
+       struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
+       struct v4l2_rect _rect;
+};
+
+#endif /* _ZC0301_SENSOR_H_ */
index b1222cd4aa46b1388e455aef5690f9b8c2827c65..7fdbc5dad5fd9d364a62fa95793c93b8a73734cf 100644 (file)
@@ -87,8 +87,6 @@ source "drivers/usb/input/Kconfig"
 
 source "drivers/usb/image/Kconfig"
 
-source "drivers/usb/media/Kconfig"
-
 source "drivers/usb/net/Kconfig"
 
 source "drivers/usb/mon/Kconfig"
index bb36a1c1dbb312851327be304eced6856d13a112..9b7d9769fdcc7179d8e95786b11f0a6f27d40ab4 100644 (file)
@@ -35,20 +35,6 @@ obj-$(CONFIG_USB_WACOM)              += input/
 obj-$(CONFIG_USB_ACECAD)       += input/
 obj-$(CONFIG_USB_XPAD)         += input/
 
-obj-$(CONFIG_USB_DABUSB)       += media/
-obj-$(CONFIG_USB_DSBR)         += media/
-obj-$(CONFIG_USB_ET61X251)     += media/
-obj-$(CONFIG_USB_IBMCAM)       += media/
-obj-$(CONFIG_USB_KONICAWC)     += media/
-obj-$(CONFIG_USB_OV511)                += media/
-obj-$(CONFIG_USB_PWC)          += media/
-obj-$(CONFIG_USB_SE401)                += media/
-obj-$(CONFIG_USB_SN9C102)      += media/
-obj-$(CONFIG_USB_STV680)       += media/
-obj-$(CONFIG_USB_VICAM)                += media/
-obj-$(CONFIG_USB_W9968CF)      += media/
-obj-$(CONFIG_USB_ZC0301)       += media/
-
 obj-$(CONFIG_USB_CATC)         += net/
 obj-$(CONFIG_USB_KAWETH)       += net/
 obj-$(CONFIG_USB_PEGASUS)      += net/
diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig
deleted file mode 100644 (file)
index 189d40f..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-#
-# USB Multimedia device configuration
-#
-comment "USB Multimedia devices"
-       depends on USB
-
-config USB_DABUSB
-       tristate "DABUSB driver"
-       depends on USB
-       ---help---
-         A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
-         brought to you by the DAB-Team
-         <http://wwwbode.cs.tum.edu/Par/arch/dab/>.  This driver can be taken
-         as an example for URB-based bulk, control, and isochronous
-         transactions. URB's are explained in
-         <file:Documentation/usb/URB.txt>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dabusb.
-
-comment "Video4Linux support is needed for USB Multimedia device support"
-       depends on USB && VIDEO_DEV=n
-
-config USB_VICAM
-       tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
-       depends on USB && VIDEO_DEV && EXPERIMENTAL
-       ---help---
-         Say Y here if you have 3com homeconnect camera (vicam).
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Multimedia Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vicam.
-
-config USB_DSBR
-       tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-       depends on USB && VIDEO_DEV && EXPERIMENTAL
-       ---help---
-         Say Y here if you want to connect this type of radio to your
-         computer's USB port. Note that the audio is not digital, and
-         you must connect the line out connector to a sound card or a
-         set of speakers.
-
-         This driver uses the Video For Linux API.  You must enable
-         (Y or M in config) Video For Linux (under Character Devices)
-         to use this driver.  Information on this API and pointers to
-         "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called dsbr100.
-
-config USB_ET61X251
-       tristate "USB ET61X[12]51 PC Camera Controller support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for cameras based on Etoms ET61X151
-         or ET61X251 PC Camera Controllers.
-
-         See <file:Documentation/usb/et61x251.txt> for more informations.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called et61x251.
-
-config USB_IBMCAM
-       tristate "USB IBM (Xirlink) C-it Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect a IBM "C-It" camera, also known as
-         "Xirlink PC Camera" to your computer's USB port.  For more
-         information, read <file:Documentation/usb/ibmcam.txt>.
-
-         This driver uses the Video For Linux API.  You must enable
-         (Y or M in config) Video For Linux (under Character Devices)
-         to use this driver.  Information on this API and pointers to
-         "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ibmcam.
-
-         This camera has several configuration options which
-         can be specified when you load the module. Read
-         <file:Documentation/usb/ibmcam.txt> to learn more.
-
-config USB_KONICAWC
-       tristate "USB Konica Webcam support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for webcams based on a Konica
-         chipset. This is known to work with the Intel YC76 webcam.
-
-         This driver uses the Video For Linux API.  You must enable
-         (Y or M in config) Video For Linux (under Character Devices)
-         to use this driver.  Information on this API and pointers to
-         "v4l" programs may be found at
-         <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called konicawc.
-
-config USB_OV511
-       tristate "USB OV511 Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. See <file:Documentation/usb/ov511.txt> for more
-         information and for a list of supported cameras.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Character Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ov511.
-
-config USB_SE401
-       tristate "USB SE401 Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. See <file:Documentation/usb/se401.txt> for more
-         information and for a list of supported cameras.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Multimedia Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called se401.
-
-config USB_SN9C102
-       tristate "USB SN9C10x PC Camera Controller support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for cameras based on SONiX SN9C101,
-         SN9C102 or SN9C103 PC Camera Controllers.
-
-         See <file:Documentation/usb/sn9c102.txt> for more informations.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called sn9c102.
-
-config USB_STV680
-       tristate "USB STV680 (Pencam) Camera support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want to connect this type of camera to your
-         computer's USB port. This includes the Pencam line of cameras.
-         See <file:Documentation/usb/stv680.txt> for more information and for
-         a list of supported cameras.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Multimedia Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called stv680.
-
-config USB_W9968CF
-       tristate "USB W996[87]CF JPEG Dual Mode Camera support"
-       depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP
-       ---help---
-         Say Y here if you want support for cameras based on OV681 or
-         Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-       
-         This driver has an optional plugin, which is distributed as a
-         separate module only (released under GPL). It allows to use higher 
-         resolutions and framerates, but cannot be included in the official 
-         Linux kernel for performance purposes.
-
-         See <file:Documentation/usb/w9968cf.txt> for more informations.
-
-         This driver uses the Video For Linux and the I2C APIs. It needs the
-         OmniVision Camera Chip support as well. You must say Y or M to
-         "Video For Linux", "I2C Support" and "OmniVision Camera Chip 
-         support" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called w9968cf.
-
-config USB_ZC0301
-       tristate "USB ZC0301 Image Processor and Control Chip support"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y here if you want support for cameras based on the ZC0301
-         Image Processor and Control Chip.
-
-         See <file:Documentation/usb/zc0301.txt> for more informations.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" to use this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called zc0301.
-
-config USB_PWC
-       tristate "USB Philips Cameras"
-       depends on USB && VIDEO_DEV
-       ---help---
-         Say Y or M here if you want to use one of these Philips & OEM
-          webcams:
-           * Philips PCA645, PCA646
-           * Philips PCVC675, PCVC680, PCVC690
-           * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
-          * Askey VC010
-          * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' 
-             and 'Orbit'/'Sphere'
-           * Samsung MPC-C10, MPC-C30
-          * Creative Webcam 5, Pro Ex
-          * SOTEC Afina Eye
-          * Visionite VCS-UC300, VCS-UM100
-          
-         The PCA635, PCVC665 and PCVC720/20 are not supported by this driver
-         and never will be, but the 665 and 720/20 are supported by other 
-         drivers.
-
-         See <file:Documentation/usb/philips.txt> for more information and
-         installation instructions.
-
-         The built-in microphone is enabled by selecting USB Audio support.
-
-         This driver uses the Video For Linux API. You must say Y or M to
-         "Video For Linux" (under Character Devices) to use this driver.
-         Information on this API and pointers to "v4l" programs may be found
-         at <file:Documentation/video4linux/API.html>.
-
-         To compile this driver as a module, choose M here: the
-         module will be called pwc.
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
deleted file mode 100644 (file)
index 50e89a3..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# Makefile for USB Media drivers
-#
-
-sn9c102-objs   := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
-                  sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
-                  sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
-                  sn9c102_tas5130d1b.o
-et61x251-objs  := et61x251_core.o et61x251_tas5130d1b.o
-zc0301-objs    := zc0301_core.o zc0301_pas202bcb.o
-
-obj-$(CONFIG_USB_DABUSB)       += dabusb.o
-obj-$(CONFIG_USB_DSBR)         += dsbr100.o
-obj-$(CONFIG_USB_ET61X251)     += et61x251.o
-obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o usbvideo.o ultracam.o
-obj-$(CONFIG_USB_KONICAWC)     += konicawc.o usbvideo.o
-obj-$(CONFIG_USB_OV511)                += ov511.o
-obj-$(CONFIG_USB_SE401)                += se401.o
-obj-$(CONFIG_USB_SN9C102)      += sn9c102.o
-obj-$(CONFIG_USB_STV680)       += stv680.o
-obj-$(CONFIG_USB_VICAM)                += vicam.o usbvideo.o
-obj-$(CONFIG_USB_W9968CF)      += w9968cf.o
-obj-$(CONFIG_USB_ZC0301)       += zc0301.o
-obj-$(CONFIG_USB_PWC)           += pwc/
diff --git a/drivers/usb/media/dabfirmware.h b/drivers/usb/media/dabfirmware.h
deleted file mode 100644 (file)
index d14d803..0000000
+++ /dev/null
@@ -1,1408 +0,0 @@
-/*
- * dabdata.h - dab usb firmware and bitstream data
- */
-
-static INTEL_HEX_RECORD firmware[] = {
-
-{  2, 0x0000, 0, {0x21,0x57} },
-{  3, 0x0003, 0, {0x02,0x01,0x66} },
-{  3, 0x000b, 0, {0x02,0x01,0x66} },
-{  3, 0x0013, 0, {0x02,0x01,0x66} },
-{  3, 0x001b, 0, {0x02,0x01,0x66} },
-{  3, 0x0023, 0, {0x02,0x01,0x66} },
-{  3, 0x002b, 0, {0x02,0x01,0x66} },
-{  3, 0x0033, 0, {0x02,0x03,0x0f} },
-{  3, 0x003b, 0, {0x02,0x01,0x66} },
-{  3, 0x0043, 0, {0x02,0x01,0x00} },
-{  3, 0x004b, 0, {0x02,0x01,0x66} },
-{  3, 0x0053, 0, {0x02,0x01,0x66} },
-{  3, 0x005b, 0, {0x02,0x04,0xbd} },
-{  3, 0x0063, 0, {0x02,0x01,0x67} },
-{  3, 0x0100, 0, {0x02,0x0c,0x5a} },
-{  3, 0x0104, 0, {0x02,0x01,0xed} },
-{  3, 0x0108, 0, {0x02,0x02,0x51} },
-{  3, 0x010c, 0, {0x02,0x02,0x7c} },
-{  3, 0x0110, 0, {0x02,0x02,0xe4} },
-{  1, 0x0114, 0, {0x32} },
-{  1, 0x0118, 0, {0x32} },
-{  3, 0x011c, 0, {0x02,0x05,0xfd} },
-{  3, 0x0120, 0, {0x02,0x00,0x00} },
-{  3, 0x0124, 0, {0x02,0x00,0x00} },
-{  3, 0x0128, 0, {0x02,0x04,0x3c} },
-{  3, 0x012c, 0, {0x02,0x04,0x6a} },
-{  3, 0x0130, 0, {0x02,0x00,0x00} },
-{  3, 0x0134, 0, {0x02,0x00,0x00} },
-{  3, 0x0138, 0, {0x02,0x00,0x00} },
-{  3, 0x013c, 0, {0x02,0x00,0x00} },
-{  3, 0x0140, 0, {0x02,0x00,0x00} },
-{  3, 0x0144, 0, {0x02,0x00,0x00} },
-{  3, 0x0148, 0, {0x02,0x00,0x00} },
-{  3, 0x014c, 0, {0x02,0x00,0x00} },
-{  3, 0x0150, 0, {0x02,0x00,0x00} },
-{  3, 0x0154, 0, {0x02,0x00,0x00} },
-{ 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} },
-{  5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} },
-{  1, 0x0166, 0, {0x32} },
-{ 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} },
-{ 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} },
-{  3, 0x019f, 0, {0x55,0x7f,0xf0} },
-{ 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
-{ 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} },
-{  3, 0x01da, 0, {0xd0,0xd0,0x32} },
-{  8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} },
-{  7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} },
-{  1, 0x01ec, 0, {0x22} },
-{ 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} },
-{ 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} },
-{ 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} },
-{  9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} },
-{  4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} },
-{ 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} },
-{ 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} },
-{  2, 0x023c, 0, {0x01,0x0b} },
-{  2, 0x023e, 0, {0x80,0xe3} },
-{  2, 0x0240, 0, {0xd0,0x86} },
-{ 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} },
-{  1, 0x0250, 0, {0x32} },
-{ 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
-{  4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} },
-{ 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
-{ 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} },
-{  6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} },
-{  6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
-{ 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} },
-{ 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
-{  4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} },
-{ 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} },
-{  7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} },
-{  6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
-{ 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} },
-{  5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} },
-{ 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
-{ 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} },
-{ 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} },
-{  1, 0x0398, 0, {0xf0} },
-{  1, 0x0399, 0, {0x22} },
-{ 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
-{ 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} },
-{ 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} },
-{ 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} },
-{  1, 0x03ca, 0, {0x22} },
-{ 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} },
-{  9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} },
-{  2, 0x03de, 0, {0x03,0x72} },
-{  1, 0x03e0, 0, {0x22} },
-{ 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} },
-{  9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} },
-{  9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} },
-{  9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} },
-{  8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} },
-{  1, 0x0410, 0,{0x22} },
-{ 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
-{  4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} },
-{ 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} },
-{  7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} },
-{ 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
-{  7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} },
-{ 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} },
-{ 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
-{ 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} },
-{ 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} },
-{  1, 0x04ee, 0, {0x22} },
-{  7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} },
-{  1, 0x04f6, 0, {0x22} },
-{ 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} },
-{ 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} },
-{ 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} },
-{ 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} },
-{  2, 0x052c, 0, {0x7a,0x00} },
-{  7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} },
-{  2, 0x0535, 0, {0x7b,0x00} },
-{ 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} },
-{  7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} },
-{  9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} },
-{  4, 0x0552, 0, {0x70,0x47,0x75,0x71} },
-{  8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} },
-{  5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} },
-{  1, 0x0563, 0, {0x22} },
-{ 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
-{ 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} },
-{ 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} },
-{ 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} },
-{  5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} },
-{  3, 0x05a1, 0, {0x02,0x05,0xf9} },
-{  6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} },
-{ 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} },
-{ 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} },
-{  2, 0x05c6, 0, {0x80,0x31} },
-{ 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} },
-{ 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} },
-{ 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} },
-{  7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} },
-{  3, 0x05f9, 0, {0x75,0x38,0x01} },
-{  1, 0x05fc, 0, {0x22} },
-{ 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
-{ 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} },
-{ 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} },
-{ 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} },
-{ 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} },
-{ 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} },
-{ 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} },
-{ 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} },
-{  3, 0x06a2, 0, {0xbf,0x81,0x0a} },
-{ 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} },
-{  8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} },
-{  3, 0x06b7, 0, {0xba,0x01,0x0c} },
-{ 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
-{ 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} },
-{  8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} },
-{  3, 0x06d9, 0, {0xba,0x01,0x0d} },
-{ 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
-{ 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} },
-{  8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} },
-{  3, 0x06fc, 0, {0xba,0x01,0x0d} },
-{ 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} },
-{ 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} },
-{  5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} },
-{  1, 0x071d, 0, {0x22} },
-{ 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} },
-{ 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
-{  9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
-{  9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
-{  7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} },
-{  3, 0x074d, 0, {0xba,0xff,0x00} },
-{  2, 0x0750, 0, {0x50,0x0a} },
-{ 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
-{ 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} },
-{  8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} },
-{  1, 0x076e, 0, {0x22} },
-{ 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} },
-{ 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} },
-{ 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} },
-{  9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} },
-{  5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} },
-{  7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} },
-{ 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} },
-{  4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} },
-{  9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} },
-{  7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} },
-{ 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} },
-{ 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} },
-{ 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
-{ 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} },
-{ 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} },
-{ 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} },
-{ 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} },
-{ 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} },
-{ 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} },
-{ 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} },
-{ 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} },
-{ 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} },
-{ 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} },
-{  9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} },
-{ 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} },
-{  9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x089d, 0, {0x80,0xe0} },
-{ 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} },
-{ 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} },
-{ 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
-{ 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x08d0, 0, {0x80,0xd9} },
-{ 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} },
-{ 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} },
-{ 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} },
-{ 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} },
-{ 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} },
-{ 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} },
-{ 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} },
-{ 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} },
-{  3, 0x0937, 0, {0x02,0x0a,0x3f} },
-{ 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} },
-{ 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} },
-{ 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
-{ 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} },
-{ 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} },
-{  2, 0x097a, 0, {0x60,0x0c} },
-{ 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} },
-{ 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} },
-{ 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} },
-{  6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} },
-{  3, 0x09a7, 0, {0xba,0xa0,0x00} },
-{  2, 0x09aa, 0, {0x50,0x24} },
-{ 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} },
-{ 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} },
-{  9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
-{  5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} },
-{  6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} },
-{ 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} },
-{ 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} },
-{  6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} },
-{  5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} },
-{  4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} },
-{ 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} },
-{ 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
-{  3, 0x0a1a, 0, {0x05,0xd0,0x04} },
-{  5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} },
-{  4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} },
-{ 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} },
-{ 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
-{  3, 0x0a3c, 0, {0x05,0xd0,0x04} },
-{ 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} },
-{ 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} },
-{ 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} },
-{  8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} },
-{  8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} },
-{ 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} },
-{  5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} },
-{  5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} },
-{  5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} },
-{ 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} },
-{  1, 0x0a9f, 0, {0x00} },
-{  7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} },
-{ 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} },
-{ 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
-{  9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} },
-{  3, 0x0ac8, 0, {0x02,0x0b,0x36} },
-{  5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} },
-{  3, 0x0ad0, 0, {0xbb,0x64,0x00} },
-{  2, 0x0ad3, 0, {0x50,0x1c} },
-{ 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
-{ 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} },
-{  1, 0x0af0, 0, {0xdf} },
-{ 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} },
-{ 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} },
-{ 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} },
-{  9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} },
-{ 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
-{ 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} },
-{  3, 0x0b36, 0, {0xba,0x2a,0x3b} },
-{ 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
-{ 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} },
-{  2, 0x0b54, 0, {0x7b,0x00} },
-{  3, 0x0b56, 0, {0xbb,0x0a,0x00} },
-{  5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} },
-{ 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
-{  8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} },
-{  3, 0x0b74, 0, {0xba,0x2b,0x1a} },
-{  8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} },
-{ 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} },
-{  4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} },
-{  3, 0x0b91, 0, {0xba,0x10,0x1f} },
-{ 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} },
-{ 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
-{  3, 0x0bb0, 0, {0x02,0x0c,0x2d} },
-{  3, 0x0bb3, 0, {0xba,0x11,0x12} },
-{ 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} },
-{  4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} },
-{  3, 0x0bc8, 0, {0xba,0x12,0x12} },
-{ 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} },
-{  4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} },
-{  3, 0x0bdd, 0, {0xba,0x13,0x0b} },
-{ 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} },
-{  3, 0x0beb, 0, {0xba,0x14,0x11} },
-{ 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} },
-{  3, 0x0bfc, 0, {0x02,0x80,0x2e} },
-{  3, 0x0bff, 0, {0xba,0x15,0x1d} },
-{ 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} },
-{ 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} },
-{  3, 0x0c1c, 0, {0x02,0x80,0x0e} },
-{  3, 0x0c1f, 0, {0xba,0x16,0x0b} },
-{ 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} },
-{ 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} },
-{  1, 0x0c38, 0, {0x22} },
-{  7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} },
-{  7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} },
-{  6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} },
-{ 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} },
-{ 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
-{ 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
-{ 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
-{ 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} },
-{  6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} },
-{  3, 0x0c97, 0, {0x02,0x0d,0x38} },
-{  3, 0x0c9a, 0, {0xba,0x80,0x14} },
-{ 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} },
-{  6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} },
-{  5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} },
-{  3, 0x0cb6, 0, {0x02,0x0d,0x1d} },
-{  8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} },
-{  2, 0x0cc1, 0, {0x40,0x21} },
-{  6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} },
-{ 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
-{ 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} },
-{  3, 0x0ce4, 0, {0xbc,0x81,0x00} },
-{  2, 0x0ce7, 0, {0x40,0x21} },
-{  6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} },
-{ 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
-{ 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} },
-{  5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} },
-{ 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} },
-{  5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} },
-{  3, 0x0d22, 0, {0x02,0x0e,0xc5} },
-{ 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} },
-{  5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} },
-{  3, 0x0d38, 0, {0xbb,0x01,0x2d} },
-{  6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
-{  3, 0x0d41, 0, {0xba,0x02,0x11} },
-{ 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
-{  4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} },
-{  5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} },
-{  3, 0x0d5a, 0, {0x02,0x0e,0xcd} },
-{ 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} },
-{  3, 0x0d68, 0, {0xbb,0x03,0x1f} },
-{  6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
-{  5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} },
-{  3, 0x0d76, 0, {0x02,0x0e,0xcd} },
-{ 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
-{  4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} },
-{  3, 0x0d8a, 0, {0xbb,0x06,0x54} },
-{  5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} },
-{  3, 0x0d92, 0, {0x02,0x0e,0xc5} },
-{  8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} },
-{ 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
-{  9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
-{ 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} },
-{  3, 0x0dbc, 0, {0x02,0x0e,0xc5} },
-{ 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} },
-{  3, 0x0dc9, 0, {0x02,0x0e,0xc5} },
-{ 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
-{  9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
-{  6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} },
-{  3, 0x0de7, 0, {0xbb,0x08,0x10} },
-{ 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
-{  3, 0x0df7, 0, {0x02,0x0e,0xcd} },
-{  3, 0x0dfa, 0, {0xbb,0x09,0x31} },
-{  5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} },
-{  3, 0x0e02, 0, {0x02,0x0e,0xc5} },
-{ 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} },
-{  8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} },
-{ 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} },
-{  9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} },
-{  3, 0x0e2e, 0, {0xbb,0x0a,0x27} },
-{  5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} },
-{  3, 0x0e36, 0, {0x02,0x0e,0xc5} },
-{ 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} },
-{ 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
-{  3, 0x0e55, 0, {0x02,0x0e,0xcd} },
-{  5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} },
-{  3, 0x0e5d, 0, {0x02,0x0e,0xa9} },
-{ 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} },
-{  8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} },
-{ 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} },
-{  4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} },
-{  8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} },
-{  8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} },
-{ 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} },
-{  5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} },
-{  5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} },
-{  5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} },
-{  5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} },
-{  5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} },
-{  3, 0x0ebd, 0, {0xbb,0x84,0x05} },
-{  5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} },
-{  8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} },
-{  6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} },
-{  2, 0x0ed3, 0, {0xd0,0x86} },
-{ 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
-{ 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
-{ 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} },
-{  7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} },
-{ 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} },
-{  9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} },
-{  7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} },
-{  7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} },
-{ 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} },
-{  7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} },
-{  1, 0x0f3a, 0, {0x22} },
-{ 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} },
-{ 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} },
-{ 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} },
-{ 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} },
-{ 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} },
-{ 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} },
-{ 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} },
-{ 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} },
-{ 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} },
-{ 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} },
-{ 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} },
-{ 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} },
-{ 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} },
-{ 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} },
-{ 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} },
-{ 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} },
-{  4, 0x1017, 0, {0x00,0x03,0x01,0x00} },
-{  2, 0x101b, 0, {0x7a,0x00} },
-{  3, 0x101d, 0, {0xba,0x05,0x00} },
-{  2, 0x1020, 0, {0x50,0x17} },
-{  8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} },
-{  5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} },
-{ 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} },
-{  3, 0x1039, 0, {0x90,0x00,0x01} },
-{  1, 0x103c, 0, {0x22} },
-{ 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} },
-{  4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} },
-{ 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} },
-{  4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} },
-{  8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} },
-{  1, 0x1069, 0, {0x22} },
-{ 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} },
-{  4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} },
-{ 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} },
-{  4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} },
-{  1, 0x108e, 0, {0x22} },
-{ 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} },
-{ 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} },
-{  5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} },
-{ 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} },
-{  6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} },
-{  6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} },
-{  1, 0x10c9, 0, {0x22} },
-{  8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} },
-{  3, 0x10d2, 0, {0xba,0xff,0x00} },
-{  2, 0x10d5, 0, {0x50,0x0a} },
-{ 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
-{  1, 0x10e1, 0, {0x22} },
-{  5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} },
-{  8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} },
-{  6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} },
-{  4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} },
-{ 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} },
-{  5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x1109, 0, {0x80,0xee} },
-{  1, 0x110b, 0, {0x22} },
-{ 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} },
-{  3, 0x1116, 0, {0xba,0x28,0x00} },
-{  2, 0x1119, 0, {0x50,0x03} },
-{  3, 0x111b, 0, {0x0a,0x80,0xf8} },
-{  5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} },
-{  8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} },
-{  5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} },
-{  9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} },
-{  2, 0x1139, 0, {0x7a,0x00} },
-{  3, 0x113b, 0, {0xba,0x28,0x00} },
-{  2, 0x113e, 0, {0x50,0x03} },
-{  3, 0x1140, 0, {0x0a,0x80,0xf8} },
-{  1, 0x1143, 0, {0x22} },
-{  4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} },
-{  2, 0x1148, 0, {0x80,0x07} },
-{  7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} },
-{  5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} },
-{  9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} },
-{ 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} },
-{  8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} },
-{  3, 0x1171, 0, {0x0a,0x80,0xf5} },
-{  1, 0x1174, 0, {0x22} },
-{  6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} },
-{ 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} },
-{ 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} },
-{  9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
-{  2, 0x119d, 0, {0x80,0xdc} },
-{  1, 0x119f, 0, {0x22} },
-{ 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} },
-{  2, 0x11ad, 0, {0x50,0x06} },
-{  6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
-{  4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} },
-{ 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} },
-{  8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} },
-{  6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
-{  4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} },
-{  5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} },
-{  1, 0x11dc, 0, {0x22} },
-{  7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} },
-{ 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} },
-{  3, 0x11f0, 0, {0x12,0x11,0x44} },
-{ 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} },
-{  5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} },
-{  1, 0x1204, 0, {0x22} },
-{  2, 0x1205, 0, {0x7a,0x04} },
-{  3, 0x1207, 0, {0xba,0x40,0x00} },
-{  2, 0x120a, 0, {0x50,0x36} },
-{ 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} },
-{  3, 0x121a, 0, {0xbc,0x08,0x00} },
-{  2, 0x121d, 0, {0x50,0x20} },
-{  6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} },
-{ 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} },
-{  8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} },
-{  7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} },
-{  3, 0x123f, 0, {0x0a,0x80,0xc5} },
-{  1, 0x1242, 0, {0x22} },
-{  4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} },
-{  3, 0x1247, 0, {0xba,0x10,0x00} },
-{  2, 0x124a, 0, {0x50,0x20} },
-{ 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} },
-{ 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} },
-{  4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} },
-{  1, 0x126c, 0, {0x22} },
-{ 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{ 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
-{  1, 0x12b3, 0, {0x22} },
-{ 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} },
-{ 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} },
-{ 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} },
-{ 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} },
-{ 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} },
-{ 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} },
-{ 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} },
-{ 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} },
-{ 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} },
-{ 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} },
-{ 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} },
-{ 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} },
-{  3, 0x135c, 0, {0xbd,0x06,0x00} },
-{  2, 0x135f, 0, {0x50,0x12} },
-{ 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
-{  7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} },
-{ 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} },
-{ 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} },
-{ 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} },
-{  6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} },
-{  1, 0x13a2, 0, {0x22} },
-{ 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} },
-{ 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} },
-{  3, 0x13be, 0, {0xfa,0x7b,0x00} },
-{  3, 0x13c1, 0, {0xbb,0x10,0x00} },
-{  2, 0x13c4, 0, {0x50,0x24} },
-{ 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} },
-{ 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} },
-{  8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} },
-{ 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} },
-{  5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} },
-{  1, 0x13fd, 0, {0x22} },
-{  4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} },
-{  2, 0x1402, 0, {0x80,0x16} },
-{ 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} },
-{ 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} },
-{ 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} },
-{  6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} },
-{  6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} },
-{ 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} },
-{  1, 0x143b, 0, {0xe4} },
-{  3, 0x143c, 0, {0xfa,0x70,0x0f} },
-{ 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} },
-{  3, 0x144b, 0, {0x02,0x80,0x0a} },
-{ 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} },
-{ 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} },
-{  4, 0x1464, 0, {0x02,0xea,0x70,0x1a} },
-{ 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} },
-{  9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} },
-{  4, 0x147e, 0, {0x11,0x75,0x80,0x36} },
-{  2, 0x1482, 0, {0x7a,0x00} },
-{  3, 0x1484, 0, {0xba,0x10,0x00} },
-{  2, 0x1487, 0, {0x50,0x2f} },
-{ 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} },
-{  4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} },
-{ 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} },
-{  9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} },
-{  4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} },
-{  3, 0x14b5, 0, {0x0a,0x80,0xcc} },
-{  1, 0x14b8, 0, {0x22} },
-{  6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} },
-{ 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} },
-{  7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} },
-{  7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} },
-{  5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} },
-{  4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} },
-{  5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} },
-{  4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} },
-{  1, 0x14ed, 0, {0x22} },
-{ 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} },
-{  6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} },
-{  5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} },
-{  3, 0x1507, 0, {0xe0,0x80,0x07} },
-{  4, 0x150a, 0, {0xe4,0x93,0x80,0x03} },
-{  3, 0x150e, 0, {0xa8,0x82,0xe2} },
-{  4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} },
-{  1, 0x1515, 0, {0x22} },
-{  0, 0x0000, 1, {0} }
-
-};
-
-static unsigned char bitstream[] = {
-
-0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D,
-0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B,
-0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39,
-0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34,
-0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B,
-0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F,
-0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF,
-0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB,
-0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF,
-0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE,
-0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF,
-0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF,
-0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,
-0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF,
-0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD,
-0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB,
-0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,
-0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF,
-0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
-0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D,
-0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
-0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE,
-0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF,
-0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F,
-0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F,
-0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF,
-0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,
-0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F,
-0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F,
-0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2,
-0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF,
-0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF,
-0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE,
-0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF,
-0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF,
-0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B,
-0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF,
-0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7,
-0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF,
-0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF,
-0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5,
-0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD,
-0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF,
-0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF,
-0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B,
-0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF,
-0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED,
-0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF,
-0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB,
-0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF,
-0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE,
-0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7,
-0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE,
-0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF,
-0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD,
-0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD,
-0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF,
-0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD,
-0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A,
-0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF,
-0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF,
-0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA,
-0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF,
-0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD,
-0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF,
-0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,
-0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E,
-0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF,
-0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF,
-0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF,
-0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF,
-0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3,
-0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF,
-0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F,
-0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF,
-0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF,
-0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7,
-0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF,
-0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF,
-0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD,
-0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD,
-0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE,
-0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF,
-0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF,
-0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3,
-0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A,
-0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6,
-0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF,
-0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB,
-0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF,
-0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD,
-0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB,
-0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,
-0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF,
-0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,
-0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F,
-0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
-0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F,
-0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
-0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED,
-0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
-0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF,
-0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7,
-0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7,
-0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF,
-0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F,
-0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE,
-0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
-0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
-0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA,
-0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F,
-0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA,
-0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB,
-0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF,
-0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB,
-0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F,
-0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF,
-0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF,
-0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD,
-0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF,
-0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF,
-0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C,
-0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF,
-0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF,
-0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD,
-0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF,
-0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3,
-0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB,
-0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F,
-0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3,
-0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF,
-0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7,
-0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7,
-0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF,
-0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE,
-0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF,
-0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB,
-0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66,
-0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE,
-0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6,
-0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED,
-0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD,
-0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7,
-0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF,
-0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB,
-0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF,
-0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F,
-0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7,
-0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9,
-0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF,
-0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF,
-0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE,
-0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF,
-0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF,
-0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF,
-0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF,
-0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD,
-0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1,
-0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF,
-0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5,
-0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF,
-0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB,
-0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF,
-0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF,
-0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3,
-0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE,
-0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD,
-0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE,
-0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF,
-0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF,
-0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB,
-0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF,
-0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF,
-0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF,
-0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F,
-0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C,
-0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD,
-0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF,
-0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F,
-0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE,
-0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD,
-0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54,
-0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2,
-0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD,
-0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF,
-0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF,
-0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7,
-0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA,
-0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF,
-0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C,
-0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF,
-0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5,
-0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB,
-0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF,
-0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF,
-0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F,
-0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F,
-0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF,
-0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF,
-0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5,
-0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF,
-0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF,
-0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A,
-0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36,
-0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF,
-0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F,
-0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F,
-0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF,
-0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF,
-0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF,
-0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF,
-0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE,
-0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,
-0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF,
-0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F,
-0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B,
-0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF,
-0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB,
-0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF,
-0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF,
-0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA,
-0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37,
-0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD,
-0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B,
-0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF,
-0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B,
-0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B,
-0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF,
-0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF,
-0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD,
-0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF,
-0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE,
-0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF,
-0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF,
-0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA,
-0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E,
-0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF,
-0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF,
-0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6,
-0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD,
-0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB,
-0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F,
-0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F,
-0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7,
-0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
-0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB,
-0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD,
-0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E,
-0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF,
-0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE,
-0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF,
-0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF,
-0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE,
-0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2,
-0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
-0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF,
-0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF,
-0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF,
-0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC,
-0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF,
-0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7,
-0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7,
-0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3,
-0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9,
-0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF,
-0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,
-0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6,
-0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F,
-0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B,
-0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE,
-0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79,
-0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F,
-0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7,
-0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC,
-0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB,
-0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7,
-0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF,
-0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF,
-0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,
-0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F,
-0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE,
-0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF,
-0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F,
-0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7,
-0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7,
-0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF,
-0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,
-0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD,
-0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF,
-0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB,
-0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE,
-0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3,
-0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF,
-0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF,
-0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE,
-0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6,
-0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF,
-0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF,
-0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F,
-0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE,
-0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6,
-0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77,
-0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF,
-0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A,
-0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F,
-0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F,
-0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF,
-0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB,
-0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F,
-0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67,
-0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF,
-0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D,
-0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3,
-0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D,
-0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB,
-0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE,
-0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5,
-0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,
-0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D,
-0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F,
-0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB,
-0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB,
-0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9,
-0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF,
-0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF,
-0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF,
-0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77,
-0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F,
-0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE,
-0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
-0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF,
-0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD,
-0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F,
-0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A,
-0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA,
-0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF,
-0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF,
-0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF,
-0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF,
-0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF,
-0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF,
-0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9,
-0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F,
-0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7,
-0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4,
-0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE,
-0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9,
-0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF,
-0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7,
-0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF,
-0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF,
-0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF,
-0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5,
-0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF,
-0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD,
-0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77,
-0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE,
-0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF,
-0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF,
-0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC,
-0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB,
-0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F,
-0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6,
-0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD,
-0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF,
-0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC,
-0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,
-0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF,
-0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E,
-0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F,
-0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB,
-0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF,
-0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7,
-0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F,
-0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
-0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2,
-0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA,
-0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF,
-0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8,
-0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB,
-0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF,
-0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB,
-0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF,
-0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF,
-0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7,
-0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3,
-0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F,
-0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD,
-0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF,
-0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
-0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF,
-0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF,
-0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F,
-0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF,
-0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F,
-0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF,
-0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7,
-0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9,
-0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71,
-0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF,
-0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF,
-0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F,
-0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7,
-0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC,
-0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE,
-0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7,
-0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF,
-0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB,
-0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B,
-0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF,
-0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,
-0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF,
-0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE,
-0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17,
-0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9,
-0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F,
-0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE,
-0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,
-0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F,
-0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF,
-0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF,
-0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F,
-0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF,
-0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5,
-0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA,
-0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE,
-0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF,
-0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA,
-0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3,
-0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,
-0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7,
-0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
-0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF,
-0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB,
-0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE,
-0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9,
-0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF,
-0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD,
-0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE,
-0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE,
-0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB,
-0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB,
-0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB,
-0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF,
-0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF,
-0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77,
-0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE,
-0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8,
-0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E,
-0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3,
-0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,
-0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7,
-0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB,
-0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF,
-0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF,
-0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF,
-0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3,
-0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F,
-0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F,
-0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF,
-0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,
-0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF,
-0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF,
-0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD,
-0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE,
-0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1,
-0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF,
-0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC,
-0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF,
-0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB,
-0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9,
-0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E,
-0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF,
-0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,
-0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,
-0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF,
-0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7,
-0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF,
-0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F,
-0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF,
-0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF,
-0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF,
-0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3,
-0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC,
-0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF,
-0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF,
-0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF,
-0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF,
-0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF,
-0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF,
-0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA,
-0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF,
-0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF,
-0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF,
-0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF,
-0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB,
-0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F,
-0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF,
-0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD,
-0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD,
-0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE,
-0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF,
-0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5,
-0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F,
-0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF,
-0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE,
-0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB,
-0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF,
-0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF,
-0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF,
-0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF,
-0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB,
-0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7,
-0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF,
-0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F,
-0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
-0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF,
-0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB,
-0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF,
-0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF,
-0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF,
-0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,
-0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,
-0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF,
-0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE,
-0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
-0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE,
-0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4,
-0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC,
-0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF,
-0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7,
-0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65,
-0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3,
-0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,
-0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,
-0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB,
-0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF,
-0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B,
-0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF,
-0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF,
-0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF,
-0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7,
-0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF,
-0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9,
-0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,
-0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF,
-0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF,
-0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,
-0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A,
-0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7,
-0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF,
-0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD,
-0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC,
-0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA,
-0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D,
-0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF,
-0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6,
-0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
-0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF,
-0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF,
-0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF,
-0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF,
-0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB,
-0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E,
-0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF,
-0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF,
-0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF,
-0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF,
-0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16,
-0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF,
-0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7,
-0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9,
-0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF,
-0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F,
-0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A,
-0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE,
-0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB,
-0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB,
-0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3,
-0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF,
-0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE,
-0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB,
-0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF,
-0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE,
-0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5,
-0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF,
-0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,
-0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD,
-0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F,
-0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7,
-0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
-0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA,
-0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD,
-0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
-0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA,
-0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33,
-0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9,
-0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF,
-0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77,
-0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF,
-0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F,
-0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF,
-0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF,
-0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7,
-0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF,
-0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,
-0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB,
-0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF,
-0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD,
-0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE,
-0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF,
-0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F,
-0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B,
-0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9,
-0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF,
-0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD,
-0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF,
-0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
-0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB,
-0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF,
-0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF,
-0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF,
-0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9,
-0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF,
-0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD,
-0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE,
-0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF,
-0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF,
-0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,
-0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE,
-0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE,
-0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF,
-0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF,
-0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF,
-0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF,
-0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF,
-0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF,
-0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD,
-0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF,
-0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F,
-0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF,
-0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE,
-0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB,
-0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF,
-0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF,
-0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5,
-0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF,
-0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
-0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF,
-0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,
-0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB,
-0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7,
-0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF,
-0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE,
-0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB,
-0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,
-0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF,
-0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB,
-0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF,
-0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7,
-0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F,
-0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF,
-0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF,
-0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F,
-0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD,
-0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF,
-0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF,
-0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF,
-0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7,
-0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,
-0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF,
-0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,
-0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC,
-0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC,
-0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF,
-0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF,
-0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB,
-0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD,
-0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF
-
-};
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
deleted file mode 100644 (file)
index 1774ab7..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      dabusb.c  --  dab usb driver.
- *
- *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.de)
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *
- *  $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/socket.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/smp_lock.h>
-#include <linux/mutex.h>
-
-#include "dabusb.h"
-#include "dabfirmware.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.54"
-#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
-#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
-
-/* --------------------------------------------------------------------- */
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define NRDABUSB 256
-#else
-#define NRDABUSB 4
-#endif
-
-/*-------------------------------------------------------------------*/
-
-static dabusb_t dabusb[NRDABUSB];
-static int buffers = 256;
-static struct usb_driver dabusb_driver;
-
-/*-------------------------------------------------------------------*/
-
-static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src)
-{
-       unsigned long flags;
-       struct list_head *tmp;
-       int ret = 0;
-
-       spin_lock_irqsave (&s->lock, flags);
-
-       if (list_empty (src)) {
-               // no elements in source buffer
-               ret = -1;
-               goto err;
-       }
-       tmp = src->next;
-       list_move_tail (tmp, dst);
-
-  err: spin_unlock_irqrestore (&s->lock, flags);
-       return ret;
-}
-/*-------------------------------------------------------------------*/
-#ifdef DEBUG 
-static void dump_urb (struct urb *urb)
-{
-       dbg("urb                   :%p", urb);
-       dbg("dev                   :%p", urb->dev);
-       dbg("pipe                  :%08X", urb->pipe);
-       dbg("status                :%d", urb->status);
-       dbg("transfer_flags        :%08X", urb->transfer_flags);
-       dbg("transfer_buffer       :%p", urb->transfer_buffer);
-       dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
-       dbg("actual_length         :%d", urb->actual_length);
-       dbg("setup_packet          :%p", urb->setup_packet);
-       dbg("start_frame           :%d", urb->start_frame);
-       dbg("number_of_packets     :%d", urb->number_of_packets);
-       dbg("interval              :%d", urb->interval);
-       dbg("error_count           :%d", urb->error_count);
-       dbg("context               :%p", urb->context);
-       dbg("complete              :%p", urb->complete);
-}
-#endif
-/*-------------------------------------------------------------------*/
-static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
-{
-       unsigned long flags;
-       pbuff_t b;
-
-       dbg("dabusb_cancel_queue");
-
-       spin_lock_irqsave (&s->lock, flags);
-
-       list_for_each_entry(b, q, buff_list) {
-#ifdef DEBUG
-               dump_urb(b->purb);
-#endif
-               usb_unlink_urb (b->purb);
-       }
-       spin_unlock_irqrestore (&s->lock, flags);
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_queue (struct list_head *q)
-{
-       struct list_head *tmp;
-       struct list_head *p;
-       pbuff_t b;
-
-       dbg("dabusb_free_queue");
-       for (p = q->next; p != q;) {
-               b = list_entry (p, buff_t, buff_list);
-
-#ifdef DEBUG 
-               dump_urb(b->purb);
-#endif
-               kfree(b->purb->transfer_buffer);
-               usb_free_urb(b->purb);
-               tmp = p->next;
-               list_del (p);
-               kfree (b);
-               p = tmp;
-       }
-
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_buffers (pdabusb_t s)
-{
-       unsigned long flags;
-       dbg("dabusb_free_buffers");
-
-       spin_lock_irqsave(&s->lock, flags);
-
-       dabusb_free_queue (&s->free_buff_list);
-       dabusb_free_queue (&s->rec_buff_list);
-
-       spin_unlock_irqrestore(&s->lock, flags);
-
-       s->got_mem = 0;
-       return 0;
-}
-/*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)
-{
-       pbuff_t b = purb->context;
-       pdabusb_t s = b->s;
-       int i;
-       int len;
-       int dst = 0;
-       void *buf = purb->transfer_buffer;
-
-       dbg("dabusb_iso_complete");
-
-       // process if URB was not killed
-       if (purb->status != -ENOENT) {
-               unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
-               int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
-               for (i = 0; i < purb->number_of_packets; i++)
-                       if (!purb->iso_frame_desc[i].status) {
-                               len = purb->iso_frame_desc[i].actual_length;
-                               if (len <= pipesize) {
-                                       memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);
-                                       dst += len;
-                               }
-                               else
-                                       err("dabusb_iso_complete: invalid len %d", len);
-                       }
-                       else
-                               warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status);
-               if (dst != purb->actual_length)
-                       err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
-       }
-
-       if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
-               s->overruns++;
-               err("overrun (%d)", s->overruns);
-       }
-       wake_up (&s->wait);
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_alloc_buffers (pdabusb_t s)
-{
-       int buffers = 0;
-       pbuff_t b;
-       unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
-       int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
-       int packets = _ISOPIPESIZE / pipesize;
-       int transfer_buffer_length = packets * pipesize;
-       int i;
-
-       dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
-                pipesize, packets, transfer_buffer_length);
-
-       while (buffers < (s->total_buffer_size << 10)) {
-               b = (pbuff_t) kzalloc (sizeof (buff_t), GFP_KERNEL);
-               if (!b) {
-                       err("kzalloc(sizeof(buff_t))==NULL");
-                       goto err;
-               }
-               b->s = s;
-               b->purb = usb_alloc_urb(packets, GFP_KERNEL);
-               if (!b->purb) {
-                       err("usb_alloc_urb == NULL");
-                       kfree (b);
-                       goto err;
-               }
-
-               b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);
-               if (!b->purb->transfer_buffer) {
-                       kfree (b->purb);
-                       kfree (b);
-                       err("kmalloc(%d)==NULL", transfer_buffer_length);
-                       goto err;
-               }
-
-               b->purb->transfer_buffer_length = transfer_buffer_length;
-               b->purb->number_of_packets = packets;
-               b->purb->complete = dabusb_iso_complete;
-               b->purb->context = b;
-               b->purb->dev = s->usbdev;
-               b->purb->pipe = pipe;
-               b->purb->transfer_flags = URB_ISO_ASAP;
-
-               for (i = 0; i < packets; i++) {
-                       b->purb->iso_frame_desc[i].offset = i * pipesize;
-                       b->purb->iso_frame_desc[i].length = pipesize;
-               }
-
-               buffers += transfer_buffer_length;
-               list_add_tail (&b->buff_list, &s->free_buff_list);
-       }
-       s->got_mem = buffers;
-
-       return 0;
-
-       err:
-       dabusb_free_buffers (s);
-       return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
-{
-       int ret;
-       unsigned int pipe;
-       int actual_length;
-
-       dbg("dabusb_bulk");
-
-       if (!pb->pipe)
-               pipe = usb_rcvbulkpipe (s->usbdev, 2);
-       else
-               pipe = usb_sndbulkpipe (s->usbdev, 2);
-
-       ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
-       if(ret<0) {
-               err("dabusb: usb_bulk_msg failed(%d)",ret);
-
-               if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-                       err("set_interface failed");
-                       return -EINVAL;
-               }
-
-       }
-       
-       if( ret == -EPIPE ) {
-               warn("CLEAR_FEATURE request to remove STALL condition.");
-               if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
-                       err("request failed");
-       }
-
-       pb->size = actual_length;
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len)
-{
-       int ret;
-       unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);
-
-       if (!transfer_buffer) {
-               err("dabusb_writemem: kmalloc(%d) failed.", len);
-               return -ENOMEM;
-       }
-
-       memcpy (transfer_buffer, data, len);
-
-       ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
-
-       kfree (transfer_buffer);
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit)
-{
-       dbg("dabusb_8051_reset: %d",reset_bit);
-       return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_loadmem (pdabusb_t s, const char *fname)
-{
-       int ret;
-       PINTEL_HEX_RECORD ptr = firmware;
-
-       dbg("Enter dabusb_loadmem (internal)");
-       
-       ret = dabusb_8051_reset (s, 1);
-       while (ptr->Type == 0) {
-
-               dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length);
-
-               ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length);
-               if (ret < 0) {
-                       err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length);
-                       break;
-               }
-               ptr++;
-       }
-       ret = dabusb_8051_reset (s, 0);
-
-       dbg("dabusb_loadmem: exit");
-
-       return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b)
-{
-       b->size = 4;
-       b->data[0] = 0x2a;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 0;
-
-       dbg("dabusb_fpga_clear");
-
-       return dabusb_bulk (s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b)
-{
-       b->size = 4;
-       b->data[0] = 0x2c;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 0;
-
-       dbg("dabusb_fpga_init");
-
-       return dabusb_bulk (s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_download (pdabusb_t s, const char *fname)
-{
-       pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
-       unsigned int blen, n;
-       int ret;
-       unsigned char *buf = bitstream;
-
-       dbg("Enter dabusb_fpga_download (internal)");
-
-       if (!b) {
-               err("kmalloc(sizeof(bulk_transfer_t))==NULL");
-               return -ENOMEM;
-       }
-
-       b->pipe = 1;
-       ret = dabusb_fpga_clear (s, b);
-       mdelay (10);
-       blen = buf[73] + (buf[72] << 8);
-
-       dbg("Bitstream len: %i", blen);
-
-       b->data[0] = 0x2b;
-       b->data[1] = 0;
-       b->data[2] = 0;
-       b->data[3] = 60;
-
-       for (n = 0; n <= blen + 60; n += 60) {
-               // some cclks for startup
-               b->size = 64;
-               memcpy (b->data + 4, buf + 74 + n, 60);
-               ret = dabusb_bulk (s, b);
-               if (ret < 0) {
-                       err("dabusb_bulk failed.");
-                       break;
-               }
-               mdelay (1);
-       }
-
-       ret = dabusb_fpga_init (s, b);
-       kfree (b);
-
-       dbg("exit dabusb_fpga_download");
-
-       return ret;
-}
-
-static int dabusb_stop (pdabusb_t s)
-{
-       dbg("dabusb_stop");
-
-       s->state = _stopped;
-       dabusb_cancel_queue (s, &s->rec_buff_list);
-
-       dbg("pending_io: %d", s->pending_io.counter);
-
-       s->pending_io.counter = 0;
-       return 0;
-}
-
-static int dabusb_startrek (pdabusb_t s)
-{
-       if (!s->got_mem && s->state != _started) {
-
-               dbg("dabusb_startrek");
-
-               if (dabusb_alloc_buffers (s) < 0)
-                       return -ENOMEM;
-               dabusb_stop (s);
-               s->state = _started;
-               s->readptr = 0;
-       }
-
-       if (!list_empty (&s->free_buff_list)) {
-               pbuff_t end;
-               int ret;
-               
-       while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) {
-
-                       dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
-
-                       end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
-
-                       ret = usb_submit_urb (end->purb, GFP_KERNEL);
-                       if (ret) {
-                               err("usb_submit_urb returned:%d", ret);
-                               if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
-                                       err("startrek: dabusb_add_buf_tail failed");
-                               break;
-                       }
-                       else
-                               atomic_inc (&s->pending_io);
-               }
-               dbg("pending_io: %d",s->pending_io.counter);
-       }
-
-       return 0;
-}
-
-static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
-{
-       pdabusb_t s = (pdabusb_t) file->private_data;
-       unsigned long flags;
-       unsigned ret = 0;
-       int rem;
-       int cnt;
-       pbuff_t b;
-       struct urb *purb = NULL;
-
-       dbg("dabusb_read");
-
-       if (*ppos)
-               return -ESPIPE;
-
-       if (s->remove_pending)
-               return -EIO;
-
-
-       if (!s->usbdev)
-               return -EIO;
-
-       while (count > 0) {
-               dabusb_startrek (s);
-
-               spin_lock_irqsave (&s->lock, flags);
-
-               if (list_empty (&s->rec_buff_list)) {
-
-                       spin_unlock_irqrestore(&s->lock, flags);
-
-                       err("error: rec_buf_list is empty");
-                       goto err;
-               }
-               
-               b = list_entry (s->rec_buff_list.next, buff_t, buff_list);
-               purb = b->purb;
-
-               spin_unlock_irqrestore(&s->lock, flags);
-
-               if (purb->status == -EINPROGRESS) {
-                       if (file->f_flags & O_NONBLOCK)         // return nonblocking
-                        {
-                               if (!ret)
-                                       ret = -EAGAIN;
-                               goto err;
-                       }
-
-                       interruptible_sleep_on (&s->wait);
-
-                       if (signal_pending (current)) {
-                               if (!ret)
-                                       ret = -ERESTARTSYS;
-                               goto err;
-                       }
-
-                       spin_lock_irqsave (&s->lock, flags);
-
-                       if (list_empty (&s->rec_buff_list)) {
-                               spin_unlock_irqrestore(&s->lock, flags);
-                               err("error: still no buffer available.");
-                               goto err;
-                       }
-                       spin_unlock_irqrestore(&s->lock, flags);
-                       s->readptr = 0;
-               }
-               if (s->remove_pending) {
-                       ret = -EIO;
-                       goto err;
-               }
-
-               rem = purb->actual_length - s->readptr;         // set remaining bytes to copy
-
-               if (count >= rem)
-                       cnt = rem;
-               else
-                       cnt = count;
-
-               dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
-
-               if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
-                       err("read: copy_to_user failed");
-                       if (!ret)
-                               ret = -EFAULT;
-                       goto err;
-               }
-
-               s->readptr += cnt;
-               count -= cnt;
-               buf += cnt;
-               ret += cnt;
-
-               if (s->readptr == purb->actual_length) {
-                       // finished, take next buffer
-                       if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
-                               err("read: dabusb_add_buf_tail failed");
-                       s->readptr = 0;
-               }
-       }
-      err:                     //mutex_unlock(&s->mutex);
-       return ret;
-}
-
-static int dabusb_open (struct inode *inode, struct file *file)
-{
-       int devnum = iminor(inode);
-       pdabusb_t s;
-
-       if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
-               return -EIO;
-
-       s = &dabusb[devnum - DABUSB_MINOR];
-
-       dbg("dabusb_open");
-       mutex_lock(&s->mutex);
-
-       while (!s->usbdev || s->opened) {
-               mutex_unlock(&s->mutex);
-
-               if (file->f_flags & O_NONBLOCK) {
-                       return -EBUSY;
-               }
-               msleep_interruptible(500);
-
-               if (signal_pending (current)) {
-                       return -EAGAIN;
-               }
-               mutex_lock(&s->mutex);
-       }
-       if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
-               mutex_unlock(&s->mutex);
-               err("set_interface failed");
-               return -EINVAL;
-       }
-       s->opened = 1;
-       mutex_unlock(&s->mutex);
-
-       file->f_pos = 0;
-       file->private_data = s;
-
-       return nonseekable_open(inode, file);
-}
-
-static int dabusb_release (struct inode *inode, struct file *file)
-{
-       pdabusb_t s = (pdabusb_t) file->private_data;
-
-       dbg("dabusb_release");
-
-       mutex_lock(&s->mutex);
-       dabusb_stop (s);
-       dabusb_free_buffers (s);
-       mutex_unlock(&s->mutex);
-
-       if (!s->remove_pending) {
-               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
-                       err("set_interface failed");
-       }
-       else
-               wake_up (&s->remove_ok);
-
-       s->opened = 0;
-       return 0;
-}
-
-static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-       pdabusb_t s = (pdabusb_t) file->private_data;
-       pbulk_transfer_t pbulk;
-       int ret = 0;
-       int version = DABUSB_VERSION;
-
-       dbg("dabusb_ioctl");
-
-       if (s->remove_pending)
-               return -EIO;
-
-       mutex_lock(&s->mutex);
-
-       if (!s->usbdev) {
-               mutex_unlock(&s->mutex);
-               return -EIO;
-       }
-
-       switch (cmd) {
-
-       case IOCTL_DAB_BULK:
-               pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
-
-               if (!pbulk) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
-                       ret = -EFAULT;
-                       kfree (pbulk);
-                       break;
-               }
-
-               ret=dabusb_bulk (s, pbulk);
-               if(ret==0)
-                       if (copy_to_user((void __user *)arg, pbulk,
-                                        sizeof(bulk_transfer_t)))
-                               ret = -EFAULT;
-               kfree (pbulk);
-               break;
-
-       case IOCTL_DAB_OVERRUNS:
-               ret = put_user (s->overruns, (unsigned int __user *) arg);
-               break;
-
-       case IOCTL_DAB_VERSION:
-               ret = put_user (version, (unsigned int __user *) arg);
-               break;
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-       mutex_unlock(&s->mutex);
-       return ret;
-}
-
-static struct file_operations dabusb_fops =
-{
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .read =         dabusb_read,
-       .ioctl =        dabusb_ioctl,
-       .open =         dabusb_open,
-       .release =      dabusb_release,
-};
-
-static struct usb_class_driver dabusb_class = {
-       .name =         "dabusb%d",
-       .fops =         &dabusb_fops,
-       .minor_base =   DABUSB_MINOR,
-};
-
-
-/* --------------------------------------------------------------------- */
-static int dabusb_probe (struct usb_interface *intf,
-                        const struct usb_device_id *id)
-{
-       struct usb_device *usbdev = interface_to_usbdev(intf);
-       int retval;
-       pdabusb_t s;
-
-       dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
-           le16_to_cpu(usbdev->descriptor.idVendor),
-           le16_to_cpu(usbdev->descriptor.idProduct),
-           intf->altsetting->desc.bInterfaceNumber);
-
-       /* We don't handle multiple configurations */
-       if (usbdev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF &&
-           le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999)
-               return -ENODEV;
-
-
-
-       s = &dabusb[intf->minor];
-
-       mutex_lock(&s->mutex);
-       s->remove_pending = 0;
-       s->usbdev = usbdev;
-       s->devnum = intf->minor;
-
-       if (usb_reset_configuration (usbdev) < 0) {
-               err("reset_configuration failed");
-               goto reject;
-       }
-       if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
-               dabusb_loadmem (s, NULL);
-               goto reject;
-       }
-       else {
-               dabusb_fpga_download (s, NULL);
-
-               if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
-                       err("set_interface failed");
-                       goto reject;
-               }
-       }
-       dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
-       usb_set_intfdata (intf, s);
-       mutex_unlock(&s->mutex);
-
-       retval = usb_register_dev(intf, &dabusb_class);
-       if (retval) {
-               usb_set_intfdata (intf, NULL);
-               return -ENOMEM;
-       }
-
-       return 0;
-
-      reject:
-       mutex_unlock(&s->mutex);
-       s->usbdev = NULL;
-       return -ENODEV;
-}
-
-static void dabusb_disconnect (struct usb_interface *intf)
-{
-       wait_queue_t __wait;
-       pdabusb_t s = usb_get_intfdata (intf);
-
-       dbg("dabusb_disconnect");
-       
-       init_waitqueue_entry(&__wait, current);
-       
-       usb_set_intfdata (intf, NULL);
-       if (s) {
-               usb_deregister_dev (intf, &dabusb_class);
-               s->remove_pending = 1;
-               wake_up (&s->wait);
-               add_wait_queue(&s->remove_ok, &__wait);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               if (s->state == _started)
-                       schedule();
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&s->remove_ok, &__wait);
-               
-               s->usbdev = NULL;
-               s->overruns = 0;
-       }
-}
-
-static struct usb_device_id dabusb_ids [] = {
-       // { USB_DEVICE(0x0547, 0x2131) },      /* An2131 chip, no boot ROM */
-       { USB_DEVICE(0x0547, 0x9999) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, dabusb_ids);
-
-static struct usb_driver dabusb_driver = {
-       .name =         "dabusb",
-       .probe =        dabusb_probe,
-       .disconnect =   dabusb_disconnect,
-       .id_table =     dabusb_ids,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int __init dabusb_init (void)
-{
-       int retval;
-       unsigned u;
-
-       /* initialize struct */
-       for (u = 0; u < NRDABUSB; u++) {
-               pdabusb_t s = &dabusb[u];
-               memset (s, 0, sizeof (dabusb_t));
-               mutex_init (&s->mutex);
-               s->usbdev = NULL;
-               s->total_buffer_size = buffers;
-               init_waitqueue_head (&s->wait);
-               init_waitqueue_head (&s->remove_ok);
-               spin_lock_init (&s->lock);
-               INIT_LIST_HEAD (&s->free_buff_list);
-               INIT_LIST_HEAD (&s->rec_buff_list);
-       }
-
-       /* register misc device */
-       retval = usb_register(&dabusb_driver);
-       if (retval)
-               goto out;
-
-       dbg("dabusb_init: driver registered");
-
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-
-out:
-       return retval;
-}
-
-static void __exit dabusb_cleanup (void)
-{
-       dbg("dabusb_cleanup");
-
-       usb_deregister (&dabusb_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
-module_param(buffers, int, 0);
-MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
-
-module_init (dabusb_init);
-module_exit (dabusb_cleanup);
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h
deleted file mode 100644 (file)
index 96b03e4..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#define _BULK_DATA_LEN 64
-typedef struct
-{
-       unsigned char data[_BULK_DATA_LEN];
-       unsigned int size;
-       unsigned int pipe;
-}bulk_transfer_t,*pbulk_transfer_t;
-
-#define DABUSB_MINOR 240               /* some unassigned USB minor */
-#define DABUSB_VERSION 0x1000
-#define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
-#define IOCTL_DAB_OVERRUNS         _IOR('d',  0x15, int)
-#define IOCTL_DAB_VERSION           _IOR('d', 0x3f, int) 
-
-#ifdef __KERNEL__
-
-typedef enum { _stopped=0, _started } driver_state_t;
-
-typedef struct
-{
-       struct mutex mutex;
-       struct usb_device *usbdev;
-       wait_queue_head_t wait;
-       wait_queue_head_t remove_ok;
-       spinlock_t lock;
-       atomic_t pending_io;
-       driver_state_t state;
-       int remove_pending;
-       int got_mem;
-       int total_buffer_size;
-       unsigned int overruns;
-       int readptr;
-       int opened;
-       int devnum;
-       struct list_head free_buff_list;
-       struct list_head rec_buff_list;
-} dabusb_t,*pdabusb_t;
-
-typedef struct 
-{
-       pdabusb_t s;
-       struct urb *purb;
-       struct list_head buff_list;
-} buff_t,*pbuff_t;
-
-typedef struct
-{
-       wait_queue_head_t wait;
-} bulk_completion_context_t, *pbulk_completion_context_t;
-
-
-#define _DABUSB_IF 2
-#define _DABUSB_ISOPIPE 0x09
-#define _ISOPIPESIZE   16384
-
-#define _BULK_DATA_LEN 64
-// Vendor specific request code for Anchor Upload/Download
-// This one is implemented in the core
-#define ANCHOR_LOAD_INTERNAL  0xA0
-
-// EZ-USB Control and Status Register.  Bit 0 controls 8051 reset
-#define CPUCS_REG    0x7F92
-#define _TOTAL_BUFFERS 384
-
-#define MAX_INTEL_HEX_RECORD_LENGTH 16
-
-#ifndef _BYTE_DEFINED
-#define _BYTE_DEFINED
-typedef unsigned char BYTE;
-#endif // !_BYTE_DEFINED
-
-#ifndef _WORD_DEFINED
-#define _WORD_DEFINED
-typedef unsigned short WORD;
-#endif // !_WORD_DEFINED
-
-typedef struct _INTEL_HEX_RECORD
-{
-   BYTE  Length;
-   WORD  Address;
-   BYTE  Type;
-   BYTE  Data[MAX_INTEL_HEX_RECORD_LENGTH];
-} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
-
-#endif
diff --git a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c
deleted file mode 100644 (file)
index 2564680..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
- into both the USB and an analog audio input, so this thing
- only deals with initialisation and frequency setting, the
- audio data has to be handled by a sound driver.
-
- Major issue: I can't find out where the device reports the signal
- strength, and indeed the windows software appearantly just looks
- at the stereo indicator as well.  So, scanning will only find
- stereo stations.  Sad, but I can't help it.
-
- Also, the windows program sends oodles of messages over to the
- device, and I couldn't figure out their meaning.  My suspicion
- is that they don't have any:-)
-
- You might find some interesting stuff about this module at
- http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
-
- Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- History:
-
- Version 0.40:
-  Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
-
- Version 0.30:
-       Markus: Updates for 2.5.x kernel and more ISO compliant source
-
- Version 0.25:
-        PSL and Markus: Cleanup, radio now doesn't stop on device close
-
- Version 0.24:
-       Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
-       right.  Some minor cleanup, improved standalone compilation
-
- Version 0.23:
-       Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
-
- Version 0.22:
-       Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, 
-       thanks to Mike Cox for pointing the problem out.
-
- Version 0.21:
-       Markus: Minor cleanup, warnings if something goes wrong, lame attempt
-       to adhere to Documentation/CodingStyle
-
- Version 0.2: 
-       Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
-       Markus: Copyright clarification
-
- Version 0.01: Markus: initial release
-
-*/
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/smp_lock.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.40"
-#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
-#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
-
-#define DSB100_VENDOR 0x04b4
-#define DSB100_PRODUCT 0x1002
-
-/* Commands the device appears to understand */
-#define DSB100_TUNE 1
-#define DSB100_ONOFF 2
-
-#define TB_LEN 16
-
-/* Frequency limits in MHz -- these are European values.  For Japanese
-devices, that would be 76 and 91.  */
-#define FREQ_MIN  87.5
-#define FREQ_MAX 108.0
-#define FREQ_MUL 16000
-
-
-static int usb_dsbr100_probe(struct usb_interface *intf,
-                            const struct usb_device_id *id);
-static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg);
-static int usb_dsbr100_open(struct inode *inode, struct file *file);
-static int usb_dsbr100_close(struct inode *inode, struct file *file);
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-/* Data for one (physical) device */
-typedef struct {
-       struct usb_device *usbdev;
-       struct video_device *videodev;
-       unsigned char transfer_buffer[TB_LEN];
-       int curfreq;
-       int stereo;
-       int users;
-       int removed;
-} dsbr100_device;
-
-
-/* File system interface */
-static struct file_operations usb_dsbr100_fops = {
-       .owner =        THIS_MODULE,
-       .open =         usb_dsbr100_open,
-       .release =      usb_dsbr100_close,
-       .ioctl =        usb_dsbr100_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-
-/* V4L interface */
-static struct video_device dsbr100_videodev_template=
-{
-       .owner =        THIS_MODULE,
-       .name =         "D-Link DSB-R 100",
-       .type =         VID_TYPE_TUNER,
-       .hardware =     VID_HARDWARE_AZTECH,
-       .fops =         &usb_dsbr100_fops,
-       .release = video_device_release,
-};
-
-static struct usb_device_id usb_dsbr100_device_table [] = {
-       { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
-       { }                                             /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_dsbr100_driver = {
-       .name =         "dsbr100",
-       .probe =        usb_dsbr100_probe,
-       .disconnect =   usb_dsbr100_disconnect,
-       .id_table =     usb_dsbr100_device_table,
-};
-
-/* Low-level device interface begins here */
-
-/* switch on radio */
-static int dsbr100_start(dsbr100_device *radio)
-{
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_ONOFF, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
-               return -1;
-       return (radio->transfer_buffer)[0];
-}
-
-
-/* switch off radio */
-static int dsbr100_stop(dsbr100_device *radio)
-{
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_ONOFF, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
-               return -1;
-       return (radio->transfer_buffer)[0];
-}
-
-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(dsbr100_device *radio, int freq)
-{
-       freq = (freq/16*80)/1000+856;
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       DSB100_TUNE, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       (freq>>8)&0x00ff, freq&0xff, 
-                       radio->transfer_buffer, 8, 300)<0 ||
-          usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                       0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
-       usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-                       USB_REQ_GET_STATUS, 
-                       USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
-                       0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
-               radio->stereo = -1;
-               return -1;
-       }
-       radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
-       return (radio->transfer_buffer)[0];
-}
-
-/* return the device status.  This is, in effect, just whether it
-sees a stereo signal or not.  Pity. */
-static void dsbr100_getstat(dsbr100_device *radio)
-{
-       if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
-               USB_REQ_GET_STATUS, 
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-               0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
-               radio->stereo = -1;
-       else
-               radio->stereo = ! (radio->transfer_buffer[0]&0x01);
-}
-
-
-/* USB subsystem interface begins here */
-
-/* check if the device is present and register with v4l and
-usb if it is */
-static int usb_dsbr100_probe(struct usb_interface *intf, 
-                        const struct usb_device_id *id)
-{
-       dsbr100_device *radio;
-
-       if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
-               return -ENOMEM;
-       if (!(radio->videodev = video_device_alloc())) {
-               kfree(radio);
-               return -ENOMEM;
-       }
-       memcpy(radio->videodev, &dsbr100_videodev_template, 
-               sizeof(dsbr100_videodev_template));
-       radio->removed = 0;
-       radio->users = 0;
-       radio->usbdev = interface_to_usbdev(intf);
-       radio->curfreq = FREQ_MIN*FREQ_MUL;
-       video_set_drvdata(radio->videodev, radio);
-       if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
-               radio_nr)) {
-               warn("Could not register video device");
-               video_device_release(radio->videodev);
-               kfree(radio);
-               return -EIO;
-       }
-       usb_set_intfdata(intf, radio);
-       return 0;
-}
-
-/* handle unplugging of the device, release data structures
-if nothing keeps us from doing it.  If something is still
-keeping us busy, the release callback of v4l will take care
-of releasing it.  stv680.c does not relase its private
-data, so I don't do this here either.  Checking out the
-code I'd expect I better did that, but if there's a memory
-leak here it's tiny (~50 bytes per disconnect) */
-static void usb_dsbr100_disconnect(struct usb_interface *intf)
-{
-       dsbr100_device *radio = usb_get_intfdata(intf);
-
-       usb_set_intfdata (intf, NULL);
-       if (radio) {
-               video_unregister_device(radio->videodev);
-               radio->videodev = NULL;
-               if (radio->users) {
-                       kfree(radio);
-               } else {
-                       radio->removed = 1;
-               }
-       }
-}
-
-
-/* Video for Linux interface */
-
-static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
-                               unsigned int cmd, void *arg)
-{
-       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-       if (!radio)
-               return -EIO;
-
-       switch(cmd) {
-               case VIDIOCGCAP: {
-                       struct video_capability *v = arg;
-
-                       memset(v, 0, sizeof(*v));
-                       v->type = VID_TYPE_TUNER;
-                       v->channels = 1;
-                       v->audios = 1;
-                       strcpy(v->name, "D-Link R-100 USB FM Radio");
-                       return 0;
-               }
-               case VIDIOCGTUNER: {
-                       struct video_tuner *v = arg;
-
-                       dsbr100_getstat(radio);
-                       if(v->tuner)    /* Only 1 tuner */ 
-                               return -EINVAL;
-                       v->rangelow = FREQ_MIN*FREQ_MUL;
-                       v->rangehigh = FREQ_MAX*FREQ_MUL;
-                       v->flags = VIDEO_TUNER_LOW;
-                       v->mode = VIDEO_MODE_AUTO;
-                       v->signal = radio->stereo*0x7000;
-                               /* Don't know how to get signal strength */
-                       v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
-                       strcpy(v->name, "DSB R-100");
-                       return 0;
-               }
-               case VIDIOCSTUNER: {
-                       struct video_tuner *v = arg;
-
-                       if(v->tuner!=0)
-                               return -EINVAL;
-                       /* Only 1 tuner so no setting needed ! */
-                       return 0;
-               }
-               case VIDIOCGFREQ: {
-                       int *freq = arg;
-
-                       if (radio->curfreq==-1)
-                               return -EINVAL;
-                       *freq = radio->curfreq;
-                       return 0;
-               }
-               case VIDIOCSFREQ: {
-                       int *freq = arg;
-
-                       radio->curfreq = *freq;
-                       if (dsbr100_setfreq(radio, radio->curfreq)==-1)
-                               warn("Set frequency failed");
-                       return 0;
-               }
-               case VIDIOCGAUDIO: {
-                       struct video_audio *v = arg;
-
-                       memset(v, 0, sizeof(*v));
-                       v->flags |= VIDEO_AUDIO_MUTABLE;
-                       v->mode = VIDEO_SOUND_STEREO;
-                       v->volume = 1;
-                       v->step = 1;
-                       strcpy(v->name, "Radio");
-                       return 0;                       
-               }
-               case VIDIOCSAUDIO: {
-                       struct video_audio *v = arg;
-
-                       if (v->audio) 
-                               return -EINVAL;
-                       if (v->flags&VIDEO_AUDIO_MUTE) {
-                               if (dsbr100_stop(radio)==-1)
-                                       warn("Radio did not respond properly");
-                       }
-                       else
-                               if (dsbr100_start(radio)==-1)
-                                       warn("Radio did not respond properly");
-                       return 0;
-               }
-               default:
-                       return -ENOIOCTLCMD;
-       }
-}
-
-static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
-}
-
-static int usb_dsbr100_open(struct inode *inode, struct file *file)
-{
-       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-       radio->users = 1;
-       if (dsbr100_start(radio)<0) {
-               warn("Radio did not start up properly");
-               radio->users = 0;
-               return -EIO;
-       }
-       dsbr100_setfreq(radio, radio->curfreq);
-       return 0;
-}
-
-static int usb_dsbr100_close(struct inode *inode, struct file *file)
-{
-       dsbr100_device *radio=video_get_drvdata(video_devdata(file));
-
-       if (!radio)
-               return -ENODEV;
-       radio->users = 0;
-       if (radio->removed) {
-               kfree(radio);
-       }
-       return 0;
-}
-
-static int __init dsbr100_init(void)
-{
-       int retval = usb_register(&usb_dsbr100_driver);
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return retval;
-}
-
-static void __exit dsbr100_exit(void)
-{
-       usb_deregister(&usb_dsbr100_driver);
-}
-
-module_init (dsbr100_init);
-module_exit (dsbr100_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/media/et61x251.h b/drivers/usb/media/et61x251.h
deleted file mode 100644 (file)
index eee8afc..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ET61X251_H_
-#define _ET61X251_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-
-#include "et61x251_sensor.h"
-
-/*****************************************************************************/
-
-#define ET61X251_DEBUG
-#define ET61X251_DEBUG_LEVEL         2
-#define ET61X251_MAX_DEVICES         64
-#define ET61X251_PRESERVE_IMGSCALE   0
-#define ET61X251_FORCE_MUNMAP        0
-#define ET61X251_MAX_FRAMES          32
-#define ET61X251_COMPRESSION_QUALITY 0
-#define ET61X251_URBS                2
-#define ET61X251_ISO_PACKETS         7
-#define ET61X251_ALTERNATE_SETTING   13
-#define ET61X251_URB_TIMEOUT         msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
-#define ET61X251_CTRL_TIMEOUT        100
-#define ET61X251_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-static const struct usb_device_id et61x251_id_table[] = {
-       { USB_DEVICE(0x102c, 0x6151), },
-       { USB_DEVICE(0x102c, 0x6251), },
-       { USB_DEVICE(0x102c, 0x6253), },
-       { USB_DEVICE(0x102c, 0x6254), },
-       { USB_DEVICE(0x102c, 0x6255), },
-       { USB_DEVICE(0x102c, 0x6256), },
-       { USB_DEVICE(0x102c, 0x6257), },
-       { USB_DEVICE(0x102c, 0x6258), },
-       { USB_DEVICE(0x102c, 0x6259), },
-       { USB_DEVICE(0x102c, 0x625a), },
-       { USB_DEVICE(0x102c, 0x625b), },
-       { USB_DEVICE(0x102c, 0x625c), },
-       { USB_DEVICE(0x102c, 0x625d), },
-       { USB_DEVICE(0x102c, 0x625e), },
-       { USB_DEVICE(0x102c, 0x625f), },
-       { USB_DEVICE(0x102c, 0x6260), },
-       { USB_DEVICE(0x102c, 0x6261), },
-       { USB_DEVICE(0x102c, 0x6262), },
-       { USB_DEVICE(0x102c, 0x6263), },
-       { USB_DEVICE(0x102c, 0x6264), },
-       { USB_DEVICE(0x102c, 0x6265), },
-       { USB_DEVICE(0x102c, 0x6266), },
-       { USB_DEVICE(0x102c, 0x6267), },
-       { USB_DEVICE(0x102c, 0x6268), },
-       { USB_DEVICE(0x102c, 0x6269), },
-       { }
-};
-
-ET61X251_SENSOR_TABLE
-
-/*****************************************************************************/
-
-enum et61x251_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct et61x251_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum et61x251_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum et61x251_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum et61x251_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum et61x251_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-struct et61x251_sysfs_attr {
-       u8 reg, i2c_reg;
-};
-
-struct et61x251_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
-
-struct et61x251_device {
-       struct video_device* v4ldev;
-
-       struct et61x251_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[ET61X251_URBS];
-       void* transfer_buffer[ET61X251_URBS];
-       u8* control_buffer;
-
-       struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum et61x251_io_method io;
-       enum et61x251_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct et61x251_sysfs_attr sysfs;
-       struct et61x251_module_param module_param;
-
-       enum et61x251_dev_state state;
-       u8 users;
-
-       struct mutex dev_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
-{
-       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
-               return cam;
-
-       return NULL;
-}
-
-
-void
-et61x251_attach_sensor(struct et61x251_device* cam,
-                       struct et61x251_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ET61X251_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("et61x251: " fmt "\n", ## args);              \
-               else if ((level) == 3)                                        \
-                       pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-         __FUNCTION__, __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ET61X251_H_ */
diff --git a/drivers/usb/media/et61x251_core.c b/drivers/usb/media/et61x251_core.c
deleted file mode 100644 (file)
index 7cc01b8..0000000
+++ /dev/null
@@ -1,2630 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers                       *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "et61x251.h"
-
-/*****************************************************************************/
-
-#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
-                                "PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
-#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.02"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, et61x251_id_table);
-
-MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
-MODULE_VERSION(ET61X251_MODULE_VERSION);
-MODULE_LICENSE(ET61X251_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "
-                 __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second registered camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-                               ET61X251_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
-                                       ET61X251_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                 "\n<n[,...]> Timeout for a video frame in seconds."
-                 "\nThis parameter is specific for each detected camera."
-                 "\nDefault value is "
-                 __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
-                 "\n");
-
-#ifdef ET61X251_DEBUG
-static unsigned short debug = ET61X251_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
-                 "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-et61x251_request_buffers(struct et61x251_device* cam, u32 count,
-                         enum et61x251_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > ET61X251_MAX_FRAMES)
-               count = ET61X251_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void et61x251_release_buffers(struct et61x251_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void et61x251_empty_framequeues(struct et61x251_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void et61x251_requeue_outqueue(struct et61x251_device* cam)
-{
-       struct et61x251_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void et61x251_queue_unusedframes(struct et61x251_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       *buff = value;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (value 0x%02X, index "
-                      "0x%02X, error %d)", value, index, res);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-int et61x251_read_reg(struct et61x251_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-                   index, res);
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
-{
-       int i, r;
-
-       for (i = 1; i <= 8; i++) {
-               if (sensor->interface == ET61X251_I2C_3WIRES) {
-                       r = et61x251_read_reg(cam, 0x8e);
-                       if (!(r & 0x02) && (r >= 0))
-                               return 0;
-               } else {
-                       r = et61x251_read_reg(cam, 0x8b);
-                       if (!(r & 0x01) && (r >= 0))
-                               return 0;
-               }
-               if (r < 0)
-                       return -EIO;
-               udelay(8*8); /* minimum for sensors at 400kHz */
-       }
-
-       return -EBUSY;
-}
-
-
-int
-et61x251_i2c_try_read(struct et61x251_device* cam,
-                      struct et61x251_sensor* sensor, u8 address)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x10;
-       data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, sensor);
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       if (err)
-               DBG(3, "I2C read failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-
-       return err ? -1 : (int)data[0];
-}
-
-
-int
-et61x251_i2c_try_write(struct et61x251_device* cam,
-                       struct et61x251_sensor* sensor, u8 address, u8 value)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x12;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       data[0] = value;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, sensor);
-
-       if (err)
-               DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-
-       return err ? -1 : 0;
-}
-
-
-int
-et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
-                       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
-                       u8 data8, u8 address)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       data[0] = data2;
-       data[1] = data3;
-       data[2] = data4;
-       data[3] = data5;
-       data[4] = data6;
-       data[5] = data7;
-       data[6] = data8;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       data[0] = address;
-       data[1] = cam->sensor.i2c_slave_id;
-       data[2] = cam->sensor.rsta | 0x02 | (n << 4);
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       /* Start writing through the serial interface */
-       data[0] = data1;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-                             0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += et61x251_i2c_wait(cam, &cam->sensor);
-
-       if (err)
-               DBG(3, "I2C raw write failed for %s image sensor",
-                   cam->sensor.name);
-
-       PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
-             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
-             " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
-             data1, data2, data3, data4, data5, data6, data7, data8);
-
-       return err ? -1 : 0;
-
-}
-
-
-int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-{
-       return et61x251_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
-{
-       return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-/*****************************************************************************/
-
-static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
-{
-       struct et61x251_device* cam = urb->context;
-       struct et61x251_frame_t** f;
-       size_t imagesize;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int len, status;
-               void *pos;
-               u8* b1, * b2, sof;
-               const u8 VOID_BYTES = 6;
-               size_t imglen;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               b1 = pos++;
-               b2 = pos++;
-               sof = ((*b1 & 0x3f) == 63);
-               imglen = ((*b1 & 0xc0) << 2) | *b2;
-
-               PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
-                     len, i, imglen);
-
-               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-                       if (sof) {
-                               (*f)->state = F_GRABBING;
-                               (*f)->buf.bytesused = 0;
-                               do_gettimeofday(&(*f)->buf.timestamp);
-                               pos += 22;
-                               DBG(3, "SOF detected: new video frame");
-                       }
-
-               if ((*f)->state == F_GRABBING) {
-                       if (sof && (*f)->buf.bytesused) {
-                               if (cam->sensor.pix_format.pixelformat ==
-                                                        V4L2_PIX_FMT_ET61X251)
-                                       goto end_of_frame;
-                               else {
-                                       DBG(3, "Not expected SOF detected "
-                                              "after %lu bytes",
-                                          (unsigned long)(*f)->buf.bytesused);
-                                       (*f)->state = F_ERROR;
-                                       continue;
-                               }
-                       }
-
-                       if ((*f)->buf.bytesused + imglen > imagesize) {
-                               DBG(3, "Video frame size exceeded");
-                               (*f)->state = F_ERROR;
-                               continue;
-                       }
-
-                       pos += VOID_BYTES;
-
-                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
-                       (*f)->buf.bytesused += imglen;
-
-                       if ((*f)->buf.bytesused == imagesize) {
-                               u32 b;
-end_of_frame:
-                               b = (*f)->buf.bytesused;
-                               (*f)->state = F_DONE;
-                               (*f)->buf.sequence= ++cam->frame_count;
-                               spin_lock(&cam->queue_lock);
-                               list_move_tail(&(*f)->frame, &cam->outqueue);
-                               if (!list_empty(&cam->inqueue))
-                                       (*f) = list_entry(cam->inqueue.next,
-                                                      struct et61x251_frame_t,
-                                                         frame);
-                               else
-                                       (*f) = NULL;
-                               spin_unlock(&cam->queue_lock);
-                               DBG(3, "Video frame captured: : %lu bytes",
-                                      (unsigned long)(b));
-
-                               if (!(*f))
-                                       goto resubmit_urb;
-
-                               if (sof &&
-                                   cam->sensor.pix_format.pixelformat ==
-                                                        V4L2_PIX_FMT_ET61X251)
-                                       goto start_of_frame;
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int et61x251_start_transfer(struct et61x251_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
-                                              864, 896, 920, 956, 980, 1000,
-                                              1022};
-       const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < ET61X251_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < ET61X251_URBS; i++) {
-               urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = ET61X251_ISO_PACKETS;
-               urb->complete = et61x251_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       err = et61x251_write_reg(cam, 0x01, 0x03);
-       err = et61x251_write_reg(cam, 0x00, 0x03);
-       err = et61x251_write_reg(cam, 0x08, 0x03);
-       if (err) {
-               err = -EIO;
-               DBG(1, "I/O hardware error");
-               goto free_urbs;
-       }
-
-       err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < ET61X251_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int et61x251_stop_transfer(struct et61x251_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = ET61X251_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int et61x251_stream_interrupt(struct et61x251_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    ET61X251_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. To "
-                      "use it, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
-{
-       char str[5];
-       char* endp;
-       unsigned long val;
-
-       if (len < 4) {
-               strncpy(str, buff, len);
-               str[len+1] = '\0';
-       } else {
-               strncpy(str, buff, 4);
-               str[4] = '\0';
-       }
-
-       val = simple_strtoul(str, &endp, 0);
-
-       *count = 0;
-       if (val <= 0xff)
-               *count = (ssize_t)(endp - str);
-       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
-               *count += 1;
-
-       return (u8)val;
-}
-
-/*
-   NOTE 1: being inside one of the following methods implies that the v4l
-           device exists for sure (see kobjects and reference counters)
-   NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = et61x251_strtou8(buf, len, &count);
-       if (index > 0x8e || !count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.reg = index;
-
-       DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       value = et61x251_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = et61x251_write_reg(cam, value, cam->sysfs.reg);
-       if (err) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = et61x251_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.i2c_reg = index;
-
-       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
-{
-       struct et61x251_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct et61x251_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&et61x251_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       value = et61x251_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
-       if (err) {
-               mutex_unlock(&et61x251_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.i2c_reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       return count;
-}
-
-
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-                         et61x251_show_reg, et61x251_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-                         et61x251_show_val, et61x251_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-                         et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-                         et61x251_show_i2c_val, et61x251_store_i2c_val);
-
-
-static void et61x251_create_sysfs(struct et61x251_device* cam)
-{
-       struct video_device *v4ldev = cam->v4ldev;
-
-       video_device_create_file(v4ldev, &class_device_attr_reg);
-       video_device_create_file(v4ldev, &class_device_attr_val);
-       if (cam->sensor.sysfs_ops) {
-               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
-       }
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-et61x251_set_pix_format(struct et61x251_device* cam,
-                        struct v4l2_pix_format* pix)
-{
-       int r, err = 0;
-
-       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
-               err += r;
-       if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
-               err += et61x251_write_reg(cam, r & 0xfd, 0x12);
-       else
-               err += et61x251_write_reg(cam, r | 0x02, 0x12);
-
-       return err ? -EIO : 0;
-}
-
-
-static int
-et61x251_set_compression(struct et61x251_device* cam,
-                         struct v4l2_jpegcompression* compression)
-{
-       int r, err = 0;
-
-       if ((r = et61x251_read_reg(cam, 0x12)) < 0)
-               err += r;
-       if (compression->quality == 0)
-               err += et61x251_write_reg(cam, r & 0xfb, 0x12);
-       else
-               err += et61x251_write_reg(cam, r | 0x04, 0x12);
-
-       return err ? -EIO : 0;
-}
-
-
-static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
-{
-       int r = 0, err = 0;
-
-       r = et61x251_read_reg(cam, 0x12);
-       if (r < 0)
-               err += r;
-
-       if (scale == 1)
-               err += et61x251_write_reg(cam, r & ~0x01, 0x12);
-       else if (scale == 2)
-               err += et61x251_write_reg(cam, r | 0x01, 0x12);
-
-       if (err)
-               return -EIO;
-
-       PDBGG("Scaling factor: %u", scale);
-
-       return 0;
-}
-
-
-static int
-et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
-                          s->active_pixel.left),
-           fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
-                          s->active_pixel.top),
-           fmw_length = (u16)(rect->width),
-           fmw_height = (u16)(rect->height);
-       int err = 0;
-
-       err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
-       err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
-       err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
-       err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
-       err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
-                                      | ((fmw_length & 0x300) >> 4)
-                                      | ((fmw_height & 0x300) >> 2), 0x6d);
-       if (err)
-               return -EIO;
-
-       PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
-             fmw_sx, fmw_sy, fmw_length, fmw_height);
-
-       return 0;
-}
-
-
-static int et61x251_init(struct et61x251_device* cam)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-               cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
-       err += et61x251_set_crop(cam, rect);
-       if (err)
-               return err;
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       err += et61x251_set_compression(cam, &cam->compression);
-       err += et61x251_set_pix_format(cam, &s->pix_format);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, &s->pix_format);
-       if (err)
-               return err;
-
-       if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
-               DBG(3, "Compressed video format is active, quality %d",
-                   cam->compression.quality);
-       else
-               DBG(3, "Uncompressed video format is active");
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-
-static void et61x251_release_resources(struct et61x251_device* cam)
-{
-       mutex_lock(&et61x251_sysfs_lock);
-
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-
-       usb_put_dev(cam->usbdev);
-
-       mutex_unlock(&et61x251_sysfs_lock);
-
-       kfree(cam->control_buffer);
-}
-
-/*****************************************************************************/
-
-static int et61x251_open(struct inode* inode, struct file* filp)
-{
-       struct et61x251_device* cam;
-       int err = 0;
-
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&et61x251_disconnect))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&et61x251_disconnect);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
-               if (err) {
-                       up_read(&et61x251_disconnect);
-                       return err;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&et61x251_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = et61x251_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = et61x251_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       et61x251_empty_framequeues(cam);
-
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
-
-out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&et61x251_disconnect);
-       return err;
-}
-
-
-static int et61x251_release(struct inode* inode, struct file* filp)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       et61x251_stop_transfer(cam);
-
-       et61x251_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               et61x251_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-}
-
-
-static ssize_t
-et61x251_read(struct file* filp, char __user * buf,
-              size_t count, loff_t* f_pos)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       struct et61x251_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose the read "
-                      "method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
-                                             IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       et61x251_empty_framequeues(cam);
-               et61x251_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       et61x251_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err ? err : count;
-}
-
-
-static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       struct et61x251_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!et61x251_request_buffers(cam, cam->nreadbuffers,
-                                             IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               et61x251_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void et61x251_vm_open(struct vm_area_struct* vma)
-{
-       struct et61x251_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void et61x251_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct et61x251_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static struct vm_operations_struct et61x251_vm_ops = {
-       .open = et61x251_vm_open,
-       .close = et61x251_vm_close,
-};
-
-
-static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &et61x251_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-
-       et61x251_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "et61x251",
-               .version = ET61X251_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_pix_format* pix_format = &(s->pix_format);
-       u8 scale;
-       const enum et61x251_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       /* Preserve R,G or B origin */
-       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
-       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
-       if (rect->width < 4)
-               rect->width = 4;
-       if (rect->height < 4)
-               rect->height = 4;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-
-       rect->width &= ~3L;
-       rect->height &= ~3L;
-
-       if (ET61X251_PRESERVE_IMGSCALE) {
-               /* Calculate the actual scaling factor */
-               u32 a, b;
-               a = rect->width * rect->height;
-               b = pix_format->width * pix_format->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-       } else
-               scale = 1;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               et61x251_release_buffers(cam);
-
-       err = et61x251_set_crop(cam, rect);
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-       err += et61x251_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width/scale;
-       s->pix_format.height = rect->height/scale;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               et61x251_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               et61x251_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "bayer rgb");
-               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-       } else if (fmtd.index == 1) {
-               strcpy(fmtd.description, "compressed");
-               fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
-                            ? 0 : (pfmt->width * pfmt->priv) / 8;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
-                          void __user * arg)
-{
-       struct et61x251_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       u8 scale;
-       const enum et61x251_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       { /* calculate the actual scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-       }
-
-       rect.width = scale * pix->width;
-       rect.height = scale * pix->height;
-
-       if (rect.width < 4)
-               rect.width = 4;
-       if (rect.height < 4)
-               rect.height = 4;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-
-       rect.width &= ~3L;
-       rect.height &= ~3L;
-
-       { /* adjust the scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
-       }
-
-       pix->width = rect.width / scale;
-       pix->height = rect.height / scale;
-
-       if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
-           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-               pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv; /* bpp */
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
-                           ? 0 : (pix->width * pix->priv) / 8;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               et61x251_release_buffers(cam);
-
-       err += et61x251_set_pix_format(cam, pix);
-       err += et61x251_set_crop(cam, &rect);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, pix);
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-       err += et61x251_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               et61x251_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               et61x251_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression,
-                        sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum et61x251_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0 && jc.quality != 1)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       err += et61x251_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open "
-                      "/dev/video%d again.", cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. "
-                              "Previous buffers are still mapped.");
-                       return -EINVAL;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       et61x251_empty_framequeues(cam);
-
-       et61x251_release_buffers(cam);
-       if (rb.count)
-               rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               et61x251_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
-                      void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct et61x251_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = et61x251_stream_interrupt(cam)))
-                       return err;
-
-       et61x251_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
-               sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
-                               unsigned int cmd, void __user * arg)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return et61x251_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return et61x251_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return et61x251_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return et61x251_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return et61x251_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return et61x251_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-               return et61x251_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP_OLD:
-       case VIDIOC_CROPCAP:
-               return et61x251_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return et61x251_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return et61x251_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return et61x251_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return et61x251_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return et61x251_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return et61x251_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return et61x251_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return et61x251_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return et61x251_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return et61x251_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return et61x251_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return et61x251_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return et61x251_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-               return et61x251_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static int et61x251_ioctl(struct inode* inode, struct file* filp,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "et61x251", cmd);
-
-       err = et61x251_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-
-static struct file_operations et61x251_fops = {
-       .owner = THIS_MODULE,
-       .open =    et61x251_open,
-       .release = et61x251_release,
-       .ioctl =   et61x251_ioctl,
-       .read =    et61x251_read,
-       .poll =    et61x251_poll,
-       .mmap =    et61x251_mmap,
-       .llseek =  no_llseek,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct et61x251_device* cam;
-       static unsigned int dev_nr = 0;
-       unsigned int i;
-       int err = 0;
-
-       if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       mutex_init(&cam->dev_mutex);
-
-       DBG(2, "ET61X[12]51 PC Camera Controller detected "
-              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
-
-       for  (i = 0; et61x251_sensor_table[i]; i++) {
-               err = et61x251_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err)
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-       else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (et61x251_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
-       cam->v4ldev->fops = &et61x251_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       mutex_lock(&cam->dev_mutex);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       et61x251_create_sysfs(cam);
-       DBG(2, "Optional device control through 'sysfs' interface ready");
-#endif
-
-       usb_set_intfdata(intf, cam);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void et61x251_usb_disconnect(struct usb_interface* intf)
-{
-       struct et61x251_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
-
-       down_write(&et61x251_disconnect);
-
-       mutex_lock(&cam->dev_mutex);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       wake_up_interruptible_all(&cam->open);
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor);
-               cam->state |= DEV_MISCONFIGURED;
-               et61x251_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
-               cam->state |= DEV_DISCONNECTED;
-               et61x251_release_resources(cam);
-       }
-
-       mutex_unlock(&cam->dev_mutex);
-
-       if (!cam->users)
-               kfree(cam);
-
-       up_write(&et61x251_disconnect);
-}
-
-
-static struct usb_driver et61x251_usb_driver = {
-       .name =       "et61x251",
-       .id_table =   et61x251_id_table,
-       .probe =      et61x251_usb_probe,
-       .disconnect = et61x251_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init et61x251_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, ET61X251_MODULE_NAME " v" ET61X251_MODULE_VERSION);
-       KDBG(3, ET61X251_MODULE_AUTHOR);
-
-       if ((err = usb_register(&et61x251_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit et61x251_module_exit(void)
-{
-       usb_deregister(&et61x251_usb_driver);
-}
-
-
-module_init(et61x251_module_init);
-module_exit(et61x251_module_exit);
diff --git a/drivers/usb/media/et61x251_sensor.h b/drivers/usb/media/et61x251_sensor.h
deleted file mode 100644 (file)
index 56841ae..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to ET61X[12]51 PC Camera Controllers    *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ET61X251_SENSOR_H_
-#define _ET61X251_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct et61x251_device;
-struct et61x251_sensor;
-
-/*****************************************************************************/
-
-extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
-
-#define ET61X251_SENSOR_TABLE                                                 \
-/* Weak detections must go at the end of the list */                          \
-static int (*et61x251_sensor_table[])(struct et61x251_device*) = {            \
-       &et61x251_probe_tas5130d1b,                                           \
-       NULL,                                                                 \
-};
-
-extern struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
-
-extern void
-et61x251_attach_sensor(struct et61x251_device* cam,
-                       struct et61x251_sensor* sensor);
-
-/*****************************************************************************/
-
-extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
-extern int et61x251_read_reg(struct et61x251_device*, u16 index);
-extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
-extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
-extern int et61x251_i2c_try_write(struct et61x251_device*,
-                                  struct et61x251_sensor*, u8 address,
-                                  u8 value);
-extern int et61x251_i2c_try_read(struct et61x251_device*,
-                                 struct et61x251_sensor*, u8 address);
-extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
-                                  u8 data2, u8 data3, u8 data4, u8 data5,
-                                  u8 data6, u8 data7, u8 data8, u8 address);
-
-/*****************************************************************************/
-
-enum et61x251_i2c_sysfs_ops {
-       ET61X251_I2C_READ = 0x01,
-       ET61X251_I2C_WRITE = 0x02,
-};
-
-enum et61x251_i2c_interface {
-       ET61X251_I2C_2WIRES,
-       ET61X251_I2C_3WIRES,
-};
-
-/* Repeat start condition when RSTA is high */
-enum et61x251_i2c_rsta {
-       ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
-       ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
-};
-
-#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-
-struct et61x251_sensor {
-       char name[32];
-
-       enum et61x251_i2c_sysfs_ops sysfs_ops;
-
-       enum et61x251_i2c_interface interface;
-       u8 i2c_slave_id;
-       enum et61x251_i2c_rsta rsta;
-       struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
-
-       struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
-       struct v4l2_cropcap cropcap;
-       struct v4l2_pix_format pix_format;
-
-       int (*init)(struct et61x251_device* cam);
-       int (*get_ctrl)(struct et61x251_device* cam,
-                       struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct et61x251_device* cam,
-                       const struct v4l2_control* ctrl);
-       int (*set_crop)(struct et61x251_device* cam,
-                       const struct v4l2_rect* rect);
-       int (*set_pix_format)(struct et61x251_device* cam,
-                             const struct v4l2_pix_format* pix);
-
-       /* Private */
-       struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/usb/media/et61x251_tas5130d1b.c b/drivers/usb/media/et61x251_tas5130d1b.c
deleted file mode 100644 (file)
index 3998d76..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51        *
- * PC Camera Controllers                                                   *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "et61x251_sensor.h"
-
-
-static int tas5130d1b_init(struct et61x251_device* cam)
-{
-       int err = 0;
-
-       err += et61x251_write_reg(cam, 0x14, 0x01);
-       err += et61x251_write_reg(cam, 0x1b, 0x02);
-       err += et61x251_write_reg(cam, 0x02, 0x12);
-       err += et61x251_write_reg(cam, 0x0e, 0x60);
-       err += et61x251_write_reg(cam, 0x80, 0x61);
-       err += et61x251_write_reg(cam, 0xf0, 0x62);
-       err += et61x251_write_reg(cam, 0x03, 0x63);
-       err += et61x251_write_reg(cam, 0x14, 0x64);
-       err += et61x251_write_reg(cam, 0xf4, 0x65);
-       err += et61x251_write_reg(cam, 0x01, 0x66);
-       err += et61x251_write_reg(cam, 0x05, 0x67);
-       err += et61x251_write_reg(cam, 0x8f, 0x68);
-       err += et61x251_write_reg(cam, 0x0f, 0x8d);
-       err += et61x251_write_reg(cam, 0x08, 0x8e);
-
-       return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
-                               const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               err += et61x251_i2c_raw_write(cam, 2, 0x20,
-                                             0xf6-ctrl->value, 0, 0, 0,
-                                             0, 0, 0, 0);
-               break;
-       case V4L2_CID_EXPOSURE:
-               err += et61x251_i2c_raw_write(cam, 2, 0x40,
-                                             0x47-ctrl->value, 0, 0, 0,
-                                             0, 0, 0, 0);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static struct et61x251_sensor tas5130d1b = {
-       .name = "TAS5130D1B",
-       .interface = ET61X251_I2C_3WIRES,
-       .rsta = ET61X251_I2C_RSTA_STOP,
-       .active_pixel = {
-               .left = 106,
-               .top = 13,
-       },
-       .init = &tas5130d1b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0xf6,
-                       .step = 0x02,
-                       .default_value = 0x0d,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = 0x47,
-                       .step = 0x01,
-                       .default_value = 0x23,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &tas5130d1b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-};
-
-
-int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
-{
-       const struct usb_device_id tas5130d1b_id_table[] = {
-               { USB_DEVICE(0x102c, 0x6251), },
-               { }
-       };
-
-       /* Sensor detection is based on USB pid/vid */
-       if (!et61x251_match_id(cam, tas5130d1b_id_table))
-               return -ENODEV;
-
-       et61x251_attach_sensor(cam, &tas5130d1b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c
deleted file mode 100644 (file)
index a42c222..0000000
+++ /dev/null
@@ -1,3932 +0,0 @@
-/*
- * USB IBM C-It Video Camera driver
- *
- * Supports Xirlink C-It Video Camera, IBM PC Camera,
- * IBM NetCamera and Veo Stingray.
- *
- * This driver is based on earlier work of:
- *
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- *
- * 5/24/00 Removed optional (and unnecessary) locking of the driver while
- * the device remains plugged in. Corrected race conditions in ibmcam_open
- * and ibmcam_probe() routines using this as a guideline:
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define IBMCAM_VENDOR_ID       0x0545
-#define IBMCAM_PRODUCT_ID      0x8080
-#define NETCAM_PRODUCT_ID      0x8002  /* IBM NetCamera, close to model 2 */
-#define VEO_800C_PRODUCT_ID    0x800C  /* Veo Stingray, repackaged Model 2 */
-#define VEO_800D_PRODUCT_ID    0x800D  /* Veo Stingray, repackaged Model 4 */
-
-#define MAX_IBMCAM             4       /* How many devices we allow to connect */
-#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
-
-/* Header signatures */
-
-/* Model 1 header: 00 FF 00 xx */
-#define HDRSIG_MODEL1_128x96   0x06    /* U Y V Y ... */
-#define HDRSIG_MODEL1_176x144  0x0e    /* U Y V Y ... */
-#define HDRSIG_MODEL1_352x288  0x00    /* V Y U Y ... */
-
-#define        IBMCAM_MODEL_1  1       /* XVP-501, 3 interfaces, rev. 0.02 */
-#define IBMCAM_MODEL_2 2       /* KSX-X9903, 2 interfaces, rev. 3.0a */
-#define IBMCAM_MODEL_3 3       /* KSX-X9902, 2 interfaces, rev. 3.01 */
-#define        IBMCAM_MODEL_4  4       /* IBM NetCamera, 0545/8002/3.0a */
-
-/* Video sizes supported */
-#define        VIDEOSIZE_128x96        VIDEOSIZE(128, 96)
-#define        VIDEOSIZE_176x144       VIDEOSIZE(176,144)
-#define        VIDEOSIZE_352x288       VIDEOSIZE(352,288)
-#define        VIDEOSIZE_320x240       VIDEOSIZE(320,240)
-#define        VIDEOSIZE_352x240       VIDEOSIZE(352,240)
-#define        VIDEOSIZE_640x480       VIDEOSIZE(640,480)
-#define        VIDEOSIZE_160x120       VIDEOSIZE(160,120)
-
-/* Video sizes supported */
-enum {
-       SIZE_128x96 = 0,
-       SIZE_160x120,
-       SIZE_176x144,
-       SIZE_320x240,
-       SIZE_352x240,
-       SIZE_352x288,
-       SIZE_640x480,
-       /* Add/remove/rearrange items before this line */
-       SIZE_LastItem
-};
-
-/*
- * This structure lives in uvd->user field.
- */
-typedef struct {
-       int initialized;        /* Had we already sent init sequence? */
-       int camera_model;       /* What type of IBM camera we got? */
-       int has_hdr;
-} ibmcam_t;
-#define        IBMCAM_T(uvd)   ((ibmcam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams;
-
-static int debug;
-
-static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth  = 8;
-static const int min_canvasHeight = 4;
-
-static int lighting = 1; /* Medium */
-
-#define SHARPNESS_MIN  0
-#define SHARPNESS_MAX  6
-static int sharpness = 4; /* Low noise, good details */
-
-#define FRAMERATE_MIN  0
-#define FRAMERATE_MAX  6
-static int framerate = -1;
-
-static int size = SIZE_352x288;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-/* Settings for camera model 2 */
-static int init_model2_rg2 = -1;
-static int init_model2_sat = -1;
-static int init_model2_yb = -1;
-
-/* 01.01.08 - Added for RCA video in support -LO */
-/* Settings for camera model 3 */
-static int init_model3_input = 0;
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-module_param(lighting, int, 0);
-MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480  (default=5)");
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-module_param(init_model2_rg2, int, 0);
-MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
-module_param(init_model2_sat, int, 0);
-MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
-module_param(init_model2_yb, int, 0);
-MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
-
-/* 01.01.08 - Added for RCA video in support -LO */
-module_param(init_model3_input, int, 0);
-MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
-
-MODULE_AUTHOR ("Dmitri");
-MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
-MODULE_LICENSE("GPL");
-
-/* Still mysterious i2c commands */
-static const unsigned short unknown_88 = 0x0088;
-static const unsigned short unknown_89 = 0x0089;
-static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
-static const unsigned short contrast_14 = 0x0014;
-static const unsigned short light_27 = 0x0027;
-static const unsigned short sharp_13 = 0x0013;
-
-/* i2c commands for Model 2 cameras */
-static const unsigned short mod2_brightness = 0x001a;          /* $5b .. $ee; default=$5a */
-static const unsigned short mod2_set_framerate = 0x001c;       /* 0 (fast).. $1F (slow) */
-static const unsigned short mod2_color_balance_rg2 = 0x001e;   /* 0 (red) .. $7F (green) */
-static const unsigned short mod2_saturation = 0x0020;          /* 0 (b/w) - $7F (full color) */
-static const unsigned short mod2_color_balance_yb = 0x0022;    /* 0..$7F, $50 is about right */
-static const unsigned short mod2_hue = 0x0024;                 /* 0..$7F, $70 is about right */
-static const unsigned short mod2_sensitivity = 0x0028;         /* 0 (min) .. $1F (max) */
-
-struct struct_initData {
-       unsigned char req;
-       unsigned short value;
-       unsigned short index;
-};
-
-/*
- * ibmcam_size_to_videosize()
- *
- * This procedure converts module option 'size' into the actual
- * videosize_t that defines the image size in pixels. We need
- * simplified 'size' because user wants a simple enumerated list
- * of choices, not an infinite set of possibilities.
- */
-static videosize_t ibmcam_size_to_videosize(int size)
-{
-       videosize_t vs = VIDEOSIZE_352x288;
-       RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
-       switch (size) {
-       case SIZE_128x96:
-               vs = VIDEOSIZE_128x96;
-               break;
-       case SIZE_160x120:
-               vs = VIDEOSIZE_160x120;
-               break;
-       case SIZE_176x144:
-               vs = VIDEOSIZE_176x144;
-               break;
-       case SIZE_320x240:
-               vs = VIDEOSIZE_320x240;
-               break;
-       case SIZE_352x240:
-               vs = VIDEOSIZE_352x240;
-               break;
-       case SIZE_352x288:
-               vs = VIDEOSIZE_352x288;
-               break;
-       case SIZE_640x480:
-               vs = VIDEOSIZE_640x480;
-               break;
-       default:
-               err("size=%d. is not valid", size);
-               break;
-       }
-       return vs;
-}
-
-/*
- * ibmcam_find_header()
- *
- * Locate one of supported header markers in the queue.
- * Once found, remove all preceding bytes AND the marker (4 bytes)
- * from the data pump queue. Whatever follows must be video lines.
- *
- * History:
- * 1/21/00  Created.
- */
-static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
-{
-       struct usbvideo_frame *frame;
-       ibmcam_t *icam;
-
-       if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-               err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
-               return scan_EndParse;
-       }
-       icam = IBMCAM_T(uvd);
-       assert(icam != NULL);
-       frame = &uvd->frame[uvd->curframe];
-       icam->has_hdr = 0;
-       switch (icam->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               const int marker_len = 4;
-               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
-                       {
-#if 0                          /* This code helps to detect new frame markers */
-                               info("Header sig: 00 FF 00 %02X", RING_QUEUE_PEEK(&uvd->dp, 3));
-#endif
-                               frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
-                               if ((frame->header == HDRSIG_MODEL1_128x96) ||
-                                   (frame->header == HDRSIG_MODEL1_176x144) ||
-                                   (frame->header == HDRSIG_MODEL1_352x288))
-                               {
-#if 0
-                                       info("Header found.");
-#endif
-                                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
-                                       icam->has_hdr = 1;
-                                       break;
-                               }
-                       }
-                       /* If we are still here then this doesn't look like a header */
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
-       {
-               int marker_len = 0;
-               switch (uvd->videosize) {
-               case VIDEOSIZE_176x144:
-                       marker_len = 10;
-                       break;
-               default:
-                       marker_len = 2;
-                       break;
-               }
-               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
-                       {
-#if 0
-                               info("Header found.");
-#endif
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
-                               icam->has_hdr = 1;
-                               frame->header = HDRSIG_MODEL1_176x144;
-                               break;
-                       }
-                       /* If we are still here then this doesn't look like a header */
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_3:
-       {       /*
-                * Headers: (one precedes every frame). nc=no compression,
-                * bq=best quality bf=best frame rate.
-                *
-                * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
-                * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
-                * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
-                *
-                * Bytes '00 FF' seem to indicate header. Other two bytes
-                * encode the frame type. This is a set of bit fields that
-                * encode image size, compression type etc. These fields
-                * do NOT contain frame number because all frames carry
-                * the same header.
-                */
-               const int marker_len = 4;
-               while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
-                       {
-                               /*
-                                * Combine 2 bytes of frame type into one
-                                * easy to use value
-                                */
-                               unsigned long byte3, byte4;
-
-                               byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
-                               byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
-                               frame->header = (byte3 << 8) | byte4;
-#if 0
-                               info("Header found.");
-#endif
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
-                               icam->has_hdr = 1;
-                               break;
-                       }
-                       /* If we are still here then this doesn't look like a header */
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-               }
-               break;
-       }
-       default:
-               break;
-       }
-       if (!icam->has_hdr) {
-               if (uvd->debug > 2)
-                       info("Skipping frame, no header");
-               return scan_EndParse;
-       }
-
-       /* Header found */
-       icam->has_hdr = 1;
-       uvd->stats.header_count++;
-       frame->scanstate = ScanState_Lines;
-       frame->curline = 0;
-
-       if (flags & FLAGS_FORCE_TESTPATTERN) {
-               usbvideo_TestPattern(uvd, 1, 1);
-               return scan_NextFrame;
-       }
-       return scan_Continue;
-}
-
-/*
- * ibmcam_parse_lines()
- *
- * Parse one line (interlaced) from the buffer, put
- * decoded RGB value into the current frame buffer
- * and add the written number of bytes (RGB) to
- * the *pcopylen.
- *
- * History:
- * 21-Jan-2000 Created.
- * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
- */
-static enum ParseState ibmcam_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       unsigned char *f;
-       ibmcam_t *icam;
-       unsigned int len, scanLength, scanHeight, order_uv, order_yc;
-       int v4l_linesize; /* V4L line offset */
-       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
-       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
-       const int ccm = 128; /* Color correction median - see below */
-       int y, u, v, i, frame_done=0, color_corr;
-       static unsigned char lineBuffer[640*3];
-       unsigned const char *chromaLine, *lumaLine;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-       icam = IBMCAM_T(uvd);
-       assert(icam != NULL);
-       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
-               /* Model 4 frame markers do not carry image size identification */
-               switch (uvd->videosize) {
-               case VIDEOSIZE_128x96:
-               case VIDEOSIZE_160x120:
-               case VIDEOSIZE_176x144:
-                       scanLength = VIDEOSIZE_X(uvd->videosize);
-                       scanHeight = VIDEOSIZE_Y(uvd->videosize);
-                       break;
-               default:
-                       err("ibmcam_parse_lines: Wrong mode.");
-                       return scan_Out;
-               }
-               order_yc = 1;   /* order_yc: true=Yc false=cY ('c'=either U or V) */
-               order_uv = 1;   /* Always true in this algorithm */
-       } else {
-               switch (frame->header) {
-               case HDRSIG_MODEL1_128x96:
-                       scanLength = 128;
-                       scanHeight = 96;
-                       order_uv = 1;   /* U Y V Y ... */
-                       break;
-               case HDRSIG_MODEL1_176x144:
-                       scanLength = 176;
-                       scanHeight = 144;
-                       order_uv = 1;   /* U Y V Y ... */
-                       break;
-               case HDRSIG_MODEL1_352x288:
-                       scanLength = 352;
-                       scanHeight = 288;
-                       order_uv = 0;   /* Y V Y V ... */
-                       break;
-               default:
-                       err("Unknown header signature 00 FF 00 %02lX", frame->header);
-                       return scan_NextFrame;
-               }
-               /* order_yc: true=Yc false=cY ('c'=either U or V) */
-               order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
-       }
-
-       len = scanLength * 3;
-       assert(len <= sizeof(lineBuffer));
-
-       /*
-        * Lines are organized this way:
-        *
-        * I420:
-        * ~~~~
-        * <scanLength->
-        * ___________________________________
-        * |-----Y-----|---UVUVUV...UVUV-----| \
-        * |-----------+---------------------|  \
-        * |<-- 176 -->|<------ 176*2 ------>|  Total 72. lines (interlaced)
-        * |...    ... |        ...          |  /
-        * |<-- 352 -->|<------ 352*2 ------>|  Total 144. lines (interlaced)
-        * |___________|_____________________| /
-        *  \           \
-        *   lumaLine    chromaLine
-        */
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Mind that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
-               return scan_NextFrame;
-
-       /*
-        * Now we are sure that entire line (representing all 'scanLength'
-        * pixels from the camera) is available in the buffer. We
-        * start copying the line left-aligned to the V4L buffer.
-        * If the camera line is shorter then we should pad the V4L
-        * buffer with something (black) to complete the line.
-        */
-       assert(frame->data != NULL);
-       f = frame->data + (v4l_linesize * frame->curline);
-
-       /*
-        * To obtain chrominance data from the 'chromaLine' use this:
-        *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
-        *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
-        *
-        * Indices must be calculated this way:
-        * v_index = (i >> 1) << 2;
-        * u_index = (i >> 1) << 2 + 2;
-        *
-        * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
-        */
-       lumaLine = lineBuffer;
-       chromaLine = lineBuffer + scanLength;
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
-       {
-               unsigned char rv, gv, bv;       /* RGB components */
-
-               /* Check for various visual debugging hints (colorized pixels) */
-               if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
-                       /*
-                        * This is bad and should not happen. This means that
-                        * we somehow overshoot the line and encountered new
-                        * frame! Obviously our camera/V4L frame size is out
-                        * of whack. This cyan dot will help you to figure
-                        * out where exactly the new frame arrived.
-                        */
-                       if (icam->has_hdr == 1) {
-                               bv = 0; /* Yellow marker */
-                               gv = 0xFF;
-                               rv = 0xFF;
-                       } else {
-                               bv = 0xFF; /* Cyan marker */
-                               gv = 0xFF;
-                               rv = 0;
-                       }
-                       icam->has_hdr = 0;
-                       goto make_pixel;
-               }
-
-               /*
-                * Check if we are still in range. We may be out of range if our
-                * V4L canvas is wider or taller than the camera "native" image.
-                * Then we quickly fill the remainder of the line with zeros to
-                * make black color and quit the horizontal scanning loop.
-                */
-               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
-                       const int j = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
-                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
-                       f = frame->data + (v4l_linesize * frame->curline) + j;
-#endif
-                       memset(f, 0, v4l_linesize - j);
-                       break;
-               }
-
-               y = lumaLine[i];
-               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
-                       rv = gv = bv = y;
-               else {
-                       int off_0, off_2;
-
-                       off_0 = (i >> 1) << 2;
-                       off_2 = off_0 + 2;
-
-                       if (order_yc) {
-                               off_0++;
-                               off_2++;
-                       }
-                       if (!order_uv) {
-                               off_0 += 2;
-                               off_2 -= 2;
-                       }
-                       u = chromaLine[off_0] + hue_corr;
-                       v = chromaLine[off_2] + hue2_corr;
-
-                       /* Apply color correction */
-                       if (color_corr != 0) {
-                               /* Magnify up to 2 times, reduce down to zero saturation */
-                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
-                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
-                       }
-                       YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
-               }
-
-       make_pixel:
-               /*
-                * The purpose of creating the pixel here, in one,
-                * dedicated place is that we may need to make the
-                * pixel wider and taller than it actually is. This
-                * may be used if camera generates small frames for
-                * sake of frame rate (or any other reason.)
-                *
-                * The output data consists of B, G, R bytes
-                * (in this order).
-                */
-#if USES_IBMCAM_PUTPIXEL
-               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-#else
-               *f++ = bv;
-               *f++ = gv;
-               *f++ = rv;
-#endif
-               /*
-                * Typically we do not decide within a legitimate frame
-                * that we want to end the frame. However debugging code
-                * may detect marker of new frame within the data. Then
-                * this condition activates. The 'data' pointer is already
-                * pointing at the new marker, so we'd better leave it as is.
-                */
-               if (frame_done)
-                       break;  /* End scanning of lines */
-       }
-       /*
-        * Account for number of bytes that we wrote into output V4L frame.
-        * We do it here, after we are done with the scanline, because we
-        * may fill more than one output scanline if we do vertical
-        * enlargement.
-        */
-       frame->curline += 2;
-       if (pcopylen != NULL)
-               *pcopylen += 2 * v4l_linesize;
-       frame->deinterlace = Deinterlace_FillOddLines;
-
-       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
-               return scan_NextFrame;
-       else
-               return scan_Continue;
-}
-
-/*
- * ibmcam_model2_320x240_parse_lines()
- *
- * This procedure deals with a weird RGB format that is produced by IBM
- * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
- * depending on horizontal size of the picture:
- *
- * <--- 160 or 176 pairs of RA,RB bytes ----->
- * *-----------------------------------------* \
- * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \   This is pair of horizontal lines,
- * |-----+-----+-----+-----+ ... +-----+-----|   *- or one interlaced line, total
- * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   120 or 144 such pairs which yield
- * |=====+=====+=====+=====+ ... +=====+=====| /    240 or 288 lines after deinterlacing.
- *
- * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
- * defines ONE pixel. Therefore this format yields 176x144 "decoded"
- * resolution at best. I do not know why camera sends such format - the
- * previous model (1) just used interlaced I420 and everyone was happy.
- *
- * I do not know what is the difference between RAi and RBi bytes. Both
- * seemingly represent R component, but slightly vary in value (so that
- * the picture looks a bit colored if one or another is used). I use
- * them both as R component in attempt to at least partially recover the
- * lost resolution.
- */
-static enum ParseState ibmcam_model2_320x240_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       unsigned char *f, *la, *lb;
-       unsigned int len;
-       int v4l_linesize; /* V4L line offset */
-       int i, j, frame_done=0, color_corr;
-       int scanLength, scanHeight;
-       static unsigned char lineBuffer[352*2];
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_320x240:
-       case VIDEOSIZE_352x240:
-       case VIDEOSIZE_352x288:
-               scanLength = VIDEOSIZE_X(uvd->videosize);
-               scanHeight = VIDEOSIZE_Y(uvd->videosize);
-               break;
-       default:
-               err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
-               return scan_Out;
-       }
-
-       color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       len = scanLength * 2; /* See explanation above */
-       assert(len <= sizeof(lineBuffer));
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Mind that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
-               return scan_NextFrame;
-
-       la = lineBuffer;
-       lb = lineBuffer + scanLength;
-
-       /*
-        * Now we are sure that entire line (representing all
-        *         VIDEOSIZE_X(frame->request)
-        * pixels from the camera) is available in the scratch buffer. We
-        * start copying the line left-aligned to the V4L buffer (which
-        * might be larger - not smaller, hopefully). If the camera
-        * line is shorter then we should pad the V4L buffer with something
-        * (black in this case) to complete the line.
-        */
-       f = frame->data + (v4l_linesize * frame->curline);
-
-       /* Fill the 2-line strip */
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-               int y, rv, gv, bv;      /* RGB components */
-
-               j = i & (~1);
-
-               /* Check for various visual debugging hints (colorized pixels) */
-               if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
-                       if (IBMCAM_T(uvd)->has_hdr == 1) {
-                               bv = 0; /* Yellow marker */
-                               gv = 0xFF;
-                               rv = 0xFF;
-                       } else {
-                               bv = 0xFF; /* Cyan marker */
-                               gv = 0xFF;
-                               rv = 0;
-                       }
-                       IBMCAM_T(uvd)->has_hdr = 0;
-                       goto make_pixel;
-               }
-
-               /*
-                * Check if we are still in range. We may be out of range if our
-                * V4L canvas is wider or taller than the camera "native" image.
-                * Then we quickly fill the remainder of the line with zeros to
-                * make black color and quit the horizontal scanning loop.
-                */
-               if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
-                       const int j = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
-                       /* Refresh 'f' because we don't use it much with PUTPIXEL */
-                       f = frame->data + (v4l_linesize * frame->curline) + j;
-#endif
-                       memset(f, 0, v4l_linesize - j);
-                       break;
-               }
-
-               /*
-                * Here I use RA and RB components, one per physical pixel.
-                * This causes fine vertical grid on the picture but may improve
-                * horizontal resolution. If you prefer replicating, use this:
-                *   rv = la[j + 0];   ... or ... rv = la[j + 1];
-                * then the pixel will be replicated.
-                */
-               rv = la[i];
-               gv = lb[j + 1];
-               bv = lb[j + 0];
-
-               y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
-
-               if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
-                       rv = gv = bv = y;
-               else if (color_corr != 128) {
-
-                       /* Calculate difference between color and brightness */
-                       rv -= y;
-                       gv -= y;
-                       bv -= y;
-
-                       /* Scale differences */
-                       rv = (rv * color_corr) / 128;
-                       gv = (gv * color_corr) / 128;
-                       bv = (bv * color_corr) / 128;
-
-                       /* Reapply brightness */
-                       rv += y;
-                       gv += y;
-                       bv += y;
-
-                       /* Watch for overflows */
-                       RESTRICT_TO_RANGE(rv, 0, 255);
-                       RESTRICT_TO_RANGE(gv, 0, 255);
-                       RESTRICT_TO_RANGE(bv, 0, 255);
-               }
-
-       make_pixel:
-               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-       }
-       /*
-        * Account for number of bytes that we wrote into output V4L frame.
-        * We do it here, after we are done with the scanline, because we
-        * may fill more than one output scanline if we do vertical
-        * enlargement.
-        */
-       frame->curline += 2;
-       *pcopylen += v4l_linesize * 2;
-       frame->deinterlace = Deinterlace_FillOddLines;
-
-       if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
-               return scan_NextFrame;
-       else
-               return scan_Continue;
-}
-
-static enum ParseState ibmcam_model3_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       unsigned char *data;
-       const unsigned char *color;
-       unsigned int len;
-       int v4l_linesize; /* V4L line offset */
-       const int hue_corr  = (uvd->vpic.hue - 0x8000) >> 10;   /* -32..+31 */
-       const int hue2_corr = (hue_correction - 128) / 4;               /* -32..+31 */
-       const int ccm = 128; /* Color correction median - see below */
-       int i, u, v, rw, data_w=0, data_h=0, color_corr;
-       static unsigned char lineBuffer[640*3];
-
-       color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       /* The header tells us what sort of data is in this frame */
-       switch (frame->header) {
-               /*
-                * Uncompressed modes (that are easy to decode).
-                */
-       case 0x0308:
-               data_w = 640;
-               data_h = 480;
-               break;
-       case 0x0208:
-               data_w = 320;
-               data_h = 240;
-               break;
-       case 0x020A:
-               data_w = 160;
-               data_h = 120;
-               break;
-               /*
-                * Compressed modes (ViCE - that I don't know how to decode).
-                */
-       case 0x0328:    /* 640x480, best quality compression */
-       case 0x0368:    /* 640x480, best frame rate compression */
-       case 0x0228:    /* 320x240, best quality compression */
-       case 0x0268:    /* 320x240, best frame rate compression */
-       case 0x02CA:    /* 160x120, best quality compression */
-       case 0x02EA:    /* 160x120, best frame rate compression */
-               /* Do nothing with this - not supported */
-               err("Unsupported mode $%04lx", frame->header);
-               return scan_NextFrame;
-       default:
-               /* Catch unknown headers, may help in learning new headers */
-               err("Strange frame->header=$%08lx", frame->header);
-               return scan_NextFrame;
-       }
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Note that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 1) >= data_h) {
-               if (uvd->debug >= 3)
-                       info("Reached line %d. (frame is done)", frame->curline);
-               return scan_NextFrame;
-       }
-
-       /* Make sure there's enough data for the entire line */
-       len = 3 * data_w; /* <y-data> <uv-data> */
-       assert(len <= sizeof(lineBuffer));
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       data = lineBuffer;
-       color = data + data_w;          /* Point to where color planes begin */
-
-       /* Bottom-to-top scanning */
-       rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
-       RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
-
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-               int y, rv, gv, bv;      /* RGB components */
-
-               if (i < data_w) {
-                       y = data[i];    /* Luminosity is the first line */
-
-                       /* Apply static color correction */
-                       u = color[i*2] + hue_corr;
-                       v = color[i*2 + 1] + hue2_corr;
-
-                       /* Apply color correction */
-                       if (color_corr != 0) {
-                               /* Magnify up to 2 times, reduce down to zero saturation */
-                               u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
-                               v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
-                       }
-               } else
-                       y = 0, u = v = 128;
-
-               YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
-               RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
-       }
-       frame->deinterlace = Deinterlace_FillEvenLines;
-
-       /*
-        * Account for number of bytes that we wrote into output V4L frame.
-        * We do it here, after we are done with the scanline, because we
-        * may fill more than one output scanline if we do vertical
-        * enlargement.
-        */
-       frame->curline += 2;
-       *pcopylen += 2 * v4l_linesize;
-
-       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
-               if (uvd->debug >= 3) {
-                       info("All requested lines (%ld.) done.",
-                            VIDEOSIZE_Y(frame->request));
-               }
-               return scan_NextFrame;
-       } else
-               return scan_Continue;
-}
-
-/*
- * ibmcam_model4_128x96_parse_lines()
- *
- * This decoder is for one strange data format that is produced by Model 4
- * camera only in 128x96 mode. This is RGB format and here is its description.
- * First of all, this is non-interlaced stream, meaning that all scan lines
- * are present in the datastream. There are 96 consecutive blocks of data
- * that describe all 96 lines of the image. Each block is 5*128 bytes long
- * and carries R, G, B components. The format of the block is shown in the
- * code below. First 128*2 bytes are interleaved R and G components. Then
- * we have a gap (junk data) 64 bytes long. Then follow B and something
- * else, also interleaved (this makes another 128*2 bytes). After that
- * probably another 64 bytes of junk follow.
- *
- * History:
- * 10-Feb-2001 Created.
- */
-static enum ParseState ibmcam_model4_128x96_parse_lines(
-       struct uvd *uvd,
-       struct usbvideo_frame *frame,
-       long *pcopylen)
-{
-       const unsigned char *data_rv, *data_gv, *data_bv;
-       unsigned int len;
-       int i, v4l_linesize; /* V4L line offset */
-       const int data_w=128, data_h=96;
-       static unsigned char lineBuffer[128*5];
-
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
-       /*
-        * Make sure that our writing into output buffer
-        * will not exceed the buffer. Note that we may write
-        * not into current output scanline but in several after
-        * it as well (if we enlarge image vertically.)
-        */
-       if ((frame->curline + 1) >= data_h) {
-               if (uvd->debug >= 3)
-                       info("Reached line %d. (frame is done)", frame->curline);
-               return scan_NextFrame;
-       }
-
-       /*
-        * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
-        * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
-        */
-
-       /* Make sure there's enough data for the entire line */
-       len = 5 * data_w;
-       assert(len <= sizeof(lineBuffer));
-
-       /* Make sure there's enough data for the entire line */
-       if (RingQueue_GetLength(&uvd->dp) < len)
-               return scan_Out;
-
-       /* Suck one line out of the ring queue */
-       RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
-       data_rv = lineBuffer;
-       data_gv = lineBuffer + 1;
-       data_bv = lineBuffer + data_w*2 + data_w/2;
-       for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
-               int rv, gv, bv; /* RGB components */
-               if (i < data_w) {
-                       const int j = i * 2;
-                       gv = data_rv[j];
-                       rv = data_gv[j];
-                       bv = data_bv[j];
-                       if (flags & FLAGS_MONOCHROME) {
-                               unsigned long y;
-                               y = rv + gv + bv;
-                               y /= 3;
-                               if (y > 0xFF)
-                                       y = 0xFF;
-                               rv = gv = bv = (unsigned char) y;
-                       }
-               } else {
-                       rv = gv = bv = 0;
-               }
-               RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-       }
-       frame->deinterlace = Deinterlace_None;
-       frame->curline++;
-       *pcopylen += v4l_linesize;
-
-       if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
-               if (uvd->debug >= 3) {
-                       info("All requested lines (%ld.) done.",
-                            VIDEOSIZE_Y(frame->request));
-               }
-               return scan_NextFrame;
-       } else
-               return scan_Continue;
-}
-
-/*
- * ibmcam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ibmcam_find_header() or ibmcam_parse_lines() to do most
- * of work.
- *
- * History:
- * 1/21/00  Created.
- */
-static void ibmcam_ProcessIsocData(struct uvd *uvd,
-                                  struct usbvideo_frame *frame)
-{
-       enum ParseState newstate;
-       long copylen = 0;
-       int mod = IBMCAM_T(uvd)->camera_model;
-
-       while (1) {
-               newstate = scan_Out;
-               if (RingQueue_GetLength(&uvd->dp) > 0) {
-                       if (frame->scanstate == ScanState_Scanning) {
-                               newstate = ibmcam_find_header(uvd);
-                       } else if (frame->scanstate == ScanState_Lines) {
-                               if ((mod == IBMCAM_MODEL_2) &&
-                                   ((uvd->videosize == VIDEOSIZE_352x288) ||
-                                    (uvd->videosize == VIDEOSIZE_320x240) ||
-                                    (uvd->videosize == VIDEOSIZE_352x240)))
-                               {
-                                       newstate = ibmcam_model2_320x240_parse_lines(
-                                               uvd, frame, &copylen);
-                               } else if (mod == IBMCAM_MODEL_4) {
-                                       /*
-                                        * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
-                                        * for 320x240 and above; 160x120 and 176x144 uses Model 1
-                                        * decoder (YUV), and 128x96 mode uses ???
-                                        */
-                                       if ((uvd->videosize == VIDEOSIZE_352x288) ||
-                                           (uvd->videosize == VIDEOSIZE_320x240) ||
-                                           (uvd->videosize == VIDEOSIZE_352x240))
-                                       {
-                                               newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
-                                       } else if (uvd->videosize == VIDEOSIZE_128x96) {
-                                               newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
-                                       } else {
-                                               newstate = ibmcam_parse_lines(uvd, frame, &copylen);
-                                       }
-                               } else if (mod == IBMCAM_MODEL_3) {
-                                       newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
-                               } else {
-                                       newstate = ibmcam_parse_lines(uvd, frame, &copylen);
-                               }
-                       }
-               }
-               if (newstate == scan_Continue)
-                       continue;
-               else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
-                       break;
-               else
-                       return; /* scan_EndParse */
-       }
-
-       if (newstate == scan_NextFrame) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-               if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
-                       /* Need software contrast adjustment for those cameras */
-                       frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
-               }
-       }
-
-       /* Update the frame's uncompressed length. */
-       frame->seqRead_Length += copylen;
-
-#if 0
-       {
-               static unsigned char j=0;
-               memset(frame->data, j++, uvd->max_frame_size);
-               frame->frameState = FrameState_Ready;
-       }
-#endif
-}
-
-/*
- * ibmcam_veio()
- *
- * History:
- * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ibmcam_veio(
-       struct uvd *uvd,
-       unsigned char req,
-       unsigned short value,
-       unsigned short index)
-{
-       static const char proc[] = "ibmcam_veio";
-       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
-       int i;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return 0;
-
-       if (req == 1) {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_rcvctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
-                       value,
-                       index,
-                       cp,
-                       sizeof(cp),
-                       1000);
-#if 0
-               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)",
-                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-                      req, value, index);
-#endif
-       } else {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_sndctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
-                       value,
-                       index,
-                       NULL,
-                       0,
-                       1000);
-       }
-       if (i < 0) {
-               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
-                   proc, i);
-               uvd->last_error = i;
-       }
-       return i;
-}
-
-/*
- * ibmcam_calculate_fps()
- *
- * This procedure roughly calculates the real frame rate based
- * on FPS code (framerate=NNN option). Actual FPS differs
- * slightly depending on lighting conditions, so that actual frame
- * rate is determined by the camera. Since I don't know how to ask
- * the camera what FPS is now I have to use the FPS code instead.
- *
- * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
- * Corresponding real FPS should be in range [3..30] frames per second.
- * The conversion formula is obvious:
- *
- * real_fps = 3 + (fps_code * 4.5)
- *
- * History:
- * 1/18/00  Created.
- */
-static int ibmcam_calculate_fps(struct uvd *uvd)
-{
-       return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ibmcam_send_FF_04_02()
- *
- * This procedure sends magic 3-command prefix to the camera.
- * The purpose of this prefix is not known.
- *
- * History:
- * 1/2/00   Created.
- */
-static void ibmcam_send_FF_04_02(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
-       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_00_04_06(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-       ibmcam_veio(uvd, 0, 0x0004, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0006, 0x0124);
-}
-
-static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-}
-
-static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_send_x_00(uvd, x);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
-{
-       ibmcam_veio(uvd, 0, x,      0x0127);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0008, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
-       ibmcam_send_x_01_00_05(uvd, unknown_88);
-       ibmcam_send_x_00_05(uvd, fkey);
-       ibmcam_send_x_00_05_02_08_01(uvd, val);
-       ibmcam_send_x_00_05(uvd, unknown_88);
-       ibmcam_send_x_00_05_02_01(uvd, fkey);
-       ibmcam_send_x_00_05(uvd, unknown_89);
-       ibmcam_send_x_00(uvd, fkey);
-       ibmcam_send_00_04_06(uvd);
-       ibmcam_veio(uvd, 1, 0x0000, 0x0126);
-       ibmcam_send_FF_04_02(uvd);
-}
-
-static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
-       ibmcam_send_x_01_00_05  (uvd, unknown_88);
-       ibmcam_send_x_00_05     (uvd, fkey);
-       ibmcam_send_x_00_05_02  (uvd, val);
-}
-
-static void ibmcam_model2_Packet2(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
-       ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
-}
-
-static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
-       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-       ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
-       ibmcam_veio(uvd, 0, v1,     0x012f);
-       ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
-       ibmcam_veio(uvd, 0, 0xc719, 0x0124);
-       ibmcam_veio(uvd, 0, v2,     0x0127);
-
-       ibmcam_model2_Packet2(uvd);
-}
-
-/*
- * ibmcam_model3_Packet1()
- *
- * 00_0078_012d        
- * 00_0097_012f
- * 00_d141_0124        
- * 00_0096_0127
- * 00_fea8_0124        
-*/
-static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
-       ibmcam_veio(uvd, 0, 0x0078, 0x012d);
-       ibmcam_veio(uvd, 0, v1,     0x012f);
-       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-       ibmcam_veio(uvd, 0, v2,     0x0127);
-       ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-}
-
-static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
-{
-       ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-       ibmcam_veio(uvd, 0, 0x0026, 0x012f);
-       ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-       ibmcam_veio(uvd, 0, i,      0x0127);
-       ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-       ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-       ibmcam_veio(uvd, 0, 0x0038, 0x012d);
-       ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-       ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-       ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-}
-
-/*
- * ibmcam_adjust_contrast()
- *
- * The contrast value changes from 0 (high contrast) to 15 (low contrast).
- * This is in reverse to usual order of things (such as TV controls), so
- * we reverse it again here.
- *
- * TODO: we probably don't need to send the setup 5 times...
- *
- * History:
- * 1/2/00   Created.
- */
-static void ibmcam_adjust_contrast(struct uvd *uvd)
-{
-       unsigned char a_contrast = uvd->vpic.contrast >> 12;
-       unsigned char new_contrast;
-
-       if (a_contrast >= 16)
-               a_contrast = 15;
-       new_contrast = 15 - a_contrast;
-       if (new_contrast == uvd->vpic_old.contrast)
-               return;
-       uvd->vpic_old.contrast = new_contrast;
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               const int ntries = 5;
-               int i;
-               for (i=0; i < ntries; i++) {
-                       ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
-                       ibmcam_send_FF_04_02(uvd);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_2:
-       case IBMCAM_MODEL_4:
-               /* Models 2, 4 do not have this control; implemented in software. */
-               break;
-       case IBMCAM_MODEL_3:
-       {       /* Preset hardware values */
-               static const struct {
-                       unsigned short cv1;
-                       unsigned short cv2;
-                       unsigned short cv3;
-               } cv[7] = {
-                       { 0x05, 0x05, 0x0f },   /* Minimum */
-                       { 0x04, 0x04, 0x16 },
-                       { 0x02, 0x03, 0x16 },
-                       { 0x02, 0x08, 0x16 },
-                       { 0x01, 0x0c, 0x16 },
-                       { 0x01, 0x0e, 0x16 },
-                       { 0x01, 0x10, 0x16 }    /* Maximum */
-               };
-               int i = a_contrast / 2;
-               RESTRICT_TO_RANGE(i, 0, 6);
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
-               ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
-               ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_change_lighting_conditions()
- *
- * Camera model 1:
- * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
- *
- * Camera model 2:
- * We have 16 levels of lighting, 0 for bright light and up to 15 for
- * low light. But values above 5 or so are useless because camera is
- * not really capable to produce anything worth viewing at such light.
- * This setting may be altered only in certain camera state.
- *
- * Low lighting forces slower FPS. Lighting is set as a module parameter.
- *
- * History:
- * 1/5/00   Created.
- * 2/20/00  Added support for Model 2 cameras.
- */
-static void ibmcam_change_lighting_conditions(struct uvd *uvd)
-{
-       static const char proc[] = "ibmcam_change_lighting_conditions";
-
-       if (debug > 0)
-               info("%s: Set lighting to %hu.", proc, lighting);
-
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               const int ntries = 5;
-               int i;
-               for (i=0; i < ntries; i++)
-                       ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
-               break;
-       }
-       case IBMCAM_MODEL_2:
-#if 0
-               /*
-                * This command apparently requires camera to be stopped. My
-                * experiments showed that it -is- possible to alter the lighting
-                * conditions setting "on the fly", but why bother? This setting does
-                * not work reliably in all cases, so I decided simply to leave the
-                * setting where Xirlink put it - in the camera setup phase. This code
-                * is commented out because it does not work at -any- moment, so its
-                * presence makes no sense. You may use it for experiments.
-                */
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop camera */
-               ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Start camera */
-#endif
-               break;
-       case IBMCAM_MODEL_3:
-       case IBMCAM_MODEL_4:
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_set_sharpness()
- *
- * Cameras model 1 have internal smoothing feature. It is controlled by value in
- * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
- * Recommended value is 4. Cameras model 2 do not have this feature at all.
- */
-static void ibmcam_set_sharpness(struct uvd *uvd)
-{
-       static const char proc[] = "ibmcam_set_sharpness";
-
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
-               unsigned short i, sv;
-
-               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
-               if (debug > 0)
-                       info("%s: Set sharpness to %hu.", proc, sharpness);
-
-               sv = sa[sharpness - SHARPNESS_MIN];
-               for (i=0; i < 2; i++) {
-                       ibmcam_send_x_01_00_05  (uvd, unknown_88);
-                       ibmcam_send_x_00_05             (uvd, sharp_13);
-                       ibmcam_send_x_00_05_02  (uvd, sv);
-               }
-               break;
-       }
-       case IBMCAM_MODEL_2:
-       case IBMCAM_MODEL_4:
-               /* Models 2, 4 do not have this control */
-               break;
-       case IBMCAM_MODEL_3:
-       {       /*
-                * "Use a table of magic numbers.
-                *  This setting doesn't really change much.
-                *  But that's how Windows does it."
-                */
-               static const struct {
-                       unsigned short sv1;
-                       unsigned short sv2;
-                       unsigned short sv3;
-                       unsigned short sv4;
-               } sv[7] = {
-                       { 0x00, 0x00, 0x05, 0x14 },     /* Smoothest */
-                       { 0x01, 0x04, 0x05, 0x14 },
-                       { 0x02, 0x04, 0x05, 0x14 },
-                       { 0x03, 0x04, 0x05, 0x14 },
-                       { 0x03, 0x05, 0x05, 0x14 },
-                       { 0x03, 0x06, 0x05, 0x14 },
-                       { 0x03, 0x07, 0x05, 0x14 }      /* Sharpest */
-               };
-               RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
-               RESTRICT_TO_RANGE(sharpness, 0, 6);
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
-               ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
-               ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
-               ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ibmcam_set_brightness(struct uvd *uvd)
-{
-       static const char proc[] = "ibmcam_set_brightness";
-       static const unsigned short n = 1;
-
-       if (debug > 0)
-               info("%s: Set brightness to %hu.", proc, uvd->vpic.brightness);
-
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-       {
-               unsigned short i, j, bv[3];
-               bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
-               if (bv[0] == (uvd->vpic_old.brightness >> 10))
-                       return;
-               uvd->vpic_old.brightness = bv[0];
-               for (j=0; j < 3; j++)
-                       for (i=0; i < n; i++)
-                               ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
-               break;
-       }
-       case IBMCAM_MODEL_2:
-       {
-               unsigned short i, j;
-               i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
-               j = 0x60 + i * ((0xee - 0x60) / 16);    /* 0x60 .. 0xee or so */
-               if (uvd->vpic_old.brightness == j)
-                       break;
-               uvd->vpic_old.brightness = j;
-               ibmcam_model2_Packet1(uvd, mod2_brightness, j);
-               break;
-       }
-       case IBMCAM_MODEL_3:
-       {
-               /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
-               unsigned short i =
-                       0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
-               RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
-               if (uvd->vpic_old.brightness == i)
-                       break;
-               uvd->vpic_old.brightness = i;
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x0036, i);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-               break;
-       }
-       case IBMCAM_MODEL_4:
-       {
-               /* Model 4: Brightness range 'i' in [0x04..0xb4] */
-               unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
-               RESTRICT_TO_RANGE(i, 0x04, 0xb4);
-               if (uvd->vpic_old.brightness == i)
-                       break;
-               uvd->vpic_old.brightness = i;
-               ibmcam_model4_BrightnessPacket(uvd, i);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static void ibmcam_set_hue(struct uvd *uvd)
-{
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_2:
-       {
-               unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
-               if (uvd->vpic_old.hue == hue)
-                       return;
-               uvd->vpic_old.hue = hue;
-               ibmcam_model2_Packet1(uvd, mod2_hue, hue);
-               /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
-               break;
-       }
-       case IBMCAM_MODEL_3:
-       {
-#if 0 /* This seems not to work. No problem, will fix programmatically */
-               unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
-               RESTRICT_TO_RANGE(hue, 0x05, 0x37);
-               if (uvd->vpic_old.hue == hue)
-                       return;
-               uvd->vpic_old.hue = hue;
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop */
-               ibmcam_model3_Packet1(uvd, 0x007e, hue);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go! */
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-#endif
-               break;
-       }
-       case IBMCAM_MODEL_4:
-       {
-               unsigned short r_gain, g_gain, b_gain, hue;
-
-               /*
-                * I am not sure r/g/b_gain variables exactly control gain
-                * of those channels. Most likely they subtly change some
-                * very internal image processing settings in the camera.
-                * In any case, here is what they do, and feel free to tweak:
-                *
-                * r_gain: seriously affects red gain
-                * g_gain: seriously affects green gain
-                * b_gain: seriously affects blue gain
-                * hue: changes average color from violet (0) to red (0xFF)
-                *
-                * These settings are preset for a decent white balance in
-                * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
-                * and therefore may need different values here.
-                */
-               hue = 20 + (uvd->vpic.hue >> 9);
-               switch (uvd->videosize) {
-               case VIDEOSIZE_128x96:
-                       r_gain = 90;
-                       g_gain = 166;
-                       b_gain = 175;
-                       break;
-               case VIDEOSIZE_160x120:
-                       r_gain = 70;
-                       g_gain = 166;
-                       b_gain = 185;
-                       break;
-               case VIDEOSIZE_176x144:
-                       r_gain = 160;
-                       g_gain = 175;
-                       b_gain = 185;
-                       break;
-               default:
-                       r_gain = 120;
-                       g_gain = 166;
-                       b_gain = 175;
-                       break;
-               }
-               RESTRICT_TO_RANGE(hue, 1, 0x7f);
-
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, g_gain, 0x0127);    /* Green gain */
-               ibmcam_veio(uvd, 0, r_gain, 0x012e);    /* Red gain */
-               ibmcam_veio(uvd, 0, b_gain, 0x0130);    /* Blue gain */
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, hue,    0x012d);    /* Hue */
-               ibmcam_veio(uvd, 0, 0xf545, 0x0124);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-/*
- * ibmcam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ibmcam_adjust_picture(struct uvd *uvd)
-{
-       ibmcam_adjust_contrast(uvd);
-       ibmcam_set_brightness(uvd);
-       ibmcam_set_hue(uvd);
-}
-
-static int ibmcam_model1_setup(struct uvd *uvd)
-{
-       const int ntries = 5;
-       int i;
-
-       ibmcam_veio(uvd, 1, 0x00, 0x0128);
-       ibmcam_veio(uvd, 1, 0x00, 0x0100);
-       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
-       ibmcam_veio(uvd, 1, 0x00, 0x0100);
-       ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
-       ibmcam_veio(uvd, 1, 0x00, 0x0100);
-       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
-       ibmcam_veio(uvd, 0, 0x01, 0x0108);
-
-       ibmcam_veio(uvd, 0, 0x03, 0x0112);
-       ibmcam_veio(uvd, 1, 0x00, 0x0115);
-       ibmcam_veio(uvd, 0, 0x06, 0x0115);
-       ibmcam_veio(uvd, 1, 0x00, 0x0116);
-       ibmcam_veio(uvd, 0, 0x44, 0x0116);
-       ibmcam_veio(uvd, 1, 0x00, 0x0116);
-       ibmcam_veio(uvd, 0, 0x40, 0x0116);
-       ibmcam_veio(uvd, 1, 0x00, 0x0115);
-       ibmcam_veio(uvd, 0, 0x0e, 0x0115);
-       ibmcam_veio(uvd, 0, 0x19, 0x012c);
-
-       ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x09);
-       ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
-       ibmcam_Packet_Format1(uvd, 0x28, 0x22);
-       ibmcam_Packet_Format1(uvd, light_27, 0);
-       ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
-
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
-
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x30, 0x14);
-
-       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
-       ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
-       ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
-       ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
-       ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
-       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
-       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
-       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
-       ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
-       ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
-       ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
-       ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
-       ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
-       ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
-       ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
-       ibmcam_PacketFormat2(uvd, 0x11, 0xba);
-       ibmcam_PacketFormat2(uvd, 0x12, 0x53);
-       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
-       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
-       ibmcam_PacketFormat2(uvd, 0x39, 0x02);
-       ibmcam_PacketFormat2(uvd, 0x16, 0x00);
-       ibmcam_PacketFormat2(uvd, 0x17, 0x28);
-       ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
-       ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
-       ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
-       ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x00, 0x18);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x13, 0x18);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x14, 0x06);
-
-       /* This is default brightness */
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x31, 0x37);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x32, 0x46);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x33, 0x55);
-
-       ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x29, 0x80);
-       ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
-       ibmcam_Packet_Format1(uvd, 0x30, 0x17);
-       ibmcam_Packet_Format1(uvd, 0x39, 0x08);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x34, 0x00);
-
-       ibmcam_veio(uvd, 0, 0x00, 0x0101);
-       ibmcam_veio(uvd, 0, 0x00, 0x010a);
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_128x96:
-               ibmcam_veio(uvd, 0, 0x80, 0x0103);
-               ibmcam_veio(uvd, 0, 0x60, 0x0105);
-               ibmcam_veio(uvd, 0, 0x0c, 0x010b);
-               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x0b, 0x011d);
-               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x00, 0x0129);
-               break;
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
-               ibmcam_veio(uvd, 0, 0x8f, 0x0105);
-               ibmcam_veio(uvd, 0, 0x06, 0x010b);
-               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x0d, 0x011d);
-               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x03, 0x0129);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0xb0, 0x0103);
-               ibmcam_veio(uvd, 0, 0x90, 0x0105);
-               ibmcam_veio(uvd, 0, 0x02, 0x010b);
-               ibmcam_veio(uvd, 0, 0x04, 0x011b);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x05, 0x011d);
-               ibmcam_veio(uvd, 0, 0x00, 0x011e);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x00, 0x0129);
-               break;
-       }
-
-       ibmcam_veio(uvd, 0, 0xff, 0x012b);
-
-       /* This is another brightness - don't know why */
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
-
-       /* Default contrast */
-       for (i=0; i < ntries; i++)
-               ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
-
-       /* Default sharpness */
-       for (i=0; i < 2; i++)
-               ibmcam_PacketFormat2(uvd, sharp_13, 0x1a);      /* Level 4 FIXME */
-
-       /* Default lighting conditions */
-       ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
-
-       /* Assorted init */
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_128x96:
-               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
-               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x36, 0x0102);
-               ibmcam_veio(uvd, 0, 0x1a, 0x0104);
-               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
-               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
-#if 0
-               ibmcam_veio(uvd, 0, 0x00, 0x0106);
-               ibmcam_veio(uvd, 0, 0x38, 0x0107);
-#else
-               ibmcam_veio(uvd, 0, 0x02, 0x0106);
-               ibmcam_veio(uvd, 0, 0x2a, 0x0107);
-#endif
-               break;
-       case VIDEOSIZE_176x144:
-               ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
-               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x04, 0x0102);
-               ibmcam_veio(uvd, 0, 0x02, 0x0104);
-               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x2b, 0x011c);
-               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x01, 0x0106);
-               ibmcam_veio(uvd, 0, 0xca, 0x0107);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
-               ibmcam_veio(uvd, 0, 0xc9, 0x0119);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x80, 0x0109);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x08, 0x0102);
-               ibmcam_veio(uvd, 0, 0x01, 0x0104);
-               ibmcam_veio(uvd, 0, 0x04, 0x011a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x2f, 0x011c);
-               ibmcam_veio(uvd, 0, 0x23, 0x012a);      /* Same everywhere */
-               ibmcam_veio(uvd, 0, 0x03, 0x0106);
-               ibmcam_veio(uvd, 0, 0xf6, 0x0107);
-               break;
-       }
-       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-static int ibmcam_model2_setup(struct uvd *uvd)
-{
-       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
-       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
-       ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-       ibmcam_veio(uvd, 0, 0x0008, 0x012b);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
-               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);    /* Unique to this mode */
-               ibmcam_veio(uvd, 0, 0x0038, 0x0119);    /* Unique to this mode */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0090, 0x0107);    /* Unique to every mode*/
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);    /* Unique to this mode */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0098, 0x0107);    /* Unique to every mode*/
-               break;
-       case VIDEOSIZE_352x240:
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);    /* 320x240, 352x240 */
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x00da, 0x0107);    /* Unique to every mode*/
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);    /* All except 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);    /* Same */
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);    /* 176x144, 352x288 */
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);    /* All except 176x144 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);    /* Same */
-               ibmcam_veio(uvd, 0, 0x00fe, 0x0107);    /* Unique to every mode*/
-               break;
-       }
-       return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-/*
- * ibmcam_model1_setup_after_video_if()
- *
- * This code adds finishing touches to the video data interface.
- * Here we configure the frame rate and turn on the LED.
- */
-static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
-{
-       unsigned short internal_frame_rate;
-
-       RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
-       internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
-       ibmcam_veio(uvd, 0, 0x01, 0x0100);      /* LED On  */
-       ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
-       ibmcam_veio(uvd, 0, 0x01, 0x0114);
-       ibmcam_veio(uvd, 0, 0xc0, 0x010c);
-}
-
-static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
-{
-       unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
-
-       ibmcam_veio(uvd, 0, 0x0000, 0x0100);    /* LED on */
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0x0050, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               break;
-       case VIDEOSIZE_320x240:
-       case VIDEOSIZE_352x240:
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0x0040, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               break;
-       }
-       ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-       ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-
-       /*
-        * Hardware settings, may affect CMOS sensor; not user controls!
-        * -------------------------------------------------------------
-        * 0x0004: no effect
-        * 0x0006: hardware effect
-        * 0x0008: no effect
-        * 0x000a: stops video stream, probably important h/w setting
-        * 0x000c: changes color in hardware manner (not user setting)
-        * 0x0012: changes number of colors (does not affect speed)
-        * 0x002a: no effect
-        * 0x002c: hardware setting (related to scan lines)
-        * 0x002e: stops video stream, probably important h/w setting
-        */
-       ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
-       ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
-       ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
-       ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
-       ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
-       ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
-
-       /*
-        * Function 0x0030 pops up all over the place. Apparently
-        * it is a hardware control register, with every bit assigned to
-        * do something.
-        */
-       ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
-
-       /*
-        * Magic control of CMOS sensor. Only lower values like
-        * 0-3 work, and picture shifts left or right. Don't change.
-        */
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
-               break;
-       case VIDEOSIZE_352x240:
-               /* This mode doesn't work as Windows programs it; changed to work */
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
-               ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
-               ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
-               break;
-       }
-
-       ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
-
-       /*
-        * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
-        * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
-        * slowest setting. However for all practical reasons high settings make no
-        * sense because USB is not fast enough to support high FPS. Be aware that
-        * the picture datastream will be severely disrupted if you ask for
-        * frame rate faster than allowed for the video size - see below:
-        *
-        * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
-        * -----------------------------------------------------------------
-        * 176x144: [6..31]
-        * 320x240: [8..31]
-        * 352x240: [10..31]
-        * 352x288: [16..31] I have to raise lower threshold for stability...
-        *
-        * As usual, slower FPS provides better sensitivity.
-        */
-       {
-               short hw_fps=31, i_framerate;
-
-               RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
-               i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
-               switch (uvd->videosize) {
-               case VIDEOSIZE_176x144:
-                       hw_fps = 6 + i_framerate*4;
-                       break;
-               case VIDEOSIZE_320x240:
-                       hw_fps = 8 + i_framerate*3;
-                       break;
-               case VIDEOSIZE_352x240:
-                       hw_fps = 10 + i_framerate*2;
-                       break;
-               case VIDEOSIZE_352x288:
-                       hw_fps = 28 + i_framerate/2;
-                       break;
-               }
-               if (uvd->debug > 0)
-                       info("Framerate (hardware): %hd.", hw_fps);
-               RESTRICT_TO_RANGE(hw_fps, 0, 31);
-               ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
-       }
-
-       /*
-        * This setting does not visibly affect pictures; left it here
-        * because it was present in Windows USB data stream. This function
-        * does not allow arbitrary values and apparently is a bit mask, to
-        * be activated only at appropriate time. Don't change it randomly!
-        */
-       switch (uvd->videosize) {
-       case VIDEOSIZE_176x144:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
-               break;
-       case VIDEOSIZE_352x240:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
-               break;
-       }
-
-       ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
-
-       if (init_model2_rg2 >= 0) {
-               RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
-               setup_model2_rg2 = init_model2_rg2;
-       } else
-               setup_model2_rg2 = 0x002f;
-
-       if (init_model2_sat >= 0) {
-               RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
-               setup_model2_sat = init_model2_sat;
-       } else
-               setup_model2_sat = 0x0034;
-
-       if (init_model2_yb >= 0) {
-               RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
-               setup_model2_yb = init_model2_yb;
-       } else
-               setup_model2_yb = 0x00a0;
-
-       ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
-       ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
-       ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
-       ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
-
-       /* Hardware control command */
-       ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
-       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);    /* Go camera, go! */
-       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
-{
-       switch (uvd->videosize) {
-       case VIDEOSIZE_128x96:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_160x120:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000b, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0025, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0048, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0035, 0x012e);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0048, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0090, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_176x144:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0038, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x0018, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0007, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0001, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x002a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
-               ibmcam_veio(uvd, 0, 0x006d, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x005e, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0028, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x001e, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000a, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0043, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0031, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0017, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0078, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break;
-       case VIDEOSIZE_352x288:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
-               ibmcam_veio(uvd, 0, 0x0080, 0x012b);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0108);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0133);
-               ibmcam_veio(uvd, 0, 0x009b, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x000a, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005c, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0004, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x000c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0009, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0012, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x002a, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0000, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0034, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0070, 0x0119);
-               ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x008c, 0x0107);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0039, 0x010a);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0102);
-               ibmcam_veio(uvd, 0, 0x002c, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0024, 0x0105);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0016, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0006, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0014, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0002, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
-               ibmcam_veio(uvd, 0, 0x001a, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
-               ibmcam_veio(uvd, 0, 0x005e, 0x012d);
-               ibmcam_veio(uvd, 0, 0x9545, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0018, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0049, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd055, 0x0124);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
-               ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0032, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
-               ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0036, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0008, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x001e, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x0127);
-               ibmcam_veio(uvd, 0, 0x0013, 0x012e);
-               ibmcam_veio(uvd, 0, 0x0025, 0x0130);
-               ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0010, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0048, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd145, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
-               ibmcam_veio(uvd, 0, 0x0038, 0x012f);
-               ibmcam_veio(uvd, 0, 0xd141, 0x0124);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0127);
-               ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               break; 
-       }
-       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
-{
-       int i;
-       /*
-        * 01.01.08 - Added for RCA video in support -LO
-        * This struct is used to init the Model3 cam to use the RCA video in port
-        * instead of the CCD sensor.
-        */
-       static const struct struct_initData initData[] = {
-               {0, 0x0000, 0x010c},
-               {0, 0x0006, 0x012c},
-               {0, 0x0078, 0x012d},
-               {0, 0x0046, 0x012f},
-               {0, 0xd141, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfea8, 0x0124},
-               {1, 0x0000, 0x0116},
-               {0, 0x0064, 0x0116},
-               {1, 0x0000, 0x0115},
-               {0, 0x0003, 0x0115},
-               {0, 0x0008, 0x0123},
-               {0, 0x0000, 0x0117},
-               {0, 0x0000, 0x0112},
-               {0, 0x0080, 0x0100},
-               {0, 0x0000, 0x0100},
-               {1, 0x0000, 0x0116},
-               {0, 0x0060, 0x0116},
-               {0, 0x0002, 0x0112},
-               {0, 0x0000, 0x0123},
-               {0, 0x0001, 0x0117},
-               {0, 0x0040, 0x0108},
-               {0, 0x0019, 0x012c},
-               {0, 0x0040, 0x0116},
-               {0, 0x000a, 0x0115},
-               {0, 0x000b, 0x0115},
-               {0, 0x0078, 0x012d},
-               {0, 0x0046, 0x012f},
-               {0, 0xd141, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfea8, 0x0124},
-               {0, 0x0064, 0x0116},
-               {0, 0x0000, 0x0115},
-               {0, 0x0001, 0x0115},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00aa, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f2, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x000f, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f8, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00fc, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f9, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x003c, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xffff, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0027, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0019, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0021, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0006, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0045, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002a, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x000e, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002b, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00f4, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002c, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0004, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002d, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0014, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002e, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0003, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x002f, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0003, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0014, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0053, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0x0000, 0x0101},
-               {0, 0x00a0, 0x0103},
-               {0, 0x0078, 0x0105},
-               {0, 0x0000, 0x010a},
-               {0, 0x0024, 0x010b},
-               {0, 0x0028, 0x0119},
-               {0, 0x0088, 0x011b},
-               {0, 0x0002, 0x011d},
-               {0, 0x0003, 0x011e},
-               {0, 0x0000, 0x0129},
-               {0, 0x00fc, 0x012b},
-               {0, 0x0008, 0x0102},
-               {0, 0x0000, 0x0104},
-               {0, 0x0008, 0x011a},
-               {0, 0x0028, 0x011c},
-               {0, 0x0021, 0x012a},
-               {0, 0x0000, 0x0118},
-               {0, 0x0000, 0x0132},
-               {0, 0x0000, 0x0109},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0031, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x00dc, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0032, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0020, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0001, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0040, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0037, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0030, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0xfff9, 0x0124},
-               {0, 0x0086, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0038, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0008, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0x0000, 0x0127},
-               {0, 0xfff8, 0x0124},
-               {0, 0xfffd, 0x0124},
-               {0, 0xfffa, 0x0124},
-               {0, 0x0003, 0x0106},
-               {0, 0x0062, 0x0107},
-               {0, 0x0003, 0x0111},
-       };
-#define NUM_INIT_DATA 
-
-       unsigned short compression = 0; /* 0=none, 7=best frame rate  */
-       int f_rate; /* 0=Fastest 7=slowest */
-
-       if (IBMCAM_T(uvd)->initialized)
-               return;
-
-       /* Internal frame rate is controlled by f_rate value */
-       f_rate = 7 - framerate;
-       RESTRICT_TO_RANGE(f_rate, 0, 7);
-
-       ibmcam_veio(uvd, 0, 0x0000, 0x0100);
-       ibmcam_veio(uvd, 1, 0x0000, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0112);
-       ibmcam_veio(uvd, 0, 0x0000, 0x0123);
-       ibmcam_veio(uvd, 0, 0x0001, 0x0117);
-       ibmcam_veio(uvd, 0, 0x0040, 0x0108);
-       ibmcam_veio(uvd, 0, 0x0019, 0x012c);
-       ibmcam_veio(uvd, 0, 0x0060, 0x0116);
-       ibmcam_veio(uvd, 0, 0x0002, 0x0115);
-       ibmcam_veio(uvd, 0, 0x0003, 0x0115);
-       ibmcam_veio(uvd, 1, 0x0000, 0x0115);
-       ibmcam_veio(uvd, 0, 0x000b, 0x0115);
-       ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
-       ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
-       ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
-       ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
-       ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
-       ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
-       ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
-       ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
-       ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
-       ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
-       ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
-       ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
-       ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
-       ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
-       ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
-       ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
-       ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
-       ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
-       ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
-       ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
-       ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
-       ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
-       ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
-       ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
-       ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
-       ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
-       ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
-       ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
-       ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
-       ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
-       ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
-       ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
-       ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
-       ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
-       ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
-       ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
-       ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_160x120:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
-               ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
-               ibmcam_veio(uvd, 0, 0x0016, 0x011b);
-               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
-               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
-               ibmcam_veio(uvd, 0, 0x0018, 0x0102);
-               ibmcam_veio(uvd, 0, 0x0004, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
-               ibmcam_veio(uvd, 0, 0x0028, 0x011c);
-               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0118);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
-               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
-               ibmcam_veio(uvd, 0, compression, 0x0109);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
-               ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
-               ibmcam_veio(uvd, 0, 0x0000, 0x011e);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
-               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
-               /* 4 commands from 160x120 skipped */
-               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
-               ibmcam_veio(uvd, 0, compression, 0x0109);
-               ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
-               ibmcam_veio(uvd, 0, 0x0006, 0x011b);
-               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0010, 0x0104);
-               ibmcam_veio(uvd, 0, 0x0004, 0x011a);
-               ibmcam_veio(uvd, 0, 0x003f, 0x011c);
-               ibmcam_veio(uvd, 0, 0x001c, 0x0118);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0132);
-               break;
-       case VIDEOSIZE_640x480:
-               ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
-               ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
-               ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
-               ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
-               ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
-               ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
-               ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
-               ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
-               ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
-               ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
-               ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
-               ibmcam_veio(uvd, 0, compression, 0x0109);
-               ibmcam_veio(uvd, 0, 0x0040, 0x0101);
-               ibmcam_veio(uvd, 0, 0x0040, 0x0103);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
-               break;
-       }
-       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);     /* Hue */
-       ibmcam_model3_Packet1(uvd, 0x0036, 0x0011);     /* Brightness */
-       ibmcam_model3_Packet1(uvd, 0x0060, 0x0002);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0061, 0x0004);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0062, 0x0005);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0063, 0x0014);     /* Sharpness */
-       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
-       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
-       ibmcam_model3_Packet1(uvd, 0x0067, 0x0001);     /* Contrast */
-       ibmcam_model3_Packet1(uvd, 0x005b, 0x000c);     /* Contrast */
-       ibmcam_model3_Packet1(uvd, 0x005c, 0x0016);     /* Contrast */
-       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x002c, 0x0003);     /* Was 1, broke 640x480 */
-       ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
-       ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
-       ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
-       ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
-       ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
-       ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
-       ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
-       ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
-       ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
-       ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
-       ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
-       ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
-       ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
-       ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
-       ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0);     /* Red gain */
-       ibmcam_model3_Packet1(uvd, 0x0097, 0x0096);     /* Blue gain */
-       ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
-
-       switch (uvd->videosize) {
-       case VIDEOSIZE_160x120:
-               ibmcam_veio(uvd, 0, 0x0002, 0x0106);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0107);
-               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
-               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
-               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
-               break;
-       case VIDEOSIZE_320x240:
-               ibmcam_veio(uvd, 0, 0x0003, 0x0106);
-               ibmcam_veio(uvd, 0, 0x0062, 0x0107);
-               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
-               ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
-               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
-               ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
-               break;
-       case VIDEOSIZE_640x480:
-               ibmcam_veio(uvd, 0, 0x0002, 0x0106);    /* Adjustments */
-               ibmcam_veio(uvd, 0, 0x00b4, 0x0107);    /* Adjustments */
-               ibmcam_veio(uvd, 0, f_rate, 0x0111);    /* Frame rate */
-               ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
-               ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
-               ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
-               ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
-               break;
-       }
-
-       /* 01.01.08 - Added for RCA video in support -LO */
-       if(init_model3_input) {
-               if (debug > 0)
-                       info("Setting input to RCA.");
-               for (i=0; i < ARRAY_SIZE(initData); i++) {
-                       ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
-               }
-       }
-
-       ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-       ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-       usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-/*
- * ibmcam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ibmcam_video_stop(struct uvd *uvd)
-{
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-               ibmcam_veio(uvd, 0, 0x00, 0x010c);
-               ibmcam_veio(uvd, 0, 0x00, 0x010c);
-               ibmcam_veio(uvd, 0, 0x01, 0x0114);
-               ibmcam_veio(uvd, 0, 0xc0, 0x010c);
-               ibmcam_veio(uvd, 0, 0x00, 0x010c);
-               ibmcam_send_FF_04_02(uvd);
-               ibmcam_veio(uvd, 1, 0x00, 0x0100);
-               ibmcam_veio(uvd, 0, 0x81, 0x0100);      /* LED Off */
-               break;
-       case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);    /* Stop the camera */
-
-               ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
-               ibmcam_veio(uvd, 0, 0x0080, 0x0100);    /* LED Off */
-               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
-               ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
-
-               ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
-
-               ibmcam_veio(uvd, 0, 0x0020, 0x0111);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
-               break;
-       case IBMCAM_MODEL_3:
-#if 1
-               ibmcam_veio(uvd, 0, 0x0000, 0x010c);
-
-               /* Here we are supposed to select video interface alt. setting 0 */
-               ibmcam_veio(uvd, 0, 0x0006, 0x012c);
-
-               ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
-
-               ibmcam_veio(uvd, 1, 0x0000, 0x0116);
-               ibmcam_veio(uvd, 0, 0x0064, 0x0116);
-               ibmcam_veio(uvd, 1, 0x0000, 0x0115);
-               ibmcam_veio(uvd, 0, 0x0003, 0x0115);
-               ibmcam_veio(uvd, 0, 0x0008, 0x0123);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0117);
-               ibmcam_veio(uvd, 0, 0x0000, 0x0112);
-               ibmcam_veio(uvd, 0, 0x0080, 0x0100);
-               IBMCAM_T(uvd)->initialized = 0;
-#endif
-               break;
-       } /* switch */
-}
-
-/*
- * ibmcam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- *
- * History:
- * 1/2/00   Created.
- */
-static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
-{
-       switch (IBMCAM_T(uvd)->camera_model) {
-       case IBMCAM_MODEL_1:
-               if (do_stop)
-                       ibmcam_video_stop(uvd);
-               ibmcam_veio(uvd, 0, 0x0001, 0x0114);
-               ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
-               usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-               ibmcam_model1_setup_after_video_if(uvd);
-               break;
-       case IBMCAM_MODEL_2:
-               ibmcam_model2_setup_after_video_if(uvd);
-               break;
-       case IBMCAM_MODEL_3:
-               ibmcam_video_stop(uvd);
-               ibmcam_model3_setup_after_video_if(uvd);
-               break;
-       case IBMCAM_MODEL_4:
-               ibmcam_model4_setup_after_video_if(uvd);
-               break;
-       }
-}
-
-static void ibmcam_video_start(struct uvd *uvd)
-{
-       ibmcam_change_lighting_conditions(uvd);
-       ibmcam_set_sharpness(uvd);
-       ibmcam_reinit_iso(uvd, 0);
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ibmcam_setup_on_open(struct uvd *uvd)
-{
-       int setup_ok = 0; /* Success by default */
-       /* Send init sequence only once, it's large! */
-       if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
-               switch (IBMCAM_T(uvd)->camera_model) {
-               case IBMCAM_MODEL_1:
-                       setup_ok = ibmcam_model1_setup(uvd);
-                       break;
-               case IBMCAM_MODEL_2:
-                       setup_ok = ibmcam_model2_setup(uvd);
-                       break;
-               case IBMCAM_MODEL_3:
-               case IBMCAM_MODEL_4:
-                       /* We do all setup when Isoc stream is requested */
-                       break;
-               }
-               IBMCAM_T(uvd)->initialized = (setup_ok != 0);
-       }
-       return setup_ok;
-}
-
-static void ibmcam_configure_video(struct uvd *uvd)
-{
-       if (uvd == NULL)
-               return;
-
-       RESTRICT_TO_RANGE(init_brightness, 0, 255);
-       RESTRICT_TO_RANGE(init_contrast, 0, 255);
-       RESTRICT_TO_RANGE(init_color, 0, 255);
-       RESTRICT_TO_RANGE(init_hue, 0, 255);
-       RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       uvd->vpic.colour = init_color << 8;
-       uvd->vpic.hue = init_hue << 8;
-       uvd->vpic.brightness = init_brightness << 8;
-       uvd->vpic.contrast = init_contrast << 8;
-       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
-       uvd->vpic.depth = 24;
-       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "IBM USB Camera");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
-       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
-       uvd->vcap.minwidth = min_canvasWidth;
-       uvd->vcap.minheight = min_canvasHeight;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ibmcam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like IBM C-it camera.
- *
- * History:
- * 22-Jan-2000 Moved camera init code to ibmcam_open()
- * 27=Jan-2000 Changed to use static structures, added locking.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 03-Jul-2000 Fixed endianness bug.
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct uvd *uvd = NULL;
-       int ix, i, nas, model=0, canvasX=0, canvasY=0;
-       int actInterface=-1, inactInterface=-1, maxPS=0;
-       __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
-       unsigned char video_ep = 0;
-
-       if (debug >= 1)
-               info("ibmcam_probe(%p,%u.)", intf, ifnum);
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       /* Check the version/revision */
-       switch (le16_to_cpu(dev->descriptor.bcdDevice)) {
-       case 0x0002:
-               if (ifnum != 2)
-                       return -ENODEV;
-               model = IBMCAM_MODEL_1;
-               break;
-       case 0x030A:
-               if (ifnum != 0)
-                       return -ENODEV;
-               if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) ||
-                   (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID))
-                       model = IBMCAM_MODEL_4;
-               else
-                       model = IBMCAM_MODEL_2;
-               break;
-       case 0x0301:
-               if (ifnum != 0)
-                       return -ENODEV;
-               model = IBMCAM_MODEL_3;
-               break;
-       default:
-               err("IBM camera with revision 0x%04x is not supported.",
-                       le16_to_cpu(dev->descriptor.bcdDevice));
-               return -ENODEV;
-       }
-
-       /* Print detailed info on what we found so far */
-       do {
-               char *brand = NULL;
-               switch (le16_to_cpu(dev->descriptor.idProduct)) {
-               case NETCAM_PRODUCT_ID:
-                       brand = "IBM NetCamera";
-                       break;
-               case VEO_800C_PRODUCT_ID:
-                       brand = "Veo Stingray [800C]";
-                       break;
-               case VEO_800D_PRODUCT_ID:
-                       brand = "Veo Stingray [800D]";
-                       break;
-               case IBMCAM_PRODUCT_ID:
-               default:
-                       brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
-                       break;
-               }
-               info("%s USB camera found (model %d, rev. 0x%04x)",
-                    brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
-       } while (0);
-
-       /* Validate found interface: must have one ISO endpoint */
-       nas = intf->num_altsetting;
-       if (debug > 0)
-               info("Number of alternate settings=%d.", nas);
-       if (nas < 2) {
-               err("Too few alternate settings for this camera!");
-               return -ENODEV;
-       }
-       /* Validate all alternate settings */
-       for (ix=0; ix < nas; ix++) {
-               const struct usb_host_interface *interface;
-               const struct usb_endpoint_descriptor *endpoint;
-
-               interface = &intf->altsetting[ix];
-               i = interface->desc.bAlternateSetting;
-               if (interface->desc.bNumEndpoints != 1) {
-                       err("Interface %d. has %u. endpoints!",
-                           ifnum, (unsigned)(interface->desc.bNumEndpoints));
-                       return -ENODEV;
-               }
-               endpoint = &interface->endpoint[0].desc;
-               if (video_ep == 0)
-                       video_ep = endpoint->bEndpointAddress;
-               else if (video_ep != endpoint->bEndpointAddress) {
-                       err("Alternate settings have different endpoint addresses!");
-                       return -ENODEV;
-               }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
-                       err("Interface %d. has non-ISO endpoint!", ifnum);
-                       return -ENODEV;
-               }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
-                       err("Interface %d. has ISO OUT endpoint!", ifnum);
-                       return -ENODEV;
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
-                       if (inactInterface < 0)
-                               inactInterface = i;
-                       else {
-                               err("More than one inactive alt. setting!");
-                               return -ENODEV;
-                       }
-               } else {
-                       if (actInterface < 0) {
-                               actInterface = i;
-                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-                               if (debug > 0)
-                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
-                       } else
-                               err("More than one active alt. setting! Ignoring #%d.", i);
-               }
-       }
-       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
-               err("Failed to recognize the camera!");
-               return -ENODEV;
-       }
-
-       /* Validate options */
-       switch (model) {
-       case IBMCAM_MODEL_1:
-               RESTRICT_TO_RANGE(lighting, 0, 2);
-               RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
-               if (framerate < 0)
-                       framerate = 2;
-               canvasX = 352;
-               canvasY = 288;
-               break;
-       case IBMCAM_MODEL_2:
-               RESTRICT_TO_RANGE(lighting, 0, 15);
-               RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
-               if (framerate < 0)
-                       framerate = 2;
-               canvasX = 352;
-               canvasY = 240;
-               break;
-       case IBMCAM_MODEL_3:
-               RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
-               switch (size) {
-               case SIZE_160x120:
-                       canvasX = 160;
-                       canvasY = 120;
-                       if (framerate < 0)
-                               framerate = 2;
-                       RESTRICT_TO_RANGE(framerate, 0, 5);
-                       break;
-               default:
-                       info("IBM camera: using 320x240");
-                       size = SIZE_320x240;
-                       /* No break here */
-               case SIZE_320x240:
-                       canvasX = 320;
-                       canvasY = 240;
-                       if (framerate < 0)
-                               framerate = 3;
-                       RESTRICT_TO_RANGE(framerate, 0, 5);
-                       break;
-               case SIZE_640x480:
-                       canvasX = 640;
-                       canvasY = 480;
-                       framerate = 0;  /* Slowest, and maybe even that is too fast */
-                       break;
-               }
-               break;
-       case IBMCAM_MODEL_4:
-               RESTRICT_TO_RANGE(lighting, 0, 2);
-               switch (size) {
-               case SIZE_128x96:
-                       canvasX = 128;
-                       canvasY = 96;
-                       break;
-               case SIZE_160x120:
-                       canvasX = 160;
-                       canvasY = 120;
-                       break;
-               default:
-                       info("IBM NetCamera: using 176x144");
-                       size = SIZE_176x144;
-                       /* No break here */
-               case SIZE_176x144:
-                       canvasX = 176;
-                       canvasY = 144;
-                       break;
-               case SIZE_320x240:
-                       canvasX = 320;
-                       canvasY = 240;
-                       break;
-               case SIZE_352x288:
-                       canvasX = 352;
-                       canvasY = 288;
-                       break;
-               }
-               break;
-       default:
-               err("IBM camera: Model %d. not supported!", model);
-               return -ENODEV;
-       }
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (uvd != NULL) {
-               /* Here uvd is a fully allocated uvd object */
-               uvd->flags = flags;
-               uvd->debug = debug;
-               uvd->dev = dev;
-               uvd->iface = ifnum;
-               uvd->ifaceAltInactive = inactInterface;
-               uvd->ifaceAltActive = actInterface;
-               uvd->video_endp = video_ep;
-               uvd->iso_packet_len = maxPS;
-               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
-               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-               uvd->canvas = VIDEOSIZE(canvasX, canvasY);
-               uvd->videosize = ibmcam_size_to_videosize(size);
-
-               /* Initialize ibmcam-specific data */
-               assert(IBMCAM_T(uvd) != NULL);
-               IBMCAM_T(uvd)->camera_model = model;
-               IBMCAM_T(uvd)->initialized = 0;
-
-               ibmcam_configure_video(uvd);
-
-               i = usbvideo_RegisterVideoDevice(uvd);
-               if (i != 0) {
-                       err("usbvideo_RegisterVideoDevice() failed.");
-                       uvd = NULL;
-               }
-       }
-       usb_set_intfdata (intf, uvd);
-       return 0;
-}
-
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) },        /* Model 1 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 2 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) },        /* Model 3 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) },        /* Model 4 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 2 */
-       { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) },      /* Model 4 */
-       { }  /* Terminating entry */
-};
-
-/*
- * ibmcam_init()
- *
- * This code is run to initialize the driver.
- *
- * History:
- * 1/27/00  Reworked to use statically allocated ibmcam structures.
- * 21/10/00 Completely redesigned to use usbvideo services.
- */
-static int __init ibmcam_init(void)
-{
-       struct usbvideo_cb cbTbl;
-       memset(&cbTbl, 0, sizeof(cbTbl));
-       cbTbl.probe = ibmcam_probe;
-       cbTbl.setupOnOpen = ibmcam_setup_on_open;
-       cbTbl.videoStart = ibmcam_video_start;
-       cbTbl.videoStop = ibmcam_video_stop;
-       cbTbl.processData = ibmcam_ProcessIsocData;
-       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
-       cbTbl.adjustPicture = ibmcam_adjust_picture;
-       cbTbl.getFPS = ibmcam_calculate_fps;
-       return usbvideo_register(
-               &cams,
-               MAX_IBMCAM,
-               sizeof(ibmcam_t),
-               "ibmcam",
-               &cbTbl,
-               THIS_MODULE,
-               id_table);
-}
-
-static void __exit ibmcam_cleanup(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-module_init(ibmcam_init);
-module_exit(ibmcam_cleanup);
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
deleted file mode 100644 (file)
index e2ede58..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- * konicawc.c - konica webcam driver
- *
- * Author: Simon Evans <spse@secret.org.uk>
- *
- * Copyright (C) 2002 Simon Evans
- *
- * Licence: GPL
- *
- * Driver for USB webcams based on Konica chipset. This
- * chipset is used in Intel YC76 camera.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb_input.h>
-
-#include "usbvideo.h"
-
-#define MAX_BRIGHTNESS 108
-#define MAX_CONTRAST   108
-#define MAX_SATURATION 108
-#define MAX_SHARPNESS  108
-#define MAX_WHITEBAL   372
-#define MAX_SPEED      6
-
-
-#define MAX_CAMERAS    1
-
-#define DRIVER_VERSION "v1.4"
-#define DRIVER_DESC    "Konica Webcam driver"
-
-enum ctrl_req {
-       SetWhitebal     = 0x01,
-       SetBrightness   = 0x02,
-        SetSharpness   = 0x03,
-       SetContrast     = 0x04,
-       SetSaturation   = 0x05,
-};
-
-
-enum frame_sizes {
-       SIZE_160X120    = 0,
-       SIZE_160X136    = 1,
-       SIZE_176X144    = 2,
-       SIZE_320X240    = 3,
-       
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-static struct usbvideo *cams;
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
-       if (n <= debug) {        \
-               printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
-       }
-#else
-#define DEBUG(n, arg...)
-static const int debug = 0;
-#endif
-
-
-/* Some default values for initial camera settings,
-   can be set by modprobe */
-
-static int size;       
-static int speed = 6;          /* Speed (fps) 0 (slowest) to 6 (fastest) */
-static int brightness =        MAX_BRIGHTNESS/2;
-static int contrast =  MAX_CONTRAST/2;
-static int saturation =        MAX_SATURATION/2;
-static int sharpness = MAX_SHARPNESS/2;
-static int whitebal =  3*(MAX_WHITEBAL/4);
-
-static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
-
-/* These FPS speeds are from the windows config box. They are
- * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
- * real fps.
- */
-
-static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
-                              { 24, 40, 48, 60, 72, 80, 100 },
-                              { 18, 30, 36, 45, 54, 60, 75  },
-                              { 6,  10, 12, 15, 18, 21, 25  } };
-
-struct cam_size {
-       u16     width;
-       u16     height;
-       u8      cmd;
-};
-
-static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
-                                         { 160, 136, 0xa },
-                                         { 176, 144, 0x4 },
-                                         { 320, 240, 0x5 } };
-
-struct konicawc {
-       u8 brightness;          /* camera uses 0 - 9, x11 for real value */
-       u8 contrast;            /* as above */
-       u8 saturation;          /* as above */
-       u8 sharpness;           /* as above */
-       u8 white_bal;           /* 0 - 33, x11 for real value */
-       u8 speed;               /* Stored as 0 - 6, used as index in spd_to_* (above) */
-       u8 size;                /* Frame Size */
-       int height;
-       int width;
-       struct urb *sts_urb[USBVIDEO_NUMSBUF];
-       u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
-       struct urb *last_data_urb;
-       int lastframe;
-       int cur_frame_size;     /* number of bytes in current frame size */
-       int maxline;            /* number of lines per frame */
-       int yplanesz;           /* Number of bytes in the Y plane */
-       unsigned int buttonsts:1;
-#ifdef CONFIG_INPUT
-       struct input_dev *input;
-       char input_physname[64];
-#endif
-};
-
-
-#define konicawc_set_misc(uvd, req, value, index)              konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
-#define konicawc_get_misc(uvd, req, value, index, buf, sz)     konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
-#define konicawc_set_value(uvd, value, index)                  konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
-
-
-static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
-{
-        int retval = usb_control_msg(uvd->dev,
-               dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
-                   request, 0x40 | dir, value, index, buf, len, 1000);
-        return retval < 0 ? retval : 0;
-}
-
-
-static inline void konicawc_camera_on(struct uvd *uvd)
-{
-        DEBUG(0, "camera on");
-        konicawc_set_misc(uvd, 0x2, 1, 0x0b);
-}
-
-
-static inline void konicawc_camera_off(struct uvd *uvd)
-{
-        DEBUG(0, "camera off");
-        konicawc_set_misc(uvd, 0x2, 0, 0x0b);
-}
-
-
-static void konicawc_set_camera_size(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
-       cam->width = camera_sizes[cam->size].width;
-       cam->height = camera_sizes[cam->size].height;
-       cam->yplanesz = cam->height * cam->width;
-       cam->cur_frame_size = (cam->yplanesz * 3) / 2;
-       cam->maxline = cam->yplanesz / 256;
-       uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-}
-
-
-static int konicawc_setup_on_open(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
-           cam->brightness * 11);
-       konicawc_set_value(uvd, cam->brightness, SetBrightness);
-       DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
-           cam->white_bal * 11);
-       konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
-       DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
-           cam->contrast * 11);
-       konicawc_set_value(uvd, cam->contrast, SetContrast);
-       DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
-           cam->saturation * 11);
-       konicawc_set_value(uvd, cam->saturation, SetSaturation);
-       DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
-           cam->sharpness * 11);
-       konicawc_set_value(uvd, cam->sharpness, SetSharpness);
-       konicawc_set_camera_size(uvd);
-       cam->lastframe = -2;
-       cam->buttonsts = 0;
-       return 0;
-}
-
-
-static void konicawc_adjust_picture(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       konicawc_camera_off(uvd);
-       DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
-       uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
-       if(cam->brightness != uvd->vpic.brightness / 11) {
-          cam->brightness = uvd->vpic.brightness / 11;
-          DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
-              cam->brightness * 11);
-          konicawc_set_value(uvd, cam->brightness, SetBrightness);
-       }
-
-       DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
-       uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
-       if(cam->contrast != uvd->vpic.contrast / 11) {
-               cam->contrast = uvd->vpic.contrast / 11;
-               DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
-                   cam->contrast * 11);
-               konicawc_set_value(uvd, cam->contrast, SetContrast);
-       }
-       konicawc_camera_on(uvd);
-}
-
-#ifdef CONFIG_INPUT
-
-static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
-{
-       struct input_dev *input_dev;
-
-       usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
-       strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
-       cam->input = input_dev = input_allocate_device();
-       if (!input_dev) {
-               warn("Not enough memory for camera's input device\n");
-               return;
-       }
-
-       input_dev->name = "Konicawc snapshot button";
-       input_dev->phys = cam->input_physname;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &dev->dev;
-
-       input_dev->evbit[0] = BIT(EV_KEY);
-       input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
-
-       input_dev->private = cam;
-
-       input_register_device(cam->input);
-}
-
-static void konicawc_unregister_input(struct konicawc *cam)
-{
-       if (cam->input) {
-               input_unregister_device(cam->input);
-               cam->input = NULL;
-       }
-}
-
-static void konicawc_report_buttonstat(struct konicawc *cam)
-{
-       if (cam->input) {
-               input_report_key(cam->input, BTN_0, cam->buttonsts);
-               input_sync(cam->input);
-       }
-}
-
-#else
-
-static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }
-static inline void konicawc_unregister_input(struct konicawc *cam) { }
-static inline void konicawc_report_buttonstat(struct konicawc *cam) { }
-
-#endif /* CONFIG_INPUT */
-
-static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
-{
-       char *cdata;
-       int i, totlen = 0;
-       unsigned char *status = stsurb->transfer_buffer;
-       int keep = 0, discard = 0, bad = 0;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       for (i = 0; i < dataurb->number_of_packets; i++) {
-               int button = cam->buttonsts;
-               unsigned char sts;
-               int n = dataurb->iso_frame_desc[i].actual_length;
-               int st = dataurb->iso_frame_desc[i].status;
-               cdata = dataurb->transfer_buffer +
-                       dataurb->iso_frame_desc[i].offset;
-
-               /* Detect and ignore errored packets */
-               if (st < 0) {
-                       DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
-                             i, n, st);
-                       uvd->stats.iso_err_count++;
-                       continue;
-               }
-
-               /* Detect and ignore empty packets */
-               if (n <= 0) {
-                       uvd->stats.iso_skip_count++;
-                       continue;
-               }
-
-               /* See what the status data said about the packet */
-               sts = *(status+stsurb->iso_frame_desc[i].offset);
-
-               /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
-                * otherwise:
-                * bit 0 0: keep packet
-                *       1: drop packet (padding data)
-                *
-                * bit 4 0 button not clicked
-                *       1 button clicked
-                * button is used to `take a picture' (in software)
-                */
-
-               if(sts < 0x80) {
-                       button = !!(sts & 0x40);
-                       sts &= ~0x40;
-               }
-               
-               /* work out the button status, but don't do
-                  anything with it for now */
-
-               if(button != cam->buttonsts) {
-                       DEBUG(2, "button: %sclicked", button ? "" : "un");
-                       cam->buttonsts = button;
-                       konicawc_report_buttonstat(cam);
-               }
-
-               if(sts == 0x01) { /* drop frame */
-                       discard++;
-                       continue;
-               }
-               
-               if((sts > 0x01) && (sts < 0x80)) {
-                       info("unknown status %2.2x", sts);
-                       bad++;
-                       continue;
-               }
-               if(!sts && cam->lastframe == -2) {
-                       DEBUG(2, "dropping frame looking for image start");
-                       continue;
-               }
-
-               keep++;
-               if(sts & 0x80) { /* frame start */
-                       unsigned char marker[] = { 0, 0xff, 0, 0x00 };
-
-                       if(cam->lastframe == -2) {
-                               DEBUG(2, "found initial image");
-                               cam->lastframe = -1;
-                       }
-                               
-                       marker[3] = sts & 0x7F;
-                       RingQueue_Enqueue(&uvd->dp, marker, 4);
-                       totlen += 4;
-               }
-
-               totlen += n;    /* Little local accounting */
-               RingQueue_Enqueue(&uvd->dp, cdata, n);
-       }
-       DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
-                   keep, discard, bad, totlen);
-       return totlen;
-}
-
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
-        int i, ret;
-        for (i = 0; i < FRAMES_PER_DESC; i++) {
-                urb->iso_frame_desc[i].status = 0;
-        }
-        urb->dev = uvd->dev;
-        urb->status = 0;
-       ret = usb_submit_urb(urb, GFP_ATOMIC);
-       DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
-        if(ret)
-                err("usb_submit_urb error (%d)", ret);
-
-}
-
-
-static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct uvd *uvd = urb->context;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       /* We don't want to do anything if we are about to be removed! */
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-
-       if (!uvd->streaming) {
-               DEBUG(1, "Not streaming, but interrupt!");
-               return;
-       }
-
-       DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
-
-       uvd->stats.urb_count++;
-
-       if (urb->transfer_buffer_length > 32) {
-               cam->last_data_urb = urb;
-               return;
-       }
-       /* Copy the data received into ring queue */
-       if(cam->last_data_urb) {
-               int len = 0;
-               if(urb->start_frame != cam->last_data_urb->start_frame)
-                       err("Lost sync on frames");
-               else if (!urb->status && !cam->last_data_urb->status)
-                       len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
-
-               resubmit_urb(uvd, cam->last_data_urb);
-               resubmit_urb(uvd, urb);
-               cam->last_data_urb = NULL;
-               uvd->stats.urb_length = len;
-               uvd->stats.data_count += len;
-               if(len)
-                       RingQueue_WakeUpInterruptible(&uvd->dp);
-               return;
-       }
-       return;
-}
-
-
-static int konicawc_start_data(struct uvd *uvd)
-{
-       struct usb_device *dev = uvd->dev;
-       int i, errFlag;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       int pktsz;
-       struct usb_interface *intf;
-       struct usb_host_interface *interface = NULL;
-
-       intf = usb_ifnum_to_if(dev, uvd->iface);
-       if (intf)
-               interface = usb_altnum_to_altsetting(intf,
-                               spd_to_iface[cam->speed]);
-       if (!interface)
-               return -ENXIO;
-       pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize);
-       DEBUG(1, "pktsz = %d", pktsz);
-       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-               err("Camera is not operational");
-               return -EFAULT;
-       }
-       uvd->curframe = -1;
-       konicawc_camera_on(uvd);
-       /* Alternate interface 1 is is the biggest frame size */
-       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
-       if (i < 0) {
-               err("usb_set_interface error");
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-
-       /* We double buffer the Iso lists */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               int j, k;
-               struct urb *urb = uvd->sbuf[i].urb;
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = uvd->sbuf[i].data;
-               urb->complete = konicawc_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
-               for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = pktsz;
-               }
-
-               urb = cam->sts_urb[i];
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = cam->sts_buf[i];
-               urb->complete = konicawc_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = FRAMES_PER_DESC;
-               for (j=0; j < FRAMES_PER_DESC; j++) {
-                       urb->iso_frame_desc[j].offset = j;
-                       urb->iso_frame_desc[j].length = 1;
-               }
-       }
-
-       cam->last_data_urb = NULL;
-       
-       /* Submit all URBs */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
-               if (errFlag)
-                       err("usb_submit_isoc(%d) ret %d", i, errFlag);
-
-               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-               if (errFlag)
-                       err ("usb_submit_isoc(%d) ret %d", i, errFlag);
-       }
-
-       uvd->streaming = 1;
-       DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
-       return 0;
-}
-
-
-static void konicawc_stop_data(struct uvd *uvd)
-{
-       int i, j;
-       struct konicawc *cam;
-
-       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-               return;
-
-       konicawc_camera_off(uvd);
-       uvd->streaming = 0;
-       cam = (struct konicawc *)uvd->user_data;
-       cam->last_data_urb = NULL;
-
-       /* Unschedule all of the iso td's */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               usb_kill_urb(uvd->sbuf[i].urb);
-               usb_kill_urb(cam->sts_urb[i]);
-       }
-
-       if (!uvd->remove_pending) {
-               /* Set packet size to 0 */
-               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
-               if (j < 0) {
-                       err("usb_set_interface() error %d.", j);
-                       uvd->last_error = j;
-               }
-       }
-}
-
-
-static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{      
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       int maxline = cam->maxline;
-       int yplanesz = cam->yplanesz;
-
-       assert(frame != NULL);
-
-       DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
-       DEBUG(3, "Frame state = %d", frame->scanstate);
-
-       if(frame->scanstate == ScanState_Scanning) {
-               int drop = 0;
-               int curframe;
-               int fdrops = 0;
-               DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
-               while(RingQueue_GetLength(&uvd->dp) >= 4) {
-                       if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
-                           (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
-                               curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
-                               if(cam->lastframe >= 0) {
-                                       fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
-                                       fdrops--;
-                                       if(fdrops) {
-                                               info("Dropped %d frames (%d -> %d)", fdrops,
-                                                    cam->lastframe, curframe);
-                                       }
-                               }
-                               cam->lastframe = curframe;
-                               frame->curline = 0;
-                               frame->scanstate = ScanState_Lines;
-                               RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
-                               break;
-                       }
-                       RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
-                       drop++;
-               }
-               if(drop)
-                       DEBUG(2, "dropped %d bytes looking for new frame", drop);
-       }
-
-       if(frame->scanstate == ScanState_Scanning)
-               return;
-               
-       /* Try to move data from queue into frame buffer
-        * We get data in blocks of 384 bytes made up of:
-        * 256 Y, 64 U, 64 V.
-        * This needs to be written out as a Y plane, a U plane and a V plane.
-        */
-               
-       while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
-               /* Y */
-               RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
-               /* U */
-               RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
-               /* V */
-               RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
-               frame->seqRead_Length += 384;
-               frame->curline++;
-       }
-       /* See if we filled the frame */
-       if (frame->curline == maxline) {
-               DEBUG(5, "got whole frame");
-
-               frame->frameState = FrameState_Done_Hold;
-               frame->curline = 0;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-
-static int konicawc_find_fps(int size, int fps)
-{
-       int i;
-
-       fps *= 3;
-       DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
-       if(fps <= spd_to_fps[size][0])
-               return 0;
-
-       if(fps >= spd_to_fps[size][MAX_SPEED])
-               return MAX_SPEED;
-
-       for(i = 0; i < MAX_SPEED; i++) {
-               if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
-                       DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
-                       if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
-                               return i;
-                       else
-                               return i+1;
-               }
-       }
-       return MAX_SPEED+1;
-}
-
-
-static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       int newspeed = cam->speed;
-       int newsize;
-       int x = vw->width;
-       int y = vw->height;
-       int fps = vw->flags;
-
-       if(x > 0 && y > 0) {
-               DEBUG(2, "trying to find size %d,%d", x, y);
-               for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
-                       if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
-                               break;
-               }
-       } else {
-               newsize = cam->size;
-       }
-
-       if(newsize > MAX_FRAME_SIZE) {
-               DEBUG(1, "couldn't find size %d,%d", x, y);
-               return -EINVAL;
-       }
-
-       if(fps > 0) {
-               DEBUG(1, "trying to set fps to %d", fps);
-               newspeed = konicawc_find_fps(newsize, fps);
-               DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
-       }
-
-       if(newspeed > MAX_SPEED)
-               return -EINVAL;
-
-       DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
-       if((newsize == cam->size) && (newspeed == cam->speed)) {
-               DEBUG(1, "Nothing to do");
-               return 0;
-       }
-       DEBUG(0, "setting to  %dx%d @ %d fps", camera_sizes[newsize].width,
-            camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
-
-       konicawc_stop_data(uvd);
-       uvd->ifaceAltActive = spd_to_iface[newspeed];
-       DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
-       cam->speed = newspeed;
-
-       if(cam->size != newsize) {
-               cam->size = newsize;
-               konicawc_set_camera_size(uvd);
-       }
-
-       /* Flush the input queue and clear any current frame in progress */
-
-       RingQueue_Flush(&uvd->dp);
-       cam->lastframe = -2;
-       if(uvd->curframe != -1) {
-               uvd->frame[uvd->curframe].curline = 0;
-               uvd->frame[uvd->curframe].seqRead_Length = 0;
-               uvd->frame[uvd->curframe].seqRead_Index = 0;
-       }
-
-       konicawc_start_data(uvd);
-       return 0;
-}
-
-
-static int konicawc_calculate_fps(struct uvd *uvd)
-{
-       struct konicawc *cam = uvd->user_data;
-       return spd_to_fps[cam->size][cam->speed]/3;
-}
-
-
-static void konicawc_configure_video(struct uvd *uvd)
-{
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-       u8 buf[2];
-
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
-       RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
-       RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
-       RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
-       RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
-
-       cam->brightness = brightness / 11;
-       cam->contrast = contrast / 11;
-       cam->saturation = saturation / 11;
-       cam->sharpness = sharpness / 11;
-       cam->white_bal = whitebal / 11;
-
-       uvd->vpic.colour = 108;
-       uvd->vpic.hue = 108;
-       uvd->vpic.brightness = brightness;
-       uvd->vpic.contrast = contrast;
-       uvd->vpic.whiteness = whitebal;
-       uvd->vpic.depth = 6;
-       uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "Konica Webcam");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-       uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
-       uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
-       uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
-       uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0 ;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-
-       /* Talk to device */
-       DEBUG(1, "device init");
-       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
-               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
-       if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
-               DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
-       if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
-               DEBUG(2, "2,0,d failed");
-       DEBUG(1, "setting initial values");
-}
-
-static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct uvd *uvd = NULL;
-       int ix, i, nas;
-       int actInterface=-1, inactInterface=-1, maxPS=0;
-       unsigned char video_ep = 0;
-
-       DEBUG(1, "konicawc_probe(%p)", intf);
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       info("Konica Webcam (rev. 0x%04x)", le16_to_cpu(dev->descriptor.bcdDevice));
-       RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
-
-       /* Validate found interface: must have one ISO endpoint */
-       nas = intf->num_altsetting;
-       if (nas != 8) {
-               err("Incorrect number of alternate settings (%d) for this camera!", nas);
-               return -ENODEV;
-       }
-       /* Validate all alternate settings */
-       for (ix=0; ix < nas; ix++) {
-               const struct usb_host_interface *interface;
-               const struct usb_endpoint_descriptor *endpoint;
-
-               interface = &intf->altsetting[ix];
-               i = interface->desc.bAlternateSetting;
-               if (interface->desc.bNumEndpoints != 2) {
-                       err("Interface %d. has %u. endpoints!",
-                           interface->desc.bInterfaceNumber,
-                           (unsigned)(interface->desc.bNumEndpoints));
-                       return -ENODEV;
-               }
-               endpoint = &interface->endpoint[1].desc;
-               DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
-                   endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize));
-               if (video_ep == 0)
-                       video_ep = endpoint->bEndpointAddress;
-               else if (video_ep != endpoint->bEndpointAddress) {
-                       err("Alternate settings have different endpoint addresses!");
-                       return -ENODEV;
-               }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
-                       err("Interface %d. has non-ISO endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
-                       err("Interface %d. has ISO OUT endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
-                       if (inactInterface < 0)
-                               inactInterface = i;
-                       else {
-                               err("More than one inactive alt. setting!");
-                               return -ENODEV;
-                       }
-               } else {
-                       if (i == spd_to_iface[speed]) {
-                               /* This one is the requested one */
-                               actInterface = i;
-                       }
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS)
-                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-       }
-       if(actInterface == -1) {
-               err("Cant find required endpoint");
-               return -ENODEV;
-       }
-
-       DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (uvd != NULL) {
-               struct konicawc *cam = (struct konicawc *)(uvd->user_data);
-               /* Here uvd is a fully allocated uvd object */
-               for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
-                       cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-                       if(cam->sts_urb[i] == NULL) {
-                               while(i--) {
-                                       usb_free_urb(cam->sts_urb[i]);
-                               }
-                               err("can't allocate urbs");
-                               return -ENOMEM;
-                       }
-               }
-               cam->speed = speed;
-               RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
-               cam->width = camera_sizes[size].width;
-               cam->height = camera_sizes[size].height;
-               cam->size = size;
-
-               uvd->flags = 0;
-               uvd->debug = debug;
-               uvd->dev = dev;
-               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
-               uvd->ifaceAltInactive = inactInterface;
-               uvd->ifaceAltActive = actInterface;
-               uvd->video_endp = video_ep;
-               uvd->iso_packet_len = maxPS;
-               uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
-               uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
-               uvd->canvas = VIDEOSIZE(320, 240);
-               uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
-               /* Initialize konicawc specific data */
-               konicawc_configure_video(uvd);
-
-               i = usbvideo_RegisterVideoDevice(uvd);
-               uvd->max_frame_size = (320 * 240 * 3)/2;
-               if (i != 0) {
-                       err("usbvideo_RegisterVideoDevice() failed.");
-                       uvd = NULL;
-               }
-
-               konicawc_register_input(cam, dev);
-       }
-
-       if (uvd) {
-               usb_set_intfdata (intf, uvd);
-               return 0;
-       }
-       return -EIO;
-}
-
-
-static void konicawc_free_uvd(struct uvd *uvd)
-{
-       int i;
-       struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
-       konicawc_unregister_input(cam);
-
-       for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
-               usb_free_urb(cam->sts_urb[i]);
-               cam->sts_urb[i] = NULL;
-       }
-}
-
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
-       { }  /* Terminating entry */
-};
-
-
-static int __init konicawc_init(void)
-{
-       struct usbvideo_cb cbTbl;
-       info(DRIVER_DESC " " DRIVER_VERSION);
-       memset(&cbTbl, 0, sizeof(cbTbl));
-       cbTbl.probe = konicawc_probe;
-       cbTbl.setupOnOpen = konicawc_setup_on_open;
-       cbTbl.processData = konicawc_process_isoc;
-       cbTbl.getFPS = konicawc_calculate_fps;
-       cbTbl.setVideoMode = konicawc_set_video_mode;
-       cbTbl.startDataPump = konicawc_start_data;
-       cbTbl.stopDataPump = konicawc_stop_data;
-       cbTbl.adjustPicture = konicawc_adjust_picture;
-       cbTbl.userFree = konicawc_free_uvd;
-       return usbvideo_register(
-               &cams,
-               MAX_CAMERAS,
-               sizeof(struct konicawc),
-               "konicawc",
-               &cbTbl,
-               THIS_MODULE,
-               id_table);
-}
-
-
-static void __exit konicawc_cleanup(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-module_param(speed, int, 0);
-MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
-module_param(saturation, int, 0);
-MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
-module_param(whitebal, int, 0);
-MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(konicawc_init);
-module_exit(konicawc_cleanup);
diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
deleted file mode 100644 (file)
index da44579..0000000
+++ /dev/null
@@ -1,5932 +0,0 @@
-/*
- * OmniVision OV511 Camera-to-USB Bridge Driver
- *
- * Copyright (c) 1999-2003 Mark W. McClelland
- * Original decompression code Copyright 1998-2000 OmniVision Technologies
- * Many improvements by Bret Wallach <bwallac1@san.rr.com>
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- * Snapshot code by Kevin Moore
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka <claudio@conectiva.com>
- * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * URB error messages from pwc driver by Nemosoft
- * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
- * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
- *
- * Based on the Linux CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt.
- * 
- * Please see the file: Documentation/usb/ov511.txt
- * and the website at:  http://alpha.dyndns.org/ov511
- * for more info.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <asm/semaphore.h>
-#include <asm/processor.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#if defined (__i386__)
-       #include <asm/cpufeature.h>
-#endif
-
-#include "ov511.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.64 for Linux 2.5"
-#define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-       & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-       <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "ov511 USB Camera Driver"
-
-#define OV511_I2C_RETRIES 3
-#define ENABLE_Y_QUANTABLE 1
-#define ENABLE_UV_QUANTABLE 1
-
-#define OV511_MAX_UNIT_VIDEO 16
-
-/* Pixel count * bytes per YUV420 pixel (1.5) */
-#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
-
-#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
-
-/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
-#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
-
-#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
-/**********************************************************************
- * Module Parameters
- * (See ov511.txt for detailed descriptions of these)
- **********************************************************************/
-
-/* These variables (and all static globals) default to zero */
-static int autobright          = 1;
-static int autogain            = 1;
-static int autoexp             = 1;
-static int debug;
-static int snapshot;
-static int cams                        = 1;
-static int compress;
-static int testpat;
-static int dumppix;
-static int led                         = 1;
-static int dump_bridge;
-static int dump_sensor;
-static int printph;
-static int phy                 = 0x1f;
-static int phuv                        = 0x05;
-static int pvy                 = 0x06;
-static int pvuv                        = 0x06;
-static int qhy                 = 0x14;
-static int qhuv                        = 0x03;
-static int qvy                 = 0x04;
-static int qvuv                        = 0x04;
-static int lightfreq;
-static int bandingfilter;
-static int clockdiv            = -1;
-static int packetsize          = -1;
-static int framedrop           = -1;
-static int fastset;
-static int force_palette;
-static int backlight;
-static int unit_video[OV511_MAX_UNIT_VIDEO];
-static int remove_zeros;
-static int mirror;
-static int ov518_color;
-
-module_param(autobright, int, 0);
-MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
-module_param(autogain, int, 0);
-MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
-module_param(autoexp, int, 0);
-MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
-  "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
-module_param(snapshot, int, 0);
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
-module_param(cams, int, 0);
-MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
-module_param(compress, int, 0);
-MODULE_PARM_DESC(compress, "Turn on compression");
-module_param(testpat, int, 0);
-MODULE_PARM_DESC(testpat,
-  "Replace image with vertical bar testpattern (only partially working)");
-module_param(dumppix, int, 0);
-MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
-module_param(led, int, 0);
-MODULE_PARM_DESC(led,
-  "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
-module_param(dump_bridge, int, 0);
-MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
-module_param(dump_sensor, int, 0);
-MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
-module_param(printph, int, 0);
-MODULE_PARM_DESC(printph, "Print frame start/end headers");
-module_param(phy, int, 0);
-MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
-module_param(phuv, int, 0);
-MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
-module_param(pvy, int, 0);
-MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
-module_param(pvuv, int, 0);
-MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
-module_param(qhy, int, 0);
-MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
-module_param(qhuv, int, 0);
-MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
-module_param(qvy, int, 0);
-MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
-module_param(qvuv, int, 0);
-MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
-module_param(lightfreq, int, 0);
-MODULE_PARM_DESC(lightfreq,
-  "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
-module_param(bandingfilter, int, 0);
-MODULE_PARM_DESC(bandingfilter,
-  "Enable banding filter (to reduce effects of fluorescent lighting)");
-module_param(clockdiv, int, 0);
-MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
-module_param(packetsize, int, 0);
-MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
-module_param(framedrop, int, 0);
-MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
-module_param(fastset, int, 0);
-MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
-module_param(force_palette, int, 0);
-MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-module_param(backlight, int, 0);
-MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static int num_uv;
-module_param_array(unit_video, int, &num_uv, 0);
-MODULE_PARM_DESC(unit_video,
-  "Force use of specific minor number(s). 0 is not allowed.");
-module_param(remove_zeros, int, 0);
-MODULE_PARM_DESC(remove_zeros,
-  "Remove zero-padding from uncompressed incoming data");
-module_param(mirror, int, 0);
-MODULE_PARM_DESC(mirror, "Reverse image horizontally");
-module_param(ov518_color, int, 0);
-MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/**********************************************************************
- * Miscellaneous Globals
- **********************************************************************/
-
-static struct usb_driver ov511_driver;
-
-/* Number of times to retry a failed I2C transaction. Increase this if you
- * are getting "Failed to read sensor ID..." */
-static const int i2c_detect_tries = 5;
-
-static struct usb_device_id device_table [] = {
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) },
-       { USB_DEVICE(VEND_OMNIVISION, PROD_OV518PLUS) },
-       { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
-       { }  /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
-
-/**********************************************************************
- * Symbolic Names
- **********************************************************************/
-
-/* Known OV511-based cameras */
-static struct symbolic_list camlist[] = {
-       {   0, "Generic Camera (no ID)" },
-       {   1, "Mustek WCam 3X" },
-       {   3, "D-Link DSB-C300" },
-       {   4, "Generic OV511/OV7610" },
-       {   5, "Puretek PT-6007" },
-       {   6, "Lifeview USB Life TV (NTSC)" },
-       {  21, "Creative Labs WebCam 3" },
-       {  22, "Lifeview USB Life TV (PAL D/K+B/G)" },
-       {  36, "Koala-Cam" },
-       {  38, "Lifeview USB Life TV (PAL)" },
-       {  41, "Samsung Anycam MPC-M10" },
-       {  43, "Mtekvision Zeca MV402" },
-       {  46, "Suma eON" },
-       {  70, "Lifeview USB Life TV (PAL/SECAM)" },
-       { 100, "Lifeview RoboCam" },
-       { 102, "AverMedia InterCam Elite" },
-       { 112, "MediaForte MV300" },    /* or OV7110 evaluation kit */
-       { 134, "Ezonics EZCam II" },
-       { 192, "Webeye 2000B" },
-       { 253, "Alpha Vision Tech. AlphaCam SE" },
-       {  -1, NULL }
-};
-
-/* Video4Linux1 Palettes */
-static struct symbolic_list v4l1_plist[] = {
-       { VIDEO_PALETTE_GREY,   "GREY" },
-       { VIDEO_PALETTE_HI240,  "HI240" },
-       { VIDEO_PALETTE_RGB565, "RGB565" },
-       { VIDEO_PALETTE_RGB24,  "RGB24" },
-       { VIDEO_PALETTE_RGB32,  "RGB32" },
-       { VIDEO_PALETTE_RGB555, "RGB555" },
-       { VIDEO_PALETTE_YUV422, "YUV422" },
-       { VIDEO_PALETTE_YUYV,   "YUYV" },
-       { VIDEO_PALETTE_UYVY,   "UYVY" },
-       { VIDEO_PALETTE_YUV420, "YUV420" },
-       { VIDEO_PALETTE_YUV411, "YUV411" },
-       { VIDEO_PALETTE_RAW,    "RAW" },
-       { VIDEO_PALETTE_YUV422P,"YUV422P" },
-       { VIDEO_PALETTE_YUV411P,"YUV411P" },
-       { VIDEO_PALETTE_YUV420P,"YUV420P" },
-       { VIDEO_PALETTE_YUV410P,"YUV410P" },
-       { -1, NULL }
-};
-
-static struct symbolic_list brglist[] = {
-       { BRG_OV511,            "OV511" },
-       { BRG_OV511PLUS,        "OV511+" },
-       { BRG_OV518,            "OV518" },
-       { BRG_OV518PLUS,        "OV518+" },
-       { -1, NULL }
-};
-
-static struct symbolic_list senlist[] = {
-       { SEN_OV76BE,   "OV76BE" },
-       { SEN_OV7610,   "OV7610" },
-       { SEN_OV7620,   "OV7620" },
-       { SEN_OV7620AE, "OV7620AE" },
-       { SEN_OV6620,   "OV6620" },
-       { SEN_OV6630,   "OV6630" },
-       { SEN_OV6630AE, "OV6630AE" },
-       { SEN_OV6630AF, "OV6630AF" },
-       { SEN_OV8600,   "OV8600" },
-       { SEN_KS0127,   "KS0127" },
-       { SEN_KS0127B,  "KS0127B" },
-       { SEN_SAA7111A, "SAA7111A" },
-       { -1, NULL }
-};
-
-/* URB error codes: */
-static struct symbolic_list urb_errlist[] = {
-       { -ENOSR,       "Buffer error (overrun)" },
-       { -EPIPE,       "Stalled (device not responding)" },
-       { -EOVERFLOW,   "Babble (bad cable?)" },
-       { -EPROTO,      "Bit-stuff error (bad cable?)" },
-       { -EILSEQ,      "CRC/Timeout" },
-       { -ETIMEDOUT,   "NAK (device does not respond)" },
-       { -1, NULL }
-};
-
-/**********************************************************************
- * Memory management
- **********************************************************************/
-static void *
-rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void
-rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-/**********************************************************************
- *
- * Register I/O
- *
- **********************************************************************/
-
-/* Write an OV51x register */
-static int
-reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       mutex_lock(&ov->cbuf_lock);
-       ov->cbuf[0] = value;
-       rc = usb_control_msg(ov->dev,
-                            usb_sndctrlpipe(ov->dev, 0),
-                            (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
-                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-       mutex_unlock(&ov->cbuf_lock);
-
-       if (rc < 0)
-               err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
-
-       return rc;
-}
-
-/* Read from an OV51x register */
-/* returns: negative is error, pos or zero is data */
-static int
-reg_r(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->cbuf_lock);
-       rc = usb_control_msg(ov->dev,
-                            usb_rcvctrlpipe(ov->dev, 0),
-                            (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
-                            USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-
-       if (rc < 0) {
-               err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
-       } else {
-               rc = ov->cbuf[0];
-               PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
-       }
-
-       mutex_unlock(&ov->cbuf_lock);
-
-       return rc;
-}
-
-/*
- * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-reg_w_mask(struct usb_ov511 *ov,
-          unsigned char reg,
-          unsigned char value,
-          unsigned char mask)
-{
-       int ret;
-       unsigned char oldval, newval;
-
-       ret = reg_r(ov, reg);
-       if (ret < 0)
-               return ret;
-
-       oldval = (unsigned char) ret;
-       oldval &= (~mask);              /* Clear the masked bits */
-       value &= mask;                  /* Enforce mask on value */
-       newval = oldval | value;        /* Set the desired bits */
-
-       return (reg_w(ov, reg, newval));
-}
-
-/* 
- * Writes multiple (n) byte value to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce).
- */
-static int
-ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
-
-       mutex_lock(&ov->cbuf_lock);
-
-       *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
-
-       rc = usb_control_msg(ov->dev,
-                            usb_sndctrlpipe(ov->dev, 0),
-                            1 /* REG_IO */,
-                            USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                            0, (__u16)reg, ov->cbuf, n, 1000);
-       mutex_unlock(&ov->cbuf_lock);
-
-       if (rc < 0)
-               err("reg write multiple: error %d: %s", rc,
-                   symbolic(urb_errlist, rc));
-
-       return rc;
-}
-
-static int
-ov511_upload_quan_tables(struct usb_ov511 *ov)
-{
-       unsigned char *pYTable = yQuanTable511;
-       unsigned char *pUVTable = uvQuanTable511;
-       unsigned char val0, val1;
-       int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-       PDEBUG(4, "Uploading quantization tables");
-
-       for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
-               if (ENABLE_Y_QUANTABLE) {
-                       val0 = *pYTable++;
-                       val1 = *pYTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               if (ENABLE_UV_QUANTABLE) {
-                       val0 = *pUVTable++;
-                       val1 = *pUVTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               reg++;
-       }
-
-       return 0;
-}
-
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
-ov518_upload_quan_tables(struct usb_ov511 *ov)
-{
-       unsigned char *pYTable = yQuanTable518;
-       unsigned char *pUVTable = uvQuanTable518;
-       unsigned char val0, val1;
-       int i, rc, reg = R511_COMP_LUT_BEGIN;
-
-       PDEBUG(4, "Uploading quantization tables");
-
-       for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
-               if (ENABLE_Y_QUANTABLE) {
-                       val0 = *pYTable++;
-                       val1 = *pYTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               if (ENABLE_UV_QUANTABLE) {
-                       val0 = *pUVTable++;
-                       val1 = *pUVTable++;
-                       val0 &= 0x0f;
-                       val1 &= 0x0f;
-                       val0 |= val1 << 4;
-                       rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
-                       if (rc < 0)
-                               return rc;
-               }
-
-               reg++;
-       }
-
-       return 0;
-}
-
-static int
-ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
-{
-       int rc;
-
-       /* Setting bit 0 not allowed on 518/518Plus */
-       if (ov->bclass == BCL_OV518)
-               reset_type &= 0xfe;
-
-       PDEBUG(4, "Reset: type=0x%02X", reset_type);
-
-       rc = reg_w(ov, R51x_SYS_RESET, reset_type);
-       rc = reg_w(ov, R51x_SYS_RESET, 0);
-
-       if (rc < 0)
-               err("reset: command failed");
-
-       return rc;
-}
-
-/**********************************************************************
- *
- * Low-level I2C I/O functions
- *
- **********************************************************************/
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_w(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_write_internal(struct usb_ov511 *ov,
-                        unsigned char reg,
-                        unsigned char value)
-{
-       int rc;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* Select camera register */
-       rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-       if (rc < 0)
-               return rc;
-
-       /* Write "value" to I2C data port of OV511 */
-       rc = reg_w(ov, R51x_I2C_DATA, value);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 3-byte write cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x01);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/* NOTE: Do not call this function directly! */
-static int
-ov511_i2c_write_internal(struct usb_ov511 *ov,
-                        unsigned char reg,
-                        unsigned char value)
-{
-       int rc, retries;
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* Three byte write cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Select camera register */
-               rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-               if (rc < 0)
-                       break;
-
-               /* Write "value" to I2C data port of OV511 */
-               rc = reg_w(ov, R51x_I2C_DATA, value);
-               if (rc < 0)
-                       break;
-
-               /* Initiate 3-byte write cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x01);
-               if (rc < 0)
-                       break;
-
-               /* Retry until idle */
-               do
-                       rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0)); 
-               if (rc < 0)
-                       break;
-
-               /* Ack? */
-               if ((rc&2) == 0) {
-                       rc = 0;
-                       break;
-               }
-#if 0
-               /* I2C abort */
-               reg_w(ov, R511_I2C_CTL, 0x10);
-#endif
-               if (--retries < 0) {
-                       err("i2c write retries exhausted");
-                       rc = -1;
-                       break;
-               }
-       }
-
-       return rc;
-}
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_r(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc, value;
-
-       /* Select camera register */
-       rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 2-byte write cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x03);
-       if (rc < 0)
-               return rc;
-
-       /* Initiate 2-byte read cycle */
-       rc = reg_w(ov, R518_I2C_CTL, 0x05);
-       if (rc < 0)
-               return rc;
-
-       value = reg_r(ov, R51x_I2C_DATA);
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       return value;
-}
-
-/* NOTE: Do not call this function directly!
- * returns: negative is error, pos or zero is data */
-static int
-ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc, value, retries;
-
-       /* Two byte write cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Select camera register */
-               rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-               if (rc < 0)
-                       return rc;
-
-               /* Initiate 2-byte write cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x03);
-               if (rc < 0)
-                       return rc;
-
-               /* Retry until idle */
-               do
-                        rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
-               if (rc < 0)
-                       return rc;
-
-               if ((rc&2) == 0) /* Ack? */
-                       break;
-
-               /* I2C abort */
-               reg_w(ov, R511_I2C_CTL, 0x10);
-
-               if (--retries < 0) {
-                       err("i2c write retries exhausted");
-                       return -1;
-               }
-       }
-
-       /* Two byte read cycle */
-       for (retries = OV511_I2C_RETRIES; ; ) {
-               /* Initiate 2-byte read cycle */
-               rc = reg_w(ov, R511_I2C_CTL, 0x05);
-               if (rc < 0)
-                       return rc;
-
-               /* Retry until idle */
-               do
-                       rc = reg_r(ov, R511_I2C_CTL);
-               while (rc > 0 && ((rc&1) == 0));
-               if (rc < 0)
-                       return rc;
-
-               if ((rc&2) == 0) /* Ack? */
-                       break;
-
-               /* I2C abort */
-               rc = reg_w(ov, R511_I2C_CTL, 0x10);
-               if (rc < 0)
-                       return rc;
-
-               if (--retries < 0) {
-                       err("i2c read retries exhausted");
-                       return -1;
-               }
-       }
-
-       value = reg_r(ov, R51x_I2C_DATA);
-
-       PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
-       /* This is needed to make i2c_w() work */
-       rc = reg_w(ov, R511_I2C_CTL, 0x05);
-       if (rc < 0)
-               return rc;
-
-       return value;
-}
-
-/* returns: negative is error, pos or zero is data */
-static int
-i2c_r(struct usb_ov511 *ov, unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_read_internal(ov, reg);
-       else
-               rc = ov511_i2c_read_internal(ov, reg);
-
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-static int
-i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_write_internal(ov, reg, value);
-       else
-               rc = ov511_i2c_write_internal(ov, reg, value);
-
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
-                             unsigned char reg,
-                             unsigned char value,
-                             unsigned char mask)
-{
-       int rc;
-       unsigned char oldval, newval;
-
-       if (mask == 0xff) {
-               newval = value;
-       } else {
-               if (ov->bclass == BCL_OV518)
-                       rc = ov518_i2c_read_internal(ov, reg);
-               else
-                       rc = ov511_i2c_read_internal(ov, reg);
-               if (rc < 0)
-                       return rc;
-
-               oldval = (unsigned char) rc;
-               oldval &= (~mask);              /* Clear the masked bits */
-               value &= mask;                  /* Enforce mask on value */
-               newval = oldval | value;        /* Set the desired bits */
-       }
-
-       if (ov->bclass == BCL_OV518)
-               return (ov518_i2c_write_internal(ov, reg, newval));
-       else
-               return (ov511_i2c_write_internal(ov, reg, newval));
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-i2c_w_mask(struct usb_ov511 *ov,
-          unsigned char reg,
-          unsigned char value,
-          unsigned char mask)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-       mutex_unlock(&ov->i2c_lock);
-
-       return rc;
-}
-
-/* Set the read and write slave IDs. The "slave" argument is the write slave,
- * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
- * when calling this. This should not be called from outside the i2c I/O
- * functions.
- */
-static int
-i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
-{
-       int rc;
-
-       rc = reg_w(ov, R51x_I2C_W_SID, slave);
-       if (rc < 0)
-               return rc;
-
-       rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
-i2c_w_slave(struct usb_ov511 *ov,
-           unsigned char slave,
-           unsigned char reg,
-           unsigned char value,
-           unsigned char mask)
-{
-       int rc = 0;
-
-       mutex_lock(&ov->i2c_lock);
-
-       /* Set new slave IDs */
-       rc = i2c_set_slave_internal(ov, slave);
-       if (rc < 0)
-               goto out;
-
-       rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-
-out:
-       /* Restore primary IDs */
-       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-               err("Couldn't restore primary I2C slave");
-
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-/* Read from a specific I2C slave ID and register */
-static int
-i2c_r_slave(struct usb_ov511 *ov,
-           unsigned char slave,
-           unsigned char reg)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       /* Set new slave IDs */
-       rc = i2c_set_slave_internal(ov, slave);
-       if (rc < 0)
-               goto out;
-
-       if (ov->bclass == BCL_OV518)
-               rc = ov518_i2c_read_internal(ov, reg);
-       else
-               rc = ov511_i2c_read_internal(ov, reg);
-
-out:
-       /* Restore primary IDs */
-       if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
-               err("Couldn't restore primary I2C slave");
-
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
-ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
-{
-       int rc;
-
-       mutex_lock(&ov->i2c_lock);
-
-       rc = i2c_set_slave_internal(ov, sid);
-       if (rc < 0)
-               goto out;
-
-       // FIXME: Is this actually necessary?
-       rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-out:
-       mutex_unlock(&ov->i2c_lock);
-       return rc;
-}
-
-static int
-write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
-{
-       int rc;
-
-       while (pRegvals->bus != OV511_DONE_BUS) {
-               if (pRegvals->bus == OV511_REG_BUS) {
-                       if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-                               return rc;
-               } else if (pRegvals->bus == OV511_I2C_BUS) {
-                       if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
-                               return rc;
-               } else {
-                       err("Bad regval array");
-                       return -1;
-               }
-               pRegvals++;
-       }
-       return 0;
-}
-
-#ifdef OV511_DEBUG
-static void
-dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-       int i, rc;
-
-       for (i = reg1; i <= regn; i++) {
-               rc = i2c_r(ov, i);
-               info("Sensor[0x%02X] = 0x%02X", i, rc);
-       }
-}
-
-static void
-dump_i2c_regs(struct usb_ov511 *ov)
-{
-       info("I2C REGS");
-       dump_i2c_range(ov, 0x00, 0x7C);
-}
-
-static void
-dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
-{
-       int i, rc;
-
-       for (i = reg1; i <= regn; i++) {
-               rc = reg_r(ov, i);
-               info("OV511[0x%02X] = 0x%02X", i, rc);
-       }
-}
-
-static void
-ov511_dump_regs(struct usb_ov511 *ov)
-{
-       info("CAMERA INTERFACE REGS");
-       dump_reg_range(ov, 0x10, 0x1f);
-       info("DRAM INTERFACE REGS");
-       dump_reg_range(ov, 0x20, 0x23);
-       info("ISO FIFO REGS");
-       dump_reg_range(ov, 0x30, 0x31);
-       info("PIO REGS");
-       dump_reg_range(ov, 0x38, 0x39);
-       dump_reg_range(ov, 0x3e, 0x3e);
-       info("I2C REGS");
-       dump_reg_range(ov, 0x40, 0x49);
-       info("SYSTEM CONTROL REGS");
-       dump_reg_range(ov, 0x50, 0x55);
-       dump_reg_range(ov, 0x5e, 0x5f);
-       info("OmniCE REGS");
-       dump_reg_range(ov, 0x70, 0x79);
-       /* NOTE: Quantization tables are not readable. You will get the value
-        * in reg. 0x79 for every table register */
-       dump_reg_range(ov, 0x80, 0x9f);
-       dump_reg_range(ov, 0xa0, 0xbf);
-
-}
-
-static void
-ov518_dump_regs(struct usb_ov511 *ov)
-{
-       info("VIDEO MODE REGS");
-       dump_reg_range(ov, 0x20, 0x2f);
-       info("DATA PUMP AND SNAPSHOT REGS");
-       dump_reg_range(ov, 0x30, 0x3f);
-       info("I2C REGS");
-       dump_reg_range(ov, 0x40, 0x4f);
-       info("SYSTEM CONTROL AND VENDOR REGS");
-       dump_reg_range(ov, 0x50, 0x5f);
-       info("60 - 6F");
-       dump_reg_range(ov, 0x60, 0x6f);
-       info("70 - 7F");
-       dump_reg_range(ov, 0x70, 0x7f);
-       info("Y QUANTIZATION TABLE");
-       dump_reg_range(ov, 0x80, 0x8f);
-       info("UV QUANTIZATION TABLE");
-       dump_reg_range(ov, 0x90, 0x9f);
-       info("A0 - BF");
-       dump_reg_range(ov, 0xa0, 0xbf);
-       info("CBR");
-       dump_reg_range(ov, 0xc0, 0xcf);
-}
-#endif
-
-/*****************************************************************************/
-
-/* Temporarily stops OV511 from functioning. Must do this before changing
- * registers while the camera is streaming */
-static inline int
-ov51x_stop(struct usb_ov511 *ov)
-{
-       PDEBUG(4, "stopping");
-       ov->stopped = 1;
-       if (ov->bclass == BCL_OV518)
-               return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
-       else
-               return (reg_w(ov, R51x_SYS_RESET, 0x3d));
-}
-
-/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
- * actually stopped (for performance). */
-static inline int
-ov51x_restart(struct usb_ov511 *ov)
-{
-       if (ov->stopped) {
-               PDEBUG(4, "restarting");
-               ov->stopped = 0;
-
-               /* Reinitialize the stream */
-               if (ov->bclass == BCL_OV518)
-                       reg_w(ov, 0x2f, 0x80);
-
-               return (reg_w(ov, R51x_SYS_RESET, 0x00));
-       }
-
-       return 0;
-}
-
-/* Sleeps until no frames are active. Returns !0 if got signal */
-static int
-ov51x_wait_frames_inactive(struct usb_ov511 *ov)
-{
-       return wait_event_interruptible(ov->wq, ov->curframe < 0);
-}
-
-/* Resets the hardware snapshot button */
-static void
-ov51x_clear_snapshot(struct usb_ov511 *ov)
-{
-       if (ov->bclass == BCL_OV511) {
-               reg_w(ov, R51x_SYS_SNAP, 0x00);
-               reg_w(ov, R51x_SYS_SNAP, 0x02);
-               reg_w(ov, R51x_SYS_SNAP, 0x00);
-       } else if (ov->bclass == BCL_OV518) {
-               warn("snapshot reset not supported yet on OV518(+)");
-       } else {
-               err("clear snap: invalid bridge type");
-       }
-}
-
-#if 0
-/* Checks the status of the snapshot button. Returns 1 if it was pressed since
- * it was last cleared, and zero in all other cases (including errors) */
-static int
-ov51x_check_snapshot(struct usb_ov511 *ov)
-{
-       int ret, status = 0;
-
-       if (ov->bclass == BCL_OV511) {
-               ret = reg_r(ov, R51x_SYS_SNAP);
-               if (ret < 0) {
-                       err("Error checking snspshot status (%d)", ret);
-               } else if (ret & 0x08) {
-                       status = 1;
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               warn("snapshot check not supported yet on OV518(+)");
-       } else {
-               err("check snap: invalid bridge type");
-       }
-
-       return status;
-}
-#endif
-
-/* This does an initial reset of an OmniVision sensor and ensures that I2C
- * is synchronized. Returns <0 for failure.
- */
-static int
-init_ov_sensor(struct usb_ov511 *ov)
-{
-       int i, success;
-
-       /* Reset the sensor */
-       if (i2c_w(ov, 0x12, 0x80) < 0)
-               return -EIO;
-
-       /* Wait for it to initialize */
-       msleep(150);
-
-       for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
-               if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-                   (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-                       success = 1;
-                       continue;
-               }
-
-               /* Reset the sensor */
-               if (i2c_w(ov, 0x12, 0x80) < 0)
-                       return -EIO;
-               /* Wait for it to initialize */
-               msleep(150);
-               /* Dummy read to sync I2C */
-               if (i2c_r(ov, 0x00) < 0)
-                       return -EIO;
-       }
-
-       if (!success)
-               return -EIO;
-
-       PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
-       return 0;
-}
-
-static int
-ov511_set_packet_size(struct usb_ov511 *ov, int size)
-{
-       int alt, mult;
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       mult = size >> 5;
-
-       if (ov->bridge == BRG_OV511) {
-               if (size == 0)
-                       alt = OV511_ALT_SIZE_0;
-               else if (size == 257)
-                       alt = OV511_ALT_SIZE_257;
-               else if (size == 513)
-                       alt = OV511_ALT_SIZE_513;
-               else if (size == 769)
-                       alt = OV511_ALT_SIZE_769;
-               else if (size == 993)
-                       alt = OV511_ALT_SIZE_993;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (size == 0)
-                       alt = OV511PLUS_ALT_SIZE_0;
-               else if (size == 33)
-                       alt = OV511PLUS_ALT_SIZE_33;
-               else if (size == 129)
-                       alt = OV511PLUS_ALT_SIZE_129;
-               else if (size == 257)
-                       alt = OV511PLUS_ALT_SIZE_257;
-               else if (size == 385)
-                       alt = OV511PLUS_ALT_SIZE_385;
-               else if (size == 513)
-                       alt = OV511PLUS_ALT_SIZE_513;
-               else if (size == 769)
-                       alt = OV511PLUS_ALT_SIZE_769;
-               else if (size == 961)
-                       alt = OV511PLUS_ALT_SIZE_961;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else {
-               err("Set packet size: Invalid bridge type");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
-
-       if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
-               return -EIO;
-
-       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-               err("Set packet size: set interface error");
-               return -EBUSY;
-       }
-
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       ov->packet_size = size;
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
- * optional packet number byte. The actual size *is* stored in ov->packet_size,
- * though. */
-static int
-ov518_set_packet_size(struct usb_ov511 *ov, int size)
-{
-       int alt;
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       if (ov->bclass == BCL_OV518) {
-               if (size == 0)
-                       alt = OV518_ALT_SIZE_0;
-               else if (size == 128)
-                       alt = OV518_ALT_SIZE_128;
-               else if (size == 256)
-                       alt = OV518_ALT_SIZE_256;
-               else if (size == 384)
-                       alt = OV518_ALT_SIZE_384;
-               else if (size == 512)
-                       alt = OV518_ALT_SIZE_512;
-               else if (size == 640)
-                       alt = OV518_ALT_SIZE_640;
-               else if (size == 768)
-                       alt = OV518_ALT_SIZE_768;
-               else if (size == 896)
-                       alt = OV518_ALT_SIZE_896;
-               else {
-                       err("Set packet size: invalid size (%d)", size);
-                       return -EINVAL;
-               }
-       } else {
-               err("Set packet size: Invalid bridge type");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d, alt=%d", size, alt);
-
-       ov->packet_size = size;
-       if (size > 0) {
-               /* Program ISO FIFO size reg (packet number isn't included) */
-               ov518_reg_w32(ov, 0x30, size, 2);
-
-               if (ov->packet_numbering)
-                       ++ov->packet_size;
-       }
-
-       if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
-               err("Set packet size: set interface error");
-               return -EBUSY;
-       }
-
-       /* Initialize the stream */
-       if (reg_w(ov, 0x2f, 0x80) < 0)
-               return -EIO;
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov511_init_compression(struct usb_ov511 *ov)
-{
-       int rc = 0;
-
-       if (!ov->compress_inited) {
-               reg_w(ov, 0x70, phy);
-               reg_w(ov, 0x71, phuv);
-               reg_w(ov, 0x72, pvy);
-               reg_w(ov, 0x73, pvuv);
-               reg_w(ov, 0x74, qhy);
-               reg_w(ov, 0x75, qhuv);
-               reg_w(ov, 0x76, qvy);
-               reg_w(ov, 0x77, qvuv);
-
-               if (ov511_upload_quan_tables(ov) < 0) {
-                       err("Error uploading quantization tables");
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-
-       ov->compress_inited = 1;
-out:
-       return rc;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov518_init_compression(struct usb_ov511 *ov)
-{
-       int rc = 0;
-
-       if (!ov->compress_inited) {
-               if (ov518_upload_quan_tables(ov) < 0) {
-                       err("Error uploading quantization tables");
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-
-       ov->compress_inited = 1;
-out:
-       return rc;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's contrast setting to "val" */
-static int
-sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       {
-               rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_OV6630:
-       {
-               rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_OV7620:
-       {
-               unsigned char ctab[] = {
-                       0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
-                       0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-               };
-
-               /* Use Y gamma control instead. Bit 0 enables it. */
-               rc = i2c_w(ov, 0x64, ctab[val>>12]);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       case SEN_SAA7111A:
-       {
-               rc = i2c_w(ov, 0x0b, val >> 9);
-               if (rc < 0)
-                       goto out;
-               break;
-       }
-       default:
-       {
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-       }
-
-       rc = 0;         /* Success */
-       ov->contrast = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's contrast setting */
-static int
-sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-               rc = i2c_r(ov, OV7610_REG_CNT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_CNT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 12;
-               break;
-       case SEN_OV7620:
-               /* Use Y gamma reg instead. Bit 0 is the enable bit. */
-               rc = i2c_r(ov, 0x64);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = (rc & 0xfe) << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->contrast;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->contrast = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's brightness setting to "val" */
-static int
-sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(4, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-               /* 7620 doesn't like manual changes when in auto mode */
-               if (!ov->auto_brt) {
-                       rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
-                       if (rc < 0)
-                               goto out;
-               }
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0a, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->brightness = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's brightness setting */
-static int
-sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV7620:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_BRT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->brightness;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->brightness = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's saturation (color intensity) setting to "val" */
-static int
-sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-//             /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-//             rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
-//             if (rc < 0)
-//                     goto out;
-               rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0c, val >> 9);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->colour = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's saturation (color intensity) setting */
-static int
-sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_SAT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV7620:
-//             /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-//             rc = i2c_r(ov, 0x62);
-//             if (rc < 0)
-//                     return rc;
-//             else
-//                     *val = (rc & 0x7e) << 9;
-               rc = i2c_r(ov, OV7610_REG_SAT);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->colour;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->colour = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's hue (red/blue balance) setting to "val" */
-static int
-sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
-               if (rc < 0)
-                       goto out;
-
-               rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       case SEN_OV7620:
-// Hue control is causing problems. I will enable it once it's fixed.
-#if 0
-               rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
-               if (rc < 0)
-                       goto out;
-
-               rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
-               if (rc < 0)
-                       goto out;
-#endif
-               break;
-       case SEN_SAA7111A:
-               rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
-               if (rc < 0)
-                       goto out;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               rc = -EPERM;
-               goto out;
-       }
-
-       rc = 0;         /* Success */
-       ov->hue = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-
-/* Gets sensor's hue (red/blue balance) setting */
-static int
-sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = i2c_r(ov, OV7610_REG_BLUE);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_OV7620:
-               rc = i2c_r(ov, 0x7a);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc << 8;
-               break;
-       case SEN_SAA7111A:
-               *val = ov->hue;
-               break;
-       default:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->hue = *val;
-
-       return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static int
-sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-       int rc;
-
-       PDEBUG(4, "sensor_set_picture");
-
-       ov->whiteness = p->whiteness;
-
-       /* Don't return error if a setting is unsupported, or rest of settings
-         * will not be performed */
-
-       rc = sensor_set_contrast(ov, p->contrast);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_brightness(ov, p->brightness);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_saturation(ov, p->colour);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_hue(ov, p->hue);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       return 0;
-}
-
-static int
-sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
-       int rc;
-
-       PDEBUG(4, "sensor_get_picture");
-
-       /* Don't return error if a setting is unsupported, or rest of settings
-         * will not be performed */
-
-       rc = sensor_get_contrast(ov, &(p->contrast));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_brightness(ov, &(p->brightness));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_saturation(ov, &(p->colour));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_get_hue(ov, &(p->hue));
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       p->whiteness = 105 << 8;
-
-       return 0;
-}
-
-#if 0
-// FIXME: Exposure range is only 0x00-0x7f in interlace mode
-/* Sets current exposure for sensor. This only has an effect if auto-exposure
- * is off */
-static inline int
-sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
-{
-       int rc;
-
-       PDEBUG(3, "%d", val);
-
-       if (ov->stop_during_set)
-               if (ov51x_stop(ov) < 0)
-                       return -EIO;
-
-       switch (ov->sensor) {
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               rc = i2c_w(ov, 0x10, val);
-               if (rc < 0)
-                       goto out;
-
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_exposure");
-               return -EINVAL;
-       }
-
-       rc = 0;         /* Success */
-       ov->exposure = val;
-out:
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return rc;
-}
-#endif
-
-/* Gets current exposure level from sensor, regardless of whether it is under
- * manual control. */
-static int
-sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
-{
-       int rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               rc = i2c_r(ov, 0x10);
-               if (rc < 0)
-                       return rc;
-               else
-                       *val = rc;
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               val = NULL;
-               PDEBUG(3, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for get_exposure");
-               return -EINVAL;
-       }
-
-       PDEBUG(3, "%d", *val);
-       ov->exposure = *val;
-
-       return 0;
-}
-
-/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static void
-ov51x_led_control(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->bridge == BRG_OV511PLUS)
-               reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
-       else if (ov->bclass == BCL_OV518)
-               reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
-
-       return;
-}
-
-/* Matches the sensor's internal frame rate to the lighting frequency.
- * Valid frequencies are:
- *     50 - 50Hz, for European and Asian lighting
- *     60 - 60Hz, for American lighting
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_light_freq(struct usb_ov511 *ov, int freq)
-{
-       int sixty;
-
-       PDEBUG(4, "%d Hz", freq);
-
-       if (freq == 60)
-               sixty = 1;
-       else if (freq == 50)
-               sixty = 0;
-       else {
-               err("Invalid light freq (%d Hz)", freq);
-               return -EINVAL;
-       }
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-               i2c_w(ov, 0x2b, sixty?0x00:0xac);
-               i2c_w_mask(ov, 0x13, 0x10, 0x10);
-               i2c_w_mask(ov, 0x13, 0x00, 0x10);
-               break;
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
-               i2c_w(ov, 0x2b, sixty?0x00:0xac);
-               i2c_w_mask(ov, 0x76, 0x01, 0x01);
-               break;
-       case SEN_OV6620:
-       case SEN_OV6630:
-               i2c_w(ov, 0x2b, sixty?0xa8:0x28);
-               i2c_w(ov, 0x2a, sixty?0x84:0xa4);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_light_freq");
-               return -EINVAL;
-       }
-
-       ov->lightfreq = freq;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's banding filter, otherwise turn it
- * off. This filter tries to reduce the pattern of horizontal light/dark bands
- * caused by some (usually fluorescent) lighting. The light frequency must be
- * set either before or after enabling it with ov51x_set_light_freq().
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620.
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
-{
-       int rc;
-
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-               || ov->sensor == SEN_SAA7111A) {
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
-       if (rc < 0)
-               return rc;
-
-       ov->bandfilt = enable;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's auto brightness control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
-{
-       int rc;
-
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
-               || ov->sensor == SEN_SAA7111A) {
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       }
-
-       rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
-       if (rc < 0)
-               return rc;
-
-       ov->auto_brt = enable;
-
-       return 0;
-}
-
-/* If enable is true, turn on the sensor's auto exposure control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
-               break;
-       case SEN_OV6620:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
-               break;
-       case SEN_OV6630:
-               i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_auto_exposure");
-               return -EINVAL;
-       }
-
-       ov->auto_exp = enable;
-
-       return 0;
-}
-
-/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
- * that are illuminated from behind.
- *
- * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_backlight(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV7620:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-               break;
-       case SEN_OV6620:
-               i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
-               break;
-       case SEN_OV6630:
-               i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
-               i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
-               i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
-               break;
-       case SEN_OV7610:
-       case SEN_OV76BE:
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_backlight");
-               return -EINVAL;
-       }
-
-       ov->backlight = enable;
-
-       return 0;
-}
-
-static int
-sensor_set_mirror(struct usb_ov511 *ov, int enable)
-{
-       PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
-       switch (ov->sensor) {
-       case SEN_OV6620:
-       case SEN_OV6630:
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-               i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-       case SEN_SAA7111A:
-               PDEBUG(5, "Unsupported with this sensor");
-               return -EPERM;
-       default:
-               err("Sensor not supported for set_mirror");
-               return -EINVAL;
-       }
-
-       ov->mirror = enable;
-
-       return 0;
-}
-
-/* Returns number of bits per pixel (regardless of where they are located;
- * planar or not), or zero for unsupported format.
- */
-static inline int
-get_depth(int palette)
-{
-       switch (palette) {
-       case VIDEO_PALETTE_GREY:    return 8;
-       case VIDEO_PALETTE_YUV420:  return 12;
-       case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
-       default:                    return 0;  /* Invalid format */
-       }
-}
-
-/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
-get_frame_length(struct ov511_frame *frame)
-{
-       if (!frame)
-               return 0;
-       else
-               return ((frame->width * frame->height
-                        * get_depth(frame->format)) >> 3);
-}
-
-static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
-                        int mode, int sub_flag, int qvga)
-{
-       int clock;
-
-       /******** Mode (VGA/QVGA) and sensor specific regs ********/
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-               i2c_w(ov, 0x14, qvga?0x24:0x04);
-// FIXME: Does this improve the image quality or frame rate?
-#if 0
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, 0x10);
-               i2c_w(ov, 0x25, qvga?0x40:0x8a);
-               i2c_w(ov, 0x2f, qvga?0x30:0xb0);
-               i2c_w(ov, 0x35, qvga?0x1c:0x9c);
-#endif
-               break;
-       case SEN_OV7620:
-//             i2c_w(ov, 0x2b, 0x00);
-               i2c_w(ov, 0x14, qvga?0xa4:0x84);
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, qvga?0x20:0x3a);
-               i2c_w(ov, 0x25, qvga?0x30:0x60);
-               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-               i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
-               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-               break;
-       case SEN_OV76BE:
-//             i2c_w(ov, 0x2b, 0x00);
-               i2c_w(ov, 0x14, qvga?0xa4:0x84);
-// FIXME: Enable this once 7620AE uses 7620 initial settings
-#if 0
-               i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
-               i2c_w(ov, 0x24, qvga?0x20:0x3a);
-               i2c_w(ov, 0x25, qvga?0x30:0x60);
-               i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
-               i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
-               i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-#endif
-               break;
-       case SEN_OV6620:
-               i2c_w(ov, 0x14, qvga?0x24:0x04);
-               break;
-       case SEN_OV6630:
-               i2c_w(ov, 0x14, qvga?0xa0:0x80);
-               break;
-       default:
-               err("Invalid sensor");
-               return -EINVAL;
-       }
-
-       /******** Palette-specific regs ********/
-
-       if (mode == VIDEO_PALETTE_GREY) {
-               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-                       /* these aren't valid on the OV6620/OV7620/6630? */
-                       i2c_w_mask(ov, 0x0e, 0x40, 0x40);
-               }
-
-               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-                   && ov518_color) {
-                       i2c_w_mask(ov, 0x12, 0x00, 0x10);
-                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
-               } else {
-                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
-               }
-       } else {
-               if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-                       /* not valid on the OV6620/OV7620/6630? */
-                       i2c_w_mask(ov, 0x0e, 0x00, 0x40);
-               }
-
-               /* The OV518 needs special treatment. Although both the OV518
-                * and the OV6630 support a 16-bit video bus, only the 8 bit Y
-                * bus is actually used. The UV bus is tied to ground.
-                * Therefore, the OV6630 needs to be in 8-bit multiplexed
-                * output mode */
-
-               if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
-                   && ov518_color) {
-                       i2c_w_mask(ov, 0x12, 0x10, 0x10);
-                       i2c_w_mask(ov, 0x13, 0x20, 0x20);
-               } else {
-                       i2c_w_mask(ov, 0x13, 0x00, 0x20);
-               }
-       }
-
-       /******** Clock programming ********/
-
-       /* The OV6620 needs special handling. This prevents the 
-        * severe banding that normally occurs */
-       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
-       {
-               /* Clock down */
-
-               i2c_w(ov, 0x2a, 0x04);
-
-               if (ov->compress) {
-//                     clock = 0;    /* This ensures the highest frame rate */
-                       clock = 3;
-               } else if (clockdiv == -1) {   /* If user didn't override it */
-                       clock = 3;    /* Gives better exposure time */
-               } else {
-                       clock = clockdiv;
-               }
-
-               PDEBUG(4, "Setting clock divisor to %d", clock);
-
-               i2c_w(ov, 0x11, clock);
-
-               i2c_w(ov, 0x2a, 0x84);
-               /* This next setting is critical. It seems to improve
-                * the gain or the contrast. The "reserved" bits seem
-                * to have some effect in this case. */
-               i2c_w(ov, 0x2d, 0x85);
-       }
-       else
-       {
-               if (ov->compress) {
-                       clock = 1;    /* This ensures the highest frame rate */
-               } else if (clockdiv == -1) {   /* If user didn't override it */
-                       /* Calculate and set the clock divisor */
-                       clock = ((sub_flag ? ov->subw * ov->subh
-                                 : width * height)
-                                * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
-                                / 66000;
-               } else {
-                       clock = clockdiv;
-               }
-
-               PDEBUG(4, "Setting clock divisor to %d", clock);
-
-               i2c_w(ov, 0x11, clock);
-       }
-
-       /******** Special Features ********/
-
-       if (framedrop >= 0)
-               i2c_w(ov, 0x16, framedrop);
-
-       /* Test Pattern */
-       i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
-
-       /* Enable auto white balance */
-       i2c_w_mask(ov, 0x12, 0x04, 0x04);
-
-       // This will go away as soon as ov51x_mode_init_sensor_regs()
-       // is fully tested.
-       /* 7620/6620/6630? don't have register 0x35, so play it safe */
-       if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
-               if (width == 640 && height == 480)
-                       i2c_w(ov, 0x35, 0x9e);
-               else
-                       i2c_w(ov, 0x35, 0x1e);
-       }
-
-       return 0;
-}
-
-static int
-set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
-                    int sub_flag)
-{
-       int ret;
-       int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; 
-       int hoffset, voffset, hwscale = 0, vwscale = 0;
-
-       /* The different sensor ICs handle setting up of window differently.
-        * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV76BE:
-               hwsbase = 0x38;
-               hwebase = 0x3a;
-               vwsbase = vwebase = 0x05;
-               break;
-       case SEN_OV6620:
-       case SEN_OV6630:
-               hwsbase = 0x38;
-               hwebase = 0x3a;
-               vwsbase = 0x05;
-               vwebase = 0x06;
-               break;
-       case SEN_OV7620:
-               hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
-               hwebase = 0x2f;
-               vwsbase = vwebase = 0x05;
-               break;
-       default:
-               err("Invalid sensor");
-               return -EINVAL;
-       }
-
-       if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
-               /* Note: OV518(+) does downsample on its own) */
-               if ((width > 176 && height > 144)
-                   || ov->bclass == BCL_OV518) {  /* CIF */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 0);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 1;
-                       vwscale = 1;  /* The datasheet says 0; it's wrong */
-                       hwsize = 352;
-                       vwsize = 288;
-               } else if (width > 176 || height > 144) {
-                       err("Illegal dimensions");
-                       return -EINVAL;
-               } else {                            /* QCIF */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 1);
-                       if (ret < 0)
-                               return ret;
-                       hwsize = 176;
-                       vwsize = 144;
-               }
-       } else {
-               if (width > 320 && height > 240) {  /* VGA */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 0);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 2;
-                       vwscale = 1;
-                       hwsize = 640;
-                       vwsize = 480;
-               } else if (width > 320 || height > 240) {
-                       err("Illegal dimensions");
-                       return -EINVAL;
-               } else {                            /* QVGA */
-                       ret = mode_init_ov_sensor_regs(ov, width, height,
-                               mode, sub_flag, 1);
-                       if (ret < 0)
-                               return ret;
-                       hwscale = 1;
-                       hwsize = 320;
-                       vwsize = 240;
-               }
-       }
-
-       /* Center the window */
-       hoffset = ((hwsize - width) / 2) >> hwscale;
-       voffset = ((vwsize - height) / 2) >> vwscale;
-
-       /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
-       if (sub_flag) {
-               i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
-               i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
-               i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
-               i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
-       } else {
-               i2c_w(ov, 0x17, hwsbase + hoffset);
-               i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
-               i2c_w(ov, 0x19, vwsbase + voffset);
-               i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
-       }
-
-#ifdef OV511_DEBUG
-       if (dump_sensor)
-               dump_i2c_regs(ov);
-#endif
-
-       return 0;
-}
-
-/* Set up the OV511/OV511+ with the given image parameters.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov511_mode_init_regs(struct usb_ov511 *ov,
-                    int width, int height, int mode, int sub_flag)
-{
-       int hsegs, vsegs;
-
-       if (sub_flag) {
-               width = ov->subw;
-               height = ov->subh;
-       }
-
-       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-              width, height, mode, sub_flag);
-
-       // FIXME: This should be moved to a 7111a-specific function once
-       // subcapture is dealt with properly
-       if (ov->sensor == SEN_SAA7111A) {
-               if (width == 320 && height == 240) {
-                       /* No need to do anything special */
-               } else if (width == 640 && height == 480) {
-                       /* Set the OV511 up as 320x480, but keep the
-                        * V4L resolution as 640x480 */
-                       width = 320;
-               } else {
-                       err("SAA7111A only allows 320x240 or 640x480");
-                       return -EINVAL;
-               }
-       }
-
-       /* Make sure width and height are a multiple of 8 */
-       if (width % 8 || height % 8) {
-               err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
-               return -EINVAL;
-       }
-
-       if (width < ov->minwidth || height < ov->minheight) {
-               err("Requested dimensions are too small");
-               return -EINVAL;
-       }
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       if (mode == VIDEO_PALETTE_GREY) {
-               reg_w(ov, R511_CAM_UV_EN, 0x00);
-               reg_w(ov, R511_SNAP_UV_EN, 0x00);
-               reg_w(ov, R511_SNAP_OPTS, 0x01);
-       } else {
-               reg_w(ov, R511_CAM_UV_EN, 0x01);
-               reg_w(ov, R511_SNAP_UV_EN, 0x01);
-               reg_w(ov, R511_SNAP_OPTS, 0x03);
-       }
-
-       /* Here I'm assuming that snapshot size == image size.
-        * I hope that's always true. --claudio
-        */
-       hsegs = (width >> 3) - 1;
-       vsegs = (height >> 3) - 1;
-
-       reg_w(ov, R511_CAM_PXCNT, hsegs);
-       reg_w(ov, R511_CAM_LNCNT, vsegs);
-       reg_w(ov, R511_CAM_PXDIV, 0x00);
-       reg_w(ov, R511_CAM_LNDIV, 0x00);
-
-       /* YUV420, low pass filter on */
-       reg_w(ov, R511_CAM_OPTS, 0x03);
-
-       /* Snapshot additions */
-       reg_w(ov, R511_SNAP_PXCNT, hsegs);
-       reg_w(ov, R511_SNAP_LNCNT, vsegs);
-       reg_w(ov, R511_SNAP_PXDIV, 0x00);
-       reg_w(ov, R511_SNAP_LNDIV, 0x00);
-
-       if (ov->compress) {
-               /* Enable Y and UV quantization and compression */
-               reg_w(ov, R511_COMP_EN, 0x07);
-               reg_w(ov, R511_COMP_LUT_EN, 0x03);
-               ov51x_reset(ov, OV511_RESET_OMNICE);
-       }
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* Sets up the OV518/OV518+ with the given image parameters
- *
- * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Also, only 15 FPS is supported now.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov518_mode_init_regs(struct usb_ov511 *ov,
-                    int width, int height, int mode, int sub_flag)
-{
-       int hsegs, vsegs, hi_res;
-
-       if (sub_flag) {
-               width = ov->subw;
-               height = ov->subh;
-       }
-
-       PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
-              width, height, mode, sub_flag);
-
-       if (width % 16 || height % 8) {
-               err("Invalid size (%d, %d)", width, height);
-               return -EINVAL;
-       }
-
-       if (width < ov->minwidth || height < ov->minheight) {
-               err("Requested dimensions are too small");
-               return -EINVAL;
-       }
-
-       if (width >= 320 && height >= 240) {
-               hi_res = 1;
-       } else if (width >= 320 || height >= 240) {
-               err("Invalid width/height combination (%d, %d)", width, height);
-               return -EINVAL;
-       } else {
-               hi_res = 0;
-       }
-
-       if (ov51x_stop(ov) < 0)
-               return -EIO;
-
-       /******** Set the mode ********/
-
-       reg_w(ov, 0x2b, 0);
-       reg_w(ov, 0x2c, 0);
-       reg_w(ov, 0x2d, 0);
-       reg_w(ov, 0x2e, 0);
-       reg_w(ov, 0x3b, 0);
-       reg_w(ov, 0x3c, 0);
-       reg_w(ov, 0x3d, 0);
-       reg_w(ov, 0x3e, 0);
-
-       if (ov->bridge == BRG_OV518 && ov518_color) {
-               /* OV518 needs U and V swapped */
-               i2c_w_mask(ov, 0x15, 0x00, 0x01);
-
-               if (mode == VIDEO_PALETTE_GREY) {
-                       /* Set 16-bit input format (UV data are ignored) */
-                       reg_w_mask(ov, 0x20, 0x00, 0x08);
-
-                       /* Set 8-bit (4:0:0) output format */
-                       reg_w_mask(ov, 0x28, 0x00, 0xf0);
-                       reg_w_mask(ov, 0x38, 0x00, 0xf0);
-               } else {
-                       /* Set 8-bit (YVYU) input format */
-                       reg_w_mask(ov, 0x20, 0x08, 0x08);
-
-                       /* Set 12-bit (4:2:0) output format */
-                       reg_w_mask(ov, 0x28, 0x80, 0xf0);
-                       reg_w_mask(ov, 0x38, 0x80, 0xf0);
-               }
-       } else {
-               reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-               reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
-       }
-
-       hsegs = width / 16;
-       vsegs = height / 4;
-
-       reg_w(ov, 0x29, hsegs);
-       reg_w(ov, 0x2a, vsegs);
-
-       reg_w(ov, 0x39, hsegs);
-       reg_w(ov, 0x3a, vsegs);
-
-       /* Windows driver does this here; who knows why */
-       reg_w(ov, 0x2f, 0x80);
-
-       /******** Set the framerate (to 15 FPS) ********/
-
-       /* Mode independent, but framerate dependent, regs */
-       reg_w(ov, 0x51, 0x02);  /* Clock divider; lower==faster */
-       reg_w(ov, 0x22, 0x18);
-       reg_w(ov, 0x23, 0xff);
-
-       if (ov->bridge == BRG_OV518PLUS)
-               reg_w(ov, 0x21, 0x19);
-       else
-               reg_w(ov, 0x71, 0x19);  /* Compression-related? */
-
-       // FIXME: Sensor-specific
-       /* Bit 5 is what matters here. Of course, it is "reserved" */
-       i2c_w(ov, 0x54, 0x23);
-
-       reg_w(ov, 0x2f, 0x80);
-
-       if (ov->bridge == BRG_OV518PLUS) {
-               reg_w(ov, 0x24, 0x94);
-               reg_w(ov, 0x25, 0x90);
-               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
-               ov518_reg_w32(ov, 0xc6,    540, 2);     /* 21ch   */
-               ov518_reg_w32(ov, 0xc7,    540, 2);     /* 21ch   */
-               ov518_reg_w32(ov, 0xc8,    108, 2);     /* 6ch    */
-               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
-               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
-               ov518_reg_w32(ov, 0xcc,   2400, 2);     /* 960h   */
-               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
-               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
-       } else {
-               reg_w(ov, 0x24, 0x9f);
-               reg_w(ov, 0x25, 0x90);
-               ov518_reg_w32(ov, 0xc4,    400, 2);     /* 190h   */
-               ov518_reg_w32(ov, 0xc6,    500, 2);     /* 1f4h   */
-               ov518_reg_w32(ov, 0xc7,    500, 2);     /* 1f4h   */
-               ov518_reg_w32(ov, 0xc8,    142, 2);     /* 8eh    */
-               ov518_reg_w32(ov, 0xca, 131098, 3);     /* 2001ah */
-               ov518_reg_w32(ov, 0xcb,    532, 2);     /* 214h   */
-               ov518_reg_w32(ov, 0xcc,   2000, 2);     /* 7d0h   */
-               ov518_reg_w32(ov, 0xcd,     32, 2);     /* 20h    */
-               ov518_reg_w32(ov, 0xce,    608, 2);     /* 260h   */
-       }
-
-       reg_w(ov, 0x2f, 0x80);
-
-       if (ov51x_restart(ov) < 0)
-               return -EIO;
-
-       /* Reset it just for good measure */
-       if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
-               return -EIO;
-
-       return 0;
-}
-
-/* This is a wrapper around the OV511, OV518, and sensor specific functions */
-static int
-mode_init_regs(struct usb_ov511 *ov,
-              int width, int height, int mode, int sub_flag)
-{
-       int rc = 0;
-
-       if (!ov || !ov->dev)
-               return -EFAULT;
-
-       if (ov->bclass == BCL_OV518) {
-               rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
-       } else {
-               rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
-       }
-
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       switch (ov->sensor) {
-       case SEN_OV7610:
-       case SEN_OV7620:
-       case SEN_OV76BE:
-       case SEN_OV8600:
-       case SEN_OV6620:
-       case SEN_OV6630:
-               rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
-               break;
-       case SEN_KS0127:
-       case SEN_KS0127B:
-               err("KS0127-series decoders not supported yet");
-               rc = -EINVAL;
-               break;
-       case SEN_SAA7111A:
-//             rc = mode_init_saa_sensor_regs(ov, width, height, mode,
-//                                            sub_flag);
-
-               PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
-               break;
-       default:
-               err("Unknown sensor");
-               rc = -EINVAL;
-       }
-
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       /* Sensor-independent settings */
-       rc = sensor_set_auto_brightness(ov, ov->auto_brt);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_auto_exposure(ov, ov->auto_exp);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_banding_filter(ov, bandingfilter);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       if (ov->lightfreq) {
-               rc = sensor_set_light_freq(ov, lightfreq);
-               if (FATAL_ERROR(rc))
-                       return rc;
-       }
-
-       rc = sensor_set_backlight(ov, ov->backlight);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       rc = sensor_set_mirror(ov, ov->mirror);
-       if (FATAL_ERROR(rc))
-               return rc;
-
-       return 0;
-}
-
-/* This sets the default image parameters. This is useful for apps that use
- * read() and do not set these.
- */
-static int
-ov51x_set_default_params(struct usb_ov511 *ov)
-{
-       int i;
-
-       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
-        * (using read() instead). */
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].width = ov->maxwidth;
-               ov->frame[i].height = ov->maxheight;
-               ov->frame[i].bytes_read = 0;
-               if (force_palette)
-                       ov->frame[i].format = force_palette;
-               else
-                       ov->frame[i].format = VIDEO_PALETTE_YUV420;
-
-               ov->frame[i].depth = get_depth(ov->frame[i].format);
-       }
-
-       PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
-              symbolic(v4l1_plist, ov->frame[0].format));
-
-       /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
-       if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
-                          ov->frame[0].format, 0) < 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-/**********************************************************************
- *
- * Video decoder stuff
- *
- **********************************************************************/
-
-/* Set analog input port of decoder */
-static int
-decoder_set_input(struct usb_ov511 *ov, int input)
-{
-       PDEBUG(4, "port %d", input);
-
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               /* Select mode */
-               i2c_w_mask(ov, 0x02, input, 0x07);
-               /* Bypass chrominance trap for modes 4..7 */
-               i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Get ASCII name of video input */
-static int
-decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
-{
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               if (input < 0 || input > 7)
-                       return -EINVAL;
-               else if (input < 4)
-                       sprintf(name, "CVBS-%d", input);
-               else // if (input < 8)
-                       sprintf(name, "S-Video-%d", input - 4);
-               break;
-       }
-       default:
-               sprintf(name, "%s", "Camera");
-       }
-
-       return 0;
-}
-
-/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
-decoder_set_norm(struct usb_ov511 *ov, int norm)
-{
-       PDEBUG(4, "%d", norm);
-
-       switch (ov->sensor) {
-       case SEN_SAA7111A:
-       {
-               int reg_8, reg_e;
-
-               if (norm == VIDEO_MODE_NTSC) {
-                       reg_8 = 0x40;   /* 60 Hz */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_PAL) {
-                       reg_8 = 0x00;   /* 50 Hz */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_AUTO) {
-                       reg_8 = 0x80;   /* Auto field detect */
-                       reg_e = 0x00;   /* NTSC M / PAL BGHI */
-               } else if (norm == VIDEO_MODE_SECAM) {
-                       reg_8 = 0x00;   /* 50 Hz */
-                       reg_e = 0x50;   /* SECAM / PAL 4.43 */
-               } else {
-                       return -EINVAL;
-               }
-
-               i2c_w_mask(ov, 0x08, reg_8, 0xc0);
-               i2c_w_mask(ov, 0x0e, reg_e, 0x70);
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**********************************************************************
- *
- * Raw data parsing
- *
- **********************************************************************/
-
-/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * image at pOut is specified by w.
- */
-static inline void
-make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
-{
-       unsigned char *pOut1 = pOut;
-       int x, y;
-
-       for (y = 0; y < 8; y++) {
-               pOut1 = pOut;
-               for (x = 0; x < 8; x++) {
-                       *pOut1++ = *pIn++;
-               }
-               pOut += w;
-       }
-}
-
-/*
- * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
- * The segments represent 4 squares of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127        248 249 ... 255
- *
- */ 
-static void
-yuv400raw_to_yuv400p(struct ov511_frame *frame,
-                    unsigned char *pIn0, unsigned char *pOut0)
-{
-       int x, y;
-       unsigned char *pIn, *pOut, *pOutLine;
-
-       /* Copy Y */
-       pIn = pIn0;
-       pOutLine = pOut0;
-       for (y = 0; y < frame->rawheight - 1; y += 8) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 8) {
-                       make_8x8(pIn, pOut, frame->rawwidth);
-                       pIn += 64;
-                       pOut += 8;
-               }
-               pOutLine += 8 * frame->rawwidth;
-       }
-}
-
-/*
- * For YUV 4:2:0 images, the data show up in 384 byte segments.
- * The first 64 bytes of each segment are U, the next 64 are V.  The U and
- * V are arranged as follows:
- *
- *      0  1 ...  7
- *      8  9 ... 15
- *           ...   
- *     56 57 ... 63
- *
- * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
- *
- * The next 256 bytes are full resolution Y data and represent 4 squares
- * of 8x8 pixels as follows:
- *
- *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
- *      8  9 ... 15    72  73 ...  79        200 201 ... 207
- *           ...              ...                    ...
- *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
- *
- * Note that the U and V data in one segment represent a 16 x 16 pixel
- * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
- * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
- * next horizontal stripe.
- *
- * If dumppix module param is set, _parse_data just dumps the incoming segments,
- * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
- * this puts the data on the standard output and can be analyzed with the
- * parseppm.c utility I wrote.  That's a much faster way for figuring out how
- * these data are scrambled.
- */
-
-/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
- *
- * FIXME: Currently only handles width and height that are multiples of 16
- */
-static void
-yuv420raw_to_yuv420p(struct ov511_frame *frame,
-                    unsigned char *pIn0, unsigned char *pOut0)
-{
-       int k, x, y;
-       unsigned char *pIn, *pOut, *pOutLine;
-       const unsigned int a = frame->rawwidth * frame->rawheight;
-       const unsigned int w = frame->rawwidth / 2;
-
-       /* Copy U and V */
-       pIn = pIn0;
-       pOutLine = pOut0 + a;
-       for (y = 0; y < frame->rawheight - 1; y += 16) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 16) {
-                       make_8x8(pIn, pOut, w);
-                       make_8x8(pIn + 64, pOut + a/4, w);
-                       pIn += 384;
-                       pOut += 8;
-               }
-               pOutLine += 8 * w;
-       }
-
-       /* Copy Y */
-       pIn = pIn0 + 128;
-       pOutLine = pOut0;
-       k = 0;
-       for (y = 0; y < frame->rawheight - 1; y += 8) {
-               pOut = pOutLine;
-               for (x = 0; x < frame->rawwidth - 1; x += 8) {
-                       make_8x8(pIn, pOut, frame->rawwidth);
-                       pIn += 64;
-                       pOut += 8;
-                       if ((++k) > 3) {
-                               k = 0;
-                               pIn += 128;
-                       }
-               }
-               pOutLine += 8 * frame->rawwidth;
-       }
-}
-
-/**********************************************************************
- *
- * Decompression
- *
- **********************************************************************/
-
-static int
-request_decompressor(struct usb_ov511 *ov)
-{
-       if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
-               err("No decompressor available");
-       } else {
-               err("Unknown bridge");
-       }
-
-       return -ENOSYS;
-}
-
-static void
-decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
-          unsigned char *pIn0, unsigned char *pOut0)
-{
-       if (!ov->decomp_ops)
-               if (request_decompressor(ov))
-                       return;
-
-}
-
-/**********************************************************************
- *
- * Format conversion
- *
- **********************************************************************/
-
-/* Fuses even and odd fields together, and doubles width.
- * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
- * OUTPUT: a normal YUV planar image, with correct aspect ratio
- */
-static void
-deinterlace(struct ov511_frame *frame, int rawformat,
-            unsigned char *pIn0, unsigned char *pOut0)
-{
-       const int fieldheight = frame->rawheight / 2;
-       const int fieldpix = fieldheight * frame->rawwidth;
-       const int w = frame->width;
-       int x, y;
-       unsigned char *pInEven, *pInOdd, *pOut;
-
-       PDEBUG(5, "fieldheight=%d", fieldheight);
-
-       if (frame->rawheight != frame->height) {
-               err("invalid height");
-               return;
-       }
-
-       if ((frame->rawwidth * 2) != frame->width) {
-               err("invalid width");
-               return;
-       }
-
-       /* Y */
-       pInOdd = pIn0;
-       pInEven = pInOdd + fieldpix;
-       pOut = pOut0;
-       for (y = 0; y < fieldheight; y++) {
-               for (x = 0; x < frame->rawwidth; x++) {
-                       *pOut = *pInEven;
-                       *(pOut+1) = *pInEven++;
-                       *(pOut+w) = *pInOdd;
-                       *(pOut+w+1) = *pInOdd++;
-                       pOut += 2;
-               }
-               pOut += w;
-       }
-
-       if (rawformat == RAWFMT_YUV420) {
-       /* U */
-               pInOdd = pIn0 + fieldpix * 2;
-               pInEven = pInOdd + fieldpix / 4;
-               for (y = 0; y < fieldheight / 2; y++) {
-                       for (x = 0; x < frame->rawwidth / 2; x++) {
-                               *pOut = *pInEven;
-                               *(pOut+1) = *pInEven++;
-                               *(pOut+w/2) = *pInOdd;
-                               *(pOut+w/2+1) = *pInOdd++;
-                               pOut += 2;
-                       }
-                       pOut += w/2;
-               }
-       /* V */
-               pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
-               pInEven = pInOdd + fieldpix / 4;
-               for (y = 0; y < fieldheight / 2; y++) {
-                       for (x = 0; x < frame->rawwidth / 2; x++) {
-                               *pOut = *pInEven;
-                               *(pOut+1) = *pInEven++;
-                               *(pOut+w/2) = *pInOdd;
-                               *(pOut+w/2+1) = *pInOdd++;
-                               pOut += 2;
-                       }
-                       pOut += w/2;
-               }
-       }
-}
-
-static void
-ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-               /* Deinterlace frame, if necessary */
-               if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-                       if (frame->compressed)
-                               decompress(ov, frame, frame->rawdata,
-                                                frame->tempdata);
-                       else
-                               yuv400raw_to_yuv400p(frame, frame->rawdata,
-                                                    frame->tempdata);
-
-                       deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
-                                   frame->data);
-               } else {
-                       if (frame->compressed)
-                               decompress(ov, frame, frame->rawdata,
-                                                frame->data);
-                       else
-                               yuv400raw_to_yuv400p(frame, frame->rawdata,
-                                                    frame->data);
-               }
-}
-
-/* Process raw YUV420 data into standard YUV420P */
-static void
-ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-       /* Deinterlace frame, if necessary */
-       if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
-               if (frame->compressed)
-                       decompress(ov, frame, frame->rawdata, frame->tempdata);
-               else
-                       yuv420raw_to_yuv420p(frame, frame->rawdata,
-                                            frame->tempdata);
-
-               deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
-                           frame->data);
-       } else {
-               if (frame->compressed)
-                       decompress(ov, frame, frame->rawdata, frame->data);
-               else
-                       yuv420raw_to_yuv420p(frame, frame->rawdata,
-                                            frame->data);
-       }
-}
-
-/* Post-processes the specified frame. This consists of:
- *     1. Decompress frame, if necessary
- *     2. Deinterlace frame and scale to proper size, if necessary
- *     3. Convert from YUV planar to destination format, if necessary
- *     4. Fix the RGB offset, if necessary
- */
-static void
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
-       if (dumppix) {
-               memset(frame->data, 0,
-                       MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-               PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
-               memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
-       } else {
-               switch (frame->format) {
-               case VIDEO_PALETTE_GREY:
-                       ov51x_postprocess_grey(ov, frame);
-                       break;
-               case VIDEO_PALETTE_YUV420:
-               case VIDEO_PALETTE_YUV420P:
-                       ov51x_postprocess_yuv420(ov, frame);
-                       break;
-               default:
-                       err("Cannot convert data to %s",
-                           symbolic(v4l1_plist, frame->format));
-               }
-       }
-}
-
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static inline void
-ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-       int num, offset;
-       int pnum = in[ov->packet_size - 1];             /* Get packet number */
-       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-       struct ov511_frame *frame = &ov->frame[ov->curframe];
-       struct timeval *ts;
-
-       /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
-        * byte non-zero. The EOF packet has image width/height in the
-        * 10th and 11th bytes. The 9th byte is given as follows:
-        *
-        * bit 7: EOF
-        *     6: compression enabled
-        *     5: 422/420/400 modes
-        *     4: 422/420/400 modes
-        *     3: 1
-        *     2: snapshot button on
-        *     1: snapshot frame
-        *     0: even/odd field
-        */
-
-       if (printph) {
-               info("ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x",
-                    pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
-                    in[7], in[8], in[9], in[10], in[11]);
-       }
-
-       /* Check for SOF/EOF packet */
-       if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
-           (~in[8] & 0x08))
-               goto check_middle;
-
-       /* Frame end */
-       if (in[8] & 0x80) {
-               ts = (struct timeval *)(frame->data
-                     + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-               do_gettimeofday(ts);
-
-               /* Get the actual frame size from the EOF header */
-               frame->rawwidth = ((int)(in[9]) + 1) * 8;
-               frame->rawheight = ((int)(in[10]) + 1) * 8;
-
-               PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
-                       ov->curframe, pnum, frame->rawwidth, frame->rawheight,
-                       frame->bytes_recvd);
-
-               /* Validate the header data */
-               RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-               RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
-                                 ov->maxheight);
-
-               /* Don't allow byte count to exceed buffer size */
-               RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-               if (frame->scanstate == STATE_LINES) {
-                       int nextf;
-
-                       frame->grabstate = FRAME_DONE;
-                       wake_up_interruptible(&frame->wq);
-
-                       /* If next frame is ready or grabbing,
-                        * point to it */
-                       nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-                       if (ov->frame[nextf].grabstate == FRAME_READY
-                           || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-                               ov->curframe = nextf;
-                               ov->frame[nextf].scanstate = STATE_SCANNING;
-                       } else {
-                               if (frame->grabstate == FRAME_DONE) {
-                                       PDEBUG(4, "** Frame done **");
-                               } else {
-                                       PDEBUG(4, "Frame not ready? state = %d",
-                                               ov->frame[nextf].grabstate);
-                               }
-
-                               ov->curframe = -1;
-                       }
-               } else {
-                       PDEBUG(5, "Frame done, but not scanning");
-               }
-               /* Image corruption caused by misplaced frame->segment = 0
-                * fixed by carlosf@conectiva.com.br
-                */
-       } else {
-               /* Frame start */
-               PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
-               /* Check to see if it's a snapshot frame */
-               /* FIXME?? Should the snapshot reset go here? Performance? */
-               if (in[8] & 0x02) {
-                       frame->snapshot = 1;
-                       PDEBUG(3, "snapshot detected");
-               }
-
-               frame->scanstate = STATE_LINES;
-               frame->bytes_recvd = 0;
-               frame->compressed = in[8] & 0x40;
-       }
-
-check_middle:
-       /* Are we in a frame? */
-       if (frame->scanstate != STATE_LINES) {
-               PDEBUG(5, "Not in a frame; packet skipped");
-               return;
-       }
-
-       /* If frame start, skip header */
-       if (frame->bytes_recvd == 0)
-               offset = 9;
-       else
-               offset = 0;
-
-       num = n - offset - 1;
-
-       /* Dump all data exactly as received */
-       if (dumppix == 2) {
-               frame->bytes_recvd += n - 1;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
-                               in, n - 1);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else if (!frame->compressed && !remove_zeros) {
-               frame->bytes_recvd += num;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - num,
-                               in + offset, num);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
-               int b, read = 0, allzero, copied = 0;
-               if (offset) {
-                       frame->bytes_recvd += 32 - offset;      // Bytes out
-                       memcpy(frame->rawdata,  in + offset, 32 - offset);
-                       read += 32;
-               }
-
-               while (read < n - 1) {
-                       allzero = 1;
-                       for (b = 0; b < 32; b++) {
-                               if (in[read + b]) {
-                                       allzero = 0;
-                                       break;
-                               }
-                       }
-
-                       if (allzero) {
-                               /* Don't copy it */
-                       } else {
-                               if (frame->bytes_recvd + copied + 32 <= max_raw)
-                               {
-                                       memcpy(frame->rawdata
-                                               + frame->bytes_recvd + copied,
-                                               in + read, 32);
-                                       copied += 32;
-                               } else {
-                                       PDEBUG(3, "Raw data buffer overrun!!");
-                               }
-                       }
-                       read += 32;
-               }
-
-               frame->bytes_recvd += copied;
-       }
-}
-
-static inline void
-ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
-       int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
-       struct ov511_frame *frame = &ov->frame[ov->curframe];
-       struct timeval *ts;
-
-       /* Don't copy the packet number byte */
-       if (ov->packet_numbering)
-               --n;
-
-       /* A false positive here is likely, until OVT gives me
-        * the definitive SOF/EOF format */
-       if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
-               if (printph) {
-                       info("ph: %2x %2x %2x %2x %2x %2x %2x %2x", in[0],
-                            in[1], in[2], in[3], in[4], in[5], in[6], in[7]);
-               }
-
-               if (frame->scanstate == STATE_LINES) {
-                       PDEBUG(4, "Detected frame end/start");
-                       goto eof;
-               } else { //scanstate == STATE_SCANNING
-                       /* Frame start */
-                       PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-                       goto sof;
-               }
-       } else {
-               goto check_middle;
-       }
-
-eof:
-       ts = (struct timeval *)(frame->data
-             + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
-       do_gettimeofday(ts);
-
-       PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
-               ov->curframe,
-               (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
-
-       // FIXME: Since we don't know the header formats yet,
-       // there is no way to know what the actual image size is
-       frame->rawwidth = frame->width;
-       frame->rawheight = frame->height;
-
-       /* Validate the header data */
-       RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
-       RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
-       /* Don't allow byte count to exceed buffer size */
-       RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
-       if (frame->scanstate == STATE_LINES) {
-               int nextf;
-
-               frame->grabstate = FRAME_DONE;
-               wake_up_interruptible(&frame->wq);
-
-               /* If next frame is ready or grabbing,
-                * point to it */
-               nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
-               if (ov->frame[nextf].grabstate == FRAME_READY
-                   || ov->frame[nextf].grabstate == FRAME_GRABBING) {
-                       ov->curframe = nextf;
-                       ov->frame[nextf].scanstate = STATE_SCANNING;
-                       frame = &ov->frame[nextf];
-               } else {
-                       if (frame->grabstate == FRAME_DONE) {
-                               PDEBUG(4, "** Frame done **");
-                       } else {
-                               PDEBUG(4, "Frame not ready? state = %d",
-                                      ov->frame[nextf].grabstate);
-                       }
-
-                       ov->curframe = -1;
-                       PDEBUG(4, "SOF dropped (no active frame)");
-                       return;  /* Nowhere to store this frame */
-               }
-       }
-sof:
-       PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-
-// Snapshot not reverse-engineered yet.
-#if 0
-       /* Check to see if it's a snapshot frame */
-       /* FIXME?? Should the snapshot reset go here? Performance? */
-       if (in[8] & 0x02) {
-               frame->snapshot = 1;
-               PDEBUG(3, "snapshot detected");
-       }
-#endif
-       frame->scanstate = STATE_LINES;
-       frame->bytes_recvd = 0;
-       frame->compressed = 1;
-
-check_middle:
-       /* Are we in a frame? */
-       if (frame->scanstate != STATE_LINES) {
-               PDEBUG(4, "scanstate: no SOF yet");
-               return;
-       }
-
-       /* Dump all data exactly as received */
-       if (dumppix == 2) {
-               frame->bytes_recvd += n;
-               if (frame->bytes_recvd <= max_raw)
-                       memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
-               else
-                       PDEBUG(3, "Raw data buffer overrun!! (%d)",
-                               frame->bytes_recvd - max_raw);
-       } else {
-               /* All incoming data are divided into 8-byte segments. If the
-                * segment contains all zero bytes, it must be skipped. These
-                * zero-segments allow the OV518 to mainain a constant data rate
-                * regardless of the effectiveness of the compression. Segments
-                * are aligned relative to the beginning of each isochronous
-                * packet. The first segment in each image is a header (the
-                * decompressor skips it later).
-                */
-
-               int b, read = 0, allzero, copied = 0;
-
-               while (read < n) {
-                       allzero = 1;
-                       for (b = 0; b < 8; b++) {
-                               if (in[read + b]) {
-                                       allzero = 0;
-                                       break;
-                               }
-                       }
-
-                       if (allzero) {
-                       /* Don't copy it */
-                       } else {
-                               if (frame->bytes_recvd + copied + 8 <= max_raw)
-                               {
-                                       memcpy(frame->rawdata
-                                               + frame->bytes_recvd + copied,
-                                               in + read, 8);
-                                       copied += 8;
-                               } else {
-                                       PDEBUG(3, "Raw data buffer overrun!!");
-                               }
-                       }
-                       read += 8;
-               }
-               frame->bytes_recvd += copied;
-       }
-}
-
-static void
-ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs)
-{
-       int i;
-       struct usb_ov511 *ov;
-       struct ov511_sbuf *sbuf;
-
-       if (!urb->context) {
-               PDEBUG(4, "no context");
-               return;
-       }
-
-       sbuf = urb->context;
-       ov = sbuf->ov;
-
-       if (!ov || !ov->dev || !ov->user) {
-               PDEBUG(4, "no device, or not open");
-               return;
-       }
-
-       if (!ov->streaming) {
-               PDEBUG(4, "hmmm... not streaming, but got interrupt");
-               return;
-       }
-
-        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-                PDEBUG(4, "URB unlinked");
-                return;
-        }
-
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
-               err("ERROR: urb->status=%d: %s", urb->status,
-                   symbolic(urb_errlist, urb->status));
-       }
-
-       /* Copy the data received into our frame buffer */
-       PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
-              urb->number_of_packets);
-       for (i = 0; i < urb->number_of_packets; i++) {
-               /* Warning: Don't call *_move_data() if no frame active! */
-               if (ov->curframe >= 0) {
-                       int n = urb->iso_frame_desc[i].actual_length;
-                       int st = urb->iso_frame_desc[i].status;
-                       unsigned char *cdata;
-
-                       urb->iso_frame_desc[i].actual_length = 0;
-                       urb->iso_frame_desc[i].status = 0;
-
-                       cdata = urb->transfer_buffer
-                               + urb->iso_frame_desc[i].offset;
-
-                       if (!n) {
-                               PDEBUG(4, "Zero-length packet");
-                               continue;
-                       }
-
-                       if (st)
-                               PDEBUG(2, "data error: [%d] len=%d, status=%d",
-                                      i, n, st);
-
-                       if (ov->bclass == BCL_OV511)
-                               ov511_move_data(ov, cdata, n);
-                       else if (ov->bclass == BCL_OV518)
-                               ov518_move_data(ov, cdata, n);
-                       else
-                               err("Unknown bridge device (%d)", ov->bridge);
-
-               } else if (waitqueue_active(&ov->wq)) {
-                       wake_up_interruptible(&ov->wq);
-               }
-       }
-
-       /* Resubmit this URB */
-       urb->dev = ov->dev;
-       if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
-               err("usb_submit_urb() ret %d", i);
-
-       return;
-}
-
-/****************************************************************************
- *
- * Stream initialization and termination
- *
- ***************************************************************************/
-
-static int
-ov51x_init_isoc(struct usb_ov511 *ov)
-{
-       struct urb *urb;
-       int fx, err, n, size;
-
-       PDEBUG(3, "*** Initializing capture ***");
-
-       ov->curframe = -1;
-
-       if (ov->bridge == BRG_OV511) {
-               if (cams == 1)
-                       size = 993;
-               else if (cams == 2)
-                       size = 513;
-               else if (cams == 3 || cams == 4)
-                       size = 257;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (cams == 1)
-                       size = 961;
-               else if (cams == 2)
-                       size = 513;
-               else if (cams == 3 || cams == 4)
-                       size = 257;
-               else if (cams >= 5 && cams <= 8)
-                       size = 129;
-               else if (cams >= 9 && cams <= 31)
-                       size = 33;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else if (ov->bclass == BCL_OV518) {
-               if (cams == 1)
-                       size = 896;
-               else if (cams == 2)
-                       size = 512;
-               else if (cams == 3 || cams == 4)
-                       size = 256;
-               else if (cams >= 5 && cams <= 8)
-                       size = 128;
-               else {
-                       err("\"cams\" parameter too high!");
-                       return -1;
-               }
-       } else {
-               err("invalid bridge type");
-               return -1;
-       }
-
-       // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
-       if (ov->bclass == BCL_OV518) {
-               if (packetsize == -1) {
-                       ov518_set_packet_size(ov, 640);
-               } else {
-                       info("Forcing packet size to %d", packetsize);
-                       ov518_set_packet_size(ov, packetsize);
-               }
-       } else {
-               if (packetsize == -1) {
-                       ov511_set_packet_size(ov, size);
-               } else {
-                       info("Forcing packet size to %d", packetsize);
-                       ov511_set_packet_size(ov, packetsize);
-               }
-       }
-
-       for (n = 0; n < OV511_NUMSBUF; n++) {
-               urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-               if (!urb) {
-                       err("init isoc: usb_alloc_urb ret. NULL");
-                       return -ENOMEM;
-               }
-               ov->sbuf[n].urb = urb;
-               urb->dev = ov->dev;
-               urb->context = &ov->sbuf[n];
-               urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = ov->sbuf[n].data;
-               urb->complete = ov51x_isoc_irq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
-               urb->interval = 1;
-               for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-                       urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
-                       urb->iso_frame_desc[fx].length = ov->packet_size;
-               }
-       }
-
-       ov->streaming = 1;
-
-       for (n = 0; n < OV511_NUMSBUF; n++) {
-               ov->sbuf[n].urb->dev = ov->dev;
-               err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
-               if (err) {
-                       err("init isoc: usb_submit_urb(%d) ret %d", n, err);
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-static void
-ov51x_unlink_isoc(struct usb_ov511 *ov)
-{
-       int n;
-
-       /* Unschedule all of the iso td's */
-       for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
-               if (ov->sbuf[n].urb) {
-                       usb_kill_urb(ov->sbuf[n].urb);
-                       usb_free_urb(ov->sbuf[n].urb);
-                       ov->sbuf[n].urb = NULL;
-               }
-       }
-}
-
-static void
-ov51x_stop_isoc(struct usb_ov511 *ov)
-{
-       if (!ov->streaming || !ov->dev)
-               return;
-
-       PDEBUG(3, "*** Stopping capture ***");
-
-       if (ov->bclass == BCL_OV518)
-               ov518_set_packet_size(ov, 0);
-       else
-               ov511_set_packet_size(ov, 0);
-
-       ov->streaming = 0;
-
-       ov51x_unlink_isoc(ov);
-}
-
-static int
-ov51x_new_frame(struct usb_ov511 *ov, int framenum)
-{
-       struct ov511_frame *frame;
-       int newnum;
-
-       PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
-
-       if (!ov->dev)
-               return -1;
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /* ready to be grabbed into, then use it instead */
-       if (ov->curframe == -1) {
-               newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
-               if (ov->frame[newnum].grabstate == FRAME_READY)
-                       framenum = newnum;
-       } else
-               return 0;
-
-       frame = &ov->frame[framenum];
-
-       PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
-              frame->width, frame->height);
-
-       frame->grabstate = FRAME_GRABBING;
-       frame->scanstate = STATE_SCANNING;
-       frame->snapshot = 0;
-
-       ov->curframe = framenum;
-
-       /* Make sure it's not too big */
-       if (frame->width > ov->maxwidth)
-               frame->width = ov->maxwidth;
-
-       frame->width &= ~7L;            /* Multiple of 8 */
-
-       if (frame->height > ov->maxheight)
-               frame->height = ov->maxheight;
-
-       frame->height &= ~3L;           /* Multiple of 4 */
-
-       return 0;
-}
-
-/****************************************************************************
- *
- * Buffer management
- *
- ***************************************************************************/
-
-/*
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- *   them if you explicitly free them somewhere else!
- */
-static void
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
-       int i;
-       PDEBUG(4, "entered");
-
-       if (ov->fbuf) {
-               rvfree(ov->fbuf, OV511_NUMFRAMES
-                      * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
-               ov->fbuf = NULL;
-       }
-
-       vfree(ov->rawfbuf);
-       ov->rawfbuf = NULL;
-
-       vfree(ov->tempfbuf);
-       ov->tempfbuf = NULL;
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               kfree(ov->sbuf[i].data);
-               ov->sbuf[i].data = NULL;
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].data = NULL;
-               ov->frame[i].rawdata = NULL;
-               ov->frame[i].tempdata = NULL;
-               if (ov->frame[i].compbuf) {
-                       free_page((unsigned long) ov->frame[i].compbuf);
-                       ov->frame[i].compbuf = NULL;
-               }
-       }
-
-       PDEBUG(4, "buffer memory deallocated");
-       ov->buf_state = BUF_NOT_ALLOCATED;
-       PDEBUG(4, "leaving");
-}
-
-static int
-ov51x_alloc(struct usb_ov511 *ov)
-{
-       int i;
-       const int w = ov->maxwidth;
-       const int h = ov->maxheight;
-       const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
-       const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
-       PDEBUG(4, "entered");
-       mutex_lock(&ov->buf_lock);
-
-       if (ov->buf_state == BUF_ALLOCATED)
-               goto out;
-
-       ov->fbuf = rvmalloc(data_bufsize);
-       if (!ov->fbuf)
-               goto error;
-
-       ov->rawfbuf = vmalloc(raw_bufsize);
-       if (!ov->rawfbuf)
-               goto error;
-
-       memset(ov->rawfbuf, 0, raw_bufsize);
-
-       ov->tempfbuf = vmalloc(raw_bufsize);
-       if (!ov->tempfbuf)
-               goto error;
-
-       memset(ov->tempfbuf, 0, raw_bufsize);
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
-                       MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
-               if (!ov->sbuf[i].data)
-                       goto error;
-
-               PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
-               ov->frame[i].rawdata = ov->rawfbuf
-                + i * MAX_RAW_DATA_SIZE(w, h);
-               ov->frame[i].tempdata = ov->tempfbuf
-                + i * MAX_RAW_DATA_SIZE(w, h);
-
-               ov->frame[i].compbuf =
-                (unsigned char *) __get_free_page(GFP_KERNEL);
-               if (!ov->frame[i].compbuf)
-                       goto error;
-
-               PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
-       }
-
-       ov->buf_state = BUF_ALLOCATED;
-out:
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "leaving");
-       return 0;
-error:
-       ov51x_do_dealloc(ov);
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "errored");
-       return -ENOMEM;
-}
-
-static void
-ov51x_dealloc(struct usb_ov511 *ov)
-{
-       PDEBUG(4, "entered");
-       mutex_lock(&ov->buf_lock);
-       ov51x_do_dealloc(ov);
-       mutex_unlock(&ov->buf_lock);
-       PDEBUG(4, "leaving");
-}
-
-/****************************************************************************
- *
- * V4L 1 API
- *
- ***************************************************************************/
-
-static int
-ov51x_v4l1_open(struct inode *inode, struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int err, i;
-
-       PDEBUG(4, "opening");
-
-       mutex_lock(&ov->lock);
-
-       err = -EBUSY;
-       if (ov->user)
-               goto out;
-
-       ov->sub_flag = 0;
-
-       /* In case app doesn't set them... */
-       err = ov51x_set_default_params(ov);
-       if (err < 0)
-               goto out;
-
-       /* Make sure frames are reset */
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].grabstate = FRAME_UNUSED;
-               ov->frame[i].bytes_read = 0;
-       }
-
-       /* If compression is on, make sure now that a
-        * decompressor can be loaded */
-       if (ov->compress && !ov->decomp_ops) {
-               err = request_decompressor(ov);
-               if (err && !dumppix)
-                       goto out;
-       }
-
-       err = ov51x_alloc(ov);
-       if (err < 0)
-               goto out;
-
-       err = ov51x_init_isoc(ov);
-       if (err) {
-               ov51x_dealloc(ov);
-               goto out;
-       }
-
-       ov->user++;
-       file->private_data = vdev;
-
-       if (ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 1);
-
-out:
-       mutex_unlock(&ov->lock);
-       return err;
-}
-
-static int
-ov51x_v4l1_close(struct inode *inode, struct file *file)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-
-       PDEBUG(4, "ov511_close");
-
-       mutex_lock(&ov->lock);
-
-       ov->user--;
-       ov51x_stop_isoc(ov);
-
-       if (ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-
-       if (ov->dev)
-               ov51x_dealloc(ov);
-
-       mutex_unlock(&ov->lock);
-
-       /* Device unplugged while open. Only a minimum of unregistration is done
-        * here; the disconnect callback already did the rest. */
-       if (!ov->dev) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-
-               ov51x_dealloc(ov);
-               kfree(ov);
-               ov = NULL;
-       }
-
-       file->private_data = NULL;
-       return 0;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       PDEBUG(5, "IOCtl: 0x%X", cmd);
-
-       if (!ov->dev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *b = arg;
-
-               PDEBUG(4, "VIDIOCGCAP");
-
-               memset(b, 0, sizeof(struct video_capability));
-               sprintf(b->name, "%s USB Camera",
-                       symbolic(brglist, ov->bridge));
-               b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-               b->channels = ov->num_inputs;
-               b->audios = 0;
-               b->maxwidth = ov->maxwidth;
-               b->maxheight = ov->maxheight;
-               b->minwidth = ov->minwidth;
-               b->minheight = ov->minheight;
-
-               return 0;
-       }
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-
-               PDEBUG(4, "VIDIOCGCHAN");
-
-               if ((unsigned)(v->channel) >= ov->num_inputs) {
-                       err("Invalid channel (%d)", v->channel);
-                       return -EINVAL;
-               }
-
-               v->norm = ov->norm;
-               v->type = VIDEO_TYPE_CAMERA;
-               v->flags = 0;
-//             v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
-               v->tuners = 0;
-               decoder_get_input_name(ov, v->channel, v->name);
-
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-               int err;
-
-               PDEBUG(4, "VIDIOCSCHAN");
-
-               /* Make sure it's not a camera */
-               if (!ov->has_decoder) {
-                       if (v->channel == 0)
-                               return 0;
-                       else
-                               return -EINVAL;
-               }
-
-               if (v->norm != VIDEO_MODE_PAL &&
-                   v->norm != VIDEO_MODE_NTSC &&
-                   v->norm != VIDEO_MODE_SECAM &&
-                   v->norm != VIDEO_MODE_AUTO) {
-                       err("Invalid norm (%d)", v->norm);
-                       return -EINVAL;
-               }
-
-               if ((unsigned)(v->channel) >= ov->num_inputs) {
-                       err("Invalid channel (%d)", v->channel);
-                       return -EINVAL;
-               }
-
-               err = decoder_set_input(ov, v->channel);
-               if (err)
-                       return err;
-
-               err = decoder_set_norm(ov, v->norm);
-               if (err)
-                       return err;
-
-               return 0;
-       }
-       case VIDIOCGPICT:
-       {
-               struct video_picture *p = arg;
-
-               PDEBUG(4, "VIDIOCGPICT");
-
-               memset(p, 0, sizeof(struct video_picture));
-               if (sensor_get_picture(ov, p))
-                       return -EIO;
-
-               /* Can we get these from frame[0]? -claudio? */
-               p->depth = ov->frame[0].depth;
-               p->palette = ov->frame[0].format;
-
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *p = arg;
-               int i, rc;
-
-               PDEBUG(4, "VIDIOCSPICT");
-
-               if (!get_depth(p->palette))
-                       return -EINVAL;
-
-               if (sensor_set_picture(ov, p))
-                       return -EIO;
-
-               if (force_palette && p->palette != force_palette) {
-                       info("Palette rejected (%s)",
-                            symbolic(v4l1_plist, p->palette));
-                       return -EINVAL;
-               }
-
-               // FIXME: Format should be independent of frames
-               if (p->palette != ov->frame[0].format) {
-                       PDEBUG(4, "Detected format change");
-
-                       rc = ov51x_wait_frames_inactive(ov);
-                       if (rc)
-                               return rc;
-
-                       mode_init_regs(ov, ov->frame[0].width,
-                               ov->frame[0].height, p->palette, ov->sub_flag);
-               }
-
-               PDEBUG(4, "Setting depth=%d, palette=%s",
-                      p->depth, symbolic(v4l1_plist, p->palette));
-
-               for (i = 0; i < OV511_NUMFRAMES; i++) {
-                       ov->frame[i].depth = p->depth;
-                       ov->frame[i].format = p->palette;
-               }
-
-               return 0;
-       }
-       case VIDIOCGCAPTURE:
-       {
-               int *vf = arg;
-
-               PDEBUG(4, "VIDIOCGCAPTURE");
-
-               ov->sub_flag = *vf;
-               return 0;
-       }
-       case VIDIOCSCAPTURE:
-       {
-               struct video_capture *vc = arg;
-
-               PDEBUG(4, "VIDIOCSCAPTURE");
-
-               if (vc->flags)
-                       return -EINVAL;
-               if (vc->decimation)
-                       return -EINVAL;
-
-               vc->x &= ~3L;
-               vc->y &= ~1L;
-               vc->y &= ~31L;
-
-               if (vc->width == 0)
-                       vc->width = 32;
-
-               vc->height /= 16;
-               vc->height *= 16;
-               if (vc->height == 0)
-                       vc->height = 16;
-
-               ov->subx = vc->x;
-               ov->suby = vc->y;
-               ov->subw = vc->width;
-               ov->subh = vc->height;
-
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *vw = arg;
-               int i, rc;
-
-               PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
-
-#if 0
-               if (vw->flags)
-                       return -EINVAL;
-               if (vw->clipcount)
-                       return -EINVAL;
-               if (vw->height != ov->maxheight)
-                       return -EINVAL;
-               if (vw->width != ov->maxwidth)
-                       return -EINVAL;
-#endif
-
-               rc = ov51x_wait_frames_inactive(ov);
-               if (rc)
-                       return rc;
-
-               rc = mode_init_regs(ov, vw->width, vw->height,
-                       ov->frame[0].format, ov->sub_flag);
-               if (rc < 0)
-                       return rc;
-
-               for (i = 0; i < OV511_NUMFRAMES; i++) {
-                       ov->frame[i].width = vw->width;
-                       ov->frame[i].height = vw->height;
-               }
-
-               return 0;
-       }
-       case VIDIOCGWIN:
-       {
-               struct video_window *vw = arg;
-
-               memset(vw, 0, sizeof(struct video_window));
-               vw->x = 0;              /* FIXME */
-               vw->y = 0;
-               vw->width = ov->frame[0].width;
-               vw->height = ov->frame[0].height;
-               vw->flags = 30;
-
-               PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
-
-               return 0;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vm = arg;
-               int i;
-
-               PDEBUG(4, "VIDIOCGMBUF");
-
-               memset(vm, 0, sizeof(struct video_mbuf));
-               vm->size = OV511_NUMFRAMES
-                          * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-               vm->frames = OV511_NUMFRAMES;
-
-               vm->offsets[0] = 0;
-               for (i = 1; i < OV511_NUMFRAMES; i++) {
-                       vm->offsets[i] = vm->offsets[i-1]
-                          + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
-               }
-
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-               int rc, depth;
-               unsigned int f = vm->frame;
-
-               PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
-                       vm->height, symbolic(v4l1_plist, vm->format));
-
-               depth = get_depth(vm->format);
-               if (!depth) {
-                       PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
-                              symbolic(v4l1_plist, vm->format));
-                       return -EINVAL;
-               }
-
-               if (f >= OV511_NUMFRAMES) {
-                       err("VIDIOCMCAPTURE: invalid frame (%d)", f);
-                       return -EINVAL;
-               }
-
-               if (vm->width > ov->maxwidth
-                   || vm->height > ov->maxheight) {
-                       err("VIDIOCMCAPTURE: requested dimensions too big");
-                       return -EINVAL;
-               }
-
-               if (ov->frame[f].grabstate == FRAME_GRABBING) {
-                       PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
-                       return -EBUSY;
-               }
-
-               if (force_palette && (vm->format != force_palette)) {
-                       PDEBUG(2, "palette rejected (%s)",
-                              symbolic(v4l1_plist, vm->format));
-                       return -EINVAL;
-               }
-
-               if ((ov->frame[f].width != vm->width) ||
-                   (ov->frame[f].height != vm->height) ||
-                   (ov->frame[f].format != vm->format) ||
-                   (ov->frame[f].sub_flag != ov->sub_flag) ||
-                   (ov->frame[f].depth != depth)) {
-                       PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
-
-                       rc = ov51x_wait_frames_inactive(ov);
-                       if (rc)
-                               return rc;
-
-                       rc = mode_init_regs(ov, vm->width, vm->height,
-                               vm->format, ov->sub_flag);
-#if 0
-                       if (rc < 0) {
-                               PDEBUG(1, "Got error while initializing regs ");
-                               return ret;
-                       }
-#endif
-                       ov->frame[f].width = vm->width;
-                       ov->frame[f].height = vm->height;
-                       ov->frame[f].format = vm->format;
-                       ov->frame[f].sub_flag = ov->sub_flag;
-                       ov->frame[f].depth = depth;
-               }
-
-               /* Mark it as ready */
-               ov->frame[f].grabstate = FRAME_READY;
-
-               PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
-
-               return ov51x_new_frame(ov, f);
-       }
-       case VIDIOCSYNC:
-       {
-               unsigned int fnum = *((unsigned int *) arg);
-               struct ov511_frame *frame;
-               int rc;
-
-               if (fnum >= OV511_NUMFRAMES) {
-                       err("VIDIOCSYNC: invalid frame (%d)", fnum);
-                       return -EINVAL;
-               }
-
-               frame = &ov->frame[fnum];
-
-               PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
-                      frame->grabstate);
-
-               switch (frame->grabstate) {
-               case FRAME_UNUSED:
-                       return -EINVAL;
-               case FRAME_READY:
-               case FRAME_GRABBING:
-               case FRAME_ERROR:
-redo:
-                       if (!ov->dev)
-                               return -EIO;
-
-                       rc = wait_event_interruptible(frame->wq,
-                           (frame->grabstate == FRAME_DONE)
-                           || (frame->grabstate == FRAME_ERROR));
-
-                       if (rc)
-                               return rc;
-
-                       if (frame->grabstate == FRAME_ERROR) {
-                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-                                       return rc;
-                               goto redo;
-                       }
-                       /* Fall through */
-               case FRAME_DONE:
-                       if (ov->snap_enabled && !frame->snapshot) {
-                               if ((rc = ov51x_new_frame(ov, fnum)) < 0)
-                                       return rc;
-                               goto redo;
-                       }
-
-                       frame->grabstate = FRAME_UNUSED;
-
-                       /* Reset the hardware snapshot button */
-                       /* FIXME - Is this the best place for this? */
-                       if ((ov->snap_enabled) && (frame->snapshot)) {
-                               frame->snapshot = 0;
-                               ov51x_clear_snapshot(ov);
-                       }
-
-                       /* Decompression, format conversion, etc... */
-                       ov51x_postprocess(ov, frame);
-
-                       break;
-               } /* end switch */
-
-               return 0;
-       }
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vb = arg;
-
-               PDEBUG(4, "VIDIOCGFBUF");
-
-               memset(vb, 0, sizeof(struct video_buffer));
-
-               return 0;
-       }
-       case VIDIOCGUNIT:
-       {
-               struct video_unit *vu = arg;
-
-               PDEBUG(4, "VIDIOCGUNIT");
-
-               memset(vu, 0, sizeof(struct video_unit));
-
-               vu->video = ov->vdev->minor;
-               vu->vbi = VIDEO_NO_UNIT;
-               vu->radio = VIDEO_NO_UNIT;
-               vu->audio = VIDEO_NO_UNIT;
-               vu->teletext = VIDEO_NO_UNIT;
-
-               return 0;
-       }
-       case OV511IOC_WI2C:
-       {
-               struct ov511_i2c_struct *w = arg;
-
-               return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
-       }
-       case OV511IOC_RI2C:
-       {
-               struct ov511_i2c_struct *r = arg;
-               int rc;
-
-               rc = i2c_r_slave(ov, r->slave, r->reg);
-               if (rc < 0)
-                       return rc;
-
-               r->value = rc;
-               return 0;
-       }
-       default:
-               PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
-               return -ENOIOCTLCMD;
-       } /* end switch */
-
-       return 0;
-}
-
-static int
-ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
-                unsigned int cmd, unsigned long arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int rc;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
-
-       mutex_unlock(&ov->lock);
-       return rc;
-}
-
-static ssize_t
-ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
-{
-       struct video_device *vdev = file->private_data;
-       int noblock = file->f_flags&O_NONBLOCK;
-       unsigned long count = cnt;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       int i, rc = 0, frmx = -1;
-       struct ov511_frame *frame;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
-
-       if (!vdev || !buf) {
-               rc = -EFAULT;
-               goto error;
-       }
-
-       if (!ov->dev) {
-               rc = -EIO;
-               goto error;
-       }
-
-// FIXME: Only supports two frames
-       /* See if a frame is completed, then use it. */
-       if (ov->frame[0].grabstate >= FRAME_DONE)       /* _DONE or _ERROR */
-               frmx = 0;
-       else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-               frmx = 1;
-
-       /* If nonblocking we return immediately */
-       if (noblock && (frmx == -1)) {
-               rc = -EAGAIN;
-               goto error;
-       }
-
-       /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
-       /* See if a frame is in process (grabbing), then use it. */
-       if (frmx == -1) {
-               if (ov->frame[0].grabstate == FRAME_GRABBING)
-                       frmx = 0;
-               else if (ov->frame[1].grabstate == FRAME_GRABBING)
-                       frmx = 1;
-       }
-
-       /* If no frame is active, start one. */
-       if (frmx == -1) {
-               if ((rc = ov51x_new_frame(ov, frmx = 0))) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-       }
-
-       frame = &ov->frame[frmx];
-
-restart:
-       if (!ov->dev) {
-               rc = -EIO;
-               goto error;
-       }
-
-       /* Wait while we're grabbing the image */
-       PDEBUG(4, "Waiting image grabbing");
-       rc = wait_event_interruptible(frame->wq,
-               (frame->grabstate == FRAME_DONE)
-               || (frame->grabstate == FRAME_ERROR));
-
-       if (rc)
-               goto error;
-
-       PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
-       PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
-
-       if (frame->grabstate == FRAME_ERROR) {
-               frame->bytes_read = 0;
-               err("** ick! ** Errored frame %d", ov->curframe);
-               if (ov51x_new_frame(ov, frmx)) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-               goto restart;
-       }
-
-
-       /* Repeat until we get a snapshot frame */
-       if (ov->snap_enabled)
-               PDEBUG(4, "Waiting snapshot frame");
-       if (ov->snap_enabled && !frame->snapshot) {
-               frame->bytes_read = 0;
-               if ((rc = ov51x_new_frame(ov, frmx))) {
-                       err("read: ov51x_new_frame error");
-                       goto error;
-               }
-               goto restart;
-       }
-
-       /* Clear the snapshot */
-       if (ov->snap_enabled && frame->snapshot) {
-               frame->snapshot = 0;
-               ov51x_clear_snapshot(ov);
-       }
-
-       /* Decompression, format conversion, etc... */
-       ov51x_postprocess(ov, frame);
-
-       PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
-               frame->bytes_read,
-               get_frame_length(frame));
-
-       /* copy bytes to user space; we allow for partials reads */
-//     if ((count + frame->bytes_read)
-//         > get_frame_length((struct ov511_frame *)frame))
-//             count = frame->scanlength - frame->bytes_read;
-
-       /* FIXME - count hardwired to be one frame... */
-       count = get_frame_length(frame);
-
-       PDEBUG(4, "Copy to user space: %ld bytes", count);
-       if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
-               PDEBUG(4, "Copy failed! %d bytes not copied", i);
-               rc = -EFAULT;
-               goto error;
-       }
-
-       frame->bytes_read += count;
-       PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
-               count, frame->bytes_read);
-
-       /* If all data have been read... */
-       if (frame->bytes_read
-           >= get_frame_length(frame)) {
-               frame->bytes_read = 0;
-
-// FIXME: Only supports two frames
-               /* Mark it as available to be used again. */
-               ov->frame[frmx].grabstate = FRAME_UNUSED;
-               if ((rc = ov51x_new_frame(ov, !frmx))) {
-                       err("ov51x_new_frame returned error");
-                       goto error;
-               }
-       }
-
-       PDEBUG(4, "read finished, returning %ld (sweet)", count);
-
-       mutex_unlock(&ov->lock);
-       return count;
-
-error:
-       mutex_unlock(&ov->lock);
-       return rc;
-}
-
-static int
-ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *vdev = file->private_data;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end - vma->vm_start;
-       struct usb_ov511 *ov = video_get_drvdata(vdev);
-       unsigned long page, pos;
-
-       if (ov->dev == NULL)
-               return -EIO;
-
-       PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
-
-       if (size > (((OV511_NUMFRAMES
-                     * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
-                     + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&ov->lock))
-               return -EINTR;
-
-       pos = (unsigned long)ov->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&ov->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       mutex_unlock(&ov->lock);
-       return 0;
-}
-
-static struct file_operations ov511_fops = {
-       .owner =        THIS_MODULE,
-       .open =         ov51x_v4l1_open,
-       .release =      ov51x_v4l1_close,
-       .read =         ov51x_v4l1_read,
-       .mmap =         ov51x_v4l1_mmap,
-       .ioctl =        ov51x_v4l1_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-
-static struct video_device vdev_template = {
-       .owner =        THIS_MODULE,
-       .name =         "OV511 USB Camera",
-       .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_OV511,
-       .fops =         &ov511_fops,
-       .release =      video_device_release,
-       .minor =        -1,
-};
-
-/****************************************************************************
- *
- * OV511 and sensor configuration
- *
- ***************************************************************************/
-
-/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
- * the same register settings as the OV7610, since they are very similar.
- */
-static int
-ov7xx0_configure(struct usb_ov511 *ov)
-{
-       int i, success;
-       int rc;
-
-       /* Lawrence Glaister <lg@jfm.bc.ca> reports:
-        *
-        * Register 0x0f in the 7610 has the following effects:
-        *
-        * 0x85 (AEC method 1): Best overall, good contrast range
-        * 0x45 (AEC method 2): Very overexposed
-        * 0xa5 (spec sheet default): Ok, but the black level is
-        *      shifted resulting in loss of contrast
-        * 0x05 (old driver setting): very overexposed, too much
-        *      contrast
-        */
-       static struct ov511_regvals aRegvalsNorm7610[] = {
-               { OV511_I2C_BUS, 0x10, 0xff },
-               { OV511_I2C_BUS, 0x16, 0x06 },
-               { OV511_I2C_BUS, 0x28, 0x24 },
-               { OV511_I2C_BUS, 0x2b, 0xac },
-               { OV511_I2C_BUS, 0x12, 0x00 },
-               { OV511_I2C_BUS, 0x38, 0x81 },
-               { OV511_I2C_BUS, 0x28, 0x24 },  /* 0c */
-               { OV511_I2C_BUS, 0x0f, 0x85 },  /* lg's setting */
-               { OV511_I2C_BUS, 0x15, 0x01 },
-               { OV511_I2C_BUS, 0x20, 0x1c },
-               { OV511_I2C_BUS, 0x23, 0x2a },
-               { OV511_I2C_BUS, 0x24, 0x10 },
-               { OV511_I2C_BUS, 0x25, 0x8a },
-               { OV511_I2C_BUS, 0x26, 0xa2 },
-               { OV511_I2C_BUS, 0x27, 0xc2 },
-               { OV511_I2C_BUS, 0x2a, 0x04 },
-               { OV511_I2C_BUS, 0x2c, 0xfe },
-               { OV511_I2C_BUS, 0x2d, 0x93 },
-               { OV511_I2C_BUS, 0x30, 0x71 },
-               { OV511_I2C_BUS, 0x31, 0x60 },
-               { OV511_I2C_BUS, 0x32, 0x26 },
-               { OV511_I2C_BUS, 0x33, 0x20 },
-               { OV511_I2C_BUS, 0x34, 0x48 },
-               { OV511_I2C_BUS, 0x12, 0x24 },
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm7620[] = {
-               { OV511_I2C_BUS, 0x00, 0x00 },
-               { OV511_I2C_BUS, 0x01, 0x80 },
-               { OV511_I2C_BUS, 0x02, 0x80 },
-               { OV511_I2C_BUS, 0x03, 0xc0 },
-               { OV511_I2C_BUS, 0x06, 0x60 },
-               { OV511_I2C_BUS, 0x07, 0x00 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x12, 0x24 },
-               { OV511_I2C_BUS, 0x13, 0x01 },
-               { OV511_I2C_BUS, 0x14, 0x84 },
-               { OV511_I2C_BUS, 0x15, 0x01 },
-               { OV511_I2C_BUS, 0x16, 0x03 },
-               { OV511_I2C_BUS, 0x17, 0x2f },
-               { OV511_I2C_BUS, 0x18, 0xcf },
-               { OV511_I2C_BUS, 0x19, 0x06 },
-               { OV511_I2C_BUS, 0x1a, 0xf5 },
-               { OV511_I2C_BUS, 0x1b, 0x00 },
-               { OV511_I2C_BUS, 0x20, 0x18 },
-               { OV511_I2C_BUS, 0x21, 0x80 },
-               { OV511_I2C_BUS, 0x22, 0x80 },
-               { OV511_I2C_BUS, 0x23, 0x00 },
-               { OV511_I2C_BUS, 0x26, 0xa2 },
-               { OV511_I2C_BUS, 0x27, 0xea },
-               { OV511_I2C_BUS, 0x28, 0x20 },
-               { OV511_I2C_BUS, 0x29, 0x00 },
-               { OV511_I2C_BUS, 0x2a, 0x10 },
-               { OV511_I2C_BUS, 0x2b, 0x00 },
-               { OV511_I2C_BUS, 0x2c, 0x88 },
-               { OV511_I2C_BUS, 0x2d, 0x91 },
-               { OV511_I2C_BUS, 0x2e, 0x80 },
-               { OV511_I2C_BUS, 0x2f, 0x44 },
-               { OV511_I2C_BUS, 0x60, 0x27 },
-               { OV511_I2C_BUS, 0x61, 0x02 },
-               { OV511_I2C_BUS, 0x62, 0x5f },
-               { OV511_I2C_BUS, 0x63, 0xd5 },
-               { OV511_I2C_BUS, 0x64, 0x57 },
-               { OV511_I2C_BUS, 0x65, 0x83 },
-               { OV511_I2C_BUS, 0x66, 0x55 },
-               { OV511_I2C_BUS, 0x67, 0x92 },
-               { OV511_I2C_BUS, 0x68, 0xcf },
-               { OV511_I2C_BUS, 0x69, 0x76 },
-               { OV511_I2C_BUS, 0x6a, 0x22 },
-               { OV511_I2C_BUS, 0x6b, 0x00 },
-               { OV511_I2C_BUS, 0x6c, 0x02 },
-               { OV511_I2C_BUS, 0x6d, 0x44 },
-               { OV511_I2C_BUS, 0x6e, 0x80 },
-               { OV511_I2C_BUS, 0x6f, 0x1d },
-               { OV511_I2C_BUS, 0x70, 0x8b },
-               { OV511_I2C_BUS, 0x71, 0x00 },
-               { OV511_I2C_BUS, 0x72, 0x14 },
-               { OV511_I2C_BUS, 0x73, 0x54 },
-               { OV511_I2C_BUS, 0x74, 0x00 },
-               { OV511_I2C_BUS, 0x75, 0x8e },
-               { OV511_I2C_BUS, 0x76, 0x00 },
-               { OV511_I2C_BUS, 0x77, 0xff },
-               { OV511_I2C_BUS, 0x78, 0x80 },
-               { OV511_I2C_BUS, 0x79, 0x80 },
-               { OV511_I2C_BUS, 0x7a, 0x80 },
-               { OV511_I2C_BUS, 0x7b, 0xe2 },
-               { OV511_I2C_BUS, 0x7c, 0x00 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "starting configuration");
-
-       /* This looks redundant, but is necessary for WebCam 3 */
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               return -1;
-
-       if (init_ov_sensor(ov) >= 0) {
-               PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
-       } else {
-               /* Reset the 76xx */
-               if (i2c_w(ov, 0x12, 0x80) < 0)
-                       return -1;
-
-               /* Wait for it to initialize */
-               msleep(150);
-
-               i = 0;
-               success = 0;
-               while (i <= i2c_detect_tries) {
-                       if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
-                           (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
-                               success = 1;
-                               break;
-                       } else {
-                               i++;
-                       }
-               }
-
-// Was (i == i2c_detect_tries) previously. This obviously used to always report
-// success. Whether anyone actually depended on that bug is unknown
-               if ((i >= i2c_detect_tries) && (success == 0)) {
-                       err("Failed to read sensor ID. You might not have an");
-                       err("OV7610/20, or it may be not responding. Report");
-                       err("this to " EMAIL);
-                       err("This is only a warning. You can attempt to use");
-                       err("your camera anyway");
-// Only issue a warning for now
-//                     return -1;
-               } else {
-                       PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
-               }
-       }
-
-       /* Detect sensor (sub)type */
-       rc = i2c_r(ov, OV7610_REG_COM_I);
-
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       } else if ((rc & 3) == 3) {
-               info("Sensor is an OV7610");
-               ov->sensor = SEN_OV7610;
-       } else if ((rc & 3) == 1) {
-               /* I don't know what's different about the 76BE yet. */
-               if (i2c_r(ov, 0x15) & 1)
-                       info("Sensor is an OV7620AE");
-               else
-                       info("Sensor is an OV76BE");
-
-               /* OV511+ will return all zero isoc data unless we
-                * configure the sensor as a 7620. Someone needs to
-                * find the exact reg. setting that causes this. */
-               if (ov->bridge == BRG_OV511PLUS) {
-                       info("Enabling 511+/7620AE workaround");
-                       ov->sensor = SEN_OV7620;
-               } else {
-                       ov->sensor = SEN_OV76BE;
-               }
-       } else if ((rc & 3) == 0) {
-               info("Sensor is an OV7620");
-               ov->sensor = SEN_OV7620;
-       } else {
-               err("Unknown image sensor version: %d", rc & 3);
-               return -1;
-       }
-
-       if (ov->sensor == SEN_OV7620) {
-               PDEBUG(4, "Writing 7620 registers");
-               if (write_regvals(ov, aRegvalsNorm7620))
-                       return -1;
-       } else {
-               PDEBUG(4, "Writing 7610 registers");
-               if (write_regvals(ov, aRegvalsNorm7610))
-                       return -1;
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 640;
-       ov->maxheight = 480;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       return 0;
-}
-
-/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
-ov6xx0_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-       static struct ov511_regvals aRegvalsNorm6x20[] = {
-               { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-               { OV511_I2C_BUS, 0x11, 0x01 },
-               { OV511_I2C_BUS, 0x03, 0x60 },
-               { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-               { OV511_I2C_BUS, 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-               { OV511_I2C_BUS, 0x0c, 0x24 },
-               { OV511_I2C_BUS, 0x0d, 0x24 },
-               { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
-               { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
-               { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
-               { OV511_I2C_BUS, 0x14, 0x04 },
-               /* 0x16: 0x06 helps frame stability with moving objects */
-               { OV511_I2C_BUS, 0x16, 0x06 },
-//             { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-               { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-               { OV511_I2C_BUS, 0x28, 0x05 },
-               { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//             { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-               { OV511_I2C_BUS, 0x2d, 0x99 },
-               { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
-               { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
-               { OV511_I2C_BUS, 0x38, 0x8b },
-               { OV511_I2C_BUS, 0x39, 0x40 },
-
-               { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-               { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-               { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-
-               { OV511_I2C_BUS, 0x3d, 0x80 },
-               /* These next two registers (0x4a, 0x4b) are undocumented. They
-                * control the color balance */
-               { OV511_I2C_BUS, 0x4a, 0x80 },
-               { OV511_I2C_BUS, 0x4b, 0x80 },
-               { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
-               { OV511_I2C_BUS, 0x4e, 0xc1 },
-               { OV511_I2C_BUS, 0x4f, 0x04 },
-// Do 50-53 have any effect?
-// Toggle 0x12[2] off and on here?
-               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
-       };
-
-       static struct ov511_regvals aRegvalsNorm6x30[] = {
-       /*OK*/  { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
-               { OV511_I2C_BUS, 0x11, 0x00 },
-       /*OK*/  { OV511_I2C_BUS, 0x03, 0x60 },
-       /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
-               { OV511_I2C_BUS, 0x07, 0xa8 },
-               /* The ratio of 0x0c and 0x0d  controls the white point */
-       /*OK*/  { OV511_I2C_BUS, 0x0c, 0x24 },
-       /*OK*/  { OV511_I2C_BUS, 0x0d, 0x24 },
-       /*A*/   { OV511_I2C_BUS, 0x0e, 0x20 },
-//     /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
-               { OV511_I2C_BUS, 0x16, 0x03 },
-//     /*OK*/  { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
-               // 21 & 22? The suggested values look wrong. Go with default
-       /*A*/   { OV511_I2C_BUS, 0x23, 0xc0 },
-       /*A*/   { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-//     /*OK*/  { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-
-               /* 0x28: 0x05 Selects RGB format if RGB on */
-//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
-//     /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
-
-       /*OK*/  { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-//     /*OK*/  { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
-               { OV511_I2C_BUS, 0x2d, 0x99 },
-//     /*A*/   { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-//     /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-//     /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
-//     /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
-//             { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-//             { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-//             { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-               { OV511_I2C_BUS, 0x3d, 0x80 },
-//     /*A*/   { OV511_I2C_BUS, 0x3f, 0x0e },
-
-               /* These next two registers (0x4a, 0x4b) are undocumented. They
-                * control the color balance */
-//     /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-//     /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
-               { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
-       /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
-
-               /* UV average mode, color killer: strongest */
-               { OV511_I2C_BUS, 0x4f, 0x07 },
-
-               { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
-               { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
-               { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
-               { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
-               { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
-//             { OV511_I2C_BUS, 0x5c, 0x10 },
-               { OV511_DONE_BUS, 0x0, 0x00 },  /* END MARKER */
-       };
-
-       PDEBUG(4, "starting sensor configuration");
-
-       if (init_ov_sensor(ov) < 0) {
-               err("Failed to read sensor ID. You might not have an OV6xx0,");
-               err("or it may be not responding. Report this to " EMAIL);
-               return -1;
-       } else {
-               PDEBUG(1, "OV6xx0 sensor detected");
-       }
-
-       /* Detect sensor (sub)type */
-       rc = i2c_r(ov, OV7610_REG_COM_I);
-
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       }
-
-       if ((rc & 3) == 0) {
-               ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630");
-       } else if ((rc & 3) == 1) {
-               ov->sensor = SEN_OV6620;
-               info("Sensor is an OV6620");
-       } else if ((rc & 3) == 2) {
-               ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630AE");
-       } else if ((rc & 3) == 3) {
-               ov->sensor = SEN_OV6630;
-               info("Sensor is an OV6630AF");
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 352;
-       ov->maxheight = 288;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       if (ov->sensor == SEN_OV6620) {
-               PDEBUG(4, "Writing 6x20 registers");
-               if (write_regvals(ov, aRegvalsNorm6x20))
-                       return -1;
-       } else {
-               PDEBUG(4, "Writing 6x30 registers");
-               if (write_regvals(ov, aRegvalsNorm6x30))
-                       return -1;
-       }
-
-       return 0;
-}
-
-/* This initializes the KS0127 and KS0127B video decoders. */
-static int 
-ks0127_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-       if (ov51x_init_ks_sensor(ov) < 0) {
-               err("Failed to initialize the KS0127");
-               return -1;
-       } else {
-               PDEBUG(1, "KS012x(B) sensor detected");
-       }
-#endif
-
-       /* Detect decoder subtype */
-       rc = i2c_r(ov, 0x00);
-       if (rc < 0) {
-               err("Error detecting sensor type");
-               return -1;
-       } else if (rc & 0x08) {
-               rc = i2c_r(ov, 0x3d);
-               if (rc < 0) {
-                       err("Error detecting sensor type");
-                       return -1;
-               } else if ((rc & 0x0f) == 0) {
-                       info("Sensor is a KS0127");
-                       ov->sensor = SEN_KS0127;
-               } else if ((rc & 0x0f) == 9) {
-                       info("Sensor is a KS0127B Rev. A");
-                       ov->sensor = SEN_KS0127B;
-               }
-       } else {
-               err("Error: Sensor is an unsupported KS0122");
-               return -1;
-       }
-
-       /* Set sensor-specific vars */
-       ov->maxwidth = 640;
-       ov->maxheight = 480;
-       ov->minwidth = 64;
-       ov->minheight = 48;
-
-       // FIXME: These do not match the actual settings yet
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x80 << 8;
-       ov->colour = 0x80 << 8;
-       ov->hue = 0x80 << 8;
-
-       /* This device is not supported yet. Bail out now... */
-       err("This sensor is not supported yet.");
-       return -1;
-
-       return 0;
-}
-
-/* This initializes the SAA7111A video decoder. */
-static int
-saa7111a_configure(struct usb_ov511 *ov)
-{
-       int rc;
-
-       /* Since there is no register reset command, all registers must be
-        * written, otherwise gives erratic results */
-       static struct ov511_regvals aRegvalsNormSAA7111A[] = {
-               { OV511_I2C_BUS, 0x06, 0xce },
-               { OV511_I2C_BUS, 0x07, 0x00 },
-               { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
-               { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
-               { OV511_I2C_BUS, 0x00, 0x00 },
-               { OV511_I2C_BUS, 0x01, 0x00 },
-               { OV511_I2C_BUS, 0x03, 0x23 },
-               { OV511_I2C_BUS, 0x04, 0x00 },
-               { OV511_I2C_BUS, 0x05, 0x00 },
-               { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
-               { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
-               { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
-               { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
-               { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
-               { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
-               { OV511_I2C_BUS, 0x0f, 0x00 },
-               { OV511_I2C_BUS, 0x11, 0x0c },
-               { OV511_I2C_BUS, 0x12, 0x00 },
-               { OV511_I2C_BUS, 0x13, 0x00 },
-               { OV511_I2C_BUS, 0x14, 0x00 },
-               { OV511_I2C_BUS, 0x15, 0x00 },
-               { OV511_I2C_BUS, 0x16, 0x00 },
-               { OV511_I2C_BUS, 0x17, 0x00 },
-               { OV511_I2C_BUS, 0x02, 0xc0 },  /* Composite input 0 */
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
-       if (ov51x_init_saa_sensor(ov) < 0) {
-               err("Failed to initialize the SAA7111A");
-               return -1;
-       } else {
-               PDEBUG(1, "SAA7111A sensor detected");
-       }
-#endif
-
-       /* 640x480 not supported with PAL */
-       if (ov->pal) {
-               ov->maxwidth = 320;
-               ov->maxheight = 240;            /* Even field only */
-       } else {
-               ov->maxwidth = 640;
-               ov->maxheight = 480;            /* Even/Odd fields */
-       }
-
-       ov->minwidth = 320;
-       ov->minheight = 240;            /* Even field only */
-
-       ov->has_decoder = 1;
-       ov->num_inputs = 8;
-       ov->norm = VIDEO_MODE_AUTO;
-       ov->stop_during_set = 0;        /* Decoder guarantees stable image */
-
-       /* Decoder doesn't change these values, so we use these instead of
-        * acutally reading the registers (which doesn't work) */
-       ov->brightness = 0x80 << 8;
-       ov->contrast = 0x40 << 9;
-       ov->colour = 0x40 << 9;
-       ov->hue = 32768;
-
-       PDEBUG(4, "Writing SAA7111A registers");
-       if (write_regvals(ov, aRegvalsNormSAA7111A))
-               return -1;
-
-       /* Detect version of decoder. This must be done after writing the
-         * initial regs or the decoder will lock up. */
-       rc = i2c_r(ov, 0x00);
-
-       if (rc < 0) {
-               err("Error detecting sensor version");
-               return -1;
-       } else {
-               info("Sensor is an SAA7111A (version 0x%x)", rc);
-               ov->sensor = SEN_SAA7111A;
-       }
-
-       // FIXME: Fix this for OV518(+)
-       /* Latch to negative edge of clock. Otherwise, we get incorrect
-        * colors and jitter in the digital signal. */
-       if (ov->bclass == BCL_OV511)
-               reg_w(ov, 0x11, 0x00);
-       else
-               warn("SAA7111A not yet supported with OV518/OV518+");
-
-       return 0;
-}
-
-/* This initializes the OV511/OV511+ and the sensor */
-static int 
-ov511_configure(struct usb_ov511 *ov)
-{
-       static struct ov511_regvals aRegvalsInit511[] = {
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x7f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3f },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0x01 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3d },
-               { OV511_DONE_BUS, 0x0, 0x00},
-       };
-
-       static struct ov511_regvals aRegvalsNorm511[] = {
-               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0x01 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R511_FIFO_OPTS,        0x1f },
-               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
-               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm511Plus[] = {
-               { OV511_REG_BUS, R511_DRAM_FLOW_CTL,    0xff },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 },
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x00 },
-               { OV511_REG_BUS, R511_FIFO_OPTS,        0xff },
-               { OV511_REG_BUS, R511_COMP_EN,          0x00 },
-               { OV511_REG_BUS, R511_COMP_LUT_EN,      0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "");
-
-       ov->customid = reg_r(ov, R511_SYS_CUST_ID);
-       if (ov->customid < 0) {
-               err("Unable to read camera bridge registers");
-               goto error;
-       }
-
-       PDEBUG (1, "CustomID = %d", ov->customid);
-       ov->desc = symbolic(camlist, ov->customid);
-       info("model: %s", ov->desc);
-
-       if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
-               err("Camera type (%d) not recognized", ov->customid);
-               err("Please notify " EMAIL " of the name,");
-               err("manufacturer, model, and this number of your camera.");
-               err("Also include the output of the detection process.");
-       } 
-
-       if (ov->customid == 70)         /* USB Life TV (PAL/SECAM) */
-               ov->pal = 1;
-
-       if (write_regvals(ov, aRegvalsInit511))
-               goto error;
-
-       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-
-       /* The OV511+ has undocumented bits in the flow control register.
-        * Setting it to 0xff fixes the corruption with moving objects. */
-       if (ov->bridge == BRG_OV511) {
-               if (write_regvals(ov, aRegvalsNorm511))
-                       goto error;
-       } else if (ov->bridge == BRG_OV511PLUS) {
-               if (write_regvals(ov, aRegvalsNorm511Plus))
-                       goto error;
-       } else {
-               err("Invalid bridge");
-       }
-
-       if (ov511_init_compression(ov))
-               goto error;
-
-       ov->packet_numbering = 1;
-       ov511_set_packet_size(ov, 0);
-
-       ov->snap_enabled = snapshot;
-
-       /* Test for 7xx0 */
-       PDEBUG(3, "Testing for 0V7xx0");
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               goto error;
-
-       if (i2c_w(ov, 0x12, 0x80) < 0) {
-               /* Test for 6xx0 */
-               PDEBUG(3, "Testing for 0V6xx0");
-               ov->primary_i2c_slave = OV6xx0_SID;
-               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-                       goto error;
-
-               if (i2c_w(ov, 0x12, 0x80) < 0) {
-                       /* Test for 8xx0 */
-                       PDEBUG(3, "Testing for 0V8xx0");
-                       ov->primary_i2c_slave = OV8xx0_SID;
-                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-                               goto error;
-
-                       if (i2c_w(ov, 0x12, 0x80) < 0) {
-                               /* Test for SAA7111A */
-                               PDEBUG(3, "Testing for SAA7111A");
-                               ov->primary_i2c_slave = SAA7111A_SID;
-                               if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
-                                       goto error;
-
-                               if (i2c_w(ov, 0x0d, 0x00) < 0) {
-                                       /* Test for KS0127 */
-                                       PDEBUG(3, "Testing for KS0127");
-                                       ov->primary_i2c_slave = KS0127_SID;
-                                       if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
-                                               goto error;
-
-                                       if (i2c_w(ov, 0x10, 0x00) < 0) {
-                                               err("Can't determine sensor slave IDs");
-                                               goto error;
-                                       } else {
-                                               if (ks0127_configure(ov) < 0) {
-                                                       err("Failed to configure KS0127");
-                                                       goto error;
-                                               }
-                                       }
-                               } else {
-                                       if (saa7111a_configure(ov) < 0) {
-                                               err("Failed to configure SAA7111A");
-                                               goto error;
-                                       }
-                               }
-                       } else {
-                               err("Detected unsupported OV8xx0 sensor");
-                               goto error;
-                       }
-               } else {
-                       if (ov6xx0_configure(ov) < 0) {
-                               err("Failed to configure OV6xx0");
-                               goto error;
-                       }
-               }
-       } else {
-               if (ov7xx0_configure(ov) < 0) {
-                       err("Failed to configure OV7xx0");
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       err("OV511 Config failed");
-
-       return -EBUSY;
-}
-
-/* This initializes the OV518/OV518+ and the sensor */
-static int
-ov518_configure(struct usb_ov511 *ov)
-{
-       /* For 518 and 518+ */
-       static struct ov511_regvals aRegvalsInit518[] = {
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x40 },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x3e },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, R51x_SYS_RESET,        0x00 },
-               { OV511_REG_BUS, R51x_SYS_INIT,         0xe1 },
-               { OV511_REG_BUS, 0x46,                  0x00 }, 
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_DONE_BUS, 0x0, 0x00},
-       };
-
-       static struct ov511_regvals aRegvalsNorm518[] = {
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
-               { OV511_REG_BUS, 0x31,                  0x0f },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_REG_BUS, 0x24,                  0x9f },
-               { OV511_REG_BUS, 0x25,                  0x90 },
-               { OV511_REG_BUS, 0x20,                  0x00 },
-               { OV511_REG_BUS, 0x51,                  0x04 },
-               { OV511_REG_BUS, 0x71,                  0x19 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       static struct ov511_regvals aRegvalsNorm518Plus[] = {
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x02 }, /* Reset */
-               { OV511_REG_BUS, R51x_SYS_SNAP,         0x01 }, /* Enable */
-               { OV511_REG_BUS, 0x31,                  0x0f },
-               { OV511_REG_BUS, 0x5d,                  0x03 },
-               { OV511_REG_BUS, 0x24,                  0x9f },
-               { OV511_REG_BUS, 0x25,                  0x90 },
-               { OV511_REG_BUS, 0x20,                  0x60 },
-               { OV511_REG_BUS, 0x51,                  0x02 },
-               { OV511_REG_BUS, 0x71,                  0x19 },
-               { OV511_REG_BUS, 0x40,                  0xff },
-               { OV511_REG_BUS, 0x41,                  0x42 },
-               { OV511_REG_BUS, 0x46,                  0x00 },
-               { OV511_REG_BUS, 0x33,                  0x04 },
-               { OV511_REG_BUS, 0x21,                  0x19 },
-               { OV511_REG_BUS, 0x3f,                  0x10 },
-               { OV511_DONE_BUS, 0x0, 0x00 },
-       };
-
-       PDEBUG(4, "");
-
-       /* First 5 bits of custom ID reg are a revision ID on OV518 */
-       info("Device revision %d", 0x1F & reg_r(ov, R511_SYS_CUST_ID));
-
-       /* Give it the default description */
-       ov->desc = symbolic(camlist, 0);
-
-       if (write_regvals(ov, aRegvalsInit518))
-               goto error;
-
-       /* Set LED GPIO pin to output mode */
-       if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
-               goto error;
-
-       /* LED is off by default with OV518; have to explicitly turn it on */
-       if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
-               ov51x_led_control(ov, 0);
-       else
-               ov51x_led_control(ov, 1);
-
-       /* Don't require compression if dumppix is enabled; otherwise it's
-        * required. OV518 has no uncompressed mode, to save RAM. */
-       if (!dumppix && !ov->compress) {
-               ov->compress = 1;
-               warn("Compression required with OV518...enabling");
-       }
-
-       if (ov->bridge == BRG_OV518) {
-               if (write_regvals(ov, aRegvalsNorm518))
-                       goto error;
-       } else if (ov->bridge == BRG_OV518PLUS) {
-               if (write_regvals(ov, aRegvalsNorm518Plus))
-                       goto error;
-       } else {
-               err("Invalid bridge");
-       }
-
-       if (reg_w(ov, 0x2f, 0x80) < 0)
-               goto error;
-
-       if (ov518_init_compression(ov))
-               goto error;
-
-       if (ov->bridge == BRG_OV518)
-       {
-               struct usb_interface *ifp;
-               struct usb_host_interface *alt;
-               __u16 mxps = 0;
-
-               ifp = usb_ifnum_to_if(ov->dev, 0);
-               if (ifp) {
-                       alt = usb_altnum_to_altsetting(ifp, 7);
-                       if (alt)
-                               mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
-               }
-
-               /* Some OV518s have packet numbering by default, some don't */
-               if (mxps == 897)
-                       ov->packet_numbering = 1;
-               else
-                       ov->packet_numbering = 0;
-       } else {
-               /* OV518+ has packet numbering turned on by default */
-               ov->packet_numbering = 1;
-       }
-
-       ov518_set_packet_size(ov, 0);
-
-       ov->snap_enabled = snapshot;
-
-       /* Test for 76xx */
-       ov->primary_i2c_slave = OV7xx0_SID;
-       if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
-               goto error;
-
-       /* The OV518 must be more aggressive about sensor detection since
-        * I2C write will never fail if the sensor is not present. We have
-        * to try to initialize the sensor to detect its presence */
-
-       if (init_ov_sensor(ov) < 0) {
-               /* Test for 6xx0 */
-               ov->primary_i2c_slave = OV6xx0_SID;
-               if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
-                       goto error;
-
-               if (init_ov_sensor(ov) < 0) {
-                       /* Test for 8xx0 */
-                       ov->primary_i2c_slave = OV8xx0_SID;
-                       if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
-                               goto error;
-
-                       if (init_ov_sensor(ov) < 0) {
-                               err("Can't determine sensor slave IDs");
-                               goto error;
-                       } else {
-                               err("Detected unsupported OV8xx0 sensor");
-                               goto error;
-                       }
-               } else {
-                       if (ov6xx0_configure(ov) < 0) {
-                               err("Failed to configure OV6xx0");
-                               goto error;
-                       }
-               }
-       } else {
-               if (ov7xx0_configure(ov) < 0) {
-                       err("Failed to configure OV7xx0");
-                       goto error;
-               }
-       }
-
-       ov->maxwidth = 352;
-       ov->maxheight = 288;
-
-       // The OV518 cannot go as low as the sensor can
-       ov->minwidth = 160;
-       ov->minheight = 120;
-
-       return 0;
-
-error:
-       err("OV518 Config failed");
-
-       return -EBUSY;
-}
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-
-static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
-{
-       struct video_device *vdev = to_video_device(cd);
-       return video_get_drvdata(vdev);
-}
-
-static ssize_t show_custom_id(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%d\n", ov->customid);
-} 
-static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-
-static ssize_t show_model(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", ov->desc);
-} 
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_bridge(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
-} 
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-
-static ssize_t show_sensor(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
-} 
-static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-
-static ssize_t show_brightness(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_brightness(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_saturation(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_contrast(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_contrast(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_hue(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned short x;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_hue(ov, &x);
-       return sprintf(buf, "%d\n", x >> 8);
-} 
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_exposure(struct class_device *cd, char *buf)
-{
-       struct usb_ov511 *ov = cd_to_ov(cd);
-       unsigned char exp = 0;
-
-       if (!ov->dev)
-               return -ENODEV;
-       sensor_get_exposure(ov, &exp);
-       return sprintf(buf, "%d\n", exp >> 8);
-} 
-static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-
-static void ov_create_sysfs(struct video_device *vdev)
-{
-       video_device_create_file(vdev, &class_device_attr_custom_id);
-       video_device_create_file(vdev, &class_device_attr_model);
-       video_device_create_file(vdev, &class_device_attr_bridge);
-       video_device_create_file(vdev, &class_device_attr_sensor);
-       video_device_create_file(vdev, &class_device_attr_brightness);
-       video_device_create_file(vdev, &class_device_attr_saturation);
-       video_device_create_file(vdev, &class_device_attr_contrast);
-       video_device_create_file(vdev, &class_device_attr_hue);
-       video_device_create_file(vdev, &class_device_attr_exposure);
-}
-
-/****************************************************************************
- *  USB routines
- ***************************************************************************/
-
-static int
-ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_interface_descriptor *idesc;
-       struct usb_ov511 *ov;
-       int i;
-
-       PDEBUG(1, "probing for device...");
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       idesc = &intf->cur_altsetting->desc;
-
-       if (idesc->bInterfaceClass != 0xFF)
-               return -ENODEV;
-       if (idesc->bInterfaceSubClass != 0x00)
-               return -ENODEV;
-
-       if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
-               err("couldn't kmalloc ov struct");
-               goto error_out;
-       }
-
-       ov->dev = dev;
-       ov->iface = idesc->bInterfaceNumber;
-       ov->led_policy = led;
-       ov->compress = compress;
-       ov->lightfreq = lightfreq;
-       ov->num_inputs = 1;        /* Video decoder init functs. change this */
-       ov->stop_during_set = !fastset;
-       ov->backlight = backlight;
-       ov->mirror = mirror;
-       ov->auto_brt = autobright;
-       ov->auto_gain = autogain;
-       ov->auto_exp = autoexp;
-
-       switch (le16_to_cpu(dev->descriptor.idProduct)) {
-       case PROD_OV511:
-               ov->bridge = BRG_OV511;
-               ov->bclass = BCL_OV511;
-               break;
-       case PROD_OV511PLUS:
-               ov->bridge = BRG_OV511PLUS;
-               ov->bclass = BCL_OV511;
-               break;
-       case PROD_OV518:
-               ov->bridge = BRG_OV518;
-               ov->bclass = BCL_OV518;
-               break;
-       case PROD_OV518PLUS:
-               ov->bridge = BRG_OV518PLUS;
-               ov->bclass = BCL_OV518;
-               break;
-       case PROD_ME2CAM:
-               if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
-                       goto error;
-               ov->bridge = BRG_OV511PLUS;
-               ov->bclass = BCL_OV511;
-               break;
-       default:
-               err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
-               goto error;
-       }
-
-       info("USB %s video device found", symbolic(brglist, ov->bridge));
-
-       init_waitqueue_head(&ov->wq);
-
-       mutex_init(&ov->lock);  /* to 1 == available */
-       mutex_init(&ov->buf_lock);
-       mutex_init(&ov->i2c_lock);
-       mutex_init(&ov->cbuf_lock);
-
-       ov->buf_state = BUF_NOT_ALLOCATED;
-
-       if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
-               err("usb_make_path error");
-               goto error;
-       }
-
-       /* Allocate control transfer buffer. */
-       /* Must be kmalloc()'ed, for DMA compatibility */
-       ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
-       if (!ov->cbuf)
-               goto error;
-
-       if (ov->bclass == BCL_OV518) {
-               if (ov518_configure(ov) < 0)
-                       goto error;
-       } else {
-               if (ov511_configure(ov) < 0)
-                       goto error;
-       }
-
-       for (i = 0; i < OV511_NUMFRAMES; i++) {
-               ov->frame[i].framenum = i;
-               init_waitqueue_head(&ov->frame[i].wq);
-       }
-
-       for (i = 0; i < OV511_NUMSBUF; i++) {
-               ov->sbuf[i].ov = ov;
-               spin_lock_init(&ov->sbuf[i].lock);
-               ov->sbuf[i].n = i;
-       }
-
-       /* Unnecessary? (This is done on open(). Need to make sure variables
-        * are properly initialized without this before removing it, though). */
-       if (ov51x_set_default_params(ov) < 0)
-               goto error;
-
-#ifdef OV511_DEBUG
-       if (dump_bridge) {
-               if (ov->bclass == BCL_OV511)
-                       ov511_dump_regs(ov);
-               else
-                       ov518_dump_regs(ov);
-       }
-#endif
-
-       ov->vdev = video_device_alloc();
-       if (!ov->vdev)
-               goto error;
-
-       memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
-       ov->vdev->dev = &dev->dev;
-       video_set_drvdata(ov->vdev, ov);
-
-       for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
-               /* Minor 0 cannot be specified; assume user wants autodetect */
-               if (unit_video[i] == 0)
-                       break;
-
-               if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
-                       unit_video[i]) >= 0) {
-                       break;
-               }
-       }
-
-       /* Use the next available one */
-       if ((ov->vdev->minor == -1) &&
-           video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
-               err("video_register_device failed");
-               goto error;
-       }
-
-       info("Device at %s registered to minor %d", ov->usb_path,
-            ov->vdev->minor);
-
-       usb_set_intfdata(intf, ov);
-       ov_create_sysfs(ov->vdev);
-       return 0;
-
-error:
-       if (ov->vdev) {
-               if (-1 == ov->vdev->minor)
-                       video_device_release(ov->vdev);
-               else
-                       video_unregister_device(ov->vdev);
-               ov->vdev = NULL;
-       }
-
-       if (ov->cbuf) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-       }
-
-       kfree(ov);
-       ov = NULL;
-
-error_out:
-       err("Camera initialization failed");
-       return -EIO;
-}
-
-static void
-ov51x_disconnect(struct usb_interface *intf)
-{
-       struct usb_ov511 *ov = usb_get_intfdata(intf);
-       int n;
-
-       PDEBUG(3, "");
-
-       usb_set_intfdata (intf, NULL);
-
-       if (!ov)
-               return;
-
-       if (ov->vdev)
-               video_unregister_device(ov->vdev);
-
-       for (n = 0; n < OV511_NUMFRAMES; n++)
-               ov->frame[n].grabstate = FRAME_ERROR;
-
-       ov->curframe = -1;
-
-       /* This will cause the process to request another frame */
-       for (n = 0; n < OV511_NUMFRAMES; n++)
-               wake_up_interruptible(&ov->frame[n].wq);
-
-       wake_up_interruptible(&ov->wq);
-
-       ov->streaming = 0;
-       ov51x_unlink_isoc(ov);
-
-       ov->dev = NULL;
-
-       /* Free the memory */
-       if (ov && !ov->user) {
-               mutex_lock(&ov->cbuf_lock);
-               kfree(ov->cbuf);
-               ov->cbuf = NULL;
-               mutex_unlock(&ov->cbuf_lock);
-
-               ov51x_dealloc(ov);
-               kfree(ov);
-               ov = NULL;
-       }
-
-       PDEBUG(3, "Disconnect complete");
-}
-
-static struct usb_driver ov511_driver = {
-       .name =         "ov511",
-       .id_table =     device_table,
-       .probe =        ov51x_probe,
-       .disconnect =   ov51x_disconnect
-};
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init
-usb_ov511_init(void)
-{
-       int retval;
-
-       retval = usb_register(&ov511_driver);
-       if (retval)
-               goto out;
-
-       info(DRIVER_VERSION " : " DRIVER_DESC);
-
-out:
-       return retval;
-}
-
-static void __exit
-usb_ov511_exit(void)
-{
-       usb_deregister(&ov511_driver);
-       info("driver deregistered");
-
-}
-
-module_init(usb_ov511_init);
-module_exit(usb_ov511_exit);
-
diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h
deleted file mode 100644 (file)
index bce9b36..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-#ifndef __LINUX_OV511_H
-#define __LINUX_OV511_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <linux/smp_lock.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#define OV511_DEBUG    /* Turn on debug messages */
-
-#ifdef OV511_DEBUG
-       #define PDEBUG(level, fmt, args...) \
-               if (debug >= (level)) info("[%s:%d] " fmt, \
-               __FUNCTION__, __LINE__ , ## args)
-#else
-       #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { \
-       if ((v) < (mi)) (v) = (mi); \
-       else if ((v) > (ma)) (v) = (ma); \
-}
-
-/* --------------------------------- */
-/* DEFINES FOR OV511 AND OTHER CHIPS */
-/* --------------------------------- */
-
-/* USB IDs */
-#define VEND_OMNIVISION        0x05A9
-#define PROD_OV511     0x0511
-#define PROD_OV511PLUS 0xA511
-#define PROD_OV518     0x0518
-#define PROD_OV518PLUS 0xA518
-
-#define VEND_MATTEL    0x0813
-#define PROD_ME2CAM    0x0002
-
-/* --------------------------------- */
-/*     OV51x REGISTER MNEMONICS      */
-/* --------------------------------- */
-
-/* Camera interface register numbers */
-#define R511_CAM_DELAY         0x10
-#define R511_CAM_EDGE          0x11
-#define R511_CAM_PXCNT         0x12
-#define R511_CAM_LNCNT         0x13
-#define R511_CAM_PXDIV         0x14
-#define R511_CAM_LNDIV         0x15
-#define R511_CAM_UV_EN         0x16
-#define R511_CAM_LINE_MODE     0x17
-#define R511_CAM_OPTS          0x18
-
-/* Snapshot mode camera interface register numbers */
-#define R511_SNAP_FRAME                0x19
-#define R511_SNAP_PXCNT                0x1A
-#define R511_SNAP_LNCNT                0x1B
-#define R511_SNAP_PXDIV                0x1C
-#define R511_SNAP_LNDIV                0x1D
-#define R511_SNAP_UV_EN                0x1E
-#define R511_SNAP_OPTS         0x1F
-
-/* DRAM register numbers */
-#define R511_DRAM_FLOW_CTL     0x20
-#define R511_DRAM_ARCP         0x21
-#define R511_DRAM_MRC          0x22
-#define R511_DRAM_RFC          0x23
-
-/* ISO FIFO register numbers */
-#define R51x_FIFO_PSIZE                0x30    /* 2 bytes wide w/ OV518(+) */
-#define R511_FIFO_OPTS         0x31
-
-/* Parallel IO register numbers */
-#define R511_PIO_OPTS          0x38
-#define R511_PIO_DATA          0x39
-#define R511_PIO_BIST          0x3E
-#define R518_GPIO_IN           0x55    /* OV518(+) only */
-#define R518_GPIO_OUT          0x56    /* OV518(+) only */
-#define R518_GPIO_CTL          0x57    /* OV518(+) only */
-#define R518_GPIO_PULSE_IN     0x58    /* OV518(+) only */
-#define R518_GPIO_PULSE_CLEAR  0x59    /* OV518(+) only */
-#define R518_GPIO_PULSE_POL    0x5a    /* OV518(+) only */
-#define R518_GPIO_PULSE_EN     0x5b    /* OV518(+) only */
-#define R518_GPIO_RESET                0x5c    /* OV518(+) only */
-
-/* I2C registers */
-#define R511_I2C_CTL           0x40
-#define R518_I2C_CTL           0x47    /* OV518(+) only */
-#define R51x_I2C_W_SID         0x41
-#define R51x_I2C_SADDR_3       0x42
-#define R51x_I2C_SADDR_2       0x43
-#define R51x_I2C_R_SID         0x44
-#define R51x_I2C_DATA          0x45
-#define R51x_I2C_CLOCK         0x46
-#define R51x_I2C_TIMEOUT       0x47
-
-/* I2C snapshot registers */
-#define R511_SI2C_SADDR_3      0x48
-#define R511_SI2C_DATA         0x49
-
-/* System control registers */
-#define R51x_SYS_RESET         0x50
-               /* Reset type definitions */
-#define        OV511_RESET_UDC         0x01
-#define        OV511_RESET_I2C         0x02
-#define        OV511_RESET_FIFO        0x04
-#define        OV511_RESET_OMNICE      0x08
-#define        OV511_RESET_DRAM        0x10
-#define        OV511_RESET_CAM_INT     0x20
-#define        OV511_RESET_OV511       0x40
-#define        OV511_RESET_NOREGS      0x3F /* All but OV511 & regs */
-#define        OV511_RESET_ALL         0x7F
-
-#define R511_SYS_CLOCK_DIV     0x51
-#define R51x_SYS_SNAP          0x52
-#define R51x_SYS_INIT          0x53
-#define R511_SYS_PWR_CLK       0x54 /* OV511+/OV518(+) only */
-#define R511_SYS_LED_CTL       0x55 /* OV511+ only */
-#define R511_SYS_USER          0x5E
-#define R511_SYS_CUST_ID       0x5F
-
-/* OmniCE (compression) registers */
-#define R511_COMP_PHY          0x70
-#define R511_COMP_PHUV         0x71
-#define R511_COMP_PVY          0x72
-#define R511_COMP_PVUV         0x73
-#define R511_COMP_QHY          0x74
-#define R511_COMP_QHUV         0x75
-#define R511_COMP_QVY          0x76
-#define R511_COMP_QVUV         0x77
-#define R511_COMP_EN           0x78
-#define R511_COMP_LUT_EN       0x79            
-#define R511_COMP_LUT_BEGIN    0x80
-
-/* --------------------------------- */
-/*         ALTERNATE NUMBERS         */
-/* --------------------------------- */
-
-/* Alternate numbers for various max packet sizes (OV511 only) */
-#define OV511_ALT_SIZE_992     0
-#define OV511_ALT_SIZE_993     1
-#define OV511_ALT_SIZE_768     2
-#define OV511_ALT_SIZE_769     3
-#define OV511_ALT_SIZE_512     4
-#define OV511_ALT_SIZE_513     5
-#define OV511_ALT_SIZE_257     6
-#define OV511_ALT_SIZE_0       7
-
-/* Alternate numbers for various max packet sizes (OV511+ only) */
-#define OV511PLUS_ALT_SIZE_0   0
-#define OV511PLUS_ALT_SIZE_33  1
-#define OV511PLUS_ALT_SIZE_129 2
-#define OV511PLUS_ALT_SIZE_257 3
-#define OV511PLUS_ALT_SIZE_385 4
-#define OV511PLUS_ALT_SIZE_513 5
-#define OV511PLUS_ALT_SIZE_769 6
-#define OV511PLUS_ALT_SIZE_961 7
-
-/* Alternate numbers for various max packet sizes (OV518(+) only) */
-#define OV518_ALT_SIZE_0       0
-#define OV518_ALT_SIZE_128     1
-#define OV518_ALT_SIZE_256     2
-#define OV518_ALT_SIZE_384     3
-#define OV518_ALT_SIZE_512     4
-#define OV518_ALT_SIZE_640     5
-#define OV518_ALT_SIZE_768     6
-#define OV518_ALT_SIZE_896     7
-
-/* --------------------------------- */
-/*     OV7610 REGISTER MNEMONICS     */
-/* --------------------------------- */
-
-/* OV7610 registers */
-#define OV7610_REG_GAIN          0x00  /* gain setting (5:0) */
-#define OV7610_REG_BLUE          0x01  /* blue channel balance */
-#define OV7610_REG_RED           0x02  /* red channel balance */
-#define OV7610_REG_SAT           0x03  /* saturation */
-                                       /* 04 reserved */
-#define OV7610_REG_CNT           0x05  /* Y contrast */
-#define OV7610_REG_BRT           0x06  /* Y brightness */
-                                       /* 08-0b reserved */
-#define OV7610_REG_BLUE_BIAS     0x0C  /* blue channel bias (5:0) */
-#define OV7610_REG_RED_BIAS      0x0D  /* read channel bias (5:0) */
-#define OV7610_REG_GAMMA_COEFF   0x0E  /* gamma settings */
-#define OV7610_REG_WB_RANGE      0x0F  /* AEC/ALC/S-AWB settings */
-#define OV7610_REG_EXP           0x10  /* manual exposure setting */
-#define OV7610_REG_CLOCK         0x11  /* polarity/clock prescaler */
-#define OV7610_REG_COM_A         0x12  /* misc common regs */
-#define OV7610_REG_COM_B         0x13  /* misc common regs */
-#define OV7610_REG_COM_C         0x14  /* misc common regs */
-#define OV7610_REG_COM_D         0x15  /* misc common regs */
-#define OV7610_REG_FIELD_DIVIDE  0x16  /* field interval/mode settings */
-#define OV7610_REG_HWIN_START    0x17  /* horizontal window start */
-#define OV7610_REG_HWIN_END      0x18  /* horizontal window end */
-#define OV7610_REG_VWIN_START    0x19  /* vertical window start */
-#define OV7610_REG_VWIN_END      0x1A  /* vertical window end */
-#define OV7610_REG_PIXEL_SHIFT   0x1B  /* pixel shift */
-#define OV7610_REG_ID_HIGH       0x1C  /* manufacturer ID MSB */
-#define OV7610_REG_ID_LOW        0x1D  /* manufacturer ID LSB */
-                                       /* 0e-0f reserved */
-#define OV7610_REG_COM_E         0x20  /* misc common regs */
-#define OV7610_REG_YOFFSET       0x21  /* Y channel offset */
-#define OV7610_REG_UOFFSET       0x22  /* U channel offset */
-                                       /* 23 reserved */
-#define OV7610_REG_ECW           0x24  /* Exposure white level for AEC */
-#define OV7610_REG_ECB           0x25  /* Exposure black level for AEC */
-#define OV7610_REG_COM_F         0x26  /* misc settings */
-#define OV7610_REG_COM_G         0x27  /* misc settings */
-#define OV7610_REG_COM_H         0x28  /* misc settings */
-#define OV7610_REG_COM_I         0x29  /* misc settings */
-#define OV7610_REG_FRAMERATE_H   0x2A  /* frame rate MSB + misc */
-#define OV7610_REG_FRAMERATE_L   0x2B  /* frame rate LSB */
-#define OV7610_REG_ALC           0x2C  /* Auto Level Control settings */
-#define OV7610_REG_COM_J         0x2D  /* misc settings */
-#define OV7610_REG_VOFFSET       0x2E  /* V channel offset adjustment */
-#define OV7610_REG_ARRAY_BIAS   0x2F   /* Array bias -- don't change */
-                                       /* 30-32 reserved */
-#define OV7610_REG_YGAMMA        0x33  /* misc gamma settings (7:6) */
-#define OV7610_REG_BIAS_ADJUST   0x34  /* misc bias settings */
-#define OV7610_REG_COM_L         0x35  /* misc settings */
-                                       /* 36-37 reserved */
-#define OV7610_REG_COM_K         0x38  /* misc registers */
-
-/* --------------------------------- */
-/*           I2C ADDRESSES           */
-/* --------------------------------- */
-
-#define OV7xx0_SID   0x42
-#define OV6xx0_SID   0xC0
-#define OV8xx0_SID   0xA0
-#define KS0127_SID   0xD8
-#define SAA7111A_SID 0x48
-
-/* --------------------------------- */
-/*       MISCELLANEOUS DEFINES       */
-/* --------------------------------- */
-
-#define I2C_CLOCK_PRESCALER    0x03
-
-#define FRAMES_PER_DESC                10      /* FIXME - What should this be? */
-#define MAX_FRAME_SIZE_PER_DESC        993     /* For statically allocated stuff */
-#define PIXELS_PER_SEG         256     /* Pixels per segment */
-
-#define OV511_ENDPOINT_ADDRESS 1       /* Isoc endpoint number */
-
-#define OV511_NUMFRAMES        2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
-       #error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF          2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE                4
-
-/* Size of usb_make_path() buffer */
-#define OV511_USB_PATH_LEN     64
-
-/* Bridge types */
-enum {
-       BRG_UNKNOWN,
-       BRG_OV511,
-       BRG_OV511PLUS,
-       BRG_OV518,
-       BRG_OV518PLUS,
-};
-
-/* Bridge classes */
-enum {
-       BCL_UNKNOWN,
-       BCL_OV511,
-       BCL_OV518,
-};
-
-/* Sensor types */
-enum {
-       SEN_UNKNOWN,
-       SEN_OV76BE,
-       SEN_OV7610,
-       SEN_OV7620,
-       SEN_OV7620AE,
-       SEN_OV6620,
-       SEN_OV6630,
-       SEN_OV6630AE,
-       SEN_OV6630AF,
-       SEN_OV8600,
-       SEN_KS0127,
-       SEN_KS0127B,
-       SEN_SAA7111A,
-};
-
-enum {
-       STATE_SCANNING,         /* Scanning for start */
-       STATE_HEADER,           /* Parsing header */
-       STATE_LINES,            /* Parsing lines */
-};
-
-/* Buffer states */
-enum {
-       BUF_NOT_ALLOCATED,
-       BUF_ALLOCATED,
-};
-
-/* --------- Definition of ioctl interface --------- */
-
-#define OV511_INTERFACE_VER 101
-
-/* LED options */
-enum {
-       LED_OFF,
-       LED_ON,
-       LED_AUTO,
-};
-
-/* Raw frame formats */
-enum {
-       RAWFMT_INVALID,
-       RAWFMT_YUV400,
-       RAWFMT_YUV420,
-       RAWFMT_YUV422,
-       RAWFMT_GBR422,
-};
-
-struct ov511_i2c_struct {
-       unsigned char slave; /* Write slave ID (read ID - 1) */
-       unsigned char reg;   /* Index of register */
-       unsigned char value; /* User sets this w/ write, driver does w/ read */
-       unsigned char mask;  /* Bits to be changed. Not used with read ops */
-};
-
-/* ioctls */
-#define OV511IOC_WI2C     _IOW('v', BASE_VIDIOCPRIVATE + 5, \
-                              struct ov511_i2c_struct)
-#define OV511IOC_RI2C    _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
-                              struct ov511_i2c_struct)
-/* ------------- End IOCTL interface -------------- */
-
-struct usb_ov511;              /* Forward declaration */
-
-struct ov511_sbuf {
-       struct usb_ov511 *ov;
-       unsigned char *data;
-       struct urb *urb;
-       spinlock_t lock;
-       int n;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-struct ov511_regvals {
-       enum {
-               OV511_DONE_BUS,
-               OV511_REG_BUS,
-               OV511_I2C_BUS,
-       } bus;
-       unsigned char reg;
-       unsigned char val;
-};
-
-struct ov511_frame {
-       int framenum;           /* Index of this frame */
-       unsigned char *data;    /* Frame buffer */
-       unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
-       unsigned char *rawdata; /* Raw camera data buffer */
-       unsigned char *compbuf; /* Temp buffer for decompressor */
-
-       int depth;              /* Bytes per pixel */
-       int width;              /* Width application is expecting */
-       int height;             /* Height application is expecting */
-
-       int rawwidth;           /* Actual width of frame sent from camera */
-       int rawheight;          /* Actual height of frame sent from camera */
-
-       int sub_flag;           /* Sub-capture mode for this frame? */
-       unsigned int format;    /* Format for this frame */
-       int compressed;         /* Is frame compressed? */
-
-       volatile int grabstate; /* State of grabbing */
-       int scanstate;          /* State of scanning */
-
-       int bytes_recvd;        /* Number of image bytes received from camera */
-
-       long bytes_read;        /* Amount that has been read() */
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int snapshot;           /* True if frame was a snapshot */
-};
-
-#define DECOMP_INTERFACE_VER 4
-
-/* Compression module operations */
-struct ov51x_decomp_ops {
-       int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
-                         int, int, int);
-       struct module *owner;
-};
-
-struct usb_ov511 {
-       struct video_device *vdev;
-       struct usb_device *dev;
-
-       int customid;
-       char *desc;
-       unsigned char iface;
-       char usb_path[OV511_USB_PATH_LEN];
-
-       /* Determined by sensor type */
-       int maxwidth;
-       int maxheight;
-       int minwidth;
-       int minheight;
-
-       int brightness;
-       int colour;
-       int contrast;
-       int hue;
-       int whiteness;
-       int exposure;
-       int auto_brt;           /* Auto brightness enabled flag */
-       int auto_gain;          /* Auto gain control enabled flag */
-       int auto_exp;           /* Auto exposure enabled flag */
-       int backlight;          /* Backlight exposure algorithm flag */
-       int mirror;             /* Image is reversed horizontally */
-
-       int led_policy;         /* LED: off|on|auto; OV511+ only */
-
-       struct mutex lock;      /* Serializes user-accessible operations */
-       int user;               /* user count for exclusive use */
-
-       int streaming;          /* Are we streaming Isochronous? */
-       int grabbing;           /* Are we grabbing? */
-
-       int compress;           /* Should the next frame be compressed? */
-       int compress_inited;    /* Are compression params uploaded? */
-
-       int lightfreq;          /* Power (lighting) frequency */
-       int bandfilt;           /* Banding filter enabled flag */
-
-       unsigned char *fbuf;    /* Videodev buffer area */
-       unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
-       unsigned char *rawfbuf; /* Raw camera data buffer area */
-
-       int sub_flag;           /* Pix Array subcapture on flag */
-       int subx;               /* Pix Array subcapture x offset */
-       int suby;               /* Pix Array subcapture y offset */
-       int subw;               /* Pix Array subcapture width */
-       int subh;               /* Pix Array subcapture height */
-
-       int curframe;           /* Current receiving sbuf */
-       struct ov511_frame frame[OV511_NUMFRAMES];      
-
-       struct ov511_sbuf sbuf[OV511_NUMSBUF];
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int snap_enabled;       /* Snapshot mode enabled */
-       
-       int bridge;             /* Type of bridge (BRG_*) */
-       int bclass;             /* Class of bridge (BCL_*) */
-       int sensor;             /* Type of image sensor chip (SEN_*) */
-
-       int packet_size;        /* Frame size per isoc desc */
-       int packet_numbering;   /* Is ISO frame numbering enabled? */
-
-       /* Framebuffer/sbuf management */
-       int buf_state;
-       struct mutex buf_lock;
-
-       struct ov51x_decomp_ops *decomp_ops;
-
-       /* Stop streaming while changing picture settings */
-       int stop_during_set;
-
-       int stopped;            /* Streaming is temporarily paused */
-
-       /* Video decoder stuff */
-       int input;              /* Composite, S-VIDEO, etc... */
-       int num_inputs;         /* Number of inputs */
-       int norm;               /* NTSC / PAL / SECAM */
-       int has_decoder;        /* Device has a video decoder */
-       int pal;                /* Device is designed for PAL resolution */
-
-       /* I2C interface */
-       struct mutex i2c_lock;    /* Protect I2C controller regs */
-       unsigned char primary_i2c_slave;  /* I2C write id of sensor */
-
-       /* Control transaction stuff */
-       unsigned char *cbuf;            /* Buffer for payload */
-       struct mutex cbuf_lock;
-};
-
-/* Used to represent a list of values and their respective symbolic names */
-struct symbolic_list {
-       int num;
-       char *name;
-};
-
-#define NOT_DEFINED_STR "Unknown"
-
-/* Returns the name of the matching element in the symbolic_list array. The
- * end of the list must be marked with an element that has a NULL name.
- */
-static inline char * 
-symbolic(struct symbolic_list list[], int num)
-{
-       int i;
-
-       for (i = 0; list[i].name != NULL; i++)
-                       if (list[i].num == num)
-                               return (list[i].name);
-
-       return (NOT_DEFINED_STR);
-}
-
-/* Compression stuff */
-
-#define OV511_QUANTABLESIZE    64
-#define OV518_QUANTABLESIZE    32
-
-#define OV511_YQUANTABLE { \
-       0, 1, 1, 2, 2, 3, 3, 4, \
-       1, 1, 1, 2, 2, 3, 4, 4, \
-       1, 1, 2, 2, 3, 4, 4, 4, \
-       2, 2, 2, 3, 4, 4, 4, 4, \
-       2, 2, 3, 4, 4, 5, 5, 5, \
-       3, 3, 4, 4, 5, 5, 5, 5, \
-       3, 4, 4, 4, 5, 5, 5, 5, \
-       4, 4, 4, 4, 5, 5, 5, 5  \
-}
-
-#define OV511_UVQUANTABLE { \
-       0, 2, 2, 3, 4, 4, 4, 4, \
-       2, 2, 2, 4, 4, 4, 4, 4, \
-       2, 2, 3, 4, 4, 4, 4, 4, \
-       3, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4, \
-       4, 4, 4, 4, 4, 4, 4, 4  \
-}
-
-#define OV518_YQUANTABLE { \
-       5, 4, 5, 6, 6, 7, 7, 7, \
-       5, 5, 5, 5, 6, 7, 7, 7, \
-       6, 6, 6, 6, 7, 7, 7, 8, \
-       7, 7, 6, 7, 7, 7, 8, 8  \
-}
-
-#define OV518_UVQUANTABLE { \
-       6, 6, 6, 7, 7, 7, 7, 7, \
-       6, 6, 6, 7, 7, 7, 7, 7, \
-       6, 6, 6, 7, 7, 7, 7, 8, \
-       7, 7, 7, 7, 7, 7, 8, 8  \
-}
-
-#endif
diff --git a/drivers/usb/media/pwc/Makefile b/drivers/usb/media/pwc/Makefile
deleted file mode 100644 (file)
index 2d93a77..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-ifneq ($(KERNELRELEASE),)
-
-pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
-
-obj-$(CONFIG_USB_PWC) += pwc.o
-
-else
-
-KDIR := /lib/modules/$(shell uname -r)/build
-PWD := $(shell pwd)
-
-default:
-       $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
-
-endif
-
-clean:
-       rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c 
-       rm -rf .tmp_versions
-
diff --git a/drivers/usb/media/pwc/philips.txt b/drivers/usb/media/pwc/philips.txt
deleted file mode 100644 (file)
index 04a640d..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-This file contains some additional information for the Philips and OEM webcams.
-E-mail: webcam@smcc.demon.nl                        Last updated: 2004-01-19
-Site: http://www.smcc.demon.nl/webcam/
-
-As of this moment, the following cameras are supported:
- * Philips PCA645
- * Philips PCA646
- * Philips PCVC675
- * Philips PCVC680
- * Philips PCVC690
- * Philips PCVC720/40
- * Philips PCVC730
- * Philips PCVC740
- * Philips PCVC750
- * Askey VC010
- * Creative Labs Webcam 5
- * Creative Labs Webcam Pro Ex
- * Logitech QuickCam 3000 Pro
- * Logitech QuickCam 4000 Pro
- * Logitech QuickCam Notebook Pro
- * Logitech QuickCam Zoom
- * Logitech QuickCam Orbit
- * Logitech QuickCam Sphere
- * Samsung MPC-C10
- * Samsung MPC-C30
- * Sotec Afina Eye
- * AME CU-001
- * Visionite VCS-UM100
- * Visionite VCS-UC300
-
-The main webpage for the Philips driver is at the address above. It contains
-a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin
-contains decompression routines that allow you to use higher image sizes and
-framerates; in addition the webcam uses less bandwidth on the USB bus (handy
-if you want to run more than 1 camera simultaneously). These routines fall
-under a NDA, and may therefor not be distributed as source; however, its use
-is completely optional.
-
-You can build this code either into your kernel, or as a module. I recommend
-the latter, since it makes troubleshooting a lot easier. The built-in
-microphone is supported through the USB Audio class.
-
-When you load the module you can set some default settings for the
-camera; some programs depend on a particular image-size or -format and
-don't know how to set it properly in the driver. The options are:
-
-size
-   Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or
-   'vga', for an image size of resp. 128x96, 160x120, 176x144,
-   320x240, 352x288 and 640x480 (of course, only for those cameras that 
-   support these resolutions).
-
-fps
-   Specifies the desired framerate. Is an integer in the range of 4-30.
-
-fbufs
-   This paramter specifies the number of internal buffers to use for storing 
-   frames from the cam. This will help if the process that reads images from 
-   the cam is a bit slow or momentarely busy. However, on slow machines it 
-   only introduces lag, so choose carefully. The default is 3, which is 
-   reasonable. You can set it between 2 and 5.
-
-mbufs
-   This is an integer between 1 and 10. It will tell the module the number of
-   buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends.
-   The default is 2, which is adequate for most applications (double
-   buffering).
-      
-   Should you experience a lot of 'Dumping frame...' messages during
-   grabbing with a tool that uses mmap(), you might want to increase if. 
-   However, it doesn't really buffer images, it just gives you a bit more
-   slack when your program is behind. But you need a multi-threaded or
-   forked program to really take advantage of these buffers.
-
-   The absolute maximum is 10, but don't set it too high!  Every buffer takes
-   up 460 KB of RAM, so unless you have a lot of memory setting this to
-   something more than 4 is an absolute waste.  This memory is only
-   allocated during open(), so nothing is wasted when the camera is not in
-   use.
-
-power_save
-   When power_save is enabled (set to 1), the module will try to shut down
-   the cam on close() and re-activate on open(). This will save power and
-   turn off the LED. Not all cameras support this though (the 645 and 646
-   don't have power saving at all), and some models don't work either (they
-   will shut down, but never wake up). Consider this experimental. By
-   default this option is disabled.
-
-compression (only useful with the plugin)
-   With this option you can control the compression factor that the camera
-   uses to squeeze the image through the USB bus. You can set the 
-   parameter between 0 and 3:
-     0 = prefer uncompressed images; if the requested mode is not available
-         in an uncompressed format, the driver will silently switch to low
-         compression.
-     1 = low compression.
-     2 = medium compression.
-     3 = high compression.
-      
-   High compression takes less bandwidth of course, but it could also
-   introduce some unwanted artefacts. The default is 2, medium compression.
-   See the FAQ on the website for an overview of which modes require
-   compression.
-
-   The compression parameter does not apply to the 645 and 646 cameras
-   and OEM models derived from those (only a few). Most cams honour this
-   parameter.
-
-leds
-   This settings takes 2 integers, that define the on/off time for the LED
-   (in milliseconds). One of the interesting things that you can do with
-   this is let the LED blink while the camera is in use. This:
-
-     leds=500,500
-      
-   will blink the LED once every second. But with:
-
-     leds=0,0
-
-   the LED never goes on, making it suitable for silent surveillance.
-
-   By default the camera's LED is on solid while in use, and turned off
-   when the camera is not used anymore.
-
-   This parameter works only with the ToUCam range of cameras (720, 730, 740,
-   750) and OEMs. For other cameras this command is silently ignored, and 
-   the LED cannot be controlled.
-
-   Finally: this parameters does not take effect UNTIL the first time you
-   open the camera device. Until then, the LED remains on.
-
-dev_hint
-   A long standing problem with USB devices is their dynamic nature: you
-   never know what device a camera gets assigned; it depends on module load
-   order, the hub configuration, the order in which devices are plugged in,
-   and the phase of the moon (i.e. it can be random). With this option you
-   can give the driver a hint as to what video device node (/dev/videoX) it
-   should use with a specific camera. This is also handy if you have two
-   cameras of the same model.
-
-   A camera is specified by its type (the number from the camera model,
-   like PCA645, PCVC750VC, etc) and optionally the serial number (visible
-   in /proc/bus/usb/devices). A hint consists of a string with the following
-   format:
-
-      [type[.serialnumber]:]node
-      
-   The square brackets mean that both the type and the serialnumber are
-   optional, but a serialnumber cannot be specified without a type (which
-   would be rather pointless). The serialnumber is separated from the type
-   by a '.'; the node number by a ':'.
-   
-   This somewhat cryptic syntax is best explained by a few examples:
-
-     dev_hint=3,5              The first detected cam gets assigned
-                               /dev/video3, the second /dev/video5. Any
-                               other cameras will get the first free 
-                               available slot (see below).
-
-     dev_hint=645:1,680:2      The PCA645 camera will get /dev/video1,
-                               and a PCVC680 /dev/video2.
-                               
-     dev_hint=645.0123:3,645.4567:0    The PCA645 camera with serialnumber 
-                                        0123 goes to /dev/video3, the same
-                                        camera model with the 4567 serial
-                                        gets /dev/video0.
-
-     dev_hint=750:1,4,5,6       The PCVC750 camera will get /dev/video1, the 
-                                next 3 Philips cams will use /dev/video4 
-                                through /dev/video6.
-
-   Some points worth knowing:
-   - Serialnumbers are case sensitive and must be written full, including 
-     leading zeroes (it's treated as a string).
-   - If a device node is already occupied, registration will fail and 
-     the webcam is not available.
-   - You can have up to 64 video devices; be sure to make enough device
-     nodes in /dev if you want to spread the numbers (this does not apply
-     to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
-   - If a camera does not match any dev_hint, it will simply get assigned
-     the first available device node, just as it used to be.
-
-trace
-   In order to better detect problems, it is now possible to turn on a
-   'trace' of some of the calls the module makes; it logs all items in your
-   kernel log at debug level.
-
-   The trace variable is a bitmask; each bit represents a certain feature.
-   If you want to trace something, look up the bit value(s) in the table 
-   below, add the values together and supply that to the trace variable.
-
-   Value  Value   Description                                     Default
-   (dec)  (hex)
-       1    0x1   Module initialization; this will log messages       On
-                  while loading and unloading the module
-
-       2    0x2   probe() and disconnect() traces                     On
-
-       4    0x4   Trace open() and close() calls                      Off
-
-       8    0x8   read(), mmap() and associated ioctl() calls         Off
-
-      16   0x10   Memory allocation of buffers, etc.                  Off
-
-      32   0x20   Showing underflow, overflow and Dumping frame       On
-                  messages
-
-      64   0x40   Show viewport and image sizes                       Off
-
-     128   0x80   PWCX debugging                                      Off
-
-   For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
-   so you would supply trace=12 during insmod or modprobe. If
-   you want to turn the initialization and probing tracing off, set trace=0.
-   The default value for trace is 35 (0x23).
-
-
-
-Example:
-     
-     # modprobe pwc size=cif fps=15 power_save=1
-
-The fbufs, mbufs and trace parameters are global and apply to all connected
-cameras. Each camera has its own set of buffers.
-
-size and fps only specify defaults when you open() the device; this is to
-accommodate some tools that don't set the size. You can change these
-settings after open() with the Video4Linux ioctl() calls. The default of
-defaults is QCIF size at 10 fps.
-
-The compression parameter is semiglobal; it sets the initial compression
-preference for all camera's, but this parameter can be set per camera with
-the VIDIOCPWCSCQUAL ioctl() call.
-
-All parameters are optional.
-
diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c
deleted file mode 100644 (file)
index 0398b81..0000000
+++ /dev/null
@@ -1,1541 +0,0 @@
-/* Driver for Philips webcam
-   Functions that send various control messages to the webcam, including
-   video modes.
-   (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added methods for changing white balance and 
-                          red/green gains
- */
-
-/* Control functions for the cam; brightness, contrast, video mode, etc. */
-
-#ifdef __KERNEL__
-#include <asm/uaccess.h> 
-#endif
-#include <asm/errno.h>
-#include "pwc.h"
-#include "pwc-ioctl.h"
-#include "pwc-uncompress.h"
-#include "pwc-kiara.h"
-#include "pwc-timon.h"
-
-/* Request types: video */
-#define SET_LUM_CTL                    0x01
-#define GET_LUM_CTL                    0x02
-#define SET_CHROM_CTL                  0x03
-#define GET_CHROM_CTL                  0x04
-#define SET_STATUS_CTL                 0x05
-#define GET_STATUS_CTL                 0x06
-#define SET_EP_STREAM_CTL              0x07
-#define GET_EP_STREAM_CTL              0x08
-#define SET_MPT_CTL                    0x0D
-#define GET_MPT_CTL                    0x0E
-
-/* Selectors for the Luminance controls [GS]ET_LUM_CTL */
-#define AGC_MODE_FORMATTER                     0x2000
-#define PRESET_AGC_FORMATTER                   0x2100
-#define SHUTTER_MODE_FORMATTER                 0x2200
-#define PRESET_SHUTTER_FORMATTER               0x2300
-#define PRESET_CONTOUR_FORMATTER               0x2400
-#define AUTO_CONTOUR_FORMATTER                 0x2500
-#define BACK_LIGHT_COMPENSATION_FORMATTER      0x2600
-#define CONTRAST_FORMATTER                     0x2700
-#define DYNAMIC_NOISE_CONTROL_FORMATTER                0x2800
-#define FLICKERLESS_MODE_FORMATTER             0x2900
-#define AE_CONTROL_SPEED                       0x2A00
-#define BRIGHTNESS_FORMATTER                   0x2B00
-#define GAMMA_FORMATTER                                0x2C00
-
-/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */
-#define WB_MODE_FORMATTER                      0x1000
-#define AWB_CONTROL_SPEED_FORMATTER            0x1100
-#define AWB_CONTROL_DELAY_FORMATTER            0x1200
-#define PRESET_MANUAL_RED_GAIN_FORMATTER       0x1300
-#define PRESET_MANUAL_BLUE_GAIN_FORMATTER      0x1400
-#define COLOUR_MODE_FORMATTER                  0x1500
-#define SATURATION_MODE_FORMATTER1             0x1600
-#define SATURATION_MODE_FORMATTER2             0x1700
-
-/* Selectors for the Status controls [GS]ET_STATUS_CTL */
-#define SAVE_USER_DEFAULTS_FORMATTER           0x0200
-#define RESTORE_USER_DEFAULTS_FORMATTER                0x0300
-#define RESTORE_FACTORY_DEFAULTS_FORMATTER     0x0400
-#define READ_AGC_FORMATTER                     0x0500
-#define READ_SHUTTER_FORMATTER                 0x0600
-#define READ_RED_GAIN_FORMATTER                        0x0700
-#define READ_BLUE_GAIN_FORMATTER               0x0800
-#define SENSOR_TYPE_FORMATTER1                 0x0C00
-#define READ_RAW_Y_MEAN_FORMATTER              0x3100
-#define SET_POWER_SAVE_MODE_FORMATTER          0x3200
-#define MIRROR_IMAGE_FORMATTER                 0x3300
-#define LED_FORMATTER                          0x3400
-#define SENSOR_TYPE_FORMATTER2                 0x3700
-
-/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
-#define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
-
-/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */
-#define PT_RELATIVE_CONTROL_FORMATTER          0x01
-#define PT_RESET_CONTROL_FORMATTER             0x02
-#define PT_STATUS_FORMATTER                    0x03
-
-static const char *size2name[PSZ_MAX] =
-{
-       "subQCIF",
-       "QSIF",
-       "QCIF",
-       "SIF",
-       "CIF",
-       "VGA",
-};  
-
-/********/
-
-/* Entries for the Nala (645/646) camera; the Nala doesn't have compression 
-   preferences, so you either get compressed or non-compressed streams.
-   
-   An alternate value of 0 means this mode is not available at all.
- */
-
-struct Nala_table_entry {
-       char alternate;                 /* USB alternate setting */
-       int compressed;                 /* Compressed yes/no */
-
-       unsigned char mode[3];          /* precomputed mode table */
-};
-
-static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
-{
-#include "pwc-nala.h"
-};
-
-
-/****************************************************************************/
-
-
-#define SendControlMsg(request, value, buflen) \
-       usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
-               request, \
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
-               value, \
-               pdev->vcinterface, \
-               &buf, buflen, 500)
-
-#define RecvControlMsg(request, value, buflen) \
-       usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
-               request, \
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
-               value, \
-               pdev->vcinterface, \
-               &buf, buflen, 500)
-
-
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
-       int i;
-       unsigned char *s;
-       char buf[100], *d;
-
-       s = (unsigned char *)p;
-       d = buf;
-       *d = '\0';
-       Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
-       for (i = 0; i < len; i++) {
-               d += sprintf(d, "%02X ", *s++);
-               if ((i & 0xF) == 0xF) {
-                       Debug("%s\n", buf);
-                       d = buf;
-                       *d = '\0';
-               }
-       }
-       if ((i & 0xF) != 0)
-               Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
-{
-       return usb_control_msg(udev,
-               usb_sndctrlpipe(udev, 0),
-               SET_EP_STREAM_CTL,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               VIDEO_OUTPUT_CONTROL_FORMATTER,
-               index,
-               buf, buflen, 1000);
-}
-
-
-
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
-{
-       unsigned char buf[3];
-       int ret, fps;
-       struct Nala_table_entry *pEntry;
-       int frames2frames[31] =
-       { /* closest match of framerate */
-          0,  0,  0,  0,  4,  /*  0-4  */
-          5,  5,  7,  7, 10,  /*  5-9  */
-          10, 10, 12, 12, 15,  /* 10-14 */
-          15, 15, 15, 20, 20,  /* 15-19 */
-          20, 20, 20, 24, 24,  /* 20-24 */
-          24, 24, 24, 24, 24,  /* 25-29 */
-          24                   /* 30    */
-       };
-       int frames2table[31] = 
-       { 0, 0, 0, 0, 0, /*  0-4  */
-         1, 1, 1, 2, 2, /*  5-9  */
-         3, 3, 4, 4, 4, /* 10-14 */
-         5, 5, 5, 5, 5, /* 15-19 */
-         6, 6, 6, 6, 7, /* 20-24 */
-         7, 7, 7, 7, 7, /* 25-29 */
-         7              /* 30    */
-       };
-       
-       if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
-               return -EINVAL;
-       frames = frames2frames[frames];
-       fps = frames2table[frames];
-       pEntry = &Nala_table[size][fps];
-       if (pEntry->alternate == 0)
-               return -EINVAL;
-
-       if (pEntry->compressed)
-               return -ENOENT; /* Not supported. */
-
-       memcpy(buf, pEntry->mode, 3);   
-       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
-       if (ret < 0) {
-               Debug("Failed to send video command... %d\n", ret);
-               return ret;
-       }
-       if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
-        {
-          switch(pdev->type) {
-            case 645:
-            case 646:
-/*            pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-              break;
-
-            case 675:
-            case 680:
-            case 690:
-            case 720:
-            case 730:
-            case 740:
-            case 750:
-/*            pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-              break;
-          }
-       }
-       pdev->cmd_len = 3;
-       memcpy(pdev->cmd_buf, buf, 3);
-
-       /* Set various parameters */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->valternate = pEntry->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
-       if (pEntry->compressed) {
-               if (pdev->release < 5) { /* 4 fold compression */
-                       pdev->vbandlength = 528;
-                       pdev->frame_size /= 4;
-               }
-               else {
-                       pdev->vbandlength = 704;
-                       pdev->frame_size /= 3;
-               }
-       }
-       else
-               pdev->vbandlength = 0;
-       return 0;
-}
-
-
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
-{
-       unsigned char buf[13];
-       const struct Timon_table_entry *pChoose;
-       int ret, fps;
-
-       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
-               return -EINVAL;
-       if (size == PSZ_VGA && frames > 15)
-               return -EINVAL;
-       fps = (frames / 5) - 1;
-
-       /* Find a supported framerate with progressively higher compression ratios
-          if the preferred ratio is not available.
-       */
-       pChoose = NULL;
-       while (compression <= 3) {
-          pChoose = &Timon_table[size][fps][compression];
-          if (pChoose->alternate != 0)
-            break;
-          compression++;
-       }
-       if (pChoose == NULL || pChoose->alternate == 0)
-               return -ENOENT; /* Not supported. */
-
-       memcpy(buf, pChoose->mode, 13);
-       if (snapshot)
-               buf[0] |= 0x80;
-       ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
-       if (ret < 0)
-               return ret;
-
-/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-          pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-
-       pdev->cmd_len = 13;
-       memcpy(pdev->cmd_buf, buf, 13);
-
-       /* Set various parameters */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->vsnapshot = snapshot;
-       pdev->valternate = pChoose->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->vbandlength = pChoose->bandlength;
-       if (pChoose->bandlength > 0)
-               pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
-       else
-               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
-       return 0;
-}
-
-
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
-{
-       const struct Kiara_table_entry *pChoose = NULL;
-       int fps, ret;
-       unsigned char buf[12];
-       struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
-
-       if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
-               return -EINVAL;
-       if (size == PSZ_VGA && frames > 15)
-               return -EINVAL;
-       fps = (frames / 5) - 1;
-
-       /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-       if (size == PSZ_VGA && frames == 5 && snapshot)
-       {
-               /* Only available in case the raw palette is selected or 
-                  we have the decompressor available. This mode is 
-                  only available in compressed form 
-               */
-               if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               {
-                       Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
-                       pChoose = &RawEntry;
-               }
-               else
-               {
-                       Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
-               }
-       }
-       else
-       {
-               /* Find a supported framerate with progressively higher compression ratios
-                  if the preferred ratio is not available.
-                   Skip this step when using RAW modes.
-               */
-               while (compression <= 3) {
-                       pChoose = &Kiara_table[size][fps][compression];
-                       if (pChoose->alternate != 0)
-                               break;
-                       compression++;
-               }
-       }
-       if (pChoose == NULL || pChoose->alternate == 0)
-               return -ENOENT; /* Not supported. */
-
-       Debug("Using alternate setting %d.\n", pChoose->alternate);
-       
-       /* usb_control_msg won't take staticly allocated arrays as argument?? */
-       memcpy(buf, pChoose->mode, 12);
-       if (snapshot)
-               buf[0] |= 0x80;
-
-       /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
-       ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12);
-       if (ret < 0)
-               return ret;
-
-/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-         pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-
-       pdev->cmd_len = 12;
-       memcpy(pdev->cmd_buf, buf, 12);
-       /* All set and go */
-       pdev->vframes = frames;
-       pdev->vsize = size;
-       pdev->vsnapshot = snapshot;
-       pdev->valternate = pChoose->alternate;
-       pdev->image = pwc_image_sizes[size];
-       pdev->vbandlength = pChoose->bandlength;
-       if (pdev->vbandlength > 0)
-               pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
-       else
-               pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
-       return 0;
-}
-
-
-
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
-       int i, factor = 0, filler = 0;
-
-       /* for PALETTE_YUV420P */
-       switch(pdev->vpalette)
-       {
-       case VIDEO_PALETTE_YUV420P:
-               factor = 6;
-               filler = 128;
-               break;
-       case VIDEO_PALETTE_RAW:
-               factor = 6; /* can be uncompressed YUV420P */
-               filler = 0;
-               break;
-       }
-
-       /* Set sizes in bytes */
-       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
-       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
-
-       /* Align offset, or you'll get some very weird results in
-          YUV420 mode... x must be multiple of 4 (to get the Y's in
-          place), and y even (or you'll mixup U & V). This is less of a
-          problem for YUV420P.
-        */
-       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
-       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
-       /* Fill buffers with gray or black */
-       for (i = 0; i < MAX_IMAGES; i++) {
-               if (pdev->image_ptr[i] != NULL)
-                       memset(pdev->image_ptr[i], filler, pdev->view.size);
-       }
-}
-
-
-
-/**
-   @pdev: device structure
-   @width: viewport width
-   @height: viewport height
-   @frame: framerate, in fps
-   @compression: preferred compression ratio
-   @snapshot: snapshot mode or streaming
- */
-int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
-{
-        int ret, size;
-
-        Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
-       size = pwc_decode_size(pdev, width, height);
-       if (size < 0) {
-               Debug("Could not find suitable size.\n");
-               return -ERANGE;
-       }
-       Debug("decode_size = %d.\n", size);
-
-        ret = -EINVAL;
-       switch(pdev->type) {
-       case 645:
-       case 646:
-               ret = set_video_mode_Nala(pdev, size, frames);
-               break;
-
-       case 675:
-       case 680:
-       case 690:
-               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
-               break;
-       
-       case 720:
-       case 730:
-       case 740:
-       case 750:
-               ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-               break;
-       }
-       if (ret < 0) {
-               if (ret == -ENOENT)
-                       Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
-               else {
-                       Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-               }
-               return ret;
-       }
-       pdev->view.x = width;
-       pdev->view.y = height;
-       pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
-       pwc_set_image_buffer_size(pdev);
-       Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
-       return 0;
-}
-
-
-/* BRIGHTNESS */
-
-int pwc_get_brightness(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-
-       ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);     
-       if (ret < 0)
-               return ret;
-       return buf << 9;
-}
-
-int pwc_set_brightness(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 9) & 0x7f;
-       return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
-}
-
-/* CONTRAST */
-
-int pwc_get_contrast(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-
-       ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       return buf << 10;
-}
-
-int pwc_set_contrast(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 10) & 0x3f;
-       return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1);
-}
-
-/* GAMMA */
-
-int pwc_get_gamma(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       return buf << 11;
-}
-
-int pwc_set_gamma(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       buf = (value >> 11) & 0x1f;
-       return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1);
-}
-
-
-/* SATURATION */
-
-int pwc_get_saturation(struct pwc_device *pdev)
-{
-       char buf;
-       int ret;
-
-       if (pdev->type < 675)
-               return -1;
-       ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
-       if (ret < 0)
-               return ret;
-       return 32768 + buf * 327;
-}
-
-int pwc_set_saturation(struct pwc_device *pdev, int value)
-{
-       char buf;
-
-       if (pdev->type < 675)
-               return -EINVAL;
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* saturation ranges from -100 to +100 */
-       buf = (value - 32768) / 327;
-       return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
-}
-
-/* AGC */
-
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
-{
-       char buf;
-       int ret;
-       
-       if (mode)
-               buf = 0x0; /* auto */
-       else
-               buf = 0xff; /* fixed */
-
-       ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1);
-       
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-               buf = (value >> 10) & 0x3F;
-               ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
-       }
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-
-       if (buf != 0) { /* fixed */
-               ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1);
-               if (ret < 0)
-                       return ret;
-               if (buf > 0x3F)
-                       buf = 0x3F;
-               *value = (buf << 10);           
-       }
-       else { /* auto */
-               ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1);
-               if (ret < 0)
-                       return ret;
-               /* Gah... this value ranges from 0x00 ... 0x9F */
-               if (buf > 0x9F)
-                       buf = 0x9F;
-               *value = -(48 + buf * 409);
-       }
-
-       return 0;
-}
-
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
-{
-       char buf[2];
-       int speed, ret;
-
-
-       if (mode)
-               buf[0] = 0x0;   /* auto */
-       else
-               buf[0] = 0xff; /* fixed */
-       
-       ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1);
-
-       if (!mode && ret >= 0) {
-               if (value < 0)
-                       value = 0;
-               if (value > 0xffff)
-                       value = 0xffff;
-               switch(pdev->type) {
-               case 675:
-               case 680:
-               case 690:
-                       /* speed ranges from 0x0 to 0x290 (656) */
-                       speed = (value / 100);
-                       buf[1] = speed >> 8;
-                       buf[0] = speed & 0xff;
-                       break;
-               case 720:
-               case 730:
-               case 740:
-               case 750:
-                       /* speed seems to range from 0x0 to 0xff */
-                       buf[1] = 0;
-                       buf[0] = value >> 8;
-                       break;
-               }
-
-               ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
-       }
-       return ret;
-}      
-
-
-/* POWER */
-
-int pwc_camera_power(struct pwc_device *pdev, int power)
-{
-       char buf;
-
-       if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
-               return 0;       /* Not supported by Nala or Timon < release 6 */
-
-       if (power)
-               buf = 0x00; /* active */
-       else
-               buf = 0xFF; /* power save */
-       return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1);
-}
-
-
-
-/* private calls */
-
-static inline int pwc_restore_user(struct pwc_device *pdev)
-{
-       char buf; /* dummy */
-       return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
-}
-
-static inline int pwc_save_user(struct pwc_device *pdev)
-{
-       char buf; /* dummy */
-       return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
-}
-
-static inline int pwc_restore_factory(struct pwc_device *pdev)
-{
-       char buf; /* dummy */
-       return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
-}
-
- /* ************************************************* */
- /* Patch by Alvarado: (not in the original version   */
-
- /*
-  * the camera recognizes modes from 0 to 4:
-  *
-  * 00: indoor (incandescant lighting)
-  * 01: outdoor (sunlight)
-  * 02: fluorescent lighting
-  * 03: manual
-  * 04: auto
-  */ 
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
-{
-       char buf;
-       int ret;
-       
-       if (mode < 0)
-           mode = 0;
-       
-       if (mode > 4)
-           mode = 4;
-       
-       buf = mode & 0x07; /* just the lowest three bits */
-       
-       ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1);
-       
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static inline int pwc_get_awb(struct pwc_device *pdev)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1);
-
-       if (ret < 0) 
-               return ret;
-       return buf;
-}
-
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
-{
-        unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
-}
-
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
-{
-       unsigned char buf;
-
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* only the msb is considered */
-       buf = value >> 8;
-       return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
-}
-
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
-       if (ret < 0)
-           return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-/* The following two functions are different, since they only read the
-   internal red/blue gains, which may be different from the manual 
-   gains set or read above.
- */   
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf << 8;
-       return 0;
-}
-
-
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
-{
-       unsigned char buf;
-       
-       /* useful range is 0x01..0x20 */
-       buf = speed / 0x7f0;
-       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
-}
-
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf * 0x7f0;
-       return 0;
-}
-
-
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
-{
-       unsigned char buf;
-       
-       /* useful range is 0x01..0x3F */
-       buf = (delay >> 10);
-       return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
-}
-
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *value = buf << 10;
-       return 0;
-}
-
-
-int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
-{
-       unsigned char buf[2];
-
-       if (pdev->type < 730)
-               return 0;
-       on_value /= 100;
-       off_value /= 100;
-       if (on_value < 0)
-               on_value = 0;
-       if (on_value > 0xff)
-               on_value = 0xff;
-       if (off_value < 0)
-               off_value = 0;
-       if (off_value > 0xff)
-               off_value = 0xff;
-
-       buf[0] = on_value;
-       buf[1] = off_value;
-
-       return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
-}
-
-static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
-{
-       unsigned char buf[2];
-       int ret;
-       
-       if (pdev->type < 730) {
-               *on_value = -1;
-               *off_value = -1;
-               return 0;
-       }
-
-       ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
-       if (ret < 0)
-               return ret;
-       *on_value = buf[0] * 100;
-       *off_value = buf[1] * 100;
-       return 0;
-}
-
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
-{
-       unsigned char buf;
-       int ret;
-       
-       if (contour < 0)
-               buf = 0xff; /* auto contour on */
-       else
-               buf = 0x0; /* auto contour off */
-       ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       
-       if (contour < 0)
-               return 0;
-       if (contour > 0xffff)
-               contour = 0xffff;
-       
-       buf = (contour >> 10); /* contour preset is [0..3f] */
-       ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
-       if (ret < 0)    
-               return ret;     
-       return 0;
-}
-
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
-{
-       unsigned char buf;
-       int ret;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-
-       if (buf == 0) {
-               /* auto mode off, query current preset value */
-               ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1);
-               if (ret < 0)    
-                       return ret;
-               *contour = buf << 10;
-       }
-       else
-               *contour = -1;
-       return 0;
-}
-
-
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
-{
-       unsigned char buf;
-       
-       if (backlight)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
-}
-
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
-{
-       int ret;
-       unsigned char buf;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *backlight = buf;
-       return 0;
-}
-
-
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
-{
-       unsigned char buf;
-       
-       if (flicker)
-               buf = 0xff;
-       else
-               buf = 0x0;
-       return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
-}
-
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
-{
-       int ret;
-       unsigned char buf;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *flicker = buf;
-       return 0;
-}
-
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
-{
-       unsigned char buf;
-
-       if (noise < 0)
-               noise = 0;
-       if (noise > 3)
-               noise = 3;
-       buf = noise;
-       return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
-}
-
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
-{
-       int ret;
-       unsigned char buf;
-       
-       ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
-       if (ret < 0)
-               return ret;
-       *noise = buf;
-       return 0;
-}
-
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
-{
-       unsigned char buf;
-       
-       buf = flags & 0x03; // only lower two bits are currently used
-       return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
-}
-
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
-{
-       unsigned char buf[4];
-       
-       /* set new relative angle; angles are expressed in degrees * 100,
-          but cam as .5 degree resolution, hence divide by 200. Also
-          the angle must be multiplied by 64 before it's send to
-          the cam (??)
-        */
-       pan  =  64 * pan  / 100;
-       tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
-       buf[0] = pan & 0xFF;
-       buf[1] = (pan >> 8) & 0xFF;
-       buf[2] = tilt & 0xFF;
-       buf[3] = (tilt >> 8) & 0xFF;
-       return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
-}
-
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
-{
-       int ret;
-       unsigned char buf[5];
-       
-       ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5);
-       if (ret < 0)
-               return ret;
-       status->status = buf[0] & 0x7; // 3 bits are used for reporting
-       status->time_pan = (buf[1] << 8) + buf[2];
-       status->time_tilt = (buf[3] << 8) + buf[4];
-       return 0;
-}
-
-
-int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
-{
-       unsigned char buf;
-       int ret = -1, request;
-       
-       if (pdev->type < 675)
-               request = SENSOR_TYPE_FORMATTER1;
-       else if (pdev->type < 730)
-               return -1; /* The Vesta series doesn't have this call */
-       else
-               request = SENSOR_TYPE_FORMATTER2;
-       
-       ret = RecvControlMsg(GET_STATUS_CTL, request, 1);
-       if (ret < 0)
-               return ret;
-       if (pdev->type < 675)
-               *sensor = buf | 0x100;
-       else
-               *sensor = buf;
-       return 0;
-}
-
-
- /* End of Add-Ons                                    */
- /* ************************************************* */
-
-
-int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
-{
-       int ret = 0;
-
-       switch(cmd) {
-       case VIDIOCPWCRUSER:
-       {
-               if (pwc_restore_user(pdev))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCSUSER:
-       {
-               if (pwc_save_user(pdev))
-                       ret = -EINVAL;
-               break;
-       }
-               
-       case VIDIOCPWCFACTORY:
-       {
-               if (pwc_restore_factory(pdev))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCSCQUAL:
-       {       
-               int *qual = arg;
-
-               if (*qual < 0 || *qual > 3)
-                       ret = -EINVAL;
-               else
-                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
-               if (ret >= 0)
-                       pdev->vcompression = *qual;
-               break;
-       }
-       
-       case VIDIOCPWCGCQUAL:
-       {
-               int *qual = arg;
-               *qual = pdev->vcompression;
-               break;
-       }
-       
-       case VIDIOCPWCPROBE:
-       {
-               struct pwc_probe *probe = arg;
-               strcpy(probe->name, pdev->vdev->name);
-               probe->type = pdev->type;
-               break;
-       }
-
-       case VIDIOCPWCGSERIAL:
-       {
-               struct pwc_serial *serial = arg;
-               strcpy(serial->serial, pdev->serial);
-               break;
-       }
-
-       case VIDIOCPWCSAGC:
-       {
-               int *agc = arg;
-               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCGAGC:
-       {
-               int *agc = arg;
-               
-               if (pwc_get_agc(pdev, agc))
-                       ret = -EINVAL;
-               break;
-       }
-       
-       case VIDIOCPWCSSHUTTER:
-       {
-               int *shutter_speed = arg;
-               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
-               break;
-       }
-       
-        case VIDIOCPWCSAWB:
-       {
-               struct pwc_whitebalance *wb = arg;
-               
-               ret = pwc_set_awb(pdev, wb->mode);
-               if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
-                       pwc_set_red_gain(pdev, wb->manual_red);
-                       pwc_set_blue_gain(pdev, wb->manual_blue);
-               }
-               break;
-       }
-
-       case VIDIOCPWCGAWB:
-       {
-               struct pwc_whitebalance *wb = arg;
-
-               memset(wb, 0, sizeof(struct pwc_whitebalance));
-               wb->mode = pwc_get_awb(pdev);
-               if (wb->mode < 0)
-                       ret = -EINVAL;
-               else {
-                       if (wb->mode == PWC_WB_MANUAL) {
-                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
-                               if (ret < 0)
-                                       break;
-                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-                       if (wb->mode == PWC_WB_AUTO) {
-                               ret = pwc_read_red_gain(pdev, &wb->read_red);
-                               if (ret < 0)
-                                       break;
-                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
-                               if (ret < 0)
-                                       break;
-                       }
-               }
-               break;
-       }
-       
-       case VIDIOCPWCSAWBSPEED:
-       {
-               struct pwc_wb_speed *wbs = arg;
-               
-               if (wbs->control_speed > 0) {
-                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
-               }
-               if (wbs->control_delay > 0) {
-                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
-               }
-               break;
-       }
-       
-       case VIDIOCPWCGAWBSPEED:
-       {
-               struct pwc_wb_speed *wbs = arg;
-               
-               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
-               if (ret < 0)
-                       break;
-               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
-               if (ret < 0)
-                       break;
-               break;
-       }
-
-        case VIDIOCPWCSLED:
-       {
-               struct pwc_leds *leds = arg;
-               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
-               break;
-       }
-
-
-       case VIDIOCPWCGLED:
-       {
-               struct pwc_leds *leds = arg;
-               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
-               break;
-       }
-
-       case VIDIOCPWCSCONTOUR:
-       {
-               int *contour = arg;
-               ret = pwc_set_contour(pdev, *contour);
-               break;
-       }
-                       
-       case VIDIOCPWCGCONTOUR:
-       {
-               int *contour = arg;
-               ret = pwc_get_contour(pdev, contour);
-               break;
-       }
-       
-       case VIDIOCPWCSBACKLIGHT:
-       {
-               int *backlight = arg;
-               ret = pwc_set_backlight(pdev, *backlight);
-               break;
-       }
-
-       case VIDIOCPWCGBACKLIGHT:
-       {
-               int *backlight = arg;
-               ret = pwc_get_backlight(pdev, backlight);
-               break;
-       }
-       
-       case VIDIOCPWCSFLICKER:
-       {
-               int *flicker = arg;
-               ret = pwc_set_flicker(pdev, *flicker);
-               break;
-       }
-
-       case VIDIOCPWCGFLICKER:
-       {
-               int *flicker = arg;
-               ret = pwc_get_flicker(pdev, flicker);
-               break;
-       }
-       
-       case VIDIOCPWCSDYNNOISE:
-       {
-               int *dynnoise = arg;
-               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
-               break;
-       }
-       
-       case VIDIOCPWCGDYNNOISE:
-       {
-               int *dynnoise = arg;
-               ret = pwc_get_dynamic_noise(pdev, dynnoise);
-               break;
-       }
-
-       case VIDIOCPWCGREALSIZE:
-       {
-               struct pwc_imagesize *size = arg;
-               size->width = pdev->image.x;
-               size->height = pdev->image.y;
-               break;
-       }
-       
-       case VIDIOCPWCMPTRESET:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       int *flags = arg;
-
-                       ret = pwc_mpt_reset(pdev, *flags);
-                       if (ret >= 0)
-                       {
-                               pdev->pan_angle = 0;
-                               pdev->tilt_angle = 0;
-                       }
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;          
-       }
-       
-       case VIDIOCPWCMPTGRANGE:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_range *range = arg;
-                       *range = pdev->angle_range;
-               }
-               else
-               {       
-                       ret = -ENXIO;
-               }
-               break;
-       }
-       
-       case VIDIOCPWCMPTSANGLE:
-       {
-               int new_pan, new_tilt;
-               
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_angles *angles = arg;
-                       /* The camera can only set relative angles, so
-                          do some calculations when getting an absolute angle .
-                        */
-                       if (angles->absolute)
-                       {
-                               new_pan  = angles->pan;
-                               new_tilt = angles->tilt;
-                       }
-                       else
-                       {
-                               new_pan  = pdev->pan_angle  + angles->pan;
-                               new_tilt = pdev->tilt_angle + angles->tilt;
-                       }
-                       /* check absolute ranges */
-                       if (new_pan  < pdev->angle_range.pan_min  ||
-                           new_pan  > pdev->angle_range.pan_max  ||
-                           new_tilt < pdev->angle_range.tilt_min ||
-                           new_tilt > pdev->angle_range.tilt_max)
-                       {
-                               ret = -ERANGE;
-                       }
-                       else
-                       {
-                               /* go to relative range, check again */
-                               new_pan  -= pdev->pan_angle;
-                               new_tilt -= pdev->tilt_angle;
-                               /* angles are specified in degrees * 100, thus the limit = 36000 */
-                               if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
-                                       ret = -ERANGE;
-                       }
-                       if (ret == 0) /* no errors so far */
-                       {
-                               ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
-                               if (ret >= 0)
-                               {
-                                       pdev->pan_angle  += new_pan;
-                                       pdev->tilt_angle += new_tilt;
-                               }
-                               if (ret == -EPIPE) /* stall -> out of range */
-                                       ret = -ERANGE;                          
-                       }
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCMPTGANGLE:
-       {
-               
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_angles *angles = arg;
-
-                       angles->absolute = 1;
-                       angles->pan  = pdev->pan_angle;
-                       angles->tilt = pdev->tilt_angle;
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-       case VIDIOCPWCMPTSTATUS:
-       {
-               if (pdev->features & FEATURE_MOTOR_PANTILT)
-               {
-                       struct pwc_mpt_status *status = arg;
-                       ret = pwc_mpt_get_status(pdev, status);
-               }
-               else
-               {
-                       ret = -ENXIO;
-               }
-               break;
-       }
-
-       case VIDIOCPWCGVIDCMD:
-       {
-               struct pwc_video_command *cmd = arg;
-               
-                cmd->type = pdev->type;
-               cmd->release = pdev->release;
-               cmd->command_len = pdev->cmd_len;
-               memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
-               cmd->bandlength = pdev->vbandlength;
-               cmd->frame_size = pdev->frame_size;
-               break;
-       }
-       /*
-       case VIDIOCPWCGVIDTABLE:
-       {
-               struct pwc_table_init_buffer *table = arg;
-               table->len = pdev->cmd_len;
-               memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
-               break;
-       }
-       */
-
-       default:
-               ret = -ENOIOCTLCMD;
-               break;
-       }
-       
-       if (ret > 0)
-               return 0;
-       return ret;
-}
-
-
-
diff --git a/drivers/usb/media/pwc/pwc-if.c b/drivers/usb/media/pwc/pwc-if.c
deleted file mode 100644 (file)
index 90eb260..0000000
+++ /dev/null
@@ -1,2205 +0,0 @@
-/* Linux driver for Philips webcam
-   USB and Video4Linux interface part.
-   (C) 1999-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-*/
-
-/*  
-   This code forms the interface between the USB layers and the Philips
-   specific stuff. Some adanved stuff of the driver falls under an
-   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
-   is thus not distributed in source form. The binary pwcx.o module 
-   contains the code that falls under the NDA.
-   
-   In case you're wondering: 'pwc' stands for "Philips WebCam", but 
-   I really didn't want to type 'philips_web_cam' every time (I'm lazy as
-   any Linux kernel hacker, but I don't like uncomprehensible abbreviations
-   without explanation).
-   
-   Oh yes, convention: to disctinguish between all the various pointers to
-   device-structures, I use these names for the pointer variables:
-   udev: struct usb_device *
-   vdev: struct video_device *
-   pdev: struct pwc_devive *
-*/
-
-/* Contributors:
-   - Alvarado: adding whitebalance code
-   - Alistar Moire: QuickCam 3000 Pro device/product ID
-   - Tony Hoyle: Creative Labs Webcam 5 device/product ID
-   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
-   - Jk Fang: Sotec Afina Eye ID
-   - Xavier Roche: QuickCam Pro 4000 ID
-   - Jens Knudsen: QuickCam Zoom ID
-   - J. Debert: QuickCam for Notebooks ID
-*/
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <asm/io.h>
-
-#include "pwc.h"
-#include "pwc-ioctl.h"
-#include "pwc-kiara.h"
-#include "pwc-timon.h"
-#include "pwc-uncompress.h"
-
-/* Function prototypes and driver templates */
-
-/* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
-       { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
-       { USB_DEVICE(0x0471, 0x0303) },
-       { USB_DEVICE(0x0471, 0x0304) },
-       { USB_DEVICE(0x0471, 0x0307) },
-       { USB_DEVICE(0x0471, 0x0308) },
-       { USB_DEVICE(0x0471, 0x030C) },
-       { USB_DEVICE(0x0471, 0x0310) },
-       { USB_DEVICE(0x0471, 0x0311) },
-       { USB_DEVICE(0x0471, 0x0312) },
-       { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
-       { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
-       { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
-       { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
-       { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
-       { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
-       { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
-       { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
-       { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
-       { USB_DEVICE(0x055D, 0x9001) },
-       { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
-       { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
-       { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
-       { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
-       { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
-       { USB_DEVICE(0x0d81, 0x1900) },
-       { }
-};
-MODULE_DEVICE_TABLE(usb, pwc_device_table);
-
-static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
-static void usb_pwc_disconnect(struct usb_interface *intf);
-
-static struct usb_driver pwc_driver = {
-       .name =                 "Philips webcam",       /* name */
-       .id_table =             pwc_device_table,
-       .probe =                usb_pwc_probe,          /* probe() */
-       .disconnect =           usb_pwc_disconnect,     /* disconnect() */
-};
-
-#define MAX_DEV_HINTS  20
-#define MAX_ISOC_ERRORS        20
-
-static int default_size = PSZ_QCIF;
-static int default_fps = 10;
-static int default_fbufs = 3;   /* Default number of frame buffers */
-static int default_mbufs = 2;  /* Default number of mmap() buffers */
-       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
-static int power_save = 0;
-static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
-static struct {
-       int type;
-       char serial_number[30];
-       int device_node;
-       struct pwc_device *pdev;
-} device_hint[MAX_DEV_HINTS];
-
-/***/
-
-static int pwc_video_open(struct inode *inode, struct file *file);
-static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
-                         size_t count, loff_t *ppos);
-static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
-static int  pwc_video_ioctl(struct inode *inode, struct file *file,
-                           unsigned int ioctlnr, unsigned long arg);
-static int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
-
-static struct file_operations pwc_fops = {
-       .owner =        THIS_MODULE,
-       .open =         pwc_video_open,
-       .release =      pwc_video_close,
-       .read =         pwc_video_read,
-       .poll =         pwc_video_poll,
-       .mmap =         pwc_video_mmap,
-       .ioctl =        pwc_video_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-static struct video_device pwc_template = {
-       .owner =        THIS_MODULE,
-       .name =         "Philips Webcam",       /* Filled in later */
-       .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_PWC,
-       .release =      video_device_release,
-       .fops =         &pwc_fops,
-       .minor =        -1,
-};
-
-/***************************************************************************/
-
-/* Okay, this is some magic that I worked out and the reasoning behind it...
-
-   The biggest problem with any USB device is of course: "what to do 
-   when the user unplugs the device while it is in use by an application?"
-   We have several options:
-   1) Curse them with the 7 plagues when they do (requires divine intervention)
-   2) Tell them not to (won't work: they'll do it anyway)
-   3) Oops the kernel (this will have a negative effect on a user's uptime)
-   4) Do something sensible.
-   
-   Of course, we go for option 4.
-
-   It happens that this device will be linked to two times, once from
-   usb_device and once from the video_device in their respective 'private'
-   pointers. This is done when the device is probed() and all initialization
-   succeeded. The pwc_device struct links back to both structures.
-
-   When a device is unplugged while in use it will be removed from the 
-   list of known USB devices; I also de-register it as a V4L device, but 
-   unfortunately I can't free the memory since the struct is still in use
-   by the file descriptor. This free-ing is then deferend until the first
-   opportunity. Crude, but it works.
-   
-   A small 'advantage' is that if a user unplugs the cam and plugs it back
-   in, it should get assigned the same video device minor, but unfortunately
-   it's non-trivial to re-link the cam back to the video device... (that 
-   would surely be magic! :))
-*/
-
-/***************************************************************************/
-/* Private functions */
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr) 
-{
-        unsigned long kva, ret;
-
-       kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-       kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-       ret = __pa(kva);
-        return ret;
-}
-
-static void * rvmalloc(unsigned long size)
-{
-       void * mem;
-       unsigned long adr;
-
-       size=PAGE_ALIGN(size);
-        mem=vmalloc_32(size);
-       if (mem) 
-       {
-               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-               adr=(unsigned long) mem;
-               while (size > 0) 
-                {
-                       SetPageReserved(vmalloc_to_page((void *)adr));
-                       adr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-       }
-       return mem;
-}
-
-static void rvfree(void * mem, unsigned long size)
-{
-        unsigned long adr;
-
-       if (mem) 
-       {
-               adr=(unsigned long) mem;
-               while ((long) size > 0) 
-                {
-                       ClearPageReserved(vmalloc_to_page((void *)adr));
-                       adr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-               vfree(mem);
-       }
-}
-
-
-
-
-static int pwc_allocate_buffers(struct pwc_device *pdev)
-{
-       int i;
-       void *kbuf;
-
-       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
-
-       if (pdev == NULL)
-               return -ENXIO;
-               
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("allocate_buffers(): magic failed.\n");
-               return -ENXIO;
-       }
-#endif 
-       /* Allocate Isochronous pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
-                       if (kbuf == NULL) {
-                               Err("Failed to allocate iso buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
-                       pdev->sbuf[i].data = kbuf;
-                       memset(kbuf, 0, ISO_BUFFER_SIZE);
-               }
-       }
-
-       /* Allocate frame buffer structure */
-       if (pdev->fbuf == NULL) {
-               kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
-               if (kbuf == NULL) {
-                       Err("Failed to allocate frame buffer structure.\n");
-                       return -ENOMEM;
-               }
-               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
-               pdev->fbuf = kbuf;
-               memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
-       }
-       /* create frame buffers, and make circular ring */
-       for (i = 0; i < default_fbufs; i++) {
-               if (pdev->fbuf[i].data == NULL) {
-                       kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
-                       if (kbuf == NULL) {
-                               Err("Failed to allocate frame buffer %d.\n", i);
-                               return -ENOMEM;
-                       }
-                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
-                       pdev->fbuf[i].data = kbuf;
-                       memset(kbuf, 128, PWC_FRAME_SIZE);
-               }
-       }
-       
-       /* Allocate decompressor table space */
-       kbuf = NULL;
-       switch (pdev->type)
-        {
-         case 675:
-         case 680:
-         case 690:
-         case 720:
-         case 730:
-         case 740:
-         case 750:
-#if 0    
-           Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
-           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);       /* Timon & Kiara */
-           break;
-         case 645:
-         case 646:
-           /* TODO & FIXME */
-           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
-           break;
-#endif  
-       ;
-        }
-       pdev->decompress_data = kbuf;
-       
-       /* Allocate image buffer; double buffer for mmap() */
-       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
-       if (kbuf == NULL) {
-               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
-               return -ENOMEM;
-       }
-       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
-       pdev->image_data = kbuf;
-       for (i = 0; i < default_mbufs; i++)
-               pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
-       for (; i < MAX_IMAGES; i++)
-               pdev->image_ptr[i] = NULL;
-
-       kbuf = NULL;
-         
-       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
-       return 0;
-}
-
-static void pwc_free_buffers(struct pwc_device *pdev)
-{
-       int i;
-
-       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
-
-       if (pdev == NULL)
-               return;
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("free_buffers(): magic failed.\n");
-               return;
-       }
-#endif 
-
-       /* Release Iso-pipe buffers */
-       for (i = 0; i < MAX_ISO_BUFS; i++)
-               if (pdev->sbuf[i].data != NULL) {
-                       Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
-                       kfree(pdev->sbuf[i].data);
-                       pdev->sbuf[i].data = NULL;
-               }
-
-       /* The same for frame buffers */
-       if (pdev->fbuf != NULL) {
-               for (i = 0; i < default_fbufs; i++) {
-                       if (pdev->fbuf[i].data != NULL) {
-                               Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
-                               vfree(pdev->fbuf[i].data);
-                               pdev->fbuf[i].data = NULL;
-                       }
-               }
-               kfree(pdev->fbuf);
-               pdev->fbuf = NULL;
-       }
-
-       /* Intermediate decompression buffer & tables */
-       if (pdev->decompress_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
-               kfree(pdev->decompress_data);
-               pdev->decompress_data = NULL;
-       }
-       pdev->decompressor = NULL;
-
-       /* Release image buffers */
-       if (pdev->image_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
-               rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
-       }
-       pdev->image_data = NULL;
-       
-       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
-}
-
-/* The frame & image buffer mess. 
-
-   Yes, this is a mess. Well, it used to be simple, but alas...  In this
-   module, 3 buffers schemes are used to get the data from the USB bus to
-   the user program. The first scheme involves the ISO buffers (called thus
-   since they transport ISO data from the USB controller), and not really
-   interesting. Suffices to say the data from this buffer is quickly 
-   gathered in an interrupt handler (pwc_isoc_handler) and placed into the
-   frame buffer.
-
-   The frame buffer is the second scheme, and is the central element here.
-   It collects the data from a single frame from the camera (hence, the
-   name). Frames are delimited by the USB camera with a short USB packet,
-   so that's easy to detect. The frame buffers form a list that is filled
-   by the camera+USB controller and drained by the user process through
-   either read() or mmap().
-
-   The image buffer is the third scheme, in which frames are decompressed
-   and converted into planar format. For mmap() there is more than
-   one image buffer available.
-
-   The frame buffers provide the image buffering. In case the user process
-   is a bit slow, this introduces lag and some undesired side-effects.
-   The problem arises when the frame buffer is full. I used to drop the last
-   frame, which makes the data in the queue stale very quickly. But dropping
-   the frame at the head of the queue proved to be a litte bit more difficult.
-   I tried a circular linked scheme, but this introduced more problems than
-   it solved.
-
-   Because filling and draining are completely asynchronous processes, this
-   requires some fiddling with pointers and mutexes.
-
-   Eventually, I came up with a system with 2 lists: an 'empty' frame list
-   and a 'full' frame list:
-     * Initially, all frame buffers but one are on the 'empty' list; the one
-       remaining buffer is our initial fill frame.
-     * If a frame is needed for filling, we try to take it from the 'empty' 
-       list, unless that list is empty, in which case we take the buffer at 
-       the head of the 'full' list.
-     * When our fill buffer has been filled, it is appended to the 'full'
-       list.
-     * If a frame is needed by read() or mmap(), it is taken from the head of
-       the 'full' list, handled, and then appended to the 'empty' list. If no
-       buffer is present on the 'full' list, we wait.
-   The advantage is that the buffer that is currently being decompressed/
-   converted, is on neither list, and thus not in our way (any other scheme
-   I tried had the problem of old data lingering in the queue).
-
-   Whatever strategy you choose, it always remains a tradeoff: with more
-   frame buffers the chances of a missed frame are reduced. On the other
-   hand, on slower machines it introduces lag because the queue will
-   always be full.
- */
-
-/**
-  \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
- */
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
-{
-       int ret;
-       unsigned long flags;
-
-       ret = 0;
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       if (pdev->fill_frame != NULL) {
-               /* append to 'full' list */
-               if (pdev->full_frames == NULL) {
-                       pdev->full_frames = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->full_frames;
-               }
-               else {
-                       pdev->full_frames_tail->next = pdev->fill_frame;
-                       pdev->full_frames_tail = pdev->fill_frame;
-               }
-       }
-       if (pdev->empty_frames != NULL) {
-               /* We have empty frames available. That's easy */
-               pdev->fill_frame = pdev->empty_frames;
-               pdev->empty_frames = pdev->empty_frames->next;
-       }
-       else {
-               /* Hmm. Take it from the full list */
-#if PWC_DEBUG
-               /* sanity check */
-               if (pdev->full_frames == NULL) {
-                       Err("Neither empty or full frames available!\n");
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       return -EINVAL;
-               }
-#endif
-               pdev->fill_frame = pdev->full_frames;
-               pdev->full_frames = pdev->full_frames->next;
-               ret = 1;
-       }
-       pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
-       Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
-       pdev->fill_frame->sequence = pdev->sequence++;
-#endif
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-
-/**
-  \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
-
-  If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
- */
-static void pwc_reset_buffers(struct pwc_device *pdev)
-{
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       pdev->full_frames = NULL;
-       pdev->full_frames_tail = NULL;
-       for (i = 0; i < default_fbufs; i++) {
-               pdev->fbuf[i].filled = 0;
-               if (i > 0)
-                       pdev->fbuf[i].next = &pdev->fbuf[i - 1];
-               else
-                       pdev->fbuf->next = NULL;
-       }
-       pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
-       pdev->empty_frames_tail = pdev->fbuf;
-       pdev->read_frame = NULL;
-       pdev->fill_frame = pdev->empty_frames;
-       pdev->empty_frames = pdev->empty_frames->next;
-
-       pdev->image_read_pos = 0;
-       pdev->fill_image = 0;
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-}
-
-
-/**
-  \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
- */
-static int pwc_handle_frame(struct pwc_device *pdev)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&pdev->ptrlock, flags);
-       /* First grab our read_frame; this is removed from all lists, so
-          we can release the lock after this without problems */
-       if (pdev->read_frame != NULL) {
-               /* This can't theoretically happen */
-               Err("Huh? Read frame still in use?\n");
-       }
-       else {
-               if (pdev->full_frames == NULL) {
-                       Err("Woops. No frames ready.\n");
-               }
-               else {
-                       pdev->read_frame = pdev->full_frames;
-                       pdev->full_frames = pdev->full_frames->next;
-                       pdev->read_frame->next = NULL;
-               }
-
-               if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
-                       Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
-                       /* Decompression is a lenghty process, so it's outside of the lock.
-                          This gives the isoc_handler the opportunity to fill more frames
-                          in the mean time.
-                       */
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       ret = pwc_decompress(pdev);
-                       spin_lock_irqsave(&pdev->ptrlock, flags);
-
-                       /* We're done with read_buffer, tack it to the end of the empty buffer list */
-                       if (pdev->empty_frames == NULL) {
-                               pdev->empty_frames = pdev->read_frame;
-                               pdev->empty_frames_tail = pdev->empty_frames;
-                       }
-                       else {
-                               pdev->empty_frames_tail->next = pdev->read_frame;
-                               pdev->empty_frames_tail = pdev->read_frame;
-                       }
-                       pdev->read_frame = NULL;
-               }
-       }
-       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-       return ret;
-}
-
-/**
-  \brief Advance pointers of image buffer (after each user request)
-*/
-static inline void pwc_next_image(struct pwc_device *pdev)
-{
-       pdev->image_used[pdev->fill_image] = 0;
-       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
-}
-
-
-/* This gets called for the Isochronous pipe (video). This is done in
- * interrupt time, so it has to be fast, not crash, and not stall. Neat.
- */
-static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
-{
-       struct pwc_device *pdev;
-       int i, fst, flen;
-       int awake;
-       struct pwc_frame_buf *fbuf;
-       unsigned char *fillptr = NULL, *iso_buf = NULL;
-
-       awake = 0;
-       pdev = (struct pwc_device *)urb->context;
-       if (pdev == NULL) {
-               Err("isoc_handler() called with NULL device?!\n");
-               return;
-       }
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("isoc_handler() called with bad magic!\n");
-               return;
-       }
-#endif
-       if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-               Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
-               return;
-       }
-       if (urb->status != -EINPROGRESS && urb->status != 0) {
-               const char *errmsg;
-
-               errmsg = "Unknown";
-               switch(urb->status) {
-                       case -ENOSR:            errmsg = "Buffer error (overrun)"; break;
-                       case -EPIPE:            errmsg = "Stalled (device not responding)"; break;
-                       case -EOVERFLOW:        errmsg = "Babble (bad cable?)"; break;
-                       case -EPROTO:           errmsg = "Bit-stuff error (bad cable?)"; break;
-                       case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
-                       case -ETIMEDOUT:        errmsg = "NAK (device does not respond)"; break;
-               }
-               Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
-               /* Give up after a number of contiguous errors on the USB bus. 
-                  Appearantly something is wrong so we simulate an unplug event.
-                */
-               if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
-               {
-                       Info("Too many ISOC errors, bailing out.\n");
-                       pdev->error_status = EIO;
-                       awake = 1;
-                       wake_up_interruptible(&pdev->frameq);
-               }
-               goto handler_end; // ugly, but practical
-       }
-
-       fbuf = pdev->fill_frame;
-       if (fbuf == NULL) {
-               Err("pwc_isoc_handler without valid fill frame.\n");
-               awake = 1;
-               goto handler_end;
-       }
-       else {
-               fillptr = fbuf->data + fbuf->filled;
-       }
-
-       /* Reset ISOC error counter. We did get here, after all. */
-       pdev->visoc_errors = 0;
-
-       /* vsync: 0 = don't copy data
-                 1 = sync-hunt
-                 2 = synched
-        */
-       /* Compact data */
-       for (i = 0; i < urb->number_of_packets; i++) {
-               fst  = urb->iso_frame_desc[i].status;
-               flen = urb->iso_frame_desc[i].actual_length;
-               iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-               if (fst == 0) {
-                       if (flen > 0) { /* if valid data... */
-                               if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
-                                       pdev->vsync = 2;
-
-                                       /* ...copy data to frame buffer, if possible */
-                                       if (flen + fbuf->filled > pdev->frame_total_size) {
-                                               Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
-                                               pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
-                                               pdev->vframes_error++;
-                                       }
-                                       else {
-                                               memmove(fillptr, iso_buf, flen);
-                                               fillptr += flen;
-                                       }
-                               }
-                               fbuf->filled += flen;
-                       } /* ..flen > 0 */
-
-                       if (flen < pdev->vlast_packet_size) {
-                               /* Shorter packet... We probably have the end of an image-frame; 
-                                  wake up read() process and let select()/poll() do something.
-                                  Decompression is done in user time over there.
-                                */
-                               if (pdev->vsync == 2) {
-                                       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus 
-                                          frames on the USB wire after an exposure change. This conditition is 
-                                          however detected  in the cam and a bit is set in the header.
-                                        */
-                                       if (pdev->type == 730) {
-                                               unsigned char *ptr = (unsigned char *)fbuf->data;
-                                               
-                                               if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
-                                                       Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
-                                                       pdev->drop_frames += 2;
-                                                       pdev->vframes_error++;
-                                               }
-                                               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                                                       if (ptr[0] & 0x01)
-                                                               Info("Snapshot button pressed.\n");
-                                                       else
-                                                               Info("Snapshot button released.\n");
-                                               }
-                                               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
-                                                       if (ptr[0] & 0x02)
-                                                               Info("Image is mirrored.\n");
-                                                       else
-                                                               Info("Image is normal.\n");
-                                               }
-                                               pdev->vmirror = ptr[0] & 0x03;
-                                               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet 
-                                                  after a short frame; this condition is filtered out specifically. A 4 byte
-                                                  frame doesn't make sense anyway.
-                                                  So we get either this sequence: 
-                                                       drop_bit set -> 4 byte frame -> short frame -> good frame
-                                                  Or this one:
-                                                       drop_bit set -> short frame -> good frame
-                                                  So we drop either 3 or 2 frames in all!
-                                                */
-                                               if (fbuf->filled == 4)
-                                                       pdev->drop_frames++;
-                                       }
-
-                                       /* In case we were instructed to drop the frame, do so silently.
-                                          The buffer pointers are not updated either (but the counters are reset below).
-                                        */
-                                       if (pdev->drop_frames > 0)
-                                               pdev->drop_frames--;
-                                       else {
-                                               /* Check for underflow first */
-                                               if (fbuf->filled < pdev->frame_total_size) {
-                                                       Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
-                                                       pdev->vframes_error++;
-                                               }
-                                               else {
-                                                       /* Send only once per EOF */
-                                                       awake = 1; /* delay wake_ups */
-
-                                                       /* Find our next frame to fill. This will always succeed, since we
-                                                        * nick a frame from either empty or full list, but if we had to
-                                                        * take it from the full list, it means a frame got dropped.
-                                                        */
-                                                       if (pwc_next_fill_frame(pdev)) {
-                                                               pdev->vframes_dumped++;
-                                                               if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
-                                                                       if (pdev->vframes_dumped < 20)
-                                                                               Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
-                                                                       if (pdev->vframes_dumped == 20)
-                                                                               Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
-                                                               }
-                                                       }
-                                                       fbuf = pdev->fill_frame;
-                                               }
-                                       } /* !drop_frames */
-                                       pdev->vframe_count++;
-                               }
-                               fbuf->filled = 0;
-                               fillptr = fbuf->data;
-                               pdev->vsync = 1;
-                       } /* .. flen < last_packet_size */
-                       pdev->vlast_packet_size = flen;
-               } /* ..status == 0 */
-#if PWC_DEBUG
-               /* This is normally not interesting to the user, unless you are really debugging something */
-               else {
-                       static int iso_error = 0;
-                       iso_error++;
-                       if (iso_error < 20)
-                               Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
-               }
-#endif
-       }
-
-handler_end:
-       if (awake)
-               wake_up_interruptible(&pdev->frameq);
-
-       urb->dev = pdev->udev;
-       i = usb_submit_urb(urb, GFP_ATOMIC);
-       if (i != 0)
-               Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
-}
-
-
-static int pwc_isoc_init(struct pwc_device *pdev)
-{
-       struct usb_device *udev;
-       struct urb *urb;
-       int i, j, ret;
-
-       struct usb_interface *intf;
-       struct usb_host_interface *idesc = NULL;
-
-       if (pdev == NULL)
-               return -EFAULT;
-       if (pdev->iso_init)
-               return 0;
-       pdev->vsync = 0;
-       udev = pdev->udev;
-
-       /* Get the current alternate interface, adjust packet size */
-       if (!udev->actconfig)
-               return -EFAULT;
-
-       intf = usb_ifnum_to_if(udev, 0);
-       if (intf)
-               idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
-               
-       if (!idesc)
-               return -EFAULT;
-
-       /* Search video endpoint */
-       pdev->vmax_packet_size = -1;
-       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
-               if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
-                       pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
-                       break;
-               }
-       
-       if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
-               Err("Failed to find packet size for video endpoint in current alternate setting.\n");
-               return -ENFILE; /* Odd error, that should be noticeable */
-       }
-
-       /* Set alternate interface */
-       ret = 0;
-       Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
-       ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
-               if (urb == NULL) {
-                       Err("Failed to allocate urb %d\n", i);
-                       ret = -ENOMEM;
-                       break;
-               }
-               pdev->sbuf[i].urb = urb;
-               Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
-       }
-       if (ret) {
-               /* De-allocate in reverse order */
-               while (i >= 0) {
-                       if (pdev->sbuf[i].urb != NULL)
-                               usb_free_urb(pdev->sbuf[i].urb);
-                       pdev->sbuf[i].urb = NULL;
-                       i--;
-               }
-               return ret;
-       }
-
-       /* init URB structure */        
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               urb = pdev->sbuf[i].urb;
-
-               urb->interval = 1; // devik
-               urb->dev = udev;
-               urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = pdev->sbuf[i].data;
-               urb->transfer_buffer_length = ISO_BUFFER_SIZE;
-               urb->complete = pwc_isoc_handler;
-               urb->context = pdev;
-               urb->start_frame = 0;
-               urb->number_of_packets = ISO_FRAMES_PER_DESC;
-               for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
-                       urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-                       urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
-               }
-       }
-
-       /* link */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
-               if (ret)
-                       Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
-               else
-                       Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
-       }
-
-       /* All is done... */
-       pdev->iso_init = 1;
-       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
-       return 0;
-}
-
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
-{
-       int i;
-
-       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
-       if (pdev == NULL)
-               return;
-
-       /* Unlinking ISOC buffers one by one */
-       for (i = 0; i < MAX_ISO_BUFS; i++) {
-               struct urb *urb;
-
-               urb = pdev->sbuf[i].urb;
-               if (urb != 0) {
-                       if (pdev->iso_init) {
-                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
-                               usb_kill_urb(urb);
-                       }
-                       Trace(TRACE_MEMORY, "Freeing URB\n");
-                       usb_free_urb(urb);
-                       pdev->sbuf[i].urb = NULL;
-               }
-       }
-
-       /* Stop camera, but only if we are sure the camera is still there (unplug
-          is signalled by EPIPE) 
-        */
-       if (pdev->error_status && pdev->error_status != EPIPE) {
-               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
-               usb_set_interface(pdev->udev, 0, 0);
-       }
-
-       pdev->iso_init = 0;
-       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
-}
-
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
-{
-       int ret, start;
-
-       /* Stop isoc stuff */
-       pwc_isoc_cleanup(pdev);
-       /* Reset parameters */
-       pwc_reset_buffers(pdev);
-       /* Try to set video mode... */
-       start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
-       if (ret) { 
-               Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
-               /* That failed... restore old mode (we know that worked) */
-               start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-               if (start) {
-                       Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
-               }
-       }
-       if (start == 0)
-       {
-               if (pwc_isoc_init(pdev) < 0)
-               {
-                       Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
-                       ret = -EAGAIN; /* let's try again, who knows if it works a second time */
-               }
-       }
-       pdev->drop_frames++; /* try to avoid garbage during switch */
-       return ret; /* Return original error code */
-}
-
-
-/***************************************************************************/
-/* Video4Linux functions */
-
-static int pwc_video_open(struct inode *inode, struct file *file)
-{
-       int i;
-       struct video_device *vdev = video_devdata(file);
-       struct pwc_device *pdev;
-
-       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
-       
-       pdev = (struct pwc_device *)vdev->priv;
-       if (pdev == NULL)
-               BUG();
-       if (pdev->vopen)
-               return -EBUSY;
-       
-       down(&pdev->modlock);
-       if (!pdev->usb_init) {
-               Trace(TRACE_OPEN, "Doing first time initialization.\n");
-               pdev->usb_init = 1;
-               
-               if (pwc_trace & TRACE_OPEN)
-               {
-                       /* Query sensor type */
-                       const char *sensor_type = NULL;
-                       int ret;
-
-                       ret = pwc_get_cmos_sensor(pdev, &i);
-                       if (ret >= 0)
-                       {
-                               switch(i) {
-                               case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
-                               case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
-                               case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
-                               case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
-                               case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
-                               case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
-                               case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
-                               case 0x40:  sensor_type = "UPA 1021 sensor"; break;
-                               case 0x100: sensor_type = "VGA sensor"; break;
-                               case 0x101: sensor_type = "PAL MR sensor"; break;
-                               default:    sensor_type = "unknown type of sensor"; break;
-                               }
-                       }
-                       if (sensor_type != NULL)
-                               Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
-               }
-       }
-
-       /* Turn on camera */
-       if (power_save) {
-               i = pwc_camera_power(pdev, 1);
-               if (i < 0)
-                       Info("Failed to restore power to the camera! (%d)\n", i);
-       }
-       /* Set LED on/off time */
-       if (pwc_set_leds(pdev, led_on, led_off) < 0)
-               Info("Failed to set LED on/off time.\n");
-       
-       pwc_construct(pdev); /* set min/max sizes correct */
-
-       /* So far, so good. Allocate memory. */
-       i = pwc_allocate_buffers(pdev);
-       if (i < 0) {
-               Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
-               up(&pdev->modlock);
-               return i;
-       }
-       
-       /* Reset buffers & parameters */
-       pwc_reset_buffers(pdev);
-       for (i = 0; i < default_mbufs; i++)
-               pdev->image_used[i] = 0;
-       pdev->vframe_count = 0;
-       pdev->vframes_dumped = 0;
-       pdev->vframes_error = 0;
-       pdev->visoc_errors = 0;
-       pdev->error_status = 0;
-#if PWC_DEBUG
-       pdev->sequence = 0;
-#endif
-       pwc_construct(pdev); /* set min/max sizes correct */
-
-       /* Set some defaults */
-       pdev->vsnapshot = 0;
-
-       /* Start iso pipe for video; first try the last used video size
-          (or the default one); if that fails try QCIF/10 or QSIF/10;
-          it that fails too, give up.
-        */
-       i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
-       if (i)  {
-               Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
-               if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
-               else
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
-       }
-       if (i) {
-               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
-               up(&pdev->modlock);
-               return i;
-       }
-       
-       i = pwc_isoc_init(pdev);
-       if (i) {
-               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
-               up(&pdev->modlock);
-               return i;
-       }
-
-       pdev->vopen++;
-       file->private_data = vdev;
-       up(&pdev->modlock);
-       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
-       return 0;
-}
-
-/* Note that all cleanup is done in the reverse order as in _open */
-static int pwc_video_close(struct inode *inode, struct file *file)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int i;
-
-       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
-
-       pdev = (struct pwc_device *)vdev->priv;
-       if (pdev->vopen == 0)
-               Info("video_close() called on closed device?\n");
-
-       /* Dump statistics, but only if a reasonable amount of frames were
-          processed (to prevent endless log-entries in case of snap-shot
-          programs)
-        */
-       if (pdev->vframe_count > 20)
-               Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
-
-       switch (pdev->type)
-        {
-         case 675:
-         case 680:
-         case 690:
-         case 720:
-         case 730:
-         case 740:
-         case 750:
-/*         pwc_dec23_exit();   *//* Timon & Kiara */
-           break;
-         case 645:
-         case 646:
-/*         pwc_dec1_exit(); */
-           break;
-        }
-
-       pwc_isoc_cleanup(pdev);
-       pwc_free_buffers(pdev);
-
-       /* Turn off LEDS and power down camera, but only when not unplugged */
-       if (pdev->error_status != EPIPE) {
-               /* Turn LEDs off */
-               if (pwc_set_leds(pdev, 0, 0) < 0)
-                       Info("Failed to set LED on/off time.\n");
-               if (power_save) {
-                       i = pwc_camera_power(pdev, 0);
-                       if (i < 0)
-                               Err("Failed to power down camera (%d)\n", i);
-               }
-       }
-       pdev->vopen = 0;
-       Trace(TRACE_OPEN, "<< video_close()\n");
-       return 0;
-}
-
-/*
- *     FIXME: what about two parallel reads ????
- *      ANSWER: Not supported. You can't open the device more than once,
-                despite what the V4L1 interface says. First, I don't see
-                the need, second there's no mechanism of alerting the
-                2nd/3rd/... process of events like changing image size.
-                And I don't see the point of blocking that for the
-                2nd/3rd/... process.
-                In multi-threaded environments reading parallel from any
-                device is tricky anyhow.
- */
-
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
-                         size_t count, loff_t *ppos)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       int noblock = file->f_flags & O_NONBLOCK;
-       DECLARE_WAITQUEUE(wait, current);
-        int bytes_to_read;
-
-       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-       if (pdev->error_status)
-               return -pdev->error_status; /* Something happened, report what. */
-
-       /* In case we're doing partial reads, we don't have to wait for a frame */
-       if (pdev->image_read_pos == 0) {
-               /* Do wait queueing according to the (doc)book */
-               add_wait_queue(&pdev->frameq, &wait);
-               while (pdev->full_frames == NULL) {
-                       /* Check for unplugged/etc. here */
-                       if (pdev->error_status) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               return -pdev->error_status ;
-                       }
-                       if (noblock) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               return -EWOULDBLOCK;
-                       }
-                       if (signal_pending(current)) {
-                               remove_wait_queue(&pdev->frameq, &wait);
-                               set_current_state(TASK_RUNNING);
-                               return -ERESTARTSYS;
-                       }
-                       schedule();
-                       set_current_state(TASK_INTERRUPTIBLE);
-               }
-               remove_wait_queue(&pdev->frameq, &wait);
-               set_current_state(TASK_RUNNING);
-                                                                                                                                                                                
-               /* Decompress and release frame */
-               if (pwc_handle_frame(pdev))
-                       return -EFAULT;
-       }
-
-       Trace(TRACE_READ, "Copying data to user space.\n");
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               bytes_to_read = pdev->frame_size;
-       else
-               bytes_to_read = pdev->view.size;
-
-       /* copy bytes to user space; we allow for partial reads */
-       if (count + pdev->image_read_pos > bytes_to_read)
-               count = bytes_to_read - pdev->image_read_pos;
-       if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
-               return -EFAULT;
-       pdev->image_read_pos += count;
-       if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
-               pdev->image_read_pos = 0;
-               pwc_next_image(pdev);
-       }
-       return count;
-}
-
-static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-
-       poll_wait(file, &pdev->frameq, wait);
-       if (pdev->error_status)
-               return POLLERR;
-       if (pdev->full_frames != NULL) /* we have frames waiting */
-               return (POLLIN | POLLRDNORM);
-
-       return 0;
-}
-
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-
-       switch (cmd) {
-               /* Query cabapilities */
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *caps = arg;
-
-                       strcpy(caps->name, vdev->name);
-                       caps->type = VID_TYPE_CAPTURE;
-                       caps->channels = 1;
-                       caps->audios = 1;
-                       caps->minwidth  = pdev->view_min.x;
-                       caps->minheight = pdev->view_min.y;
-                       caps->maxwidth  = pdev->view_max.x;
-                       caps->maxheight = pdev->view_max.y;
-                       break;
-               }
-
-               /* Channel functions (simulate 1 channel) */
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       v->flags = 0;
-                       v->tuners = 0;
-                       v->type = VIDEO_TYPE_CAMERA;
-                       strcpy(v->name, "Webcam");
-                       return 0;
-               }
-
-               case VIDIOCSCHAN:
-               {
-                       /* The spec says the argument is an integer, but
-                          the bttv driver uses a video_channel arg, which
-                          makes sense becasue it also has the norm flag.
-                        */
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-
-
-               /* Picture functions; contrast etc. */
-               case VIDIOCGPICT:
-               {
-                       struct video_picture *p = arg;
-                       int val;
-
-                       val = pwc_get_brightness(pdev);
-                       if (val >= 0)
-                               p->brightness = val;
-                       else
-                               p->brightness = 0xffff;
-                       val = pwc_get_contrast(pdev);
-                       if (val >= 0)
-                               p->contrast = val;
-                       else
-                               p->contrast = 0xffff;
-                       /* Gamma, Whiteness, what's the difference? :) */
-                       val = pwc_get_gamma(pdev);
-                       if (val >= 0)
-                               p->whiteness = val;
-                       else
-                               p->whiteness = 0xffff;
-                       val = pwc_get_saturation(pdev);
-                       if (val >= 0)
-                               p->colour = val;
-                       else
-                               p->colour = 0xffff;
-                       p->depth = 24;
-                       p->palette = pdev->vpalette;
-                       p->hue = 0xFFFF; /* N/A */
-                       break;
-               }
-
-               case VIDIOCSPICT:
-               {
-                       struct video_picture *p = arg;
-                       /*
-                        *      FIXME:  Suppose we are mid read
-                               ANSWER: No problem: the firmware of the camera
-                                       can handle brightness/contrast/etc
-                                       changes at _any_ time, and the palette
-                                       is used exactly once in the uncompress
-                                       routine.
-                        */
-                       pwc_set_brightness(pdev, p->brightness);
-                       pwc_set_contrast(pdev, p->contrast);
-                       pwc_set_gamma(pdev, p->whiteness);
-                       pwc_set_saturation(pdev, p->colour);
-                       if (p->palette && p->palette != pdev->vpalette) {
-                               switch (p->palette) {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               pdev->vpalette = p->palette;
-                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-                       break;
-               }
-
-               /* Window/size parameters */            
-               case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-                       
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = pdev->view.x;
-                       vw->height = pdev->view.y;
-                       vw->chromakey = 0;
-                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | 
-                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
-                       break;
-               }
-               
-               case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-                       int fps, snapshot, ret;
-
-                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
-                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
-                       if (fps == 0)
-                               fps = pdev->vframes;
-                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
-                               return 0;
-                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
-                       if (ret)
-                               return ret;
-                       break;          
-               }
-               
-               /* We don't have overlay support (yet) */
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb,0,sizeof(*vb));
-                       break;
-               }
-
-               /* mmap() functions */
-               case VIDIOCGMBUF:
-               {
-                       /* Tell the user program how much memory is needed for a mmap() */
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset(vm, 0, sizeof(*vm));
-                       vm->size = default_mbufs * pdev->len_per_image;
-                       vm->frames = default_mbufs; /* double buffering should be enough for most applications */
-                       for (i = 0; i < default_mbufs; i++)
-                               vm->offsets[i] = i * pdev->len_per_image;
-                       break;
-               }
-
-               case VIDIOCMCAPTURE:
-               {
-                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
-                       struct video_mmap *vm = arg;
-
-                       Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
-                       if (vm->frame < 0 || vm->frame >= default_mbufs)
-                               return -EINVAL;
-
-                       /* xawtv is nasty. It probes the available palettes
-                          by setting a very small image size and trying
-                          various palettes... The driver doesn't support
-                          such small images, so I'm working around it.
-                        */
-                       if (vm->format)
-                       {
-                               switch (vm->format)
-                               {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-
-                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
-                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
-                               int ret;
-
-                               Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
-                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                               if (ret)
-                                       return ret;
-                       } /* ... size mismatch */
-
-                       /* FIXME: should we lock here? */
-                       if (pdev->image_used[vm->frame])
-                               return -EBUSY;  /* buffer wasn't available. Bummer */
-                       pdev->image_used[vm->frame] = 1;
-
-                       /* Okay, we're done here. In the SYNC call we wait until a 
-                          frame comes available, then expand image into the given 
-                          buffer.
-                          In contrast to the CPiA cam the Philips cams deliver a
-                          constant stream, almost like a grabber card. Also,
-                          we have separate buffers for the rawdata and the image,
-                          meaning we can nearly always expand into the requested buffer.
-                        */
-                       Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
-                       break;
-               }
-
-               case VIDIOCSYNC:
-               {
-                       /* The doc says: "Whenever a buffer is used it should
-                          call VIDIOCSYNC to free this frame up and continue."
-                          
-                          The only odd thing about this whole procedure is 
-                          that MCAPTURE flags the buffer as "in use", and
-                          SYNC immediately unmarks it, while it isn't 
-                          after SYNC that you know that the buffer actually
-                          got filled! So you better not start a CAPTURE in
-                          the same frame immediately (use double buffering). 
-                          This is not a problem for this cam, since it has 
-                          extra intermediate buffers, but a hardware 
-                          grabber card will then overwrite the buffer 
-                          you're working on.
-                        */
-                       int *mbuf = arg;
-                       int ret;
-
-                       Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
-                       /* bounds check */
-                       if (*mbuf < 0 || *mbuf >= default_mbufs)
-                               return -EINVAL;
-                       /* check if this buffer was requested anyway */
-                       if (pdev->image_used[*mbuf] == 0)
-                               return -EINVAL;
-
-                       /* Add ourselves to the frame wait-queue.
-                          
-                          FIXME: needs auditing for safety.
-                          QUESTION: In what respect? I think that using the
-                                    frameq is safe now.
-                        */
-                       add_wait_queue(&pdev->frameq, &wait);
-                       while (pdev->full_frames == NULL) {
-                               if (pdev->error_status) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -pdev->error_status;
-                               }
-                       
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -ERESTARTSYS;
-                               }
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       }
-                       remove_wait_queue(&pdev->frameq, &wait);
-                       set_current_state(TASK_RUNNING);
-                               
-                       /* The frame is ready. Expand in the image buffer 
-                          requested by the user. I don't care if you 
-                          mmap() 5 buffers and request data in this order: 
-                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
-                          Grabber hardware may not be so forgiving.
-                        */
-                       Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
-                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
-                       /* Decompress, etc */
-                       ret = pwc_handle_frame(pdev);
-                       pdev->image_used[*mbuf] = 0;
-                       if (ret)
-                               return -EFAULT;
-                       break;
-               }
-               
-               case VIDIOCGAUDIO:
-               {
-                       struct video_audio *v = arg;
-                       
-                       strcpy(v->name, "Microphone");
-                       v->audio = -1; /* unknown audio minor */
-                       v->flags = 0;
-                       v->mode = VIDEO_SOUND_MONO;
-                       v->volume = 0;
-                       v->bass = 0;
-                       v->treble = 0;
-                       v->balance = 0x8000;
-                       v->step = 1;
-                       break;  
-               }
-               
-               case VIDIOCSAUDIO:
-               {
-                       /* Dummy: nothing can be set */
-                       break;
-               }
-               
-               case VIDIOCGUNIT:
-               {
-                       struct video_unit *vu = arg;
-                       
-                       vu->video = pdev->vdev->minor & 0x3F;
-                       vu->audio = -1; /* not known yet */
-                       vu->vbi = -1;
-                       vu->radio = -1;
-                       vu->teletext = -1;
-                       break;
-               }
-               default:
-                       return pwc_ioctl(pdev, cmd, arg);
-       } /* ..switch */
-       return 0;
-}      
-
-static int pwc_video_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
-}
-
-
-static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-       
-       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
-       pdev = vdev->priv;
-       
-       vma->vm_flags |= VM_IO;
-
-       pos = (unsigned long)pdev->image_data;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-/***************************************************************************/
-/* USB functions */
-
-/* This function gets called when a new device is plugged in or the usb core
- * is loaded.
- */
-
-static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct pwc_device *pdev = NULL;
-       int vendor_id, product_id, type_id;
-       int i, hint;
-       int features = 0;
-       int video_nr = -1; /* default: use next available device */
-       char serial_number[30], *name;
-
-       /* Check if we can handle this device */
-       Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", 
-               le16_to_cpu(udev->descriptor.idVendor),
-               le16_to_cpu(udev->descriptor.idProduct),
-               intf->altsetting->desc.bInterfaceNumber);
-
-       /* the interfaces are probed one by one. We are only interested in the
-          video interface (0) now.
-          Interface 1 is the Audio Control, and interface 2 Audio itself.
-        */
-       if (intf->altsetting->desc.bInterfaceNumber > 0)
-               return -ENODEV;
-
-       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
-       product_id = le16_to_cpu(udev->descriptor.idProduct);
-
-       if (vendor_id == 0x0471) {
-               switch (product_id) {
-               case 0x0302:
-                       Info("Philips PCA645VC USB webcam detected.\n");
-                       name = "Philips 645 webcam";
-                       type_id = 645;
-                       break;
-               case 0x0303:
-                       Info("Philips PCA646VC USB webcam detected.\n");
-                       name = "Philips 646 webcam";
-                       type_id = 646;
-                       break;
-               case 0x0304:
-                       Info("Askey VC010 type 2 USB webcam detected.\n");
-                       name = "Askey VC010 webcam";
-                       type_id = 646;
-                       break;
-               case 0x0307:
-                       Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
-                       name = "Philips 675 webcam";
-                       type_id = 675;
-                       break;
-               case 0x0308:
-                       Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
-                       name = "Philips 680 webcam";
-                       type_id = 680;
-                       break;
-               case 0x030C:
-                       Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
-                       name = "Philips 690 webcam";
-                       type_id = 690;
-                       break;
-               case 0x0310:
-                       Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
-                       name = "Philips 730 webcam";
-                       type_id = 730;
-                       break;
-               case 0x0311:
-                       Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
-                       name = "Philips 740 webcam";
-                       type_id = 740;
-                       break;
-               case 0x0312:
-                       Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
-                       name = "Philips 750 webcam";
-                       type_id = 750;
-                       break;
-               case 0x0313:
-                       Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
-                       name = "Philips 720K/40 webcam";
-                       type_id = 720;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x069A) {
-               switch(product_id) {
-               case 0x0001:
-                       Info("Askey VC010 type 1 USB webcam detected.\n");
-                       name = "Askey VC010 webcam";
-                       type_id = 645;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x046d) {
-               switch(product_id) {
-               case 0x08b0:
-                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
-                       name = "Logitech QuickCam Pro 3000";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b1:
-                       Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
-                       name = "Logitech QuickCam Notebook Pro";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b2:
-                       Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
-                       name = "Logitech QuickCam Pro 4000";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b3:
-                       Info("Logitech QuickCam Zoom USB webcam detected.\n");
-                       name = "Logitech QuickCam Zoom";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08B4:
-                       Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
-                       name = "Logitech QuickCam Zoom";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x08b5:
-                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
-                       name = "Logitech QuickCam Orbit";
-                       type_id = 740; /* CCD sensor */
-                       features |= FEATURE_MOTOR_PANTILT;
-                       break;
-               case 0x08b6:
-               case 0x08b7:
-               case 0x08b8:
-                       Info("Logitech QuickCam detected (reserved ID).\n");
-                       name = "Logitech QuickCam (res.)";
-                       type_id = 730; /* Assuming CMOS */
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-        }
-       else if (vendor_id == 0x055d) {
-               /* I don't know the difference between the C10 and the C30;
-                  I suppose the difference is the sensor, but both cameras
-                  work equally well with a type_id of 675
-                */
-               switch(product_id) {
-               case 0x9000:
-                       Info("Samsung MPC-C10 USB webcam detected.\n");
-                       name = "Samsung MPC-C10";
-                       type_id = 675;
-                       break;
-               case 0x9001:
-                       Info("Samsung MPC-C30 USB webcam detected.\n");
-                       name = "Samsung MPC-C30";
-                       type_id = 675;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x041e) {
-               switch(product_id) {
-               case 0x400c:
-                       Info("Creative Labs Webcam 5 detected.\n");
-                       name = "Creative Labs Webcam 5";
-                       type_id = 730;
-                       break;
-               case 0x4011:
-                       Info("Creative Labs Webcam Pro Ex detected.\n");
-                       name = "Creative Labs Webcam Pro Ex";
-                       type_id = 740;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x04cc) {
-               switch(product_id) {
-               case 0x8116:
-                       Info("Sotec Afina Eye USB webcam detected.\n");
-                       name = "Sotec Afina Eye";
-                       type_id = 730;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else if (vendor_id == 0x06be) {
-               switch(product_id) {
-               case 0x8116:
-                       /* This is essentially the same cam as the Sotec Afina Eye */
-                       Info("AME Co. Afina Eye USB webcam detected.\n");
-                       name = "AME Co. Afina Eye";
-                       type_id = 750;
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       
-       }
-       else if (vendor_id == 0x0d81) {
-               switch(product_id) {
-               case 0x1900:
-                       Info("Visionite VCS-UC300 USB webcam detected.\n");
-                       name = "Visionite VCS-UC300";
-                       type_id = 740; /* CCD sensor */
-                       break;
-               case 0x1910:
-                       Info("Visionite VCS-UM100 USB webcam detected.\n");
-                       name = "Visionite VCS-UM100";
-                       type_id = 730; /* CMOS sensor */
-                       break;
-               default:
-                       return -ENODEV;
-                       break;
-               }
-       }
-       else 
-               return -ENODEV; /* Not any of the know types; but the list keeps growing. */
-
-       memset(serial_number, 0, 30);
-       usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
-       Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
-
-       if (udev->descriptor.bNumConfigurations > 1)
-               Info("Warning: more than 1 configuration available.\n");
-
-       /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
-       pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
-       if (pdev == NULL) {
-               Err("Oops, could not allocate memory for pwc_device.\n");
-               return -ENOMEM;
-       }
-       pdev->type = type_id;
-       pdev->vsize = default_size;
-       pdev->vframes = default_fps;
-       strcpy(pdev->serial, serial_number);
-       pdev->features = features;
-       if (vendor_id == 0x046D && product_id == 0x08B5)
-       {
-               /* Logitech QuickCam Orbit
-                  The ranges have been determined experimentally; they may differ from cam to cam.
-                  Also, the exact ranges left-right and up-down are different for my cam
-                 */
-               pdev->angle_range.pan_min  = -7000;
-               pdev->angle_range.pan_max  =  7000;
-               pdev->angle_range.tilt_min = -3000;
-               pdev->angle_range.tilt_max =  2500;
-       }
-
-       init_MUTEX(&pdev->modlock);
-       spin_lock_init(&pdev->ptrlock);
-
-       pdev->udev = udev;
-       init_waitqueue_head(&pdev->frameq);
-       pdev->vcompression = pwc_preferred_compression;
-
-       /* Allocate video_device structure */
-       pdev->vdev = video_device_alloc();
-       if (pdev->vdev == 0)
-       {
-               Err("Err, cannot allocate video_device struture. Failing probe.");
-               kfree(pdev);
-               return -ENOMEM;
-       }
-       memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
-       strcpy(pdev->vdev->name, name);
-       pdev->vdev->owner = THIS_MODULE;
-       video_set_drvdata(pdev->vdev, pdev);
-
-       pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
-       Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
-
-       /* Now search device_hint[] table for a match, so we can hint a node number. */
-       for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
-               if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
-                    (device_hint[hint].pdev == NULL)) {
-                       /* so far, so good... try serial number */
-                       if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
-                               /* match! */
-                               video_nr = device_hint[hint].device_node;
-                               Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
-                               break;
-                       }
-               }
-       }
-
-       pdev->vdev->release = video_device_release;
-       i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
-       if (i < 0) {
-               Err("Failed to register as video device (%d).\n", i);
-               video_device_release(pdev->vdev); /* Drip... drip... drip... */
-               kfree(pdev); /* Oops, no memory leaks please */
-               return -EIO;
-       }
-       else {
-               Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
-       }
-
-       /* occupy slot */
-       if (hint < MAX_DEV_HINTS) 
-               device_hint[hint].pdev = pdev;
-
-       Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
-       usb_set_intfdata (intf, pdev);
-       return 0;
-}
-
-/* The user janked out the cable... */
-static void usb_pwc_disconnect(struct usb_interface *intf)
-{
-       struct pwc_device *pdev;
-       int hint;
-
-       lock_kernel();
-       pdev = usb_get_intfdata (intf);
-       usb_set_intfdata (intf, NULL);
-       if (pdev == NULL) {
-               Err("pwc_disconnect() Called without private pointer.\n");
-               goto disconnect_out;
-       }
-       if (pdev->udev == NULL) {
-               Err("pwc_disconnect() already called for %p\n", pdev);
-               goto disconnect_out;
-       }
-       if (pdev->udev != interface_to_usbdev(intf)) {
-               Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
-               goto disconnect_out;
-       }
-#ifdef PWC_MAGIC       
-       if (pdev->magic != PWC_MAGIC) {
-               Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
-               goto disconnect_out;
-       }
-#endif
-       
-       /* We got unplugged; this is signalled by an EPIPE error code */
-       if (pdev->vopen) {
-               Info("Disconnected while webcam is in use!\n");
-               pdev->error_status = EPIPE;
-       }
-
-       /* Alert waiting processes */
-       wake_up_interruptible(&pdev->frameq);
-       /* Wait until device is closed */
-       while (pdev->vopen)
-               schedule();
-       /* Device is now closed, so we can safely unregister it */
-       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
-       video_unregister_device(pdev->vdev);
-
-       /* Free memory (don't set pdev to 0 just yet) */
-       kfree(pdev);
-
-disconnect_out:
-       /* search device_hint[] table if we occupy a slot, by any chance */
-       for (hint = 0; hint < MAX_DEV_HINTS; hint++)
-               if (device_hint[hint].pdev == pdev)
-                       device_hint[hint].pdev = NULL;
-
-       unlock_kernel();
-}
-
-
-/* *grunt* We have to do atoi ourselves :-( */
-static int pwc_atoi(const char *s)
-{
-       int k = 0;
-
-       k = 0;
-       while (*s != '\0' && *s >= '0' && *s <= '9') {
-               k = 10 * k + (*s - '0');
-               s++;
-       }
-       return k;
-}
-
-
-/* 
- * Initialization code & module stuff 
- */
-
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
-static int compression = -1;
-static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
-
-module_param_string(size, size, sizeof(size), 0);
-MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
-MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
-MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
-MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
-MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
-MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
-MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
-MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
-MODULE_PARM_DESC(dev_hint, "Device node hints");
-
-MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
-MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
-MODULE_LICENSE("GPL");
-
-static int __init usb_pwc_init(void)
-{
-       int i, sz;
-       char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
-
-       Info("Philips webcam module version " PWC_VERSION " loaded.\n");
-       Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
-       Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
-       Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
-
-       if (fps) {
-               if (fps < 4 || fps > 30) {
-                       Err("Framerate out of bounds (4-30).\n");
-                       return -EINVAL;
-               }
-               default_fps = fps;
-               Info("Default framerate set to %d.\n", default_fps);
-       }
-
-       if (size[0]) {
-               /* string; try matching with array */
-               for (sz = 0; sz < PSZ_MAX; sz++) {
-                       if (!strcmp(sizenames[sz], size)) { /* Found! */
-                               default_size = sz;
-                               break;
-                       }
-               }
-               if (sz == PSZ_MAX) {
-                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
-                       return -EINVAL;
-               }
-               Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
-       }
-       if (mbufs) {
-               if (mbufs < 1 || mbufs > MAX_IMAGES) {
-                       Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
-                       return -EINVAL;
-               }
-               default_mbufs = mbufs;
-               Info("Number of image buffers set to %d.\n", default_mbufs);
-       }
-       if (fbufs) {
-               if (fbufs < 2 || fbufs > MAX_FRAMES) {
-                       Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
-                       return -EINVAL;
-               }
-               default_fbufs = fbufs;
-               Info("Number of frame buffers set to %d.\n", default_fbufs);
-       }
-       if (trace >= 0) {
-               Info("Trace options: 0x%04x\n", trace);
-               pwc_trace = trace;
-       }
-       if (compression >= 0) {
-               if (compression > 3) {
-                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
-                       return -EINVAL;
-               }
-               pwc_preferred_compression = compression;
-               Info("Preferred compression set to %d.\n", pwc_preferred_compression);
-       }
-       if (power_save)
-               Info("Enabling power save on open/close.\n");
-       if (leds[0] >= 0)
-               led_on = leds[0];
-       if (leds[1] >= 0)
-               led_off = leds[1];
-
-       /* Big device node whoopla. Basically, it allows you to assign a
-          device node (/dev/videoX) to a camera, based on its type
-          & serial number. The format is [type[.serialnumber]:]node.
-
-          Any camera that isn't matched by these rules gets the next
-          available free device node.
-        */
-       for (i = 0; i < MAX_DEV_HINTS; i++) {
-               char *s, *colon, *dot;
-
-               /* This loop also initializes the array */
-               device_hint[i].pdev = NULL;
-               s = dev_hint[i];
-               if (s != NULL && *s != '\0') {
-                       device_hint[i].type = -1; /* wildcard */
-                       strcpy(device_hint[i].serial_number, "*");
-
-                       /* parse string: chop at ':' & '/' */
-                       colon = dot = s;
-                       while (*colon != '\0' && *colon != ':')
-                               colon++;
-                       while (*dot != '\0' && *dot != '.')
-                               dot++;
-                       /* Few sanity checks */
-                       if (*dot != '\0' && dot > colon) {
-                               Err("Malformed camera hint: the colon must be after the dot.\n");
-                               return -EINVAL;
-                       }
-
-                       if (*colon == '\0') {
-                               /* No colon */
-                               if (*dot != '\0') {
-                                       Err("Malformed camera hint: no colon + device node given.\n");
-                                       return -EINVAL;
-                               }
-                               else {
-                                       /* No type or serial number specified, just a number. */
-                                       device_hint[i].device_node = pwc_atoi(s);
-                               }
-                       }
-                       else {
-                               /* There's a colon, so we have at least a type and a device node */
-                               device_hint[i].type = pwc_atoi(s);
-                               device_hint[i].device_node = pwc_atoi(colon + 1);
-                               if (*dot != '\0') {
-                                       /* There's a serial number as well */
-                                       int k;
-                                       
-                                       dot++;
-                                       k = 0;
-                                       while (*dot != ':' && k < 29) {
-                                               device_hint[i].serial_number[k++] = *dot;
-                                               dot++;
-                                       }
-                                       device_hint[i].serial_number[k] = '\0';
-                               }
-                       }
-#if PWC_DEBUG          
-                       Debug("device_hint[%d]:\n", i);
-                       Debug("  type    : %d\n", device_hint[i].type);
-                       Debug("  serial# : %s\n", device_hint[i].serial_number);
-                       Debug("  node    : %d\n", device_hint[i].device_node);
-#endif                 
-               }
-               else
-                       device_hint[i].type = 0; /* not filled */
-       } /* ..for MAX_DEV_HINTS */
-
-       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
-       return usb_register(&pwc_driver);
-}
-
-static void __exit usb_pwc_exit(void)
-{
-       Trace(TRACE_MODULE, "Deregistering driver.\n");
-       usb_deregister(&pwc_driver);
-       Info("Philips webcam module removed.\n");
-}
-
-module_init(usb_pwc_init);
-module_exit(usb_pwc_exit);
-
diff --git a/drivers/usb/media/pwc/pwc-ioctl.h b/drivers/usb/media/pwc/pwc-ioctl.h
deleted file mode 100644 (file)
index 5f9cb08..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-#ifndef PWC_IOCTL_H
-#define PWC_IOCTL_H
-
-/* (C) 2001-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* This is pwc-ioctl.h belonging to PWC 8.12.1
-   It contains structures and defines to communicate from user space
-   directly to the driver.
- */
-
-/*
-   Changes
-   2001/08/03  Alvarado   Added ioctl constants to access methods for
-                          changing white balance and red/blue gains
-   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
-   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
-               PWCX easier
- */
-
-/* These are private ioctl() commands, specific for the Philips webcams.
-   They contain functions not found in other webcams, and settings not
-   specified in the Video4Linux API.
-
-   The #define names are built up like follows:
-   VIDIOC              VIDeo IOCtl prefix
-         PWC           Philps WebCam
-            G           optional: Get
-            S           optional: Set
-             ...       the function
- */
-
-
- /* Enumeration of image sizes */
-#define PSZ_SQCIF      0x00
-#define PSZ_QSIF       0x01
-#define PSZ_QCIF       0x02
-#define PSZ_SIF                0x03
-#define PSZ_CIF                0x04
-#define PSZ_VGA                0x05
-#define PSZ_MAX                6
-
-
-/* The frame rate is encoded in the video_window.flags parameter using
-   the upper 16 bits, since some flags are defined nowadays. The following
-   defines provide a mask and shift to filter out this value.
-
-   In 'Snapshot' mode the camera freezes its automatic exposure and colour
-   balance controls.
- */
-#define PWC_FPS_SHIFT          16
-#define PWC_FPS_MASK           0x00FF0000
-#define PWC_FPS_FRMASK         0x003F0000
-#define PWC_FPS_SNAPSHOT       0x00400000
-
-
-/* structure for transferring x & y coordinates */
-struct pwc_coord
-{
-       int x, y;               /* guess what */
-       int size;               /* size, or offset */
-};
-
-
-/* Used with VIDIOCPWCPROBE */
-struct pwc_probe
-{
-       char name[32];
-       int type;
-};
-
-struct pwc_serial
-{
-       char serial[30];        /* String with serial number. Contains terminating 0 */
-};
-       
-/* pwc_whitebalance.mode values */
-#define PWC_WB_INDOOR          0
-#define PWC_WB_OUTDOOR         1
-#define PWC_WB_FL              2
-#define PWC_WB_MANUAL          3
-#define PWC_WB_AUTO            4
-
-/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). 
-   Set mode to one of the PWC_WB_* values above.
-   *red and *blue are the respective gains of these colour components inside 
-   the camera; range 0..65535
-   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; 
-   otherwise undefined.
-   'read_red' and 'read_blue' are read-only.
-*/   
-struct pwc_whitebalance
-{
-       int mode;
-       int manual_red, manual_blue;    /* R/W */
-       int read_red, read_blue;        /* R/O */
-};
-
-/* 
-   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
-   and tell the camera how fast it should react to changes in lighting, and 
-   with how much delay. Valid values are 0..65535.
-*/
-struct pwc_wb_speed
-{
-       int control_speed;
-       int control_delay;
-
-};
-
-/* Used with VIDIOCPWC[SG]LED */
-struct pwc_leds
-{
-       int led_on;                     /* Led on-time; range = 0..25000 */
-       int led_off;                    /* Led off-time; range = 0..25000  */
-};
-
-/* Image size (used with GREALSIZE) */
-struct pwc_imagesize
-{
-       int width;
-       int height;
-};
-
-/* Defines and structures for Motorized Pan & Tilt */
-#define PWC_MPT_PAN            0x01
-#define PWC_MPT_TILT           0x02
-#define PWC_MPT_TIMEOUT                0x04 /* for status */
-
-/* Set angles; when absolute != 0, the angle is absolute and the 
-   driver calculates the relative offset for you. This can only
-   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
-   absolute angles.
- */   
-struct pwc_mpt_angles
-{
-       int absolute;           /* write-only */
-       int pan;                /* degrees * 100 */
-       int tilt;               /* degress * 100 */
-};
-
-/* Range of angles of the camera, both horizontally and vertically.
- */
-struct pwc_mpt_range
-{
-       int pan_min, pan_max;           /* degrees * 100 */
-       int tilt_min, tilt_max;
-};
-
-struct pwc_mpt_status
-{
-       int status;
-       int time_pan;
-       int time_tilt;
-};
-
-
-/* This is used for out-of-kernel decompression. With it, you can get
-   all the necessary information to initialize and use the decompressor
-   routines in standalone applications.
- */   
-struct pwc_video_command
-{
-       int type;               /* camera type (645, 675, 730, etc.) */
-       int release;            /* release number */
-
-        int size;              /* one of PSZ_* */
-        int alternate;
-       int command_len;        /* length of USB video command */
-       unsigned char command_buf[13];  /* Actual USB video command */
-       int bandlength;         /* >0 = compressed */
-       int frame_size;         /* Size of one (un)compressed frame */
-};
-
-/* Flags for PWCX subroutines. Not all modules honour all flags. */
-#define PWCX_FLAG_PLANAR       0x0001
-#define PWCX_FLAG_BAYER                0x0008
-
-
-/* IOCTL definitions */
-
- /* Restore user settings */
-#define VIDIOCPWCRUSER         _IO('v', 192)
- /* Save user settings */
-#define VIDIOCPWCSUSER         _IO('v', 193)
- /* Restore factory settings */
-#define VIDIOCPWCFACTORY       _IO('v', 194)
-
- /* You can manipulate the compression factor. A compression preference of 0
-    means use uncompressed modes when available; 1 is low compression, 2 is
-    medium and 3 is high compression preferred. Of course, the higher the
-    compression, the lower the bandwidth used but more chance of artefacts
-    in the image. The driver automatically chooses a higher compression when
-    the preferred mode is not available.
-  */
- /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
-#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
- /* Get preferred compression quality */
-#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
-
-
-/* Retrieve serial number of camera */
-#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
-
- /* This is a probe function; since so many devices are supported, it
-    becomes difficult to include all the names in programs that want to
-    check for the enhanced Philips stuff. So in stead, try this PROBE;
-    it returns a structure with the original name, and the corresponding
-    Philips type.
-    To use, fill the structure with zeroes, call PROBE and if that succeeds,
-    compare the name with that returned from VIDIOCGCAP; they should be the
-    same. If so, you can be assured it is a Philips (OEM) cam and the type
-    is valid.
- */
-#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
-
- /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
-#define VIDIOCPWCSAGC          _IOW('v', 200, int)
- /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCGAGC          _IOR('v', 200, int)
- /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
-#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
-
- /* Color compensation (Auto White Balance) */
-#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
-#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
-
- /* Auto WB speed */
-#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
-#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
-
- /* LEDs on/off/blink; int range 0..65535 */
-#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
-#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
-
-  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
-#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
-#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
-
-  /* Backlight compensation; 0 = off, otherwise on */
-#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
-#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
-
-  /* Flickerless mode; = 0 off, otherwise on */
-#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
-#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)  
-
-  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
-#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
-#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
-
- /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
-#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
-
- /* Motorized pan & tilt functions */ 
-#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
-#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
-#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
-#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
-
- /* Get the USB set-video command; needed for initializing libpwcx */
-#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
-struct pwc_table_init_buffer {
-   int len;
-   char *buffer;
-
-};
-#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
-
-#endif
diff --git a/drivers/usb/media/pwc/pwc-kiara.c b/drivers/usb/media/pwc/pwc-kiara.c
deleted file mode 100644 (file)
index c498c68..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-/* This tables contains entries for the 730/740/750 (Kiara) camera, with
-   4 different qualities (no compression, low, medium, high).
-   It lists the bandwidth requirements for said mode by its alternate interface
-   number. An alternate of 0 means that the mode is unavailable.
-
-   There are 6 * 4 * 4 entries:
-     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
-     6 framerates: 5, 10, 15, 20, 25, 30
-     4 compression modi: none, low, medium, high
-
-   When an uncompressed mode is not available, the next available compressed mode
-   will be chosen (unless the decompressor is absent). Sometimes there are only
-   1 or 2 compressed modes available; in that case entries are duplicated.
-*/
-
-
-#include "pwc-kiara.h"
-#include "pwc-uncompress.h"
-
-const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
-{
-   /* SQCIF */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-   /* QSIF */
-   {
-      /* 5 fps */
-      {
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-         {1, 146,    0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}},
-      },
-      /* 10 fps */
-      {
-         {2, 291,    0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}},
-         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
-         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
-         {1, 192,  630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}},
-      },
-      /* 15 fps */
-      {
-         {3, 437,    0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}},
-         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
-         {2, 292,  640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}},
-         {1, 192,  420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
-      },
-      /* 20 fps */
-      {
-         {4, 589,    0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}},
-         {3, 448,  730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}},
-         {2, 292,  476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}},
-         {1, 192,  312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}},
-      },
-      /* 25 fps */
-      {
-         {5, 703,    0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}},
-         {3, 447,  610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}},
-         {2, 292,  398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}},
-         {1, 193,  262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}},
-      },
-      /* 30 fps */
-      {
-         {8, 874,    0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}},
-         {5, 704,  730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}},
-         {3, 448,  492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}},
-         {2, 292,  320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}},
-      },
-   },
-   /* QCIF */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-   /* SIF */
-   {
-      /* 5 fps */
-      {
-         {4, 582,    0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}},
-         {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}},
-         {2, 291,  960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}},
-         {1, 191,  630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}},
-         {3, 447,  736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}},
-         {2, 292,  480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}},
-         {4, 592,  650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}},
-         {3, 448,  492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {9, 958,  782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}},
-         {5, 703,  574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}},
-         {3, 446,  364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}},
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {9, 958,  654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}},
-         {6, 776,  530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}},
-         {4, 592,  404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}},
-         {6, 775,  426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}},
-         {4, 590,  324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}},
-      },
-   },
-   /* CIF */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-   /* VGA */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}},
-         {4, 592,  976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}},
-         {3, 448,  738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {9, 956,  788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}},
-         {6, 776,  640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}},
-         {4, 592,  488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
-         {9, 957,  526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}},
-         {8, 895,  492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-};
-
diff --git a/drivers/usb/media/pwc/pwc-kiara.h b/drivers/usb/media/pwc/pwc-kiara.h
deleted file mode 100644 (file)
index 12929ab..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* Entries for the Kiara (730/740/750) camera */
-
-#ifndef PWC_KIARA_H
-#define PWC_KIARA_H
-
-#include "pwc-ioctl.h"
-
-struct Kiara_table_entry
-{
-       char alternate;                 /* USB alternate interface */
-       unsigned short packetsize;      /* Normal packet size */
-       unsigned short bandlength;      /* Bandlength when decompressing */
-       unsigned char mode[12];         /* precomputed mode settings for cam */
-};
-
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
-
-#endif
-
-
diff --git a/drivers/usb/media/pwc/pwc-misc.c b/drivers/usb/media/pwc/pwc-misc.c
deleted file mode 100644 (file)
index b7a4bd3..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Linux driver for Philips webcam 
-   Various miscellaneous functions and tables.
-   (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <linux/slab.h>
-
-#include "pwc.h"
-
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
-{
-       { 128,  96, 0 },
-       { 160, 120, 0 },
-       { 176, 144, 0 },
-       { 320, 240, 0 },
-       { 352, 288, 0 },
-       { 640, 480, 0 },
-};
-
-/* x,y -> PSZ_ */
-int pwc_decode_size(struct pwc_device *pdev, int width, int height)
-{
-       int i, find;
-
-       /* Make sure we don't go beyond our max size.
-           NB: we have different limits for RAW and normal modes. In case
-           you don't have the decompressor loaded or use RAW mode, 
-           the maximum viewable size is smaller.
-        */
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
-       {
-               if (width > pdev->abs_max.x || height > pdev->abs_max.y)
-               {
-                       Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
-                       return -1;
-                }
-       }
-       else
-       {
-               if (width > pdev->view_max.x || height > pdev->view_max.y)
-               {
-                       Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
-                       return -1;
-               }
-       }
-
-       /* Find the largest size supported by the camera that fits into the
-          requested size.
-        */
-       find = -1;
-       for (i = 0; i < PSZ_MAX; i++) {
-               if (pdev->image_mask & (1 << i)) {
-                       if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height)
-                               find = i;
-               }
-       }
-       return find;
-}
-
-/* initialize variables depending on type and decompressor*/
-void pwc_construct(struct pwc_device *pdev)
-{
-       switch(pdev->type) {
-       case 645:
-       case 646:
-               pdev->view_min.x = 128;
-               pdev->view_min.y =  96;
-               pdev->view_max.x = 352;
-               pdev->view_max.y = 288;
-                pdev->abs_max.x  = 352;
-                pdev->abs_max.y  = 288;
-               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF;
-               pdev->vcinterface = 2;
-               pdev->vendpoint = 4;
-               pdev->frame_header_size = 0;
-               pdev->frame_trailer_size = 0;
-               break;
-       case 675:
-       case 680:
-       case 690:
-               pdev->view_min.x = 128;
-               pdev->view_min.y =  96;
-               /* Anthill bug #38: PWC always reports max size, even without PWCX */
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
-               pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA;
-                pdev->abs_max.x = 640;
-                pdev->abs_max.y = 480;
-               pdev->vcinterface = 3;
-               pdev->vendpoint = 4;
-               pdev->frame_header_size = 0;
-               pdev->frame_trailer_size = 0;
-               break;
-       case 720:
-       case 730:
-       case 740:
-       case 750:
-               pdev->view_min.x = 160;
-               pdev->view_min.y = 120;
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
-               pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
-                pdev->abs_max.x = 640;
-                pdev->abs_max.y = 480;
-               pdev->vcinterface = 3;
-               pdev->vendpoint = 5;
-               pdev->frame_header_size = TOUCAM_HEADER_SIZE;
-               pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
-               break;
-       }
-       Debug("type = %d\n",pdev->type);
-       pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
-       pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
-       pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
-       /* length of image, in YUV format; always allocate enough memory. */
-       pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
-}
-
-
diff --git a/drivers/usb/media/pwc/pwc-nala.h b/drivers/usb/media/pwc/pwc-nala.h
deleted file mode 100644 (file)
index e6c5cb6..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-   /* SQCIF */
-   {
-      {0, 0, {0x04, 0x01, 0x03}},
-      {8, 0, {0x05, 0x01, 0x03}},
-      {7, 0, {0x08, 0x01, 0x03}},
-      {7, 0, {0x0A, 0x01, 0x03}},
-      {6, 0, {0x0C, 0x01, 0x03}},
-      {5, 0, {0x0F, 0x01, 0x03}},
-      {4, 0, {0x14, 0x01, 0x03}},
-      {3, 0, {0x18, 0x01, 0x03}},
-   },
-   /* QSIF */
-   {
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-   },
-   /* QCIF */
-   {
-      {0, 0, {0x04, 0x01, 0x02}},
-      {8, 0, {0x05, 0x01, 0x02}},
-      {7, 0, {0x08, 0x01, 0x02}},
-      {6, 0, {0x0A, 0x01, 0x02}},
-      {5, 0, {0x0C, 0x01, 0x02}},
-      {4, 0, {0x0F, 0x01, 0x02}},
-      {1, 0, {0x14, 0x01, 0x02}},
-      {1, 0, {0x18, 0x01, 0x02}},
-   },
-   /* SIF */
-   {
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-   },
-   /* CIF */
-   {
-      {4, 0, {0x04, 0x01, 0x01}},
-      {7, 1, {0x05, 0x03, 0x01}},
-      {6, 1, {0x08, 0x03, 0x01}},
-      {4, 1, {0x0A, 0x03, 0x01}},
-      {3, 1, {0x0C, 0x03, 0x01}},
-      {2, 1, {0x0F, 0x03, 0x01}},
-      {0},
-      {0},
-   },
-   /* VGA */
-   {  
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-      {0},
-   },
diff --git a/drivers/usb/media/pwc/pwc-timon.c b/drivers/usb/media/pwc/pwc-timon.c
deleted file mode 100644 (file)
index dee9671..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-/* This tables contains entries for the 675/680/690 (Timon) camera, with
-   4 different qualities (no compression, low, medium, high).
-   It lists the bandwidth requirements for said mode by its alternate interface
-   number. An alternate of 0 means that the mode is unavailable.
-
-   There are 6 * 4 * 4 entries:
-     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
-     6 framerates: 5, 10, 15, 20, 25, 30
-     4 compression modi: none, low, medium, high
-
-   When an uncompressed mode is not available, the next available compressed mode
-   will be chosen (unless the decompressor is absent). Sometimes there are only
-   1 or 2 compressed modes available; in that case entries are duplicated.
-*/
-
-#include "pwc-timon.h"
-
-const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
-{
-   /* SQCIF */
-   {
-      /* 5 fps */
-      {
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-         {1, 140,    0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-         {2, 280,    0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-         {3, 410,    0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-         {4, 559,    0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-         {5, 659,    0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-         {7, 838,    0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}},
-      },
-   },
-   /* QSIF */
-   {
-      /* 5 fps */
-      {
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-         {1, 146,    0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {2, 291,    0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}},
-         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-         {1, 191,  630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {3, 437,    0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}},
-         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {2, 291,  640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {1, 191,  420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {4, 588,    0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}},
-         {3, 447,  730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
-         {1, 192,  312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {5, 703,    0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}},
-         {3, 447,  610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
-         {1, 192,  262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {8, 873,    0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}},
-         {5, 704,  774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}},
-         {3, 448,  492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}},
-         {2, 291,  320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
-      },
-   },
-   /* QCIF */
-   {
-      /* 5 fps */
-      {
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-         {1, 193,    0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {3, 385,    0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}},
-         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {2, 291,  800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}},
-         {1, 194,  532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {4, 577,    0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}},
-         {3, 447,  818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}},
-         {1, 195,  356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {6, 776,    0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}},
-         {4, 591,  804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}},
-         {3, 447,  608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 291,  396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {9, 928,    0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}},
-         {5, 703,  800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}},
-         {3, 447,  508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}},
-         {2, 292,  332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 956,  876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}},
-         {4, 592,  542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}},
-         {2, 291,  266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}},
-      },
-   },
-   /* SIF */
-   {
-      /* 5 fps */
-      {
-         {4, 582,    0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}},
-         {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}},
-         {2, 291,  960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}},
-         {1, 191,  630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}},
-         {3, 447,  736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}},
-         {2, 291,  480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}},
-         {4, 591,  650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}},
-         {3, 448,  492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {9, 958,  782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}},
-         {5, 703,  574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}},
-         {3, 446,  364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}},
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {9, 958,  654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}},
-         {6, 776,  530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}},
-         {4, 592,  404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}},
-         {6, 775,  426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}},
-         {4, 590,  324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}},
-      },
-   },
-   /* CIF */
-   {
-      /* 5 fps */
-      {
-         {6, 771,    0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}},
-         {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}},
-         {2, 291,  800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}},
-         {1, 193,  528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}},
-         {4, 591,  812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}},
-         {2, 291,  400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 956,  876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}},
-         {5, 703,  644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}},
-         {3, 448,  410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {9, 956,  650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}},
-         {6, 776,  528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}},
-         {4, 591,  402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}},
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {9, 956,  544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}},
-         {7, 840,  478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}},
-         {5, 703,  400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}},
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {9, 956,  438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}},
-         {7, 838,  384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}},
-         {6, 773,  354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}},
-      },
-   },
-   /* VGA */
-   {
-      /* 5 fps */
-      {
-         {0, },
-         {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}},
-         {4, 592,  976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}},
-         {3, 448,  738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}},
-      },
-      /* 10 fps */
-      {
-         {0, },
-         {9, 956,  788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}},
-         {6, 776,  640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}},
-         {4, 592,  488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}},
-      },
-      /* 15 fps */
-      {
-         {0, },
-         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
-         {9, 957,  526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}},
-         {8, 895,  492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}},
-      },
-      /* 20 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 25 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-      /* 30 fps */
-      {
-         {0, },
-         {0, },
-         {0, },
-         {0, },
-      },
-   },
-};
-
diff --git a/drivers/usb/media/pwc/pwc-timon.h b/drivers/usb/media/pwc/pwc-timon.h
deleted file mode 100644 (file)
index a86b378..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-
-
-/* This tables contains entries for the 675/680/690 (Timon) camera, with
-   4 different qualities (no compression, low, medium, high).
-   It lists the bandwidth requirements for said mode by its alternate interface
-   number. An alternate of 0 means that the mode is unavailable.
-
-   There are 6 * 4 * 4 entries:
-     6 different resolutions subqcif, qsif, qcif, sif, cif, vga
-     6 framerates: 5, 10, 15, 20, 25, 30
-     4 compression modi: none, low, medium, high
-
-   When an uncompressed mode is not available, the next available compressed mode
-   will be chosen (unless the decompressor is absent). Sometimes there are only
-   1 or 2 compressed modes available; in that case entries are duplicated.
-*/
-
-#ifndef PWC_TIMON_H
-#define PWC_TIMON_H
-
-#include "pwc-ioctl.h"
-
-struct Timon_table_entry
-{
-       char alternate;                 /* USB alternate interface */
-       unsigned short packetsize;      /* Normal packet size */
-       unsigned short bandlength;      /* Bandlength when decompressing */
-       unsigned char mode[13];         /* precomputed mode settings for cam */
-};
-
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
-
-
-#endif
-
-
diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c
deleted file mode 100644 (file)
index ef4204e..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Linux driver for Philips webcam
-   Decompression frontend.
-   (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#include <asm/current.h>
-#include <asm/types.h>
-
-#include "pwc.h"
-#include "pwc-uncompress.h"
-
-int pwc_decompress(struct pwc_device *pdev)
-{
-       struct pwc_frame_buf *fbuf;
-       int n, line, col, stride;
-       void *yuv, *image;
-       u16 *src;
-       u16 *dsty, *dstu, *dstv;
-
-       if (pdev == NULL)
-               return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
-       if (pdev->magic != PWC_MAGIC) {
-               Err("pwc_decompress(): magic failed.\n");
-               return -EFAULT;
-       }
-#endif
-
-       fbuf = pdev->read_frame;
-       if (fbuf == NULL)
-               return -EFAULT;
-       image = pdev->image_ptr[pdev->fill_image];
-       if (!image)
-               return -EFAULT;
-
-       yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
-
-       /* Raw format; that's easy... */
-       if (pdev->vpalette == VIDEO_PALETTE_RAW)
-       {
-               memcpy(image, yuv, pdev->frame_size);
-               return 0;
-       }
-
-       if (pdev->vbandlength == 0) {
-               /* Uncompressed mode. We copy the data into the output buffer,
-                  using the viewport size (which may be larger than the image
-                  size). Unfortunately we have to do a bit of byte stuffing
-                  to get the desired output format/size.
-                */
-                       /*
-                        * We do some byte shuffling here to go from the
-                        * native format to YUV420P.
-                        */
-                       src = (u16 *)yuv;
-                       n = pdev->view.x * pdev->view.y;
-
-                       /* offset in Y plane */
-                       stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
-                       dsty = (u16 *)(image + stride);
-
-                       /* offsets in U/V planes */
-                       stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
-                       dstu = (u16 *)(image + n +         stride);
-                       dstv = (u16 *)(image + n + n / 4 + stride);
-
-                       /* increment after each line */
-                       stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
-                       for (line = 0; line < pdev->image.y; line++) {
-                               for (col = 0; col < pdev->image.x; col += 4) {
-                                       *dsty++ = *src++;
-                                       *dsty++ = *src++;
-                                       if (line & 1)
-                                               *dstv++ = *src++;
-                                       else
-                                               *dstu++ = *src++;
-                               }
-                               dsty += stride;
-                               if (line & 1)
-                                       dstv += (stride >> 1);
-                               else
-                                       dstu += (stride >> 1);
-                       }
-       }
-       else {
-               /* Compressed; the decompressor routines will write the data
-                  in planar format immediately.
-                */
-               int flags;
-                
-                flags = PWCX_FLAG_PLANAR;
-                if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
-                {
-                  printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
-                  flags |= PWCX_FLAG_BAYER;
-                  return -ENXIO; /* No such device or address: missing decompressor */
-                }
-
-#if 0
-               switch (pdev->type)
-                {
-                 case 675:
-                 case 680:
-                 case 690:
-                 case 720:
-                 case 730:
-                 case 740:
-                 case 750:
-                   pwc_dec23_decompress(&pdev->image, &pdev->view,
-                               &pdev->offset, yuv, image, flags,
-                               pdev->decompress_data, pdev->vbandlength);
-                   break;
-                 case 645:
-                 case 646:
-                   /* TODO & FIXME */
-                   return -ENXIO; /* Missing decompressor */
-                   break;
-                }
-#endif
-       }
-       return 0;
-}
-
-
diff --git a/drivers/usb/media/pwc/pwc-uncompress.h b/drivers/usb/media/pwc/pwc-uncompress.h
deleted file mode 100644 (file)
index d3b9250..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-/* This file is the bridge between the kernel module and the plugin; it
-   describes the structures and datatypes used in both modules. Any
-   significant change should be reflected by increasing the 
-   pwc_decompressor_version major number.
- */
-#ifndef PWC_UNCOMPRESS_H
-#define PWC_UNCOMPRESS_H
-
-#include <linux/config.h>
-
-#include "pwc-ioctl.h"
-
-/* from pwc-dec.h */
-#define PWCX_FLAG_PLANAR        0x0001
-/* */
-
-#endif
diff --git a/drivers/usb/media/pwc/pwc.h b/drivers/usb/media/pwc/pwc.h
deleted file mode 100644 (file)
index 6dd76bb..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
-
-   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
-   driver and thus may have bugs that are not present in the original version.
-   Please send bug reports and support requests to <luc@saillard.org>.
-   The decompression routines have been implemented by reverse-engineering the
-   Nemosoft binary pwcx module. Caveat emptor.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-*/
-
-#ifndef PWC_H
-#define PWC_H
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/spinlock.h>
-#include <linux/videodev.h>
-#include <linux/wait.h>
-#include <linux/smp_lock.h>
-#include <asm/semaphore.h>
-#include <asm/errno.h>
-
-#include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
-
-/* Turn some debugging options on/off */
-#define PWC_DEBUG 0
-
-/* Trace certain actions in the driver */
-#define TRACE_MODULE   0x0001
-#define TRACE_PROBE    0x0002
-#define TRACE_OPEN     0x0004
-#define TRACE_READ     0x0008
-#define TRACE_MEMORY   0x0010
-#define TRACE_FLOW     0x0020
-#define TRACE_SIZE     0x0040
-#define TRACE_PWCX     0x0080
-#define TRACE_SEQUENCE 0x1000
-
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
-#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
-
-
-/* Defines for ToUCam cameras */
-#define TOUCAM_HEADER_SIZE             8
-#define TOUCAM_TRAILER_SIZE            4
-
-#define FEATURE_MOTOR_PANTILT          0x0001
-
-/* Version block */
-#define PWC_MAJOR      9
-#define PWC_MINOR      0
-#define PWC_VERSION    "9.0.2-unofficial"
-#define PWC_NAME       "pwc"
-
-/* Turn certain features on/off */
-#define PWC_INT_PIPE 0
-
-/* Ignore errors in the first N frames, to allow for startup delays */
-#define FRAME_LOWMARK 5
-
-/* Size and number of buffers for the ISO pipe. */
-#define MAX_ISO_BUFS           2
-#define ISO_FRAMES_PER_DESC    10
-#define ISO_MAX_FRAME_SIZE     960
-#define ISO_BUFFER_SIZE        (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
-
-/* Frame buffers: contains compressed or uncompressed video data. */
-#define MAX_FRAMES             5
-/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */
-#define PWC_FRAME_SIZE                 (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE)
-
-/* Absolute maximum number of buffers available for mmap() */
-#define MAX_IMAGES             10
-
-/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
-struct pwc_iso_buf
-{
-       void *data;
-       int  length;
-       int  read;
-       struct urb *urb;
-};
-
-/* intermediate buffers with raw data from the USB cam */
-struct pwc_frame_buf
-{
-   void *data;
-   volatile int filled;                /* number of bytes filled */
-   struct pwc_frame_buf *next; /* list */
-#if PWC_DEBUG
-   int sequence;               /* Sequence number */
-#endif
-};
-
-struct pwc_device
-{
-   struct video_device *vdev;
-#ifdef PWC_MAGIC
-   int magic;
-#endif
-   /* Pointer to our usb_device */
-   struct usb_device *udev;
-   
-   int type;                    /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
-   int release;                        /* release number */
-   int features;               /* feature bits */
-   char serial[30];            /* serial number (string) */
-   int error_status;           /* set when something goes wrong with the cam (unplugged, USB errors) */
-   int usb_init;               /* set when the cam has been initialized over USB */
-
-   /*** Video data ***/
-   int vopen;                  /* flag */
-   int vendpoint;              /* video isoc endpoint */
-   int vcinterface;            /* video control interface */
-   int valternate;             /* alternate interface needed */
-   int vframes, vsize;         /* frames-per-second & size (see PSZ_*) */
-   int vpalette;               /* palette: 420P, RAW or RGBBAYER */
-   int vframe_count;           /* received frames */
-   int vframes_dumped;                 /* counter for dumped frames */
-   int vframes_error;          /* frames received in error */
-   int vmax_packet_size;       /* USB maxpacket size */
-   int vlast_packet_size;      /* for frame synchronisation */
-   int visoc_errors;           /* number of contiguous ISOC errors */
-   int vcompression;           /* desired compression factor */
-   int vbandlength;            /* compressed band length; 0 is uncompressed */
-   char vsnapshot;             /* snapshot mode */
-   char vsync;                 /* used by isoc handler */
-   char vmirror;               /* for ToUCaM series */
-   
-   int cmd_len;
-   unsigned char cmd_buf[13];
-
-   /* The image acquisition requires 3 to 4 steps:
-      1. data is gathered in short packets from the USB controller
-      2. data is synchronized and packed into a frame buffer
-      3a. in case data is compressed, decompress it directly into image buffer
-      3b. in case data is uncompressed, copy into image buffer with viewport
-      4. data is transferred to the user process
-
-      Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES....
-      We have in effect a back-to-back-double-buffer system.
-    */
-   /* 1: isoc */
-   struct pwc_iso_buf sbuf[MAX_ISO_BUFS];
-   char iso_init;
-
-   /* 2: frame */
-   struct pwc_frame_buf *fbuf; /* all frames */
-   struct pwc_frame_buf *empty_frames, *empty_frames_tail;     /* all empty frames */
-   struct pwc_frame_buf *full_frames, *full_frames_tail;       /* all filled frames */
-   struct pwc_frame_buf *fill_frame;   /* frame currently being filled */
-   struct pwc_frame_buf *read_frame;   /* frame currently read by user process */
-   int frame_header_size, frame_trailer_size;
-   int frame_size;
-   int frame_total_size; /* including header & trailer */
-   int drop_frames;
-#if PWC_DEBUG
-   int sequence;                       /* Debugging aid */
-#endif
-
-   /* 3: decompression */
-   struct pwc_decompressor *decompressor;      /* function block with decompression routines */
-   void *decompress_data;              /* private data for decompression engine */
-
-   /* 4: image */
-   /* We have an 'image' and a 'view', where 'image' is the fixed-size image
-      as delivered by the camera, and 'view' is the size requested by the
-      program. The camera image is centered in this viewport, laced with
-      a gray or black border. view_min <= image <= view <= view_max;
-    */
-   int image_mask;                     /* bitmask of supported sizes */
-   struct pwc_coord view_min, view_max;        /* minimum and maximum viewable sizes */
-   struct pwc_coord abs_max;            /* maximum supported size with compression */
-   struct pwc_coord image, view;       /* image and viewport size */
-   struct pwc_coord offset;            /* offset within the viewport */
-
-   void *image_data;                   /* total buffer, which is subdivided into ... */
-   void *image_ptr[MAX_IMAGES];                /* ...several images... */
-   int fill_image;                     /* ...which are rotated. */
-   int len_per_image;                  /* length per image */
-   int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
-   int image_used[MAX_IMAGES];         /* For MCAPTURE and SYNC */
-
-   struct semaphore modlock;           /* to prevent races in video_open(), etc */
-   spinlock_t ptrlock;                 /* for manipulating the buffer pointers */
-
-   /*** motorized pan/tilt feature */
-   struct pwc_mpt_range angle_range;
-   int pan_angle;                      /* in degrees * 100 */
-   int tilt_angle;                     /* absolute angle; 0,0 is home position */
-
-   /*** Misc. data ***/
-   wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
-#if PWC_INT_PIPE
-   void *usb_int_handler;              /* for the interrupt endpoint */
-#endif
-};
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Global variable */
-extern int pwc_trace;
-
-/** functions in pwc-if.c */
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
-
-/** Functions in pwc-misc.c */
-/* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
-
-int pwc_decode_size(struct pwc_device *pdev, int width, int height);
-void pwc_construct(struct pwc_device *pdev);
-
-/** Functions in pwc-ctrl.c */
-/* Request a certain video mode. Returns < 0 if not possible */
-extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
-
-/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
-extern int pwc_get_brightness(struct pwc_device *pdev);
-extern int pwc_set_brightness(struct pwc_device *pdev, int value);
-extern int pwc_get_contrast(struct pwc_device *pdev);
-extern int pwc_set_contrast(struct pwc_device *pdev, int value);
-extern int pwc_get_gamma(struct pwc_device *pdev);
-extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
-extern int pwc_set_saturation(struct pwc_device *pdev, int value);
-extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
-extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
-
-/* Power down or up the camera; not supported by all models */
-extern int pwc_camera_power(struct pwc_device *pdev, int power);
-
-/* Private ioctl()s; see pwc-ioctl.h */
-extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
-
-
-/** pwc-uncompress.c */
-/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
-extern int pwc_decompress(struct pwc_device *pdev);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif
diff --git a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
deleted file mode 100644 (file)
index f03ea7f..0000000
+++ /dev/null
@@ -1,1435 +0,0 @@
-/*
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- *
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
- * their chipset available and supporting me while writing this driver.
- *     - Jeroen Vreeken
- */
-
-static const char version[] = "0.24";
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/usb.h>
-#include "se401.h"
-
-static int flickerless=0;
-static int video_nr = -1;
-
-static struct usb_device_id device_table [] = {
-       { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
-       { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
-       { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
-       { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
-       { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, device_table);
-
-MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
-MODULE_DESCRIPTION("SE401 USB Camera Driver");
-MODULE_LICENSE("GPL");
-module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
-module_param(video_nr, int, 0);
-
-static struct usb_driver se401_driver;
-
-
-/**********************************************************************
- *
- * Memory management
- *
- **********************************************************************/
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-
-
-/****************************************************************************
- *
- * se401 register read/write functions
- *
- ***************************************************************************/
-
-static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
-                        unsigned short value, unsigned char *cp, int size)
-{
-       return usb_control_msg (
-                se401->dev,
-                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
-                req,
-                (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                value,
-                0,
-                cp,
-                size,
-                1000
-        );
-}
-
-static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
-                            unsigned short param)
-{
-       /* specs say that the selector (address) should go in the value field
-          and the param in index, but in the logs of the windows driver they do
-          this the other way around...
-        */
-       return usb_control_msg (
-               se401->dev,
-               usb_sndctrlpipe(se401->dev, 0),
-               SE401_REQ_SET_EXT_FEATURE,
-               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               param,
-               selector,
-                NULL,
-                0,
-                1000
-        );
-}
-
-static unsigned short se401_get_feature(struct usb_se401 *se401, 
-                                       unsigned short selector)
-{
-       /* For 'set' the selecetor should be in index, not sure if the spec is
-          wrong here to....
-        */
-       unsigned char cp[2];
-        usb_control_msg (
-                se401->dev,
-                usb_rcvctrlpipe(se401->dev, 0),
-                SE401_REQ_GET_EXT_FEATURE,
-                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0,
-                selector,
-                cp,
-                2,
-                1000
-        );
-       return cp[0]+cp[1]*256;
-}
-
-/****************************************************************************
- *
- * Camera control
- *
- ***************************************************************************/
-
-
-static int se401_send_pict(struct usb_se401 *se401)
-{
-       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
-       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
-       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
-       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
-       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
-               
-       return 0;
-}
-
-static void se401_set_exposure(struct usb_se401 *se401, int brightness)
-{
-       int integration=brightness<<5;
-       
-       if (flickerless==50) {
-               integration=integration-integration%106667;
-       }
-       if (flickerless==60) {
-               integration=integration-integration%88889;
-       }
-       se401->brightness=integration>>5;
-       se401->expose_h=(integration>>16)&0xff;
-       se401->expose_m=(integration>>8)&0xff;
-       se401->expose_l=integration&0xff;
-}
-
-static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
-{
-       p->brightness=se401->brightness;
-       if (se401->enhance) {
-               p->whiteness=32768;
-       } else {
-               p->whiteness=0;
-       }
-       p->colour=65535;
-       p->contrast=65535;
-       p->hue=se401->rgain<<10;
-       p->palette=se401->palette;
-       p->depth=3; /* rgb24 */
-       return 0;
-}
-
-
-static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
-{
-       if (p->palette != VIDEO_PALETTE_RGB24)
-               return 1;
-       se401->palette=p->palette;
-       if (p->hue!=se401->hue) {
-               se401->rgain= p->hue>>10;
-               se401->bgain= 0x40-(p->hue>>10);
-               se401->hue=p->hue;
-       }
-       if (p->brightness!=se401->brightness) {
-               se401_set_exposure(se401, p->brightness);
-       }
-       if (p->whiteness>=32768) {
-               se401->enhance=1;
-       } else {
-               se401->enhance=0;
-       }
-       se401_send_pict(se401);
-       se401_send_pict(se401);
-       return 0;
-}
-
-/*
-       Hyundai have some really nice docs about this and other sensor related
-       stuff on their homepage: www.hei.co.kr
-*/
-static void se401_auto_resetlevel(struct usb_se401 *se401)
-{
-       unsigned int ahrc, alrc;
-       int oldreset=se401->resetlevel;
-
-       /* For some reason this normally read-only register doesn't get reset
-          to zero after reading them just once...
-        */
-       se401_get_feature(se401, HV7131_REG_HIREFNOH); 
-       se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       se401_get_feature(se401, HV7131_REG_LOREFNOH);
-       se401_get_feature(se401, HV7131_REG_LOREFNOL);
-       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + 
-           se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
-           se401_get_feature(se401, HV7131_REG_LOREFNOL);
-
-       /* Not an exact science, but it seems to work pretty well... */
-       if (alrc > 10) {
-               while (alrc>=10 && se401->resetlevel < 63) {
-                       se401->resetlevel++;
-                       alrc /=2;
-               }
-       } else if (ahrc > 20) {
-               while (ahrc>=20 && se401->resetlevel > 0) {
-                       se401->resetlevel--;
-                       ahrc /=2;
-               }
-       }
-       if (se401->resetlevel!=oldreset)
-               se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
-
-       return;
-}
-
-/* irq handler for snapshot button */
-static void se401_button_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_se401 *se401 = urb->context;
-       int status;
-       
-       if (!se401->dev) {
-               info("ohoh: device vapourished");
-               return;
-       }
-       
-       switch (urb->status) {
-       case 0:
-               /* success */
-               break;
-       case -ECONNRESET:
-       case -ENOENT:
-       case -ESHUTDOWN:
-               /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-               return;
-       default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-               goto exit;
-       }
-
-       if (urb->actual_length >=2) {
-               if (se401->button)
-                       se401->buttonpressed=1;
-       }
-exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
-               err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, status);
-}
-
-static void se401_video_irq(struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_se401 *se401 = urb->context;
-       int length = urb->actual_length;
-
-       /* ohoh... */
-       if (!se401->streaming)
-               return;
-
-       if (!se401->dev) {
-               info ("ohoh: device vapourished");
-               return;
-       }
-
-       /* 0 sized packets happen if we are to fast, but sometimes the camera
-          keeps sending them forever...
-        */
-       if (length && !urb->status) {
-               se401->nullpackets=0;
-               switch(se401->scratch[se401->scratch_next].state) {
-                       case BUFFER_READY:
-                       case BUFFER_BUSY: {
-                               se401->dropped++;
-                               break;
-                       }
-                       case BUFFER_UNUSED: {
-                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
-                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
-                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
-                               se401->scratch[se401->scratch_next].length=length;
-                               if (waitqueue_active(&se401->wq)) {
-                                       wake_up_interruptible(&se401->wq);
-                               }
-                               se401->scratch_overflow=0;
-                               se401->scratch_next++;
-                               if (se401->scratch_next>=SE401_NUMSCRATCH)
-                                       se401->scratch_next=0;
-                               break;
-                       }
-               }
-               se401->bayeroffset+=length;
-               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
-                       se401->bayeroffset=0;
-               }
-       } else {
-               se401->nullpackets++;
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       if (waitqueue_active(&se401->wq)) {
-                               wake_up_interruptible(&se401->wq);
-                       }               
-               }
-       }
-
-       /* Resubmit urb for new data */
-       urb->status=0;
-       urb->dev=se401->dev;
-       if(usb_submit_urb(urb, GFP_KERNEL))
-               info("urb burned down");
-       return;
-}
-
-static void se401_send_size(struct usb_se401 *se401, int width, int height)
-{
-       int i=0;
-       int mode=0x03; /* No compression */
-       int sendheight=height;
-       int sendwidth=width;
-
-       /* JangGu compression can only be used with the camera supported sizes,
-          but bayer seems to work with any size that fits on the sensor.
-          We check if we can use compression with the current size with either
-          4 or 16 times subcapturing, if not we use uncompressed bayer data
-          but this will result in cutouts of the maximum size....
-        */
-       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
-               i++;
-       while (i<se401->sizes) {
-               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x40;
-               }
-               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x42;
-               }
-               i++;
-       }
-
-       se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
-       se401_set_feature(se401, SE401_OPERATINGMODE, mode);
-
-       if (mode==0x03) {
-               se401->format=FMT_BAYER;
-       } else {
-               se401->format=FMT_JANGGU;
-       }
-
-       return;
-}
-
-/*
-       In this function se401_send_pict is called several times,
-       for some reason (depending on the state of the sensor and the phase of
-       the moon :) doing this only in either place doesn't always work...
-*/
-static int se401_start_stream(struct usb_se401 *se401)
-{
-       struct urb *urb;
-       int err=0, i;
-       se401->streaming=1;
-
-        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
-        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
-       /* Set picture settings */
-       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
-       se401_send_pict(se401);
-
-       se401_send_size(se401, se401->cwidth, se401->cheight);
-
-       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
-
-       /* Do some memory allocation */
-       for (i=0; i<SE401_NUMFRAMES; i++) {
-               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
-               se401->frame[i].curpix=0;
-       }
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
-       }
-
-       se401->bayeroffset=0;
-       se401->scratch_next=0;
-       se401->scratch_use=0;
-       se401->scratch_overflow=0;
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
-               se401->scratch[i].state=BUFFER_UNUSED;
-       }
-
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               urb=usb_alloc_urb(0, GFP_KERNEL);
-               if(!urb)
-                       return -ENOMEM;
-
-               usb_fill_bulk_urb(urb, se401->dev,
-                       usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
-                       se401->sbuf[i].data, SE401_PACKETSIZE,
-                       se401_video_irq,
-                       se401);
-
-               se401->urb[i]=urb;
-
-               err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
-               if(err)
-                       err("urb burned down");
-       }
-
-       se401->framecount=0;
-
-       return 0;
-}
-
-static int se401_stop_stream(struct usb_se401 *se401)
-{
-       int i;
-
-       if (!se401->streaming || !se401->dev)
-               return 1;
-
-       se401->streaming=0;
-
-       se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
-
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-
-       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
-               usb_kill_urb(se401->urb[i]);
-               usb_free_urb(se401->urb[i]);
-               se401->urb[i]=NULL;
-               kfree(se401->sbuf[i].data);
-       }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               kfree(se401->scratch[i].data);
-               se401->scratch[i].data=NULL;
-       }
-
-       return 0;
-}
-
-static int se401_set_size(struct usb_se401 *se401, int width, int height)
-{
-       int wasstreaming=se401->streaming;
-       /* Check to see if we need to change */
-       if (se401->cwidth==width && se401->cheight==height)
-               return 0;
-
-       /* Check for a valid mode */
-       if (!width || !height)
-               return 1;
-       if ((width & 1) || (height & 1))
-               return 1;
-       if (width>se401->width[se401->sizes-1])
-               return 1;
-       if (height>se401->height[se401->sizes-1])
-               return 1;
-
-       /* Stop a current stream and start it again at the new size */
-       if (wasstreaming)
-               se401_stop_stream(se401);
-       se401->cwidth=width;
-       se401->cheight=height;
-       if (wasstreaming)
-               se401_start_stream(se401);
-       return 0;
-}
-
-
-/****************************************************************************
- *
- * Video Decoding
- *
- ***************************************************************************/
-
-/*
-       This shouldn't really be done in a v4l driver....
-       But it does make the image look a lot more usable.
-       Basically it lifts the dark pixels more than the light pixels.
-*/
-static inline void enhance_picture(unsigned char *frame, int len)
-{
-       while (len--) {
-               *frame=(((*frame^255)*(*frame^255))/255)^255;
-               frame++;
-       }
-}
-
-static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
-{
-       struct se401_frame *frame=&se401->frame[se401->curframe];
-       int linelength=se401->cwidth*3;
-
-       if (frame->curlinepix >= linelength) {
-               frame->curlinepix=0;
-               frame->curline+=linelength;
-       }
-
-       /* First three are absolute, all others relative.
-        * Format is rgb from right to left (mirrorred image), 
-        * we flip it to get bgr from left to right. */
-       if (frame->curlinepix < 3) {
-               *(frame->curline-frame->curlinepix)=1+data*4;
-       } else {
-               *(frame->curline-frame->curlinepix)=
-                   *(frame->curline-frame->curlinepix+3)+data*4;
-       }
-       frame->curlinepix++;
-}
-
-static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
-{
-       int pos=0;
-       int vlc_cod=0;
-       int vlc_size=0;
-       int vlc_data=0;
-       int bit_cur;
-       int bit;
-       data+=4;
-       while (pos < packetlength) {
-               bit_cur=8;
-               while (bit_cur && bit_exp) {
-                       bit=((*data)>>(bit_cur-1))&1;
-                       if (!vlc_cod) {
-                               if (bit) {
-                                       vlc_size++;
-                               } else {
-                                       if (!vlc_size) {
-                                               decode_JangGu_integrate(se401, 0);
-                                       } else {
-                                               vlc_cod=2;
-                                               vlc_data=0;
-                                       }
-                               }
-                       } else {
-                               if (vlc_cod==2) {
-                                       if (!bit)
-                                               vlc_data =  -(1<<vlc_size) + 1;
-                                       vlc_cod--;
-                               }
-                               vlc_size--;
-                               vlc_data+=bit<<vlc_size;
-                               if (!vlc_size) {
-                                       decode_JangGu_integrate(se401, vlc_data);
-                                       vlc_cod=0;
-                               }
-                       }
-                       bit_cur--;
-                       bit_exp--;
-               }
-               pos++;
-               data++;
-       }
-}
-
-static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
-{
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
-       int datapos=0;
-
-       /* New image? */
-       if (!se401->frame[se401->curframe].curpix) {
-               se401->frame[se401->curframe].curlinepix=0;
-               se401->frame[se401->curframe].curline=
-                   se401->frame[se401->curframe].data+
-                   se401->cwidth*3-1;
-               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
-                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
-               se401->vlcdatapos=0;
-       }
-       while (datapos < len) {
-               size=1024-se401->vlcdatapos;
-               if (size+datapos > len)
-                       size=len-datapos;
-               memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
-               se401->vlcdatapos+=size;
-               packetlength=0;
-               if (se401->vlcdatapos >= 4) {
-                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
-                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
-                       frameinfo=se401->vlcdata[0]&0xc0;
-                       packetlength=((bit_exp+47)>>4)<<1;
-                       if (packetlength > 1024) {
-                               se401->vlcdatapos=0;
-                               datapos=len;
-                               packetlength=0;
-                               se401->error++;
-                               se401->frame[se401->curframe].curpix=0;
-                       }
-               }
-               if (packetlength && se401->vlcdatapos >= packetlength) {
-                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
-                       se401->frame[se401->curframe].curpix+=pix_exp*3;
-                       datapos+=size-(se401->vlcdatapos-packetlength);
-                       se401->vlcdatapos=0;
-                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
-                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
-                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
-                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
-                                               se401->framecount++;
-                                               se401->readcount++;
-                                       }
-                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
-                                       }
-                               } else {
-                                       se401->error++;
-                               }
-                               se401->frame[se401->curframe].curpix=0;
-                               datapos=len;
-                       }
-               } else {
-                       datapos+=size;
-               }
-       }
-}
-
-static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
-{
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int offset=buffer->offset;
-       int datasize=se401->cwidth*se401->cheight;
-       struct se401_frame *frame=&se401->frame[se401->curframe];
-
-       unsigned char *framedata=frame->data, *curline, *nextline;
-       int width=se401->cwidth;
-       int blineoffset=0, bline;
-       int linelength=width*3, i;
-       
-
-       if (frame->curpix==0) {
-               if (frame->grabstate==FRAME_READY) {
-                       frame->grabstate=FRAME_GRABBING;
-               }
-               frame->curline=framedata+linelength;
-               frame->curlinepix=0;
-       }
-
-       if (offset!=frame->curpix) {
-               /* Regard frame as lost :( */
-               frame->curpix=0;
-               se401->error++;
-               return;
-       }
-
-       /* Check if we have to much data */
-       if (frame->curpix+len > datasize) {
-               len=datasize-frame->curpix;
-       }
-       if (se401->cheight%4)
-               blineoffset=1;
-       bline=frame->curpix/se401->cwidth+blineoffset;
-
-       curline=frame->curline;
-       nextline=curline+linelength;
-       if (nextline >= framedata+datasize*3)
-               nextline=curline;
-       while (len) {
-               if (frame->curlinepix>=width) {
-                       frame->curlinepix-=width;
-                       bline=frame->curpix/width+blineoffset;
-                       curline+=linelength*2;
-                       nextline+=linelength*2;
-                       if (curline >= framedata+datasize*3) {
-                               frame->curlinepix++;
-                               curline-=3;
-                               nextline-=3;
-                               len--;
-                               data++;
-                               frame->curpix++;
-                       }
-                       if (nextline >= framedata+datasize*3)
-                               nextline=curline;
-               }
-               if ((bline&1)) {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+2)=*data;
-                               *(curline-1)=*data;
-                               *(nextline+2)=*data;
-                               *(nextline-1)=*data;
-                       } else {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
-                       }
-               } else {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
-                       } else {
-                               *curline=*data;
-                               *(curline-3)=*data;
-                               *nextline=*data;
-                               *(nextline-3)=*data;
-                       }
-               }
-               frame->curlinepix++;
-               curline-=3;
-               nextline-=3;
-               len--;
-               data++;
-               frame->curpix++;
-       }
-       frame->curline=curline;
-
-       if (frame->curpix>=datasize) {
-               /* Fix the top line */
-               framedata+=linelength;
-               for (i=0; i<linelength; i++) {
-                       framedata--;
-                       *framedata=*(framedata+linelength);
-               }
-               /* Fix the left side (green is already present) */
-               for (i=0; i<se401->cheight; i++) {
-                       *framedata=*(framedata+3);
-                       *(framedata+1)=*(framedata+4);
-                       *(framedata+2)=*(framedata+5);
-                       framedata+=linelength;
-               }
-               frame->curpix=0;
-               frame->grabstate=FRAME_DONE;
-               se401->framecount++;
-               se401->readcount++;
-               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
-               }
-       }
-}
-
-static int se401_newframe(struct usb_se401 *se401, int framenr)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       int errors=0;
-
-       while (se401->streaming &&
-           (se401->frame[framenr].grabstate==FRAME_READY ||
-            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
-               if(!se401->frame[framenr].curpix) {
-                       errors++;
-               }
-               wait_interruptible(
-                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
-                   &se401->wq,
-                   &wait
-               );
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       se401->nullpackets=0;
-                       info("to many null length packets, restarting capture");
-                       se401_stop_stream(se401);
-                       se401_start_stream(se401);                      
-               } else {
-                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
-                               se401->frame[framenr].grabstate=FRAME_ERROR;
-                               return -EIO;
-                       }
-                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
-                       if (se401->format==FMT_JANGGU) {
-                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
-                       } else {
-                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
-                       }
-                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
-                       se401->scratch_use++;
-                       if (se401->scratch_use>=SE401_NUMSCRATCH)
-                               se401->scratch_use=0;
-                       if (errors > SE401_MAX_ERRORS) {
-                               errors=0;
-                               info("to much errors, restarting capture");
-                               se401_stop_stream(se401);
-                               se401_start_stream(se401);
-                       }
-               }
-       }
-
-       if (se401->frame[framenr].grabstate==FRAME_DONE)
-               if (se401->enhance)
-                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
-       return 0;
-}
-
-static void usb_se401_remove_disconnected (struct usb_se401 *se401)
-{
-       int i;
-
-        se401->dev = NULL;
-
-       for (i=0; i<SE401_NUMSBUF; i++)
-               if (se401->urb[i]) {
-                       usb_kill_urb(se401->urb[i]);
-                       usb_free_urb(se401->urb[i]);
-                       se401->urb[i] = NULL;
-                       kfree(se401->sbuf[i].data);
-               }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               kfree(se401->scratch[i].data);
-       }
-       if (se401->inturb) {
-               usb_kill_urb(se401->inturb);
-               usb_free_urb(se401->inturb);
-       }
-        info("%s disconnected", se401->camera_name);
-
-        /* Free the memory */
-       kfree(se401->width);
-       kfree(se401->height);
-       kfree(se401);
-}
-
-
-
-/****************************************************************************
- *
- * Video4Linux
- *
- ***************************************************************************/
-
-
-static int se401_open(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       int err = 0;
-
-       if (se401->user)
-               return -EBUSY;
-       se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
-       if (se401->fbuf)
-               file->private_data = dev;
-       else 
-               err = -ENOMEM;
-       se401->user = !err;
-
-       return err;
-}
-
-static int se401_close(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = file->private_data;
-        struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       int i;
-
-       rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
-        if (se401->removed) {
-               usb_se401_remove_disconnected(se401);
-               info("device unregistered");
-       } else {
-               for (i=0; i<SE401_NUMFRAMES; i++)
-                       se401->frame[i].grabstate=FRAME_UNUSED;
-               if (se401->streaming)
-                       se401_stop_stream(se401);
-               se401->user=0;
-       }
-       file->private_data = NULL;
-       return 0;
-}
-
-static int se401_do_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-        struct usb_se401 *se401 = (struct usb_se401 *)vdev;
-
-        if (!se401->dev)
-                return -EIO;
-
-        switch (cmd) {
-       case VIDIOCGCAP:
-       {
-               struct video_capability *b = arg;
-               strcpy(b->name, se401->camera_name);
-               b->type = VID_TYPE_CAPTURE;
-               b->channels = 1;
-               b->audios = 0;
-               b->maxwidth = se401->width[se401->sizes-1];
-               b->maxheight = se401->height[se401->sizes-1];
-               b->minwidth = se401->width[0];
-               b->minheight = se401->height[0];
-               return 0;
-       }
-       case VIDIOCGCHAN:
-       {
-               struct video_channel *v = arg;
-
-               if (v->channel != 0)
-                       return -EINVAL;
-               v->flags = 0;
-               v->tuners = 0;
-               v->type = VIDEO_TYPE_CAMERA;
-               strcpy(v->name, "Camera");
-               return 0;
-       }
-       case VIDIOCSCHAN:
-       {
-               struct video_channel *v = arg;
-
-               if (v->channel != 0)
-                       return -EINVAL;
-               return 0;
-       }
-        case VIDIOCGPICT:
-        {
-               struct video_picture *p = arg;
-
-               se401_get_pict(se401, p);
-               return 0;
-       }
-       case VIDIOCSPICT:
-       {
-               struct video_picture *p = arg;
-
-               if (se401_set_pict(se401, p))
-                       return -EINVAL;
-               return 0;
-       }
-       case VIDIOCSWIN:
-       {
-               struct video_window *vw = arg;
-
-               if (vw->flags)
-                       return -EINVAL;
-               if (vw->clipcount)
-                       return -EINVAL;
-               if (se401_set_size(se401, vw->width, vw->height))
-                       return -EINVAL;
-               return 0;
-        }
-       case VIDIOCGWIN:
-       {
-               struct video_window *vw = arg;
-
-               vw->x = 0;               /* FIXME */
-               vw->y = 0;
-               vw->chromakey = 0;
-               vw->flags = 0;
-               vw->clipcount = 0;
-               vw->width = se401->cwidth;
-               vw->height = se401->cheight;
-               return 0;
-       }
-       case VIDIOCGMBUF:
-       {
-               struct video_mbuf *vm = arg;
-               int i;
-
-               memset(vm, 0, sizeof(*vm));
-               vm->size = SE401_NUMFRAMES * se401->maxframesize;
-               vm->frames = SE401_NUMFRAMES;
-               for (i=0; i<SE401_NUMFRAMES; i++)
-                       vm->offsets[i] = se401->maxframesize * i;
-               return 0;
-       }
-       case VIDIOCMCAPTURE:
-       {
-               struct video_mmap *vm = arg;
-
-               if (vm->format != VIDEO_PALETTE_RGB24)
-                       return -EINVAL;
-               if (vm->frame >= SE401_NUMFRAMES)
-                       return -EINVAL;
-               if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
-                       return -EBUSY;
-
-               /* Is this according to the v4l spec??? */
-               if (se401_set_size(se401, vm->width, vm->height))
-                       return -EINVAL;
-               se401->frame[vm->frame].grabstate=FRAME_READY;
-
-               if (!se401->streaming)
-                       se401_start_stream(se401);
-
-               /* Set the picture properties */
-               if (se401->framecount==0)
-                       se401_send_pict(se401);
-               /* Calibrate the reset level after a few frames. */
-               if (se401->framecount%20==1)
-                       se401_auto_resetlevel(se401);
-
-               return 0;
-       }
-       case VIDIOCSYNC:
-       {
-               int *frame = arg;
-               int ret=0;
-
-               if(*frame <0 || *frame >= SE401_NUMFRAMES)
-                       return -EINVAL;
-
-               ret=se401_newframe(se401, *frame);
-               se401->frame[*frame].grabstate=FRAME_UNUSED;
-               return ret;
-       }
-       case VIDIOCGFBUF:
-       {
-               struct video_buffer *vb = arg;
-
-               memset(vb, 0, sizeof(*vb));
-               return 0;
-       }
-       case VIDIOCKEY:
-               return 0;
-       case VIDIOCCAPTURE:
-               return -EINVAL;
-       case VIDIOCSFBUF:
-               return -EINVAL;
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-               return -EINVAL;
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               return -EINVAL;
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-        default:
-                return -ENOIOCTLCMD;
-        } /* end switch */
-
-        return 0;
-}
-
-static int se401_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);
-}
-
-static ssize_t se401_read(struct file *file, char __user *buf,
-                    size_t count, loff_t *ppos)
-{
-       int realcount=count, ret=0;
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-
-
-       if (se401->dev == NULL)
-               return -EIO;
-       if (realcount > se401->cwidth*se401->cheight*3)
-               realcount=se401->cwidth*se401->cheight*3;
-
-       /* Shouldn't happen: */
-       if (se401->frame[0].grabstate==FRAME_GRABBING)
-               return -EBUSY;
-       se401->frame[0].grabstate=FRAME_READY;
-       se401->frame[1].grabstate=FRAME_UNUSED;
-       se401->curframe=0;
-
-       if (!se401->streaming)
-               se401_start_stream(se401);
-
-       /* Set the picture properties */
-       if (se401->framecount==0)
-               se401_send_pict(se401);
-       /* Calibrate the reset level after a few frames. */
-       if (se401->framecount%20==1)
-               se401_auto_resetlevel(se401);
-
-       ret=se401_newframe(se401, 0);
-
-       se401->frame[0].grabstate=FRAME_UNUSED;
-       if (ret)
-               return ret;     
-       if (copy_to_user(buf, se401->frame[0].data, realcount))
-               return -EFAULT;
-
-       return realcount;
-}
-
-static int se401_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_se401 *se401 = (struct usb_se401 *)dev;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       mutex_lock(&se401->lock);
-
-       if (se401->dev == NULL) {
-               mutex_unlock(&se401->lock);
-               return -EIO;
-       }
-       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-               mutex_unlock(&se401->lock);
-               return -EINVAL;
-       }
-       pos = (unsigned long)se401->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&se401->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       mutex_unlock(&se401->lock);
-
-        return 0;
-}
-
-static struct file_operations se401_fops = {
-       .owner =        THIS_MODULE,
-        .open =         se401_open,
-        .release =      se401_close,
-        .read =         se401_read,
-        .mmap =         se401_mmap,
-       .ioctl =        se401_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-static struct video_device se401_template = {
-       .owner =        THIS_MODULE,
-        .name =         "se401 USB camera",
-        .type =         VID_TYPE_CAPTURE,
-        .hardware =     VID_HARDWARE_SE401,
-       .fops =         &se401_fops,
-};
-
-
-
-/***************************/
-static int se401_init(struct usb_se401 *se401, int button)
-{
-        int i=0, rc;
-        unsigned char cp[0x40];
-       char temp[200];
-
-       /* led on */
-        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
-       /* get camera descriptor */
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
-       if (cp[1]!=0x41) {
-               err("Wrong descriptor type");
-               return 1;
-       }
-       sprintf (temp, "ExtraFeatures: %d", cp[3]);
-
-       se401->sizes=cp[4]+cp[5]*256;
-       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
-       if (!se401->width)
-               return 1;
-       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
-       if (!se401->height) {
-               kfree(se401->width);
-               return 1;
-       }
-       for (i=0; i<se401->sizes; i++) {
-                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
-                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
-       }
-       sprintf (temp, "%s Sizes:", temp);
-       for (i=0; i<se401->sizes; i++) {
-               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
-       }
-       info("%s", temp);
-       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
-
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
-       se401->cwidth=cp[0]+cp[1]*256;
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
-       se401->cheight=cp[0]+cp[1]*256;
-
-       if (!cp[2] && SE401_FORMAT_BAYER) {
-               err("Bayer format not supported!");
-               return 1;
-       }
-       /* set output mode (BAYER) */
-        se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
-
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
-       se401->brightness=cp[0]+cp[1]*256;
-       /* some default values */
-       se401->resetlevel=0x2d;
-       se401->rgain=0x20;
-       se401->ggain=0x20;
-       se401->bgain=0x20;
-       se401_set_exposure(se401, 20000);
-       se401->palette=VIDEO_PALETTE_RGB24;
-       se401->enhance=1;
-       se401->dropped=0;
-       se401->error=0;
-       se401->framecount=0;
-       se401->readcount=0;
-
-       /* Start interrupt transfers for snapshot button */
-       if (button) {
-               se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
-               if (!se401->inturb) {
-                       info("Allocation of inturb failed");
-                       return 1;
-               }
-               usb_fill_int_urb(se401->inturb, se401->dev,
-                   usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
-                   &se401->button, sizeof(se401->button),
-                   se401_button_irq,
-                   se401,
-                   8
-               );
-               if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
-                       info("int urb burned down");
-                       return 1;
-               }
-       } else
-               se401->inturb=NULL;
-
-        /* Flash the led */
-        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
-        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-       se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-
-        return 0;
-}
-
-static int se401_probe(struct usb_interface *intf,
-       const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-        struct usb_interface_descriptor *interface;
-        struct usb_se401 *se401;
-        char *camera_name=NULL;
-       int button=1;
-
-        /* We don't handle multi-config cameras */
-        if (dev->descriptor.bNumConfigurations != 1)
-                return -ENODEV;
-
-        interface = &intf->cur_altsetting->desc;
-
-        /* Is it an se401? */
-        if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
-            le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
-                camera_name="Endpoints/Aox SE401";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
-            le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
-                camera_name="Philips PCVC665K";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
-               camera_name="Kensington VideoCAM 67014";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
-               camera_name="Kensington VideoCAM 6701(5/7)";
-        } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
-               camera_name="Kensington VideoCAM 67016";
-               button=0;
-       } else
-               return -ENODEV;
-
-        /* Checking vendor/product should be enough, but what the hell */
-        if (interface->bInterfaceClass != 0x00)
-               return -ENODEV;
-        if (interface->bInterfaceSubClass != 0x00)
-               return -ENODEV;
-
-        /* We found one */
-        info("SE401 camera found: %s", camera_name);
-
-        if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
-                err("couldn't kmalloc se401 struct");
-               return -ENOMEM;
-        }
-
-        se401->dev = dev;
-        se401->iface = interface->bInterfaceNumber;
-        se401->camera_name = camera_name;
-
-       info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
-
-        if (se401_init(se401, button)) {
-               kfree(se401);
-               return -EIO;
-       }
-
-       memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
-       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
-       init_waitqueue_head(&se401->wq);
-       mutex_init(&se401->lock);
-       wmb();
-
-       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               kfree(se401);
-               err("video_register_device failed");
-               return -EIO;
-       }
-       info("registered new video device: video%d", se401->vdev.minor);
-
-       usb_set_intfdata (intf, se401);
-        return 0;
-}
-
-static void se401_disconnect(struct usb_interface *intf)
-{
-       struct usb_se401 *se401 = usb_get_intfdata (intf);
-
-       usb_set_intfdata (intf, NULL);
-       if (se401) {
-               video_unregister_device(&se401->vdev);
-               if (!se401->user){
-                       usb_se401_remove_disconnected(se401);
-               } else {
-                       se401->frame[0].grabstate = FRAME_ERROR;
-                       se401->frame[0].grabstate = FRAME_ERROR;
-
-                       se401->streaming = 0;
-
-                       wake_up_interruptible(&se401->wq);
-                       se401->removed = 1;
-               }
-       }
-}
-
-static struct usb_driver se401_driver = {
-        .name          = "se401",
-        .id_table      = device_table,
-       .probe          = se401_probe,
-        .disconnect    = se401_disconnect,
-};
-
-
-
-/****************************************************************************
- *
- *  Module routines
- *
- ***************************************************************************/
-
-static int __init usb_se401_init(void)
-{
-       info("SE401 usb camera driver version %s registering", version);
-       if (flickerless)
-               if (flickerless!=50 && flickerless!=60) {
-                       info("Invallid flickerless value, use 0, 50 or 60.");
-                       return -1;
-       }
-       return usb_register(&se401_driver);
-}
-
-static void __exit usb_se401_exit(void)
-{
-       usb_deregister(&se401_driver);
-       info("SE401 driver deregistered");
-}
-
-module_init(usb_se401_init);
-module_exit(usb_se401_exit);
diff --git a/drivers/usb/media/se401.h b/drivers/usb/media/se401.h
deleted file mode 100644 (file)
index e88a40d..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-
-#ifndef __LINUX_se401_H
-#define __LINUX_se401_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <linux/smp_lock.h>
-#include <linux/mutex.h>
-
-#define se401_DEBUG    /* Turn on debug messages */
-
-#ifdef se401_DEBUG
-#  define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
-#else
-#  define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* An almost drop-in replacement for sleep_on_interruptible */
-#define wait_interruptible(test, queue, wait) \
-{ \
-       add_wait_queue(queue, wait); \
-       set_current_state(TASK_INTERRUPTIBLE); \
-       if (test) \
-               schedule(); \
-       remove_wait_queue(queue, wait); \
-       set_current_state(TASK_RUNNING); \
-       if (signal_pending(current)) \
-               break; \
-}
-
-#define SE401_REQ_GET_CAMERA_DESCRIPTOR                0x06
-#define SE401_REQ_START_CONTINUOUS_CAPTURE     0x41
-#define SE401_REQ_STOP_CONTINUOUS_CAPTURE      0x42
-#define SE401_REQ_CAPTURE_FRAME                        0x43
-#define SE401_REQ_GET_BRT                      0x44
-#define SE401_REQ_SET_BRT                      0x45
-#define SE401_REQ_GET_WIDTH                    0x4c
-#define SE401_REQ_SET_WIDTH                    0x4d
-#define SE401_REQ_GET_HEIGHT                   0x4e
-#define SE401_REQ_SET_HEIGHT                   0x4f
-#define SE401_REQ_GET_OUTPUT_MODE              0x50
-#define SE401_REQ_SET_OUTPUT_MODE              0x51
-#define SE401_REQ_GET_EXT_FEATURE              0x52
-#define SE401_REQ_SET_EXT_FEATURE              0x53
-#define SE401_REQ_CAMERA_POWER                 0x56
-#define SE401_REQ_LED_CONTROL                  0x57
-#define SE401_REQ_BIOS                         0xff
-
-#define SE401_BIOS_READ                                0x07
-
-#define SE401_FORMAT_BAYER     0x40
-
-/* Hyundai hv7131b registers
-   7121 and 7141 should be the same (haven't really checked...) */
-/* Mode registers: */
-#define HV7131_REG_MODE_A              0x00
-#define HV7131_REG_MODE_B              0x01
-#define HV7131_REG_MODE_C              0x02
-/* Frame registers: */
-#define HV7131_REG_FRSU                0x10
-#define HV7131_REG_FRSL                0x11
-#define HV7131_REG_FCSU                0x12
-#define HV7131_REG_FCSL                0x13
-#define HV7131_REG_FWHU                0x14
-#define HV7131_REG_FWHL                0x15
-#define HV7131_REG_FWWU                0x16
-#define HV7131_REG_FWWL                0x17
-/* Timing registers: */
-#define HV7131_REG_THBU                0x20
-#define HV7131_REG_THBL                0x21
-#define HV7131_REG_TVBU                0x22
-#define HV7131_REG_TVBL                0x23
-#define HV7131_REG_TITU                0x25
-#define HV7131_REG_TITM                0x26
-#define HV7131_REG_TITL                0x27
-#define HV7131_REG_TMCD                0x28
-/* Adjust Registers: */
-#define HV7131_REG_ARLV                0x30
-#define HV7131_REG_ARCG                0x31
-#define HV7131_REG_AGCG                0x32
-#define HV7131_REG_ABCG                0x33
-#define HV7131_REG_APBV                0x34
-#define HV7131_REG_ASLP                0x54
-/* Offset Registers: */
-#define HV7131_REG_OFSR                0x50
-#define HV7131_REG_OFSG                0x51
-#define HV7131_REG_OFSB                0x52
-/* REset level statistics registers: */
-#define HV7131_REG_LOREFNOH    0x57
-#define HV7131_REG_LOREFNOL    0x58
-#define HV7131_REG_HIREFNOH    0x59
-#define HV7131_REG_HIREFNOL    0x5a
-
-/* se401 registers */
-#define SE401_OPERATINGMODE    0x2000
-
-
-/* size of usb transfers */
-#define SE401_PACKETSIZE       4096
-/* number of queued bulk transfers to use, should be about 8 */
-#define SE401_NUMSBUF          1
-/* read the usb specs for this one :) */
-#define SE401_VIDEO_ENDPOINT   1
-#define SE401_BUTTON_ENDPOINT  2
-/* number of frames supported by the v4l part */
-#define SE401_NUMFRAMES                2
-/* scratch buffers for passing data to the decoders */
-#define SE401_NUMSCRATCH       32
-/* maximum amount of data in a JangGu packet */
-#define SE401_VLCDATALEN       1024
-/* number of nul sized packets to receive before kicking the camera */
-#define SE401_MAX_NULLPACKETS  4000
-/* number of decoding errors before kicking the camera */
-#define SE401_MAX_ERRORS       200
-
-struct usb_device;
-
-struct se401_sbuf {
-       unsigned char *data;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-enum {
-       FMT_BAYER,
-       FMT_JANGGU,
-};
-
-enum {
-       BUFFER_UNUSED,
-       BUFFER_READY,
-       BUFFER_BUSY,
-       BUFFER_DONE,
-};
-
-struct se401_scratch {
-       unsigned char *data;
-       volatile int state;
-       int offset;
-       int length;
-};
-
-struct se401_frame {
-       unsigned char *data;            /* Frame buffer */
-
-       volatile int grabstate; /* State of grabbing */
-
-       unsigned char *curline;
-       int curlinepix;
-       int curpix;
-};
-
-struct usb_se401 {
-       struct video_device vdev;
-
-       /* Device structure */
-       struct usb_device *dev;
-
-       unsigned char iface;
-
-       char *camera_name;
-
-       int change;
-       int brightness;
-       int hue;
-       int rgain;
-       int ggain;
-       int bgain;
-       int expose_h;
-       int expose_m;
-       int expose_l;
-       int resetlevel;
-       
-       int enhance;
-
-       int format;
-       int sizes;
-       int *width;
-       int *height;
-       int cwidth;             /* current width */
-       int cheight;            /* current height */
-       int palette;
-       int maxframesize;
-       int cframesize;         /* current framesize */
-
-       struct mutex lock;
-       int user;               /* user count for exclusive use */
-       int removed;            /* device disconnected */
-
-       int streaming;          /* Are we streaming video? */
-
-       char *fbuf;             /* Videodev buffer area */
-
-       struct urb *urb[SE401_NUMSBUF];
-       struct urb *inturb;
-       
-       int button;
-       int buttonpressed;
-
-       int curframe;           /* Current receiving frame */
-       struct se401_frame frame[SE401_NUMFRAMES];      
-       int readcount;
-       int framecount;
-       int error;
-       int dropped;
-
-       int scratch_next;
-       int scratch_use;
-       int scratch_overflow;
-       struct se401_scratch scratch[SE401_NUMSCRATCH];
-
-       /* Decoder specific data: */
-       unsigned char vlcdata[SE401_VLCDATALEN];
-       int vlcdatapos;
-       int bayeroffset;
-
-       struct se401_sbuf sbuf[SE401_NUMSBUF];
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int nullpackets;
-};
-
-
-
-#endif
-
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
deleted file mode 100644 (file)
index 1d70a62..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _SN9C102_H_
-#define _SN9C102_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/string.h>
-#include <linux/stddef.h>
-
-#include "sn9c102_sensor.h"
-
-/*****************************************************************************/
-
-#define SN9C102_DEBUG
-#define SN9C102_DEBUG_LEVEL       2
-#define SN9C102_MAX_DEVICES       64
-#define SN9C102_PRESERVE_IMGSCALE 0
-#define SN9C102_FORCE_MUNMAP      0
-#define SN9C102_MAX_FRAMES        32
-#define SN9C102_URBS              2
-#define SN9C102_ISO_PACKETS       7
-#define SN9C102_ALTERNATE_SETTING 8
-#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
-#define SN9C102_CTRL_TIMEOUT      300
-#define SN9C102_FRAME_TIMEOUT     2
-
-/*****************************************************************************/
-
-enum sn9c102_bridge {
-       BRIDGE_SN9C101 = 0x01,
-       BRIDGE_SN9C102 = 0x02,
-       BRIDGE_SN9C103 = 0x04,
-};
-
-SN9C102_ID_TABLE
-SN9C102_SENSOR_TABLE
-
-enum sn9c102_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct sn9c102_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum sn9c102_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum sn9c102_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum sn9c102_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum sn9c102_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-typedef char sn9c103_sof_header_t[18];
-typedef char sn9c102_sof_header_t[12];
-typedef char sn9c102_eof_header_t[4];
-
-struct sn9c102_sysfs_attr {
-       u8 reg, i2c_reg;
-       sn9c103_sof_header_t frame_header;
-};
-
-struct sn9c102_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
-
-struct sn9c102_device {
-       struct video_device* v4ldev;
-
-       enum sn9c102_bridge bridge;
-       struct sn9c102_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[SN9C102_URBS];
-       void* transfer_buffer[SN9C102_URBS];
-       u8* control_buffer;
-
-       struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum sn9c102_io_method io;
-       enum sn9c102_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct sn9c102_sysfs_attr sysfs;
-       sn9c103_sof_header_t sof_header;
-       u16 reg[63];
-
-       struct sn9c102_module_param module_param;
-
-       enum sn9c102_dev_state state;
-       u8 users;
-
-       struct mutex dev_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
-{
-       if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
-               return cam;
-
-       return NULL;
-}
-
-
-void
-sn9c102_attach_sensor(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef SN9C102_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("sn9c102: " fmt "\n", ## args);               \
-               else if ((level) == 3)                                        \
-                       pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__,  \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-         __FUNCTION__, __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _SN9C102_H_ */
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
deleted file mode 100644 (file)
index 4c6cc63..0000000
+++ /dev/null
@@ -1,2919 +0,0 @@
-/***************************************************************************
- * V4L2 driver for SN9C10x PC Camera Controllers                           *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "sn9c102.h"
-
-/*****************************************************************************/
-
-#define SN9C102_MODULE_NAME     "V4L2 driver for SN9C10x PC Camera Controllers"
-#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
-#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.27"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
-
-MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
-MODULE_VERSION(SN9C102_MODULE_VERSION);
-MODULE_LICENSE(SN9C102_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
-                 " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] = 
-                               SN9C102_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
-                                       SN9C102_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                 "\n<n[,...]> Timeout for a video frame in seconds."
-                 "\nThis parameter is specific for each detected camera."
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
-                 "\n");
-
-#ifdef SN9C102_DEBUG
-static unsigned short debug = SN9C102_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
-                 "\n");
-#endif
-
-/*****************************************************************************/
-
-static sn9c102_sof_header_t sn9c102_sof_header[] = {
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00},
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
-};
-
-static sn9c103_sof_header_t sn9c103_sof_header[] = {
-       {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x20},
-};
-
-static sn9c102_eof_header_t sn9c102_eof_header[] = {
-       {0x00, 0x00, 0x00, 0x00},
-       {0x40, 0x00, 0x00, 0x00},
-       {0x80, 0x00, 0x00, 0x00},
-       {0xc0, 0x00, 0x00, 0x00},
-};
-
-/*****************************************************************************/
-
-static u32 
-sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
-                        enum sn9c102_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > SN9C102_MAX_FRAMES)
-               count = SN9C102_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void sn9c102_release_buffers(struct sn9c102_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < SN9C102_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
-{
-       struct sn9c102_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       int i, res;
-
-       if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg))
-               return -1;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             index, 0, buff, sizeof(buff),
-                             SN9C102_CTRL_TIMEOUT*sizeof(buff));
-       if (res < 0) {
-               DBG(3, "Failed to write registers (index 0x%02X, error %d)",
-                   index, res);
-               return -1;
-       }
-
-       for (i = 0; i < sizeof(buff); i++)
-               cam->reg[index+i] = buff[i];
-
-       return 0;
-}
-
-
-int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       if (index >= ARRAY_SIZE(cam->reg))
-               return -1;
-
-       *buff = value;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (value 0x%02X, index "
-                      "0x%02X, error %d)", value, index, res);
-               return -1;
-       }
-
-       cam->reg[index] = value;
-
-       return 0;
-}
-
-
-/* NOTE: reading some registers always returns 0 */
-static int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             index, 0, buff, 1, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%02X, error %d)",
-                   index, res);
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
-{
-       if (index >= ARRAY_SIZE(cam->reg))
-               return -1;
-
-       return cam->reg[index];
-}
-
-
-static int
-sn9c102_i2c_wait(struct sn9c102_device* cam, struct sn9c102_sensor* sensor)
-{
-       int i, r;
-
-       for (i = 1; i <= 5; i++) {
-               r = sn9c102_read_reg(cam, 0x08);
-               if (r < 0)
-                       return -EIO;
-               if (r & 0x04)
-                       return 0;
-               if (sensor->frequency & SN9C102_I2C_400KHZ)
-                       udelay(5*16);
-               else
-                       udelay(16*16);
-       }
-       return -EBUSY;
-}
-
-
-static int
-sn9c102_i2c_detect_read_error(struct sn9c102_device* cam, 
-                              struct sn9c102_sensor* sensor)
-{
-       int r;
-       r = sn9c102_read_reg(cam, 0x08);
-       return (r < 0 || (r >= 0 && !(r & 0x08))) ? -EIO : 0;
-}
-
-
-static int
-sn9c102_i2c_detect_write_error(struct sn9c102_device* cam, 
-                               struct sn9c102_sensor* sensor)
-{
-       int r;
-       r = sn9c102_read_reg(cam, 0x08);
-       return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
-}
-
-
-int 
-sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
-                         struct sn9c102_sensor* sensor, u8 data0, u8 data1,
-                         u8 n, u8 buffer[])
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       /* Write cycle */
-       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) | 0x10;
-       data[1] = data0; /* I2C slave id */
-       data[2] = data1; /* address */
-       data[7] = 0x10;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_wait(cam, sensor);
-
-       /* Read cycle - n bytes */
-       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0) |
-                 (n << 4) | 0x02;
-       data[1] = data0;
-       data[7] = 0x10;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_wait(cam, sensor);
-
-       /* The first read byte will be placed in data[4] */
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-                             0x0a, 0, data, 5, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_detect_read_error(cam, sensor);
-
-       PDBGG("I2C read: address 0x%02X, first read byte: 0x%02X", data1,
-             data[4]);
-
-       if (err) {
-               DBG(3, "I2C read failed for %s image sensor", sensor->name);
-               return -1;
-       }
-
-       if (buffer)
-               memcpy(buffer, data, sizeof(buffer));
-
-       return (int)data[4];
-}
-
-
-int 
-sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
-                          struct sn9c102_sensor* sensor, u8 n, u8 data0,
-                          u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* data = cam->control_buffer;
-       int err = 0, res;
-
-       /* Write cycle. It usually is address + value */
-       data[0] = ((sensor->interface == SN9C102_I2C_2WIRES) ? 0x80 : 0) |
-                 ((sensor->frequency & SN9C102_I2C_400KHZ) ? 0x01 : 0)
-                 | ((n - 1) << 4);
-       data[1] = data0;
-       data[2] = data1;
-       data[3] = data2;
-       data[4] = data3;
-       data[5] = data4;
-       data[6] = data5;
-       data[7] = 0x14;
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
-                             0x08, 0, data, 8, SN9C102_CTRL_TIMEOUT);
-       if (res < 0)
-               err += res;
-
-       err += sn9c102_i2c_wait(cam, sensor);
-       err += sn9c102_i2c_detect_write_error(cam, sensor);
-
-       if (err)
-               DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-       PDBGG("I2C raw write: %u bytes, data0 = 0x%02X, data1 = 0x%02X, "
-             "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X",
-             n, data0, data1, data2, data3, data4, data5);
-
-       return err ? -1 : 0;
-}
-
-
-int
-sn9c102_i2c_try_read(struct sn9c102_device* cam,
-                     struct sn9c102_sensor* sensor, u8 address)
-{
-       return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
-                                       address, 1, NULL);
-}
-
-
-int
-sn9c102_i2c_try_write(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor, u8 address, u8 value)
-{
-       return sn9c102_i2c_try_raw_write(cam, sensor, 3, 
-                                        sensor->i2c_slave_id, address,
-                                        value, 0, 0, 0);
-}
-
-
-int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
-{
-       return sn9c102_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
-{
-       return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-/*****************************************************************************/
-
-static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
-{
-       size_t soflen = 0, i;
-       u8 j, n = 0;
-
-       switch (cam->bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               soflen = sizeof(sn9c102_sof_header_t);
-               n = sizeof(sn9c102_sof_header) / soflen;
-               break;
-       case BRIDGE_SN9C103:
-               soflen = sizeof(sn9c103_sof_header_t);
-               n = sizeof(sn9c103_sof_header) / soflen;
-       }
-
-       for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
-               for (j = 0; j < n; j++)
-                       /* The invariable part of the header is 6 bytes long */
-                       if ((cam->bridge != BRIDGE_SN9C103 &&
-                           !memcmp(mem + i, sn9c102_sof_header[j], 6)) ||
-                           (cam->bridge == BRIDGE_SN9C103 &&
-                           !memcmp(mem + i, sn9c103_sof_header[j], 6))) {
-                               memcpy(cam->sof_header, mem + i, soflen);
-                               /* Skip the header */
-                               return mem + i + soflen;
-                       }
-
-       return NULL;
-}
-
-
-static void*
-sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
-{
-       size_t eoflen = sizeof(sn9c102_eof_header_t), i;
-       unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
-
-       if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
-               return NULL; /* EOF header does not exist in compressed data */
-
-       for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
-               for (j = 0; j < n; j++)
-                       if (!memcmp(mem + i, sn9c102_eof_header[j], eoflen))
-                               return mem + i;
-
-       return NULL;
-}
-
-
-static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
-{
-       struct sn9c102_device* cam = urb->context;
-       struct sn9c102_frame_t** f;
-       size_t imagesize, soflen;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       soflen = (cam->bridge) == BRIDGE_SN9C103 ?
-                                 sizeof(sn9c103_sof_header_t) :
-                                 sizeof(sn9c102_sof_header_t);
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int img, len, status;
-               void *pos, *sof, *eof;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               PDBGG("Isochrnous frame: length %u, #%u i", len, i);
-
-redo:
-               sof = sn9c102_find_sof_header(cam, pos, len);
-               if (likely(!sof)) {
-                       eof = sn9c102_find_eof_header(cam, pos, len);
-                       if ((*f)->state == F_GRABBING) {
-end_of_frame:
-                               img = len;
-
-                               if (eof)
-                                       img = (eof > pos) ? eof - pos - 1 : 0;
-
-                               if ((*f)->buf.bytesused+img > imagesize) {
-                                       u32 b;
-                                       b = (*f)->buf.bytesused + img -
-                                           imagesize;
-                                       img = imagesize - (*f)->buf.bytesused;
-                                       DBG(3, "Expected EOF not found: "
-                                              "video frame cut");
-                                       if (eof)
-                                               DBG(3, "Exceeded limit: +%u "
-                                                      "bytes", (unsigned)(b));
-                               }
-
-                               memcpy((*f)->bufmem + (*f)->buf.bytesused, pos,
-                                      img);
-
-                               if ((*f)->buf.bytesused == 0)
-                                       do_gettimeofday(&(*f)->buf.timestamp);
-
-                               (*f)->buf.bytesused += img;
-
-                               if ((*f)->buf.bytesused == imagesize ||
-                                   (cam->sensor.pix_format.pixelformat ==
-                                               V4L2_PIX_FMT_SN9C10X && eof)) {
-                                       u32 b;
-                                       b = (*f)->buf.bytesused;
-                                       (*f)->state = F_DONE;
-                                       (*f)->buf.sequence= ++cam->frame_count;
-                                       spin_lock(&cam->queue_lock);
-                                       list_move_tail(&(*f)->frame,
-                                                      &cam->outqueue);
-                                       if (!list_empty(&cam->inqueue))
-                                               (*f) = list_entry(
-                                                       cam->inqueue.next,
-                                                       struct sn9c102_frame_t,
-                                                       frame );
-                                       else
-                                               (*f) = NULL;
-                                       spin_unlock(&cam->queue_lock);
-                                       memcpy(cam->sysfs.frame_header,
-                                              cam->sof_header, soflen);
-                                       DBG(3, "Video frame captured: %lu "
-                                              "bytes", (unsigned long)(b));
-
-                                       if (!(*f))
-                                               goto resubmit_urb;
-
-                               } else if (eof) {
-                                       (*f)->state = F_ERROR;
-                                       DBG(3, "Not expected EOF after %lu "
-                                              "bytes of image data", 
-                                           (unsigned long)
-                                           ((*f)->buf.bytesused));
-                               }
-
-                               if (sof) /* (1) */
-                                       goto start_of_frame;
-
-                       } else if (eof) {
-                               DBG(3, "EOF without SOF");
-                               continue;
-
-                       } else {
-                               PDBGG("Ignoring pointless isochronous frame");
-                               continue;
-                       }
-
-               } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
-start_of_frame:
-                       (*f)->state = F_GRABBING;
-                       (*f)->buf.bytesused = 0;
-                       len -= (sof - pos);
-                       pos = sof;
-                       DBG(3, "SOF detected: new video frame");
-                       if (len)
-                               goto redo;
-
-               } else if ((*f)->state == F_GRABBING) {
-                       eof = sn9c102_find_eof_header(cam, pos, len);
-                       if (eof && eof < sof)
-                               goto end_of_frame; /* (1) */
-                       else {
-                               if (cam->sensor.pix_format.pixelformat ==
-                                   V4L2_PIX_FMT_SN9C10X) {
-                                       eof = sof - soflen;
-                                       goto end_of_frame;
-                               } else {
-                                       DBG(3, "SOF before expected EOF after "
-                                              "%lu bytes of image data", 
-                                           (unsigned long)
-                                           ((*f)->buf.bytesused));
-                                       goto start_of_frame;
-                               }
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int sn9c102_start_transfer(struct sn9c102_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const unsigned int sn9c102_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1023};
-       const unsigned int sn9c103_wMaxPacketSize[] = {0, 128, 256, 384, 512,
-                                                      680, 800, 900, 1003};
-       const unsigned int psz = (cam->bridge == BRIDGE_SN9C103) ?
-                           sn9c103_wMaxPacketSize[SN9C102_ALTERNATE_SETTING] :
-                           sn9c102_wMaxPacketSize[SN9C102_ALTERNATE_SETTING];
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < SN9C102_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(SN9C102_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < SN9C102_URBS; i++) {
-               urb = usb_alloc_urb(SN9C102_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = SN9C102_ISO_PACKETS;
-               urb->complete = sn9c102_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * SN9C102_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < SN9C102_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       /* Enable video */
-       if (!(cam->reg[0x01] & 0x04)) {
-               err = sn9c102_write_reg(cam, cam->reg[0x01] | 0x04, 0x01);
-               if (err) {
-                       err = -EIO;
-                       DBG(1, "I/O hardware error");
-                       goto free_urbs;
-               }
-       }
-
-       err = usb_set_interface(udev, 0, SN9C102_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < SN9C102_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < SN9C102_URBS) &&  cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < SN9C102_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int sn9c102_stop_transfer(struct sn9c102_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = SN9C102_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    SN9C102_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. "
-                      "To use it, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
-{
-       char str[5];
-       char* endp;
-       unsigned long val;
-
-       if (len < 4) {
-               strncpy(str, buff, len);
-               str[len+1] = '\0';
-       } else {
-               strncpy(str, buff, 4);
-               str[4] = '\0';
-       }
-
-       val = simple_strtoul(str, &endp, 0);
-
-       *count = 0;
-       if (val <= 0xff)
-               *count = (ssize_t)(endp - str);
-       if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
-               *count += 1;
-
-       return (u8)val;
-}
-
-/*
-   NOTE 1: being inside one of the following methods implies that the v4l
-           device exists for sure (see kobjects and reference counters)
-   NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-} 
-
-
-static ssize_t 
-sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = sn9c102_strtou8(buf, len, &count);
-       if (index > 0x1f || !count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.reg = index;
-
-       DBG(2, "Moved SN9C10X register index to 0x%02X", cam->sysfs.reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if ((val = sn9c102_read_reg(cam, cam->sysfs.reg)) < 0) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-} 
-
-
-static ssize_t
-sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = sn9c102_write_reg(cam, value, cam->sysfs.reg);
-       if (err) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written SN9C10X reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t 
-sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 index;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       index = sn9c102_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       cam->sysfs.i2c_reg = index;
-
-       DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-       int val;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       if ((val = sn9c102_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       count = sprintf(buf, "%d\n", val);
-
-       DBG(3, "Read bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-} 
-
-
-static ssize_t
-sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       u8 value;
-       ssize_t count;
-       int err;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENOSYS;
-       }
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EINVAL;
-       }
-
-       err = sn9c102_i2c_write(cam, cam->sysfs.i2c_reg, value);
-       if (err) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -EIO;
-       }
-
-       DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
-           cam->sysfs.i2c_reg, value);
-       DBG(3, "Written bytes: %zd", count);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       return count;
-}
-
-
-static ssize_t
-sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
-{
-       struct sn9c102_device* cam;
-       enum sn9c102_bridge bridge;
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam) {
-               mutex_unlock(&sn9c102_sysfs_lock);
-               return -ENODEV;
-       }
-
-       bridge = cam->bridge;
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count)
-               return -EINVAL;
-
-       switch (bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               if (value > 0x0f)
-                       return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
-                       res = sn9c102_store_val(cd, buf, len);
-               break;
-       case BRIDGE_SN9C103:
-               if (value > 0x7f)
-                       return -EINVAL;
-               if ((res = sn9c102_store_reg(cd, "0x04", 4)) >= 0)
-                       res = sn9c102_store_val(cd, buf, len);
-               break;
-       }
-
-       return res;
-}
-
-
-static ssize_t
-sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
-{
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x7f)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
-               res = sn9c102_store_val(cd, buf, len);
-
-       return res;
-}
-
-
-static ssize_t
-sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
-{
-       ssize_t res = 0;
-       u8 value;
-       ssize_t count;
-
-       value = sn9c102_strtou8(buf, len, &count);
-       if (!count || value > 0x7f)
-               return -EINVAL;
-
-       if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
-               res = sn9c102_store_val(cd, buf, len);
-
-       return res;
-}
-
-
-static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
-{
-       struct sn9c102_device* cam;
-       ssize_t count;
-
-       cam = video_get_drvdata(to_video_device(cd));
-       if (!cam)
-               return -ENODEV;
-
-       count = sizeof(cam->sysfs.frame_header);
-       memcpy(buf, cam->sysfs.frame_header, count);
-
-       DBG(3, "Frame header, read bytes: %zd", count);
-
-       return count;
-} 
-
-
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-                         sn9c102_show_reg, sn9c102_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-                         sn9c102_show_val, sn9c102_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-                         sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-                         sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
-static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
-static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
-static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
-                         sn9c102_show_frame_header, NULL);
-
-
-static void sn9c102_create_sysfs(struct sn9c102_device* cam)
-{
-       struct video_device *v4ldev = cam->v4ldev;
-
-       video_device_create_file(v4ldev, &class_device_attr_reg);
-       video_device_create_file(v4ldev, &class_device_attr_val);
-       video_device_create_file(v4ldev, &class_device_attr_frame_header);
-       if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
-               video_device_create_file(v4ldev, &class_device_attr_green);
-       else if (cam->bridge == BRIDGE_SN9C103) {
-               video_device_create_file(v4ldev, &class_device_attr_blue);
-               video_device_create_file(v4ldev, &class_device_attr_red);
-       }
-       if (cam->sensor.sysfs_ops) {
-               video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
-               video_device_create_file(v4ldev, &class_device_attr_i2c_val);
-       }
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, cam->reg[0x18] | 0x80, 0x18);
-       else
-               err += sn9c102_write_reg(cam, cam->reg[0x18] & 0x7f, 0x18);
-
-       return err ? -EIO : 0;
-}
-
-
-static int
-sn9c102_set_compression(struct sn9c102_device* cam,
-                        struct v4l2_jpegcompression* compression)
-{
-       int err = 0;
-
-       if (compression->quality == 0)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, 0x17);
-       else if (compression->quality == 1)
-               err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, 0x17);
-
-       return err ? -EIO : 0;
-}
-
-
-static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
-{
-       u8 r = 0;
-       int err = 0;
-
-       if (scale == 1)
-               r = cam->reg[0x18] & 0xcf;
-       else if (scale == 2) {
-               r = cam->reg[0x18] & 0xcf;
-               r |= 0x10;
-       } else if (scale == 4)
-               r = cam->reg[0x18] | 0x20;
-
-       err += sn9c102_write_reg(cam, r, 0x18);
-       if (err)
-               return -EIO;
-
-       PDBGG("Scaling factor: %u", scale);
-
-       return 0;
-}
-
-
-static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
-          v_start = (u8)(rect->top - s->cropcap.bounds.top),
-          h_size = (u8)(rect->width / 16),
-          v_size = (u8)(rect->height / 16);
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-       err += sn9c102_write_reg(cam, h_size, 0x15);
-       err += sn9c102_write_reg(cam, v_size, 0x16);
-       if (err)
-               return -EIO;
-
-       PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
-             "%u %u %u %u", h_start, v_start, h_size, v_size);
-
-       return 0;
-}
-
-
-static int sn9c102_init(struct sn9c102_device* cam)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       err += sn9c102_set_scale(cam, rect->width / s->pix_format.width);
-       err += sn9c102_set_crop(cam, rect);
-       if (err)
-               return err;
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED))
-               cam->compression.quality =  cam->reg[0x17] & 0x01 ? 0 : 1;
-       else
-               err += sn9c102_set_compression(cam, &cam->compression);
-       err += sn9c102_set_pix_format(cam, &s->pix_format);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, &s->pix_format);
-       if (err)
-               return err;
-
-       if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
-               DBG(3, "Compressed video format is active, quality %d",
-                   cam->compression.quality);
-       else
-               DBG(3, "Uncompressed video format is active");
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-
-static void sn9c102_release_resources(struct sn9c102_device* cam)
-{
-       mutex_lock(&sn9c102_sysfs_lock);
-
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-
-       usb_put_dev(cam->usbdev);
-
-       mutex_unlock(&sn9c102_sysfs_lock);
-
-       kfree(cam->control_buffer);
-}
-
-/*****************************************************************************/
-
-static int sn9c102_open(struct inode* inode, struct file* filp)
-{
-       struct sn9c102_device* cam;
-       int err = 0;
-
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&sn9c102_disconnect))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&sn9c102_disconnect);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
-               if (err) {
-                       up_read(&sn9c102_disconnect);
-                       return err;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&sn9c102_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = sn9c102_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = sn9c102_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       sn9c102_empty_framequeues(cam);
-
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
-
-out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&sn9c102_disconnect);
-       return err;
-}
-
-
-static int sn9c102_release(struct inode* inode, struct file* filp)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       sn9c102_stop_transfer(cam);
-
-       sn9c102_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               sn9c102_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-}
-
-
-static ssize_t
-sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       struct sn9c102_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose "
-                      "the read method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       sn9c102_empty_framequeues(cam);
-               sn9c102_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct sn9c102_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       sn9c102_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return count;
-}
-
-
-static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       struct sn9c102_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!sn9c102_request_buffers(cam, cam->nreadbuffers,
-                                            IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               sn9c102_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void sn9c102_vm_open(struct vm_area_struct* vma)
-{
-       struct sn9c102_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void sn9c102_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct sn9c102_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static struct vm_operations_struct sn9c102_vm_ops = {
-       .open = sn9c102_vm_open,
-       .close = sn9c102_vm_close,
-};
-
-
-static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &sn9c102_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-
-       sn9c102_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "sn9c102",
-               .version = SN9C102_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id && ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       PDBGG("VIDIOC_S_CTRL: id %lu, value %lu",
-             (unsigned long)ctrl.id, (unsigned long)ctrl.value);
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_pix_format* pix_format = &(s->pix_format);
-       u8 scale;
-       const enum sn9c102_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       /* Preserve R,G or B origin */
-       rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
-       rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
-       if (rect->width < 16)
-               rect->width = 16;
-       if (rect->height < 16)
-               rect->height = 16;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-
-       rect->width &= ~15L;
-       rect->height &= ~15L;
-
-       if (SN9C102_PRESERVE_IMGSCALE) {
-               /* Calculate the actual scaling factor */
-               u32 a, b;
-               a = rect->width * rect->height;
-               b = pix_format->width * pix_format->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
-       } else
-               scale = 1;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               sn9c102_release_buffers(cam);
-
-       err = sn9c102_set_crop(cam, rect);
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-       err += sn9c102_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width/scale;
-       s->pix_format.height = rect->height/scale;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
-           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               sn9c102_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               sn9c102_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "bayer rgb");
-               fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
-       } else if (fmtd.index == 1) {
-               strcpy(fmtd.description, "compressed");
-               fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X)
-                            ? 0 : (pfmt->width * pfmt->priv) / 8;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
-                         void __user * arg)
-{
-       struct sn9c102_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       u8 scale;
-       const enum sn9c102_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       { /* calculate the actual scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
-       }
-
-       rect.width = scale * pix->width;
-       rect.height = scale * pix->height;
-
-       if (rect.width < 16)
-               rect.width = 16;
-       if (rect.height < 16)
-               rect.height = 16;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-
-       rect.width &= ~15L;
-       rect.height &= ~15L;
-
-       { /* adjust the scaling factor */
-               u32 a, b;
-               a = rect.width * rect.height;
-               b = pix->width * pix->height;
-               scale = b ? (u8)((a / b) < 4 ? 1 : ((a / b) < 16 ? 2 : 4)) : 1;
-       }
-
-       pix->width = rect.width / scale;
-       pix->height = rect.height / scale;
-
-       if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
-           pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
-               pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv; /* bpp */
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-                           ? 0 : (pix->width * pix->priv) / 8;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. Unmap the "
-                                      "buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap  || cam->io == IO_READ)
-               sn9c102_release_buffers(cam);
-
-       err += sn9c102_set_pix_format(cam, pix);
-       err += sn9c102_set_crop(cam, &rect);
-       if (s->set_pix_format)
-               err += s->set_pix_format(cam, pix);
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-       err += sn9c102_set_scale(cam, scale);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               sn9c102_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               sn9c102_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression,
-                        sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum sn9c102_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0 && jc.quality != 1)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       err += sn9c102_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open "
-                      "/dev/video%d again.", cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
-                              "still mapped.");
-                       return -EINVAL;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       sn9c102_empty_framequeues(cam);
-
-       sn9c102_release_buffers(cam);
-       if (rb.count)
-               rb.count = sn9c102_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               sn9c102_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
-                     void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct sn9c102_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct sn9c102_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = sn9c102_stream_interrupt(cam)))
-                       return err;
-
-       sn9c102_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > SN9C102_MAX_FRAMES)
-               sp.parm.capture.readbuffers = SN9C102_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
-                              unsigned int cmd, void __user * arg)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return sn9c102_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return sn9c102_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return sn9c102_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return sn9c102_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return sn9c102_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return sn9c102_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-               return sn9c102_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP_OLD:
-       case VIDIOC_CROPCAP:
-               return sn9c102_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return sn9c102_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return sn9c102_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return sn9c102_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return sn9c102_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return sn9c102_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return sn9c102_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return sn9c102_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return sn9c102_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return sn9c102_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return sn9c102_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return sn9c102_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return sn9c102_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return sn9c102_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return sn9c102_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-               return sn9c102_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static int sn9c102_ioctl(struct inode* inode, struct file* filp,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "sn9c102", cmd);
-
-       err = sn9c102_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-/*****************************************************************************/
-
-static struct file_operations sn9c102_fops = {
-       .owner = THIS_MODULE,
-       .open =    sn9c102_open,
-       .release = sn9c102_release,
-       .ioctl =   sn9c102_ioctl,
-       .read =    sn9c102_read,
-       .poll =    sn9c102_poll,
-       .mmap =    sn9c102_mmap,
-       .llseek =  no_llseek,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct sn9c102_device* cam;
-       static unsigned int dev_nr = 0;
-       unsigned int i;
-       int err = 0, r;
-
-       if (!(cam = kzalloc(sizeof(struct sn9c102_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       mutex_init(&cam->dev_mutex);
-
-       r = sn9c102_read_reg(cam, 0x00);
-       if (r < 0 || r != 0x10) {
-               DBG(1, "Sorry, this is not a SN9C10x based camera "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
-               err = -ENODEV;
-               goto fail;
-       }
-
-       cam->bridge = (id->idProduct & 0xffc0) == 0x6080 ?
-                     BRIDGE_SN9C103 : BRIDGE_SN9C102;
-       switch (cam->bridge) {
-       case BRIDGE_SN9C101:
-       case BRIDGE_SN9C102:
-               DBG(2, "SN9C10[12] PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
-               break;
-       case BRIDGE_SN9C103:
-               DBG(2, "SN9C103 PC Camera Controller detected "
-                      "(vid/pid 0x%04X/0x%04X)", id->idVendor, id->idProduct);
-               break;
-       }
-
-       for  (i = 0; sn9c102_sensor_table[i]; i++) {
-               err = sn9c102_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err) {
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-               DBG(3, "Support for %s maintained by %s",
-                   cam->sensor.name, cam->sensor.maintainer);
-       } else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (sn9c102_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "SN9C10x PC Camera");
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
-       cam->v4ldev->fops = &sn9c102_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       mutex_lock(&cam->dev_mutex);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       sn9c102_create_sysfs(cam);
-       DBG(2, "Optional device control through 'sysfs' interface ready");
-#endif
-
-       usb_set_intfdata(intf, cam);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void sn9c102_usb_disconnect(struct usb_interface* intf)
-{
-       struct sn9c102_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
-
-       down_write(&sn9c102_disconnect);
-
-       mutex_lock(&cam->dev_mutex);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       wake_up_interruptible_all(&cam->open);
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor);
-               cam->state |= DEV_MISCONFIGURED;
-               sn9c102_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
-               cam->state |= DEV_DISCONNECTED;
-               sn9c102_release_resources(cam);
-       }
-
-       mutex_unlock(&cam->dev_mutex);
-
-       if (!cam->users)
-               kfree(cam);
-
-       up_write(&sn9c102_disconnect);
-}
-
-
-static struct usb_driver sn9c102_usb_driver = {
-       .name =       "sn9c102",
-       .id_table =   sn9c102_id_table,
-       .probe =      sn9c102_usb_probe,
-       .disconnect = sn9c102_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init sn9c102_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, SN9C102_MODULE_NAME " v" SN9C102_MODULE_VERSION);
-       KDBG(3, SN9C102_MODULE_AUTHOR);
-
-       if ((err = usb_register(&sn9c102_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit sn9c102_module_exit(void)
-{
-       usb_deregister(&sn9c102_usb_driver);
-}
-
-
-module_init(sn9c102_module_init);
-module_exit(sn9c102_module_exit);
diff --git a/drivers/usb/media/sn9c102_hv7131d.c b/drivers/usb/media/sn9c102_hv7131d.c
deleted file mode 100644 (file)
index 46c12ec..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/***************************************************************************
- * Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera     *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor hv7131d;
-
-
-static int hv7131d_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x0e, 0x18);
-       err += sn9c102_write_reg(cam, 0xf2, 0x19);
-
-       err += sn9c102_i2c_write(cam, 0x01, 0x04);
-       err += sn9c102_i2c_write(cam, 0x02, 0x00);
-       err += sn9c102_i2c_write(cam, 0x28, 0x00);
-
-       return err;
-}
-
-
-static int hv7131d_get_ctrl(struct sn9c102_device* cam, 
-                            struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = sn9c102_i2c_read(cam, 0x26),
-                           r2 = sn9c102_i2c_read(cam, 0x27);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 8) | (r2 & 0xff);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
-                       return -EIO;
-               ctrl->value = 0x3f - (ctrl->value & 0x3f);
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
-                       return -EIO;
-               ctrl->value = 0x3f - (ctrl->value & 0x3f);
-               return 0;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
-                       return -EIO;
-               ctrl->value = 0x3f - (ctrl->value & 0x3f);
-               return 0;
-       case SN9C102_V4L2_CID_RESET_LEVEL:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x3f;
-               return 0;
-       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x07;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int hv7131d_set_ctrl(struct sn9c102_device* cam, 
-                            const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
-               err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_RESET_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
-               err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int hv7131d_set_crop(struct sn9c102_device* cam, 
-                            const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &hv7131d;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int hv7131d_set_pix_format(struct sn9c102_device* cam, 
-                                  const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x42, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0xf2, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor hv7131d = {
-       .name = "HV7131D",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x11,
-       .init = &hv7131d_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x0250,
-                       .maximum = 0xffff,
-                       .step = 0x0001,
-                       .default_value = 0x0250,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x20,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x1e,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_RESET_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "reset level",
-                       .minimum = 0x19,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x30,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "pixel bias voltage",
-                       .minimum = 0x00,
-                       .maximum = 0x07,
-                       .step = 0x01,
-                       .default_value = 0x02,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &hv7131d_get_ctrl,
-       .set_ctrl = &hv7131d_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &hv7131d_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &hv7131d_set_pix_format
-};
-
-
-int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
-       r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
-       if (r0 < 0 || r1 < 0)
-               return -EIO;
-
-       if (r0 != 0x00 && r1 != 0x04)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &hv7131d);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_mi0343.c b/drivers/usb/media/sn9c102_mi0343.c
deleted file mode 100644 (file)
index d9aa7a6..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/***************************************************************************
- * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor mi0343;
-static u8 mi0343_i2c_data[5+1];
-
-
-static int mi0343_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x0a, 0x14);
-       err += sn9c102_write_reg(cam, 0x40, 0x01);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x07, 0x18);
-       err += sn9c102_write_reg(cam, 0xa0, 0x19);
-
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x0d, 0x00, 0x01, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x0d, 0x00, 0x00, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x03, 0x01, 0xe1, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x04, 0x02, 0x81, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x05, 0x00, 0x17, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x06, 0x00, 0x11, 0, 0);
-       err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
-                                        0x62, 0x04, 0x9a, 0, 0);
-
-       return err;
-}
-
-
-static int mi0343_get_ctrl(struct sn9c102_device* cam, 
-                           struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x09, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               ctrl->value = mi0343_i2c_data[2];
-               return 0;
-       case V4L2_CID_GAIN:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x35, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       case V4L2_CID_HFLIP:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x20, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
-               return 0;
-       case V4L2_CID_VFLIP:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x20, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x2d, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x2c, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
-                                            0x2e, 2+1, mi0343_i2c_data) < 0)
-                       return -EIO;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-       case V4L2_CID_RED_BALANCE:
-       case V4L2_CID_BLUE_BALANCE:
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
-               if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
-                       ctrl->value -= 0x10;
-               else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
-                       ctrl->value -= 0x60;
-               else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
-                       ctrl->value -= 0xe0;
-       }
-
-       return 0;
-}
-
-
-static int mi0343_set_ctrl(struct sn9c102_device* cam, 
-                           const struct v4l2_control* ctrl)
-{
-       u16 reg = 0;
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-       case V4L2_CID_RED_BALANCE:
-       case V4L2_CID_BLUE_BALANCE:
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if (ctrl->value <= (0x3f-0x10))
-                       reg = 0x10 + ctrl->value;
-               else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
-                       reg = 0x60 + (ctrl->value - (0x3f-0x10));
-               else
-                       reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
-               break;
-       }
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x09, ctrl->value, 0x00,
-                                                0, 0);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x35, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       case V4L2_CID_HFLIP:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x20, ctrl->value ? 0x40:0x00,
-                                                ctrl->value ? 0x20:0x00,
-                                                0, 0);
-               break;
-       case V4L2_CID_VFLIP:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x20, ctrl->value ? 0x80:0x00,
-                                                ctrl->value ? 0x80:0x00,
-                                                0, 0);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2d, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2c, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2b, reg >> 8, reg & 0xff,
-                                                0, 0);
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x2e, reg >> 8, reg & 0xff,
-                                                0, 0);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int mi0343_set_crop(struct sn9c102_device* cam, 
-                            const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &mi0343;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int mi0343_set_pix_format(struct sn9c102_device* cam, 
-                                 const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x0a, 0x00, 0x03, 0, 0);
-               err += sn9c102_write_reg(cam, 0x20, 0x19);
-       } else {
-               err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
-                                                mi0343.i2c_slave_id,
-                                                0x0a, 0x00, 0x05, 0, 0);
-               err += sn9c102_write_reg(cam, 0xa0, 0x19);
-       }
-
-       return err;
-}
-
-
-static struct sn9c102_sensor mi0343 = {
-       .name = "MI-0343",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x5d,
-       .init = &mi0343_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x06,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_HFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "horizontal mirror",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_VFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "vertical mirror",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &mi0343_get_ctrl,
-       .set_ctrl = &mi0343_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &mi0343_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &mi0343_set_pix_format
-};
-
-
-int sn9c102_probe_mi0343(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
-                                    2, mi0343_i2c_data) < 0)
-               return -EIO;
-
-       if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &mi0343);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c
deleted file mode 100644 (file)
index 42852b7..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/***************************************************************************
- * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera      *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor ov7630;
-
-
-static int ov7630_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x0f, 0x18);
-       err += sn9c102_write_reg(cam, 0x50, 0x19);
-
-       err += sn9c102_i2c_write(cam, 0x12, 0x80);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-       err += sn9c102_i2c_write(cam, 0x15, 0x34);
-       err += sn9c102_i2c_write(cam, 0x16, 0x03);
-       err += sn9c102_i2c_write(cam, 0x17, 0x1c);
-       err += sn9c102_i2c_write(cam, 0x18, 0xbd);
-       err += sn9c102_i2c_write(cam, 0x19, 0x06);
-       err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
-       err += sn9c102_i2c_write(cam, 0x1b, 0x04);
-       err += sn9c102_i2c_write(cam, 0x20, 0xf6);
-       err += sn9c102_i2c_write(cam, 0x23, 0xee);
-       err += sn9c102_i2c_write(cam, 0x26, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x27, 0x9a);
-       err += sn9c102_i2c_write(cam, 0x28, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x29, 0x30);
-       err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
-       err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
-       err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
-       err += sn9c102_i2c_write(cam, 0x30, 0x24);
-       err += sn9c102_i2c_write(cam, 0x32, 0x86);
-       err += sn9c102_i2c_write(cam, 0x60, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x61, 0x42);
-       err += sn9c102_i2c_write(cam, 0x65, 0x00);
-       err += sn9c102_i2c_write(cam, 0x69, 0x38);
-       err += sn9c102_i2c_write(cam, 0x6f, 0x88);
-       err += sn9c102_i2c_write(cam, 0x70, 0x0b);
-       err += sn9c102_i2c_write(cam, 0x71, 0x00);
-       err += sn9c102_i2c_write(cam, 0x74, 0x21);
-       err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
-
-       return err;
-}
-
-
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
-                           const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
-               err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
-               break;
-       case V4L2_CID_CONTRAST:
-               err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
-                                                      (ctrl->value-1) | 0x20)
-                                  : sn9c102_i2c_write(cam, 0x05, 0x00);
-               break;
-       case V4L2_CID_BRIGHTNESS:
-               err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
-               break;
-       case V4L2_CID_SATURATION:
-               err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
-               break;
-       case V4L2_CID_HUE:
-               err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
-                                                      (ctrl->value-1) | 0x20)
-                                  : sn9c102_i2c_write(cam, 0x04, 0x00);
-               break;
-       case V4L2_CID_DO_WHITE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       case V4L2_CID_WHITENESS:
-               err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
-               break;
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
-               break;
-       case V4L2_CID_AUTOGAIN:
-               err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
-               break;
-       case V4L2_CID_VFLIP:
-               err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
-               break;
-       case V4L2_CID_BLACK_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_BRIGHT_LEVEL:
-               err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GAMMA:
-               err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
-               break;
-       case SN9C102_V4L2_CID_BAND_FILTER:
-               err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int ov7630_set_crop(struct sn9c102_device* cam,
-                           const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &ov7630;
-       int err = 0;
-       u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
-
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int ov7630_set_pix_format(struct sn9c102_device* cam,
-                                 const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x20, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0x50, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor ov7630 = {
-       .name = "OV7630",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x21,
-       .init = &ov7630_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x14,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_HUE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "hue",
-                       .minimum = 0x00,
-                       .maximum = 0x1f+1,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_SATURATION,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "saturation",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x08,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "contrast",
-                       .minimum = 0x00,
-                       .maximum = 0x1f+1,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x000,
-                       .maximum = 0x3ff,
-                       .step = 0x001,
-                       .default_value = 0x83<<2,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x3a,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x77,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BRIGHTNESS,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0xa0,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_DO_WHITE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "white balance background: blue",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x20,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_WHITENESS,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "white balance background: red",
-                       .minimum = 0x00,
-                       .maximum = 0x3f,
-                       .step = 0x01,
-                       .default_value = 0x20,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "auto white balance",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_AUTOGAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "gain & exposure mode",
-                       .minimum = 0x00,
-                       .maximum = 0x03,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_VFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "vertical flip",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLACK_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "black pixel ratio",
-                       .minimum = 0x01,
-                       .maximum = 0x9a,
-                       .step = 0x01,
-                       .default_value = 0x8a,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "bright pixel ratio",
-                       .minimum = 0x01,
-                       .maximum = 0x9a,
-                       .step = 0x01,
-                       .default_value = 0x10,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_BAND_FILTER,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "band filter",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GAMMA,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "rgb gamma",
-                       .minimum = 0x00,
-                       .maximum = 0x01,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &ov7630_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &ov7630_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &ov7630_set_pix_format
-};
-
-
-int sn9c102_probe_ov7630(struct sn9c102_device* cam)
-{
-       const struct usb_device_id ov7630_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x602c), },
-               { USB_DEVICE(0x0c45, 0x602d), },
-               { USB_DEVICE(0x0c45, 0x608f), },
-               { USB_DEVICE(0x0c45, 0x60b0), },
-               { }
-       };
-       int err = 0;
-
-       if (!sn9c102_match_id(cam, ov7630_id_table))
-               return -ENODEV;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
-       if (err)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &ov7630);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_pas106b.c b/drivers/usb/media/sn9c102_pas106b.c
deleted file mode 100644 (file)
index b1dee78..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera     *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas106b;
-
-
-static int pas106b_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x20, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x0c);
-       err += sn9c102_i2c_write(cam, 0x05, 0x5a);
-       err += sn9c102_i2c_write(cam, 0x06, 0x88);
-       err += sn9c102_i2c_write(cam, 0x07, 0x80);
-       err += sn9c102_i2c_write(cam, 0x10, 0x06);
-       err += sn9c102_i2c_write(cam, 0x11, 0x06);
-       err += sn9c102_i2c_write(cam, 0x12, 0x00);
-       err += sn9c102_i2c_write(cam, 0x14, 0x02);
-       err += sn9c102_i2c_write(cam, 0x13, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas106b_get_ctrl(struct sn9c102_device* cam, 
-                            struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = sn9c102_i2c_read(cam, 0x03),
-                           r2 = sn9c102_i2c_read(cam, 0x04);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 4) | (r2 & 0x0f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case V4L2_CID_CONTRAST:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x07;
-               return 0;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
-                       return -EIO;
-               ctrl->value = (ctrl->value & 0x1f) << 1;
-               return 0;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
-                       return -EIO;
-               ctrl->value &= 0xf8;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas106b_set_ctrl(struct sn9c102_device* cam, 
-                            const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
-               break;
-       case V4L2_CID_CONTRAST:
-               err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
-               err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x13, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas106b_set_crop(struct sn9c102_device* cam, 
-                            const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas106b;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static int pas106b_set_pix_format(struct sn9c102_device* cam, 
-                                  const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x2c, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas106b = {
-       .name = "PAS106B",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas106b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x125,
-                       .maximum = 0xfff,
-                       .step = 0x001,
-                       .default_value = 0x140,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0d,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_CONTRAST,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "contrast",
-                       .minimum = 0x00,
-                       .maximum = 0x07,
-                       .step = 0x01,
-                       .default_value = 0x00, /* 0x00~0x03 have same effect */
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x06,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x3e,
-                       .step = 0x02,
-                       .default_value = 0x02,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &pas106b_get_ctrl,
-       .set_ctrl = &pas106b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-       },
-       .set_crop = &pas106b_set_crop,
-       .pix_format = {
-               .width = 352,
-               .height = 288,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8, /* we use this field as 'bits per pixel' */
-       },
-       .set_pix_format = &pas106b_set_pix_format
-};
-
-
-int sn9c102_probe_pas106b(struct sn9c102_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       /*
-          Minimal initialization to enable the I2C communication
-          NOTE: do NOT change the values!
-       */
-       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
-       err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
-       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
-       if (err)
-               return -EIO;
-
-       r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
-       r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
-
-       if (r0 < 0 || r1 < 0)
-               return -EIO;
-
-       pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x007)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas106b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c
deleted file mode 100644 (file)
index 3453237..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bca;
-
-
-static int pas202bca_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x30, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x14);
-       err += sn9c102_i2c_write(cam, 0x03, 0x40);
-       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
-       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x10, 0x08);
-       err += sn9c102_i2c_write(cam, 0x13, 0x63);
-       err += sn9c102_i2c_write(cam, 0x15, 0x70);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas202bca_set_pix_format(struct sn9c102_device* cam,
-                                    const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x24, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static int pas202bca_set_ctrl(struct sn9c102_device* cam,
-                              const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas202bca_set_crop(struct sn9c102_device* cam,
-                              const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas202bca;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas202bca = {
-       .name = "PAS202BCA",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas202bca_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &pas202bca_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &pas202bca_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &pas202bca_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
-{
-       const struct usb_device_id pas202bca_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x60af), },
-               { }
-       };
-       int err = 0;
-
-       if (!sn9c102_match_id(cam,pas202bca_id_table))
-               return -ENODEV;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x40, 0x01);
-       err += sn9c102_write_reg(cam, 0x28, 0x17);
-       if (err)
-               return -EIO;
-
-       if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas202bca);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_pas202bcb.c b/drivers/usb/media/sn9c102_pas202bcb.c
deleted file mode 100644 (file)
index d068616..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera   *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
- *                       <medaglia@undl.org.br>                            *
- *                       http://cadu.homelinux.com:8080/                   *
- *                                                                         *
- * DAC Magnitude, exposure and green gain controls added by                *
- * Luca Risolia <luca.risolia@studio.unibo.it>                             *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x30, 0x19);
-       err += sn9c102_write_reg(cam, 0x09, 0x18);
-
-       err += sn9c102_i2c_write(cam, 0x02, 0x14);
-       err += sn9c102_i2c_write(cam, 0x03, 0x40);
-       err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
-       err += sn9c102_i2c_write(cam, 0x0e, 0x01);
-       err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
-       err += sn9c102_i2c_write(cam, 0x10, 0x08);
-       err += sn9c102_i2c_write(cam, 0x13, 0x63);
-       err += sn9c102_i2c_write(cam, 0x15, 0x70);
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       msleep(400);
-
-       return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct sn9c102_device* cam, 
-                              struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = sn9c102_i2c_read(cam, 0x04),
-                           r2 = sn9c102_i2c_read(cam, 0x05);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
-                       return -EIO;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas202bcb_set_pix_format(struct sn9c102_device* cam, 
-                                    const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x24, 0x17);
-       else
-               err += sn9c102_write_reg(cam, 0x20, 0x17);
-
-       return err;
-}
-
-
-static int pas202bcb_set_ctrl(struct sn9c102_device* cam, 
-                              const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_GREEN_BALANCE:
-               err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case SN9C102_V4L2_CID_DAC_MAGNITUDE:
-               err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static int pas202bcb_set_crop(struct sn9c102_device* cam, 
-                              const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &pas202bcb;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor pas202bcb = {
-       .name = "PAS202BCB",
-       .maintainer = "Carlos Eduardo Medaglia Dyonisio "
-                     "<medaglia@undl.org.br>",
-       .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_2WIRES,
-       .i2c_slave_id = 0x40,
-       .init = &pas202bcb_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
-               },
-       },
-       .get_ctrl = &pas202bcb_get_ctrl,
-       .set_ctrl = &pas202bcb_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &pas202bcb_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &pas202bcb_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       /*
-        *  Minimal initialization to enable the I2C communication
-        *  NOTE: do NOT change the values!
-        */
-       err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
-       err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
-       err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
-       if (err)
-               return -EIO;
-
-       r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
-       r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
-
-       if (r0 < 0 || r1 < 0)
-               return -EIO;
-
-       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x017)
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &pas202bcb);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
deleted file mode 100644 (file)
index 2afd9e9..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the SN9C10x PC Camera Controllers    *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _SN9C102_SENSOR_H_
-#define _SN9C102_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct sn9c102_device;
-struct sn9c102_sensor;
-
-/*****************************************************************************/
-
-/*
-   OVERVIEW.
-   This is a small interface that allows you to add support for any CCD/CMOS
-   image sensors connected to the SN9C10X bridges. The entire API is documented
-   below. In the most general case, to support a sensor there are three steps
-   you have to follow:
-   1) define the main "sn9c102_sensor" structure by setting the basic fields;
-   2) write a probing function to be called by the core module when the USB
-      camera is recognized, then add both the USB ids and the name of that
-      function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
-      below);
-   3) implement the methods that you want/need (and fill the rest of the main
-      structure accordingly).
-   "sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
-   NOT need to touch the source code of the core module for the things to work
-   properly, unless you find bugs or flaws in it. Finally, do not forget to
-   read the V4L2 API for completeness.
-*/
-
-/*****************************************************************************/
-
-/*
-   Probing functions: on success, you must attach the sensor to the camera
-   by calling sn9c102_attach_sensor() provided below.
-   To enable the I2C communication, you might need to perform a really basic
-   initialization of the SN9C10X chip by using the write function declared 
-   ahead.
-   Functions must return 0 on success, the appropriate error otherwise.
-*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
-
-/*
-   Add the above entries to this table. Be sure to add the entry in the right
-   place, since, on failure, the next probing routine is called according to 
-   the order of the list below, from top to bottom.
-*/
-#define SN9C102_SENSOR_TABLE                                                  \
-static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {              \
-       &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */     \
-       &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */    \
-       &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */  \
-       &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */    \
-       &sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
-       &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */    \
-       &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */       \
-       &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */       \
-       NULL,                                                                 \
-};
-
-/* Device identification */
-extern struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
-
-/* Attach a probed sensor to the camera. */
-extern void 
-sn9c102_attach_sensor(struct sn9c102_device* cam,
-                      struct sn9c102_sensor* sensor);
-
-/*
-   Each SN9C10x camera has proper PID/VID identifiers.
-   SN9C103 supports multiple interfaces, but we only handle the video class
-   interface.
-*/
-#define SN9C102_USB_DEVICE(vend, prod, intclass)                              \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-       .idVendor = (vend),                                                   \
-       .idProduct = (prod),                                                  \
-       .bInterfaceClass = (intclass)
-
-#define SN9C102_ID_TABLE                                                      \
-static const struct usb_device_id sn9c102_id_table[] = {                      \
-       { USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */                     \
-       { USB_DEVICE(0x0c45, 0x6007), },                                      \
-       { USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x6024), },                                      \
-       { USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */      \
-       { USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */                      \
-       { USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */                        \
-       { USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */                        \
-       { USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */                        \
-       { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x602d), },                                      \
-       { USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */                         \
-       { USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */                          \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */  \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */     \
-       { SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */         \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */         \
-       { SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */           \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */          \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */       \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), },                        \
-       { SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), },                        \
-       { }                                                                   \
-};
-
-/*****************************************************************************/
-
-/*
-   Read/write routines: they always return -1 on error, 0 or the read value
-   otherwise. NOTE that a real read operation is not supported by the SN9C10X
-   chip for some of its registers. To work around this problem, a pseudo-read
-   call is provided instead: it returns the last successfully written value 
-   on the register (0 if it has never been written), the usual -1 on error.
-*/
-
-/* The "try" I2C I/O versions are used when probing the sensor */
-extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*,
-                                 u8 address, u8 value);
-extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
-                                u8 address);
-
-/*
-   These must be used if and only if the sensor doesn't implement the standard
-   I2C protocol. There are a number of good reasons why you must use the 
-   single-byte versions of these functions: do not abuse. The first function
-   writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
-   chip. The second one programs the registers 0x09 and 0x10 with data0 and
-   data1, and places the n bytes read from the sensor register table in the
-   buffer pointed by 'buffer'. Both the functions return -1 on error; the write
-   version returns 0 on success, while the read version returns the first read
-   byte.
-*/
-extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
-                                     struct sn9c102_sensor* sensor, u8 n, 
-                                     u8 data0, u8 data1, u8 data2, u8 data3,
-                                     u8 data4, u8 data5);
-extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
-                                    struct sn9c102_sensor* sensor, u8 data0,
-                                    u8 data1, u8 n, u8 buffer[]);
-
-/* To be used after the sensor struct has been attached to the camera struct */
-extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value);
-extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address);
-
-/* I/O on registers in the bridge. Could be used by the sensor methods too */
-extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
-extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
-extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
-
-/*
-   NOTE: there are no exported debugging functions. To uniform the output you
-   must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
-   already included here, the argument being the struct device '&usbdev->dev'
-   of the sensor structure. Do NOT use these macros before the sensor is
-   attached or the kernel will crash! However, you should not need to notify
-   the user about common errors or other messages, since this is done by the
-   master module.
-*/
-
-/*****************************************************************************/
-
-enum sn9c102_i2c_sysfs_ops {
-       SN9C102_I2C_READ = 0x01,
-       SN9C102_I2C_WRITE = 0x02,
-};
-
-enum sn9c102_i2c_frequency { /* sensors may support both the frequencies */
-       SN9C102_I2C_100KHZ = 0x01,
-       SN9C102_I2C_400KHZ = 0x02,
-};
-
-enum sn9c102_i2c_interface {
-       SN9C102_I2C_2WIRES,
-       SN9C102_I2C_3WIRES,
-};
-
-#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-
-struct sn9c102_sensor {
-       char name[32], /* sensor name */
-            maintainer[64]; /* name of the mantainer <email> */
-
-       /* Supported operations through the 'sysfs' interface */
-       enum sn9c102_i2c_sysfs_ops sysfs_ops;
-
-       /*
-          These sensor capabilities must be provided if the SN9C10X controller
-          needs to communicate through the sensor serial interface by using
-          at least one of the i2c functions available.
-       */
-       enum sn9c102_i2c_frequency frequency;
-       enum sn9c102_i2c_interface interface;
-
-       /*
-          This identifier must be provided if the image sensor implements
-          the standard I2C protocol.
-       */
-       u8 i2c_slave_id; /* reg. 0x09 */
-
-       /*
-          NOTE: Where not noted,most of the functions below are not mandatory.
-                Set to null if you do not implement them. If implemented,
-                they must return 0 on success, the proper error otherwise.
-       */
-
-       int (*init)(struct sn9c102_device* cam);
-       /*
-          This function will be called after the sensor has been attached. 
-          It should be used to initialize the sensor only, but may also
-          configure part of the SN9C10X chip if necessary. You don't need to
-          setup picture settings like brightness, contrast, etc.. here, if
-          the corrisponding controls are implemented (see below), since 
-          they are adjusted in the core driver by calling the set_ctrl()
-          method after init(), where the arguments are the default values
-          specified in the v4l2_queryctrl list of supported controls;
-          Same suggestions apply for other settings, _if_ the corresponding
-          methods are present; if not, the initialization must configure the
-          sensor according to the default configuration structures below.
-       */
-
-       struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
-       /*
-          Optional list of default controls, defined as indicated in the 
-          V4L2 API. Menu type controls are not handled by this interface.
-       */
-
-       int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct sn9c102_device* cam,
-                       const struct v4l2_control* ctrl);
-       /*
-          You must implement at least the set_ctrl method if you have defined
-          the list above. The returned value must follow the V4L2
-          specifications for the VIDIOC_G|C_CTRL ioctls. V4L2_CID_H|VCENTER
-          are not supported by this driver, so do not implement them. Also,
-          you don't have to check whether the passed values are out of bounds,
-          given that this is done by the core module.
-       */
-
-       struct v4l2_cropcap cropcap;
-       /*
-          Think the image sensor as a grid of R,G,B monochromatic pixels
-          disposed according to a particular Bayer pattern, which describes
-          the complete array of pixels, from (0,0) to (xmax, ymax). We will
-          use this coordinate system from now on. It is assumed the sensor
-          chip can be programmed to capture/transmit a subsection of that
-          array of pixels: we will call this subsection "active window".
-          It is not always true that the largest achievable active window can
-          cover the whole array of pixels. The V4L2 API defines another
-          area called "source rectangle", which, in turn, is a subrectangle of
-          the active window. The SN9C10X chip is always programmed to read the
-          source rectangle.
-          The bounds of both the active window and the source rectangle are
-          specified in the cropcap substructures 'bounds' and 'defrect'.
-          By default, the source rectangle should cover the largest possible
-          area. Again, it is not always true that the largest source rectangle
-          can cover the entire active window, although it is a rare case for 
-          the hardware we have. The bounds of the source rectangle _must_ be
-          multiple of 16 and must use the same coordinate system as indicated
-          before; their centers shall align initially.
-          If necessary, the sensor chip must be initialized during init() to
-          set the bounds of the active sensor window; however, by default, it
-          usually covers the largest achievable area (maxwidth x maxheight)
-          of pixels, so no particular initialization is needed, if you have
-          defined the correct default bounds in the structures.
-          See the V4L2 API for further details.
-          NOTE: once you have defined the bounds of the active window
-                (struct cropcap.bounds) you must not change them.anymore.
-          Only 'bounds' and 'defrect' fields are mandatory, other fields
-          will be ignored.
-       */
-
-       int (*set_crop)(struct sn9c102_device* cam,
-                       const struct v4l2_rect* rect);
-       /*
-          To be called on VIDIOC_C_SETCROP. The core module always calls a
-          default routine which configures the appropriate SN9C10X regs (also
-          scaling), but you may need to override/adjust specific stuff.
-          'rect' contains width and height values that are multiple of 16: in
-          case you override the default function, you always have to program
-          the chip to match those values; on error return the corresponding
-          error code without rolling back.
-          NOTE: in case, you must program the SN9C10X chip to get rid of 
-                blank pixels or blank lines at the _start_ of each line or
-                frame after each HSYNC or VSYNC, so that the image starts with
-                real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
-                V_SIZE you don't have to care about blank pixels or blank
-                lines at the end of each line or frame).
-       */
-
-       struct v4l2_pix_format pix_format;
-       /*
-          What you have to define here are: 1) initial 'width' and 'height' of
-          the target rectangle 2) the initial 'pixelformat', which can be
-          either V4L2_PIX_FMT_SN9C10X (for compressed video) or
-          V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
-          number of bits per pixel for uncompressed video, 8 or 9 (despite the
-          current value of 'pixelformat').
-          NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
-                  of cropcap.defrect.width and cropcap.defrect.height. I
-                  suggest 1/1.
-          NOTE 2: The initial compression quality is defined by the first bit
-                  of reg 0x17 during the initialization of the image sensor.
-          NOTE 3: as said above, you have to program the SN9C10X chip to get
-                  rid of any blank pixels, so that the output of the sensor
-                  matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
-       */
-
-       int (*set_pix_format)(struct sn9c102_device* cam,
-                             const struct v4l2_pix_format* pix);
-       /*
-          To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
-          SN9C10X pixel format or viceversa. On error return the corresponding
-          error code without rolling back.
-       */
-
-       /*
-          Do NOT write to the data below, it's READ ONLY. It is used by the
-          core module to store successfully updated values of the above
-          settings, for rollbacks..etc..in case of errors during atomic I/O
-       */
-       struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-/*****************************************************************************/
-
-/* Private ioctl's for control settings supported by some image sensors */
-#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
-#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
-#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
-#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
-#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
-
-#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
deleted file mode 100644 (file)
index 2e08c55..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera  *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor tas5110c1b;
-
-
-static int tas5110c1b_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x44, 0x01);
-       err += sn9c102_write_reg(cam, 0x00, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x0a, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x06, 0x18);
-       err += sn9c102_write_reg(cam, 0xfb, 0x19);
-
-       err += sn9c102_i2c_write(cam, 0xc0, 0x80);
-
-       return err;
-}
-
-
-static int tas5110c1b_set_ctrl(struct sn9c102_device* cam, 
-                               const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int tas5110c1b_set_crop(struct sn9c102_device* cam, 
-                               const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &tas5110c1b;
-       int err = 0;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       /* Don't change ! */
-       err += sn9c102_write_reg(cam, 0x14, 0x1a);
-       err += sn9c102_write_reg(cam, 0x0a, 0x1b);
-       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
-
-       return err;
-}
-
-
-static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, 
-                                     const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x2b, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0xfb, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor tas5110c1b = {
-       .name = "TAS5110C1B",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_3WIRES,
-       .init = &tas5110c1b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0xf6,
-                       .step = 0x01,
-                       .default_value = 0x40,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &tas5110c1b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 352,
-                       .height = 288,
-               },
-       },
-       .set_crop = &tas5110c1b_set_crop,
-       .pix_format = {
-               .width = 352,
-               .height = 288,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &tas5110c1b_set_pix_format
-};
-
-
-int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
-{
-       const struct usb_device_id tas5110c1b_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x6001), },
-               { USB_DEVICE(0x0c45, 0x6005), },
-               { USB_DEVICE(0x0c45, 0x60ab), },
-               { }
-       };
-
-       /* Sensor detection is based on USB pid/vid */
-       if (!sn9c102_match_id(cam, tas5110c1b_id_table))
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &tas5110c1b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
deleted file mode 100644 (file)
index c7b3397..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera  *
- * Controllers                                                             *
- *                                                                         *
- * Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor tas5130d1b;
-
-
-static int tas5130d1b_init(struct sn9c102_device* cam)
-{
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, 0x01, 0x01);
-       err += sn9c102_write_reg(cam, 0x20, 0x17);
-       err += sn9c102_write_reg(cam, 0x04, 0x01);
-       err += sn9c102_write_reg(cam, 0x01, 0x10);
-       err += sn9c102_write_reg(cam, 0x00, 0x11);
-       err += sn9c102_write_reg(cam, 0x00, 0x14);
-       err += sn9c102_write_reg(cam, 0x60, 0x17);
-       err += sn9c102_write_reg(cam, 0x07, 0x18);
-
-       return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct sn9c102_device* cam, 
-                               const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_GAIN:
-               err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
-               break;
-       case V4L2_CID_EXPOSURE:
-               err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return err ? -EIO : 0;
-}
-
-
-static int tas5130d1b_set_crop(struct sn9c102_device* cam, 
-                               const struct v4l2_rect* rect)
-{
-       struct sn9c102_sensor* s = &tas5130d1b;
-       u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
-          v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
-       int err = 0;
-
-       err += sn9c102_write_reg(cam, h_start, 0x12);
-       err += sn9c102_write_reg(cam, v_start, 0x13);
-
-       /* Do NOT change! */
-       err += sn9c102_write_reg(cam, 0x1f, 0x1a);
-       err += sn9c102_write_reg(cam, 0x1a, 0x1b);
-       err += sn9c102_write_reg(cam, sn9c102_pread_reg(cam, 0x19), 0x19);
-
-       return err;
-}
-
-
-static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, 
-                                     const struct v4l2_pix_format* pix)
-{
-       int err = 0;
-
-       if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-               err += sn9c102_write_reg(cam, 0x63, 0x19);
-       else
-               err += sn9c102_write_reg(cam, 0xf3, 0x19);
-
-       return err;
-}
-
-
-static struct sn9c102_sensor tas5130d1b = {
-       .name = "TAS5130D1B",
-       .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-       .sysfs_ops = SN9C102_I2C_WRITE,
-       .frequency = SN9C102_I2C_100KHZ,
-       .interface = SN9C102_I2C_3WIRES,
-       .init = &tas5130d1b_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0xf6,
-                       .step = 0x02,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = 0x47,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = 0,
-               },
-       },
-       .set_ctrl = &tas5130d1b_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .set_crop = &tas5130d1b_set_crop,
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_SBGGR8,
-               .priv = 8,
-       },
-       .set_pix_format = &tas5130d1b_set_pix_format
-};
-
-
-int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
-{
-       const struct usb_device_id tas5130d1b_id_table[] = {
-               { USB_DEVICE(0x0c45, 0x6025), },
-               { USB_DEVICE(0x0c45, 0x60aa), },
-               { }
-       };
-
-       /* Sensor detection is based on USB pid/vid */
-       if (!sn9c102_match_id(cam, tas5130d1b_id_table))
-               return -ENODEV;
-
-       sn9c102_attach_sensor(cam, &tas5130d1b);
-
-       return 0;
-}
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
deleted file mode 100644 (file)
index 9636da2..0000000
+++ /dev/null
@@ -1,1508 +0,0 @@
-/*
- *  STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
- *  
- * Thanks to STMicroelectronics for information on the usb commands, and 
- * to Steve Miller at STM for his help and encouragement while I was 
- * writing this driver.
- *
- * This driver is based heavily on the 
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History: 
- * ver 0.1 October, 2001. Initial attempt. 
- *
- * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
- *                         function, made more stable (?)
- *
- * ver 0.21 Nov, 2001.     Added gamma correction and white balance, 
- *                         due to Alexander Schwartz. Still trying to 
- *                         improve stablility. Moved stuff into stv680.h
- *
- * ver 0.22 Nov, 2001.    Added sharpen function (by Michael Sweet, 
- *                         mike@easysw.com) from GIMP, also used in pencam. 
- *                         Simple, fast, good integer math routine.
- *
- * ver 0.23 Dec, 2001 (gkh)
- *                        Took out sharpen function, ran code through
- *                        Lindent, and did other minor tweaks to get
- *                        things to work properly with 2.5.1
- *
- * ver 0.24 Jan, 2002 (kjs) 
- *                         Fixed the problem with webcam crashing after
- *                         two pictures. Changed the way pic is halved to 
- *                         improve quality. Got rid of green line around 
- *                         frame. Fix brightness reset when changing size 
- *                         bug. Adjusted gamma filters slightly.
- *
- * ver 0.25 Jan, 2002 (kjs)
- *                        Fixed a bug in which the driver sometimes attempted
- *                        to set to a non-supported size. This allowed
- *                        gnomemeeting to work.
- *                        Fixed proc entry removal bug.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/errno.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#include "stv680.h"
-
-static int video_nr = -1;
-static int swapRGB = 0;   /* default for auto sleect */
-static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
-
-static unsigned int debug = 0;
-
-#define PDEBUG(level, fmt, args...) \
-       do { \
-       if (debug >= level)     \
-               info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \
-       } while (0)
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.25"
-#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
-#define DRIVER_DESC "STV0680 USB Camera Driver"
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (debug, "Debug enabled or not");
-module_param(swapRGB_on, int, 0);
-MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
-module_param(video_nr, int, 0);
-
-/********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
- ********************************************************************/
-static void *rvmalloc (unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32 (size);
-       if (!mem)
-               return NULL;
-
-       memset (mem, 0, size);  /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       return mem;
-}
-
-static void rvfree (void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree (mem);
-}
-
-
-/*********************************************************************
- * pencam read/write functions
- ********************************************************************/
-
-static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
-{
-       int ret = -1;
-
-       switch (set) {
-       case 0:         /*  0xc1  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_rcvctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 1:         /*  0x41  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_sndctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 2:         /*  0x80  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_rcvctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_IN | USB_RECIP_DEVICE),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       case 3:         /*  0x40  */
-               ret = usb_control_msg (stv680->udev,
-                                      usb_sndctrlpipe (stv680->udev, 0),
-                                      req,
-                                      (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                                      value, 0, buffer, size, PENCAM_TIMEOUT);
-               break;
-
-       }
-       if ((ret < 0) && (req != 0x0a)) {
-               PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
-       }
-       return ret;
-}
-
-static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
-{
-
-       if (configuration != dev->udev->actconfig->desc.bConfigurationValue
-                       || usb_reset_configuration (dev->udev) < 0) {
-               PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
-               return -1;
-       }
-       if (usb_set_interface (dev->udev, interface, alternate) < 0) {
-               PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
-               return -1;
-       }
-       return 0;
-}
-
-static int stv_stop_video (struct usb_stv *dev)
-{
-       int i;
-       unsigned char *buf;
-
-       buf = kmalloc (40, GFP_KERNEL);
-       if (buf == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-
-       /* this is a high priority command; it stops all lower order commands */
-       if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
-               i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02);   /* Get Last Error; 2 = busy */
-               PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buf[0], buf[1]);
-       } else {
-               PDEBUG (1, "STV(i): Camera reset to idle mode.");
-       }
-
-       if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
-               PDEBUG (1, "STV(e): Reset config during exit failed");
-
-       /*  get current mode  */
-       buf[0] = 0xf0;
-       if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08)     /* get mode */
-               PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
-       if (dev->origMode != buf[0]) {
-               memset (buf, 0, 8);
-               buf[0] = (unsigned char) dev->origMode;
-               if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
-                       PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
-                       i = -1;
-               }
-               buf[0] = 0xf0;
-               i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
-               if ((i != 0x08) || (buf[0] != dev->origMode)) {
-                       PDEBUG (0, "STV(e): camera NOT set to original resolution.");
-                       i = -1;
-               } else
-                       PDEBUG (0, "STV(i): Camera set to original resolution");
-       }
-       /* origMode */
-       kfree(buf);
-       return i;
-}
-
-static int stv_set_video_mode (struct usb_stv *dev)
-{
-       int i, stop_video = 1;
-       unsigned char *buf;
-
-       buf = kmalloc (40, GFP_KERNEL);
-       if (buf == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-
-       if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
-               kfree(buf);
-               return i;
-       }
-
-       i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
-       if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
-               PDEBUG (1, "STV(e): Could not get descriptor 0100.");
-               goto error;
-       }
-
-       /*  set alternate interface 1 */
-       if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
-               goto error;
-
-       if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
-               goto error;
-       PDEBUG (1, "STV(i): Setting video mode.");
-       /*  Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240)  */
-       if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
-               stop_video = 0;
-               goto error;
-       }
-       goto exit;
-
-error:
-       kfree(buf);
-       if (stop_video == 1)
-               stv_stop_video (dev);
-       return -1;
-
-exit:
-       kfree(buf);
-       return 0;
-}
-
-static int stv_init (struct usb_stv *stv680)
-{
-       int i = 0;
-       unsigned char *buffer;
-       unsigned long int bufsize;
-
-       buffer = kzalloc (40, GFP_KERNEL);
-       if (buffer == NULL) {
-               PDEBUG (0, "STV(e): Out of (small buf) memory");
-               return -1;
-       }
-       udelay (100);
-
-       /* set config 1, interface 0, alternate 0 */
-       if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
-               kfree(buffer);
-               PDEBUG (0, "STV(e): set config 1,0,0 failed");
-               return -1;
-       }
-       /* ping camera to be sure STV0680 is present */
-       if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
-               goto error;
-       if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
-               PDEBUG (1, "STV(e): camera ping failed!!");
-               goto error;
-       }
-
-       /* get camera descriptor */
-       if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
-               goto error;
-       i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
-       if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
-               PDEBUG (1, "STV(e): Could not get descriptor 0200.");
-               goto error;
-       }
-       if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-               goto error;
-
-       stv680->SupportedModes = buffer[7];
-       i = stv680->SupportedModes;
-       stv680->CIF = 0;
-       stv680->VGA = 0;
-       stv680->QVGA = 0;
-       if (i & 1)
-               stv680->CIF = 1;
-       if (i & 2)
-               stv680->VGA = 1;
-       if (i & 8)
-               stv680->QVGA = 1;
-       if (stv680->SupportedModes == 0) {
-               PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
-               i = -1;
-               goto error;
-       } else {
-               if (stv680->CIF)
-                       PDEBUG (0, "STV(i): CIF is supported");
-               if (stv680->QVGA)
-                       PDEBUG (0, "STV(i): QVGA is supported");
-       }
-       /* FW rev, ASIC rev, sensor ID  */
-       PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
-       PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
-       PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
-
-       /*  set alternate interface 1 */
-       if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
-               goto error;
-
-       if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
-               goto error;
-       if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
-               goto error;
-       i = buffer[3];
-       PDEBUG (0, "STV(i): Camera has %i pictures.", i);
-
-       /*  get current mode */
-       if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
-               goto error;
-       stv680->origMode = buffer[0];   /* 01 = VGA, 03 = QVGA, 00 = CIF */
-
-       /* This will attemp CIF mode, if supported. If not, set to QVGA  */
-       memset (buffer, 0, 8);
-       if (stv680->CIF)
-               buffer[0] = 0x00;
-       else if (stv680->QVGA)
-               buffer[0] = 0x03;
-       if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
-               PDEBUG (0, "STV(i): Set_Camera_Mode failed");
-               i = -1;
-               goto error;
-       }
-       buffer[0] = 0xf0;
-       stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
-       if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
-               PDEBUG (0, "STV(e): Error setting camera video mode!");
-               i = -1;
-               goto error;
-       } else {
-               if (buffer[0] == 0) {
-                       stv680->VideoMode = 0x0000;
-                       PDEBUG (0, "STV(i): Video Mode set to CIF");
-               }
-               if (buffer[0] == 0x03) {
-                       stv680->VideoMode = 0x0300;
-                       PDEBUG (0, "STV(i): Video Mode set to QVGA");
-               }
-       }
-       if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
-               goto error;
-       bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
-       stv680->cwidth = (buffer[4] << 8) | (buffer[5]);        /* ->camera = 322, 356, 644  */
-       stv680->cheight = (buffer[6] << 8) | (buffer[7]);       /* ->camera = 242, 292, 484  */
-       stv680->origGain = buffer[12];
-
-       goto exit;
-
-error:
-       i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02);     /* Get Last Error */
-       PDEBUG (1, "STV(i): last error: %i,  command = 0x%x", buffer[0], buffer[1]);
-       kfree(buffer);
-       return -1;
-
-exit:
-       kfree(buffer);
-
-       /* video = 320x240, 352x288 */
-       if (stv680->CIF == 1) {
-               stv680->maxwidth = 352;
-               stv680->maxheight = 288;
-               stv680->vwidth = 352;
-               stv680->vheight = 288;
-       }
-       if (stv680->QVGA == 1) {
-               stv680->maxwidth = 320;
-               stv680->maxheight = 240;
-               stv680->vwidth = 320;
-               stv680->vheight = 240;
-       }
-
-       stv680->rawbufsize = bufsize;   /* must be ./. by 8 */
-       stv680->maxframesize = bufsize * 3;     /* RGB size */
-       PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
-       PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
-
-       /* some default values */
-       stv680->bulk_in_endpointAddr = 0x82;
-       stv680->dropped = 0;
-       stv680->error = 0;
-       stv680->framecount = 0;
-       stv680->readcount = 0;
-       stv680->streaming = 0;
-       /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
-       stv680->brightness = 32767;
-       stv680->chgbright = 0;
-       stv680->whiteness = 0;  /* only for greyscale */
-       stv680->colour = 32767;
-       stv680->contrast = 32767;
-       stv680->hue = 32767;
-       stv680->palette = STV_VIDEO_PALETTE;
-       stv680->depth = 24;     /* rgb24 bits */
-       if ((swapRGB_on == 0) && (swapRGB == 0))
-               PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
-       else if ((swapRGB_on == 0) && (swapRGB == 1))
-               PDEBUG (1, "STV(i): swapRGB is (auto) ON");
-       else if (swapRGB_on == 1)
-               PDEBUG (1, "STV(i): swapRGB is (forced) ON");
-       else if (swapRGB_on == -1)
-               PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
-       
-       if (stv_set_video_mode (stv680) < 0) {
-               PDEBUG (0, "STV(e): Could not set video mode in stv_init");
-               return -1;
-       }
-
-       return 0;
-}
-
-/***************** last of pencam  routines  *******************/
-
-/****************************************************************************
- *  sysfs
- ***************************************************************************/
-#define stv680_file(name, variable, field)                             \
-static ssize_t show_##name(struct class_device *class_dev, char *buf)  \
-{                                                                      \
-       struct video_device *vdev = to_video_device(class_dev);         \
-       struct usb_stv *stv = video_get_drvdata(vdev);                  \
-       return sprintf(buf, field, stv->variable);                      \
-}                                                                      \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-stv680_file(model, camera_name, "%s\n");
-stv680_file(in_use, user, "%d\n");
-stv680_file(streaming, streaming, "%d\n");
-stv680_file(palette, palette, "%i\n");
-stv680_file(frames_total, readcount, "%d\n");
-stv680_file(frames_read, framecount, "%d\n");
-stv680_file(packets_dropped, dropped, "%d\n");
-stv680_file(decoding_errors, error, "%d\n");
-
-static void stv680_create_sysfs_files(struct video_device *vdev)
-{
-       video_device_create_file(vdev, &class_device_attr_model);
-       video_device_create_file(vdev, &class_device_attr_in_use);
-       video_device_create_file(vdev, &class_device_attr_streaming);
-       video_device_create_file(vdev, &class_device_attr_palette);
-       video_device_create_file(vdev, &class_device_attr_frames_total);
-       video_device_create_file(vdev, &class_device_attr_frames_read);
-       video_device_create_file(vdev, &class_device_attr_packets_dropped);
-       video_device_create_file(vdev, &class_device_attr_decoding_errors);
-}
-
-static void stv680_remove_sysfs_files(struct video_device *vdev)
-{
-       video_device_remove_file(vdev, &class_device_attr_model);
-       video_device_remove_file(vdev, &class_device_attr_in_use);
-       video_device_remove_file(vdev, &class_device_attr_streaming);
-       video_device_remove_file(vdev, &class_device_attr_palette);
-       video_device_remove_file(vdev, &class_device_attr_frames_total);
-       video_device_remove_file(vdev, &class_device_attr_frames_read);
-       video_device_remove_file(vdev, &class_device_attr_packets_dropped);
-       video_device_remove_file(vdev, &class_device_attr_decoding_errors);
-}
-
-/********************************************************************
- * Camera control
- *******************************************************************/
-
-static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-       /* This sets values for v4l interface. max/min = 65535/0  */
-
-       p->brightness = stv680->brightness;
-       p->whiteness = stv680->whiteness;       /* greyscale */
-       p->colour = stv680->colour;
-       p->contrast = stv680->contrast;
-       p->hue = stv680->hue;
-       p->palette = stv680->palette;
-       p->depth = stv680->depth;
-       return 0;
-}
-
-static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
-{
-       /* See above stv680_get_pict  */
-
-       if (p->palette != STV_VIDEO_PALETTE) {
-               PDEBUG (2, "STV(e): Palette set error in _set_pic");
-               return 1;
-       }
-
-       if (stv680->brightness != p->brightness) {
-               stv680->chgbright = 1;
-               stv680->brightness = p->brightness;
-       } 
-
-       stv680->whiteness = p->whiteness;       /* greyscale */
-       stv680->colour = p->colour;
-       stv680->contrast = p->contrast;
-       stv680->hue = p->hue;
-       stv680->palette = p->palette;
-       stv680->depth = p->depth;
-
-       return 0;
-}
-
-static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
-{
-       struct usb_stv *stv680 = urb->context;
-       int length = urb->actual_length;
-
-       if (length < stv680->rawbufsize)
-               PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
-
-       /* ohoh... */
-       if (!stv680->streaming)
-               return;
-
-       if (!stv680->udev) {
-               PDEBUG (0, "STV(e): device vapourished in video_irq");
-               return;
-       }
-
-       /* 0 sized packets happen if we are to fast, but sometimes the camera
-          keeps sending them forever...
-        */
-       if (length && !urb->status) {
-               stv680->nullpackets = 0;
-               switch (stv680->scratch[stv680->scratch_next].state) {
-               case BUFFER_READY:
-               case BUFFER_BUSY:
-                       stv680->dropped++;
-                       break;
-
-               case BUFFER_UNUSED:
-                       memcpy (stv680->scratch[stv680->scratch_next].data,
-                               (unsigned char *) urb->transfer_buffer, length);
-                       stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
-                       stv680->scratch[stv680->scratch_next].length = length;
-                       if (waitqueue_active (&stv680->wq)) {
-                               wake_up_interruptible (&stv680->wq);
-                       }
-                       stv680->scratch_overflow = 0;
-                       stv680->scratch_next++;
-                       if (stv680->scratch_next >= STV680_NUMSCRATCH)
-                               stv680->scratch_next = 0;
-                       break;
-               }               /* switch  */
-       } else {
-               stv680->nullpackets++;
-               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-                       if (waitqueue_active (&stv680->wq)) {
-                               wake_up_interruptible (&stv680->wq);
-                       }
-               }
-       }                       /*  if - else */
-
-       /* Resubmit urb for new data */
-       urb->status = 0;
-       urb->dev = stv680->udev;
-       if (usb_submit_urb (urb, GFP_ATOMIC))
-               PDEBUG (0, "STV(e): urb burned down in video irq");
-       return;
-}                              /*  _video_irq  */
-
-static int stv680_start_stream (struct usb_stv *stv680)
-{
-       struct urb *urb;
-       int err = 0, i;
-
-       stv680->streaming = 1;
-
-       /* Do some memory allocation */
-       for (i = 0; i < STV680_NUMFRAMES; i++) {
-               stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
-               stv680->frame[i].curpix = 0;
-       }
-       /* packet size = 4096  */
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-               if (stv680->sbuf[i].data == NULL) {
-                       PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
-                       return -1;
-               }
-       }
-
-       stv680->scratch_next = 0;
-       stv680->scratch_use = 0;
-       stv680->scratch_overflow = 0;
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
-               if (stv680->scratch[i].data == NULL) {
-                       PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
-                       return -1;
-               }
-               stv680->scratch[i].state = BUFFER_UNUSED;
-       }
-
-       for (i = 0; i < STV680_NUMSBUF; i++) {
-               urb = usb_alloc_urb (0, GFP_KERNEL);
-               if (!urb)
-                       return -ENOMEM;
-
-               /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
-               usb_fill_bulk_urb (urb, stv680->udev,
-                                  usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
-                                  stv680->sbuf[i].data, stv680->rawbufsize,
-                                  stv680_video_irq, stv680);
-               stv680->urb[i] = urb;
-               err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-               if (err)
-                       PDEBUG (0, "STV(e): urb burned down in start stream");
-       }                       /* i STV680_NUMSBUF */
-
-       stv680->framecount = 0;
-       return 0;
-}
-
-static int stv680_stop_stream (struct usb_stv *stv680)
-{
-       int i;
-
-       if (!stv680->streaming || !stv680->udev)
-               return 1;
-
-       stv680->streaming = 0;
-
-       for (i = 0; i < STV680_NUMSBUF; i++)
-               if (stv680->urb[i]) {
-                       usb_kill_urb (stv680->urb[i]);
-                       usb_free_urb (stv680->urb[i]);
-                       stv680->urb[i] = NULL;
-                       kfree(stv680->sbuf[i].data);
-               }
-       for (i = 0; i < STV680_NUMSCRATCH; i++) {
-               kfree(stv680->scratch[i].data);
-               stv680->scratch[i].data = NULL;
-       }
-
-       return 0;
-}
-
-static int stv680_set_size (struct usb_stv *stv680, int width, int height)
-{
-       int wasstreaming = stv680->streaming;
-
-       /* Check to see if we need to change */
-       if ((stv680->vwidth == width) && (stv680->vheight == height))
-               return 0;
-
-       PDEBUG (1, "STV(i): size request for %i x %i", width, height);
-       /* Check for a valid mode */
-       if ((!width || !height) || ((width & 1) || (height & 1))) {
-               PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-               return 1;
-       }
-
-       if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
-               width = stv680->maxwidth / 2;
-               height = stv680->maxheight / 2;
-       } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
-               width = 160;
-               height = 120;
-       } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
-               width = 176;
-               height = 144;
-       } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
-               width = 320;
-               height = 240;
-       } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
-               width = 352;
-               height = 288;
-       } else {
-               PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i  actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
-               return 1;
-       }
-       
-       /* Stop a current stream and start it again at the new size */
-       if (wasstreaming)
-               stv680_stop_stream (stv680);
-       stv680->vwidth = width;
-       stv680->vheight = height;
-       PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
-       if (wasstreaming)
-               stv680_start_stream (stv680);
-
-       return 0;
-}
-
-/**********************************************************************
- * Video Decoding
- **********************************************************************/
-
-/*******  routines from the pencam program; hey, they work!  ********/
-
-/*
- * STV0680 Vision Camera Chipset Driver
- * Copyright (C) 2000 Adam Harrison <adam@antispin.org> 
-*/
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define AD(x, y, w) (((y)*(w)+(x))*3)
-
-static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
-{
-       int x, y, i;
-       int w = stv680->cwidth;
-       int vw = stv680->cwidth, vh = stv680->cheight;
-       unsigned int p = 0;
-       int colour = 0, bayer = 0;
-       unsigned char *raw = buffer->data;
-       struct stv680_frame *frame = &stv680->frame[stv680->curframe];
-       unsigned char *output = frame->data;
-       unsigned char *temp = frame->data;
-       int offset = buffer->offset;
-
-       if (frame->curpix == 0) {
-               if (frame->grabstate == FRAME_READY) {
-                       frame->grabstate = FRAME_GRABBING;
-               }
-       }
-       if (offset != frame->curpix) {  /* Regard frame as lost :( */
-               frame->curpix = 0;
-               stv680->error++;
-               return;
-       }
-
-       if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
-               vw = 320;
-               vh = 240;
-       }
-       if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
-               vw = 352;
-               vh = 288;
-       }
-
-       memset (output, 0, 3 * vw * vh);        /* clear output matrix. */
-
-       for (y = 0; y < vh; y++) {
-               for (x = 0; x < vw; x++) {
-                       if (x & 1)
-                               p = *(raw + y * w + (x >> 1));
-                       else
-                               p = *(raw + y * w + (x >> 1) + (w >> 1));
-
-                       if (y & 1)
-                               bayer = 2;
-                       else
-                               bayer = 0;
-                       if (x & 1)
-                               bayer++;
-
-                       switch (bayer) {
-                       case 0:
-                       case 3:
-                               colour = 1;
-                               break;
-                       case 1:
-                               colour = 0;
-                               break;
-                       case 2:
-                               colour = 2;
-                               break;
-                       }
-                       i = (y * vw + x) * 3;   
-                       *(output + i + colour) = (unsigned char) p;
-               }               /* for x */
-
-       }                       /* for y */
-
-       /****** gamma correction plus hardcoded white balance */
-       /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
-          Correction values red[], green[], blue[], are generated by 
-          (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
-          White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
-          converted to unsigned char. Values are in stv680.h  */
-
-       for (y = 0; y < vh; y++) {
-               for (x = 0; x < vw; x++) {
-                       i = (y * vw + x) * 3;
-                       *(output + i) = red[*(output + i)];
-                       *(output + i + 1) = green[*(output + i + 1)];
-                       *(output + i + 2) = blue[*(output + i + 2)];
-               }
-       }
-
-       /******  bayer demosaic  ******/
-       for (y = 1; y < (vh - 1); y++) {
-               for (x = 1; x < (vw - 1); x++) {        /* work out pixel type */
-                       if (y & 1)
-                               bayer = 0;
-                       else
-                               bayer = 2;
-                       if (!(x & 1))
-                               bayer++;
-
-                       switch (bayer) {
-                       case 0: /* green. blue lr, red tb */
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
-                               break;
-
-                       case 1: /* blue. green lrtb, red diagonals */
-                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
-                               break;
-
-                       case 2: /* red. green lrtb, blue diagonals */
-                               *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
-                               break;
-
-                       case 3: /* green. red lr, blue tb */
-                               *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
-                               *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
-                               break;
-                       }       /* switch */
-               }               /* for x */
-       }                       /* for y  - end demosaic  */
-
-       /* fix top and bottom row, left and right side */
-       i = vw * 3;
-       memcpy (output, (output + i), i);
-       memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
-       for (y = 0; y < vh; y++) {
-               i = y * vw * 3;
-               memcpy ((output + i), (output + i + 3), 3);
-               memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
-       }
-
-       /*  process all raw data, then trim to size if necessary */
-       if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
-               i = 0;
-               for (y = 0; y < vh; y++) {
-                       if (!(y & 1)) {
-                               for (x = 0; x < vw; x++) {
-                                       p = (y * vw + x) * 3;
-                                       if (!(x & 1)) {
-                                               *(output + i) = *(output + p);
-                                               *(output + i + 1) = *(output + p + 1);
-                                               *(output + i + 2) = *(output + p + 2);
-                                               i += 3;
-                                       }
-                               }  /* for x */
-                       }
-               }  /* for y */
-       }
-       /* reset to proper width */
-       if ((stv680->vwidth == 160)) {
-               vw = 160;
-               vh = 120;
-       }
-       if ((stv680->vwidth == 176)) {
-               vw = 176;
-               vh = 144;
-       }
-
-       /* output is RGB; some programs want BGR  */
-       /* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
-       /* swapRGB_on=-1, never swap */
-       if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
-               for (y = 0; y < vh; y++) {
-                       for (x = 0; x < vw; x++) {
-                               i = (y * vw + x) * 3;
-                               *(temp) = *(output + i);
-                               *(output + i) = *(output + i + 2);
-                               *(output + i + 2) = *(temp);
-                       }
-               }
-       }
-       /* brightness */
-       if (stv680->chgbright == 1) {
-               if (stv680->brightness >= 32767) {
-                       p = (stv680->brightness - 32767) / 256;
-                       for (x = 0; x < (vw * vh * 3); x++) {
-                               if ((*(output + x) + (unsigned char) p) > 255)
-                                       *(output + x) = 255;
-                               else
-                                       *(output + x) += (unsigned char) p;
-                       }       /* for */
-               } else {
-                       p = (32767 - stv680->brightness) / 256;
-                       for (x = 0; x < (vw * vh * 3); x++) {
-                               if ((unsigned char) p > *(output + x))
-                                       *(output + x) = 0;
-                               else
-                                       *(output + x) -= (unsigned char) p;
-                       }       /* for */
-               }               /* else */
-       }
-       /* if */
-       frame->curpix = 0;
-       frame->curlinepix = 0;
-       frame->grabstate = FRAME_DONE;
-       stv680->framecount++;
-       stv680->readcount++;
-       if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
-               stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
-       }
-
-}                              /* bayer_unshuffle */
-
-/*******  end routines from the pencam program  *********/
-
-static int stv680_newframe (struct usb_stv *stv680, int framenr)
-{
-       int errors = 0;
-
-       while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
-               if (!stv680->frame[framenr].curpix) {
-                       errors++;
-               }
-               wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
-
-               if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
-                       stv680->nullpackets = 0;
-                       PDEBUG (2, "STV(i): too many null length packets, restarting capture");
-                       stv680_stop_stream (stv680);
-                       stv680_start_stream (stv680);
-               } else {
-                       if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
-                               stv680->frame[framenr].grabstate = FRAME_ERROR;
-                               PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
-                               return -EIO;
-                       }
-                       stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
-
-                       bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
-
-                       stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
-                       stv680->scratch_use++;
-                       if (stv680->scratch_use >= STV680_NUMSCRATCH)
-                               stv680->scratch_use = 0;
-                       if (errors > STV680_MAX_ERRORS) {
-                               errors = 0;
-                               PDEBUG (2, "STV(i): too many errors, restarting capture");
-                               stv680_stop_stream (stv680);
-                               stv680_start_stream (stv680);
-                       }
-               }               /* else */
-       }                       /* while */
-       return 0;
-}
-
-/*********************************************************************
- * Video4Linux
- *********************************************************************/
-
-static int stv_open (struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       int err = 0;
-
-       /* we are called with the BKL held */
-       stv680->user = 1;
-       err = stv_init (stv680);        /* main initialization routine for camera */
-
-       if (err >= 0) {
-               stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
-               if (!stv680->fbuf) {
-                       PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
-                       err = -ENOMEM;
-               }
-               file->private_data = dev;
-       }
-       if (err)
-               stv680->user = 0;
-
-       return err;
-}
-
-static int stv_close (struct inode *inode, struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       int i;
-
-       for (i = 0; i < STV680_NUMFRAMES; i++)
-               stv680->frame[i].grabstate = FRAME_UNUSED;
-       if (stv680->streaming)
-               stv680_stop_stream (stv680);
-
-       if ((i = stv_stop_video (stv680)) < 0)
-               PDEBUG (1, "STV(e): stop_video failed in stv_close");
-
-       rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
-       stv680->user = 0;
-
-       if (stv680->removed) {
-               kfree(stv680);
-               stv680 = NULL;
-               PDEBUG (0, "STV(i): device unregistered");
-       }
-       file->private_data = NULL;
-       return 0;
-}
-
-static int stv680_do_ioctl (struct inode *inode, struct file *file,
-                           unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(vdev);
-
-       if (!stv680->udev)
-               return -EIO;
-
-       switch (cmd) {
-       case VIDIOCGCAP:{
-                       struct video_capability *b = arg;
-
-                       strcpy (b->name, stv680->camera_name);
-                       b->type = VID_TYPE_CAPTURE;
-                       b->channels = 1;
-                       b->audios = 0;
-                       b->maxwidth = stv680->maxwidth;
-                       b->maxheight = stv680->maxheight;
-                       b->minwidth = stv680->maxwidth / 2;
-                       b->minheight = stv680->maxheight / 2;
-                       return 0;
-               }
-       case VIDIOCGCHAN:{
-                       struct video_channel *v = arg;
-
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       v->flags = 0;
-                       v->tuners = 0;
-                       v->type = VIDEO_TYPE_CAMERA;
-                       strcpy (v->name, "STV Camera");
-                       return 0;
-               }
-       case VIDIOCSCHAN:{
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-       case VIDIOCGPICT:{
-                       struct video_picture *p = arg;
-
-                       stv680_get_pict (stv680, p);
-                       return 0;
-               }
-       case VIDIOCSPICT:{
-                       struct video_picture *p = arg;
-
-                       if (stv680_set_pict (stv680, p))
-                               return -EINVAL;
-                       return 0;
-               }
-       case VIDIOCSWIN:{
-                       struct video_window *vw = arg;
-
-                       if (vw->flags)
-                               return -EINVAL;
-                       if (vw->clipcount)
-                               return -EINVAL;
-                       if (vw->width != stv680->vwidth) {
-                               if (stv680_set_size (stv680, vw->width, vw->height)) {
-                                       PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
-                                       return -EINVAL;
-                               }
-                       }
-                       return 0;
-               }
-       case VIDIOCGWIN:{
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;      /* FIXME */
-                       vw->y = 0;
-                       vw->chromakey = 0;
-                       vw->flags = 0;
-                       vw->clipcount = 0;
-                       vw->width = stv680->vwidth;
-                       vw->height = stv680->vheight;
-                       return 0;
-               }
-       case VIDIOCGMBUF:{
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset (vm, 0, sizeof (*vm));
-                       vm->size = STV680_NUMFRAMES * stv680->maxframesize;
-                       vm->frames = STV680_NUMFRAMES;
-                       for (i = 0; i < STV680_NUMFRAMES; i++)
-                               vm->offsets[i] = stv680->maxframesize * i;
-                       return 0;
-               }
-       case VIDIOCMCAPTURE:{
-                       struct video_mmap *vm = arg;
-
-                       if (vm->format != STV_VIDEO_PALETTE) {
-                               PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
-                                       vm->format, STV_VIDEO_PALETTE);
-                               if ((vm->format == 3) && (swapRGB_on == 0))  {
-                                       PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
-                                       /* this may fix those apps (e.g., xawtv) that want BGR */
-                                       swapRGB = 1;
-                               }
-                               return -EINVAL;
-                       }
-                       if (vm->frame >= STV680_NUMFRAMES) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
-                               return -EINVAL;
-                       }
-                       if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
-                           || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
-                               PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
-                                       stv680->frame[vm->frame].grabstate);
-                               return -EBUSY;
-                       }
-                       /* Is this according to the v4l spec??? */
-                       if (stv680->vwidth != vm->width) {
-                               if (stv680_set_size (stv680, vm->width, vm->height)) {
-                                       PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
-                                       return -EINVAL;
-                               }
-                       }
-                       stv680->frame[vm->frame].grabstate = FRAME_READY;
-
-                       if (!stv680->streaming)
-                               stv680_start_stream (stv680);
-
-                       return 0;
-               }
-       case VIDIOCSYNC:{
-                       int *frame = arg;
-                       int ret = 0;
-
-                       if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
-                               PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
-                               return -EINVAL;
-                       }
-                       ret = stv680_newframe (stv680, *frame);
-                       stv680->frame[*frame].grabstate = FRAME_UNUSED;
-                       return ret;
-               }
-       case VIDIOCGFBUF:{
-                       struct video_buffer *vb = arg;
-
-                       memset (vb, 0, sizeof (*vb));
-                       return 0;
-               }
-       case VIDIOCKEY:
-               return 0;
-       case VIDIOCCAPTURE:
-               {
-                       PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
-                       return -EINVAL;
-               }
-       case VIDIOCSFBUF:
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               return -EINVAL;
-       default:
-               return -ENOIOCTLCMD;
-       }                       /* end switch */
-
-       return 0;
-}
-
-static int stv680_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, stv680_do_ioctl);
-}
-
-static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
-{
-       struct video_device *dev = file->private_data;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       mutex_lock(&stv680->lock);
-
-       if (stv680->udev == NULL) {
-               mutex_unlock(&stv680->lock);
-               return -EIO;
-       }
-       if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
-                   & ~(PAGE_SIZE - 1))) {
-               mutex_unlock(&stv680->lock);
-               return -EINVAL;
-       }
-       pos = (unsigned long) stv680->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-                       mutex_unlock(&stv680->lock);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       mutex_unlock(&stv680->lock);
-
-       return 0;
-}
-
-static ssize_t stv680_read (struct file *file, char __user *buf,
-                       size_t count, loff_t *ppos)
-{
-       struct video_device *dev = file->private_data;
-       unsigned long int realcount = count;
-       int ret = 0;
-       struct usb_stv *stv680 = video_get_drvdata(dev);
-       unsigned long int i;
-
-       if (STV680_NUMFRAMES != 2) {
-               PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
-               return -1;
-       }
-       if (stv680->udev == NULL)
-               return -EIO;
-       if (realcount > (stv680->vwidth * stv680->vheight * 3))
-               realcount = stv680->vwidth * stv680->vheight * 3;
-
-       /* Shouldn't happen: */
-       if (stv680->frame[0].grabstate == FRAME_GRABBING) {
-               PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
-               return -EBUSY;
-       }
-       stv680->frame[0].grabstate = FRAME_READY;
-       stv680->frame[1].grabstate = FRAME_UNUSED;
-       stv680->curframe = 0;
-
-       if (!stv680->streaming)
-               stv680_start_stream (stv680);
-
-       if (!stv680->streaming) {
-               ret = stv680_newframe (stv680, 0);      /* ret should = 0 */
-       }
-
-       ret = stv680_newframe (stv680, 0);
-
-       if (!ret) {
-               if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
-                       PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
-                       return -EFAULT;
-               }
-       } else {
-               realcount = ret;
-       }
-       stv680->frame[0].grabstate = FRAME_UNUSED;
-       return realcount;
-}                              /* stv680_read */
-
-static struct file_operations stv680_fops = {
-       .owner =        THIS_MODULE,
-       .open =         stv_open,
-       .release =      stv_close,
-       .read =         stv680_read,
-       .mmap =         stv680_mmap,
-       .ioctl =        stv680_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek =       no_llseek,
-};
-static struct video_device stv680_template = {
-       .owner =        THIS_MODULE,
-       .name =         "STV0680 USB camera",
-       .type =         VID_TYPE_CAPTURE,
-       .hardware =     VID_HARDWARE_SE401,
-       .fops =         &stv680_fops,
-       .release =      video_device_release,
-       .minor =        -1,
-};
-
-static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_host_interface *interface;
-       struct usb_stv *stv680 = NULL;
-       char *camera_name = NULL;
-       int retval = 0;
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1) {
-               PDEBUG (0, "STV(e): Number of Configurations != 1");
-               return -ENODEV;
-       }
-
-       interface = &intf->altsetting[0];
-       /* Is it a STV680? */
-       if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
-           (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
-               camera_name = "STV0680";
-               PDEBUG (0, "STV(i): STV0680 camera found.");
-       } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
-                  (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
-               camera_name = "Creative WebCam Go Mini";
-               PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
-       } else {
-               PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
-               PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
-               retval = -ENODEV;
-               goto error;
-       }
-       /* We found one */
-       if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
-               PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
-               retval = -ENOMEM;
-               goto error;
-       }
-
-       stv680->udev = dev;
-       stv680->camera_name = camera_name;
-
-       stv680->vdev = video_device_alloc();
-       if (!stv680->vdev) {
-               retval = -ENOMEM;
-               goto error;
-       }
-       memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
-       stv680->vdev->dev = &intf->dev;
-       video_set_drvdata(stv680->vdev, stv680);
-
-       memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
-       init_waitqueue_head (&stv680->wq);
-       mutex_init (&stv680->lock);
-       wmb ();
-
-       if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               PDEBUG (0, "STV(e): video_register_device failed");
-               retval = -EIO;
-               goto error_vdev;
-       }
-       PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
-
-       usb_set_intfdata (intf, stv680);
-       stv680_create_sysfs_files(stv680->vdev);
-       return 0;
-
-error_vdev:
-       video_device_release(stv680->vdev);
-error:
-       kfree(stv680);
-       return retval;
-}
-
-static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
-{
-       int i;
-
-       stv680->udev = NULL;
-       stv680->frame[0].grabstate = FRAME_ERROR;
-       stv680->frame[1].grabstate = FRAME_ERROR;
-       stv680->streaming = 0;
-
-       wake_up_interruptible (&stv680->wq);
-
-       for (i = 0; i < STV680_NUMSBUF; i++)
-               if (stv680->urb[i]) {
-                       usb_kill_urb (stv680->urb[i]);
-                       usb_free_urb (stv680->urb[i]);
-                       stv680->urb[i] = NULL;
-                       kfree(stv680->sbuf[i].data);
-               }
-       for (i = 0; i < STV680_NUMSCRATCH; i++)
-               kfree(stv680->scratch[i].data);
-       PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
-
-       /* Free the memory */
-       kfree(stv680);
-}
-
-static void stv680_disconnect (struct usb_interface *intf)
-{
-       struct usb_stv *stv680 = usb_get_intfdata (intf);
-
-       usb_set_intfdata (intf, NULL);
-
-       if (stv680) {
-               /* We don't want people trying to open up the device */
-               if (stv680->vdev) {
-                       stv680_remove_sysfs_files(stv680->vdev);
-                       video_unregister_device(stv680->vdev);
-                       stv680->vdev = NULL;
-               }
-               if (!stv680->user) {
-                       usb_stv680_remove_disconnected (stv680);
-               } else {
-                       stv680->removed = 1;
-               }
-       }
-}
-
-static struct usb_driver stv680_driver = {
-       .name =         "stv680",
-       .probe =        stv680_probe,
-       .disconnect =   stv680_disconnect,
-       .id_table =     device_table
-};
-
-/********************************************************************
- *  Module routines
- ********************************************************************/
-
-static int __init usb_stv680_init (void)
-{
-       if (usb_register (&stv680_driver) < 0) {
-               PDEBUG (0, "STV(e): Could not setup STV0680 driver");
-               return -1;
-       }
-       PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
-
-       info(DRIVER_DESC " " DRIVER_VERSION);
-       return 0;
-}
-
-static void __exit usb_stv680_exit (void)
-{
-       usb_deregister (&stv680_driver);
-       PDEBUG (0, "STV(i): driver deregistered");
-}
-
-module_init (usb_stv680_init);
-module_exit (usb_stv680_exit);
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h
deleted file mode 100644 (file)
index ea46e00..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
- *
- *  Filename: stv680.h
- *
- *  Description:
- *     This is a USB driver for STV0680 based usb video cameras.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- * 
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- * 
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************************/
-
-/* size of usb transfers */
-#define STV680_PACKETSIZE      4096
-
-/* number of queued bulk transfers to use, may have problems if > 1 */
-#define STV680_NUMSBUF         1
-
-/* number of frames supported by the v4l part */
-#define STV680_NUMFRAMES       2
-
-/* scratch buffers for passing data to the decoders: 2 or 4 are good */
-#define STV680_NUMSCRATCH      2
-
-/* number of nul sized packets to receive before kicking the camera */
-#define STV680_MAX_NULLPACKETS 200
-
-/* number of decoding errors before kicking the camera */
-#define STV680_MAX_ERRORS      100
-
-#define USB_PENCAM_VENDOR_ID   0x0553
-#define USB_PENCAM_PRODUCT_ID  0x0202
-
-#define USB_CREATIVEGOMINI_VENDOR_ID   0x041e
-#define USB_CREATIVEGOMINI_PRODUCT_ID  0x4007
-
-#define PENCAM_TIMEOUT          1000
-/* fmt 4 */
-#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
-
-static struct usb_device_id device_table[] = {
-       {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
-       {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
-       {}
-};
-MODULE_DEVICE_TABLE (usb, device_table);
-
-struct stv680_sbuf {
-       unsigned char *data;
-};
-
-enum {
-       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
-       FRAME_READY,            /* Ready to start grabbing */
-       FRAME_GRABBING,         /* In the process of being grabbed into */
-       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
-       FRAME_ERROR,            /* Something bad happened while processing */
-};
-
-enum {
-       BUFFER_UNUSED,
-       BUFFER_READY,
-       BUFFER_BUSY,
-       BUFFER_DONE,
-};
-
-/* raw camera data <- sbuf (urb transfer buf) */
-struct stv680_scratch {
-       unsigned char *data;
-       volatile int state;
-       int offset;
-       int length;
-};
-
-/* processed data for display ends up here, after bayer */
-struct stv680_frame {
-       unsigned char *data;    /* Frame buffer */
-       volatile int grabstate; /* State of grabbing */
-       unsigned char *curline;
-       int curlinepix;
-       int curpix;
-};
-
-/* this is almost the video structure uvd_t, with extra parameters for stv */
-struct usb_stv {
-       struct video_device *vdev;
-
-       struct usb_device *udev;
-
-       unsigned char bulk_in_endpointAddr;     /* __u8  the address of the bulk in endpoint */
-       char *camera_name;
-
-       unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
-       int SupportedModes;
-       int CIF;
-       int VGA;
-       int QVGA;
-       int cwidth;             /* camera width */
-       int cheight;            /* camera height */
-       int maxwidth;           /* max video width */
-       int maxheight;          /* max video height */
-       int vwidth;             /* current width for video window */
-       int vheight;            /* current height for video window */
-       unsigned long int rawbufsize;
-       unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
-
-       int origGain;
-       int origMode;           /* original camera mode */
-
-       struct mutex lock;      /* to lock the structure */
-       int user;               /* user count for exclusive use */
-       int removed;            /* device disconnected */
-       int streaming;          /* Are we streaming video? */
-       char *fbuf;             /* Videodev buffer area */
-       struct urb *urb[STV680_NUMSBUF];        /* # of queued bulk transfers */
-       int curframe;           /* Current receiving frame */
-       struct stv680_frame frame[STV680_NUMFRAMES];    /* # frames supported by v4l part */
-       int readcount;
-       int framecount;
-       int error;
-       int dropped;
-       int scratch_next;
-       int scratch_use;
-       int scratch_overflow;
-       struct stv680_scratch scratch[STV680_NUMSCRATCH];       /* for decoders */
-       struct stv680_sbuf sbuf[STV680_NUMSBUF];
-
-       unsigned int brightness;
-       unsigned int chgbright;
-       unsigned int whiteness;
-       unsigned int colour;
-       unsigned int contrast;
-       unsigned int hue;
-       unsigned int palette;
-       unsigned int depth;     /* rgb24 in bits */
-
-       wait_queue_head_t wq;   /* Processes waiting */
-
-       int nullpackets;
-};
-
-
-static const unsigned char red[256] = {
-       0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
-       18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
-       44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
-       71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
-       88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
-       102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
-       114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
-       125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
-       134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
-       143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
-       152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
-       159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
-       167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
-       173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
-       180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
-       187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
-       192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
-       198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
-       204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
-       209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
-       215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
-       220, 220, 221, 221 
-}; 
-
-static const unsigned char green[256] = {
-       0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
-       21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
-       50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
-       79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
-       98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
-       114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
-       127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
-       139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
-       150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
-       160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
-       169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
-       177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
-       186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
-       193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
-       201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
-       208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
-       214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
-       227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
-       233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
-       239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
-       245, 245, 246, 246 
-}; 
-
-static const unsigned char blue[256] = {
-       0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
-       23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
-       55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
-       86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
-       107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
-       125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
-       139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
-       152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
-       165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
-       176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
-       185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
-       194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
-       204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
-       212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
-       221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
-       228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
-       235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
-       243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
-       249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
-       255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
-       255, 255, 255, 255 
-}; 
diff --git a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c
deleted file mode 100644 (file)
index 75ff755..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * USB NB Camera driver
- *
- * HISTORY:
- * 25-Dec-2002 Dmitri      Removed lighting, sharpness parameters, methods.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define        ULTRACAM_VENDOR_ID      0x0461
-#define        ULTRACAM_PRODUCT_ID     0x0813
-
-#define MAX_CAMERAS            4       /* How many devices we allow to connect */
-
-/*
- * This structure lives in uvd_t->user field.
- */
-typedef struct {
-       int initialized;        /* Had we already sent init sequence? */
-       int camera_model;       /* What type of IBM camera we got? */
-        int has_hdr;
-} ultracam_t;
-#define        ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams = NULL;
-
-static int debug = 0;
-
-static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth  = 8;
-static const int min_canvasHeight = 4;
-
-#define FRAMERATE_MIN  0
-#define FRAMERATE_MAX  6
-static int framerate = -1;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags,
-               "Bitfield: 0=VIDIOCSYNC, "
-               "1=B/W, "
-               "2=show hints, "
-               "3=show stats, "
-               "4=test pattern, "
-               "5=separate frames, "
-               "6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-/*
- * ultracam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ultracam_find_header() or ultracam_parse_lines() to do most
- * of work.
- *
- * 02-Nov-2000 First (mostly dummy) version.
- * 06-Nov-2000 Rewrote to dump all data into frame.
- */
-static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       int n;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-
-       /* Try to move data from queue into frame buffer */
-       n = RingQueue_GetLength(&uvd->dp);
-       if (n > 0) {
-               int m;
-               /* See how much spare we have left */
-               m = uvd->max_frame_size - frame->seqRead_Length;
-               if (n > m)
-                       n = m;
-               /* Now move that much data into frame buffer */
-               RingQueue_Dequeue(
-                       &uvd->dp,
-                       frame->data + frame->seqRead_Length,
-                       m);
-               frame->seqRead_Length += m;
-       }
-       /* See if we filled the frame */
-       if (frame->seqRead_Length >= uvd->max_frame_size) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-/*
- * ultracam_veio()
- *
- * History:
- * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ultracam_veio(
-       struct uvd *uvd,
-       unsigned char req,
-       unsigned short value,
-       unsigned short index,
-       int is_out)
-{
-       static const char proc[] = "ultracam_veio";
-       unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
-       int i;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return 0;
-
-       if (!is_out) {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_rcvctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value,
-                       index,
-                       cp,
-                       sizeof(cp),
-                       1000);
-#if 1
-               info("USB => %02x%02x%02x%02x%02x%02x%02x%02x "
-                      "(req=$%02x val=$%04x ind=$%04x)",
-                      cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
-                      req, value, index);
-#endif
-       } else {
-               i = usb_control_msg(
-                       uvd->dev,
-                       usb_sndctrlpipe(uvd->dev, 0),
-                       req,
-                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value,
-                       index,
-                       NULL,
-                       0,
-                       1000);
-       }
-       if (i < 0) {
-               err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
-                   proc, i);
-               uvd->last_error = i;
-       }
-       return i;
-}
-
-/*
- * ultracam_calculate_fps()
- */
-static int ultracam_calculate_fps(struct uvd *uvd)
-{
-       return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ultracam_adjust_contrast()
- */
-static void ultracam_adjust_contrast(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ultracam_set_brightness(struct uvd *uvd)
-{
-}
-
-static void ultracam_set_hue(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ultracam_adjust_picture(struct uvd *uvd)
-{
-       ultracam_adjust_contrast(uvd);
-       ultracam_set_brightness(uvd);
-       ultracam_set_hue(uvd);
-}
-
-/*
- * ultracam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ultracam_video_stop(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- */
-static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
-{
-}
-
-static void ultracam_video_start(struct uvd *uvd)
-{
-       ultracam_reinit_iso(uvd, 0);
-}
-
-static int ultracam_resetPipe(struct uvd *uvd)
-{
-       usb_clear_halt(uvd->dev, uvd->video_endp);
-       return 0;
-}
-
-static int ultracam_alternateSetting(struct uvd *uvd, int setting)
-{
-       static const char proc[] = "ultracam_alternateSetting";
-       int i;
-       i = usb_set_interface(uvd->dev, uvd->iface, setting);
-       if (i < 0) {
-               err("%s: usb_set_interface error", proc);
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-       return 0;
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ultracam_setup_on_open(struct uvd *uvd)
-{
-       int setup_ok = 0; /* Success by default */
-       /* Send init sequence only once, it's large! */
-       if (!ULTRACAM_T(uvd)->initialized) {
-               ultracam_alternateSetting(uvd, 0x04);
-               ultracam_alternateSetting(uvd, 0x00);
-               ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
-               ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
-               ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
-               ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
-               ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
-               ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
-               ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
-               ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
-               ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
-               ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
-               ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
-               ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
-               ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
-               ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
-               ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
-               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
-               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
-               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
-               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
-               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
-               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
-               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
-               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
-               ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
-               ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
-               ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
-               ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
-               ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
-               ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
-               ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
-               ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
-               ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
-               ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
-               ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
-               ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
-               ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
-               ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
-               ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
-               ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
-               ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
-               ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
-               ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
-               ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
-               ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
-               ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
-               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
-               ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
-               ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
-               ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
-               ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
-               ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
-               ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
-               ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
-               ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
-               ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
-               ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
-               ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
-               ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
-               ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
-               ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
-               ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
-               ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
-               ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
-               ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
-               ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
-               ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
-               ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
-               ultracam_alternateSetting(uvd, 0x04);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
-               ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
-               ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
-               ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
-               ultracam_resetPipe(uvd);
-               ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
-       }
-       return setup_ok;
-}
-
-static void ultracam_configure_video(struct uvd *uvd)
-{
-       if (uvd == NULL)
-               return;
-
-       RESTRICT_TO_RANGE(init_brightness, 0, 255);
-       RESTRICT_TO_RANGE(init_contrast, 0, 255);
-       RESTRICT_TO_RANGE(init_color, 0, 255);
-       RESTRICT_TO_RANGE(init_hue, 0, 255);
-       RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
-       memset(&uvd->vpic, 0, sizeof(uvd->vpic));
-       memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
-       uvd->vpic.colour = init_color << 8;
-       uvd->vpic.hue = init_hue << 8;
-       uvd->vpic.brightness = init_brightness << 8;
-       uvd->vpic.contrast = init_contrast << 8;
-       uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
-       uvd->vpic.depth = 24;
-       uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
-       memset(&uvd->vcap, 0, sizeof(uvd->vcap));
-       strcpy(uvd->vcap.name, "IBM Ultra Camera");
-       uvd->vcap.type = VID_TYPE_CAPTURE;
-       uvd->vcap.channels = 1;
-       uvd->vcap.audios = 0;
-       uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
-       uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
-       uvd->vcap.minwidth = min_canvasWidth;
-       uvd->vcap.minheight = min_canvasHeight;
-
-       memset(&uvd->vchan, 0, sizeof(uvd->vchan));
-       uvd->vchan.flags = 0;
-       uvd->vchan.tuners = 0;
-       uvd->vchan.channel = 0;
-       uvd->vchan.type = VIDEO_TYPE_CAMERA;
-       strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ultracam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like our camera.
- *
- * History:
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct uvd *uvd = NULL;
-       int ix, i, nas;
-       int actInterface=-1, inactInterface=-1, maxPS=0;
-       unsigned char video_ep = 0;
-
-       if (debug >= 1)
-               info("ultracam_probe(%p)", intf);
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return -ENODEV;
-
-       info("IBM Ultra camera found (rev. 0x%04x)",
-               le16_to_cpu(dev->descriptor.bcdDevice));
-
-       /* Validate found interface: must have one ISO endpoint */
-       nas = intf->num_altsetting;
-       if (debug > 0)
-               info("Number of alternate settings=%d.", nas);
-       if (nas < 8) {
-               err("Too few alternate settings for this camera!");
-               return -ENODEV;
-       }
-       /* Validate all alternate settings */
-       for (ix=0; ix < nas; ix++) {
-               const struct usb_host_interface *interface;
-               const struct usb_endpoint_descriptor *endpoint;
-
-               interface = &intf->altsetting[ix];
-               i = interface->desc.bAlternateSetting;
-               if (interface->desc.bNumEndpoints != 1) {
-                       err("Interface %d. has %u. endpoints!",
-                           interface->desc.bInterfaceNumber,
-                           (unsigned)(interface->desc.bNumEndpoints));
-                       return -ENODEV;
-               }
-               endpoint = &interface->endpoint[0].desc;
-               if (video_ep == 0)
-                       video_ep = endpoint->bEndpointAddress;
-               else if (video_ep != endpoint->bEndpointAddress) {
-                       err("Alternate settings have different endpoint addresses!");
-                       return -ENODEV;
-               }
-               if ((endpoint->bmAttributes & 0x03) != 0x01) {
-                       err("Interface %d. has non-ISO endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if ((endpoint->bEndpointAddress & 0x80) == 0) {
-                       err("Interface %d. has ISO OUT endpoint!",
-                           interface->desc.bInterfaceNumber);
-                       return -ENODEV;
-               }
-               if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
-                       if (inactInterface < 0)
-                               inactInterface = i;
-                       else {
-                               err("More than one inactive alt. setting!");
-                               return -ENODEV;
-                       }
-               } else {
-                       if (actInterface < 0) {
-                               actInterface = i;
-                               maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-                               if (debug > 0)
-                                       info("Active setting=%d. maxPS=%d.", i, maxPS);
-                       } else {
-                               /* Got another active alt. setting */
-                               if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
-                                       /* This one is better! */
-                                       actInterface = i;
-                                       maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
-                                       if (debug > 0) {
-                                               info("Even better ctive setting=%d. maxPS=%d.",
-                                                    i, maxPS);
-                                       }
-                               }
-                       }
-               }
-       }
-       if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
-               err("Failed to recognize the camera!");
-               return -ENODEV;
-       }
-
-       uvd = usbvideo_AllocateDevice(cams);
-       if (uvd != NULL) {
-               /* Here uvd is a fully allocated uvd object */
-               uvd->flags = flags;
-               uvd->debug = debug;
-               uvd->dev = dev;
-               uvd->iface = intf->altsetting->desc.bInterfaceNumber;
-               uvd->ifaceAltInactive = inactInterface;
-               uvd->ifaceAltActive = actInterface;
-               uvd->video_endp = video_ep;
-               uvd->iso_packet_len = maxPS;
-               uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
-               uvd->defaultPalette = VIDEO_PALETTE_RGB24;
-               uvd->canvas = VIDEOSIZE(640, 480);      /* FIXME */
-               uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
-
-               /* Initialize ibmcam-specific data */
-               assert(ULTRACAM_T(uvd) != NULL);
-               ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
-               ULTRACAM_T(uvd)->initialized = 0;
-
-               ultracam_configure_video(uvd);
-
-               i = usbvideo_RegisterVideoDevice(uvd);
-               if (i != 0) {
-                       err("usbvideo_RegisterVideoDevice() failed.");
-                       uvd = NULL;
-               }
-       }
-
-       if (uvd) {
-               usb_set_intfdata (intf, uvd);
-               return 0;
-       }
-       return -EIO;
-}
-
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
-       { }  /* Terminating entry */
-};
-
-/*
- * ultracam_init()
- *
- * This code is run to initialize the driver.
- */
-static int __init ultracam_init(void)
-{
-       struct usbvideo_cb cbTbl;
-       memset(&cbTbl, 0, sizeof(cbTbl));
-       cbTbl.probe = ultracam_probe;
-       cbTbl.setupOnOpen = ultracam_setup_on_open;
-       cbTbl.videoStart = ultracam_video_start;
-       cbTbl.videoStop = ultracam_video_stop;
-       cbTbl.processData = ultracam_ProcessIsocData;
-       cbTbl.postProcess = usbvideo_DeinterlaceFrame;
-       cbTbl.adjustPicture = ultracam_adjust_picture;
-       cbTbl.getFPS = ultracam_calculate_fps;
-       return usbvideo_register(
-               &cams,
-               MAX_CAMERAS,
-               sizeof(ultracam_t),
-               "ultracam",
-               &cbTbl,
-               THIS_MODULE,
-               id_table);
-}
-
-static void __exit ultracam_cleanup(void)
-{
-       usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-MODULE_LICENSE("GPL");
-
-module_init(ultracam_init);
-module_exit(ultracam_cleanup);
diff --git a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
deleted file mode 100644 (file)
index 0b51fae..0000000
+++ /dev/null
@@ -1,2190 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-
-#include "usbvideo.h"
-
-#if defined(MAP_NR)
-#define        virt_to_page(v) MAP_NR(v)       /* Kernels 2.2.x */
-#endif
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-
-/*
- * Local prototypes.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf);
-static void usbvideo_CameraRelease(struct uvd *uvd);
-
-static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, unsigned long arg);
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
-static int usbvideo_v4l_open(struct inode *inode, struct file *file);
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
-                            size_t count, loff_t *ppos);
-static int usbvideo_v4l_close(struct inode *inode, struct file *file);
-
-static int usbvideo_StartDataPump(struct uvd *uvd);
-static void usbvideo_StopDataPump(struct uvd *uvd);
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
-                                               struct usbvideo_frame *frame);
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-static void *usbvideo_rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void usbvideo_rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-static void RingQueue_Initialize(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       init_waitqueue_head(&rq->wqh);
-}
-
-static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
-{
-       /* Make sure the requested size is a power of 2 and
-          round up if necessary. This allows index wrapping
-          using masks rather than modulo */
-
-       int i = 1;
-       assert(rq != NULL);
-       assert(rqLen > 0);
-
-       while(rqLen >> i)
-               i++;
-       if(rqLen != 1 << (i-1))
-               rqLen = 1 << i;
-
-       rq->length = rqLen;
-       rq->ri = rq->wi = 0;
-       rq->queue = usbvideo_rvmalloc(rq->length);
-       assert(rq->queue != NULL);
-}
-
-static int RingQueue_IsAllocated(const struct RingQueue *rq)
-{
-       if (rq == NULL)
-               return 0;
-       return (rq->queue != NULL) && (rq->length > 0);
-}
-
-static void RingQueue_Free(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       if (RingQueue_IsAllocated(rq)) {
-               usbvideo_rvfree(rq->queue, rq->length);
-               rq->queue = NULL;
-               rq->length = 0;
-       }
-}
-
-int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
-{
-       int rql, toread;
-
-       assert(rq != NULL);
-       assert(dst != NULL);
-
-       rql = RingQueue_GetLength(rq);
-       if(!rql)
-               return 0;
-
-       /* Clip requested length to available data */
-       if(len > rql)
-               len = rql;
-
-       toread = len;
-       if(rq->ri > rq->wi) {
-               /* Read data from tail */
-               int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
-               memcpy(dst, rq->queue + rq->ri, read);
-               toread -= read;
-               dst += read;
-               rq->ri = (rq->ri + read) & (rq->length-1);
-       }
-       if(toread) {
-               /* Read data from head */
-               memcpy(dst, rq->queue + rq->ri, toread);
-               rq->ri = (rq->ri + toread) & (rq->length-1);
-       }
-       return len;
-}
-
-EXPORT_SYMBOL(RingQueue_Dequeue);
-
-int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
-{
-       int enqueued = 0;
-
-       assert(rq != NULL);
-       assert(cdata != NULL);
-       assert(rq->length > 0);
-       while (n > 0) {
-               int m, q_avail;
-
-               /* Calculate the largest chunk that fits the tail of the ring */
-               q_avail = rq->length - rq->wi;
-               if (q_avail <= 0) {
-                       rq->wi = 0;
-                       q_avail = rq->length;
-               }
-               m = n;
-               assert(q_avail > 0);
-               if (m > q_avail)
-                       m = q_avail;
-
-               memcpy(rq->queue + rq->wi, cdata, m);
-               RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
-               cdata += m;
-               enqueued += m;
-               n -= m;
-       }
-       return enqueued;
-}
-
-EXPORT_SYMBOL(RingQueue_Enqueue);
-
-static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       interruptible_sleep_on(&rq->wqh);
-}
-
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       if (waitqueue_active(&rq->wqh))
-               wake_up_interruptible(&rq->wqh);
-}
-
-EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
-
-void RingQueue_Flush(struct RingQueue *rq)
-{
-       assert(rq != NULL);
-       rq->ri = 0;
-       rq->wi = 0;
-}
-
-EXPORT_SYMBOL(RingQueue_Flush);
-
-
-/*
- * usbvideo_VideosizeToString()
- *
- * This procedure converts given videosize value to readable string.
- *
- * History:
- * 07-Aug-2000 Created.
- * 19-Oct-2000 Reworked for usbvideo module.
- */
-static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
-{
-       char tmp[40];
-       int n;
-
-       n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));
-       assert(n < sizeof(tmp));
-       if ((buf == NULL) || (bufLen < n))
-               err("usbvideo_VideosizeToString: buffer is too small.");
-       else
-               memmove(buf, tmp, n);
-}
-
-/*
- * usbvideo_OverlayChar()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
-                                int x, int y, int ch)
-{
-       static const unsigned short digits[16] = {
-               0xF6DE, /* 0 */
-               0x2492, /* 1 */
-               0xE7CE, /* 2 */
-               0xE79E, /* 3 */
-               0xB792, /* 4 */
-               0xF39E, /* 5 */
-               0xF3DE, /* 6 */
-               0xF492, /* 7 */
-               0xF7DE, /* 8 */
-               0xF79E, /* 9 */
-               0x77DA, /* a */
-               0xD75C, /* b */
-               0xF24E, /* c */
-               0xD6DC, /* d */
-               0xF34E, /* e */
-               0xF348  /* f */
-       };
-       unsigned short digit;
-       int ix, iy;
-
-       if ((uvd == NULL) || (frame == NULL))
-               return;
-
-       if (ch >= '0' && ch <= '9')
-               ch -= '0';
-       else if (ch >= 'A' && ch <= 'F')
-               ch = 10 + (ch - 'A');
-       else if (ch >= 'a' && ch <= 'f')
-               ch = 10 + (ch - 'a');
-       else
-               return;
-       digit = digits[ch];
-
-       for (iy=0; iy < 5; iy++) {
-               for (ix=0; ix < 3; ix++) {
-                       if (digit & 0x8000) {
-                               if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {
-/* TODO */                             RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
-                               }
-                       }
-                       digit = digit << 1;
-               }
-       }
-}
-
-/*
- * usbvideo_OverlayString()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
-                                  int x, int y, const char *str)
-{
-       while (*str) {
-               usbvideo_OverlayChar(uvd, frame, x, y, *str);
-               str++;
-               x += 4; /* 3 pixels character + 1 space */
-       }
-}
-
-/*
- * usbvideo_OverlayStats()
- *
- * Overlays important debugging information.
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       const int y_diff = 8;
-       char tmp[16];
-       int x = 10, y=10;
-       long i, j, barLength;
-       const int qi_x1 = 60, qi_y1 = 10;
-       const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;
-
-       /* Call the user callback, see if we may proceed after that */
-       if (VALID_CALLBACK(uvd, overlayHook)) {
-               if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)
-                       return;
-       }
-
-       /*
-        * We draw a (mostly) hollow rectangle with qi_xxx coordinates.
-        * Left edge symbolizes the queue index 0; right edge symbolizes
-        * the full capacity of the queue.
-        */
-       barLength = qi_x2 - qi_x1 - 2;
-       if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {
-/* TODO */     long u_lo, u_hi, q_used;
-               long m_ri, m_wi, m_lo, m_hi;
-
-               /*
-                * Determine fill zones (used areas of the queue):
-                * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length
-                *
-                * if u_lo < 0 then there is no first filler.
-                */
-
-               q_used = RingQueue_GetLength(&uvd->dp);
-               if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
-                       u_hi = uvd->dp.length;
-                       u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
-               } else {
-                       u_hi = (q_used + uvd->dp.ri);
-                       u_lo = -1;
-               }
-
-               /* Convert byte indices into screen units */
-               m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);
-               m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);
-               m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;
-               m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);
-
-               for (j=qi_y1; j < (qi_y1 + qi_h); j++) {
-                       for (i=qi_x1; i < qi_x2; i++) {
-                               /* Draw border lines */
-                               if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||
-                                   (i == qi_x1) || (i == (qi_x2 - 1))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);
-                                       continue;
-                               }
-                               /* For all other points the Y coordinate does not matter */
-                               if ((i >= m_ri) && (i <= (m_ri + 3))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);
-                               } else if ((i >= m_wi) && (i <= (m_wi + 3))) {
-                                       RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);
-                               } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))
-                                       RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);
-                       }
-               }
-       }
-
-       sprintf(tmp, "%8lx", uvd->stats.frame_num);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.urb_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.urb_length);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.data_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.header_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.colour);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.hue);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-
-       sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
-       usbvideo_OverlayString(uvd, frame, x, y, tmp);
-       y += y_diff;
-}
-
-/*
- * usbvideo_ReportStatistics()
- *
- * This procedure prints packet and transfer statistics.
- *
- * History:
- * 14-Jan-2000 Corrected default multiplier.
- */
-static void usbvideo_ReportStatistics(const struct uvd *uvd)
-{
-       if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
-               unsigned long allPackets, badPackets, goodPackets, percent;
-               allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;
-               badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;
-               goodPackets = allPackets - badPackets;
-               /* Calculate percentage wisely, remember integer limits */
-               assert(allPackets != 0);
-               if (goodPackets < (((unsigned long)-1)/100))
-                       percent = (100 * goodPackets) / allPackets;
-               else
-                       percent = goodPackets / (allPackets / 100);
-               info("Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%",
-                    allPackets, badPackets, percent);
-               if (uvd->iso_packet_len > 0) {
-                       unsigned long allBytes, xferBytes;
-                       char multiplier = ' ';
-                       allBytes = allPackets * uvd->iso_packet_len;
-                       xferBytes = uvd->stats.data_count;
-                       assert(allBytes != 0);
-                       if (xferBytes < (((unsigned long)-1)/100))
-                               percent = (100 * xferBytes) / allBytes;
-                       else
-                               percent = xferBytes / (allBytes / 100);
-                       /* Scale xferBytes for easy reading */
-                       if (xferBytes > 10*1024) {
-                               xferBytes /= 1024;
-                               multiplier = 'K';
-                               if (xferBytes > 10*1024) {
-                                       xferBytes /= 1024;
-                                       multiplier = 'M';
-                                       if (xferBytes > 10*1024) {
-                                               xferBytes /= 1024;
-                                               multiplier = 'G';
-                                               if (xferBytes > 10*1024) {
-                                                       xferBytes /= 1024;
-                                                       multiplier = 'T';
-                                               }
-                                       }
-                               }
-                       }
-                       info("Transfer Statistics: Transferred=%lu%cB Usage=%lu%%",
-                            xferBytes, multiplier, percent);
-               }
-       }
-}
-
-/*
- * usbvideo_TestPattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe: if TRUE then entire frame is filled, otherwise the procedure
- *           continues from the current scanline.
- * pmode      0: fill the frame with solid blue color (like on VCR or TV)
- *           1: Draw a colored grid
- *
- * History:
- * 01-Feb-2000 Created.
- */
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
-{
-       struct usbvideo_frame *frame;
-       int num_cell = 0;
-       int scan_length = 0;
-       static int num_pass = 0;
-
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __FUNCTION__);
-               return;
-       }
-       if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
-               err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
-               return;
-       }
-
-       /* Grab the current frame */
-       frame = &uvd->frame[uvd->curframe];
-
-       /* Optionally start at the beginning */
-       if (fullframe) {
-               frame->curline = 0;
-               frame->seqRead_Length = 0;
-       }
-#if 0
-       {       /* For debugging purposes only */
-               char tmp[20];
-               usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
-               info("testpattern: frame=%s", tmp);
-       }
-#endif
-       /* Form every scan line */
-       for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) {
-               int i;
-               unsigned char *f = frame->data +
-                       (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline);
-               for (i=0; i < VIDEOSIZE_X(frame->request); i++) {
-                       unsigned char cb=0x80;
-                       unsigned char cg = 0;
-                       unsigned char cr = 0;
-
-                       if (pmode == 1) {
-                               if (frame->curline % 32 == 0)
-                                       cb = 0, cg = cr = 0xFF;
-                               else if (i % 32 == 0) {
-                                       if (frame->curline % 32 == 1)
-                                               num_cell++;
-                                       cb = 0, cg = cr = 0xFF;
-                               } else {
-                                       cb = ((num_cell*7) + num_pass) & 0xFF;
-                                       cg = ((num_cell*5) + num_pass*2) & 0xFF;
-                                       cr = ((num_cell*3) + num_pass*3) & 0xFF;
-                               }
-                       } else {
-                               /* Just the blue screen */
-                       }
-                               
-                       *f++ = cb;
-                       *f++ = cg;
-                       *f++ = cr;
-                       scan_length += 3;
-               }
-       }
-
-       frame->frameState = FrameState_Done;
-       frame->seqRead_Length += scan_length;
-       ++num_pass;
-
-       /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
-       usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_TestPattern);
-
-
-#ifdef DEBUG
-/*
- * usbvideo_HexDump()
- *
- * A debugging tool. Prints hex dumps.
- *
- * History:
- * 29-Jul-2000 Added printing of offsets.
- */
-void usbvideo_HexDump(const unsigned char *data, int len)
-{
-       const int bytes_per_line = 32;
-       char tmp[128]; /* 32*3 + 5 */
-       int i, k;
-
-       for (i=k=0; len > 0; i++, len--) {
-               if (i > 0 && ((i % bytes_per_line) == 0)) {
-                       printk("%s\n", tmp);
-                       k=0;
-               }
-               if ((i % bytes_per_line) == 0)
-                       k += sprintf(&tmp[k], "%04x: ", i);
-               k += sprintf(&tmp[k], "%02x ", data[i]);
-       }
-       if (k > 0)
-               printk("%s\n", tmp);
-}
-
-EXPORT_SYMBOL(usbvideo_HexDump);
-
-#endif
-
-/* ******************************************************************** */
-
-/* XXX: this piece of crap really wants some error handling.. */
-static void usbvideo_ClientIncModCount(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle == NULL) {
-               err("%s: uvd->handle == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle->md_module == NULL) {
-               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
-               return;
-       }
-       if (!try_module_get(uvd->handle->md_module)) {
-               err("%s: try_module_get() == 0", __FUNCTION__);
-               return;
-       }
-}
-
-static void usbvideo_ClientDecModCount(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: uvd == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle == NULL) {
-               err("%s: uvd->handle == NULL", __FUNCTION__);
-               return;
-       }
-       if (uvd->handle->md_module == NULL) {
-               err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
-               return;
-       }
-       module_put(uvd->handle->md_module);
-}
-
-int usbvideo_register(
-       struct usbvideo **pCams,
-       const int num_cams,
-       const int num_extra,
-       const char *driverName,
-       const struct usbvideo_cb *cbTbl,
-       struct module *md,
-       const struct usb_device_id *id_table)
-{
-       struct usbvideo *cams;
-       int i, base_size, result;
-
-       /* Check parameters for sanity */
-       if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
-               err("%s: Illegal call", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       /* Check registration callback - must be set! */
-       if (cbTbl->probe == NULL) {
-               err("%s: probe() is required!", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
-       cams = (struct usbvideo *) kzalloc(base_size, GFP_KERNEL);
-       if (cams == NULL) {
-               err("Failed to allocate %d. bytes for usbvideo struct", base_size);
-               return -ENOMEM;
-       }
-       dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
-           __FUNCTION__, cams, base_size, num_cams);
-
-       /* Copy callbacks, apply defaults for those that are not set */
-       memmove(&cams->cb, cbTbl, sizeof(cams->cb));
-       if (cams->cb.getFrame == NULL)
-               cams->cb.getFrame = usbvideo_GetFrame;
-       if (cams->cb.disconnect == NULL)
-               cams->cb.disconnect = usbvideo_Disconnect;
-       if (cams->cb.startDataPump == NULL)
-               cams->cb.startDataPump = usbvideo_StartDataPump;
-       if (cams->cb.stopDataPump == NULL)
-               cams->cb.stopDataPump = usbvideo_StopDataPump;
-
-       cams->num_cameras = num_cams;
-       cams->cam = (struct uvd *) &cams[1];
-       cams->md_module = md;
-       if (cams->md_module == NULL)
-               warn("%s: module == NULL!", __FUNCTION__);
-       mutex_init(&cams->lock);        /* to 1 == available */
-
-       for (i = 0; i < num_cams; i++) {
-               struct uvd *up = &cams->cam[i];
-
-               up->handle = cams;
-
-               /* Allocate user_data separately because of kmalloc's limits */
-               if (num_extra > 0) {
-                       up->user_size = num_cams * num_extra;
-                       up->user_data = kmalloc(up->user_size, GFP_KERNEL);
-                       if (up->user_data == NULL) {
-                               err("%s: Failed to allocate user_data (%d. bytes)",
-                                   __FUNCTION__, up->user_size);
-                               while (i) {
-                                       up = &cams->cam[--i];
-                                       kfree(up->user_data);
-                               }
-                               kfree(cams);
-                               return -ENOMEM;
-                       }
-                       dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
-                            __FUNCTION__, i, up->user_data, up->user_size);
-               }
-       }
-
-       /*
-        * Register ourselves with USB stack.
-        */
-       strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown");
-       cams->usbdrv.name = cams->drvName;
-       cams->usbdrv.probe = cams->cb.probe;
-       cams->usbdrv.disconnect = cams->cb.disconnect;
-       cams->usbdrv.id_table = id_table;
-
-       /*
-        * Update global handle to usbvideo. This is very important
-        * because probe() can be called before usb_register() returns.
-        * If the handle is not yet updated then the probe() will fail.
-        */
-       *pCams = cams;
-       result = usb_register(&cams->usbdrv);
-       if (result) {
-               for (i = 0; i < num_cams; i++) {
-                       struct uvd *up = &cams->cam[i];
-                       kfree(up->user_data);
-               }
-               kfree(cams);
-       }
-
-       return result;
-}
-
-EXPORT_SYMBOL(usbvideo_register);
-
-/*
- * usbvideo_Deregister()
- *
- * Procedure frees all usbvideo and user data structures. Be warned that
- * if you had some dynamically allocated components in ->user field then
- * you should free them before calling here.
- */
-void usbvideo_Deregister(struct usbvideo **pCams)
-{
-       struct usbvideo *cams;
-       int i;
-
-       if (pCams == NULL) {
-               err("%s: pCams == NULL", __FUNCTION__);
-               return;
-       }
-       cams = *pCams;
-       if (cams == NULL) {
-               err("%s: cams == NULL", __FUNCTION__);
-               return;
-       }
-
-       dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
-       usb_deregister(&cams->usbdrv);
-
-       dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
-       for (i=0; i < cams->num_cameras; i++) {
-               struct uvd *up = &cams->cam[i];
-               int warning = 0;
-
-               if (up->user_data != NULL) {
-                       if (up->user_size <= 0)
-                               ++warning;
-               } else {
-                       if (up->user_size > 0)
-                               ++warning;
-               }
-               if (warning) {
-                       err("%s: Warning: user_data=$%p user_size=%d.",
-                           __FUNCTION__, up->user_data, up->user_size);
-               } else {
-                       dbg("%s: Freeing %d. $%p->user_data=$%p",
-                           __FUNCTION__, i, up, up->user_data);
-                       kfree(up->user_data);
-               }
-       }
-       /* Whole array was allocated in one chunk */
-       dbg("%s: Freed %d uvd structures",
-           __FUNCTION__, cams->num_cameras);
-       kfree(cams);
-       *pCams = NULL;
-}
-
-EXPORT_SYMBOL(usbvideo_Deregister);
-
-/*
- * usbvideo_Disconnect()
- *
- * This procedure stops all driver activity. Deallocation of
- * the interface-private structure (pointed by 'ptr') is done now
- * (if we don't have any open files) or later, when those files
- * are closed. After that driver should be removable.
- *
- * This code handles surprise removal. The uvd->user is a counter which
- * increments on open() and decrements on close(). If we see here that
- * this counter is not 0 then we have a client who still has us opened.
- * We set uvd->remove_pending flag as early as possible, and after that
- * all access to the camera will gracefully fail. These failures should
- * prompt client to (eventually) close the video device, and then - in
- * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter.
- *
- * History:
- * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone.
- * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close()
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 19-Oct-2000 Moved to usbvideo module.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf)
-{
-       struct uvd *uvd = usb_get_intfdata (intf);
-       int i;
-
-       if (uvd == NULL) {
-               err("%s($%p): Illegal call.", __FUNCTION__, intf);
-               return;
-       }
-
-       usb_set_intfdata (intf, NULL);
-
-       usbvideo_ClientIncModCount(uvd);
-       if (uvd->debug > 0)
-               info("%s(%p.)", __FUNCTION__, intf);
-
-       mutex_lock(&uvd->lock);
-       uvd->remove_pending = 1; /* Now all ISO data will be ignored */
-
-       /* At this time we ask to cancel outstanding URBs */
-       GET_CALLBACK(uvd, stopDataPump)(uvd);
-
-       for (i=0; i < USBVIDEO_NUMSBUF; i++)
-               usb_free_urb(uvd->sbuf[i].urb);
-
-       usb_put_dev(uvd->dev);
-       uvd->dev = NULL;            /* USB device is no more */
-
-       video_unregister_device(&uvd->vdev);
-       if (uvd->debug > 0)
-               info("%s: Video unregistered.", __FUNCTION__);
-
-       if (uvd->user)
-               info("%s: In use, disconnect pending.", __FUNCTION__);
-       else
-               usbvideo_CameraRelease(uvd);
-       mutex_unlock(&uvd->lock);
-       info("USB camera disconnected.");
-
-       usbvideo_ClientDecModCount(uvd);
-}
-
-/*
- * usbvideo_CameraRelease()
- *
- * This code does final release of uvd. This happens
- * after the device is disconnected -and- all clients
- * closed their files.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static void usbvideo_CameraRelease(struct uvd *uvd)
-{
-       if (uvd == NULL) {
-               err("%s: Illegal call", __FUNCTION__);
-               return;
-       }
-
-       RingQueue_Free(&uvd->dp);
-       if (VALID_CALLBACK(uvd, userFree))
-               GET_CALLBACK(uvd, userFree)(uvd);
-       uvd->uvd_used = 0;      /* This is atomic, no need to take mutex */
-}
-
-/*
- * usbvideo_find_struct()
- *
- * This code searches the array of preallocated (static) structures
- * and returns index of the first one that isn't in use. Returns -1
- * if there are no free structures.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static int usbvideo_find_struct(struct usbvideo *cams)
-{
-       int u, rv = -1;
-
-       if (cams == NULL) {
-               err("No usbvideo handle?");
-               return -1;
-       }
-       mutex_lock(&cams->lock);
-       for (u = 0; u < cams->num_cameras; u++) {
-               struct uvd *uvd = &cams->cam[u];
-               if (!uvd->uvd_used) /* This one is free */
-               {
-                       uvd->uvd_used = 1;      /* In use now */
-                       mutex_init(&uvd->lock); /* to 1 == available */
-                       uvd->dev = NULL;
-                       rv = u;
-                       break;
-               }
-       }
-       mutex_unlock(&cams->lock);
-       return rv;
-}
-
-static struct file_operations usbvideo_fops = {
-       .owner =  THIS_MODULE,
-       .open =   usbvideo_v4l_open,
-       .release =usbvideo_v4l_close,
-       .read =   usbvideo_v4l_read,
-       .mmap =   usbvideo_v4l_mmap,
-       .ioctl =  usbvideo_v4l_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .llseek = no_llseek,
-};
-static const struct video_device usbvideo_template = {
-       .owner =      THIS_MODULE,
-       .type =       VID_TYPE_CAPTURE,
-       .hardware =   VID_HARDWARE_CPIA,
-       .fops =       &usbvideo_fops,
-};
-
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
-{
-       int i, devnum;
-       struct uvd *uvd = NULL;
-
-       if (cams == NULL) {
-               err("No usbvideo handle?");
-               return NULL;
-       }
-
-       devnum = usbvideo_find_struct(cams);
-       if (devnum == -1) {
-               err("IBM USB camera driver: Too many devices!");
-               return NULL;
-       }
-       uvd = &cams->cam[devnum];
-       dbg("Device entry #%d. at $%p", devnum, uvd);
-
-       /* Not relying upon caller we increase module counter ourselves */
-       usbvideo_ClientIncModCount(uvd);
-
-       mutex_lock(&uvd->lock);
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
-               if (uvd->sbuf[i].urb == NULL) {
-                       err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC);
-                       uvd->uvd_used = 0;
-                       uvd = NULL;
-                       goto allocate_done;
-               }
-       }
-       uvd->user=0;
-       uvd->remove_pending = 0;
-       uvd->last_error = 0;
-       RingQueue_Initialize(&uvd->dp);
-
-       /* Initialize video device structure */
-       uvd->vdev = usbvideo_template;
-       sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
-       /*
-        * The client is free to overwrite those because we
-        * return control to the client's probe function right now.
-        */
-allocate_done:
-       mutex_unlock(&uvd->lock);
-       usbvideo_ClientDecModCount(uvd);
-       return uvd;
-}
-
-EXPORT_SYMBOL(usbvideo_AllocateDevice);
-
-int usbvideo_RegisterVideoDevice(struct uvd *uvd)
-{
-       char tmp1[20], tmp2[20];        /* Buffers for printing */
-
-       if (uvd == NULL) {
-               err("%s: Illegal call.", __FUNCTION__);
-               return -EINVAL;
-       }
-       if (uvd->video_endp == 0) {
-               info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
-       }
-       if (uvd->paletteBits == 0) {
-               err("%s: No palettes specified!", __FUNCTION__);
-               return -EINVAL;
-       }
-       if (uvd->defaultPalette == 0) {
-               info("%s: No default palette!", __FUNCTION__);
-       }
-
-       uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
-               VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL;
-       usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize);
-       usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
-
-       if (uvd->debug > 0) {
-               info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
-                    __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
-       }
-       if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-               err("%s: video_register_device failed", __FUNCTION__);
-               return -EPIPE;
-       }
-       if (uvd->debug > 1) {
-               info("%s: video_register_device() successful", __FUNCTION__);
-       }
-       if (uvd->dev == NULL) {
-               err("%s: uvd->dev == NULL", __FUNCTION__);
-               return -EINVAL;
-       }
-
-       info("%s on /dev/video%d: canvas=%s videosize=%s",
-            (uvd->handle != NULL) ? uvd->handle->drvName : "???",
-            uvd->vdev.minor, tmp2, tmp1);
-
-       usb_get_dev(uvd->dev);
-       return 0;
-}
-
-EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
-
-/* ******************************************************************** */
-
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct uvd *uvd = file->private_data;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return -EFAULT;
-
-       if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
-               return -EINVAL;
-
-       pos = (unsigned long) uvd->fbuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-/*
- * usbvideo_v4l_open()
- *
- * This is part of Video 4 Linux API. The driver can be opened by one
- * client only (checks internal counter 'uvdser'). The procedure
- * then allocates buffers needed for video processing.
- *
- * History:
- * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the
- *             camera is also initialized here (once per connect), at
- *             expense of V4L client (it waits on open() call).
- * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- */
-static int usbvideo_v4l_open(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct uvd *uvd = (struct uvd *) dev;
-       const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
-       int i, errCode = 0;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, dev);
-
-       usbvideo_ClientIncModCount(uvd);
-       mutex_lock(&uvd->lock);
-
-       if (uvd->user) {
-               err("%s: Someone tried to open an already opened device!", __FUNCTION__);
-               errCode = -EBUSY;
-       } else {
-               /* Clear statistics */
-               memset(&uvd->stats, 0, sizeof(uvd->stats));
-
-               /* Clean pointers so we know if we allocated something */
-               for (i=0; i < USBVIDEO_NUMSBUF; i++)
-                       uvd->sbuf[i].data = NULL;
-
-               /* Allocate memory for the frame buffers */
-               uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
-               uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
-               RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
-               if ((uvd->fbuf == NULL) ||
-                   (!RingQueue_IsAllocated(&uvd->dp))) {
-                       err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
-                       errCode = -ENOMEM;
-               } else {
-                       /* Allocate all buffers */
-                       for (i=0; i < USBVIDEO_NUMFRAMES; i++) {
-                               uvd->frame[i].frameState = FrameState_Unused;
-                               uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);
-                               /*
-                                * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
-                                * is not used (using read() instead).
-                                */
-                               uvd->frame[i].canvas = uvd->canvas;
-                               uvd->frame[i].seqRead_Index = 0;
-                       }
-                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-                               uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
-                               if (uvd->sbuf[i].data == NULL) {
-                                       errCode = -ENOMEM;
-                                       break;
-                               }
-                       }
-               }
-               if (errCode != 0) {
-                       /* Have to free all that memory */
-                       if (uvd->fbuf != NULL) {
-                               usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
-                               uvd->fbuf = NULL;
-                       }
-                       RingQueue_Free(&uvd->dp);
-                       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-                               kfree(uvd->sbuf[i].data);
-                               uvd->sbuf[i].data = NULL;
-                       }
-               }
-       }
-
-       /* If so far no errors then we shall start the camera */
-       if (errCode == 0) {
-               /* Start data pump if we have valid endpoint */
-               if (uvd->video_endp != 0)
-                       errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
-               if (errCode == 0) {
-                       if (VALID_CALLBACK(uvd, setupOnOpen)) {
-                               if (uvd->debug > 1)
-                                       info("%s: setupOnOpen callback", __FUNCTION__);
-                               errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
-                               if (errCode < 0) {
-                                       err("%s: setupOnOpen callback failed (%d.).",
-                                           __FUNCTION__, errCode);
-                               } else if (uvd->debug > 1) {
-                                       info("%s: setupOnOpen callback successful", __FUNCTION__);
-                               }
-                       }
-                       if (errCode == 0) {
-                               uvd->settingsAdjusted = 0;
-                               if (uvd->debug > 1)
-                                       info("%s: Open succeeded.", __FUNCTION__);
-                               uvd->user++;
-                               file->private_data = uvd;
-                       }
-               }
-       }
-       mutex_unlock(&uvd->lock);
-       if (errCode != 0)
-               usbvideo_ClientDecModCount(uvd);
-       if (uvd->debug > 0)
-               info("%s: Returning %d.", __FUNCTION__, errCode);
-       return errCode;
-}
-
-/*
- * usbvideo_v4l_close()
- *
- * This is part of Video 4 Linux API. The procedure
- * stops streaming and deallocates all buffers that were earlier
- * allocated in usbvideo_v4l_open().
- *
- * History:
- * 22-Jan-2000 Moved scratch buffer deallocation here.
- * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers.
- * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep.
- */
-static int usbvideo_v4l_close(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = file->private_data;
-       struct uvd *uvd = (struct uvd *) dev;
-       int i;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, dev);
-
-       mutex_lock(&uvd->lock);
-       GET_CALLBACK(uvd, stopDataPump)(uvd);
-       usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
-       uvd->fbuf = NULL;
-       RingQueue_Free(&uvd->dp);
-
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               kfree(uvd->sbuf[i].data);
-               uvd->sbuf[i].data = NULL;
-       }
-
-#if USBVIDEO_REPORT_STATS
-       usbvideo_ReportStatistics(uvd);
-#endif    
-
-       uvd->user--;
-       if (uvd->remove_pending) {
-               if (uvd->debug > 0)
-                       info("usbvideo_v4l_close: Final disconnect.");
-               usbvideo_CameraRelease(uvd);
-       }
-       mutex_unlock(&uvd->lock);
-       usbvideo_ClientDecModCount(uvd);
-
-       if (uvd->debug > 1)
-               info("%s: Completed.", __FUNCTION__);
-       file->private_data = NULL;
-       return 0;
-}
-
-/*
- * usbvideo_v4l_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
- * History:
- * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
- */
-static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
-                                unsigned int cmd, void *arg)
-{
-       struct uvd *uvd = file->private_data;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return -EIO;
-
-       switch (cmd) {
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *b = arg;
-                       *b = uvd->vcap;
-                       return 0;
-               }
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-                       *v = uvd->vchan;
-                       return 0;
-               }
-               case VIDIOCSCHAN:
-               {       
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-               case VIDIOCGPICT:
-               {
-                       struct video_picture *pic = arg;
-                       *pic = uvd->vpic;
-                       return 0;
-               }
-               case VIDIOCSPICT:
-               {
-                       struct video_picture *pic = arg;
-                       /*
-                        * Use temporary 'video_picture' structure to preserve our
-                        * own settings (such as color depth, palette) that we
-                        * aren't allowing everyone (V4L client) to change.
-                        */
-                       uvd->vpic.brightness = pic->brightness;
-                       uvd->vpic.hue = pic->hue;
-                       uvd->vpic.colour = pic->colour;
-                       uvd->vpic.contrast = pic->contrast;
-                       uvd->settingsAdjusted = 0;      /* Will force new settings */
-                       return 0;
-               }
-               case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       if(VALID_CALLBACK(uvd, setVideoMode)) {
-                               return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
-                       }
-
-                       if (vw->flags)
-                               return -EINVAL;
-                       if (vw->clipcount)
-                               return -EINVAL;
-                       if (vw->width != VIDEOSIZE_X(uvd->canvas))
-                               return -EINVAL;
-                       if (vw->height != VIDEOSIZE_Y(uvd->canvas))
-                               return -EINVAL;
-
-                       return 0;
-               }
-               case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = VIDEOSIZE_X(uvd->videosize);
-                       vw->height = VIDEOSIZE_Y(uvd->videosize);
-                       vw->chromakey = 0;
-                       if (VALID_CALLBACK(uvd, getFPS))
-                               vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
-                       else 
-                               vw->flags = 10; /* FIXME: do better! */
-                       return 0;
-               }
-               case VIDIOCGMBUF:
-               {
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset(vm, 0, sizeof(*vm));
-                       vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
-                       vm->frames = USBVIDEO_NUMFRAMES;
-                       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) 
-                         vm->offsets[i] = i * uvd->max_frame_size;
-
-                       return 0;
-               }
-               case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap *vm = arg;
-
-                       if (uvd->debug >= 1) {
-                               info("VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.",
-                                    vm->frame, vm->width, vm->height, vm->format);
-                       }
-                       /*
-                        * Check if the requested size is supported. If the requestor
-                        * requests too big a frame then we may be tricked into accessing
-                        * outside of own preallocated frame buffer (in uvd->frame).
-                        * This will cause oops or a security hole. Theoretically, we
-                        * could only clamp the size down to acceptable bounds, but then
-                        * we'd need to figure out how to insert our smaller buffer into
-                        * larger caller's buffer... this is not an easy question. So we
-                        * here just flatly reject too large requests, assuming that the
-                        * caller will resubmit with smaller size. Callers should know
-                        * what size we support (returned by VIDIOCGCAP). However vidcat,
-                        * for one, does not care and allows to ask for any size.
-                        */
-                       if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
-                           (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
-                               if (uvd->debug > 0) {
-                                       info("VIDIOCMCAPTURE: Size=%dx%d too large; "
-                                            "allowed only up to %ldx%ld", vm->width, vm->height,
-                                            VIDEOSIZE_X(uvd->canvas), VIDEOSIZE_Y(uvd->canvas));
-                               }
-                               return -EINVAL;
-                       }
-                       /* Check if the palette is supported */
-                       if (((1L << vm->format) & uvd->paletteBits) == 0) {
-                               if (uvd->debug > 0) {
-                                       info("VIDIOCMCAPTURE: format=%d. not supported"
-                                            " (paletteBits=$%08lx)",
-                                            vm->format, uvd->paletteBits);
-                               }
-                               return -EINVAL;
-                       }
-                       if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
-                               err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
-                               return -EINVAL;
-                       }
-                       if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
-                               /* Not an error - can happen */
-                       }
-                       uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
-                       uvd->frame[vm->frame].palette = vm->format;
-
-                       /* Mark it as ready */
-                       uvd->frame[vm->frame].frameState = FrameState_Ready;
-
-                       return usbvideo_NewFrame(uvd, vm->frame);
-               }
-               case VIDIOCSYNC:
-               {
-                       int *frameNum = arg;
-                       int ret;
-
-                       if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
-                               return -EINVAL;
-                               
-                       if (uvd->debug >= 1)
-                               info("VIDIOCSYNC: syncing to frame %d.", *frameNum);
-                       if (uvd->flags & FLAGS_NO_DECODING)
-                               ret = usbvideo_GetFrame(uvd, *frameNum);
-                       else if (VALID_CALLBACK(uvd, getFrame)) {
-                               ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
-                               if ((ret < 0) && (uvd->debug >= 1)) {
-                                       err("VIDIOCSYNC: getFrame() returned %d.", ret);
-                               }
-                       } else {
-                               err("VIDIOCSYNC: getFrame is not set");
-                               ret = -EFAULT;
-                       }
-
-                       /*
-                        * The frame is in FrameState_Done_Hold state. Release it
-                        * right now because its data is already mapped into
-                        * the user space and it's up to the application to
-                        * make use of it until it asks for another frame.
-                        */
-                       uvd->frame[*frameNum].frameState = FrameState_Unused;
-                       return ret;
-               }
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb, 0, sizeof(*vb));
-                       return 0;
-               }
-               case VIDIOCKEY:
-                       return 0;
-
-               case VIDIOCCAPTURE:
-                       return -EINVAL;
-
-               case VIDIOCSFBUF:
-
-               case VIDIOCGTUNER:
-               case VIDIOCSTUNER:
-
-               case VIDIOCGFREQ:
-               case VIDIOCSFREQ:
-
-               case VIDIOCGAUDIO:
-               case VIDIOCSAUDIO:
-                       return -EINVAL;
-
-               default:
-                       return -ENOIOCTLCMD;
-       }
-       return 0;
-}
-
-static int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
-}
-
-/*
- * usbvideo_v4l_read()
- *
- * This is mostly boring stuff. We simply ask for a frame and when it
- * arrives copy all the video data from it into user space. There is
- * no obvious need to override this method.
- *
- * History:
- * 20-Oct-2000 Created.
- * 01-Nov-2000 Added mutex (uvd->lock).
- */
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
-                     size_t count, loff_t *ppos)
-{
-       struct uvd *uvd = file->private_data;
-       int noblock = file->f_flags & O_NONBLOCK;
-       int frmx = -1, i;
-       struct usbvideo_frame *frame;
-
-       if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
-               return -EFAULT;
-
-       if (uvd->debug >= 1)
-               info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
-
-       mutex_lock(&uvd->lock);
-
-       /* See if a frame is completed, then use it. */
-       for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-               if ((uvd->frame[i].frameState == FrameState_Done) ||
-                   (uvd->frame[i].frameState == FrameState_Done_Hold) ||
-                   (uvd->frame[i].frameState == FrameState_Error)) {
-                       frmx = i;
-                       break;
-               }
-       }
-
-       /* FIXME: If we don't start a frame here then who ever does? */
-       if (noblock && (frmx == -1)) {
-               count = -EAGAIN;
-               goto read_done;
-       }
-
-       /*
-        * If no FrameState_Done, look for a FrameState_Grabbing state.
-        * See if a frame is in process (grabbing), then use it.
-        * We will need to wait until it becomes cooked, of course.
-        */
-       if (frmx == -1) {
-               for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
-                       if (uvd->frame[i].frameState == FrameState_Grabbing) {
-                               frmx = i;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * If no frame is active, start one. We don't care which one
-        * it will be, so #0 is as good as any.
-        * In read access mode we don't have convenience of VIDIOCMCAPTURE
-        * to specify the requested palette (video format) on per-frame
-        * basis. This means that we have to return data in -some- format
-        * and just hope that the client knows what to do with it.
-        * The default format is configured in uvd->defaultPalette field
-        * as one of VIDEO_PALETTE_xxx values. We stuff it into the new
-        * frame and initiate the frame filling process.
-        */
-       if (frmx == -1) {
-               if (uvd->defaultPalette == 0) {
-                       err("%s: No default palette; don't know what to do!", __FUNCTION__);
-                       count = -EFAULT;
-                       goto read_done;
-               }
-               frmx = 0;
-               /*
-                * We have no per-frame control over video size.
-                * Therefore we only can use whatever size was
-                * specified as default.
-                */
-               uvd->frame[frmx].request = uvd->videosize;
-               uvd->frame[frmx].palette = uvd->defaultPalette;
-               uvd->frame[frmx].frameState = FrameState_Ready;
-               usbvideo_NewFrame(uvd, frmx);
-               /* Now frame 0 is supposed to start filling... */
-       }
-
-       /*
-        * Get a pointer to the active frame. It is either previously
-        * completed frame or frame in progress but not completed yet.
-        */
-       frame = &uvd->frame[frmx];
-
-       /*
-        * Sit back & wait until the frame gets filled and postprocessed.
-        * If we fail to get the picture [in time] then return the error.
-        * In this call we specify that we want the frame to be waited for,
-        * postprocessed and switched into FrameState_Done_Hold state. This
-        * state is used to hold the frame as "fully completed" between
-        * subsequent partial reads of the same frame.
-        */
-       if (frame->frameState != FrameState_Done_Hold) {
-               long rv = -EFAULT;
-               if (uvd->flags & FLAGS_NO_DECODING)
-                       rv = usbvideo_GetFrame(uvd, frmx);
-               else if (VALID_CALLBACK(uvd, getFrame))
-                       rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);
-               else
-                       err("getFrame is not set");
-               if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {
-                       count = rv;
-                       goto read_done;
-               }
-       }
-
-       /*
-        * Copy bytes to user space. We allow for partial reads, which
-        * means that the user application can request read less than
-        * the full frame size. It is up to the application to issue
-        * subsequent calls until entire frame is read.
-        *
-        * First things first, make sure we don't copy more than we
-        * have - even if the application wants more. That would be
-        * a big security embarassment!
-        */
-       if ((count + frame->seqRead_Index) > frame->seqRead_Length)
-               count = frame->seqRead_Length - frame->seqRead_Index;
-
-       /*
-        * Copy requested amount of data to user space. We start
-        * copying from the position where we last left it, which
-        * will be zero for a new frame (not read before).
-        */
-       if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {
-               count = -EFAULT;
-               goto read_done;
-       }
-
-       /* Update last read position */
-       frame->seqRead_Index += count;
-       if (uvd->debug >= 1) {
-               err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
-                       __FUNCTION__, count, frame->seqRead_Index);
-       }
-
-       /* Finally check if the frame is done with and "release" it */
-       if (frame->seqRead_Index >= frame->seqRead_Length) {
-               /* All data has been read */
-               frame->seqRead_Index = 0;
-
-               /* Mark it as available to be used again. */
-               uvd->frame[frmx].frameState = FrameState_Unused;
-               if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
-                       err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
-               }
-       }
-read_done:
-       mutex_unlock(&uvd->lock);
-       return count;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
-{
-       char *cdata;
-       int i, totlen = 0;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               int n = urb->iso_frame_desc[i].actual_length;
-               int st = urb->iso_frame_desc[i].status;
-
-               cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
-               /* Detect and ignore errored packets */
-               if (st < 0) {
-                       if (uvd->debug >= 1)
-                               err("Data error: packet=%d. len=%d. status=%d.", i, n, st);
-                       uvd->stats.iso_err_count++;
-                       continue;
-               }
-
-               /* Detect and ignore empty packets */
-               if (n <= 0) {
-                       uvd->stats.iso_skip_count++;
-                       continue;
-               }
-               totlen += n;    /* Little local accounting */
-               RingQueue_Enqueue(&uvd->dp, cdata, n);
-       }
-       return totlen;
-}
-
-static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs)
-{
-       int i, ret, len;
-       struct uvd *uvd = urb->context;
-
-       /* We don't want to do anything if we are about to be removed! */
-       if (!CAMERA_IS_OPERATIONAL(uvd))
-               return;
-#if 0
-       if (urb->actual_length > 0) {
-               info("urb=$%p status=%d. errcount=%d. length=%d.",
-                    urb, urb->status, urb->error_count, urb->actual_length);
-       } else {
-               static int c = 0;
-               if (c++ % 100 == 0)
-                       info("No Isoc data");
-       }
-#endif
-
-       if (!uvd->streaming) {
-               if (uvd->debug >= 1)
-                       info("Not streaming, but interrupt!");
-               return;
-       }
-       
-       uvd->stats.urb_count++;
-       if (urb->actual_length <= 0)
-               goto urb_done_with;
-
-       /* Copy the data received into ring queue */
-       len = usbvideo_CompressIsochronous(uvd, urb);
-       uvd->stats.urb_length = len;
-       if (len <= 0)
-               goto urb_done_with;
-
-       /* Here we got some data */
-       uvd->stats.data_count += len;
-       RingQueue_WakeUpInterruptible(&uvd->dp);
-
-urb_done_with:
-       for (i = 0; i < FRAMES_PER_DESC; i++) {
-               urb->iso_frame_desc[i].status = 0;
-               urb->iso_frame_desc[i].actual_length = 0;
-       }
-       urb->status = 0;
-       urb->dev = uvd->dev;
-       ret = usb_submit_urb (urb, GFP_KERNEL);
-       if(ret)
-               err("usb_submit_urb error (%d)", ret);
-       return;
-}
-
-/*
- * usbvideo_StartDataPump()
- *
- * History:
- * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead
- *             of hardcoded values. Simplified by using for loop,
- *             allowed any number of URBs.
- */
-static int usbvideo_StartDataPump(struct uvd *uvd)
-{
-       struct usb_device *dev = uvd->dev;
-       int i, errFlag;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, uvd);
-
-       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-               err("%s: Camera is not operational", __FUNCTION__);
-               return -EFAULT;
-       }
-       uvd->curframe = -1;
-
-       /* Alternate interface 1 is is the biggest frame size */
-       i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
-       if (i < 0) {
-               err("%s: usb_set_interface error", __FUNCTION__);
-               uvd->last_error = i;
-               return -EBUSY;
-       }
-       if (VALID_CALLBACK(uvd, videoStart))
-               GET_CALLBACK(uvd, videoStart)(uvd);
-       else 
-               err("%s: videoStart not set", __FUNCTION__);
-
-       /* We double buffer the Iso lists */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               int j, k;
-               struct urb *urb = uvd->sbuf[i].urb;
-               urb->dev = dev;
-               urb->context = uvd;
-               urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
-               urb->interval = 1;
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = uvd->sbuf[i].data;
-               urb->complete = usbvideo_IsocIrq;
-               urb->number_of_packets = FRAMES_PER_DESC;
-               urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
-               for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length = uvd->iso_packet_len;
-               }
-       }
-
-       /* Submit all URBs */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
-               if (errFlag)
-                       err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
-       }
-
-       uvd->streaming = 1;
-       if (uvd->debug > 1)
-               info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
-       return 0;
-}
-
-/*
- * usbvideo_StopDataPump()
- *
- * This procedure stops streaming and deallocates URBs. Then it
- * activates zero-bandwidth alt. setting of the video interface.
- *
- * History:
- * 22-Jan-2000 Corrected order of actions to work after surprise removal.
- * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
- */
-static void usbvideo_StopDataPump(struct uvd *uvd)
-{
-       int i, j;
-
-       if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
-               return;
-
-       if (uvd->debug > 1)
-               info("%s($%p)", __FUNCTION__, uvd);
-
-       /* Unschedule all of the iso td's */
-       for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-               usb_kill_urb(uvd->sbuf[i].urb);
-       }
-       if (uvd->debug > 1)
-               info("%s: streaming=0", __FUNCTION__);
-       uvd->streaming = 0;
-
-       if (!uvd->remove_pending) {
-               /* Invoke minidriver's magic to stop the camera */
-               if (VALID_CALLBACK(uvd, videoStop))
-                       GET_CALLBACK(uvd, videoStop)(uvd);
-               else 
-                       err("%s: videoStop not set", __FUNCTION__);
-
-               /* Set packet size to 0 */
-               j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
-               if (j < 0) {
-                       err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
-                       uvd->last_error = j;
-               }
-       }
-}
-
-/*
- * usbvideo_NewFrame()
- *
- * History:
- * 29-Mar-00 Added copying of previous frame into the current one.
- * 6-Aug-00  Added model 3 video sizes, removed redundant width, height.
- */
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
-{
-       struct usbvideo_frame *frame;
-       int n;
-
-       if (uvd->debug > 1)
-               info("usbvideo_NewFrame($%p,%d.)", uvd, framenum);
-
-       /* If we're not grabbing a frame right now and the other frame is */
-       /*  ready to be grabbed into, then use it instead */
-       if (uvd->curframe != -1)
-               return 0;
-
-       /* If necessary we adjust picture settings between frames */
-       if (!uvd->settingsAdjusted) {
-               if (VALID_CALLBACK(uvd, adjustPicture))
-                       GET_CALLBACK(uvd, adjustPicture)(uvd);
-               uvd->settingsAdjusted = 1;
-       }
-
-       n = (framenum + 1) % USBVIDEO_NUMFRAMES;
-       if (uvd->frame[n].frameState == FrameState_Ready)
-               framenum = n;
-
-       frame = &uvd->frame[framenum];
-
-       frame->frameState = FrameState_Grabbing;
-       frame->scanstate = ScanState_Scanning;
-       frame->seqRead_Length = 0;      /* Accumulated in xxx_parse_data() */
-       frame->deinterlace = Deinterlace_None;
-       frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */
-       uvd->curframe = framenum;
-
-       /*
-        * Normally we would want to copy previous frame into the current one
-        * before we even start filling it with data; this allows us to stop
-        * filling at any moment; top portion of the frame will be new and
-        * bottom portion will stay as it was in previous frame. If we don't
-        * do that then missing chunks of video stream will result in flickering
-        * portions of old data whatever it was before.
-        *
-        * If we choose not to copy previous frame (to, for example, save few
-        * bus cycles - the frame can be pretty large!) then we have an option
-        * to clear the frame before using. If we experience losses in this
-        * mode then missing picture will be black (no flickering).
-        *
-        * Finally, if user chooses not to clean the current frame before
-        * filling it with data then the old data will be visible if we fail
-        * to refill entire frame with new data.
-        */
-       if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
-               /* This copies previous frame into this one to mask losses */
-               int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
-               memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
-       } else {
-               if (uvd->flags & FLAGS_CLEAN_FRAMES) {
-                       /* This provides a "clean" frame but slows things down */
-                       memset(frame->data, 0, uvd->max_frame_size);
-               }
-       }
-       return 0;
-}
-
-/*
- * usbvideo_CollectRawData()
- *
- * This procedure can be used instead of 'processData' callback if you
- * only want to dump the raw data from the camera into the output
- * device (frame buffer). You can look at it with V4L client, but the
- * image will be unwatchable. The main purpose of this code and of the
- * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from
- * new, unknown cameras. This procedure will be automatically invoked
- * instead of the specified callback handler when uvd->flags has bit
- * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
- * based on usbvideo can use this feature at any time.
- */
-static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       int n;
-
-       assert(uvd != NULL);
-       assert(frame != NULL);
-
-       /* Try to move data from queue into frame buffer */
-       n = RingQueue_GetLength(&uvd->dp);
-       if (n > 0) {
-               int m;
-               /* See how much space we have left */
-               m = uvd->max_frame_size - frame->seqRead_Length;
-               if (n > m)
-                       n = m;
-               /* Now move that much data into frame buffer */
-               RingQueue_Dequeue(
-                       &uvd->dp,
-                       frame->data + frame->seqRead_Length,
-                       m);
-               frame->seqRead_Length += m;
-       }
-       /* See if we filled the frame */
-       if (frame->seqRead_Length >= uvd->max_frame_size) {
-               frame->frameState = FrameState_Done;
-               uvd->curframe = -1;
-               uvd->stats.frame_num++;
-       }
-}
-
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
-{
-       struct usbvideo_frame *frame = &uvd->frame[frameNum];
-
-       if (uvd->debug >= 2)
-               info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
-
-       switch (frame->frameState) {
-        case FrameState_Unused:
-               if (uvd->debug >= 2)
-                       info("%s: FrameState_Unused", __FUNCTION__);
-               return -EINVAL;
-        case FrameState_Ready:
-        case FrameState_Grabbing:
-        case FrameState_Error:
-        {
-               int ntries, signalPending;
-       redo:
-               if (!CAMERA_IS_OPERATIONAL(uvd)) {
-                       if (uvd->debug >= 2)
-                               info("%s: Camera is not operational (1)", __FUNCTION__);
-                       return -EIO;
-               }
-               ntries = 0; 
-               do {
-                       RingQueue_InterruptibleSleepOn(&uvd->dp);
-                       signalPending = signal_pending(current);
-                       if (!CAMERA_IS_OPERATIONAL(uvd)) {
-                               if (uvd->debug >= 2)
-                                       info("%s: Camera is not operational (2)", __FUNCTION__);
-                               return -EIO;
-                       }
-                       assert(uvd->fbuf != NULL);
-                       if (signalPending) {
-                               if (uvd->debug >= 2)
-                                       info("%s: Signal=$%08x", __FUNCTION__, signalPending);
-                               if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
-                                       usbvideo_TestPattern(uvd, 1, 0);
-                                       uvd->curframe = -1;
-                                       uvd->stats.frame_num++;
-                                       if (uvd->debug >= 2)
-                                               info("%s: Forced test pattern screen", __FUNCTION__);
-                                       return 0;
-                               } else {
-                                       /* Standard answer: Interrupted! */
-                                       if (uvd->debug >= 2)
-                                               info("%s: Interrupted!", __FUNCTION__);
-                                       return -EINTR;
-                               }
-                       } else {
-                               /* No signals - we just got new data in dp queue */
-                               if (uvd->flags & FLAGS_NO_DECODING)
-                                       usbvideo_CollectRawData(uvd, frame);
-                               else if (VALID_CALLBACK(uvd, processData))
-                                       GET_CALLBACK(uvd, processData)(uvd, frame);
-                               else 
-                                       err("%s: processData not set", __FUNCTION__);
-                       }
-               } while (frame->frameState == FrameState_Grabbing);
-               if (uvd->debug >= 2) {
-                       info("%s: Grabbing done; state=%d. (%lu. bytes)",
-                            __FUNCTION__, frame->frameState, frame->seqRead_Length);
-               }
-               if (frame->frameState == FrameState_Error) {
-                       int ret = usbvideo_NewFrame(uvd, frameNum);
-                       if (ret < 0) {
-                               err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
-                               return ret;
-                       }
-                       goto redo;
-               }
-               /* Note that we fall through to meet our destiny below */
-        }
-        case FrameState_Done:
-               /*
-                * Do all necessary postprocessing of data prepared in
-                * "interrupt" code and the collecting code above. The
-                * frame gets marked as FrameState_Done by queue parsing code.
-                * This status means that we collected enough data and
-                * most likely processed it as we went through. However
-                * the data may need postprocessing, such as deinterlacing
-                * or picture adjustments implemented in software (horror!)
-                *
-                * As soon as the frame becomes "final" it gets promoted to
-                * FrameState_Done_Hold status where it will remain until the
-                * caller consumed all the video data from the frame. Then
-                * the empty shell of ex-frame is thrown out for dogs to eat.
-                * But we, worried about pets, will recycle the frame!
-                */
-               uvd->stats.frame_num++;
-               if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
-                       if (VALID_CALLBACK(uvd, postProcess))
-                               GET_CALLBACK(uvd, postProcess)(uvd, frame);
-                       if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
-                               usbvideo_SoftwareContrastAdjustment(uvd, frame);
-               }
-               frame->frameState = FrameState_Done_Hold;
-               if (uvd->debug >= 2)
-                       info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
-               return 0;
-
-       case FrameState_Done_Hold:
-               /*
-                * We stay in this state indefinitely until someone external,
-                * like ioctl() or read() call finishes digesting the frame
-                * data. Then it will mark the frame as FrameState_Unused and
-                * it will be released back into the wild to roam freely.
-                */
-               if (uvd->debug >= 2)
-                       info("%s: FrameState_Done_Hold state.", __FUNCTION__);
-               return 0;
-       }
-
-       /* Catch-all for other cases. We shall not be here. */
-       err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
-       frame->frameState = FrameState_Unused;
-       return 0;
-}
-
-/*
- * usbvideo_DeinterlaceFrame()
- *
- * This procedure deinterlaces the given frame. Some cameras produce
- * only half of scanlines - sometimes only even lines, sometimes only
- * odd lines. The deinterlacing method is stored in frame->deinterlace
- * variable.
- *
- * Here we scan the frame vertically and replace missing scanlines with
- * average between surrounding ones - before and after. If we have no
- * line above then we just copy next line. Similarly, if we need to
- * create a last line then preceding line is used.
- */
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
-{
-       if ((uvd == NULL) || (frame == NULL))
-               return;
-
-       if ((frame->deinterlace == Deinterlace_FillEvenLines) ||
-           (frame->deinterlace == Deinterlace_FillOddLines))
-       {
-               const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-               int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1;
-
-               for (; i < VIDEOSIZE_Y(frame->request); i += 2) {
-                       const unsigned char *fs1, *fs2;
-                       unsigned char *fd;
-                       int ip, in, j;  /* Previous and next lines */
-
-                       /*
-                        * Need to average lines before and after 'i'.
-                        * If we go out of bounds seeking those lines then
-                        * we point back to existing line.
-                        */
-                       ip = i - 1;     /* First, get rough numbers */
-                       in = i + 1;
-
-                       /* Now validate */
-                       if (ip < 0)
-                               ip = in;
-                       if (in >= VIDEOSIZE_Y(frame->request))
-                               in = ip;
-
-                       /* Sanity check */
-                       if ((ip < 0) || (in < 0) ||
-                           (ip >= VIDEOSIZE_Y(frame->request)) ||
-                           (in >= VIDEOSIZE_Y(frame->request)))
-                       {
-                               err("Error: ip=%d. in=%d. req.height=%ld.",
-                                   ip, in, VIDEOSIZE_Y(frame->request));
-                               break;
-                       }
-
-                       /* Now we need to average lines 'ip' and 'in' to produce line 'i' */
-                       fs1 = frame->data + (v4l_linesize * ip);
-                       fs2 = frame->data + (v4l_linesize * in);
-                       fd = frame->data + (v4l_linesize * i);
-
-                       /* Average lines around destination */
-                       for (j=0; j < v4l_linesize; j++) {
-                               fd[j] = (unsigned char)((((unsigned) fs1[j]) +
-                                                        ((unsigned)fs2[j])) >> 1);
-                       }
-               }
-       }
-
-       /* Optionally display statistics on the screen */
-       if (uvd->flags & FLAGS_OVERLAY_STATS)
-               usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
-
-/*
- * usbvideo_SoftwareContrastAdjustment()
- *
- * This code adjusts the contrast of the frame, assuming RGB24 format.
- * As most software image processing, this job is CPU-intensive.
- * Get a camera that supports hardware adjustment!
- *
- * History:
- * 09-Feb-2001  Created.
- */
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, 
-                                               struct usbvideo_frame *frame)
-{
-       int i, j, v4l_linesize;
-       signed long adj;
-       const int ccm = 128; /* Color correction median - see below */
-
-       if ((uvd == NULL) || (frame == NULL)) {
-               err("%s: Illegal call.", __FUNCTION__);
-               return;
-       }
-       adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
-       RESTRICT_TO_RANGE(adj, -ccm, ccm+1);
-       if (adj == 0) {
-               /* In rare case of no adjustment */
-               return;
-       }
-       v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-       for (i=0; i < VIDEOSIZE_Y(frame->request); i++) {
-               unsigned char *fd = frame->data + (v4l_linesize * i);
-               for (j=0; j < v4l_linesize; j++) {
-                       signed long v = (signed long) fd[j];
-                       /* Magnify up to 2 times, reduce down to zero */
-                       v = 128 + ((ccm + adj) * (v - 128)) / ccm;
-                       RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */
-                       fd[j] = (unsigned char) v;
-               }
-       }
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
deleted file mode 100644 (file)
index 135433c..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef usbvideo_h
-#define        usbvideo_h
-
-#include <linux/config.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-/* Most helpful debugging aid */
-#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
-
-#define USBVIDEO_REPORT_STATS  1       /* Set to 0 to block statistics on close */
-
-/* Bit flags (options) */
-#define FLAGS_RETRY_VIDIOCSYNC         (1 << 0)
-#define        FLAGS_MONOCHROME                (1 << 1)
-#define FLAGS_DISPLAY_HINTS            (1 << 2)
-#define FLAGS_OVERLAY_STATS            (1 << 3)
-#define FLAGS_FORCE_TESTPATTERN                (1 << 4)
-#define FLAGS_SEPARATE_FRAMES          (1 << 5)
-#define FLAGS_CLEAN_FRAMES             (1 << 6)
-#define        FLAGS_NO_DECODING               (1 << 7)
-
-/* Bit flags for frames (apply to the frame where they are specified) */
-#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST  (1 << 0)
-
-/* Camera capabilities (maximum) */
-#define CAMERA_URB_FRAMES       32
-#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
-#define FRAMES_PER_DESC                (CAMERA_URB_FRAMES)
-#define FRAME_SIZE_PER_DESC    (CAMERA_MAX_ISO_PACKET)
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
-
-#define V4L_BYTES_PER_PIXEL     3      /* Because we produce RGB24 */
-
-/*
- * Use this macro to construct constants for different video sizes.
- * We have to deal with different video sizes that have to be
- * configured in the device or compared against when we receive
- * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y
- * #defines and that's the end of story. However this solution
- * does not allow to convert between real pixel sizes and the
- * constant (integer) value that may be used to tag a frame or
- * whatever. The set of macros below constructs videosize constants
- * from the pixel size and allows to reconstruct the pixel size
- * from the combined value later.
- */
-#define        VIDEOSIZE(x,y)  (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16))
-#define        VIDEOSIZE_X(vs) ((vs) & 0xFFFFL)
-#define        VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL)
-typedef unsigned long videosize_t;
-
-/*
- * This macro checks if the camera is still operational. The 'uvd'
- * pointer must be valid, uvd->dev must be valid, we are not
- * removing the device and the device has not erred on us.
- */
-#define CAMERA_IS_OPERATIONAL(uvd) (\
-       (uvd != NULL) && \
-       ((uvd)->dev != NULL) && \
-       ((uvd)->last_error == 0) && \
-       (!(uvd)->remove_pending))
-
-/*
- * We use macros to do YUV -> RGB conversion because this is
- * very important for speed and totally unimportant for size.
- *
- * YUV -> RGB Conversion
- * ---------------------
- *
- * B = 1.164*(Y-16)                + 2.018*(V-128)
- * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
- * R = 1.164*(Y-16) + 1.596*(U-128)
- *
- * If you fancy integer arithmetics (as you should), hear this:
- *
- * 65536*B = 76284*(Y-16)                + 132252*(V-128)
- * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
- * 65536*R = 76284*(Y-16) + 104595*(U-128)
- *
- * Make sure the output values are within [0..255] range.
- */
-#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
-#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
-    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
-    mm_y = (my) - 16;  \
-    mm_u = (mu) - 128; \
-    mm_v = (mv) - 128; \
-    mm_yc= mm_y * 76284; \
-    mm_b = (mm_yc              + 132252*mm_v   ) >> 16; \
-    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v  ) >> 16; \
-    mm_r = (mm_yc + 104595*mm_u                        ) >> 16; \
-    mb = LIMIT_RGB(mm_b); \
-    mg = LIMIT_RGB(mm_g); \
-    mr = LIMIT_RGB(mm_r); \
-}
-
-#define        RING_QUEUE_SIZE         (128*1024)      /* Must be a power of 2 */
-#define        RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
-#define        RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
-#define        RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
-
-struct RingQueue {
-       unsigned char *queue;   /* Data from the Isoc data pump */
-       int length;             /* How many bytes allocated for the queue */
-       int wi;                 /* That's where we write */
-       int ri;                 /* Read from here until you hit write index */
-       wait_queue_head_t wqh;  /* Processes waiting */
-};
-
-enum ScanState {
-       ScanState_Scanning,     /* Scanning for header */
-       ScanState_Lines         /* Parsing lines */
-};
-
-/* Completion states of the data parser */
-enum ParseState {
-       scan_Continue,          /* Just parse next item */
-       scan_NextFrame,         /* Frame done, send it to V4L */
-       scan_Out,               /* Not enough data for frame */
-       scan_EndParse           /* End parsing */
-};
-
-enum FrameState {
-       FrameState_Unused,      /* Unused (no MCAPTURE) */
-       FrameState_Ready,       /* Ready to start grabbing */
-       FrameState_Grabbing,    /* In the process of being grabbed into */
-       FrameState_Done,        /* Finished grabbing, but not been synced yet */
-       FrameState_Done_Hold,   /* Are syncing or reading */
-       FrameState_Error,       /* Something bad happened while processing */
-};
-
-/*
- * Some frames may contain only even or odd lines. This type
- * specifies what type of deinterlacing is required.
- */
-enum Deinterlace {
-       Deinterlace_None=0,
-       Deinterlace_FillOddLines,
-       Deinterlace_FillEvenLines
-};
-
-#define USBVIDEO_NUMFRAMES     2       /* How many frames we work with */
-#define USBVIDEO_NUMSBUF       2       /* How many URBs linked in a ring */
-
-/* This structure represents one Isoc request - URB and buffer */
-struct usbvideo_sbuf {
-       char *data;
-       struct urb *urb;
-};
-
-struct usbvideo_frame {
-       char *data;             /* Frame buffer */
-       unsigned long header;   /* Significant bits from the header */
-
-       videosize_t canvas;     /* The canvas (max. image) allocated */
-       videosize_t request;    /* That's what the application asked for */
-       unsigned short palette; /* The desired format */
-
-       enum FrameState frameState;/* State of grabbing */
-       enum ScanState scanstate;       /* State of scanning */
-       enum Deinterlace deinterlace;
-       int flags;              /* USBVIDEO_FRAME_FLAG_xxx bit flags */
-
-       int curline;            /* Line of frame we're working on */
-
-       long seqRead_Length;    /* Raw data length of frame */
-       long seqRead_Index;     /* Amount of data that has been already read */
-
-       void *user;             /* Additional data that user may need */
-};
-
-/* Statistics that can be overlaid on screen */
-struct usbvideo_statistics {
-        unsigned long frame_num;       /* Sequential number of the frame */
-        unsigned long urb_count;        /* How many URBs we received so far */
-        unsigned long urb_length;       /* Length of last URB */
-        unsigned long data_count;       /* How many bytes we received */
-        unsigned long header_count;     /* How many frame headers we found */
-       unsigned long iso_skip_count;   /* How many empty ISO packets received */
-       unsigned long iso_err_count;    /* How many bad ISO packets received */
-};
-
-struct usbvideo;
-
-struct uvd {
-       struct video_device vdev;       /* Must be the first field! */
-       struct usb_device *dev;
-       struct usbvideo *handle;        /* Points back to the struct usbvideo */
-       void *user_data;                /* Camera-dependent data */
-       int user_size;                  /* Size of that camera-dependent data */
-       int debug;                      /* Debug level for usbvideo */
-       unsigned char iface;            /* Video interface number */
-       unsigned char video_endp;
-       unsigned char ifaceAltActive;
-       unsigned char ifaceAltInactive; /* Alt settings */
-       unsigned long flags;            /* FLAGS_USBVIDEO_xxx */
-       unsigned long paletteBits;      /* Which palettes we accept? */
-       unsigned short defaultPalette;  /* What palette to use for read() */
-       struct mutex lock;
-       int user;               /* user count for exclusive use */
-
-       videosize_t videosize;  /* Current setting */
-       videosize_t canvas;     /* This is the width,height of the V4L canvas */
-       int max_frame_size;     /* Bytes in one video frame */
-
-       int uvd_used;           /* Is this structure in use? */
-       int streaming;          /* Are we streaming Isochronous? */
-       int grabbing;           /* Are we grabbing? */
-       int settingsAdjusted;   /* Have we adjusted contrast etc.? */
-       int last_error;         /* What calamity struck us? */
-
-       char *fbuf;             /* Videodev buffer area */
-       int fbuf_size;          /* Videodev buffer size */
-
-       int curframe;
-       int iso_packet_len;     /* Videomode-dependent, saves bus bandwidth */
-
-       struct RingQueue dp;    /* Isoc data pump */
-       struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
-       struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
-
-       volatile int remove_pending;    /* If set then about to exit */
-
-       struct video_picture vpic, vpic_old;    /* Picture settings */
-       struct video_capability vcap;           /* Video capabilities */
-       struct video_channel vchan;     /* May be used for tuner support */
-       struct usbvideo_statistics stats;
-       char videoName[32];             /* Holds name like "video7" */
-};
-
-/*
- * usbvideo callbacks (virtual methods). They are set when usbvideo
- * services are registered. All of these default to NULL, except those
- * that default to usbvideo-provided methods.
- */
-struct usbvideo_cb {
-       int (*probe)(struct usb_interface *, const struct usb_device_id *);
-       void (*userFree)(struct uvd *);
-       void (*disconnect)(struct usb_interface *);
-       int (*setupOnOpen)(struct uvd *);
-       void (*videoStart)(struct uvd *);
-       void (*videoStop)(struct uvd *);
-       void (*processData)(struct uvd *, struct usbvideo_frame *);
-       void (*postProcess)(struct uvd *, struct usbvideo_frame *);
-       void (*adjustPicture)(struct uvd *);
-       int (*getFPS)(struct uvd *);
-       int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
-       int (*getFrame)(struct uvd *, int);
-       int (*startDataPump)(struct uvd *uvd);
-       void (*stopDataPump)(struct uvd *uvd);
-       int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
-};
-
-struct usbvideo {
-       int num_cameras;                /* As allocated */
-       struct usb_driver usbdrv;       /* Interface to the USB stack */
-       char drvName[80];               /* Driver name */
-       struct mutex lock;              /* Mutex protecting camera structures */
-       struct usbvideo_cb cb;          /* Table of callbacks (virtual methods) */
-       struct video_device vdt;        /* Video device template */
-       struct uvd *cam;                        /* Array of camera structures */
-       struct module *md_module;       /* Minidriver module */
-};
-
-
-/*
- * This macro retrieves callback address from the struct uvd object.
- * No validity checks are done here, so be sure to check the
- * callback beforehand with VALID_CALLBACK.
- */
-#define        GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName)
-
-/*
- * This macro returns either callback pointer or NULL. This is safe
- * macro, meaning that most of components of data structures involved
- * may be NULL - this only results in NULL being returned. You may
- * wish to use this macro to make sure that the callback is callable.
- * However keep in mind that those checks take time.
- */
-#define        VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
-               ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
-
-int  RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
-int  RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
-void RingQueue_Flush(struct RingQueue *rq);
-
-static inline int RingQueue_GetLength(const struct RingQueue *rq)
-{
-       return (rq->wi - rq->ri + rq->length) & (rq->length-1);
-}
-
-static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
-{
-       return rq->length - RingQueue_GetLength(rq);
-}
-
-void usbvideo_DrawLine(
-       struct usbvideo_frame *frame,
-       int x1, int y1,
-       int x2, int y2,
-       unsigned char cr, unsigned char cg, unsigned char cb);
-void usbvideo_HexDump(const unsigned char *data, int len);
-void usbvideo_SayAndWait(const char *what);
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
-
-/* Memory allocation routines */
-unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
-
-int usbvideo_register(
-       struct usbvideo **pCams,
-       const int num_cams,
-       const int num_extra,
-       const char *driverName,
-       const struct usbvideo_cb *cbTable,
-       struct module *md,
-       const struct usb_device_id *id_table);
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
-int usbvideo_RegisterVideoDevice(struct uvd *uvd);
-void usbvideo_Deregister(struct usbvideo **uvt);
-
-int usbvideo_v4l_initialize(struct video_device *dev);
-
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
-
-/*
- * This code performs bounds checking - use it when working with
- * new formats, or else you may get oopses all over the place.
- * If pixel falls out of bounds then it gets shoved back (as close
- * to place of offence as possible) and is painted bright red.
- *
- * There are two important concepts: frame width, height and
- * V4L canvas width, height. The former is the area requested by
- * the application -for this very frame-. The latter is the largest
- * possible frame that we can serve (we advertise that via V4L ioctl).
- * The frame data is expected to be formatted as lines of length
- * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
- */
-static inline void RGB24_PUTPIXEL(
-       struct usbvideo_frame *fr,
-       int ix, int iy,
-       unsigned char vr,
-       unsigned char vg,
-       unsigned char vb)
-{
-       register unsigned char *pf;
-       int limiter = 0, mx, my;
-       mx = ix;
-       my = iy;
-       if (mx < 0) {
-               mx=0;
-               limiter++;
-       } else if (mx >= VIDEOSIZE_X((fr)->request)) {
-               mx= VIDEOSIZE_X((fr)->request) - 1;
-               limiter++;
-       }
-       if (my < 0) {
-               my = 0;
-               limiter++;
-       } else if (my >= VIDEOSIZE_Y((fr)->request)) {
-               my = VIDEOSIZE_Y((fr)->request) - 1;
-               limiter++;
-       }
-       pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix));
-       if (limiter) {
-               *pf++ = 0;
-               *pf++ = 0;
-               *pf++ = 0xFF;
-       } else {
-               *pf++ = (vb);
-               *pf++ = (vg);
-               *pf++ = (vr);
-       }
-}
-
-#endif /* usbvideo_h */
diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
deleted file mode 100644 (file)
index 1d06e53..0000000
+++ /dev/null
@@ -1,1411 +0,0 @@
-/*
- * USB ViCam WebCam driver
- * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
- *                    Christopher L Cheney (ccheney@cheney.cx),
- *                    Pavel Machek (pavel@suse.cz),
- *                    John Tyner (jtyner@cs.ucr.edu),
- *                    Monroe Williams (monroe@pobox.com)
- *
- * Supports 3COM HomeConnect PC Digital WebCam
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This source code is based heavily on the CPiA webcam driver which was
- * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
- *
- * Portions of this code were also copied from usbvideo.c
- *
- * Special thanks to the the whole team at Sourceforge for help making
- * this driver become a reality.  Notably:
- * Andy Armstrong who reverse engineered the color encoding and
- * Pavel Machek and Chris Cheney who worked on reverse engineering the
- *    camera controls and wrote the first generation driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-#include "usbvideo.h"
-
-// #define VICAM_DEBUG
-
-#ifdef VICAM_DEBUG
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
-#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
-#else
-#define DBG(fmn,args...) do {} while(0)
-#endif
-
-#define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
-#define DRIVER_DESC             "ViCam WebCam Driver"
-
-/* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID    0x04c1
-#define USB_VICAM_PRODUCT_ID   0x009d
-
-#define VICAM_BYTES_PER_PIXEL   3
-#define VICAM_MAX_READ_SIZE     (512*242+128)
-#define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
-#define VICAM_FRAMES            2
-
-#define VICAM_HEADER_SIZE       64
-
-#define clamp( x, l, h )        max_t( __typeof__( x ),         \
-                                       ( l ),                   \
-                                       min_t( __typeof__( x ),  \
-                                              ( h ),            \
-                                              ( x ) ) )
-
-/* Not sure what all the bytes in these char
- * arrays do, but they're necessary to make
- * the camera work.
- */
-
-static unsigned char setup1[] = {
-       0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
-       0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
-       0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
-       0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
-       0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
-};
-
-static unsigned char setup2[] = {
-       0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
-       0x00, 0x00
-};
-
-static unsigned char setup3[] = {
-       0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
-};
-
-static unsigned char setup4[] = {
-       0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
-       0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
-       0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
-       0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
-       0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
-       0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
-       0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
-       0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
-       0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
-       0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
-       0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
-       0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
-       0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
-       0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
-       0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
-       0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
-       0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
-       0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
-       0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
-       0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
-       0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
-       0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
-       0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
-       0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
-       0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
-       0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
-       0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
-       0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
-       0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
-       0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
-       0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
-       0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
-       0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
-       0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
-       0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
-       0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
-       0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
-       0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
-       0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
-       0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
-       0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
-       0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
-       0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
-       0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
-       0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
-       0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
-       0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
-       0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
-       0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
-       0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
-       0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
-       0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
-       0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
-       0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
-       0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
-       0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
-       0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
-       0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-       0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
-       0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
-       0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
-       0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
-       0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
-       0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
-       0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
-       0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
-       0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
-       0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
-       0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
-       0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
-       0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
-       0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
-       0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
-       0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
-       0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
-       0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
-       0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
-       0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
-       0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
-       0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
-       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
-       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
-       0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
-       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
-       0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
-       0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
-       0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
-       0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
-       0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
-       0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
-       0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
-       0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
-       0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
-       0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-       0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
-       0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-       0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
-       0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
-       0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
-       0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
-       0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
-       0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
-       0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
-       0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
-       0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
-       0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
-       0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
-       0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
-       0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
-       0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
-       0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
-       0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
-       0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
-       0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
-       0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
-       0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
-       0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
-       0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
-       0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
-       0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
-       0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
-       0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
-       0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
-       0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
-       0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
-       0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-       0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
-       0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
-       0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
-       0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
-       0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
-       0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
-       0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
-       0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
-       0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
-       0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-       0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
-       0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
-       0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
-       0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
-       0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
-       0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
-       0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
-       0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
-       0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-       0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
-       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
-       0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
-       0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
-       0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-       0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
-       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
-       0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-       0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
-       0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
-       0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-       0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
-       0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
-       0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
-       0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
-       0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
-       0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
-       0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
-       0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
-       0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
-       0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
-       0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
-       0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-       0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-       0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
-       0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-       0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
-       0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
-       0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
-       0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
-       0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
-       0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
-       0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
-       0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-       0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
-       0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
-       0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
-       0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
-       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
-       0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
-       0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
-       0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
-       0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-       0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static unsigned char setup5[] = {
-       0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
-       0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
-       0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
-       0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
-       0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
-       0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
-       0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
-       0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
-       0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
-       0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
-       0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
-       0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
-       0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
-       0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
-       0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
-       0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
-       0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
-       0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
-       0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
-       0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
-       0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
-       0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
-       0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
-       0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
-       0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
-       0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
-       0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
-       0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
-       0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
-       0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
-       0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
-       0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
-       0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
-       0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
-       0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
-       0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
-       0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
-       0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
-       0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
-};
-
-/* rvmalloc / rvfree copied from usbvideo.c
- *
- * Not sure why these are not yet non-statics which I can reference through
- * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
- * in the future.
- * 
-*/
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-struct vicam_camera {
-       u16 shutter_speed;      // capture shutter speed
-       u16 gain;               // capture gain
-
-       u8 *raw_image;          // raw data captured from the camera
-       u8 *framebuf;           // processed data in RGB24 format
-       u8 *cntrlbuf;           // area used to send control msgs
-
-       struct video_device vdev;       // v4l video device
-       struct usb_device *udev;        // usb device
-
-       /* guard against simultaneous accesses to the camera */
-       struct mutex cam_lock;
-
-       int is_initialized;
-       u8 open_count;
-       u8 bulkEndpoint;
-       int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-       struct proc_dir_entry *proc_dir;
-#endif
-
-};
-
-static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
-static void vicam_disconnect(struct usb_interface *intf);
-static void read_frame(struct vicam_camera *cam, int framenum);
-static void vicam_decode_color(const u8 *, u8 *);
-
-static int __send_control_msg(struct vicam_camera *cam,
-                             u8 request,
-                             u16 value,
-                             u16 index,
-                             unsigned char *cp,
-                             u16 size)
-{
-       int status;
-
-       /* cp must be memory that has been allocated by kmalloc */
-
-       status = usb_control_msg(cam->udev,
-                                usb_sndctrlpipe(cam->udev, 0),
-                                request,
-                                USB_DIR_OUT | USB_TYPE_VENDOR |
-                                USB_RECIP_DEVICE, value, index,
-                                cp, size, 1000);
-
-       status = min(status, 0);
-
-       if (status < 0) {
-               printk(KERN_INFO "Failed sending control message, error %d.\n",
-                      status);
-       }
-
-       return status;
-}
-
-static int send_control_msg(struct vicam_camera *cam,
-                           u8 request,
-                           u16 value,
-                           u16 index,
-                           unsigned char *cp,
-                           u16 size)
-{
-       int status = -ENODEV;
-       mutex_lock(&cam->cam_lock);
-       if (cam->udev) {
-               status = __send_control_msg(cam, request, value,
-                                           index, cp, size);
-       }
-       mutex_unlock(&cam->cam_lock);
-       return status;
-}
-static int
-initialize_camera(struct vicam_camera *cam)
-{
-       const struct {
-               u8 *data;
-               u32 size;
-       } firmware[] = {
-               { .data = setup1, .size = sizeof(setup1) },
-               { .data = setup2, .size = sizeof(setup2) },
-               { .data = setup3, .size = sizeof(setup3) },
-               { .data = setup4, .size = sizeof(setup4) },
-               { .data = setup5, .size = sizeof(setup5) },
-               { .data = setup3, .size = sizeof(setup3) },
-               { .data = NULL, .size = 0 }
-       };
-
-       int err, i;
-
-       for (i = 0, err = 0; firmware[i].data && !err; i++) {
-               memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size);
-
-               err = send_control_msg(cam, 0xff, 0, 0,
-                                      cam->cntrlbuf, firmware[i].size);
-       }
-
-       return err;
-}
-
-static int
-set_camera_power(struct vicam_camera *cam, int state)
-{
-       int status;
-
-       if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
-               return status;
-
-       if (state) {
-               send_control_msg(cam, 0x55, 1, 0, NULL, 0);
-       }
-
-       return 0;
-}
-
-static int
-vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg)
-{
-       void __user *user_arg = (void __user *)arg;
-       struct vicam_camera *cam = file->private_data;
-       int retval = 0;
-
-       if (!cam)
-               return -ENODEV;
-
-       switch (ioctlnr) {
-               /* query capabilities */
-       case VIDIOCGCAP:
-               {
-                       struct video_capability b;
-
-                       DBG("VIDIOCGCAP\n");
-                       memset(&b, 0, sizeof(b));
-                       strcpy(b.name, "ViCam-based Camera");
-                       b.type = VID_TYPE_CAPTURE;
-                       b.channels = 1;
-                       b.audios = 0;
-                       b.maxwidth = 320;       /* VIDEOSIZE_CIF */
-                       b.maxheight = 240;
-                       b.minwidth = 320;       /* VIDEOSIZE_48_48 */
-                       b.minheight = 240;
-
-                       if (copy_to_user(user_arg, &b, sizeof(b)))
-                               retval = -EFAULT;
-
-                       break;
-               }
-               /* get/set video source - we are a camera and nothing else */
-       case VIDIOCGCHAN:
-               {
-                       struct video_channel v;
-
-                       DBG("VIDIOCGCHAN\n");
-                       if (copy_from_user(&v, user_arg, sizeof(v))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       if (v.channel != 0) {
-                               retval = -EINVAL;
-                               break;
-                       }
-
-                       v.channel = 0;
-                       strcpy(v.name, "Camera");
-                       v.tuners = 0;
-                       v.flags = 0;
-                       v.type = VIDEO_TYPE_CAMERA;
-                       v.norm = 0;
-
-                       if (copy_to_user(user_arg, &v, sizeof(v)))
-                               retval = -EFAULT;
-                       break;
-               }
-
-       case VIDIOCSCHAN:
-               {
-                       int v;
-
-                       if (copy_from_user(&v, user_arg, sizeof(v)))
-                               retval = -EFAULT;
-                       DBG("VIDIOCSCHAN %d\n", v);
-
-                       if (retval == 0 && v != 0)
-                               retval = -EINVAL;
-
-                       break;
-               }
-
-               /* image properties */
-       case VIDIOCGPICT:
-               {
-                       struct video_picture vp;
-                       DBG("VIDIOCGPICT\n");
-                       memset(&vp, 0, sizeof (struct video_picture));
-                       vp.brightness = cam->gain << 8;
-                       vp.depth = 24;
-                       vp.palette = VIDEO_PALETTE_RGB24;
-                       if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
-                               retval = -EFAULT;
-                       break;
-               }
-
-       case VIDIOCSPICT:
-               {
-                       struct video_picture vp;
-                       
-                       if (copy_from_user(&vp, user_arg, sizeof(vp))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       
-                       DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
-                           vp.palette);
-
-                       cam->gain = vp.brightness >> 8;
-
-                       if (vp.depth != 24
-                           || vp.palette != VIDEO_PALETTE_RGB24)
-                               retval = -EINVAL;
-
-                       break;
-               }
-
-               /* get/set capture window */
-       case VIDIOCGWIN:
-               {
-                       struct video_window vw;
-                       vw.x = 0;
-                       vw.y = 0;
-                       vw.width = 320;
-                       vw.height = 240;
-                       vw.chromakey = 0;
-                       vw.flags = 0;
-                       vw.clips = NULL;
-                       vw.clipcount = 0;
-
-                       DBG("VIDIOCGWIN\n");
-
-                       if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
-                               retval = -EFAULT;
-
-                       // I'm not sure what the deal with a capture window is, it is very poorly described
-                       // in the doc.  So I won't support it now.
-                       break;
-               }
-
-       case VIDIOCSWIN:
-               {
-
-                       struct video_window vw;
-
-                       if (copy_from_user(&vw, user_arg, sizeof(vw))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
-                       
-                       if ( vw.width != 320 || vw.height != 240 )
-                               retval = -EFAULT;
-
-                       break;
-               }
-
-               /* mmap interface */
-       case VIDIOCGMBUF:
-               {
-                       struct video_mbuf vm;
-                       int i;
-
-                       DBG("VIDIOCGMBUF\n");
-                       memset(&vm, 0, sizeof (vm));
-                       vm.size =
-                           VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
-                       vm.frames = VICAM_FRAMES;
-                       for (i = 0; i < VICAM_FRAMES; i++)
-                               vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
-
-                       if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
-                               retval = -EFAULT;
-
-                       break;
-               }
-
-       case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap vm;
-                       // int video_size;
-
-                       if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-
-                       DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
-
-                       if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
-                               retval = -EINVAL;
-
-                       // in theory right here we'd start the image capturing
-                       // (fill in a bulk urb and submit it asynchronously)
-                       //
-                       // Instead we're going to do a total hack job for now and
-                       // retrieve the frame in VIDIOCSYNC
-
-                       break;
-               }
-
-       case VIDIOCSYNC:
-               {
-                       int frame;
-
-                       if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
-                               retval = -EFAULT;
-                               break;
-                       }
-                       DBG("VIDIOCSYNC: %d\n", frame);
-
-                       read_frame(cam, frame);
-                       vicam_decode_color(cam->raw_image,
-                                          cam->framebuf +
-                                          frame * VICAM_MAX_FRAME_SIZE );
-
-                       break;
-               }
-
-               /* pointless to implement overlay with this camera */
-       case VIDIOCCAPTURE:
-       case VIDIOCGFBUF:
-       case VIDIOCSFBUF:
-       case VIDIOCKEY:
-               retval = -EINVAL;
-               break;
-
-               /* tuner interface - we have none */
-       case VIDIOCGTUNER:
-       case VIDIOCSTUNER:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-               retval = -EINVAL;
-               break;
-
-               /* audio interface - we have none */
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-               retval = -EINVAL;
-               break;
-       default:
-               retval = -ENOIOCTLCMD;
-               break;
-       }
-
-       return retval;
-}
-
-static int
-vicam_open(struct inode *inode, struct file *file)
-{
-       struct video_device *dev = video_devdata(file);
-       struct vicam_camera *cam =
-           (struct vicam_camera *) dev->priv;
-       DBG("open\n");
-
-       if (!cam) {
-               printk(KERN_ERR
-                      "vicam video_device improperly initialized");
-               return -EINVAL;
-       }
-
-       /* the videodev_lock held above us protects us from
-        * simultaneous opens...for now. we probably shouldn't
-        * rely on this fact forever.
-        */
-
-       if (cam->open_count > 0) {
-               printk(KERN_INFO
-                      "vicam_open called on already opened camera");
-               return -EBUSY;
-       }
-
-       cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
-       if (!cam->raw_image) {
-               return -ENOMEM;
-       }
-
-       cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-       if (!cam->framebuf) {
-               kfree(cam->raw_image);
-               return -ENOMEM;
-       }
-
-       cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!cam->cntrlbuf) {
-               kfree(cam->raw_image);
-               rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-               return -ENOMEM;
-       }
-
-       // First upload firmware, then turn the camera on
-
-       if (!cam->is_initialized) {
-               initialize_camera(cam);
-
-               cam->is_initialized = 1;
-       }
-
-       set_camera_power(cam, 1);
-
-       cam->needsDummyRead = 1;
-       cam->open_count++;
-
-       file->private_data = cam;       
-       
-       return 0;
-}
-
-static int 
-vicam_close(struct inode *inode, struct file *file)
-{
-       struct vicam_camera *cam = file->private_data;
-       int open_count;
-       struct usb_device *udev;
-
-       DBG("close\n");
-
-       /* it's not the end of the world if
-        * we fail to turn the camera off.
-        */
-
-       set_camera_power(cam, 0);
-
-       kfree(cam->raw_image);
-       rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-       kfree(cam->cntrlbuf);
-
-       mutex_lock(&cam->cam_lock);
-
-       cam->open_count--;
-       open_count = cam->open_count;
-       udev = cam->udev;
-
-       mutex_unlock(&cam->cam_lock);
-
-       if (!open_count && !udev) {
-               kfree(cam);
-       }
-
-       return 0;
-}
-
-static void vicam_decode_color(const u8 *data, u8 *rgb)
-{
-       /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
-        * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
-        */
-
-       int i, prevY, nextY;
-
-       prevY = 512;
-       nextY = 512;
-
-       data += VICAM_HEADER_SIZE;
-
-       for( i = 0; i < 240; i++, data += 512 ) {
-               const int y = ( i * 242 ) / 240;
-
-               int j, prevX, nextX;
-               int Y, Cr, Cb;
-
-               if ( y == 242 - 1 ) {
-                       nextY = -512;
-               }
-
-               prevX = 1;
-               nextX = 1;
-
-               for ( j = 0; j < 320; j++, rgb += 3 ) {
-                       const int x = ( j * 512 ) / 320;
-                       const u8 * const src = &data[x];
-
-                       if ( x == 512 - 1 ) {
-                               nextX = -1;
-                       }
-
-                       Cr = ( src[prevX] - src[0] ) +
-                               ( src[nextX] - src[0] );
-                       Cr /= 2;
-
-                       Cb = ( src[prevY] - src[prevX + prevY] ) +
-                               ( src[prevY] - src[nextX + prevY] ) +
-                               ( src[nextY] - src[prevX + nextY] ) +
-                               ( src[nextY] - src[nextX + nextY] );
-                       Cb /= 4;
-
-                       Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
-
-                       if ( i & 1 ) {
-                               int Ct = Cr;
-                               Cr = Cb;
-                               Cb = Ct;
-                       }
-
-                       if ( ( x ^ i ) & 1 ) {
-                               Cr = -Cr;
-                               Cb = -Cb;
-                       }
-
-                       rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
-                                       500 ) / 900, 0, 255 );
-                       rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
-                                         ( 813 * Cr ) ) +
-                                         500 ) / 1000, 0, 255 );
-                       rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
-                                       500 ) / 1300, 0, 255 );
-
-                       prevX = -1;
-               }
-
-               prevY = -512;
-       }
-}
-
-static void
-read_frame(struct vicam_camera *cam, int framenum)
-{
-       unsigned char *request = cam->cntrlbuf;
-       int realShutter;
-       int n;
-       int actual_length;
-
-       if (cam->needsDummyRead) {
-               cam->needsDummyRead = 0;
-               read_frame(cam, framenum);
-       }
-
-       memset(request, 0, 16);
-       request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
-
-       request[1] = 0; // 512x242 capture
-
-       request[2] = 0x90;      // the function of these two bytes
-       request[3] = 0x07;      // is not yet understood
-
-       if (cam->shutter_speed > 60) {
-               // Short exposure
-               realShutter =
-                   ((-15631900 / cam->shutter_speed) + 260533) / 1000;
-               request[4] = realShutter & 0xFF;
-               request[5] = (realShutter >> 8) & 0xFF;
-               request[6] = 0x03;
-               request[7] = 0x01;
-       } else {
-               // Long exposure
-               realShutter = 15600 / cam->shutter_speed - 1;
-               request[4] = 0;
-               request[5] = 0;
-               request[6] = realShutter & 0xFF;
-               request[7] = realShutter >> 8;
-       }
-
-       // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
-       request[8] = 0;
-       // bytes 9-15 do not seem to affect exposure or image quality
-
-       mutex_lock(&cam->cam_lock);
-
-       if (!cam->udev) {
-               goto done;
-       }
-
-       n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
-
-       if (n < 0) {
-               printk(KERN_ERR
-                      " Problem sending frame capture control message");
-               goto done;
-       }
-
-       n = usb_bulk_msg(cam->udev,
-                        usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
-                        cam->raw_image,
-                        512 * 242 + 128, &actual_length, 10000);
-
-       if (n < 0) {
-               printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
-                      n);
-       }
-
- done:
-       mutex_unlock(&cam->cam_lock);
-}
-
-static ssize_t
-vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
-{
-       struct vicam_camera *cam = file->private_data;
-
-       DBG("read %d bytes.\n", (int) count);
-
-       if (*ppos >= VICAM_MAX_FRAME_SIZE) {
-               *ppos = 0;
-               return 0;
-       }
-
-       if (*ppos == 0) {
-               read_frame(cam, 0);
-               vicam_decode_color(cam->raw_image,
-                                  cam->framebuf +
-                                  0 * VICAM_MAX_FRAME_SIZE);
-       }
-
-       count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
-
-       if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
-               count = -EFAULT;
-       } else {
-               *ppos += count;
-       }
-
-       if (count == VICAM_MAX_FRAME_SIZE) {
-               *ppos = 0;
-       }
-
-       return count;
-}
-
-
-static int
-vicam_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       // TODO: allocate the raw frame buffer if necessary
-       unsigned long page, pos;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       struct vicam_camera *cam = file->private_data;
-
-       if (!cam)
-               return -ENODEV;
-
-       DBG("vicam_mmap: %ld\n", size);
-
-       /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
-        * to the size the application requested for mmap and it was screwing apps up.
-        if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
-        return -EINVAL;
-        */
-
-       pos = (unsigned long)cam->framebuf;
-       while (size > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
-                       return -EAGAIN;
-
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return 0;
-}
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
-                               int count, int *eof, int value)
-{
-       char *out = page;
-       int len;
-
-       out += sprintf(out, "%d",value);
-
-       len = out - page;
-       len -= off;
-       if (len < count) {
-               *eof = 1;
-               if (len <= 0)
-                       return 0;
-       } else
-               len = count;
-
-       *start = page + off;
-       return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
-                               int count, int *eof, void *data)
-{
-       return vicam_read_helper(page,start,off,count,eof,
-                               ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
-                        unsigned long count, void *data)
-{
-       u16 stmp;
-       char kbuf[8];
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 6)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       stmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (stmp < 4 || stmp > 32000)
-               return -EINVAL;
-
-       cam->shutter_speed = stmp;
-
-       return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
-                     unsigned long count, void *data)
-{
-       u16 gtmp;
-       char kbuf[8];
-
-       struct vicam_camera *cam = (struct vicam_camera *) data;
-
-       if (count > 4)
-               return -EINVAL;
-
-       if (copy_from_user(kbuf, buffer, count))
-               return -EFAULT;
-
-       gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
-       if (gtmp > 255)
-               return -EINVAL;
-       cam->gain = gtmp;
-
-       return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
-       vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
-       if (vicam_proc_root)
-               vicam_proc_root->owner = THIS_MODULE;
-       else
-               printk(KERN_ERR
-                      "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
-       if (vicam_proc_root)
-               remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
-       char name[64];
-       struct proc_dir_entry *ent;
-
-       DBG(KERN_INFO "vicam: creating proc entry\n");
-
-       if (!vicam_proc_root || !cam) {
-               printk(KERN_INFO
-                      "vicam: could not create proc entry, %s pointer is null.\n",
-                      (!cam ? "camera" : "root"));
-               return;
-       }
-
-       sprintf(name, "video%d", cam->vdev.minor);
-
-       cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
-       if ( !cam->proc_dir )
-               return; // FIXME: We should probably return an error here
-       
-       ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_shutter;
-               ent->write_proc = vicam_write_proc_shutter;
-               ent->size = 64;
-       }
-
-       ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
-                               cam->proc_dir);
-       if (ent) {
-               ent->data = cam;
-               ent->read_proc = vicam_read_proc_gain;
-               ent->write_proc = vicam_write_proc_gain;
-               ent->size = 64;
-       }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
-       struct vicam_camera *cam = (struct vicam_camera *) ptr;
-       char name[16];
-
-       if ( !cam->proc_dir )
-               return;
-
-       sprintf(name, "video%d", cam->vdev.minor);
-       remove_proc_entry("shutter", cam->proc_dir);
-       remove_proc_entry("gain", cam->proc_dir);
-       remove_proc_entry(name,vicam_proc_root);
-       cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
-static struct file_operations vicam_fops = {
-       .owner          = THIS_MODULE,
-       .open           = vicam_open,
-       .release        = vicam_close,
-       .read           = vicam_read,
-       .mmap           = vicam_mmap,
-       .ioctl          = vicam_ioctl,
-       .compat_ioctl   = v4l_compat_ioctl32,
-       .llseek         = no_llseek,
-};
-
-static struct video_device vicam_template = {
-       .owner          = THIS_MODULE,
-       .name           = "ViCam-based USB Camera",
-       .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_VICAM,
-       .fops           = &vicam_fops,
-       .minor          = -1,
-};
-
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table[] = {
-       {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
-       {}                      /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, vicam_table);
-
-static struct usb_driver vicam_driver = {
-       .name           = "vicam",
-       .probe          = vicam_probe,
-       .disconnect     = vicam_disconnect,
-       .id_table       = vicam_table
-};
-
-/**
- *     vicam_probe
- *     @intf: the interface
- *     @id: the device id
- *
- *     Called by the usb core when a new device is connected that it thinks
- *     this driver might be interested in.
- */
-static int
-vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       int bulkEndpoint = 0;
-       const struct usb_host_interface *interface;
-       const struct usb_endpoint_descriptor *endpoint;
-       struct vicam_camera *cam;
-       
-       printk(KERN_INFO "ViCam based webcam connected\n");
-
-       interface = intf->cur_altsetting;
-
-       DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
-              interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
-       endpoint = &interface->endpoint[0].desc;
-
-       if ((endpoint->bEndpointAddress & 0x80) &&
-           ((endpoint->bmAttributes & 3) == 0x02)) {
-               /* we found a bulk in endpoint */
-               bulkEndpoint = endpoint->bEndpointAddress;
-       } else {
-               printk(KERN_ERR
-                      "No bulk in endpoint was found ?! (this is bad)\n");
-       }
-
-       if ((cam =
-            kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
-               printk(KERN_WARNING
-                      "could not allocate kernel memory for vicam_camera struct\n");
-               return -ENOMEM;
-       }
-
-       memset(cam, 0, sizeof (struct vicam_camera));
-
-       cam->shutter_speed = 15;
-
-       mutex_init(&cam->cam_lock);
-
-       memcpy(&cam->vdev, &vicam_template,
-              sizeof (vicam_template));
-       cam->vdev.priv = cam;   // sort of a reverse mapping for those functions that get vdev only
-
-       cam->udev = dev;
-       cam->bulkEndpoint = bulkEndpoint;
-
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
-               kfree(cam);
-               printk(KERN_WARNING "video_register_device failed\n");
-               return -EIO;
-       }
-
-       vicam_create_proc_entry(cam);
-
-       printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
-
-       usb_set_intfdata (intf, cam);
-       
-       return 0;
-}
-
-static void
-vicam_disconnect(struct usb_interface *intf)
-{
-       int open_count;
-       struct vicam_camera *cam = usb_get_intfdata (intf);
-       usb_set_intfdata (intf, NULL);
-
-       /* we must unregister the device before taking its
-        * cam_lock. This is because the video open call
-        * holds the same lock as video unregister. if we
-        * unregister inside of the cam_lock and open also
-        * uses the cam_lock, we get deadlock.
-        */
-
-       video_unregister_device(&cam->vdev);
-
-       /* stop the camera from being used */
-
-       mutex_lock(&cam->cam_lock);
-
-       /* mark the camera as gone */
-
-       cam->udev = NULL;
-
-       vicam_destroy_proc_entry(cam);
-
-       /* the only thing left to do is synchronize with
-        * our close/release function on who should release
-        * the camera memory. if there are any users using the
-        * camera, it's their job. if there are no users,
-        * it's ours.
-        */
-
-       open_count = cam->open_count;
-
-       mutex_unlock(&cam->cam_lock);
-
-       if (!open_count) {
-               kfree(cam);
-       }
-
-       printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
-}
-
-/*
- */
-static int __init
-usb_vicam_init(void)
-{
-       int retval;
-       DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
-       vicam_create_proc_root();
-       retval = usb_register(&vicam_driver);
-       if (retval)
-               printk(KERN_WARNING "usb_register failed!\n");
-       return retval;
-}
-
-static void __exit
-usb_vicam_exit(void)
-{
-       DBG(KERN_INFO
-              "ViCam-based WebCam driver shutdown\n");
-
-       usb_deregister(&vicam_driver);
-       vicam_destroy_proc_root();
-}
-
-module_init(usb_vicam_init);
-module_exit(usb_vicam_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c
deleted file mode 100644 (file)
index b57dec3..0000000
+++ /dev/null
@@ -1,3691 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * - Memory management code from bttv driver by Ralph Metzler,             *
- *   Marcus Metzler and Gerd Knorr.                                        *
- * - I2C interface to kernel, high-level image sensor control routines and *
- *   some symbolic names from OV511 driver by Mark W. McClelland.          *
- * - Low-level I2C fast write function by Piotr Czerczak.                  *
- * - Low-level I2C read function by Frederic Jouault.                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <linux/page-flags.h>
-#include <linux/moduleparam.h>
-
-#include "w9968cf.h"
-#include "w9968cf_decoder.h"
-
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
-
-/****************************************************************************
- * Module macros and parameters                                             *
- ****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, winbond_id_table);
-
-MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
-MODULE_VERSION(W9968CF_MODULE_VERSION);
-MODULE_LICENSE(W9968CF_MODULE_LICENSE);
-MODULE_SUPPORTED_DEVICE("Video");
-
-static int ovmod_load = W9968CF_OVMOD_LOAD;
-static unsigned short simcams = W9968CF_SIMCAMS;
-static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
-static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                     W9968CF_PACKET_SIZE};
-static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                       W9968CF_BUFFERS};
-static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                              W9968CF_DOUBLE_BUFFER};
-static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
-static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                      W9968CF_FILTER_TYPE};
-static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
-static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                         W9968CF_DECOMPRESSION};
-static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
-static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
-static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
-static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
-static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
-static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                     W9968CF_LIGHTFREQ};
-static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
-                              W9968CF_BANDINGFILTER};
-static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
-static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
-static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
-static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                    W9968CF_BRIGHTNESS};
-static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
-static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
-static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                  W9968CF_CONTRAST};
-static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] = 
-                                   W9968CF_WHITENESS};
-#ifdef W9968CF_DEBUG
-static unsigned short debug = W9968CF_DEBUG_LEVEL;
-static int specific_debug = W9968CF_SPECIFIC_DEBUG;
-#endif
-
-static unsigned int param_nv[24]; /* number of values per parameter */
-
-#ifdef CONFIG_KMOD
-module_param(ovmod_load, bool, 0644);
-#endif
-module_param(simcams, ushort, 0644);
-module_param_array(video_nr, short, &param_nv[0], 0444);
-module_param_array(packet_size, uint, &param_nv[1], 0444);
-module_param_array(max_buffers, ushort, &param_nv[2], 0444);
-module_param_array(double_buffer, bool, &param_nv[3], 0444);
-module_param_array(clamping, bool, &param_nv[4], 0444);
-module_param_array(filter_type, ushort, &param_nv[5], 0444);
-module_param_array(largeview, bool, &param_nv[6], 0444);
-module_param_array(decompression, ushort, &param_nv[7], 0444);
-module_param_array(upscaling, bool, &param_nv[8], 0444);
-module_param_array(force_palette, ushort, &param_nv[9], 0444);
-module_param_array(force_rgb, ushort, &param_nv[10], 0444);
-module_param_array(autobright, bool, &param_nv[11], 0444);
-module_param_array(autoexp, bool, &param_nv[12], 0444);
-module_param_array(lightfreq, ushort, &param_nv[13], 0444);
-module_param_array(bandingfilter, bool, &param_nv[14], 0444);
-module_param_array(clockdiv, short, &param_nv[15], 0444);
-module_param_array(backlight, bool, &param_nv[16], 0444);
-module_param_array(mirror, bool, &param_nv[17], 0444);
-module_param_array(monochrome, bool, &param_nv[18], 0444);
-module_param_array(brightness, uint, &param_nv[19], 0444);
-module_param_array(hue, uint, &param_nv[20], 0444);
-module_param_array(colour, uint, &param_nv[21], 0444);
-module_param_array(contrast, uint, &param_nv[22], 0444);
-module_param_array(whiteness, uint, &param_nv[23], 0444);
-#ifdef W9968CF_DEBUG
-module_param(debug, ushort, 0644);
-module_param(specific_debug, bool, 0644);
-#endif
-
-#ifdef CONFIG_KMOD
-MODULE_PARM_DESC(ovmod_load, 
-                 "\n<0|1> Automatic 'ovcamchip' module loading."
-                 "\n0 disabled, 1 enabled."
-                 "\nIf enabled,'insmod' searches for the required 'ovcamchip'"
-                 "\nmodule in the system, according to its configuration, and"
-                 "\nattempts to load that module automatically. This action is"
-                 "\nperformed once as soon as the 'w9968cf' module is loaded"
-                 "\ninto memory."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_OVMOD_LOAD)"."
-                 "\n");
-#endif
-MODULE_PARM_DESC(simcams, 
-                 "\n<n> Number of cameras allowed to stream simultaneously."
-                 "\nn may vary from 0 to "
-                 __MODULE_STRING(W9968CF_MAX_DEVICES)"."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
-                 "\n");
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
-                 " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-MODULE_PARM_DESC(packet_size,
-                 "\n<n[,...]> Specify the maximum data payload"
-                 "\nsize in bytes for alternate settings, for each device."
-                 "\nn is scaled between 63 and 1023 "
-                 "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
-                 "\n");
-MODULE_PARM_DESC(max_buffers,
-                 "\n<n[,...]> For advanced users."
-                 "\nSpecify the maximum number of video frame buffers"
-                 "\nto allocate for each device, from 2 to "
-                 __MODULE_STRING(W9968CF_MAX_BUFFERS)
-                 ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
-                 "\n");
-MODULE_PARM_DESC(double_buffer, 
-                 "\n<0|1[,...]> "
-                 "Hardware double buffering: 0 disabled, 1 enabled."
-                 "\nIt should be enabled if you want smooth video output: if"
-                 "\nyou obtain out of sync. video, disable it, or try to"
-                 "\ndecrease the 'clockdiv' module parameter value."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(clamping, 
-                 "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(filter_type, 
-                 "\n<0|1|2[,...]> Video filter type."
-                 "\n0 none, 1 (1-2-1) 3-tap filter, "
-                 "2 (2-3-6-3-2) 5-tap filter."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
-                 " for every device."
-                 "\nThe filter is used to reduce noise and aliasing artifacts"
-                 "\nproduced by the CCD or CMOS image sensor, and the scaling"
-                 " process."
-                 "\n");
-MODULE_PARM_DESC(largeview, 
-                 "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(upscaling, 
-                 "\n<0|1[,...]> Software scaling (for non-compressed video):"
-                 "\n0 disabled, 1 enabled."
-                 "\nDisable it if you have a slow CPU or you don't have"
-                 " enough memory."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
-                 " for every device."
-                 "\nIf 'w9968cf-vpp' is not present, this parameter is"
-                 " set to 0."
-                 "\n");
-MODULE_PARM_DESC(decompression,
-                 "\n<0|1|2[,...]> Software video decompression:"
-                 "\n- 0 disables decompression (doesn't allow formats needing"
-                 " decompression)"
-                 "\n- 1 forces decompression (allows formats needing"
-                 " decompression only);"
-                 "\n- 2 allows any permitted formats."
-                 "\nFormats supporting compressed video are YUV422P and"
-                 " YUV420P/YUV420 "
-                 "\nin any resolutions where both width and height are "
-                 "a multiple of 16."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
-                 " for every device."
-                 "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
-                 "\nnot allowed; in this case this parameter is set to 2."
-                 "\n");
-MODULE_PARM_DESC(force_palette,
-                 "\n<0"
-                 "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
-                 "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
-                 "[,...]>"
-                 " Force picture palette."
-                 "\nIn order:"
-                 "\n- 0 allows any of the following formats:"
-                 "\n- UYVY    16 bpp - Original video, compression disabled"
-                 "\n- YUV420  12 bpp - Original video, compression enabled"
-                 "\n- YUV422P 16 bpp - Original video, compression enabled"
-                 "\n- YUV420P 12 bpp - Original video, compression enabled"
-                 "\n- YUVY    16 bpp - Software conversion from UYVY"
-                 "\n- YUV422  16 bpp - Software conversion from UYVY"
-                 "\n- GREY     8 bpp - Software conversion from UYVY"
-                 "\n- RGB555  16 bpp - Software conversion from UYVY"
-                 "\n- RGB565  16 bpp - Software conversion from UYVY"
-                 "\n- RGB24   24 bpp - Software conversion from UYVY"
-                 "\n- RGB32   32 bpp - Software conversion from UYVY"
-                 "\nWhen not 0, this parameter will override 'decompression'."
-                 "\nDefault value is 0 for every device."
-                 "\nInitial palette is "
-                 __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
-                 "\nIf 'w9968cf-vpp' is not present, this parameter is"
-                 " set to 9 (UYVY)."
-                 "\n");
-MODULE_PARM_DESC(force_rgb, 
-                 "\n<0|1[,...]> Read RGB video data instead of BGR:"
-                 "\n 1 = use RGB component ordering."
-                 "\n 0 = use BGR component ordering."
-                 "\nThis parameter has effect when using RGBX palettes only."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(autobright,
-                 "\n<0|1[,...]> Image sensor automatically changes brightness:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(autoexp,
-                 "\n<0|1[,...]> Image sensor automatically changes exposure:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(lightfreq,
-                 "\n<50|60[,...]> Light frequency in Hz:"
-                 "\n 50 for European and Asian lighting,"
-                 " 60 for American lighting."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(bandingfilter,
-                 "\n<0|1[,...]> Banding filter to reduce effects of"
-                 " fluorescent lighting:"
-                 "\n 0 disabled, 1 enabled."
-                 "\nThis filter tries to reduce the pattern of horizontal"
-                 "\nlight/dark bands caused by some (usually fluorescent)"
-                 " lighting."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(clockdiv,
-                 "\n<-1|n[,...]> "
-                 "Force pixel clock divisor to a specific value (for experts):"
-                 "\n  n may vary from 0 to 127."
-                 "\n -1 for automatic value."
-                 "\nSee also the 'double_buffer' module parameter."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(backlight,
-                 "\n<0|1[,...]> Objects are lit from behind:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(mirror,
-                 "\n<0|1[,...]> Reverse image horizontally:"
-                 "\n 0 = no, 1 = yes"
-                 "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(monochrome,
-                 "\n<0|1[,...]> Use image sensor as monochrome sensor:"
-                 "\n 0 = no, 1 = yes"
-                 "\nNot all the sensors support monochrome color."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(brightness, 
-                 "\n<n[,...]> Set picture brightness (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
-                 " for every device."
-                 "\nThis parameter has no effect if 'autobright' is enabled."
-                 "\n");
-MODULE_PARM_DESC(hue, 
-                 "\n<n[,...]> Set picture hue (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(colour, 
-                 "\n<n[,...]> Set picture saturation (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(contrast, 
-                 "\n<n[,...]> Set picture contrast (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
-                 " for every device."
-                 "\n");
-MODULE_PARM_DESC(whiteness, 
-                 "\n<n[,...]> Set picture whiteness (0-65535)."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
-                 " for every device."
-                 "\n");
-#ifdef W9968CF_DEBUG
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 6:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = configuration or general messages"
-                 "\n4 = warnings"
-                 "\n5 = called functions"
-                 "\n6 = function internals"
-                 "\nLevel 5 and 6 are useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
-                 "\n");
-MODULE_PARM_DESC(specific_debug,
-                 "\n<0|1> Enable or disable specific debugging messages:"
-                 "\n0 = print messages concerning every level"
-                 " <= 'debug' level."
-                 "\n1 = print messages concerning the level"
-                 " indicated by 'debug'."
-                 "\nDefault value is "
-                 __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
-                 "\n");
-#endif /* W9968CF_DEBUG */
-
-
-
-/****************************************************************************
- * Some prototypes                                                          *
- ****************************************************************************/
-
-/* Video4linux interface */
-static struct file_operations w9968cf_fops;
-static int w9968cf_open(struct inode*, struct file*);
-static int w9968cf_release(struct inode*, struct file*);
-static int w9968cf_mmap(struct file*, struct vm_area_struct*);
-static int w9968cf_ioctl(struct inode*, struct file*, unsigned, unsigned long);
-static ssize_t w9968cf_read(struct file*, char __user *, size_t, loff_t*);
-static int w9968cf_v4l_ioctl(struct inode*, struct file*, unsigned int,
-                             void __user *);
-
-/* USB-specific */
-static int w9968cf_start_transfer(struct w9968cf_device*);
-static int w9968cf_stop_transfer(struct w9968cf_device*);
-static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
-static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
-static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
-static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
-static int w9968cf_read_sb(struct w9968cf_device*);
-static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
-
-/* Low-level I2C (SMBus) I/O */
-static int w9968cf_smbus_start(struct w9968cf_device*);
-static int w9968cf_smbus_stop(struct w9968cf_device*);
-static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
-static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
-static int w9968cf_smbus_write_ack(struct w9968cf_device*);
-static int w9968cf_smbus_read_ack(struct w9968cf_device*);
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
-static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-                                      u16 address, u8* value);
-static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address, 
-                                           u8 subaddress, u8* value);
-static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
-                                       u16 address, u8 subaddress);
-static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
-                                                u16 address, u8 subaddress,
-                                                u8 value);
-
-/* I2C interface to kernel */
-static int w9968cf_i2c_init(struct w9968cf_device*);
-static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr, 
-                                  unsigned short flags, char read_write, 
-                                  u8 command, int size, union i2c_smbus_data*);
-static u32 w9968cf_i2c_func(struct i2c_adapter*);
-static int w9968cf_i2c_attach_inform(struct i2c_client*);
-static int w9968cf_i2c_detach_inform(struct i2c_client*);
-static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
-                               unsigned long arg);
-
-/* Memory management */
-static void* rvmalloc(unsigned long size);
-static void rvfree(void *mem, unsigned long size);
-static void w9968cf_deallocate_memory(struct w9968cf_device*);
-static int  w9968cf_allocate_memory(struct w9968cf_device*);
-
-/* High-level image sensor control functions */
-static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
-static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
-static int w9968cf_sensor_cmd(struct w9968cf_device*,
-                              unsigned int cmd, void *arg);
-static int w9968cf_sensor_init(struct w9968cf_device*);
-static int w9968cf_sensor_update_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*);
-static int w9968cf_sensor_update_picture(struct w9968cf_device*, 
-                                         struct video_picture pict);
-
-/* Other helper functions */
-static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
-                                     enum w9968cf_model_id, 
-                                     const unsigned short dev_nr);
-static void w9968cf_adjust_configuration(struct w9968cf_device*);
-static int w9968cf_turn_on_led(struct w9968cf_device*);
-static int w9968cf_init_chip(struct w9968cf_device*);
-static inline u16 w9968cf_valid_palette(u16 palette);
-static inline u16 w9968cf_valid_depth(u16 palette);
-static inline u8 w9968cf_need_decompression(u16 palette);
-static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
-static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
-static int w9968cf_postprocess_frame(struct w9968cf_device*, 
-                                     struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u16* w, u16* h);
-static void w9968cf_init_framelist(struct w9968cf_device*);
-static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
-static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
-static void w9968cf_release_resources(struct w9968cf_device*);
-
-
-
-/****************************************************************************
- * Symbolic names                                                           *
- ****************************************************************************/
-
-/* Used to represent a list of values and their respective symbolic names */
-struct w9968cf_symbolic_list {
-       const int num;
-       const char *name;
-};
-
-/*-------------------------------------------------------------------------- 
-  Returns the name of the matching element in the symbolic_list array. The
-  end of the list must be marked with an element that has a NULL name.
-  --------------------------------------------------------------------------*/
-static inline const char * 
-symbolic(struct w9968cf_symbolic_list list[], const int num)
-{
-       int i;
-
-       for (i = 0; list[i].name != NULL; i++)
-               if (list[i].num == num)
-                       return (list[i].name);
-
-       return "Unknown";
-}
-
-static struct w9968cf_symbolic_list camlist[] = {
-       { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
-       { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
-
-       /* Other cameras (having the same descriptors as Generic W996[87]CF) */
-       { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
-       { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
-       { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
-       { W9968CF_MOD_LL, "Lebon LDC-035A" },
-       { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
-       { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
-       { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
-       { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
-       { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
-
-       {  -1, NULL }
-};
-
-static struct w9968cf_symbolic_list senlist[] = {
-       { CC_OV76BE,   "OV76BE" },
-       { CC_OV7610,   "OV7610" },
-       { CC_OV7620,   "OV7620" },
-       { CC_OV7620AE, "OV7620AE" },
-       { CC_OV6620,   "OV6620" },
-       { CC_OV6630,   "OV6630" },
-       { CC_OV6630AE, "OV6630AE" },
-       { CC_OV6630AF, "OV6630AF" },
-       { -1, NULL }
-};
-
-/* Video4Linux1 palettes */
-static struct w9968cf_symbolic_list v4l1_plist[] = {
-       { VIDEO_PALETTE_GREY,    "GREY" },
-       { VIDEO_PALETTE_HI240,   "HI240" },
-       { VIDEO_PALETTE_RGB565,  "RGB565" },
-       { VIDEO_PALETTE_RGB24,   "RGB24" },
-       { VIDEO_PALETTE_RGB32,   "RGB32" },
-       { VIDEO_PALETTE_RGB555,  "RGB555" },
-       { VIDEO_PALETTE_YUV422,  "YUV422" },
-       { VIDEO_PALETTE_YUYV,    "YUYV" },
-       { VIDEO_PALETTE_UYVY,    "UYVY" },
-       { VIDEO_PALETTE_YUV420,  "YUV420" },
-       { VIDEO_PALETTE_YUV411,  "YUV411" },
-       { VIDEO_PALETTE_RAW,     "RAW" },
-       { VIDEO_PALETTE_YUV422P, "YUV422P" },
-       { VIDEO_PALETTE_YUV411P, "YUV411P" },
-       { VIDEO_PALETTE_YUV420P, "YUV420P" },
-       { VIDEO_PALETTE_YUV410P, "YUV410P" },
-       { -1, NULL }
-};
-
-/* Decoder error codes: */
-static struct w9968cf_symbolic_list decoder_errlist[] = {
-       { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
-       { W9968CF_DEC_ERR_BUF_OVERFLOW,   "Buffer overflow" },
-       { W9968CF_DEC_ERR_NO_SOI,         "SOI marker not found" },     
-       { W9968CF_DEC_ERR_NO_SOF0,        "SOF0 marker not found" },
-       { W9968CF_DEC_ERR_NO_SOS,         "SOS marker not found" },
-       { W9968CF_DEC_ERR_NO_EOI,         "EOI marker not found" },
-       { -1, NULL }
-};
-
-/* URB error codes: */
-static struct w9968cf_symbolic_list urb_errlist[] = {
-       { -ENOMEM,    "No memory for allocation of internal structures" },
-       { -ENOSPC,    "The host controller's bandwidth is already consumed" },
-       { -ENOENT,    "URB was canceled by unlink_urb" },
-       { -EXDEV,     "ISO transfer only partially completed" },
-       { -EAGAIN,    "Too match scheduled for the future" },
-       { -ENXIO,     "URB already queued" },
-       { -EFBIG,     "Too much ISO frames requested" },
-       { -ENOSR,     "Buffer error (overrun)" },
-       { -EPIPE,     "Specified endpoint is stalled (device not responding)"},
-       { -EOVERFLOW, "Babble (bad cable?)" },
-       { -EPROTO,    "Bit-stuff error (bad cable?)" },
-       { -EILSEQ,    "CRC/Timeout" },
-       { -ETIMEDOUT, "NAK (device does not respond)" },
-       { -1, NULL }
-};
-
-
-
-/****************************************************************************
- * Memory management functions                                              *
- ****************************************************************************/
-static void* rvmalloc(unsigned long size)
-{
-       void* mem;
-       unsigned long adr;
-
-       size = PAGE_ALIGN(size);
-       mem = vmalloc_32(size);
-       if (!mem)
-               return NULL;
-
-       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-       adr = (unsigned long) mem;
-       while (size > 0) {
-               SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       return mem;
-}
-
-
-static void rvfree(void* mem, unsigned long size)
-{
-       unsigned long adr;
-
-       if (!mem)
-               return;
-
-       adr = (unsigned long) mem;
-       while ((long) size > 0) {
-               ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-       vfree(mem);
-}
-
-
-/*--------------------------------------------------------------------------
-  Deallocate previously allocated memory.
-  --------------------------------------------------------------------------*/
-static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
-{
-       u8 i;
-
-       /* Free the isochronous transfer buffers */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               kfree(cam->transfer_buffer[i]);
-               cam->transfer_buffer[i] = NULL;
-       }
-
-       /* Free temporary frame buffer */
-       if (cam->frame_tmp.buffer) {
-               rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
-               cam->frame_tmp.buffer = NULL;
-       }
-
-       /* Free helper buffer */
-       if (cam->frame_vpp.buffer) {
-               rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
-               cam->frame_vpp.buffer = NULL;
-       }
-
-       /* Free video frame buffers */
-       if (cam->frame[0].buffer) {
-               rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
-               cam->frame[0].buffer = NULL;
-       }
-
-       cam->nbuffers = 0;
-
-       DBG(5, "Memory successfully deallocated")
-}
-
-
-/*--------------------------------------------------------------------------
-  Allocate memory buffers for USB transfers and video frames.
-  This function is called by open() only.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_allocate_memory(struct w9968cf_device* cam)
-{
-       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-       void* buff = NULL;
-       unsigned long hw_bufsize, vpp_bufsize;
-       u8 i, bpp;
-
-       /* NOTE: Deallocation is done elsewhere in case of error */
-
-       /* Calculate the max amount of raw data per frame from the device */
-       hw_bufsize = cam->maxwidth*cam->maxheight*2;
-
-       /* Calculate the max buf. size needed for post-processing routines */
-       bpp = (w9968cf_vpp) ? 4 : 2;
-       if (cam->upscaling)
-               vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
-                                 cam->maxwidth*cam->maxheight*bpp);
-       else
-               vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
-
-       /* Allocate memory for the isochronous transfer buffers */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               if (!(cam->transfer_buffer[i] =
-                     kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
-                       DBG(1, "Couldn't allocate memory for the isochronous "
-                              "transfer buffers (%u bytes)", 
-                           p_size * W9968CF_ISO_PACKETS)
-                       return -ENOMEM;
-               }
-       }
-
-       /* Allocate memory for the temporary frame buffer */
-       if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
-               DBG(1, "Couldn't allocate memory for the temporary "
-                      "video frame buffer (%lu bytes)", hw_bufsize)
-               return -ENOMEM;
-       }
-       cam->frame_tmp.size = hw_bufsize;
-       cam->frame_tmp.number = -1;
-
-       /* Allocate memory for the helper buffer */
-       if (w9968cf_vpp) {
-               if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
-                       DBG(1, "Couldn't allocate memory for the helper buffer"
-                              " (%lu bytes)", vpp_bufsize)
-                       return -ENOMEM;
-               }
-               cam->frame_vpp.size = vpp_bufsize;
-       } else
-               cam->frame_vpp.buffer = NULL;
-
-       /* Allocate memory for video frame buffers */
-       cam->nbuffers = cam->max_buffers;
-       while (cam->nbuffers >= 2) {
-               if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
-                       break;
-               else
-                       cam->nbuffers--;
-       }
-
-       if (!buff) {
-               DBG(1, "Couldn't allocate memory for the video frame buffers")
-               cam->nbuffers = 0;
-               return -ENOMEM;
-       }
-
-       if (cam->nbuffers != cam->max_buffers)
-               DBG(2, "Couldn't allocate memory for %u video frame buffers. "
-                      "Only memory for %u buffers has been allocated",
-                   cam->max_buffers, cam->nbuffers)
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].buffer = buff + i*vpp_bufsize;
-               cam->frame[i].size = vpp_bufsize;
-               cam->frame[i].number = i;
-               /* Circular list */
-               if (i != cam->nbuffers-1)
-                       cam->frame[i].next = &cam->frame[i+1];
-               else
-                       cam->frame[i].next = &cam->frame[0];
-               cam->frame[i].status = F_UNUSED;
-       }
-
-       DBG(5, "Memory successfully allocated")
-       return 0;
-}
-
-
-
-/****************************************************************************
- * USB-specific functions                                                   *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This is an handler function which is called after the URBs are completed.
-  It collects multiple data packets coming from the camera by putting them
-  into frame buffers: one or more zero data length data packets are used to
-  mark the end of a video frame; the first non-zero data packet is the start
-  of the next video frame; if an error is encountered in a packet, the entire
-  video frame is discarded and grabbed again.
-  If there are no requested frames in the FIFO list, packets are collected into
-  a temporary buffer. 
-  --------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
-{
-       struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
-       struct w9968cf_frame_t** f;
-       unsigned int len, status;
-       void* pos;
-       u8 i;
-       int err = 0;
-
-       if ((!cam->streaming) || cam->disconnected) {
-               DBG(4, "Got interrupt, but not streaming")
-               return;
-       }
-
-       /* "(*f)" will be used instead of "cam->frame_current" */
-       f = &cam->frame_current;
-
-       /* If a frame has been requested and we are grabbing into  
-          the temporary frame, we'll switch to that requested frame */
-       if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
-               if (cam->frame_tmp.status == F_GRABBING) {
-                       w9968cf_pop_frame(cam, &cam->frame_current);
-                       (*f)->status = F_GRABBING;
-                       (*f)->length = cam->frame_tmp.length;
-                       memcpy((*f)->buffer, cam->frame_tmp.buffer,
-                              (*f)->length);
-                       DBG(6, "Switched from temp. frame to frame #%d", 
-                           (*f)->number)
-               }
-       }
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status && len != 0) {
-                       DBG(4, "URB failed, error in data packet "
-                              "(error #%u, %s)",
-                           status, symbolic(urb_errlist, status))
-                       (*f)->status = F_ERROR;
-                       continue;
-               }
-
-               if (len) { /* start of frame */
-
-                       if ((*f)->status == F_UNUSED) {
-                               (*f)->status = F_GRABBING;
-                               (*f)->length = 0;
-                       }
-
-                       /* Buffer overflows shouldn't happen, however...*/
-                       if ((*f)->length + len > (*f)->size) {
-                               DBG(4, "Buffer overflow: bad data packets")
-                               (*f)->status = F_ERROR;
-                       }
-
-                       if ((*f)->status == F_GRABBING) {
-                               memcpy((*f)->buffer + (*f)->length, pos, len);
-                               (*f)->length += len;
-                       }
-
-               } else if ((*f)->status == F_GRABBING) { /* end of frame */
-
-                       DBG(6, "Frame #%d successfully grabbed", (*f)->number)
-
-                       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-                               err = w9968cf_vpp->check_headers((*f)->buffer,
-                                                                (*f)->length);
-                               if (err) {
-                                       DBG(4, "Skip corrupted frame: %s",
-                                           symbolic(decoder_errlist, err))
-                                       (*f)->status = F_UNUSED;
-                                       continue; /* grab this frame again */
-                               }
-                       }
-
-                       (*f)->status = F_READY;
-                       (*f)->queued = 0;
-
-                       /* Take a pointer to the new frame from the FIFO list.
-                          If the list is empty,we'll use the temporary frame*/
-                       if (*cam->requested_frame)
-                               w9968cf_pop_frame(cam, &cam->frame_current);
-                       else {
-                               cam->frame_current = &cam->frame_tmp;
-                               (*f)->status = F_UNUSED;
-                       }
-
-               } else if ((*f)->status == F_ERROR)
-                       (*f)->status = F_UNUSED; /* grab it again */
-
-               PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
-                     (unsigned long)(*f)->length, i, len, (*f)->status)
-
-       } /* end for */
-
-       /* Resubmit this URB */
-       urb->dev = cam->usbdev;
-       urb->status = 0;
-       spin_lock(&cam->urb_lock);
-       if (cam->streaming)
-               if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
-                       cam->misconfigured = 1;
-                       DBG(1, "Couldn't resubmit the URB: error %d, %s",
-                           err, symbolic(urb_errlist, err))
-               }
-       spin_unlock(&cam->urb_lock);
-
-       /* Wake up the user process */
-       wake_up_interruptible(&cam->wait_queue);
-}
-
-
-/*---------------------------------------------------------------------------
-  Setup the URB structures for the isochronous transfer.
-  Submit the URBs so that the data transfer begins.
-  Return 0 on success, a negative number otherwise.
-  ---------------------------------------------------------------------------*/
-static int w9968cf_start_transfer(struct w9968cf_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const u16 p_size = wMaxPacketSize[cam->altsetting-1];
-       u16 w, h, d;
-       int vidcapt;
-       u32 t_size;
-       int err = 0;
-       s8 i, j;
-
-       for (i = 0; i < W9968CF_URBS; i++) {
-               urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       for (j = 0; j < i; j++)
-                               usb_free_urb(cam->urb[j]);
-                       DBG(1, "Couldn't allocate the URB structures")
-                       return -ENOMEM;
-               }
-
-               urb->dev = udev;
-               urb->context = (void*)cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = W9968CF_ISO_PACKETS;
-               urb->complete = w9968cf_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = p_size*j;
-                       urb->iso_frame_desc[j].length = p_size;
-               }
-       }
-
-       /* Transfer size per frame, in WORD ! */
-       d = cam->hw_depth;
-       w = cam->hw_width;
-       h = cam->hw_height;
-
-       t_size = (w*h*d)/16;
-
-       err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-
-       /* Transfer size */
-       err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
-       err += w9968cf_write_reg(cam, t_size >> 16, 0x3e);    /* high bits */
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION)
-               err += w9968cf_upload_quantizationtables(cam);
-
-       vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
-       err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
-
-       err += usb_set_interface(udev, 0, cam->altsetting);
-       err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
-
-       if (err || (vidcapt < 0)) {
-               for (i = 0; i < W9968CF_URBS; i++)
-                       usb_free_urb(cam->urb[i]);
-               DBG(1, "Couldn't tell the camera to start the data transfer")
-               return err;
-       }
-
-       w9968cf_init_framelist(cam);
-
-       /* Begin to grab into the temporary buffer */
-       cam->frame_tmp.status = F_UNUSED;
-       cam->frame_tmp.queued = 0;
-       cam->frame_current = &cam->frame_tmp;
-
-       if (!(cam->vpp_flag & VPP_DECOMPRESSION))
-               DBG(5, "Isochronous transfer size: %lu bytes/frame", 
-                   (unsigned long)t_size*2)
-
-       DBG(5, "Starting the isochronous transfer...")
-
-       cam->streaming = 1;
-
-       /* Submit the URBs */
-       for (i = 0; i < W9968CF_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       cam->streaming = 0;
-                       for (j = i-1; j >= 0; j--) {
-                               usb_kill_urb(cam->urb[j]);
-                               usb_free_urb(cam->urb[j]);
-                       }
-                       DBG(1, "Couldn't send a transfer request to the "
-                              "USB core (error #%d, %s)", err, 
-                           symbolic(urb_errlist, err))
-                       return err;
-               }
-       }
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_stop_transfer(struct w9968cf_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       unsigned long lock_flags;
-       int err = 0;
-       s8 i;
-
-       if (!cam->streaming)
-               return 0;
-
-       /* This avoids race conditions with usb_submit_urb() 
-          in the URB completition handler */
-       spin_lock_irqsave(&cam->urb_lock, lock_flags);
-       cam->streaming = 0;
-       spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
-
-       for (i = W9968CF_URBS-1; i >= 0; i--)
-               if (cam->urb[i]) {
-                       usb_kill_urb(cam->urb[i]);
-                       usb_free_urb(cam->urb[i]);
-                       cam->urb[i] = NULL;
-               }
-
-       if (cam->disconnected)
-               goto exit;
-
-       err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
-       err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
-       err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
-
-       if (err) {
-               DBG(2, "Failed to tell the camera to stop the isochronous "
-                      "transfer. However this is not a critical error.")
-               return -EIO;
-       }
-
-exit:
-       DBG(5, "Isochronous transfer stopped")
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write a W9968CF register. 
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       int res;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-                             value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to write a register "
-                      "(value 0x%04X, index 0x%02X, error #%d, %s)",
-                   value, index, res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read a W9968CF register. 
-  Return the register value on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u16* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
-                             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                             0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to read a register "
-                      "(index 0x%02X, error #%d, %s)",
-                   index, res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write 64-bit data to the fast serial bus registers.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
-{
-       struct usb_device* udev = cam->usbdev;
-       u16 value;
-       int res;
-
-       value = *data++;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
-                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
-                             value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
-
-       if (res < 0)
-               DBG(4, "Failed to write the FSB registers "
-                      "(error #%d, %s)", res, symbolic(urb_errlist, res))
-
-       return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write data to the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
-{
-       int err = 0;
-
-       err = w9968cf_write_reg(cam, value, 0x01);
-       udelay(W9968CF_I2C_BUS_DELAY);
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Read data from the serial bus control register.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_read_sb(struct w9968cf_device* cam)
-{
-       int v = 0;
-
-       v = w9968cf_read_reg(cam, 0x01);
-       udelay(W9968CF_I2C_BUS_DELAY);
-
-       return v;
-}
-
-
-/*--------------------------------------------------------------------------
-  Upload quantization tables for the JPEG compression.
-  This function is called by w9968cf_start_transfer().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
-{
-       u16 a, b;
-       int err = 0, i, j;
-
-       err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
-
-       for (i = 0, j = 0; i < 32; i++, j += 2) {
-               a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
-               b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
-               err += w9968cf_write_reg(cam, a, 0x40+i);
-               err += w9968cf_write_reg(cam, b, 0x60+i);
-       }
-       err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
-
-       return err;
-}
-
-
-
-/****************************************************************************
- * Low-level I2C I/O functions.                                             *
- * The adapter supports the following I2C transfer functions:               *
- * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only)           *
- * i2c_adap_read_byte_data()                                                *
- * i2c_adap_read_byte()                                                     *
- ****************************************************************************/
-
-static int w9968cf_smbus_start(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_stop(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
-{
-       u8 bit;
-       int err = 0, sda;
-
-       for (bit = 0 ; bit < 8 ; bit++) {
-               sda = (v & 0x80) ? 2 : 0;
-               v <<= 1;
-               /* SDE=1, SDA=sda, SCL=0 */
-               err += w9968cf_write_sb(cam, 0x10 | sda);
-               /* SDE=1, SDA=sda, SCL=1 */
-               err += w9968cf_write_sb(cam, 0x11 | sda);
-               /* SDE=1, SDA=sda, SCL=0 */
-               err += w9968cf_write_sb(cam, 0x10 | sda);
-       }
-
-       return err;
-}
-
-
-static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
-{
-       u8 bit;
-       int err = 0;
-
-       *v = 0;
-       for (bit = 0 ; bit < 8 ; bit++) {
-               *v <<= 1;
-               err += w9968cf_write_sb(cam, 0x0013);
-               *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
-               err += w9968cf_write_sb(cam, 0x0012);
-       }
-
-       return err;
-}
-
-
-static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-       err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
-       err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
-       return err;
-}
-
-
-static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
-{
-       int err = 0, sda;
-
-       err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-       sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
-       err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
-       if (sda < 0)
-               err += sda;
-       if (sda == 1) {
-               DBG(6, "Couldn't receive the ACK")
-               err += -1;
-       }
-
-       return err;
-}
-
-
-/* This seems to refresh the communication through the serial bus */
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
-{
-       int err = 0, j;
-
-       for (j = 1; j <= 10; j++) {
-               err = w9968cf_write_reg(cam, 0x0020, 0x01);
-               err += w9968cf_write_reg(cam, 0x0000, 0x01);
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int 
-w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam, 
-                                     u16 address, u8 subaddress,u8 value)
-{
-       u16* data = cam->data_buffer;
-       int err = 0;
-
-       err += w9968cf_smbus_refresh_bus(cam);
-
-       /* Enable SBUS outputs */
-       err += w9968cf_write_sb(cam, 0x0020);
-
-       data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
-       data[0] |= (address & 0x40) ? 0x4000 : 0x0;
-       data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
-       data[1] |= (address & 0x20) ? 0x0150 : 0x0;
-       data[1] |= (address & 0x10) ? 0x5400 : 0x0;
-       data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
-       data[2] |= (address & 0x04) ? 0x0540 : 0x0;
-       data[2] |= (address & 0x02) ? 0x5000 : 0x0;
-       data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
-       data[3] |= (address & 0x01) ? 0x0054 : 0x0;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
-       data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
-       data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
-       data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
-       data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
-       data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
-       data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
-       data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
-       data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
-       data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
-       data[3] = 0x001d;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
-       data[0] |= (value & 0x40) ? 0x0540 : 0x0;
-       data[0] |= (value & 0x20) ? 0x5000 : 0x0;
-       data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
-       data[1] |= (value & 0x10) ? 0x0054 : 0x0;
-       data[1] |= (value & 0x08) ? 0x1500 : 0x0;
-       data[1] |= (value & 0x04) ? 0x4000 : 0x0;
-       data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
-       data[2] |= (value & 0x02) ? 0x0150 : 0x0;
-       data[2] |= (value & 0x01) ? 0x5400 : 0x0;
-       data[3] = 0xfe1d;
-
-       err += w9968cf_write_fsb(cam, data);
-
-       /* Disable SBUS outputs */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
-                      "value 0x%02X", address, subaddress, value)
-       else
-               DBG(5, "I2C write byte data failed, addr.0x%04X, "
-                      "subaddr.0x%02X, value 0x%02X", 
-                   address, subaddress, value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
-static int 
-w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam, 
-                                u16 address, u8 subaddress, 
-                                u8* value)
-{
-       int err = 0;
-
-       /* Serial data enable */
-       err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
-
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_write_byte(cam, subaddress);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address + 1);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_read_byte(cam, value);
-       err += w9968cf_smbus_write_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-
-       /* Serial data disable */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C read byte data done, addr.0x%04X, "
-                      "subaddr.0x%02X, value 0x%02X", 
-                   address, subaddress, *value)
-       else
-               DBG(5, "I2C read byte data failed, addr.0x%04X, "
-                      "subaddr.0x%02X, wrong value 0x%02X",
-                   address, subaddress, *value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
-static int 
-w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
-                           u16 address, u8* value)
-{
-       int err = 0;
-
-       /* Serial data enable */
-       err += w9968cf_write_sb(cam, 0x0013);
-
-       err += w9968cf_smbus_start(cam);
-       err += w9968cf_smbus_write_byte(cam, address + 1);
-       err += w9968cf_smbus_read_ack(cam);
-       err += w9968cf_smbus_read_byte(cam, value);
-       err += w9968cf_smbus_write_ack(cam);
-       err += w9968cf_smbus_stop(cam);
-       /* Serial data disable */
-       err += w9968cf_write_sb(cam, 0x0000);
-
-       if (!err)
-               DBG(5, "I2C read byte done, addr.0x%04X, "
-                      "value 0x%02X", address, *value)
-       else
-               DBG(5, "I2C read byte failed, addr.0x%04X, "
-                      "wrong value 0x%02X", address, *value)
-
-       return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Value [A] P */
-static int 
-w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
-                            u16 address, u8 value)
-{
-       DBG(4, "i2c_write_byte() is an unsupported transfer mode")
-       return -EINVAL;
-}
-
-
-
-/****************************************************************************
- * I2C interface to kernel                                                  *
- ****************************************************************************/
-
-static int
-w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 
-                       unsigned short flags, char read_write, u8 command,
-                       int size, union i2c_smbus_data *data)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(adapter);
-       u8 i;
-       int err = 0; 
-
-       switch (addr) {
-               case OV6xx0_SID:
-               case OV7xx0_SID:
-                       break;
-               default:
-                       DBG(4, "Rejected slave ID 0x%04X", addr)
-                       return -EINVAL;
-       }
-
-       if (size == I2C_SMBUS_BYTE) {
-               /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
-               addr <<= 1;
-
-               if (read_write == I2C_SMBUS_WRITE)
-                       err = w9968cf_i2c_adap_write_byte(cam, addr, command);
-               else if (read_write == I2C_SMBUS_READ) 
-                       err = w9968cf_i2c_adap_read_byte(cam,addr,&data->byte);
-
-       } else if (size == I2C_SMBUS_BYTE_DATA) {
-               addr <<= 1;
-
-               if (read_write == I2C_SMBUS_WRITE)
-                       err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
-                                                         command, data->byte);
-               else if (read_write == I2C_SMBUS_READ) {
-                       for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
-                               err = w9968cf_i2c_adap_read_byte_data(cam,addr,
-                                                        command, &data->byte);
-                               if (err) {
-                                       if (w9968cf_smbus_refresh_bus(cam)) {
-                                               err = -EIO;
-                                               break;
-                                       }
-                               } else
-                                       break;
-                       }
-
-               } else
-                       return -EINVAL;
-
-       } else {
-               DBG(4, "Unsupported I2C transfer mode (%d)", size)
-               return -EINVAL;
-       }
-
-       return err;
-}
-
-
-static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
-{
-       return I2C_FUNC_SMBUS_READ_BYTE |
-              I2C_FUNC_SMBUS_READ_BYTE_DATA  |
-              I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_attach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-       int id = client->driver->id, err = 0;
-
-       if (id == I2C_DRIVERID_OVCAMCHIP) {
-               cam->sensor_client = client;
-               err = w9968cf_sensor_init(cam);
-               if (err) {
-                       cam->sensor_client = NULL;
-                       return err;
-               }
-       } else {
-               DBG(4, "Rejected client [%s] with driver [%s]", 
-                   client->name, client->driver->driver.name)
-               return -EINVAL;
-       }
-
-       DBG(5, "I2C attach client [%s] with driver [%s]",
-           client->name, client->driver->driver.name)
-
-       return 0;
-}
-
-
-static int w9968cf_i2c_detach_inform(struct i2c_client* client)
-{
-       struct w9968cf_device* cam = i2c_get_adapdata(client->adapter);
-
-       if (cam->sensor_client == client)
-               cam->sensor_client = NULL;
-
-       DBG(5, "I2C detach client [%s]", client->name)
-
-       return 0;
-}
-
-
-static int 
-w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
-                    unsigned long arg)
-{
-       return 0;
-}
-
-
-static int w9968cf_i2c_init(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       static struct i2c_algorithm algo = {
-               .smbus_xfer =    w9968cf_i2c_smbus_xfer,
-               .algo_control =  w9968cf_i2c_control,
-               .functionality = w9968cf_i2c_func,
-       };
-
-       static struct i2c_adapter adap = {
-               .id =                I2C_HW_SMBUS_W9968CF,
-               .class =             I2C_CLASS_CAM_DIGITAL,
-               .owner =             THIS_MODULE,
-               .client_register =   w9968cf_i2c_attach_inform,
-               .client_unregister = w9968cf_i2c_detach_inform,
-               .algo =              &algo,
-       };
-
-       memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
-       strcpy(cam->i2c_adapter.name, "w9968cf");
-       i2c_set_adapdata(&cam->i2c_adapter, cam);
-
-       DBG(6, "Registering I2C adapter with kernel...")
-
-       err = i2c_add_adapter(&cam->i2c_adapter);
-       if (err)
-               DBG(1, "Failed to register the I2C adapter")
-       else
-               DBG(5, "I2C adapter registered")
-
-       return err;
-}
-
-
-
-/****************************************************************************
- * Helper functions                                                         *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  Turn on the LED on some webcams. A beep should be heard too.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_turn_on_led(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
-       err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
-       err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
-       err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
-
-       if (err)
-               DBG(2, "Couldn't turn on the LED")
-
-       DBG(5, "LED turned on")
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Write some registers for the device initialization.
-  This function is called once on open().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_init_chip(struct w9968cf_device* cam)
-{
-       unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
-                     y0 = 0x0000,
-                     u0 = y0 + hw_bufsize/2,
-                     v0 = u0 + hw_bufsize/4,
-                     y1 = v0 + hw_bufsize/4,
-                     u1 = y1 + hw_bufsize/2,
-                     v1 = u1 + hw_bufsize/4;
-       int err = 0;
-
-       err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
-       err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
-
-       err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
-       err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
-
-       err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
-       err += w9968cf_write_reg(cam, y0 >> 16, 0x21);    /* Y buf.0, high */
-       err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
-       err += w9968cf_write_reg(cam, u0 >> 16, 0x25);    /* U buf.0, high */
-       err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
-       err += w9968cf_write_reg(cam, v0 >> 16, 0x29);    /* V buf.0, high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x23);    /* Y buf.1, high */
-       err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
-       err += w9968cf_write_reg(cam, u1 >> 16, 0x27);    /* U buf.1, high */
-       err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
-       err += w9968cf_write_reg(cam, v1 >> 16, 0x2b);    /* V buf.1, high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x33);    /* JPEG buf 0 high */
-
-       err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
-       err += w9968cf_write_reg(cam, y1 >> 16, 0x35);    /* JPEG bug 1 high */
-
-       err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
-       err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
-       err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
-       err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
-
-       err += w9968cf_set_picture(cam, cam->picture); /* this before */
-       err += w9968cf_set_window(cam, cam->window);
-
-       if (err)
-               DBG(1, "Chip initialization failed")
-       else
-               DBG(5, "Chip successfully initialized")
-
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the palette is supported, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_palette(u16 palette)
-{
-       u8 i = 0;
-       while (w9968cf_formatlist[i].palette != 0) {
-               if (palette == w9968cf_formatlist[i].palette)
-                       return palette;
-               i++;
-       }
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return the depth corresponding to the given palette.
-  Palette _must_ be supported !
-  --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_depth(u16 palette)
-{
-       u8 i=0;
-       while (w9968cf_formatlist[i].palette != palette)
-               i++;
-
-       return w9968cf_formatlist[i].depth;
-}
-
-
-/*--------------------------------------------------------------------------
-  Return non-zero if the format requires decompression, 0 otherwise.
-  --------------------------------------------------------------------------*/
-static inline u8 w9968cf_need_decompression(u16 palette)
-{
-       u8 i = 0;
-       while (w9968cf_formatlist[i].palette != 0) {
-               if (palette == w9968cf_formatlist[i].palette)
-                       return w9968cf_formatlist[i].compression;
-               i++;
-       }
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the picture settings of the camera.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
-{
-       u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
-       int err = 0;
-
-       /* Make sure we are using a valid depth */
-       pict.depth = w9968cf_valid_depth(pict.palette);
-
-       fmt = pict.palette;
-
-       hw_depth = pict.depth; /* depth used by the winbond chip */
-       hw_palette = pict.palette; /* palette used by the winbond chip */
-
-       /* VS & HS polarities */
-       reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
-
-       switch (fmt)
-       {
-               case VIDEO_PALETTE_UYVY:
-                       reg_v |= 0x0000;
-                       cam->vpp_flag = VPP_NONE;
-                       break;
-               case VIDEO_PALETTE_YUV422P:
-                       reg_v |= 0x0002;
-                       cam->vpp_flag = VPP_DECOMPRESSION;
-                       break;
-               case VIDEO_PALETTE_YUV420:
-               case VIDEO_PALETTE_YUV420P:
-                       reg_v |= 0x0003;
-                       cam->vpp_flag = VPP_DECOMPRESSION;
-                       break;
-               case VIDEO_PALETTE_YUYV:
-               case VIDEO_PALETTE_YUV422:
-                       reg_v |= 0x0000;
-                       cam->vpp_flag = VPP_SWAP_YUV_BYTES;
-                       hw_palette = VIDEO_PALETTE_UYVY;
-                       break;
-               /* Original video is used instead of RGBX palettes. 
-                  Software conversion later. */
-               case VIDEO_PALETTE_GREY:
-               case VIDEO_PALETTE_RGB555:
-               case VIDEO_PALETTE_RGB565:
-               case VIDEO_PALETTE_RGB24:
-               case VIDEO_PALETTE_RGB32:
-                       reg_v |= 0x0000; /* UYVY 16 bit is used */
-                       hw_depth = 16;
-                       hw_palette = VIDEO_PALETTE_UYVY;
-                       cam->vpp_flag = VPP_UYVY_TO_RGBX;
-                       break;
-       }
-
-       /* NOTE: due to memory issues, it is better to disable the hardware
-                double buffering during compression */
-       if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
-               reg_v |= 0x0080;
-
-       if (cam->clamping)
-               reg_v |= 0x0020;
-
-       if (cam->filter_type == 1)
-               reg_v |= 0x0008;
-       else if (cam->filter_type == 2)
-               reg_v |= 0x000c;
-
-       if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
-               goto error;
-
-       if ((err = w9968cf_sensor_update_picture(cam, pict)))
-               goto error;
-
-       /* If all went well, update the device data structure */
-       memcpy(&cam->picture, &pict, sizeof(pict));
-       cam->hw_depth = hw_depth;
-       cam->hw_palette = hw_palette;
-
-       /* Settings changed, so we clear the frame buffers */
-       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-       DBG(4, "Palette is %s, depth is %u bpp",
-           symbolic(v4l1_plist, pict.palette), pict.depth)
-
-       return 0;
-
-error:
-       DBG(1, "Failed to change picture settings")
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Change the capture area size of the camera.
-  This function _must_ be called _after_ w9968cf_set_picture().
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
-{
-       u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
-       unsigned long fw, fh;
-       struct ovcamchip_window s_win;
-       int err = 0;
-
-       /* Work around to avoid FP arithmetics */
-       #define __SC(x) ((x) << 10)
-       #define __UNSC(x) ((x) >> 10)
-
-       /* Make sure we are using a supported resolution */
-       if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width, 
-                                             (u16*)&win.height)))
-               goto error;
-
-       /* Scaling factors */
-       fw = __SC(win.width) / cam->maxwidth;
-       fh = __SC(win.height) / cam->maxheight;
-
-       /* Set up the width and height values used by the chip */
-       if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
-               cam->vpp_flag |= VPP_UPSCALE;
-               /* Calculate largest w,h mantaining the same w/h ratio */
-               w = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
-               h = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
-               if (w < cam->minwidth) /* just in case */
-                       w = cam->minwidth;
-               if (h < cam->minheight) /* just in case */
-                       h = cam->minheight;
-       } else {
-               cam->vpp_flag &= ~VPP_UPSCALE;
-               w = win.width;
-               h = win.height;
-       }
-
-       /* x,y offsets of the cropped area */
-       scx = cam->start_cropx;
-       scy = cam->start_cropy;
-
-       /* Calculate cropped area manteining the right w/h ratio */
-       if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
-               cw = (fw >= fh) ? cam->maxwidth : __SC(win.width)/fh;
-               ch = (fw >= fh) ? __SC(win.height)/fw : cam->maxheight;
-       } else {
-               cw = w;
-               ch = h;
-       }
-
-       /* Setup the window of the sensor */
-       s_win.format = VIDEO_PALETTE_UYVY;
-       s_win.width = cam->maxwidth;
-       s_win.height = cam->maxheight;
-       s_win.quarter = 0; /* full progressive video */
-
-       /* Center it */
-       s_win.x = (s_win.width - cw) / 2;
-       s_win.y = (s_win.height - ch) / 2;
-
-       /* Clock divisor */
-       if (cam->clockdiv >= 0)
-               s_win.clockdiv = cam->clockdiv; /* manual override */
-       else
-               switch (cam->sensor) {
-                       case CC_OV6620:
-                               s_win.clockdiv = 0;
-                               break;
-                       case CC_OV6630:
-                               s_win.clockdiv = 0;
-                               break;
-                       case CC_OV76BE:
-                       case CC_OV7610:
-                       case CC_OV7620:
-                               s_win.clockdiv = 0;
-                               break;
-                       default:
-                               s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
-               }
-
-       /* We have to scale win.x and win.y offsets */
-       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-            || (cam->vpp_flag & VPP_UPSCALE) ) {
-               ax = __SC(win.x)/fw;
-               ay = __SC(win.y)/fh;
-       } else {
-               ax = win.x;
-               ay = win.y;
-       }
-
-       if ((ax + cw) > cam->maxwidth)
-               ax = cam->maxwidth - cw;
-
-       if ((ay + ch) > cam->maxheight)
-               ay = cam->maxheight - ch;
-
-       /* Adjust win.x, win.y */
-       if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
-            || (cam->vpp_flag & VPP_UPSCALE) ) {
-               win.x = __UNSC(ax*fw);
-               win.y = __UNSC(ay*fh);
-       } else {
-               win.x = ax;
-               win.y = ay;
-       }
-
-       /* Offsets used by the chip */
-       x = ax + s_win.x;
-       y = ay + s_win.y;
-
-       /* Go ! */
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
-               goto error;
-
-       err += w9968cf_write_reg(cam, scx + x, 0x10);
-       err += w9968cf_write_reg(cam, scy + y, 0x11);
-       err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
-       err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
-       err += w9968cf_write_reg(cam, w, 0x14);
-       err += w9968cf_write_reg(cam, h, 0x15);
-
-       /* JPEG width & height */
-       err += w9968cf_write_reg(cam, w, 0x30);
-       err += w9968cf_write_reg(cam, h, 0x31);
-
-       /* Y & UV frame buffer strides (in WORD) */
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               err += w9968cf_write_reg(cam, w/2, 0x2c);
-               err += w9968cf_write_reg(cam, w/4, 0x2d);
-       } else
-               err += w9968cf_write_reg(cam, w, 0x2c);
-
-       if (err)
-               goto error;
-
-       /* If all went well, update the device data structure */
-       memcpy(&cam->window, &win, sizeof(win));
-       cam->hw_width = w;
-       cam->hw_height = h;
-
-       /* Settings changed, so we clear the frame buffers */
-       memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
-       DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)", 
-           win.width, win.height, win.x, win.y)
-
-       PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
-             "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
-             x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
-             win.width, win.height)
-
-       return 0;
-
-error:
-       DBG(1, "Failed to change the capture area size")
-       return err;
-}
-
-
-/*-------------------------------------------------------------------------- 
-  Adjust the asked values for window width and height.
-  Return 0 on success, -1 otherwise.
-  --------------------------------------------------------------------------*/
-static int 
-w9968cf_adjust_window_size(struct w9968cf_device* cam, u16* width, u16* height)
-{
-       u16 maxw, maxh;
-
-       if ((*width < cam->minwidth) || (*height < cam->minheight))
-               return -ERANGE;
-
-       maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-              w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
-                          : cam->maxwidth;
-       maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
-              w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-                          : cam->maxheight;
-
-       if (*width > maxw)
-               *width = maxw;
-       if (*height > maxh)
-               *height = maxh;
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               *width  &= ~15L; /* multiple of 16 */
-               *height &= ~15L;
-       }
-
-       PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Initialize the FIFO list of requested frames.
-  --------------------------------------------------------------------------*/
-static void w9968cf_init_framelist(struct w9968cf_device* cam)
-{
-       u8 i;
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->requested_frame[i] = NULL;
-               cam->frame[i].queued = 0;
-               cam->frame[i].status = F_UNUSED;
-       }
-}
-
-
-/*--------------------------------------------------------------------------
-  Add a frame in the FIFO list of requested frames.
-  This function is called in process context.
-  --------------------------------------------------------------------------*/
-static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
-{
-       u8 f;
-       unsigned long lock_flags;
-
-       spin_lock_irqsave(&cam->flist_lock, lock_flags);
-
-       for (f=0; cam->requested_frame[f] != NULL; f++);
-       cam->requested_frame[f] = &cam->frame[f_num];
-       cam->frame[f_num].queued = 1;
-       cam->frame[f_num].status = F_UNUSED; /* clear the status */
-
-       spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
-
-       DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
-}
-
-
-/*--------------------------------------------------------------------------
-  Read, store and remove the first pointer in the FIFO list of requested
-  frames. This function is called in interrupt context.
-  --------------------------------------------------------------------------*/
-static void 
-w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
-{
-       u8 i;
-
-       spin_lock(&cam->flist_lock);
-
-       *framep = cam->requested_frame[0];
-
-       /* Shift the list of pointers */
-       for (i = 0; i < cam->nbuffers-1; i++)
-               cam->requested_frame[i] = cam->requested_frame[i+1];
-       cam->requested_frame[i] = NULL;
-
-       spin_unlock(&cam->flist_lock);
-
-       DBG(6,"Popped frame #%d from the list", (*framep)->number)
-}
-
-
-/*--------------------------------------------------------------------------
-  High-level video post-processing routine on grabbed frames.
-  Return 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int 
-w9968cf_postprocess_frame(struct w9968cf_device* cam, 
-                          struct w9968cf_frame_t* fr)
-{
-       void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
-       u16 w = cam->window.width,
-           h = cam->window.height,
-           d = cam->picture.depth,
-           fmt = cam->picture.palette,
-           rgb = cam->force_rgb,
-           hw_w = cam->hw_width,
-           hw_h = cam->hw_height,
-           hw_d = cam->hw_depth;
-       int err = 0;
-
-       #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
-
-       if (cam->vpp_flag & VPP_DECOMPRESSION) {
-               memcpy(pOut, pIn, fr->length);
-               _PSWAP(pIn, pOut)
-               err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
-               PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
-               fr->length = (hw_w*hw_h*hw_d)/8;
-               _PSWAP(pIn, pOut)
-               if (err) {
-                       DBG(4, "An error occurred while decoding the frame: "
-                              "%s", symbolic(decoder_errlist, err))
-                       return err;
-               } else
-                       DBG(6, "Frame decoded")
-       }
-
-       if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
-               w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
-               DBG(6, "Original UYVY component ordering changed")
-       }
-
-       if (cam->vpp_flag & VPP_UPSCALE) {
-               w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
-               fr->length = (w*h*hw_d)/8;
-               _PSWAP(pIn, pOut)
-               DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
-                   hw_w, hw_h, hw_d, w, h)
-       }
-
-       if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
-               w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
-               fr->length = (w*h*d)/8;
-               _PSWAP(pIn, pOut)
-               DBG(6, "UYVY-16bit to %s conversion done", 
-                   symbolic(v4l1_plist, fmt))
-       }
-
-       if (pOut == fr->buffer)
-               memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
-
-       return 0;
-}
-
-
-
-/****************************************************************************
- * Image sensor control routines                                            *
- ****************************************************************************/
-
-static int 
-w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
-{
-       struct ovcamchip_control ctl;
-       int err;
-
-       ctl.id = cid;
-       ctl.value = val;
-
-       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
-
-       return err;
-}
-
-
-static int 
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
-{
-       struct ovcamchip_control ctl;
-       int err;
-
-       ctl.id = cid;
-
-       err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
-       if (!err)
-               *val = ctl.value;
-
-       return err;
-}
-
-
-static int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
-{
-       struct i2c_client* c = cam->sensor_client;
-       int rc = 0;
-
-       if (!c || !c->driver || !c->driver->command)
-               return -EINVAL;
-
-       rc = c->driver->command(c, cmd, arg);
-       /* The I2C driver returns -EPERM on non-supported controls */
-       return (rc < 0 && rc != -EPERM) ? rc : 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update some settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       /* Auto brightness */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT, 
-                                        cam->auto_brt);
-       if (err)
-               return err;
-
-       /* Auto exposure */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP, 
-                                        cam->auto_exp);
-       if (err)
-               return err;
-
-       /* Banding filter */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT, 
-                                        cam->bandfilt);
-       if (err)
-               return err;
-
-       /* Light frequency */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
-                                        cam->lightfreq);
-       if (err)
-               return err;
-
-       /* Back light */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
-                                        cam->backlight);
-       if (err)
-               return err;
-
-       /* Mirror */
-       err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
-                                        cam->mirror);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Get some current picture settings from the image sensor and update the
-  internal 'picture' structure of the camera.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
-{
-       int err, v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
-       if (err)
-               return err;
-       cam->picture.contrast = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
-       if (err)
-               return err;
-       cam->picture.brightness = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
-       if (err)
-               return err;
-       cam->picture.colour = v;
-
-       err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
-       if (err)
-               return err;
-       cam->picture.hue = v;
-
-       DBG(5, "Got picture settings from the image sensor")
-
-       PDBGG("Brightness, contrast, hue, colour, whiteness are "
-             "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
-             cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
-
-       return 0;
-}
-
-
-/*--------------------------------------------------------------------------
-  Update picture settings of the image sensor.
-  Returns: 0 on success, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_update_picture(struct w9968cf_device* cam, 
-                              struct video_picture pict)
-{
-       int err = 0;
-
-       if ((!cam->sensor_initialized)
-           || pict.contrast != cam->picture.contrast) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
-                                                pict.contrast);
-               if (err)
-                       goto fail;
-               DBG(4, "Contrast changed from %u to %u",
-                   cam->picture.contrast, pict.contrast)
-               cam->picture.contrast = pict.contrast;
-       }
-
-       if (((!cam->sensor_initialized) || 
-           pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT, 
-                                                pict.brightness);
-               if (err)
-                       goto fail;
-               DBG(4, "Brightness changed from %u to %u",
-                   cam->picture.brightness, pict.brightness)
-               cam->picture.brightness = pict.brightness;
-       }
-
-       if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT, 
-                                                pict.colour);
-               if (err)
-                       goto fail;
-               DBG(4, "Colour changed from %u to %u",
-                   cam->picture.colour, pict.colour)
-               cam->picture.colour = pict.colour;
-       }
-
-       if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
-               err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE, 
-                                                pict.hue);
-               if (err)
-                       goto fail;
-               DBG(4, "Hue changed from %u to %u",
-                   cam->picture.hue, pict.hue)
-               cam->picture.hue = pict.hue;
-       }
-
-       return 0;
-
-fail:
-       DBG(4, "Failed to change sensor picture setting")
-       return err;
-}
-
-
-
-/****************************************************************************
- * Camera configuration                                                     *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
-  This function is called when a supported image sensor is detected.
-  Return 0 if the initialization succeeds, a negative number otherwise.
-  --------------------------------------------------------------------------*/
-static int w9968cf_sensor_init(struct w9968cf_device* cam)
-{
-       int err = 0;
-
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE, 
-                                     &cam->monochrome)))
-               goto error;
-
-       if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE, 
-                                     &cam->sensor)))
-               goto error;
-
-       /* NOTE: Make sure width and height are a multiple of 16 */
-       switch (cam->sensor_client->addr) {
-               case OV6xx0_SID:
-                       cam->maxwidth = 352;
-                       cam->maxheight = 288;
-                       cam->minwidth = 64;
-                       cam->minheight = 48;
-                       break;
-               case OV7xx0_SID:
-                       cam->maxwidth = 640;
-                       cam->maxheight = 480;
-                       cam->minwidth = 64;
-                       cam->minheight = 48;
-                       break;
-               default:
-                       DBG(1, "Not supported image sensor detected for %s",
-                           symbolic(camlist, cam->id))
-                       return -EINVAL;
-       }
-
-       /* These values depend on the ones in the ovxxx0.c sources */
-       switch (cam->sensor) {
-               case CC_OV7620:
-                       cam->start_cropx = 287;
-                       cam->start_cropy = 35;
-                       /* Seems to work around a bug in the image sensor */
-                       cam->vs_polarity = 1;
-                       cam->hs_polarity = 1;
-                       break;
-               default:
-                       cam->start_cropx = 320;
-                       cam->start_cropy = 35;
-                       cam->vs_polarity = 1;
-                       cam->hs_polarity = 0;
-       }
-
-       if ((err = w9968cf_sensor_update_settings(cam)))
-               goto error;
-
-       if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
-               goto error;
-
-       cam->sensor_initialized = 1;
-
-       DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
-       return 0;
-
-error:
-       cam->sensor_initialized = 0;
-       cam->sensor = CC_UNKNOWN;
-       DBG(1, "Image sensor initialization failed for %s (/dev/video%d). "
-              "Try to detach and attach this device again",
-           symbolic(camlist, cam->id), cam->v4ldev->minor)
-       return err;
-}
-
-
-/*--------------------------------------------------------------------------
-  Fill some basic fields in the main device data structure.
-  This function is called once on w9968cf_usb_probe() for each recognized 
-  camera.
-  --------------------------------------------------------------------------*/
-static void
-w9968cf_configure_camera(struct w9968cf_device* cam,
-                         struct usb_device* udev,
-                         enum w9968cf_model_id mod_id,
-                         const unsigned short dev_nr)
-{
-       mutex_init(&cam->fileop_mutex);
-       init_waitqueue_head(&cam->open);
-       spin_lock_init(&cam->urb_lock);
-       spin_lock_init(&cam->flist_lock);
-
-       cam->users = 0;
-       cam->disconnected = 0;
-       cam->id = mod_id;
-       cam->sensor = CC_UNKNOWN;
-       cam->sensor_initialized = 0;
-
-       /* Calculate the alternate setting number (from 1 to 16)
-          according to the 'packet_size' module parameter */
-       if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
-               packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
-       for (cam->altsetting = 1;
-            packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
-            cam->altsetting++);
-
-       cam->max_buffers = (max_buffers[dev_nr] < 2 || 
-                           max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
-                          ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
-
-       cam->double_buffer = (double_buffer[dev_nr] == 0 || 
-                             double_buffer[dev_nr] == 1)
-                            ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
-
-       cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
-                       ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
-       
-       cam->filter_type = (filter_type[dev_nr] == 0 ||
-                           filter_type[dev_nr] == 1 ||
-                           filter_type[dev_nr] == 2)
-                          ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
-
-       cam->capture = 1;
-
-       cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
-                        ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
-
-       cam->decompression = (decompression[dev_nr] == 0 || 
-                             decompression[dev_nr] == 1 ||
-                             decompression[dev_nr] == 2)
-                            ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
-
-       cam->upscaling = (upscaling[dev_nr] == 0 || 
-                         upscaling[dev_nr] == 1)
-                        ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
-
-       cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
-                       ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
-
-       cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
-                       ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
-
-       cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
-                        ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
-
-       cam->bandfilt = (bandingfilter[dev_nr] == 0 || 
-                        bandingfilter[dev_nr] == 1)
-                       ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
-
-       cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
-                        ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
-
-       cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
-                       ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
-
-       cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
-                     ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
-
-       cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
-                         ? monochrome[dev_nr] : W9968CF_MONOCHROME;
-
-       cam->picture.brightness = (u16)brightness[dev_nr];
-       cam->picture.hue = (u16)hue[dev_nr];
-       cam->picture.colour = (u16)colour[dev_nr];
-       cam->picture.contrast = (u16)contrast[dev_nr];
-       cam->picture.whiteness = (u16)whiteness[dev_nr];
-       if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
-               cam->picture.palette = (u16)force_palette[dev_nr];
-               cam->force_palette = 1;
-       } else {
-               cam->force_palette = 0;
-               if (cam->decompression == 0)
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
-               else if (cam->decompression == 1)
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
-               else
-                       cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
-       }
-       cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-
-       cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
-                        ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
-
-       cam->window.x = 0;
-       cam->window.y = 0;
-       cam->window.width = W9968CF_WIDTH;
-       cam->window.height = W9968CF_HEIGHT;
-       cam->window.chromakey = 0;
-       cam->window.clipcount = 0;
-       cam->window.flags = 0;
-
-       DBG(3, "%s configured with settings #%u:",
-           symbolic(camlist, cam->id), dev_nr)
-       
-       DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
-           wMaxPacketSize[cam->altsetting-1])
-       
-       DBG(3, "- Number of requested video frame buffers: %u",
-           cam->max_buffers)
-
-       if (cam->double_buffer)
-               DBG(3, "- Hardware double buffering enabled")
-       else 
-               DBG(3, "- Hardware double buffering disabled")
-
-       if (cam->filter_type == 0)
-               DBG(3, "- Video filtering disabled")
-       else if (cam->filter_type == 1)
-               DBG(3, "- Video filtering enabled: type 1-2-1")
-       else if (cam->filter_type == 2)
-               DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
-
-       if (cam->clamping)
-               DBG(3, "- Video data clamping (CCIR-601 format) enabled")
-       else
-               DBG(3, "- Video data clamping (CCIR-601 format) disabled")
-
-       if (cam->largeview)
-               DBG(3, "- Large view enabled")
-       else
-               DBG(3, "- Large view disabled")
-
-       if ((cam->decompression) == 0 && (!cam->force_palette))
-               DBG(3, "- Decompression disabled")
-       else if ((cam->decompression) == 1 && (!cam->force_palette))
-               DBG(3, "- Decompression forced")
-       else if ((cam->decompression) == 2 && (!cam->force_palette))
-               DBG(3, "- Decompression allowed")
-
-       if (cam->upscaling)
-               DBG(3, "- Software image scaling enabled")
-       else
-               DBG(3, "- Software image scaling disabled")
-
-       if (cam->force_palette)
-               DBG(3, "- Image palette forced to %s",
-                   symbolic(v4l1_plist, cam->picture.palette))
-
-       if (cam->force_rgb)
-               DBG(3, "- RGB component ordering will be used instead of BGR")
-
-       if (cam->auto_brt)
-               DBG(3, "- Auto brightness enabled")
-       else
-               DBG(3, "- Auto brightness disabled")
-
-       if (cam->auto_exp)
-               DBG(3, "- Auto exposure enabled")
-       else
-               DBG(3, "- Auto exposure disabled")
-
-       if (cam->backlight)
-               DBG(3, "- Backlight exposure algorithm enabled")
-       else
-               DBG(3, "- Backlight exposure algorithm disabled")
-
-       if (cam->mirror)
-               DBG(3, "- Mirror enabled")
-       else
-               DBG(3, "- Mirror disabled")
-
-       if (cam->bandfilt)
-               DBG(3, "- Banding filter enabled")
-       else
-               DBG(3, "- Banding filter disabled")
-
-       DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
-
-       if (cam->clockdiv == -1)
-               DBG(3, "- Automatic clock divisor enabled")
-       else
-               DBG(3, "- Clock divisor: %d", cam->clockdiv)
-
-       if (cam->monochrome)
-               DBG(3, "- Image sensor used as monochrome")
-       else
-               DBG(3, "- Image sensor not used as monochrome")
-}
-
-
-/*--------------------------------------------------------------------------
-  If the video post-processing module is not loaded, some parameters
-  must be overridden.
-  --------------------------------------------------------------------------*/
-static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
-{
-       if (!w9968cf_vpp) {
-               if (cam->decompression == 1) {
-                       cam->decompression = 2;
-                       DBG(2, "Video post-processing module not found: "
-                              "'decompression' parameter forced to 2")
-               }
-               if (cam->upscaling) {
-                       cam->upscaling = 0;
-                       DBG(2, "Video post-processing module not found: "
-                              "'upscaling' parameter forced to 0")
-               }
-               if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
-                       cam->force_palette = 0;
-                       DBG(2, "Video post-processing module not found: "
-                              "'force_palette' parameter forced to 0")
-               }
-               cam->picture.palette = VIDEO_PALETTE_UYVY;
-               cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-       }
-}
-
-
-/*--------------------------------------------------------------------------
-  Release the resources used by the driver.
-  This function is called on disconnect 
-  (or on close if deallocation has been deferred)
-  --------------------------------------------------------------------------*/
-static void w9968cf_release_resources(struct w9968cf_device* cam)
-{
-       mutex_lock(&w9968cf_devlist_mutex);
-
-       DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor)
-
-       video_unregister_device(cam->v4ldev);
-       list_del(&cam->v4llist);
-       i2c_del_adapter(&cam->i2c_adapter);
-       w9968cf_deallocate_memory(cam);
-       kfree(cam->control_buffer);
-       kfree(cam->data_buffer);
-
-       mutex_unlock(&w9968cf_devlist_mutex);
-}
-
-
-
-/****************************************************************************
- * Video4Linux interface                                                    *
- ****************************************************************************/
-
-static int w9968cf_open(struct inode* inode, struct file* filp)
-{
-       struct w9968cf_device* cam;
-       int err;
-
-       /* This the only safe way to prevent race conditions with disconnect */
-       if (!down_read_trylock(&w9968cf_disconnect))
-               return -ERESTARTSYS;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex);
-
-       if (cam->sensor == CC_UNKNOWN) {
-               DBG(2, "No supported image sensor has been detected by the "
-                      "'ovcamchip' module for the %s (/dev/video%d). Make "
-                      "sure it is loaded *before* (re)connecting the camera.",
-                   symbolic(camlist, cam->id), cam->v4ldev->minor)
-               mutex_unlock(&cam->dev_mutex);
-               up_read(&w9968cf_disconnect);
-               return -ENODEV;
-       }
-
-       if (cam->users) {
-               DBG(2, "%s (/dev/video%d) has been already occupied by '%s'",
-                   symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command)
-               if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
-                       mutex_unlock(&cam->dev_mutex);
-                       up_read(&w9968cf_disconnect);
-                       return -EWOULDBLOCK;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                        cam->disconnected ||
-                                                        !cam->users);
-               if (err) {
-                       up_read(&w9968cf_disconnect);
-                       return err;
-               }
-               if (cam->disconnected) {
-                       up_read(&w9968cf_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-       DBG(5, "Opening '%s', /dev/video%d ...",
-           symbolic(camlist, cam->id), cam->v4ldev->minor)
-
-       cam->streaming = 0;
-       cam->misconfigured = 0;
-
-       w9968cf_adjust_configuration(cam);
-
-       if ((err = w9968cf_allocate_memory(cam)))
-               goto deallocate_memory;
-
-       if ((err = w9968cf_init_chip(cam)))
-               goto deallocate_memory;
-
-       if ((err = w9968cf_start_transfer(cam)))
-               goto deallocate_memory;
-
-       filp->private_data = cam;
-
-       cam->users++;
-       strcpy(cam->command, current->comm);
-
-       init_waitqueue_head(&cam->wait_queue);
-
-       DBG(5, "Video device is open")
-
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&w9968cf_disconnect);
-
-       return 0;
-
-deallocate_memory:
-       w9968cf_deallocate_memory(cam);
-       DBG(2, "Failed to open the video device")
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&w9968cf_disconnect);
-       return err;
-}
-
-
-static int w9968cf_release(struct inode* inode, struct file* filp)
-{
-       struct w9968cf_device* cam;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       w9968cf_stop_transfer(cam);
-
-       if (cam->disconnected) {
-               w9968cf_release_resources(cam);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       w9968cf_deallocate_memory(cam);
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(5, "Video device closed")
-       mutex_unlock(&cam->dev_mutex);
-       return 0;
-}
-
-
-static ssize_t
-w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct w9968cf_device* cam;
-       struct w9968cf_frame_t* fr;
-       int err = 0;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       if (filp->f_flags & O_NONBLOCK)
-               return -EWOULDBLOCK;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again.")
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (!cam->frame[0].queued)
-               w9968cf_push_frame(cam, 0);
-
-       if (!cam->frame[1].queued)
-               w9968cf_push_frame(cam, 1);
-
-       err = wait_event_interruptible(cam->wait_queue,
-                                      cam->frame[0].status == F_READY ||
-                                      cam->frame[1].status == F_READY ||
-                                      cam->disconnected);
-       if (err) {
-               mutex_unlock(&cam->fileop_mutex);
-               return err;
-       }
-       if (cam->disconnected) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
-
-       if (w9968cf_vpp)
-               w9968cf_postprocess_frame(cam, fr);
-
-       if (count > fr->length)
-               count = fr->length;
-
-       if (copy_to_user(buf, fr->buffer, count)) {
-               fr->status = F_UNUSED;
-               mutex_unlock(&cam->fileop_mutex);
-               return -EFAULT;
-       }
-       *f_pos += count;
-
-       fr->status = F_UNUSED;
-
-       DBG(5, "%zu bytes read", count)
-
-       mutex_unlock(&cam->fileop_mutex);
-       return count;
-}
-
-
-static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct w9968cf_device* cam = (struct w9968cf_device*)
-                                    video_get_drvdata(video_devdata(filp));
-       unsigned long vsize = vma->vm_end - vma->vm_start,
-                     psize = cam->nbuffers * cam->frame[0].size,
-                     start = vma->vm_start,
-                     pos = (unsigned long)cam->frame[0].buffer,
-                     page;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again")
-               return -EIO;
-       }
-
-       PDBGG("mmapping %lu bytes...", vsize)
-
-       if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
-               return -EINVAL;
-
-       while (vsize > 0) {
-               page = vmalloc_to_pfn((void *)pos);
-               if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
-                                               PAGE_SIZE, vma->vm_page_prot))
-                       return -EAGAIN;
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               vsize -= PAGE_SIZE;
-       }
-
-       DBG(5, "mmap method successfully called")
-       return 0;
-}
-
-
-static int
-w9968cf_ioctl(struct inode* inode, struct file* filp,
-              unsigned int cmd, unsigned long arg)
-{
-       struct w9968cf_device* cam;
-       int err;
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->disconnected) {
-               DBG(2, "Device not present")
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->misconfigured) {
-               DBG(2, "The camera is misconfigured. Close and open it again.")
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-       return err;
-}
-
-
-static int w9968cf_v4l_ioctl(struct inode* inode, struct file* filp,
-                             unsigned int cmd, void __user * arg)
-{
-       struct w9968cf_device* cam;
-       const char* v4l1_ioctls[] = {
-               "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", 
-               "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
-               "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
-               "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
-               "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", 
-               "GVBIFMT", "SVBIFMT" 
-       };
-
-       #define V4L1_IOCTL(cmd) \
-               ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
-               v4l1_ioctls[_IOC_NR((cmd))] : "?")
-
-       cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOCGCAP: /* get video capability */
-       {
-               struct video_capability cap = {
-                       .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
-                       .channels = 1,
-                       .audios = 0,
-                       .minwidth = cam->minwidth,
-                       .minheight = cam->minheight,
-               };
-               sprintf(cap.name, "W996[87]CF USB Camera #%d", 
-                       cam->v4ldev->minor);
-               cap.maxwidth = (cam->upscaling && w9968cf_vpp)
-                              ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) 
-                                : cam->maxwidth;
-               cap.maxheight = (cam->upscaling && w9968cf_vpp)
-                               ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
-                                 : cam->maxheight;
-
-               if (copy_to_user(arg, &cap, sizeof(cap)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGCAP successfully called")
-               return 0;
-       }
-
-       case VIDIOCGCHAN: /* get video channel informations */
-       {
-               struct video_channel chan;
-               if (copy_from_user(&chan, arg, sizeof(chan)))
-                       return -EFAULT;
-
-               if (chan.channel != 0)
-                       return -EINVAL;
-
-               strcpy(chan.name, "Camera");
-               chan.tuners = 0;
-               chan.flags = 0;
-               chan.type = VIDEO_TYPE_CAMERA;
-               chan.norm = VIDEO_MODE_AUTO;
-
-               if (copy_to_user(arg, &chan, sizeof(chan)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGCHAN successfully called")
-               return 0;
-       }
-
-       case VIDIOCSCHAN: /* set active channel */
-       {
-               struct video_channel chan;
-
-               if (copy_from_user(&chan, arg, sizeof(chan)))
-                       return -EFAULT;
-
-               if (chan.channel != 0)
-                       return -EINVAL;
-
-               DBG(5, "VIDIOCSCHAN successfully called")
-               return 0;
-       }
-
-       case VIDIOCGPICT: /* get image properties of the picture */
-       {
-               if (w9968cf_sensor_get_picture(cam))
-                       return -EIO;
-
-               if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGPICT successfully called")
-               return 0;
-       }
-
-       case VIDIOCSPICT: /* change picture settings */
-       {
-               struct video_picture pict;
-               int err = 0;
-
-               if (copy_from_user(&pict, arg, sizeof(pict)))
-                       return -EFAULT;
-
-               if ( (cam->force_palette || !w9968cf_vpp) 
-                    && pict.palette != cam->picture.palette ) {
-                       DBG(4, "Palette %s rejected: only %s is allowed",
-                           symbolic(v4l1_plist, pict.palette),
-                           symbolic(v4l1_plist, cam->picture.palette))
-                       return -EINVAL;
-               }
-
-               if (!w9968cf_valid_palette(pict.palette)) {
-                       DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
-                           symbolic(v4l1_plist, pict.palette))
-                       return -EINVAL;
-               }
-
-               if (!cam->force_palette) {
-                  if (cam->decompression == 0) {
-                     if (w9968cf_need_decompression(pict.palette)) {
-                        DBG(4, "Decompression disabled: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, pict.palette))
-                        return -EINVAL;
-                     }
-                  } else if (cam->decompression == 1) {
-                     if (!w9968cf_need_decompression(pict.palette)) {
-                        DBG(4, "Decompression forced: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, pict.palette))
-                        return -EINVAL;
-                     }
-                  }
-               }
-
-               if (pict.depth != w9968cf_valid_depth(pict.palette)) {
-                       DBG(4, "Requested depth %u bpp is not valid for %s "
-                              "palette: ignored and changed to %u bpp", 
-                           pict.depth, symbolic(v4l1_plist, pict.palette),
-                           w9968cf_valid_depth(pict.palette))
-                       pict.depth = w9968cf_valid_depth(pict.palette);
-               }
-
-               if (pict.palette != cam->picture.palette) {
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_picture(cam, pict))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-
-               } else if (w9968cf_sensor_update_picture(cam, pict))
-                       return -EIO;
-
-
-               DBG(5, "VIDIOCSPICT successfully called")
-               return 0;
-       }
-
-       case VIDIOCSWIN: /* set capture area */
-       {
-               struct video_window win;
-               int err = 0;
-
-               if (copy_from_user(&win, arg, sizeof(win)))
-                       return -EFAULT;
-
-               DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
-                      "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
-                   win.x, win.y, win.width, win.height)
-
-               if (win.clipcount != 0 || win.flags != 0)
-                       return -EINVAL;
-
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&win.width,
-                                                     (u16*)&win.height))) {
-                       DBG(4, "Resolution not supported (%ux%u). "
-                              "VIDIOCSWIN failed", win.width, win.height)
-                       return err;
-               }
-
-               if (win.x != cam->window.x ||
-                   win.y != cam->window.y ||
-                   win.width != cam->window.width ||
-                   win.height != cam->window.height) {
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       /* This _must_ be called before set_window() */
-                       if (w9968cf_set_picture(cam, cam->picture))
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_window(cam, win))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-               }
-
-               DBG(5, "VIDIOCSWIN successfully called. ")
-               return 0;
-       }
-
-       case VIDIOCGWIN: /* get current window properties */
-       {
-               if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGWIN successfully called")
-               return 0;
-       }
-
-       case VIDIOCGMBUF: /* request for memory (mapped) buffer */
-       {
-               struct video_mbuf mbuf;
-               u8 i;
-
-               mbuf.size = cam->nbuffers * cam->frame[0].size;
-               mbuf.frames = cam->nbuffers;
-               for (i = 0; i < cam->nbuffers; i++)
-                       mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
-                                         (unsigned long)cam->frame[0].buffer;
-
-               if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGMBUF successfully called")
-               return 0;
-       }
-
-       case VIDIOCMCAPTURE: /* start the capture to a frame */
-       {
-               struct video_mmap mmap;
-               struct w9968cf_frame_t* fr;
-               int err = 0;
-
-               if (copy_from_user(&mmap, arg, sizeof(mmap)))
-                       return -EFAULT;
-
-               DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
-                   mmap.frame, symbolic(v4l1_plist, mmap.format), 
-                   mmap.width, mmap.height)
-
-               if (mmap.frame >= cam->nbuffers) {
-                       DBG(4, "Invalid frame number (%u). "
-                              "VIDIOCMCAPTURE failed", mmap.frame)
-                       return -EINVAL;
-               }
-
-               if (mmap.format!=cam->picture.palette && 
-                   (cam->force_palette || !w9968cf_vpp)) {
-                       DBG(4, "Palette %s rejected: only %s is allowed",
-                           symbolic(v4l1_plist, mmap.format),
-                           symbolic(v4l1_plist, cam->picture.palette))
-                       return -EINVAL;
-               }
-
-               if (!w9968cf_valid_palette(mmap.format)) {
-                       DBG(4, "Palette %s not supported. "
-                              "VIDIOCMCAPTURE failed", 
-                           symbolic(v4l1_plist, mmap.format))
-                       return -EINVAL;
-               }
-
-               if (!cam->force_palette) {
-                  if (cam->decompression == 0) {
-                     if (w9968cf_need_decompression(mmap.format)) {
-                        DBG(4, "Decompression disabled: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, mmap.format))
-                        return -EINVAL;
-                     }
-                  } else if (cam->decompression == 1) {
-                     if (!w9968cf_need_decompression(mmap.format)) {
-                        DBG(4, "Decompression forced: palette %s is not "
-                               "allowed. VIDIOCSPICT failed",
-                            symbolic(v4l1_plist, mmap.format))
-                        return -EINVAL;
-                     }
-                  }
-               }
-
-               if ((err = w9968cf_adjust_window_size(cam, (u16*)&mmap.width, 
-                                                     (u16*)&mmap.height))) {
-                       DBG(4, "Resolution not supported (%dx%d). "
-                              "VIDIOCMCAPTURE failed",
-                           mmap.width, mmap.height)
-                       return err;
-               }
-
-               fr = &cam->frame[mmap.frame];
-
-               if (mmap.width  != cam->window.width ||
-                   mmap.height != cam->window.height ||
-                   mmap.format != cam->picture.palette) {
-
-                       struct video_window win;
-                       struct video_picture pict;
-
-                       if(*cam->requested_frame
-                          || cam->frame_current->queued) {
-                               DBG(6, "VIDIOCMCAPTURE. Change settings for "
-                                      "frame #%u: %dx%d, format %s. Wait...",
-                                   mmap.frame, mmap.width, mmap.height,
-                                   symbolic(v4l1_plist, mmap.format))
-                               err = wait_event_interruptible
-                                     ( cam->wait_queue,
-                                       cam->disconnected ||
-                                       (!*cam->requested_frame &&
-                                        !cam->frame_current->queued) );
-                               if (err)
-                                       return err;
-                               if (cam->disconnected)
-                                       return -ENODEV;
-                       }
-
-                       memcpy(&win, &cam->window, sizeof(win));
-                       memcpy(&pict, &cam->picture, sizeof(pict));
-                       win.width = mmap.width;
-                       win.height = mmap.height;
-                       pict.palette = mmap.format;
-
-                       if (w9968cf_stop_transfer(cam))
-                               goto ioctl_fail;
-
-                       /* This before set_window */
-                       if (w9968cf_set_picture(cam, pict)) 
-                               goto ioctl_fail;
-
-                       if (w9968cf_set_window(cam, win))
-                               goto ioctl_fail;
-
-                       if (w9968cf_start_transfer(cam))
-                               goto ioctl_fail;
-
-               } else  if (fr->queued) {
-
-                       DBG(6, "Wait until frame #%u is free", mmap.frame)
-                       
-                       err = wait_event_interruptible(cam->wait_queue, 
-                                                      cam->disconnected ||
-                                                      (!fr->queued));
-                       if (err)
-                               return err;
-                       if (cam->disconnected)
-                               return -ENODEV;
-               }
-
-               w9968cf_push_frame(cam, mmap.frame);
-               DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
-               return 0;
-       }
-
-       case VIDIOCSYNC: /* wait until the capture of a frame is finished */
-       {
-               unsigned int f_num;
-               struct w9968cf_frame_t* fr;
-               int err = 0;
-
-               if (copy_from_user(&f_num, arg, sizeof(f_num)))
-                       return -EFAULT;
-
-               if (f_num >= cam->nbuffers) {
-                       DBG(4, "Invalid frame number (%u). "
-                              "VIDIOCMCAPTURE failed", f_num)
-                       return -EINVAL;
-               }
-
-               DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
-
-               fr = &cam->frame[f_num];
-
-               switch (fr->status) {
-               case F_UNUSED:
-                       if (!fr->queued) {
-                               DBG(4, "VIDIOSYNC: Frame #%u not requested!",
-                                   f_num)
-                               return -EFAULT;
-                       }
-               case F_ERROR:
-               case F_GRABBING:
-                       err = wait_event_interruptible(cam->wait_queue, 
-                                                      (fr->status == F_READY)
-                                                      || cam->disconnected);
-                       if (err)
-                               return err;
-                       if (cam->disconnected)
-                               return -ENODEV;
-                       break;
-               case F_READY:
-                       break;
-               }
-
-               if (w9968cf_vpp)
-                       w9968cf_postprocess_frame(cam, fr);
-
-               fr->status = F_UNUSED;
-
-               DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
-               return 0;
-       }
-
-       case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
-       {
-               struct video_unit unit = {
-                       .video = cam->v4ldev->minor,
-                       .vbi = VIDEO_NO_UNIT,
-                       .radio = VIDEO_NO_UNIT,
-                       .audio = VIDEO_NO_UNIT,
-                       .teletext = VIDEO_NO_UNIT,
-               };
-
-               if (copy_to_user(arg, &unit, sizeof(unit)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGUNIT successfully called")
-               return 0;
-       }
-
-       case VIDIOCKEY:
-               return 0;
-
-       case VIDIOCGFBUF:
-       {
-               if (clear_user(arg, sizeof(struct video_buffer)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGFBUF successfully called")
-               return 0;
-       }
-
-       case VIDIOCGTUNER:
-       {
-               struct video_tuner tuner;
-               if (copy_from_user(&tuner, arg, sizeof(tuner)))
-                       return -EFAULT;
-
-               if (tuner.tuner != 0)
-                       return -EINVAL;
-
-               strcpy(tuner.name, "no_tuner");
-               tuner.rangelow = 0;
-               tuner.rangehigh = 0;
-               tuner.flags = VIDEO_TUNER_NORM;
-               tuner.mode = VIDEO_MODE_AUTO;
-               tuner.signal = 0xffff;
-
-               if (copy_to_user(arg, &tuner, sizeof(tuner)))
-                       return -EFAULT;
-
-               DBG(5, "VIDIOCGTUNER successfully called")
-               return 0;
-       }
-
-       case VIDIOCSTUNER:
-       {
-               struct video_tuner tuner;
-               if (copy_from_user(&tuner, arg, sizeof(tuner)))
-                       return -EFAULT;
-
-               if (tuner.tuner != 0)
-                       return -EINVAL;
-
-               if (tuner.mode != VIDEO_MODE_AUTO)
-                       return -EINVAL;
-
-               DBG(5, "VIDIOCSTUNER successfully called")
-               return 0;
-       }
-
-       case VIDIOCSFBUF:
-       case VIDIOCCAPTURE:
-       case VIDIOCGFREQ:
-       case VIDIOCSFREQ:
-       case VIDIOCGAUDIO:
-       case VIDIOCSAUDIO:
-       case VIDIOCSPLAYMODE:
-       case VIDIOCSWRITEMODE:
-       case VIDIOCGPLAYINFO:
-       case VIDIOCSMICROCODE:
-       case VIDIOCGVBIFMT:
-       case VIDIOCSVBIFMT:
-               DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
-                      "(type 0x%01X, "
-                      "n. 0x%01X, "
-                      "dir. 0x%01X, " 
-                      "size 0x%02X)",
-                   V4L1_IOCTL(cmd),
-                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-               return -EINVAL;
-
-       default:
-               DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
-                      "type 0x%01X, "
-                      "n. 0x%01X, "
-                      "dir. 0x%01X, "
-                      "size 0x%02X",
-                   V4L1_IOCTL(cmd),
-                   _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
-               return -ENOIOCTLCMD;
-
-       } /* end of switch */
-
-ioctl_fail:
-       cam->misconfigured = 1;
-       DBG(1, "VIDIOC%s failed because of hardware problems. "
-              "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
-       return -EFAULT;
-}
-
-
-static struct file_operations w9968cf_fops = {
-       .owner =   THIS_MODULE,
-       .open =    w9968cf_open,
-       .release = w9968cf_release,
-       .read =    w9968cf_read,
-       .ioctl =   w9968cf_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
-       .mmap =    w9968cf_mmap,
-       .llseek =  no_llseek,
-};
-
-
-
-/****************************************************************************
- * USB probe and V4L registration, disconnect and id_table[] definition     *
- ****************************************************************************/
-
-static int
-w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct w9968cf_device* cam;
-       int err = 0;
-       enum w9968cf_model_id mod_id;
-       struct list_head* ptr;
-       u8 sc = 0; /* number of simultaneous cameras */
-       static unsigned short dev_nr = 0; /* we are handling device number n */
-
-       if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[0].idVendor &&
-           le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
-               mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
-       else if (le16_to_cpu(udev->descriptor.idVendor)  == winbond_id_table[1].idVendor &&
-                le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
-               mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
-       else
-               return -ENODEV;
-
-       cam = (struct w9968cf_device*)
-                 kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
-       if (!cam)
-               return -ENOMEM;
-
-       mutex_init(&cam->dev_mutex);
-       mutex_lock(&cam->dev_mutex);
-
-       cam->usbdev = udev;
-       /* NOTE: a local copy is used to avoid possible race conditions */
-       memcpy(&cam->dev, &udev->dev, sizeof(struct device));
-
-       DBG(2, "%s detected", symbolic(camlist, mod_id))
-
-       if (simcams > W9968CF_MAX_DEVICES)
-               simcams = W9968CF_SIMCAMS;
-
-       /* How many cameras are connected ? */
-       mutex_lock(&w9968cf_devlist_mutex);
-       list_for_each(ptr, &w9968cf_dev_list)
-               sc++;
-       mutex_unlock(&w9968cf_devlist_mutex);
-
-       if (sc >= simcams) {
-               DBG(2, "Device rejected: too many connected cameras "
-                      "(max. %u)", simcams)
-               err = -EPERM;
-               goto fail;
-       }
-
-
-       /* Allocate 2 bytes of memory for camera control USB transfers */
-       if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
-               DBG(1,"Couldn't allocate memory for camera control transfers")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Allocate 8 bytes of memory for USB data transfers to the FSB */
-       if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
-               DBG(1, "Couldn't allocate memory for data "
-                      "transfers to the FSB")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Register the V4L device */
-       cam->v4ldev = video_device_alloc();
-       if (!cam->v4ldev) {
-               DBG(1, "Could not allocate memory for a V4L structure")
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
-       cam->v4ldev->fops = &w9968cf_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-       cam->v4ldev->dev = &cam->dev;
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L device registration failed")
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(2, "Couldn't find a free /dev/videoX node")
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               goto fail;
-       }
-
-       DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->minor)
-
-       /* Set some basic constants */
-       w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
-
-       /* Add a new entry into the list of V4L registered devices */
-       mutex_lock(&w9968cf_devlist_mutex);
-       list_add(&cam->v4llist, &w9968cf_dev_list);
-       mutex_unlock(&w9968cf_devlist_mutex);
-       dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-       w9968cf_turn_on_led(cam);
-
-       w9968cf_i2c_init(cam);
-
-       usb_set_intfdata(intf, cam);
-       mutex_unlock(&cam->dev_mutex);
-       return 0;
-
-fail: /* Free unused memory */
-       kfree(cam->control_buffer);
-       kfree(cam->data_buffer);
-       if (cam->v4ldev)
-               video_device_release(cam->v4ldev);
-       mutex_unlock(&cam->dev_mutex);
-       kfree(cam);
-       return err;
-}
-
-
-static void w9968cf_usb_disconnect(struct usb_interface* intf)
-{
-       struct w9968cf_device* cam = 
-          (struct w9968cf_device*)usb_get_intfdata(intf);
-
-       down_write(&w9968cf_disconnect);
-
-       if (cam) {
-               /* Prevent concurrent accesses to data */
-               mutex_lock(&cam->dev_mutex);
-
-               cam->disconnected = 1;
-
-               DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id))
-
-               wake_up_interruptible_all(&cam->open);
-
-               if (cam->users) {
-                       DBG(2, "The device is open (/dev/video%d)! "
-                              "Process name: %s. Deregistration and memory "
-                              "deallocation are deferred on close.",
-                           cam->v4ldev->minor, cam->command)
-                       cam->misconfigured = 1;
-                       w9968cf_stop_transfer(cam);
-                       wake_up_interruptible(&cam->wait_queue);
-               } else
-                       w9968cf_release_resources(cam);
-
-               mutex_unlock(&cam->dev_mutex);
-
-               if (!cam->users)
-                       kfree(cam);
-       }
-
-       up_write(&w9968cf_disconnect);
-}
-
-
-static struct usb_driver w9968cf_usb_driver = {
-       .name =       "w9968cf",
-       .id_table =   winbond_id_table,
-       .probe =      w9968cf_usb_probe,
-       .disconnect = w9968cf_usb_disconnect,
-};
-
-
-
-/****************************************************************************
- * Module init, exit and intermodule communication                          *
- ****************************************************************************/
-
-static int __init w9968cf_module_init(void)
-{
-       int err;
-
-       KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
-       KDBG(3, W9968CF_MODULE_AUTHOR)
-
-       if (ovmod_load)
-               request_module("ovcamchip");
-
-       if ((err = usb_register(&w9968cf_usb_driver)))
-               return err;
-
-       return 0;
-}
-
-
-static void __exit w9968cf_module_exit(void)
-{
-       /* w9968cf_usb_disconnect() will be called */
-       usb_deregister(&w9968cf_usb_driver);
-
-       KDBG(2, W9968CF_MODULE_NAME" deregistered")
-}
-
-
-module_init(w9968cf_module_init);
-module_exit(w9968cf_module_exit);
-
diff --git a/drivers/usb/media/w9968cf.h b/drivers/usb/media/w9968cf.h
deleted file mode 100644 (file)
index a87be71..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip.       *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_H_
-#define _W9968CF_H_
-
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/config.h>
-#include <linux/param.h>
-#include <linux/types.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-
-#include <media/ovcamchip.h>
-
-#include "w9968cf_vpp.h"
-
-
-/****************************************************************************
- * Default values                                                           *
- ****************************************************************************/
-
-#define W9968CF_OVMOD_LOAD      1  /* automatic 'ovcamchip' module loading */
-#define W9968CF_VPPMOD_LOAD     1  /* automatic 'w9968cf-vpp' module loading */
-
-/* Comment/uncomment the following line to enable/disable debugging messages */
-#define W9968CF_DEBUG
-
-/* These have effect only if W9968CF_DEBUG is defined */
-#define W9968CF_DEBUG_LEVEL    2 /* from 0 to 6. 0 for no debug informations */
-#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
-
-#define W9968CF_MAX_DEVICES    32
-#define W9968CF_SIMCAMS        W9968CF_MAX_DEVICES /* simultaneous cameras */
-
-#define W9968CF_MAX_BUFFERS   32
-#define W9968CF_BUFFERS       2 /* n. of frame buffers from 2 to MAX_BUFFERS */
-
-/* Maximum data payload sizes in bytes for alternate settings */
-static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
-                                      511, 447, 383, 319, 255, 191, 127,  63};
-#define W9968CF_PACKET_SIZE      1023 /* according to wMaxPacketSizes[] */
-#define W9968CF_MIN_PACKET_SIZE  63 /* minimum value */
-#define W9968CF_ISO_PACKETS      5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
-#define W9968CF_URBS             2 /* n. of scheduled URBs for ISO transfer */
-
-#define W9968CF_I2C_BUS_DELAY    4 /* delay in us for I2C bit r/w operations */
-#define W9968CF_I2C_RW_RETRIES   15 /* number of max I2C r/w retries */
-
-/* Available video formats */
-struct w9968cf_format {
-       const u16 palette;
-       const u16 depth;
-       const u8 compression;
-};
-
-static const struct w9968cf_format w9968cf_formatlist[] = {
-       { VIDEO_PALETTE_UYVY,    16, 0 }, /* original video */
-       { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
-       { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
-       { VIDEO_PALETTE_YUV420,  12, 1 }, /* same as YUV420P */
-       { VIDEO_PALETTE_YUYV,    16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_YUV422,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_GREY,     8, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB555,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB565,  16, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB24,   24, 0 }, /* software conversion */
-       { VIDEO_PALETTE_RGB32,   32, 0 }, /* software conversion */
-       { 0,                      0, 0 }  /* 0 is a terminating entry */
-};
-
-#define W9968CF_DECOMPRESSION    2 /* decomp:0=disable,1=force,2=any formats */
-#define W9968CF_PALETTE_DECOMP_OFF   VIDEO_PALETTE_UYVY    /* when decomp=0 */
-#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
-#define W9968CF_PALETTE_DECOMP_ON    VIDEO_PALETTE_UYVY    /* when decomp=2 */
-
-#define W9968CF_FORCE_RGB        0  /* read RGB instead of BGR, yes=1/no=0 */
-
-#define W9968CF_MAX_WIDTH      800 /* Has effect if up-scaling is on */
-#define W9968CF_MAX_HEIGHT     600 /* Has effect if up-scaling is on */
-#define W9968CF_WIDTH          320 /* from 128 to 352, multiple of 16 */
-#define W9968CF_HEIGHT         240 /* from  96 to 288, multiple of 16 */
-
-#define W9968CF_CLAMPING       0 /* 0 disable, 1 enable video data clamping */
-#define W9968CF_FILTER_TYPE    0 /* 0 disable  1 (1-2-1), 2 (2-3-6-3-2) */
-#define W9968CF_DOUBLE_BUFFER  1 /* 0 disable, 1 enable double buffer */
-#define W9968CF_LARGEVIEW      1 /* 0 disable, 1 enable */
-#define W9968CF_UPSCALING      0 /* 0 disable, 1 enable */
-
-#define W9968CF_MONOCHROME     0 /* 0 not monochrome, 1 monochrome sensor */
-#define W9968CF_BRIGHTNESS     31000 /* from 0 to 65535 */
-#define W9968CF_HUE            32768 /* from 0 to 65535 */
-#define W9968CF_COLOUR         32768 /* from 0 to 65535 */
-#define W9968CF_CONTRAST       50000 /* from 0 to 65535 */
-#define W9968CF_WHITENESS      32768 /* from 0 to 65535 */
-
-#define W9968CF_AUTOBRIGHT     0 /* 0 disable, 1 enable automatic brightness */
-#define W9968CF_AUTOEXP        1 /* 0 disable, 1 enable automatic exposure */
-#define W9968CF_LIGHTFREQ      50 /* light frequency. 50Hz (Europe) or 60Hz */
-#define W9968CF_BANDINGFILTER  0 /* 0 disable, 1 enable banding filter */
-#define W9968CF_BACKLIGHT      0 /* 0 or 1, 1=object is lit from behind */
-#define W9968CF_MIRROR         0 /* 0 or 1 [don't] reverse image horizontally*/
-
-#define W9968CF_CLOCKDIV         -1 /* -1 = automatic clock divisor */
-#define W9968CF_DEF_CLOCKDIVISOR  0 /* default sensor clock divisor value */
-
-
-/****************************************************************************
- * Globals                                                                  *
- ****************************************************************************/
-
-#define W9968CF_MODULE_NAME     "V4L driver for W996[87]CF JPEG USB " \
-                                "Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION  "1:1.33-basic"
-#define W9968CF_MODULE_AUTHOR   "(C) 2002-2004 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
-#define W9968CF_MODULE_LICENSE  "GPL"
-
-static const struct usb_device_id winbond_id_table[] = {
-       {
-               /* Creative Labs Video Blaster WebCam Go Plus */
-               USB_DEVICE(0x041e, 0x4003),
-               .driver_info = (unsigned long)"w9968cf",
-       },
-       {
-               /* Generic W996[87]CF JPEG USB Dual Mode Camera */
-               USB_DEVICE(0x1046, 0x9967),
-               .driver_info = (unsigned long)"w9968cf",
-       },
-       { } /* terminating entry */
-};
-
-/* W996[87]CF camera models, internal ids: */
-enum w9968cf_model_id {
-       W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
-       W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
-       W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
-       W9986CF_MOD_AAU = 31,     /* AVerMedia AVerTV USB */
-       W9968CF_MOD_CLVBWG = 34,  /* Creative Labs Video Blaster WebCam Go */
-       W9968CF_MOD_LL = 37,      /* Lebon LDC-035A */
-       W9968CF_MOD_EEEMC = 40,   /* Ezonics EZ-802 EZMega Cam */
-       W9968CF_MOD_OOE = 42,     /* OmniVision OV8610-EDE */
-       W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
-       W9968CF_MOD_PDPII = 46,   /* Pretec Digi Pen-II */
-       W9968CF_MOD_PDP480 = 49,  /* Pretec DigiPen-480 */
-};
-
-enum w9968cf_frame_status {
-       F_READY,            /* finished grabbing & ready to be read/synced */
-       F_GRABBING,         /* in the process of being grabbed into */
-       F_ERROR,            /* something bad happened while processing */
-       F_UNUSED            /* unused (no VIDIOCMCAPTURE) */
-};
-
-struct w9968cf_frame_t {
-       void* buffer;
-       unsigned long size;
-       u32 length;
-       int number;
-       enum w9968cf_frame_status status;
-       struct w9968cf_frame_t* next;
-       u8 queued;
-};
-
-enum w9968cf_vpp_flag {
-       VPP_NONE = 0x00,
-       VPP_UPSCALE = 0x01,
-       VPP_SWAP_YUV_BYTES = 0x02,
-       VPP_DECOMPRESSION = 0x04,
-       VPP_UYVY_TO_RGBX = 0x08,
-};
-
-/* Main device driver structure */
-struct w9968cf_device {
-       struct device dev; /* device structure */
-
-       enum w9968cf_model_id id;   /* private device identifier */
-
-       struct video_device* v4ldev; /* -> V4L structure */
-       struct list_head v4llist;    /* entry of the list of V4L cameras */
-
-       struct usb_device* usbdev;           /* -> main USB structure */
-       struct urb* urb[W9968CF_URBS];       /* -> USB request block structs */
-       void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
-       u16* control_buffer;                 /* -> buffer for control req.*/
-       u16* data_buffer;                    /* -> data to send to the FSB */
-
-       struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
-       struct w9968cf_frame_t frame_tmp; /* temporary frame */
-       struct w9968cf_frame_t frame_vpp; /* helper frame.*/
-       struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
-       struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-
-       u8 max_buffers,   /* number of requested buffers */
-          force_palette, /* yes=1/no=0 */
-          force_rgb,     /* read RGB instead of BGR, yes=1, no=0 */
-          double_buffer, /* hardware double buffering yes=1/no=0 */
-          clamping,      /* video data clamping yes=1/no=0 */
-          filter_type,   /* 0=disabled, 1=3 tap, 2=5 tap filter */
-          capture,       /* 0=disabled, 1=enabled */
-          largeview,     /* 0=disabled, 1=enabled */
-          decompression, /* 0=disabled, 1=forced, 2=allowed */
-          upscaling;     /* software image scaling, 0=enabled, 1=disabled */
-
-       struct video_picture picture; /* current picture settings */
-       struct video_window window;   /* current window settings */
-
-       u16 hw_depth,    /* depth (used by the chip) */
-           hw_palette,  /* palette (used by the chip) */
-           hw_width,    /* width (used by the chip) */
-           hw_height,   /* height (used by the chip) */
-           hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-           vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
-           start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
-           start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
-
-       enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
-
-       u8 nbuffers,      /* number of allocated frame buffers */
-          altsetting,    /* camera alternate setting */
-          disconnected,  /* flag: yes=1, no=0 */
-          misconfigured, /* flag: yes=1, no=0 */
-          users,         /* flag: number of users holding the device */
-          streaming;     /* flag: yes=1, no=0 */
-
-       u8 sensor_initialized; /* flag: yes=1, no=0 */
-
-       /* Determined by the image sensor type: */
-       int sensor,       /* type of image sensor chip (CC_*) */
-           monochrome;   /* image sensor is (probably) monochrome */
-       u16 maxwidth,     /* maximum width supported by the image sensor */
-           maxheight,    /* maximum height supported by the image sensor */
-           minwidth,     /* minimum width supported by the image sensor */
-           minheight;    /* minimum height supported by the image sensor */
-       u8  auto_brt,     /* auto brightness enabled flag */
-           auto_exp,     /* auto exposure enabled flag */
-           backlight,    /* backlight exposure algorithm flag */
-           mirror,       /* image is reversed horizontally */
-           lightfreq,    /* power (lighting) frequency */
-           bandfilt;     /* banding filter enabled flag */
-       s8  clockdiv;     /* clock divisor */
-
-       /* I2C interface to kernel */
-       struct i2c_adapter i2c_adapter;
-       struct i2c_client* sensor_client;
-
-       /* Locks */
-       struct mutex dev_mutex,    /* for probe, disconnect,open and close */
-                        fileop_mutex; /* for read and ioctl */
-       spinlock_t urb_lock,   /* for submit_urb() and unlink_urb() */
-                  flist_lock; /* for requested frame list accesses */
-       wait_queue_head_t open, wait_queue;
-
-       char command[16]; /* name of the program holding the device */
-};
-
-
-/****************************************************************************
- * Macros for debugging                                                     *
- ****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef W9968CF_DEBUG
-/* For device specific debugging messages */
-#      define DBG(level, fmt, args...)                                       \
-{                                                                             \
-       if ( ((specific_debug) && (debug == (level))) ||                      \
-            ((!specific_debug) && (debug >= (level))) ) {                    \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->dev, fmt "\n", ## args);                \
-               else if ((level) == 2 || (level) == 3)                        \
-                       dev_info(&cam->dev, fmt "\n", ## args);               \
-               else if ((level) == 4)                                        \
-                       dev_warn(&cam->dev, fmt "\n", ## args);               \
-               else if ((level) >= 5)                                        \
-                       dev_info(&cam->dev, "[%s:%d] " fmt "\n",              \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-}
-/* For generic kernel (not device specific) messages */
-#      define KDBG(level, fmt, args...)                                      \
-{                                                                             \
-       if ( ((specific_debug) && (debug == (level))) ||                      \
-            ((!specific_debug) && (debug >= (level))) ) {                    \
-               if ((level) >= 1 && (level) <= 4)                             \
-                       pr_info("w9968cf: " fmt "\n", ## args);               \
-               else if ((level) >= 5)                                        \
-                       pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__,  \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-}
-#else
-       /* Not debugging: nothing */
-#      define DBG(level, fmt, args...) do {;} while(0);
-#      define KDBG(level, fmt, args...) do {;} while(0);
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
-
-#endif /* _W9968CF_H_ */
diff --git a/drivers/usb/media/w9968cf_decoder.h b/drivers/usb/media/w9968cf_decoder.h
deleted file mode 100644 (file)
index 31faccb..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Video decoder for the W996[87]CF driver for Linux.                      *
- *                                                                         *
- * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_DECODER_H_
-#define _W9968CF_DECODER_H_
-
-/* Comment/uncomment this for high/low quality of compressed video */
-#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-
-#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-static const unsigned char Y_QUANTABLE[64] = {
-       16,  11,  10,  16,  24,  40,  51,  61,
-       12,  12,  14,  19,  26,  58,  60,  55,
-       14,  13,  16,  24,  40,  57,  69,  56,
-       14,  17,  22,  29,  51,  87,  80,  62,
-       18,  22,  37,  56,  68, 109, 103,  77,
-       24,  35,  55,  64,  81, 104, 113,  92,
-       49,  64,  78,  87, 103, 121, 120, 101,
-       72,  92,  95,  98, 112, 100, 103,  99
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-       17,  18,  24,  47,  99,  99,  99,  99,
-       18,  21,  26,  66,  99,  99,  99,  99,
-       24,  26,  56,  99,  99,  99,  99,  99,
-       47,  66,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99,
-       99,  99,  99,  99,  99,  99,  99,  99
-};
-#else
-static const unsigned char Y_QUANTABLE[64] = {
-        8,   5,   5,   8,  12,  20,  25,  30,
-        6,   6,   7,   9,  13,  29,  30,  27,
-        7,   6,   8,  12,  20,  28,  34,  28,
-        7,   8,  11,  14,  25,  43,  40,  31,
-        9,  11,  18,  28,  34,  54,  51,  38,
-       12,  17,  27,  32,  40,  52,  56,  46,
-       24,  32,  39,  43,  51,  60,  60,  50,
-       36,  46,  47,  49,  56,  50,  51,  49
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
-        8,   9,  12,  23,  49,  49,  49,  49,
-        9,  10,  13,  33,  49,  49,  49,  49,
-       12,  13,  28,  49,  49,  49,  49,  49,
-       23,  33,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49,
-       49,  49,  49,  49,  49,  49,  49,  49
-};
-#endif
-
-#define W9968CF_DEC_ERR_CORRUPTED_DATA  -1
-#define W9968CF_DEC_ERR_BUF_OVERFLOW    -2
-#define W9968CF_DEC_ERR_NO_SOI          -3
-#define W9968CF_DEC_ERR_NO_SOF0         -4
-#define W9968CF_DEC_ERR_NO_SOS          -5
-#define W9968CF_DEC_ERR_NO_EOI          -6
-
-extern void w9968cf_init_decoder(void);
-extern int w9968cf_check_headers(const unsigned char* Pin, 
-                                 const unsigned long BUF_SIZE);
-extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE, 
-                          const unsigned W, const unsigned H, char* Pout);
-
-#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/usb/media/w9968cf_vpp.h b/drivers/usb/media/w9968cf_vpp.h
deleted file mode 100644 (file)
index f3b91b7..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- * Interface for video post-processing functions for the W996[87]CF driver *
- * for Linux.                                                              *
- *                                                                         *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>  *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _W9968CF_VPP_H_
-#define _W9968CF_VPP_H_
-
-#include <linux/module.h>
-#include <asm/types.h>
-
-struct w9968cf_vpp_t {
-       struct module* owner;
-       int (*check_headers)(const unsigned char*, const unsigned long);
-       int (*decode)(const char*, const unsigned long, const unsigned,
-                     const unsigned, char*);
-       void (*swap_yuvbytes)(void*, unsigned long);
-       void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
-       void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
-
-       u8 busy; /* read-only flag: module is/is not in use */
-};
-
-#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h
deleted file mode 100644 (file)
index 8e06551..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ZC0301 Image Processor and Control Chip                 *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ZC0301_H_
-#define _ZC0301_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-
-#include "zc0301_sensor.h"
-
-/*****************************************************************************/
-
-#define ZC0301_DEBUG
-#define ZC0301_DEBUG_LEVEL         2
-#define ZC0301_MAX_DEVICES         64
-#define ZC0301_FORCE_MUNMAP        0
-#define ZC0301_MAX_FRAMES          32
-#define ZC0301_COMPRESSION_QUALITY 0
-#define ZC0301_URBS                2
-#define ZC0301_ISO_PACKETS         7
-#define ZC0301_ALTERNATE_SETTING   7
-#define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
-#define ZC0301_CTRL_TIMEOUT        100
-#define ZC0301_FRAME_TIMEOUT       2
-
-/*****************************************************************************/
-
-ZC0301_ID_TABLE
-ZC0301_SENSOR_TABLE
-
-enum zc0301_frame_state {
-       F_UNUSED,
-       F_QUEUED,
-       F_GRABBING,
-       F_DONE,
-       F_ERROR,
-};
-
-struct zc0301_frame_t {
-       void* bufmem;
-       struct v4l2_buffer buf;
-       enum zc0301_frame_state state;
-       struct list_head frame;
-       unsigned long vma_use_count;
-};
-
-enum zc0301_dev_state {
-       DEV_INITIALIZED = 0x01,
-       DEV_DISCONNECTED = 0x02,
-       DEV_MISCONFIGURED = 0x04,
-};
-
-enum zc0301_io_method {
-       IO_NONE,
-       IO_READ,
-       IO_MMAP,
-};
-
-enum zc0301_stream_state {
-       STREAM_OFF,
-       STREAM_INTERRUPT,
-       STREAM_ON,
-};
-
-struct zc0301_module_param {
-       u8 force_munmap;
-       u16 frame_timeout;
-};
-
-static DECLARE_RWSEM(zc0301_disconnect);
-
-struct zc0301_device {
-       struct video_device* v4ldev;
-
-       struct zc0301_sensor sensor;
-
-       struct usb_device* usbdev;
-       struct urb* urb[ZC0301_URBS];
-       void* transfer_buffer[ZC0301_URBS];
-       u8* control_buffer;
-
-       struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
-       struct list_head inqueue, outqueue;
-       u32 frame_count, nbuffers, nreadbuffers;
-
-       enum zc0301_io_method io;
-       enum zc0301_stream_state stream;
-
-       struct v4l2_jpegcompression compression;
-
-       struct zc0301_module_param module_param;
-
-       enum zc0301_dev_state state;
-       u8 users;
-
-       struct mutex dev_mutex, fileop_mutex;
-       spinlock_t queue_lock;
-       wait_queue_head_t open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
-{
-       return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
-{
-       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ZC0301_DEBUG
-#      define DBG(level, fmt, args...)                                       \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1)                                             \
-                       dev_err(&cam->usbdev->dev, fmt "\n", ## args);        \
-               else if ((level) == 2)                                        \
-                       dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
-               else if ((level) >= 3)                                        \
-                       dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-                                __FUNCTION__, __LINE__ , ## args);           \
-       }                                                                     \
-} while (0)
-#      define KDBG(level, fmt, args...)                                      \
-do {                                                                          \
-       if (debug >= (level)) {                                               \
-               if ((level) == 1 || (level) == 2)                             \
-                       pr_info("zc0301: " fmt "\n", ## args);                \
-               else if ((level) == 3)                                        \
-                       pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
-                                __LINE__ , ## args);                         \
-       }                                                                     \
-} while (0)
-#      define V4LDBG(level, name, cmd)                                       \
-do {                                                                          \
-       if (debug >= (level))                                                 \
-               v4l_print_ioctl(name, cmd);                                   \
-} while (0)
-#else
-#      define DBG(level, fmt, args...) do {;} while(0)
-#      define KDBG(level, fmt, args...) do {;} while(0)
-#      define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-         __FUNCTION__, __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ZC0301_H_ */
diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c
deleted file mode 100644 (file)
index 4036c62..0000000
+++ /dev/null
@@ -1,2055 +0,0 @@
-/***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip         *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * Informations about the chip internals needed to enable the I2C protocol *
- * have been taken from the documentation of the ZC030x Video4Linux1       *
- * driver written by Andrew Birkett <andy@nobugs.org>                      *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/moduleparam.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <linux/byteorder/generic.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "zc0301.h"
-
-/*****************************************************************************/
-
-#define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301 "                       \
-                              "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
-#define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
-#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.03"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 3)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, zc0301_id_table);
-
-MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
-MODULE_VERSION(ZC0301_MODULE_VERSION);
-MODULE_LICENSE(ZC0301_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
-                 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-                 "\n -1 = use next available (default)"
-                 "\n  n = use minor number n (integer >= 0)"
-                 "\nYou can specify up to "
-                 __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
-                 "\nFor example:"
-                 "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
-                 "\nthe second registered camera and use auto for the first"
-                 "\none and for every other camera."
-                 "\n");
-
-static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-                               ZC0301_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
-                 "\n<0|1[,...]> Force the application to unmap previously"
-                 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
-                 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
-                 "\nthis feature. This parameter is specific for each"
-                 "\ndetected camera."
-                 "\n 0 = do not force memory unmapping"
-                 "\n 1 = force memory unmapping (save memory)"
-                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
-                 "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
-                                       ZC0301_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
-                 "\n<n[,...]> Timeout for a video frame in seconds."
-                 "\nThis parameter is specific for each detected camera."
-                 "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
-                 "\n");
-
-#ifdef ZC0301_DEBUG
-static unsigned short debug = ZC0301_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
-                 "\n<n> Debugging information level, from 0 to 3:"
-                 "\n0 = none (use carefully)"
-                 "\n1 = critical errors"
-                 "\n2 = significant informations"
-                 "\n3 = more verbose messages"
-                 "\nLevel 3 is useful for testing only, when only "
-                 "one device is used."
-                 "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
-                 "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-zc0301_request_buffers(struct zc0301_device* cam, u32 count,
-                       enum zc0301_io_method io)
-{
-       struct v4l2_pix_format* p = &(cam->sensor.pix_format);
-       struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
-       const size_t imagesize = cam->module_param.force_munmap ||
-                                io == IO_READ ?
-                                (p->width * p->height * p->priv) / 8 :
-                                (r->width * r->height * p->priv) / 8;
-       void* buff = NULL;
-       u32 i;
-
-       if (count > ZC0301_MAX_FRAMES)
-               count = ZC0301_MAX_FRAMES;
-
-       cam->nbuffers = count;
-       while (cam->nbuffers > 0) {
-               if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
-                       break;
-               cam->nbuffers--;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.index = i;
-               cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
-               cam->frame[i].buf.length = imagesize;
-               cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               cam->frame[i].buf.sequence = 0;
-               cam->frame[i].buf.field = V4L2_FIELD_NONE;
-               cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
-               cam->frame[i].buf.flags = 0;
-       }
-
-       return cam->nbuffers;
-}
-
-
-static void zc0301_release_buffers(struct zc0301_device* cam)
-{
-       if (cam->nbuffers) {
-               vfree(cam->frame[0].bufmem);
-               cam->nbuffers = 0;
-       }
-       cam->frame_current = NULL;
-}
-
-
-static void zc0301_empty_framequeues(struct zc0301_device* cam)
-{
-       u32 i;
-
-       INIT_LIST_HEAD(&cam->inqueue);
-       INIT_LIST_HEAD(&cam->outqueue);
-
-       for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
-               cam->frame[i].state = F_UNUSED;
-               cam->frame[i].buf.bytesused = 0;
-       }
-}
-
-
-static void zc0301_requeue_outqueue(struct zc0301_device* cam)
-{
-       struct zc0301_frame_t *i;
-
-       list_for_each_entry(i, &cam->outqueue, frame) {
-               i->state = F_QUEUED;
-               list_add(&i->frame, &cam->inqueue);
-       }
-
-       INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void zc0301_queue_unusedframes(struct zc0301_device* cam)
-{
-       unsigned long lock_flags;
-       u32 i;
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].state == F_UNUSED) {
-                       cam->frame[i].state = F_QUEUED;
-                       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-                       list_add_tail(&cam->frame[i].frame, &cam->inqueue);
-                       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               }
-}
-
-/*****************************************************************************/
-
-int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
-{
-       struct usb_device* udev = cam->usbdev;
-       int res;
-
-       res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
-                             value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
-       if (res < 0) {
-               DBG(3, "Failed to write a register (index 0x%04X, "
-                      "value 0x%02X, error %d)",index, value, res);
-               return -1;
-       }
-
-       return 0;
-}
-
-
-int zc0301_read_reg(struct zc0301_device* cam, u16 index)
-{
-       struct usb_device* udev = cam->usbdev;
-       u8* buff = cam->control_buffer;
-       int res;
-
-       res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
-                             0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
-       if (res < 0)
-               DBG(3, "Failed to read a register (index 0x%04X, error %d)",
-                   index, res);
-
-       PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
-
-       return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
-{
-       int err = 0, res, r0, r1;
-
-       err += zc0301_write_reg(cam, 0x0092, address);
-       err += zc0301_write_reg(cam, 0x0090, 0x02);
-
-       msleep(1);
-
-       res = zc0301_read_reg(cam, 0x0091);
-       if (res < 0)
-               err += res;
-       r0 = zc0301_read_reg(cam, 0x0095);
-       if (r0 < 0)
-               err += r0;
-       r1 = zc0301_read_reg(cam, 0x0096);
-       if (r1 < 0)
-               err += r1;
-
-       res = (length <= 1) ? r0 : r0 | (r1 << 8);
-
-       if (err)
-               DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
-                   address, res);
-
-
-       PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
-
-       return err ? -1 : res;
-}
-
-
-int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
-{
-       int err = 0, res;
-
-       err += zc0301_write_reg(cam, 0x0092, address);
-       err += zc0301_write_reg(cam, 0x0093, value & 0xff);
-       err += zc0301_write_reg(cam, 0x0094, value >> 8);
-       err += zc0301_write_reg(cam, 0x0090, 0x01);
-
-       msleep(1);
-
-       res = zc0301_read_reg(cam, 0x0091);
-       if (res < 0)
-               err += res;
-
-       if (err)
-               DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
-                   address, value);
-
-       PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
-
-       return err ? -1 : 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
-{
-       struct zc0301_device* cam = urb->context;
-       struct zc0301_frame_t** f;
-       size_t imagesize;
-       u8 i;
-       int err = 0;
-
-       if (urb->status == -ENOENT)
-               return;
-
-       f = &cam->frame_current;
-
-       if (cam->stream == STREAM_INTERRUPT) {
-               cam->stream = STREAM_OFF;
-               if ((*f))
-                       (*f)->state = F_QUEUED;
-               DBG(3, "Stream interrupted");
-               wake_up(&cam->wait_stream);
-       }
-
-       if (cam->state & DEV_DISCONNECTED)
-               return;
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               wake_up_interruptible(&cam->wait_frame);
-               return;
-       }
-
-       if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
-               goto resubmit_urb;
-
-       if (!(*f))
-               (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
-                                 frame);
-
-       imagesize = (cam->sensor.pix_format.width *
-                    cam->sensor.pix_format.height *
-                    cam->sensor.pix_format.priv) / 8;
-
-       for (i = 0; i < urb->number_of_packets; i++) {
-               unsigned int len, status;
-               void *pos;
-               u16* soi;
-               u8 sof;
-
-               len = urb->iso_frame_desc[i].actual_length;
-               status = urb->iso_frame_desc[i].status;
-               pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
-               if (status) {
-                       DBG(3, "Error in isochronous frame");
-                       (*f)->state = F_ERROR;
-                       continue;
-               }
-
-               sof = (*(soi = pos) == 0xd8ff);
-
-               PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
-
-               if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
-                       if (sof) {
-                               (*f)->state = F_GRABBING;
-                               (*f)->buf.bytesused = 0;
-                               do_gettimeofday(&(*f)->buf.timestamp);
-                               DBG(3, "SOF detected: new video frame");
-                       }
-
-               if ((*f)->state == F_GRABBING) {
-                       if (sof && (*f)->buf.bytesused)
-                                       goto end_of_frame;
-
-                       if ((*f)->buf.bytesused + len > imagesize) {
-                               DBG(3, "Video frame size exceeded");
-                               (*f)->state = F_ERROR;
-                               continue;
-                       }
-
-                       memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
-                       (*f)->buf.bytesused += len;
-
-                       if ((*f)->buf.bytesused == imagesize) {
-                               u32 b;
-end_of_frame:
-                               b = (*f)->buf.bytesused;
-                               (*f)->state = F_DONE;
-                               (*f)->buf.sequence= ++cam->frame_count;
-                               spin_lock(&cam->queue_lock);
-                               list_move_tail(&(*f)->frame, &cam->outqueue);
-                               if (!list_empty(&cam->inqueue))
-                                       (*f) = list_entry(cam->inqueue.next,
-                                                      struct zc0301_frame_t,
-                                                         frame);
-                               else
-                                       (*f) = NULL;
-                               spin_unlock(&cam->queue_lock);
-                               DBG(3, "Video frame captured: : %lu bytes",
-                                      (unsigned long)(b));
-
-                               if (!(*f))
-                                       goto resubmit_urb;
-
-                               if (sof)
-                                       goto start_of_frame;
-                       }
-               }
-       }
-
-resubmit_urb:
-       urb->dev = cam->usbdev;
-       err = usb_submit_urb(urb, GFP_ATOMIC);
-       if (err < 0 && err != -EPERM) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "usb_submit_urb() failed");
-       }
-
-       wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int zc0301_start_transfer(struct zc0301_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       struct urb* urb;
-       const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
-                                              512, 768, 1023};
-       const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
-       s8 i, j;
-       int err = 0;
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
-                                                 GFP_KERNEL);
-               if (!cam->transfer_buffer[i]) {
-                       err = -ENOMEM;
-                       DBG(1, "Not enough memory");
-                       goto free_buffers;
-               }
-       }
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
-               cam->urb[i] = urb;
-               if (!urb) {
-                       err = -ENOMEM;
-                       DBG(1, "usb_alloc_urb() failed");
-                       goto free_urbs;
-               }
-               urb->dev = udev;
-               urb->context = cam;
-               urb->pipe = usb_rcvisocpipe(udev, 1);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->number_of_packets = ZC0301_ISO_PACKETS;
-               urb->complete = zc0301_urb_complete;
-               urb->transfer_buffer = cam->transfer_buffer[i];
-               urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
-               urb->interval = 1;
-               for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
-                       urb->iso_frame_desc[j].offset = psz * j;
-                       urb->iso_frame_desc[j].length = psz;
-               }
-       }
-
-       err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
-       if (err) {
-               DBG(1, "usb_set_interface() failed");
-               goto free_urbs;
-       }
-
-       cam->frame_current = NULL;
-
-       for (i = 0; i < ZC0301_URBS; i++) {
-               err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
-               if (err) {
-                       for (j = i-1; j >= 0; j--)
-                               usb_kill_urb(cam->urb[j]);
-                       DBG(1, "usb_submit_urb() failed, error %d", err);
-                       goto free_urbs;
-               }
-       }
-
-       return 0;
-
-free_urbs:
-       for (i = 0; (i < ZC0301_URBS) &&  cam->urb[i]; i++)
-               usb_free_urb(cam->urb[i]);
-
-free_buffers:
-       for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
-               kfree(cam->transfer_buffer[i]);
-
-       return err;
-}
-
-
-static int zc0301_stop_transfer(struct zc0301_device* cam)
-{
-       struct usb_device *udev = cam->usbdev;
-       s8 i;
-       int err = 0;
-
-       if (cam->state & DEV_DISCONNECTED)
-               return 0;
-
-       for (i = ZC0301_URBS-1; i >= 0; i--) {
-               usb_kill_urb(cam->urb[i]);
-               usb_free_urb(cam->urb[i]);
-               kfree(cam->transfer_buffer[i]);
-       }
-
-       err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
-       if (err)
-               DBG(3, "usb_set_interface() failed");
-
-       return err;
-}
-
-
-static int zc0301_stream_interrupt(struct zc0301_device* cam)
-{
-       long timeout;
-
-       cam->stream = STREAM_INTERRUPT;
-       timeout = wait_event_timeout(cam->wait_stream,
-                                    (cam->stream == STREAM_OFF) ||
-                                    (cam->state & DEV_DISCONNECTED),
-                                    ZC0301_URB_TIMEOUT);
-       if (cam->state & DEV_DISCONNECTED)
-               return -ENODEV;
-       else if (cam->stream != STREAM_OFF) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "URB timeout reached. The camera is misconfigured. To "
-                      "use it, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_set_compression(struct zc0301_device* cam,
-                       struct v4l2_jpegcompression* compression)
-{
-       int r, err = 0;
-
-       if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
-               err += r;
-       err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
-
-       return err ? -EIO : 0;
-}
-
-
-static int zc0301_init(struct zc0301_device* cam)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       struct v4l2_queryctrl *qctrl;
-       struct v4l2_rect* rect;
-       u8 i = 0;
-       int err = 0;
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               init_waitqueue_head(&cam->open);
-               qctrl = s->qctrl;
-               rect = &(s->cropcap.defrect);
-               cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
-       } else { /* use current values */
-               qctrl = s->_qctrl;
-               rect = &(s->_rect);
-       }
-
-       if (s->init) {
-               err = s->init(cam);
-               if (err) {
-                       DBG(3, "Sensor initialization failed");
-                       return err;
-               }
-       }
-
-       if ((err = zc0301_set_compression(cam, &cam->compression))) {
-               DBG(3, "set_compression() failed");
-               return err;
-       }
-
-       if (s->set_crop)
-               if ((err = s->set_crop(cam, rect))) {
-                       DBG(3, "set_crop() failed");
-                       return err;
-               }
-
-       if (s->set_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (s->qctrl[i].id != 0 &&
-                           !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
-                               ctrl.id = s->qctrl[i].id;
-                               ctrl.value = qctrl[i].default_value;
-                               err = s->set_ctrl(cam, &ctrl);
-                               if (err) {
-                                       DBG(3, "Set %s control failed",
-                                           s->qctrl[i].name);
-                                       return err;
-                               }
-                               DBG(3, "Image sensor supports '%s' control",
-                                   s->qctrl[i].name);
-                       }
-       }
-
-       if (!(cam->state & DEV_INITIALIZED)) {
-               mutex_init(&cam->fileop_mutex);
-               spin_lock_init(&cam->queue_lock);
-               init_waitqueue_head(&cam->wait_frame);
-               init_waitqueue_head(&cam->wait_stream);
-               cam->nreadbuffers = 2;
-               memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
-               memcpy(&(s->_rect), &(s->cropcap.defrect),
-                      sizeof(struct v4l2_rect));
-               cam->state |= DEV_INITIALIZED;
-       }
-
-       DBG(2, "Initialization succeeded");
-       return 0;
-}
-
-
-static void zc0301_release_resources(struct zc0301_device* cam)
-{
-       DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
-       video_set_drvdata(cam->v4ldev, NULL);
-       video_unregister_device(cam->v4ldev);
-       kfree(cam->control_buffer);
-}
-
-/*****************************************************************************/
-
-static int zc0301_open(struct inode* inode, struct file* filp)
-{
-       struct zc0301_device* cam;
-       int err = 0;
-
-       /*
-          This is the only safe way to prevent race conditions with
-          disconnect
-       */
-       if (!down_read_trylock(&zc0301_disconnect))
-               return -ERESTARTSYS;
-
-       cam = video_get_drvdata(video_devdata(filp));
-
-       if (mutex_lock_interruptible(&cam->dev_mutex)) {
-               up_read(&zc0301_disconnect);
-               return -ERESTARTSYS;
-       }
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
-               if ((filp->f_flags & O_NONBLOCK) ||
-                   (filp->f_flags & O_NDELAY)) {
-                       err = -EWOULDBLOCK;
-                       goto out;
-               }
-               mutex_unlock(&cam->dev_mutex);
-               err = wait_event_interruptible_exclusive(cam->open,
-                                                 cam->state & DEV_DISCONNECTED
-                                                        || !cam->users);
-               if (err) {
-                       up_read(&zc0301_disconnect);
-                       return err;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       up_read(&zc0301_disconnect);
-                       return -ENODEV;
-               }
-               mutex_lock(&cam->dev_mutex);
-       }
-
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               err = zc0301_init(cam);
-               if (err) {
-                       DBG(1, "Initialization failed again. "
-                              "I will retry on next open().");
-                       goto out;
-               }
-               cam->state &= ~DEV_MISCONFIGURED;
-       }
-
-       if ((err = zc0301_start_transfer(cam)))
-               goto out;
-
-       filp->private_data = cam;
-       cam->users++;
-       cam->io = IO_NONE;
-       cam->stream = STREAM_OFF;
-       cam->nbuffers = 0;
-       cam->frame_count = 0;
-       zc0301_empty_framequeues(cam);
-
-       DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
-
-out:
-       mutex_unlock(&cam->dev_mutex);
-       up_read(&zc0301_disconnect);
-       return err;
-}
-
-
-static int zc0301_release(struct inode* inode, struct file* filp)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-
-       mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
-       zc0301_stop_transfer(cam);
-
-       zc0301_release_buffers(cam);
-
-       if (cam->state & DEV_DISCONNECTED) {
-               zc0301_release_resources(cam);
-               usb_put_dev(cam->usbdev);
-               mutex_unlock(&cam->dev_mutex);
-               kfree(cam);
-               return 0;
-       }
-
-       cam->users--;
-       wake_up_interruptible_nr(&cam->open, 1);
-
-       DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-}
-
-
-static ssize_t
-zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       struct zc0301_frame_t* f, * i;
-       unsigned long lock_flags;
-       long timeout;
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io == IO_MMAP) {
-               DBG(3, "Close and open the device again to choose the read "
-                      "method");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "read() failed, not enough memory");
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENOMEM;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (list_empty(&cam->inqueue)) {
-               if (!list_empty(&cam->outqueue))
-                       zc0301_empty_framequeues(cam);
-               zc0301_queue_unusedframes(cam);
-       }
-
-       if (!count) {
-               mutex_unlock(&cam->fileop_mutex);
-               return 0;
-       }
-
-       if (list_empty(&cam->outqueue)) {
-               if (filp->f_flags & O_NONBLOCK) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return timeout;
-               }
-               if (cam->state & DEV_DISCONNECTED) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -ENODEV;
-               }
-               if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EIO;
-               }
-       }
-
-       f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
-
-       if (count > f->buf.bytesused)
-               count = f->buf.bytesused;
-
-       if (copy_to_user(buf, f->bufmem, count)) {
-               err = -EFAULT;
-               goto exit;
-       }
-       *f_pos += count;
-
-exit:
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_for_each_entry(i, &cam->outqueue, frame)
-               i->state = F_UNUSED;
-       INIT_LIST_HEAD(&cam->outqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       zc0301_queue_unusedframes(cam);
-
-       PDBGG("Frame #%lu, bytes read: %zu",
-             (unsigned long)f->buf.index, count);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err ? err : count;
-}
-
-
-static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       struct zc0301_frame_t* f;
-       unsigned long lock_flags;
-       unsigned int mask = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return POLLERR;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               goto error;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               goto error;
-       }
-
-       if (cam->io == IO_NONE) {
-               if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
-                       DBG(1, "poll() failed, not enough memory");
-                       goto error;
-               }
-               cam->io = IO_READ;
-               cam->stream = STREAM_ON;
-       }
-
-       if (cam->io == IO_READ) {
-               spin_lock_irqsave(&cam->queue_lock, lock_flags);
-               list_for_each_entry(f, &cam->outqueue, frame)
-                       f->state = F_UNUSED;
-               INIT_LIST_HEAD(&cam->outqueue);
-               spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-               zc0301_queue_unusedframes(cam);
-       }
-
-       poll_wait(filp, &cam->wait_frame, wait);
-
-       if (!list_empty(&cam->outqueue))
-               mask |= POLLIN | POLLRDNORM;
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return mask;
-
-error:
-       mutex_unlock(&cam->fileop_mutex);
-       return POLLERR;
-}
-
-
-static void zc0301_vm_open(struct vm_area_struct* vma)
-{
-       struct zc0301_frame_t* f = vma->vm_private_data;
-       f->vma_use_count++;
-}
-
-
-static void zc0301_vm_close(struct vm_area_struct* vma)
-{
-       /* NOTE: buffers are not freed here */
-       struct zc0301_frame_t* f = vma->vm_private_data;
-       f->vma_use_count--;
-}
-
-
-static struct vm_operations_struct zc0301_vm_ops = {
-       .open = zc0301_vm_open,
-       .close = zc0301_vm_close,
-};
-
-
-static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       unsigned long size = vma->vm_end - vma->vm_start,
-                     start = vma->vm_start;
-       void *pos;
-       u32 i;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-           size != PAGE_ALIGN(cam->frame[0].buf.length)) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++) {
-               if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
-                       break;
-       }
-       if (i == cam->nbuffers) {
-               mutex_unlock(&cam->fileop_mutex);
-               return -EINVAL;
-       }
-
-       vma->vm_flags |= VM_IO;
-       vma->vm_flags |= VM_RESERVED;
-
-       pos = cam->frame[i].bufmem;
-       while (size > 0) { /* size is page-aligned */
-               if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
-                       mutex_unlock(&cam->fileop_mutex);
-                       return -EAGAIN;
-               }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       vma->vm_ops = &zc0301_vm_ops;
-       vma->vm_private_data = &cam->frame[i];
-
-       zc0301_vm_open(vma);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_capability cap = {
-               .driver = "zc0301",
-               .version = ZC0301_MODULE_VERSION_CODE,
-               .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
-                               V4L2_CAP_STREAMING,
-       };
-
-       strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
-       if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
-               strlcpy(cap.bus_info, cam->usbdev->dev.bus_id,
-                       sizeof(cap.bus_info));
-
-       if (copy_to_user(arg, &cap, sizeof(cap)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_input i;
-
-       if (copy_from_user(&i, arg, sizeof(i)))
-               return -EFAULT;
-
-       if (i.index)
-               return -EINVAL;
-
-       memset(&i, 0, sizeof(i));
-       strcpy(i.name, "Camera");
-       i.type = V4L2_INPUT_TYPE_CAMERA;
-
-       if (copy_to_user(arg, &i, sizeof(i)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
-{
-       int index = 0;
-
-       if (copy_to_user(arg, &index, sizeof(index)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
-{
-       int index;
-
-       if (copy_from_user(&index, arg, sizeof(index)))
-               return -EFAULT;
-
-       if (index != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_queryctrl qc;
-       u8 i;
-
-       if (copy_from_user(&qc, arg, sizeof(qc)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (qc.id && qc.id == s->qctrl[i].id) {
-                       memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
-                       if (copy_to_user(arg, &qc, sizeof(qc)))
-                               return -EFAULT;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-
-static int
-zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       int err = 0;
-       u8 i;
-
-       if (!s->get_ctrl && !s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       if (!s->get_ctrl) {
-               for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-                       if (ctrl.id == s->qctrl[i].id) {
-                               ctrl.value = s->_qctrl[i].default_value;
-                               goto exit;
-                       }
-               return -EINVAL;
-       } else
-               err = s->get_ctrl(cam, &ctrl);
-
-exit:
-       if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
-               return -EFAULT;
-
-       return err;
-}
-
-
-static int
-zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_control ctrl;
-       u8 i;
-       int err = 0;
-
-       if (!s->set_ctrl)
-               return -EINVAL;
-
-       if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
-               return -EFAULT;
-
-       for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
-               if (ctrl.id == s->qctrl[i].id) {
-                       if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
-                               return -EINVAL;
-                       if (ctrl.value < s->qctrl[i].minimum ||
-                           ctrl.value > s->qctrl[i].maximum)
-                               return -ERANGE;
-                       ctrl.value -= ctrl.value % s->qctrl[i].step;
-                       break;
-               }
-
-       if ((err = s->set_ctrl(cam, &ctrl)))
-               return err;
-
-       s->_qctrl[i].default_value = ctrl.value;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
-       cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       cc->pixelaspect.numerator = 1;
-       cc->pixelaspect.denominator = 1;
-
-       if (copy_to_user(arg, cc, sizeof(*cc)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_crop crop = {
-               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-       };
-
-       memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
-       if (copy_to_user(arg, &crop, sizeof(crop)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_crop crop;
-       struct v4l2_rect* rect;
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       const enum zc0301_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&crop, arg, sizeof(crop)))
-               return -EFAULT;
-
-       rect = &(crop.c);
-
-       if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_CROP failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (!s->set_crop) {
-               memcpy(rect, &(s->_rect), sizeof(*rect));
-               if (copy_to_user(arg, &crop, sizeof(crop)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       rect->left &= ~7L;
-       rect->top &= ~7L;
-       if (rect->width < 8)
-               rect->width = 8;
-       if (rect->height < 8)
-               rect->height = 8;
-       if (rect->width > bounds->width)
-               rect->width = bounds->width;
-       if (rect->height > bounds->height)
-               rect->height = bounds->height;
-       if (rect->left < bounds->left)
-               rect->left = bounds->left;
-       if (rect->top < bounds->top)
-               rect->top = bounds->top;
-       if (rect->left + rect->width > bounds->left + bounds->width)
-               rect->left = bounds->left+bounds->width - rect->width;
-       if (rect->top + rect->height > bounds->top + bounds->height)
-               rect->top = bounds->top+bounds->height - rect->height;
-       rect->width &= ~7L;
-       rect->height &= ~7L;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &crop, sizeof(crop))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               zc0301_release_buffers(cam);
-
-       if (s->set_crop)
-               err += s->set_crop(cam, rect);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       s->pix_format.width = rect->width;
-       s->pix_format.height = rect->height;
-       memcpy(&(s->_rect), rect, sizeof(*rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               zc0301_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               zc0301_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_fmtdesc fmtd;
-
-       if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
-               return -EFAULT;
-
-       if (fmtd.index == 0) {
-               strcpy(fmtd.description, "JPEG");
-               fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
-               fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
-       } else
-               return -EINVAL;
-
-       fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
-       if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_format format;
-       struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       pfmt->bytesperline = 0;
-       pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
-       pfmt->field = V4L2_FIELD_NONE;
-       memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
-       if (copy_to_user(arg, &format, sizeof(format)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
-                        void __user * arg)
-{
-       struct zc0301_sensor* s = &cam->sensor;
-       struct v4l2_format format;
-       struct v4l2_pix_format* pix;
-       struct v4l2_pix_format* pfmt = &(s->pix_format);
-       struct v4l2_rect* bounds = &(s->cropcap.bounds);
-       struct v4l2_rect rect;
-       const enum zc0301_stream_state stream = cam->stream;
-       const u32 nbuffers = cam->nbuffers;
-       u32 i;
-       int err = 0;
-
-       if (copy_from_user(&format, arg, sizeof(format)))
-               return -EFAULT;
-
-       pix = &(format.fmt.pix);
-
-       if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       memcpy(&rect, &(s->_rect), sizeof(rect));
-
-       if (!s->set_crop) {
-               pix->width = rect.width;
-               pix->height = rect.height;
-       } else {
-               rect.width = pix->width;
-               rect.height = pix->height;
-       }
-
-       if (rect.width < 8)
-               rect.width = 8;
-       if (rect.height < 8)
-               rect.height = 8;
-       if (rect.width > bounds->left + bounds->width - rect.left)
-               rect.width = bounds->left + bounds->width - rect.left;
-       if (rect.height > bounds->top + bounds->height - rect.top)
-               rect.height = bounds->top + bounds->height - rect.top;
-       rect.width &= ~7L;
-       rect.height &= ~7L;
-
-       pix->width = rect.width;
-       pix->height = rect.height;
-       pix->pixelformat = pfmt->pixelformat;
-       pix->priv = pfmt->priv;
-       pix->colorspace = pfmt->colorspace;
-       pix->bytesperline = 0;
-       pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
-       pix->field = V4L2_FIELD_NONE;
-
-       if (cmd == VIDIOC_TRY_FMT) {
-               if (copy_to_user(arg, &format, sizeof(format)))
-                       return -EFAULT;
-               return 0;
-       }
-
-       if (cam->module_param.force_munmap)
-               for (i = 0; i < cam->nbuffers; i++)
-                       if (cam->frame[i].vma_use_count) {
-                               DBG(3, "VIDIOC_S_FMT failed. "
-                                      "Unmap the buffers first.");
-                               return -EINVAL;
-                       }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       if (copy_to_user(arg, &format, sizeof(format))) {
-               cam->stream = stream;
-               return -EFAULT;
-       }
-
-       if (cam->module_param.force_munmap || cam->io == IO_READ)
-               zc0301_release_buffers(cam);
-
-       if (s->set_crop)
-               err += s->set_crop(cam, &rect);
-
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       memcpy(pfmt, pix, sizeof(*pix));
-       memcpy(&(s->_rect), &rect, sizeof(rect));
-
-       if ((cam->module_param.force_munmap  || cam->io == IO_READ) &&
-           nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
-                      "use the camera, close and open /dev/video%d again.",
-                   cam->v4ldev->minor);
-               return -ENOMEM;
-       }
-
-       if (cam->io == IO_READ)
-               zc0301_empty_framequeues(cam);
-       else if (cam->module_param.force_munmap)
-               zc0301_requeue_outqueue(cam);
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-       if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_jpegcompression jc;
-       const enum zc0301_stream_state stream = cam->stream;
-       int err = 0;
-
-       if (copy_from_user(&jc, arg, sizeof(jc)))
-               return -EFAULT;
-
-       if (jc.quality != 0)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       err += zc0301_set_compression(cam, &jc);
-       if (err) { /* atomic, no rollback in ioctl() */
-               cam->state |= DEV_MISCONFIGURED;
-               DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
-                      "problems. To use the camera, close and open "
-                      "/dev/video%d again.", cam->v4ldev->minor);
-               return -EIO;
-       }
-
-       cam->compression.quality = jc.quality;
-
-       cam->stream = stream;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_requestbuffers rb;
-       u32 i;
-       int err;
-
-       if (copy_from_user(&rb, arg, sizeof(rb)))
-               return -EFAULT;
-
-       if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           rb.memory != V4L2_MEMORY_MMAP)
-               return -EINVAL;
-
-       if (cam->io == IO_READ) {
-               DBG(3, "Close and open the device again to choose the mmap "
-                      "I/O method");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < cam->nbuffers; i++)
-               if (cam->frame[i].vma_use_count) {
-                       DBG(3, "VIDIOC_REQBUFS failed. "
-                              "Previous buffers are still mapped.");
-                       return -EINVAL;
-               }
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       zc0301_empty_framequeues(cam);
-
-       zc0301_release_buffers(cam);
-       if (rb.count)
-               rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
-
-       if (copy_to_user(arg, &rb, sizeof(rb))) {
-               zc0301_release_buffers(cam);
-               cam->io = IO_NONE;
-               return -EFAULT;
-       }
-
-       cam->io = rb.count ? IO_MMAP : IO_NONE;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
-       if (cam->frame[b.index].vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (cam->frame[b.index].state == F_DONE)
-               b.flags |= V4L2_BUF_FLAG_DONE;
-       else if (cam->frame[b.index].state != F_UNUSED)
-               b.flags |= V4L2_BUF_FLAG_QUEUED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_buffer b;
-       unsigned long lock_flags;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-           b.index >= cam->nbuffers || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->frame[b.index].state != F_UNUSED)
-               return -EINVAL;
-
-       cam->frame[b.index].state = F_QUEUED;
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
-                    void __user * arg)
-{
-       struct v4l2_buffer b;
-       struct zc0301_frame_t *f;
-       unsigned long lock_flags;
-       long timeout;
-
-       if (copy_from_user(&b, arg, sizeof(b)))
-               return -EFAULT;
-
-       if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->outqueue)) {
-               if (cam->stream == STREAM_OFF)
-                       return -EINVAL;
-               if (filp->f_flags & O_NONBLOCK)
-                       return -EAGAIN;
-               timeout = wait_event_interruptible_timeout
-                         ( cam->wait_frame,
-                           (!list_empty(&cam->outqueue)) ||
-                           (cam->state & DEV_DISCONNECTED) ||
-                           (cam->state & DEV_MISCONFIGURED),
-                           cam->module_param.frame_timeout *
-                           1000 * msecs_to_jiffies(1) );
-               if (timeout < 0)
-                       return timeout;
-               if (cam->state & DEV_DISCONNECTED)
-                       return -ENODEV;
-               if (!timeout || (cam->state & DEV_MISCONFIGURED))
-                       return -EIO;
-       }
-
-       spin_lock_irqsave(&cam->queue_lock, lock_flags);
-       f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
-       list_del(cam->outqueue.next);
-       spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
-       f->state = F_UNUSED;
-
-       memcpy(&b, &f->buf, sizeof(b));
-       if (f->vma_use_count)
-               b.flags |= V4L2_BUF_FLAG_MAPPED;
-
-       if (copy_to_user(arg, &b, sizeof(b)))
-               return -EFAULT;
-
-       PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
-{
-       int type;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (list_empty(&cam->inqueue))
-               return -EINVAL;
-
-       cam->stream = STREAM_ON;
-
-       DBG(3, "Stream on");
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
-{
-       int type, err;
-
-       if (copy_from_user(&type, arg, sizeof(type)))
-               return -EFAULT;
-
-       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
-               return -EINVAL;
-
-       if (cam->stream == STREAM_ON)
-               if ((err = zc0301_stream_interrupt(cam)))
-                       return err;
-
-       zc0301_empty_framequeues(cam);
-
-       DBG(3, "Stream off");
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-       sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       return 0;
-}
-
-
-static int
-zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
-{
-       struct v4l2_streamparm sp;
-
-       if (copy_from_user(&sp, arg, sizeof(sp)))
-               return -EFAULT;
-
-       if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               return -EINVAL;
-
-       sp.parm.capture.extendedmode = 0;
-
-       if (sp.parm.capture.readbuffers == 0)
-               sp.parm.capture.readbuffers = cam->nreadbuffers;
-
-       if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
-               sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
-
-       if (copy_to_user(arg, &sp, sizeof(sp)))
-               return -EFAULT;
-
-       cam->nreadbuffers = sp.parm.capture.readbuffers;
-
-       return 0;
-}
-
-
-static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
-                             unsigned int cmd, void __user * arg)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-
-       switch (cmd) {
-
-       case VIDIOC_QUERYCAP:
-               return zc0301_vidioc_querycap(cam, arg);
-
-       case VIDIOC_ENUMINPUT:
-               return zc0301_vidioc_enuminput(cam, arg);
-
-       case VIDIOC_G_INPUT:
-               return zc0301_vidioc_g_input(cam, arg);
-
-       case VIDIOC_S_INPUT:
-               return zc0301_vidioc_s_input(cam, arg);
-
-       case VIDIOC_QUERYCTRL:
-               return zc0301_vidioc_query_ctrl(cam, arg);
-
-       case VIDIOC_G_CTRL:
-               return zc0301_vidioc_g_ctrl(cam, arg);
-
-       case VIDIOC_S_CTRL_OLD:
-       case VIDIOC_S_CTRL:
-               return zc0301_vidioc_s_ctrl(cam, arg);
-
-       case VIDIOC_CROPCAP_OLD:
-       case VIDIOC_CROPCAP:
-               return zc0301_vidioc_cropcap(cam, arg);
-
-       case VIDIOC_G_CROP:
-               return zc0301_vidioc_g_crop(cam, arg);
-
-       case VIDIOC_S_CROP:
-               return zc0301_vidioc_s_crop(cam, arg);
-
-       case VIDIOC_ENUM_FMT:
-               return zc0301_vidioc_enum_fmt(cam, arg);
-
-       case VIDIOC_G_FMT:
-               return zc0301_vidioc_g_fmt(cam, arg);
-
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT:
-               return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
-
-       case VIDIOC_G_JPEGCOMP:
-               return zc0301_vidioc_g_jpegcomp(cam, arg);
-
-       case VIDIOC_S_JPEGCOMP:
-               return zc0301_vidioc_s_jpegcomp(cam, arg);
-
-       case VIDIOC_REQBUFS:
-               return zc0301_vidioc_reqbufs(cam, arg);
-
-       case VIDIOC_QUERYBUF:
-               return zc0301_vidioc_querybuf(cam, arg);
-
-       case VIDIOC_QBUF:
-               return zc0301_vidioc_qbuf(cam, arg);
-
-       case VIDIOC_DQBUF:
-               return zc0301_vidioc_dqbuf(cam, filp, arg);
-
-       case VIDIOC_STREAMON:
-               return zc0301_vidioc_streamon(cam, arg);
-
-       case VIDIOC_STREAMOFF:
-               return zc0301_vidioc_streamoff(cam, arg);
-
-       case VIDIOC_G_PARM:
-               return zc0301_vidioc_g_parm(cam, arg);
-
-       case VIDIOC_S_PARM_OLD:
-       case VIDIOC_S_PARM:
-               return zc0301_vidioc_s_parm(cam, arg);
-
-       case VIDIOC_G_STD:
-       case VIDIOC_S_STD:
-       case VIDIOC_QUERYSTD:
-       case VIDIOC_ENUMSTD:
-       case VIDIOC_QUERYMENU:
-               return -EINVAL;
-
-       default:
-               return -EINVAL;
-
-       }
-}
-
-
-static int zc0301_ioctl(struct inode* inode, struct file* filp,
-                        unsigned int cmd, unsigned long arg)
-{
-       struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
-       int err = 0;
-
-       if (mutex_lock_interruptible(&cam->fileop_mutex))
-               return -ERESTARTSYS;
-
-       if (cam->state & DEV_DISCONNECTED) {
-               DBG(1, "Device not present");
-               mutex_unlock(&cam->fileop_mutex);
-               return -ENODEV;
-       }
-
-       if (cam->state & DEV_MISCONFIGURED) {
-               DBG(1, "The camera is misconfigured. Close and open it "
-                      "again.");
-               mutex_unlock(&cam->fileop_mutex);
-               return -EIO;
-       }
-
-       V4LDBG(3, "zc0301", cmd);
-
-       err = zc0301_ioctl_v4l2(inode, filp, cmd, (void __user *)arg);
-
-       mutex_unlock(&cam->fileop_mutex);
-
-       return err;
-}
-
-
-static struct file_operations zc0301_fops = {
-       .owner =   THIS_MODULE,
-       .open =    zc0301_open,
-       .release = zc0301_release,
-       .ioctl =   zc0301_ioctl,
-       .read =    zc0301_read,
-       .poll =    zc0301_poll,
-       .mmap =    zc0301_mmap,
-       .llseek =  no_llseek,
-};
-
-/*****************************************************************************/
-
-static int
-zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct zc0301_device* cam;
-       static unsigned int dev_nr = 0;
-       unsigned int i;
-       int err = 0;
-
-       if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
-               return -ENOMEM;
-
-       cam->usbdev = udev;
-
-       if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
-               DBG(1, "kmalloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       if (!(cam->v4ldev = video_device_alloc())) {
-               DBG(1, "video_device_alloc() failed");
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       mutex_init(&cam->dev_mutex);
-
-       DBG(2, "ZC0301 Image Processor and Control Chip detected "
-              "(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
-
-       for  (i = 0; zc0301_sensor_table[i]; i++) {
-               err = zc0301_sensor_table[i](cam);
-               if (!err)
-                       break;
-       }
-
-       if (!err)
-               DBG(2, "%s image sensor detected", cam->sensor.name);
-       else {
-               DBG(1, "No supported image sensor detected");
-               err = -ENODEV;
-               goto fail;
-       }
-
-       if (zc0301_init(cam)) {
-               DBG(1, "Initialization failed. I will retry on open().");
-               cam->state |= DEV_MISCONFIGURED;
-       }
-
-       strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
-       cam->v4ldev->owner = THIS_MODULE;
-       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
-       cam->v4ldev->hardware = 0;
-       cam->v4ldev->fops = &zc0301_fops;
-       cam->v4ldev->minor = video_nr[dev_nr];
-       cam->v4ldev->release = video_device_release;
-       video_set_drvdata(cam->v4ldev, cam);
-
-       mutex_lock(&cam->dev_mutex);
-
-       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
-                                   video_nr[dev_nr]);
-       if (err) {
-               DBG(1, "V4L2 device registration failed");
-               if (err == -ENFILE && video_nr[dev_nr] == -1)
-                       DBG(1, "Free /dev/videoX node not found");
-               video_nr[dev_nr] = -1;
-               dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-               mutex_unlock(&cam->dev_mutex);
-               goto fail;
-       }
-
-       DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
-
-       cam->module_param.force_munmap = force_munmap[dev_nr];
-       cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
-       dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-       usb_set_intfdata(intf, cam);
-
-       mutex_unlock(&cam->dev_mutex);
-
-       return 0;
-
-fail:
-       if (cam) {
-               kfree(cam->control_buffer);
-               if (cam->v4ldev)
-                       video_device_release(cam->v4ldev);
-               kfree(cam);
-       }
-       return err;
-}
-
-
-static void zc0301_usb_disconnect(struct usb_interface* intf)
-{
-       struct zc0301_device* cam = usb_get_intfdata(intf);
-
-       if (!cam)
-               return;
-
-       down_write(&zc0301_disconnect);
-
-       mutex_lock(&cam->dev_mutex);
-
-       DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
-       wake_up_interruptible_all(&cam->open);
-
-       if (cam->users) {
-               DBG(2, "Device /dev/video%d is open! Deregistration and "
-                      "memory deallocation are deferred on close.",
-                   cam->v4ldev->minor);
-               cam->state |= DEV_MISCONFIGURED;
-               zc0301_stop_transfer(cam);
-               cam->state |= DEV_DISCONNECTED;
-               wake_up_interruptible(&cam->wait_frame);
-               wake_up(&cam->wait_stream);
-               usb_get_dev(cam->usbdev);
-       } else {
-               cam->state |= DEV_DISCONNECTED;
-               zc0301_release_resources(cam);
-       }
-
-       mutex_unlock(&cam->dev_mutex);
-
-       if (!cam->users)
-               kfree(cam);
-
-       up_write(&zc0301_disconnect);
-}
-
-
-static struct usb_driver zc0301_usb_driver = {
-       .name =       "zc0301",
-       .id_table =   zc0301_id_table,
-       .probe =      zc0301_usb_probe,
-       .disconnect = zc0301_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init zc0301_module_init(void)
-{
-       int err = 0;
-
-       KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
-       KDBG(3, ZC0301_MODULE_AUTHOR);
-
-       if ((err = usb_register(&zc0301_usb_driver)))
-               KDBG(1, "usb_register() failed");
-
-       return err;
-}
-
-
-static void __exit zc0301_module_exit(void)
-{
-       usb_deregister(&zc0301_usb_driver);
-}
-
-
-module_init(zc0301_module_init);
-module_exit(zc0301_module_exit);
diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c
deleted file mode 100644 (file)
index 9d282a2..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image        *
- * Processor and Control Chip                                              *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * Initialization values of the ZC0301 have been taken from the SPCA5XX    *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-/*
-   NOTE: Sensor controls are disabled for now, becouse changing them while
-         streaming sometimes results in out-of-sync video frames. We'll use
-         the default initialization, until we know how to stop and start video
-         in the chip. However, the image quality still looks good under various
-         light conditions.
-*/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct zc0301_device* cam)
-{
-       int err = 0;
-
-       err += zc0301_write_reg(cam, 0x0002, 0x00);
-       err += zc0301_write_reg(cam, 0x0003, 0x02);
-       err += zc0301_write_reg(cam, 0x0004, 0x80);
-       err += zc0301_write_reg(cam, 0x0005, 0x01);
-       err += zc0301_write_reg(cam, 0x0006, 0xE0);
-       err += zc0301_write_reg(cam, 0x0098, 0x00);
-       err += zc0301_write_reg(cam, 0x009A, 0x03);
-       err += zc0301_write_reg(cam, 0x011A, 0x00);
-       err += zc0301_write_reg(cam, 0x011C, 0x03);
-       err += zc0301_write_reg(cam, 0x009B, 0x01);
-       err += zc0301_write_reg(cam, 0x009C, 0xE6);
-       err += zc0301_write_reg(cam, 0x009D, 0x02);
-       err += zc0301_write_reg(cam, 0x009E, 0x86);
-
-       err += zc0301_i2c_write(cam, 0x02, 0x02);
-       err += zc0301_i2c_write(cam, 0x0A, 0x01);
-       err += zc0301_i2c_write(cam, 0x0B, 0x01);
-       err += zc0301_i2c_write(cam, 0x0D, 0x00);
-       err += zc0301_i2c_write(cam, 0x12, 0x05);
-       err += zc0301_i2c_write(cam, 0x13, 0x63);
-       err += zc0301_i2c_write(cam, 0x15, 0x70);
-
-       err += zc0301_write_reg(cam, 0x0101, 0xB7);
-       err += zc0301_write_reg(cam, 0x0100, 0x0D);
-       err += zc0301_write_reg(cam, 0x0189, 0x06);
-       err += zc0301_write_reg(cam, 0x01AD, 0x00);
-       err += zc0301_write_reg(cam, 0x01C5, 0x03);
-       err += zc0301_write_reg(cam, 0x01CB, 0x13);
-       err += zc0301_write_reg(cam, 0x0250, 0x08);
-       err += zc0301_write_reg(cam, 0x0301, 0x08);
-       err += zc0301_write_reg(cam, 0x018D, 0x70);
-       err += zc0301_write_reg(cam, 0x0008, 0x03);
-       err += zc0301_write_reg(cam, 0x01C6, 0x04);
-       err += zc0301_write_reg(cam, 0x01CB, 0x07);
-       err += zc0301_write_reg(cam, 0x0120, 0x11);
-       err += zc0301_write_reg(cam, 0x0121, 0x37);
-       err += zc0301_write_reg(cam, 0x0122, 0x58);
-       err += zc0301_write_reg(cam, 0x0123, 0x79);
-       err += zc0301_write_reg(cam, 0x0124, 0x91);
-       err += zc0301_write_reg(cam, 0x0125, 0xA6);
-       err += zc0301_write_reg(cam, 0x0126, 0xB8);
-       err += zc0301_write_reg(cam, 0x0127, 0xC7);
-       err += zc0301_write_reg(cam, 0x0128, 0xD3);
-       err += zc0301_write_reg(cam, 0x0129, 0xDE);
-       err += zc0301_write_reg(cam, 0x012A, 0xE6);
-       err += zc0301_write_reg(cam, 0x012B, 0xED);
-       err += zc0301_write_reg(cam, 0x012C, 0xF3);
-       err += zc0301_write_reg(cam, 0x012D, 0xF8);
-       err += zc0301_write_reg(cam, 0x012E, 0xFB);
-       err += zc0301_write_reg(cam, 0x012F, 0xFF);
-       err += zc0301_write_reg(cam, 0x0130, 0x26);
-       err += zc0301_write_reg(cam, 0x0131, 0x23);
-       err += zc0301_write_reg(cam, 0x0132, 0x20);
-       err += zc0301_write_reg(cam, 0x0133, 0x1C);
-       err += zc0301_write_reg(cam, 0x0134, 0x16);
-       err += zc0301_write_reg(cam, 0x0135, 0x13);
-       err += zc0301_write_reg(cam, 0x0136, 0x10);
-       err += zc0301_write_reg(cam, 0x0137, 0x0D);
-       err += zc0301_write_reg(cam, 0x0138, 0x0B);
-       err += zc0301_write_reg(cam, 0x0139, 0x09);
-       err += zc0301_write_reg(cam, 0x013A, 0x07);
-       err += zc0301_write_reg(cam, 0x013B, 0x06);
-       err += zc0301_write_reg(cam, 0x013C, 0x05);
-       err += zc0301_write_reg(cam, 0x013D, 0x04);
-       err += zc0301_write_reg(cam, 0x013E, 0x03);
-       err += zc0301_write_reg(cam, 0x013F, 0x02);
-       err += zc0301_write_reg(cam, 0x010A, 0x4C);
-       err += zc0301_write_reg(cam, 0x010B, 0xF5);
-       err += zc0301_write_reg(cam, 0x010C, 0xFF);
-       err += zc0301_write_reg(cam, 0x010D, 0xF9);
-       err += zc0301_write_reg(cam, 0x010E, 0x51);
-       err += zc0301_write_reg(cam, 0x010F, 0xF5);
-       err += zc0301_write_reg(cam, 0x0110, 0xFB);
-       err += zc0301_write_reg(cam, 0x0111, 0xED);
-       err += zc0301_write_reg(cam, 0x0112, 0x5F);
-       err += zc0301_write_reg(cam, 0x0180, 0x00);
-       err += zc0301_write_reg(cam, 0x0019, 0x00);
-       err += zc0301_write_reg(cam, 0x0087, 0x20);
-       err += zc0301_write_reg(cam, 0x0088, 0x21);
-
-       err += zc0301_i2c_write(cam, 0x20, 0x02);
-       err += zc0301_i2c_write(cam, 0x21, 0x1B);
-       err += zc0301_i2c_write(cam, 0x03, 0x44);
-       err += zc0301_i2c_write(cam, 0x0E, 0x01);
-       err += zc0301_i2c_write(cam, 0x0F, 0x00);
-
-       err += zc0301_write_reg(cam, 0x01A9, 0x14);
-       err += zc0301_write_reg(cam, 0x01AA, 0x24);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0191, 0x02);
-       err += zc0301_write_reg(cam, 0x0192, 0x1B);
-       err += zc0301_write_reg(cam, 0x0195, 0x00);
-       err += zc0301_write_reg(cam, 0x0196, 0x00);
-       err += zc0301_write_reg(cam, 0x0197, 0x4D);
-       err += zc0301_write_reg(cam, 0x018C, 0x10);
-       err += zc0301_write_reg(cam, 0x018F, 0x20);
-       err += zc0301_write_reg(cam, 0x001D, 0x44);
-       err += zc0301_write_reg(cam, 0x001E, 0x6F);
-       err += zc0301_write_reg(cam, 0x001F, 0xAD);
-       err += zc0301_write_reg(cam, 0x0020, 0xEB);
-       err += zc0301_write_reg(cam, 0x0087, 0x0F);
-       err += zc0301_write_reg(cam, 0x0088, 0x0E);
-       err += zc0301_write_reg(cam, 0x0180, 0x40);
-       err += zc0301_write_reg(cam, 0x0192, 0x1B);
-       err += zc0301_write_reg(cam, 0x0191, 0x02);
-       err += zc0301_write_reg(cam, 0x0190, 0x00);
-       err += zc0301_write_reg(cam, 0x0116, 0x1D);
-       err += zc0301_write_reg(cam, 0x0117, 0x40);
-       err += zc0301_write_reg(cam, 0x0118, 0x99);
-       err += zc0301_write_reg(cam, 0x0180, 0x42);
-       err += zc0301_write_reg(cam, 0x0116, 0x1D);
-       err += zc0301_write_reg(cam, 0x0117, 0x40);
-       err += zc0301_write_reg(cam, 0x0118, 0x99);
-       err += zc0301_write_reg(cam, 0x0007, 0x00);
-
-       err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-       msleep(100);
-
-       return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct zc0301_device* cam,
-                              struct v4l2_control* ctrl)
-{
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               {
-                       int r1 = zc0301_i2c_read(cam, 0x04, 1),
-                           r2 = zc0301_i2c_read(cam, 0x05, 1);
-                       if (r1 < 0 || r2 < 0)
-                               return -EIO;
-                       ctrl->value = (r1 << 6) | (r2 & 0x3f);
-               }
-               return 0;
-       case V4L2_CID_RED_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_BLUE_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case V4L2_CID_GAIN:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x1f;
-               return 0;
-       case ZC0301_V4L2_CID_GREEN_BALANCE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
-                       return -EIO;
-               ctrl->value &= 0x0f;
-               return 0;
-       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-               if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
-                       return -EIO;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-
-static int pas202bcb_set_ctrl(struct zc0301_device* cam,
-                              const struct v4l2_control* ctrl)
-{
-       int err = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE:
-               err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
-               err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
-               break;
-       case V4L2_CID_RED_BALANCE:
-               err += zc0301_i2c_write(cam, 0x09, ctrl->value);
-               break;
-       case V4L2_CID_BLUE_BALANCE:
-               err += zc0301_i2c_write(cam, 0x07, ctrl->value);
-               break;
-       case V4L2_CID_GAIN:
-               err += zc0301_i2c_write(cam, 0x10, ctrl->value);
-               break;
-       case ZC0301_V4L2_CID_GREEN_BALANCE:
-               err += zc0301_i2c_write(cam, 0x08, ctrl->value);
-               break;
-       case ZC0301_V4L2_CID_DAC_MAGNITUDE:
-               err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
-               break;
-       default:
-               return -EINVAL;
-       }
-       err += zc0301_i2c_write(cam, 0x11, 0x01);
-
-       return err ? -EIO : 0;
-}
-
-
-static struct zc0301_sensor pas202bcb = {
-       .name = "PAS202BCB",
-       .init = &pas202bcb_init,
-       .qctrl = {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x01e5,
-                       .maximum = 0x3fff,
-                       .step = 0x0001,
-                       .default_value = 0x01e5,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "global gain",
-                       .minimum = 0x00,
-                       .maximum = 0x1f,
-                       .step = 0x01,
-                       .default_value = 0x0c,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_RED_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "red balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x01,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = V4L2_CID_BLUE_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "blue balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x05,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_GREEN_BALANCE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "green balance",
-                       .minimum = 0x00,
-                       .maximum = 0x0f,
-                       .step = 0x01,
-                       .default_value = 0x00,
-                       .flags = V4L2_CTRL_FLAG_DISABLED,
-               },
-       },
-       .get_ctrl = &pas202bcb_get_ctrl,
-       .set_ctrl = &pas202bcb_set_ctrl,
-       .cropcap = {
-               .bounds = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-               .defrect = {
-                       .left = 0,
-                       .top = 0,
-                       .width = 640,
-                       .height = 480,
-               },
-       },
-       .pix_format = {
-               .width = 640,
-               .height = 480,
-               .pixelformat = V4L2_PIX_FMT_JPEG,
-               .priv = 8,
-       },
-};
-
-
-int zc0301_probe_pas202bcb(struct zc0301_device* cam)
-{
-       int r0 = 0, r1 = 0, err = 0;
-       unsigned int pid = 0;
-
-       err += zc0301_write_reg(cam, 0x0000, 0x01);
-       err += zc0301_write_reg(cam, 0x0010, 0x0e);
-       err += zc0301_write_reg(cam, 0x0001, 0x01);
-       err += zc0301_write_reg(cam, 0x0012, 0x03);
-       err += zc0301_write_reg(cam, 0x0012, 0x01);
-       err += zc0301_write_reg(cam, 0x008d, 0x08);
-
-       msleep(10);
-
-       r0 = zc0301_i2c_read(cam, 0x00, 1);
-       r1 = zc0301_i2c_read(cam, 0x01, 1);
-
-       if (r0 < 0 || r1 < 0 || err)
-               return -EIO;
-
-       pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
-       if (pid != 0x017)
-               return -ENODEV;
-
-       zc0301_attach_sensor(cam, &pas202bcb);
-
-       return 0;
-}
diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h
deleted file mode 100644 (file)
index cf0965a..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and       *
- * Control Chip                                                            *
- *                                                                         *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>       *
- *                                                                         *
- * This program is free software; you can redistribute it and/or modify    *
- * it under the terms of the GNU General Public License as published by    *
- * the Free Software Foundation; either version 2 of the License, or       *
- * (at your option) any later version.                                     *
- *                                                                         *
- * This program is distributed in the hope that it will be useful,         *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
- * GNU General Public License for more details.                            *
- *                                                                         *
- * You should have received a copy of the GNU General Public License       *
- * along with this program; if not, write to the Free Software             *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
- ***************************************************************************/
-
-#ifndef _ZC0301_SENSOR_H_
-#define _ZC0301_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct zc0301_device;
-struct zc0301_sensor;
-
-/*****************************************************************************/
-
-extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
-
-#define ZC0301_SENSOR_TABLE                                                   \
-/* Weak detections must go at the end of the list */                          \
-static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
-       &zc0301_probe_pas202bcb,                                              \
-       NULL,                                                                 \
-};
-
-extern struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
-
-extern void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
-
-#define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
-                      USB_DEVICE_ID_MATCH_INT_CLASS,                         \
-       .idVendor = (vend),                                                   \
-       .idProduct = (prod),                                                  \
-       .bInterfaceClass = (intclass)
-
-#define ZC0301_ID_TABLE                                                       \
-static const struct usb_device_id zc0301_id_table[] =  {                      \
-       { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */           \
-       { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */            \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
-       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
-       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
-       { }                                                                   \
-};
-
-/*****************************************************************************/
-
-extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
-extern int zc0301_read_reg(struct zc0301_device*, u16 index);
-extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
-extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
-
-/*****************************************************************************/
-
-#define ZC0301_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
-#define ZC0301_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
-
-struct zc0301_sensor {
-       char name[32];
-
-       struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
-       struct v4l2_cropcap cropcap;
-       struct v4l2_pix_format pix_format;
-
-       int (*init)(struct zc0301_device*);
-       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct zc0301_device*,
-                       const struct v4l2_control* ctrl);
-       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
-
-       /* Private */
-       struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
-       struct v4l2_rect _rect;
-};
-
-#endif /* _ZC0301_SENSOR_H_ */
This page took 1.861715 seconds and 5 git commands to generate.