On Fri, Mar 24, 2000, Dunlap, Randy <[EMAIL PROTECTED]> wrote:
> Last error was as modules.  Sorry about not saying that.

Actually, you did say that, I was just curious since I don't get that error
while compiling as modules, and now compiling into the kernel, I see I
get that error.

I also forgot to rip out the 2.2 code for the core and PP driver. I've done
it in this patch.

I've attached a patch to fix these problems. It compiles into modules and
into the kernel now, without any of the 2.2 compatibility code.

> Yep, I could need to upgrade some things.
> Would you compare and let me know?
> 
> patch 2.5
> gcc: egcs-2.91.66
> binutils: 2.9.1.0.25

Same here.

JE

diff -urN linux-2.3.99-pre3.orig/Documentation/Configure.help 
linux-2.3.99-pre3/Documentation/Configure.help
--- linux-2.3.99-pre3.orig/Documentation/Configure.help Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/Documentation/Configure.help      Fri Mar 24 13:57:52 2000
@@ -9203,22 +9203,6 @@
   The module will be called printer.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-USB CPiA Camera support
-CONFIG_USB_CPIA
-  Say Y here if you want to connect this type of camera to your
-  computer's USB port.
-
-  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 on the WWW at
-  http://roadrunner.swansea.uk.linux.org/v4l.shtml .
-
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called cpia.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
-
 USB IBM (Xirlink) C-It Camera support
 CONFIG_USB_IBMCAM
   Say Y here if you want to connect this type of camera to your
@@ -14915,6 +14899,31 @@
   Here you find the drivers which allow you to use the i2c-* device 
   files, usually found in the /dev directory on your system. They
   make it possible to have user-space programs use the I2C bus.
+
+CPiA Video For Linux
+CONFIG_VIDEO_CPIA
+  This is the video4linux driver for cameras based on Vision's CPiA
+  (Colour Processor Interface ASIC), such as the Creative Labs Video
+  Blaster Webcam II. If you have one of these cameras, say Y here
+  and select parallel port and/or USB lowlevel support below,
+  otherwise say N. This will not work with the Creative Webcam III.
+  It is also available as a module (cpia.o).
+
+CPiA Parallel Port Lowlevel Support
+CONFIG_VIDEO_CPIA_PP
+  This is the lowlevel parallel port support for cameras based on
+  Vision's CPiA (Colour Processor Interface ASIC), such as the
+  Creative Webcam II. If you have the parallel port version of one
+  of these cameras, say Y here, otherwise say N. It is also available
+  as a module (cpia_pp.o).
+
+CPiA USB Lowlevel Support
+CONFIG_VIDEO_CPIA_USB
+  This is the lowlevel USB support for cameras based on Vision's CPiA
+  (Colour Processor Interface ASIC), such as the Creative Webcam II.
+  If you have the USB version of one of these cameras, say Y here,
+  otherwise say N. This will not work with the Creative Webcam III.
+  It is also available as a module (cpia_usb.o).
 
 #
 # A couple of things I keep forgetting:
diff -urN linux-2.3.99-pre3.orig/Documentation/video4linux/README.cpia 
linux-2.3.99-pre3/Documentation/video4linux/README.cpia
--- linux-2.3.99-pre3.orig/Documentation/video4linux/README.cpia        Wed Dec 31 
16:00:00 1969
+++ linux-2.3.99-pre3/Documentation/video4linux/README.cpia     Fri Mar 24 13:57:52 
+2000
@@ -0,0 +1,191 @@
+This is a driver for the CPiA PPC2 driven parallel connected
+Camera. For example the Creative WebcamII is CPiA driven.
+
+   ) [1]Peter Pregler, Linz 2000, published under the [2]GNU GPL
+
+---------------------------------------------------------------------------
+
+USAGE:
+
+General:
+========
+
+1) Make sure you have created the video devices (/dev/video*):
+
+- if you have a recent MAKEDEV do a 'cd /dev;./MAKEDEV video'
+- otherwise do a:
+
+cd /dev
+mknod video0 c 81 0
+ln -s video0 video
+
+2) Compile the kernel (see below for the list of options to use),
+   configure your parport and reboot.
+
+3) If all worked well you should get messages similar
+   to the following (your versions may be different) on the console:
+
+V4L-Driver for Vision CPiA based cameras v0.7.4
+parport0: read2 timeout.
+parport0: Multimedia device, VLSI Vision Ltd PPC2
+Parallel port driver for Vision CPiA based camera
+  CPIA Version: 1.20 (2.0)
+  CPIA PnP-ID: 0553:0002:0100
+  VP-Version: 1.0 0100
+  1 camera(s) found
+
+
+As modules:
+===========
+
+Make sure you have selected the following kernel options (you can
+select all stuff as modules):
+
+The cpia-stuff is in the section 'Character devices -> Video For Linux'.
+
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_1284=y
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_PP=m
+
+For autoloading of all those modules you need to tell kerneld some
+stuff. Add the following line to your kerneld config-file
+(e.g. /etc/modules.conf or wherever your distribution does store that
+stuff):
+
+options parport_pc dma=3 irq=7
+alias char-major-81 cpia_pp
+
+The first line tells the dma/irq channels to use. Those _must_ match
+the settings of your BIOS. Do NOT simply use the values above.  See
+Documentation/parport.txt for more information about this. The second
+line associates the video-device file with the driver. Of cause you
+can also load the modules once upon boot (usually done in /etc/modules).
+
+Linked into the kernel:
+=======================
+
+Make sure you have selected the following kernel options. Note that
+you cannot compile the parport-stuff as modules and the cpia-driver
+statically (the other way round is okay though).
+
+The cpia-stuff is in the section 'Character devices -> Video For Linux'.
+
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_PARPORT_1284=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_CPIA=y
+CONFIG_VIDEO_CPIA_PP=y
+
+To use DMA/irq you will need to tell the kernel upon boot time the
+hardware configuration of the parport. You can give the boot-parameter
+at the LILO-prompt or specify it in lilo.conf. I use the following
+append-line in lilo.conf:
+
+        append="parport=0x378,7,3"
+
+See Documentation/parport.txt for more information about the
+configuration of the parport and the values given above. Do not simply
+use the values given above.
+
+---------------------------------------------------------------------------
+FEATURES:
+
+- mmap/read v4l-interface (but no overlay)
+- image formats: CIF/QCIF, SIF/QSIF, various others used by isabel;
+  note: all sizes except CIF/QCIF are implemented by clipping, i.e.
+  pixels are not uploaded from the camera
+- palettes: VIDEO_PALETTE_GRAY, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB555,
+  VIDEO_PALETTE_RGB24, VIDEO_PALETTE_RGB32, VIDEO_PALETTE_YUYV,
+  VIDEO_PALETTE_UYVY, VIDEO_PALETTE_YUV422
+- state information (color balance, exposure, ...) is preserved between
+  device opens
+- complete control over camera via proc-interface (_all_ camera settings are
+  supported), there is also a python-gtk application available for this [3]
+- works under SMP (but the driver is completly serialized and synchronous)
+  so you get no benefit from SMP, but at least it does not crash your box
+- might work for non-Intel architecture, let us know about this
+
+---------------------------------------------------------------------------
+TESTED APPLICATIONS:
+
+- a simple test application based on Xt is available at [3]
+- another test-application based on gqcam-0.4 (uses GTK)
+- gqcam-0.6 should work
+- xawtv-3.x (also the webcam software)
+- xawtv-2.46
+- w3cam (cgi-interface and vidcat, e.g. you may try out 'vidcat  |xv
+  -maxpect -root -quit +noresetroot -rmode 5 -')
+- vic, the MBONE video conferencing tool (version 2.8ucl4-1)
+- isabel 3R4beta (barely working, but AFAICT all the problems are on
+  their side)
+- camserv-0.40
+
+See [3] for pointers to v4l-applications.
+
+---------------------------------------------------------------------------
+KNOWN PROBLEMS:
+
+- some applications do not handle the image format correctly, you will
+  see strange horizontal stripes instead of a nice picture -> make sure
+  your application does use a supported image size or queries the driver
+  for the actually used size (reason behind this: the camera cannot
+  provide any image format, so if size NxM is requested the driver will
+  use a format to the closest fitting N1xM1, the application should now
+  query for this granted size, most applications do not).
+- all the todo ;)
+- if there is not enough light and the picture is too dark try to
+  adjust the SetSensorFPS setting, automatic frame rate adjustment
+  has its price
+- do not try out isabel 3R4beta (built 135), you will be disappointed
+
+---------------------------------------------------------------------------
+TODO:
+
+- multiple camera support (struct camera or something) - This should work,
+  but hasn't been tested yet.
+- architecture independence?
+- SMP-safe asynchronous mmap interface
+- nibble mode for old parport interfaces
+- streaming capture, this should give a performance gain
+
+---------------------------------------------------------------------------
+IMPLEMENTATION NOTES:
+
+The camera can act in two modes, streaming or grabbing. Right now a
+polling grab-scheme is used. Maybe interrupt driven streaming will be
+used for a ansychronous mmap interface in the next major release of the
+driver. This might give a better frame rate.
+
+---------------------------------------------------------------------------
+THANKS (in no particular order):
+
+- Scott J. Bertin <[EMAIL PROTECTED]> for cleanups, the proc-filesystem
+  and much more
+- Henry Bruce <[EMAIL PROTECTED]> for providing developers information about
+  the CPiA chip, I wish all companies would treat Linux as seriously
+- Karoly Erdei <[EMAIL PROTECTED]> and RISC-Linz for being
+  my boss ;) resp. my employer and for providing me the hardware and
+  allow me to devote some working time to this project
+- Manuel J. Petit de Gabriel <[EMAIL PROTECTED]> for providing help
+  with Isabel (http://isabel.dit.upm.es/)
+- Bas Huisman <[EMAIL PROTECTED]> for writing the initial parport code
+- Jarl Totland <[EMAIL PROTECTED]> for setting up the mailing list 
+  and maintaining the web-server[3]
+- Chris Whiteford <[EMAIL PROTECTED]> for fixes related to the
+  1.02 firmware
+- special kudos to all the tester whose machines crashed and/or
+  will crash. :)
+
+---------------------------------------------------------------------------
+REFERENCES
+
+   1. http://www.risc.uni-linz.ac.at/people/ppregler
+      mailto:[EMAIL PROTECTED]
+   2. see the file COPYING in the top directory of the kernel tree
+   3. http://webcam.sourceforge.net/
diff -urN linux-2.3.99-pre3.orig/drivers/char/Config.in 
linux-2.3.99-pre3/drivers/char/Config.in
--- linux-2.3.99-pre3.orig/drivers/char/Config.in       Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/char/Config.in    Fri Mar 24 13:59:23 2000
@@ -209,6 +209,15 @@
         dep_tristate '  QuickCam Colour Video For Linux (EXPERIMENTAL)' 
CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
       fi
    fi
+   dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
+   if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
+     if [ "CONFIG_PARPORT_1284" != "n" ]; then
+       dep_tristate 'CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP 
+$CONFIG_VIDEO_CPIA $CONFIG_PARPORT
+     fi
+     if [ "$CONFIG_USB" != "n" ]; then
+       dep_tristate 'CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB 
+$CONFIG_VIDEO_CPIA $CONFIG_USB
+     fi
+   fi
    dep_tristate '  SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV 
$CONFIG_I2C
    dep_tristate '  SAB3036 tuner' CONFIG_TUNER_3036 $CONFIG_VIDEO_DEV $CONFIG_I2C
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -urN linux-2.3.99-pre3.orig/drivers/char/Makefile 
linux-2.3.99-pre3/drivers/char/Makefile
--- linux-2.3.99-pre3.orig/drivers/char/Makefile        Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/char/Makefile     Fri Mar 24 13:57:52 2000
@@ -38,7 +38,7 @@
 
 export-objs     :=     busmouse.o console.o i2c-old.o keyboard.o sysrq.o \
                        misc.o pty.o random.o selection.o serial.o videodev.o \
-                       tty_io.o bttv.o
+                       tty_io.o bttv.o cpia.o
 
 KEYMAP   =defkeymap.o
 KEYBD    =pc_keyb.o
@@ -252,6 +252,9 @@
 obj-$(CONFIG_VIDEO_PLANB) += planb.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
+obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o
 obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o
 obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o
diff -urN linux-2.3.99-pre3.orig/drivers/char/cpia.c 
linux-2.3.99-pre3/drivers/char/cpia.c
--- linux-2.3.99-pre3.orig/drivers/char/cpia.c  Wed Dec 31 16:00:00 1969
+++ linux-2.3.99-pre3/drivers/char/cpia.c       Fri Mar 24 14:27:09 2000
@@ -0,0 +1,3319 @@
+/*
+ * cpia CPiA driver
+ *
+ * Supports CPiA based Video Camera's.
+ *
+ * (C) Copyright 1999-2000 Peter Pregler,
+ * (C) Copyright 1999-2000 Scott J. Bertin,
+ * (C) Copyright 1999-2000 Johannes Erdfelt, [EMAIL PROTECTED]
+ *
+ * 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.
+ */
+
+/* #define _CPIA_DEBUG_                define for verbose debug output */
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "cpia.h"
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+extern int cpia_pp_init(void);
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB
+extern int cpia_usb_init(void);
+#endif
+
+#ifdef MODULE
+MODULE_AUTHOR("Scott J. Bertin <[EMAIL PROTECTED]> & Peter Pregler 
+<[EMAIL PROTECTED]> & Johannes Erdfelt <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
+MODULE_SUPPORTED_DEVICE("video");
+#endif
+
+#define ABOUT "V4L-Driver for Vision CPiA based cameras"
+
+#ifndef VID_HARDWARE_CPIA
+#define VID_HARDWARE_CPIA 24    /* FIXME -> from linux/videodev.h */
+#endif
+
+#define CPIA_MODULE_CPIA                       (0<<5)
+#define CPIA_MODULE_SYSTEM                     (1<<5)
+#define CPIA_MODULE_VP_CTRL                    (5<<5)
+#define CPIA_MODULE_CAPTURE                    (6<<5)
+#define CPIA_MODULE_DEBUG                      (7<<5)
+
+#define INPUT (DATA_IN << 8)
+#define OUTPUT (DATA_OUT << 8)
+
+#define CPIA_COMMAND_GetCPIAVersion    (INPUT | CPIA_MODULE_CPIA | 1)
+#define CPIA_COMMAND_GetPnPID          (INPUT | CPIA_MODULE_CPIA | 2)
+#define CPIA_COMMAND_GetCameraStatus   (INPUT | CPIA_MODULE_CPIA | 3)
+#define CPIA_COMMAND_GotoHiPower       (OUTPUT | CPIA_MODULE_CPIA | 4)
+#define CPIA_COMMAND_GotoLoPower       (OUTPUT | CPIA_MODULE_CPIA | 5)
+#define CPIA_COMMAND_GotoSuspend       (OUTPUT | CPIA_MODULE_CPIA | 7)
+#define CPIA_COMMAND_GotoPassThrough   (OUTPUT | CPIA_MODULE_CPIA | 8)
+#define CPIA_COMMAND_ModifyCameraStatus        (OUTPUT | CPIA_MODULE_CPIA | 10)
+
+#define CPIA_COMMAND_ReadVCRegs                (INPUT | CPIA_MODULE_SYSTEM | 1)
+#define CPIA_COMMAND_WriteVCReg                (OUTPUT | CPIA_MODULE_SYSTEM | 2)
+#define CPIA_COMMAND_ReadMCPorts       (INPUT | CPIA_MODULE_SYSTEM | 3)
+#define CPIA_COMMAND_WriteMCPort       (OUTPUT | CPIA_MODULE_SYSTEM | 4)
+#define CPIA_COMMAND_SetBaudRate       (OUTPUT | CPIA_MODULE_SYSTEM | 5)
+#define CPIA_COMMAND_SetECPTiming      (OUTPUT | CPIA_MODULE_SYSTEM | 6)
+#define CPIA_COMMAND_ReadIDATA         (INPUT | CPIA_MODULE_SYSTEM | 7)
+#define CPIA_COMMAND_WriteIDATA                (OUTPUT | CPIA_MODULE_SYSTEM | 8)
+#define CPIA_COMMAND_GenericCall       (OUTPUT | CPIA_MODULE_SYSTEM | 9)
+#define CPIA_COMMAND_I2CStart          (OUTPUT | CPIA_MODULE_SYSTEM | 10)
+#define CPIA_COMMAND_I2CStop           (OUTPUT | CPIA_MODULE_SYSTEM | 11)
+#define CPIA_COMMAND_I2CWrite          (OUTPUT | CPIA_MODULE_SYSTEM | 12)
+#define CPIA_COMMAND_I2CRead           (INPUT | CPIA_MODULE_SYSTEM | 13)
+
+#define CPIA_COMMAND_GetVPVersion      (INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_SetColourParams   (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
+#define CPIA_COMMAND_SetExposure       (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
+#define CPIA_COMMAND_SetColourBalance  (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
+#define CPIA_COMMAND_SetSensorFPS      (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
+#define CPIA_COMMAND_SetVPDefaults     (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
+#define CPIA_COMMAND_SetApcor          (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
+#define CPIA_COMMAND_SetFlickerCtrl    (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
+#define CPIA_COMMAND_SetVLOffset       (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
+#define CPIA_COMMAND_GetColourParams   (INPUT | CPIA_MODULE_VP_CTRL | 16)
+#define CPIA_COMMAND_GetColourBalance  (INPUT | CPIA_MODULE_VP_CTRL | 17)
+#define CPIA_COMMAND_GetExposure       (INPUT | CPIA_MODULE_VP_CTRL | 18)
+#define CPIA_COMMAND_SetSensorMatrix   (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
+#define CPIA_COMMAND_ColourBars                (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
+#define CPIA_COMMAND_ReadVPRegs                (INPUT | CPIA_MODULE_VP_CTRL | 30)
+#define CPIA_COMMAND_WriteVPReg                (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
+
+#define CPIA_COMMAND_GrabFrame         (OUTPUT | CPIA_MODULE_CAPTURE | 1)
+#define CPIA_COMMAND_UploadFrame       (OUTPUT | CPIA_MODULE_CAPTURE | 2)
+#define CPIA_COMMAND_SetGrabMode       (OUTPUT | CPIA_MODULE_CAPTURE | 3)
+#define CPIA_COMMAND_InitStreamCap     (OUTPUT | CPIA_MODULE_CAPTURE | 4)
+#define CPIA_COMMAND_FiniStreamCap     (OUTPUT | CPIA_MODULE_CAPTURE | 5)
+#define CPIA_COMMAND_StartStreamCap    (OUTPUT | CPIA_MODULE_CAPTURE | 6)
+#define CPIA_COMMAND_EndStreamCap      (OUTPUT | CPIA_MODULE_CAPTURE | 7)
+#define CPIA_COMMAND_SetFormat         (OUTPUT | CPIA_MODULE_CAPTURE | 8)
+#define CPIA_COMMAND_SetROI            (OUTPUT | CPIA_MODULE_CAPTURE | 9)
+#define CPIA_COMMAND_SetCompression    (OUTPUT | CPIA_MODULE_CAPTURE | 10)
+#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
+#define CPIA_COMMAND_SetYUVThresh      (OUTPUT | CPIA_MODULE_CAPTURE | 12)
+#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
+#define CPIA_COMMAND_DiscardFrame      (OUTPUT | CPIA_MODULE_CAPTURE | 14)
+
+#define CPIA_COMMAND_OutputRS232       (OUTPUT | CPIA_MODULE_DEBUG | 1)
+#define CPIA_COMMAND_AbortProcess      (OUTPUT | CPIA_MODULE_DEBUG | 4)
+#define CPIA_COMMAND_SetDramPage       (OUTPUT | CPIA_MODULE_DEBUG | 5)
+#define CPIA_COMMAND_StartDramUpload   (OUTPUT | CPIA_MODULE_DEBUG | 6)
+#define CPIA_COMMAND_StartDummyDtream  (OUTPUT | CPIA_MODULE_DEBUG | 8)
+#define CPIA_COMMAND_AbortStream       (OUTPUT | CPIA_MODULE_DEBUG | 9)
+#define CPIA_COMMAND_DownloadDRAM      (OUTPUT | CPIA_MODULE_DEBUG | 10)
+
+enum {
+       FRAME_READY,            /* Ready to grab into */
+       FRAME_GRABBING,         /* In the process of being grabbed into */
+       FRAME_DONE,             /* Finished grabbing, but not been synced yet */
+       FRAME_UNUSED,           /* Unused (no MCAPTURE) */
+};
+
+#define COMMAND_NONE                   0x0000
+#define COMMAND_SETCOMPRESSION         0x0001
+#define COMMAND_SETCOMPRESSIONTARGET   0x0002
+#define COMMAND_SETCOLOURPARAMS                0x0004
+#define COMMAND_SETFORMAT              0x0008
+#define COMMAND_PAUSE                  0x0010
+#define COMMAND_RESUME                 0x0020
+#define COMMAND_SETYUVTHRESH           0x0040
+#define COMMAND_SETECPTIMING           0x0080
+#define COMMAND_SETCOMPRESSIONPARAMS   0x0100
+#define COMMAND_SETEXPOSURE            0x0200
+#define COMMAND_SETCOLOURBALANCE       0x0400
+#define COMMAND_SETSENSORFPS           0x0800
+#define COMMAND_SETAPCOR               0x1000
+#define COMMAND_SETFLICKERCTRL         0x2000
+#define COMMAND_SETVLOFFSET            0x4000
+
+/* Developer's Guide Table 5 p 3-34
+ * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
+static u8 flicker_jumps[2][2][4] =
+{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
+  { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
+};
+
+/* forward declaration of local function */
+static void reset_camera_struct(struct cam_data *cam);
+
+/**********************************************************************
+ *
+ * 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
+ *
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+       unsigned long ret = 0UL;
+       pmd_t *pmd;
+       pte_t *ptep, pte;
+
+       if (!pgd_none(*pgd)) {
+               pmd = pmd_offset(pgd, adr);
+               if (!pmd_none(*pmd)) {
+                       ptep = pte_offset(pmd, adr);
+                       pte = *ptep;
+                       if (pte_present(pte))
+                               ret = page_address(pte_page(pte)) |
+                                     (adr & (PAGE_SIZE-1));
+               }
+       }
+       return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+       unsigned long va, kva, ret;
+
+       va = VMALLOC_VMADDR(adr);
+       kva = uvirt_to_kva(pgd_offset_k(va), va);
+       ret = __pa(kva);
+       return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+       void *mem;
+       unsigned long adr, page;
+
+       /* Round it off to PAGE_SIZE */
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       mem = vmalloc(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) {
+               page = kvirt_to_pa(adr);
+               mem_map_reserve(MAP_NR(__va(page)));
+               adr += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+       unsigned long adr, page;
+
+       if (!mem)
+               return;
+
+       size += (PAGE_SIZE - 1);
+       size &= ~(PAGE_SIZE - 1);
+
+       adr = (unsigned long) mem;
+       while (size > 0) {
+               page = kvirt_to_pa(adr);
+               mem_map_unreserve(MAP_NR(__va(page)));
+               adr += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+       vfree(mem);
+}
+
+/**********************************************************************
+ *
+ * /proc interface
+ *
+ **********************************************************************/
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *cpia_proc_root=NULL;
+
+static int cpia_read_proc(char *page, char **start, off_t off,
+                          int count, int *eof, void *data)
+{
+       char *out = page;
+       int len, tmp;
+       struct cam_data *cam = data;
+       char tmpstr[20];
+
+       /* IMPORTANT: This output MUST be kept under PAGE_SIZE
+        *            or we need to get more sophisticated. */
+
+       out += sprintf(out, "read-only\n-----------------------\n");
+       out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
+                      CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+       out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
+                      cam->params.version.firmwareVersion,
+                      cam->params.version.firmwareRevision,
+                      cam->params.version.vcVersion,
+                      cam->params.version.vcRevision);
+       out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
+                      cam->params.pnpID.vendor, cam->params.pnpID.product,
+                      cam->params.pnpID.deviceRevision);
+       out += sprintf(out, "VP-Version:               %d.%d %04x\n",
+                      cam->params.vpVersion.vpVersion,
+                      cam->params.vpVersion.vpRevision,
+                      cam->params.vpVersion.cameraHeadID);
+       
+       out += sprintf(out, "system_state:             %#04x\n",
+                      cam->params.status.systemState);
+       out += sprintf(out, "grab_state:               %#04x\n",
+                      cam->params.status.grabState);
+       out += sprintf(out, "stream_state:             %#04x\n",
+                      cam->params.status.streamState);
+       out += sprintf(out, "fatal_error:              %#04x\n",
+                      cam->params.status.fatalError);
+       out += sprintf(out, "cmd_error:                %#04x\n",
+                      cam->params.status.cmdError);
+       out += sprintf(out, "debug_flags:              %#04x\n",
+                      cam->params.status.debugFlags);
+       out += sprintf(out, "vp_status:                %#04x\n",
+                      cam->params.status.vpStatus);
+       out += sprintf(out, "error_code:               %#04x\n",
+                      cam->params.status.errorCode);
+       out += sprintf(out, "video_size:               %s\n",
+                      cam->params.format.videoSize == VIDEOSIZE_CIF ?
+                      "CIF " : "QCIF");
+       out += sprintf(out, "sub_sample:               %s\n",
+                      cam->params.format.subSample == SUBSAMPLE_420 ?
+                      "420" : "422");
+       out += sprintf(out, "yuv_order:                %s\n",
+                      cam->params.format.yuvOrder == YUVORDER_YUYV ?
+                      "YUYV" : "UYVY");
+       out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
+                      cam->params.roi.colStart*8,
+                      cam->params.roi.rowStart*4,
+                      cam->params.roi.colEnd*8,
+                      cam->params.roi.rowEnd*4);
+       out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
+       out += sprintf(out, "transfer_rate:            %4dkB/s\n",
+                      cam->transfer_rate);
+       
+       out += sprintf(out, "\nread-write\n");
+       out += sprintf(out, "-----------------------  current       min"
+                      "       max   default  comment\n");
+       out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
+                      cam->params.colourParams.brightness, 0, 100, 50);
+       if (cam->params.version.firmwareVersion == 1 &&
+          cam->params.version.firmwareRevision == 2)
+               /* 1-02 firmware limits contrast to 80 */
+               tmp = 80;
+       else
+               tmp = 96;
+
+       out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
+                      "  steps of 8\n",
+                      cam->params.colourParams.contrast, 0, tmp, 48);
+       out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
+                      cam->params.colourParams.saturation, 0, 100, 50);
+       tmp = (25000+5000*cam->params.sensorFps.baserate)/
+             (1<<cam->params.sensorFps.divisor);
+       out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
+                      tmp/1000, tmp%1000, 3, 30, 15);
+       out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
+                      2*cam->params.streamStartLine, 0,
+                      cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
+                      cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
+       out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
+                      cam->params.ecpTiming ? "slow" : "normal", "slow",
+                      "normal", "normal");
+
+       if (cam->params.colourBalance.balanceModeIsAuto) {
+               sprintf(tmpstr, "auto");
+       } else {
+               sprintf(tmpstr, "manual");
+       }
+       out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
+                      "  %8s\n",  tmpstr, "manual", "auto", "auto");
+       out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
+                      cam->params.colourBalance.redGain, 0, 212, 32);
+       out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
+                      cam->params.colourBalance.greenGain, 0, 212, 6);
+       out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
+                      cam->params.colourBalance.blueGain, 0, 212, 92);
+
+       if (cam->params.version.firmwareVersion == 1 &&
+          cam->params.version.firmwareRevision == 2)
+               /* 1-02 firmware limits gain to 2 */
+               sprintf(tmpstr, "%8d  %8d", 1, 2);
+       else
+               sprintf(tmpstr, "1,2,4,8");
+
+       if (cam->params.exposure.gainMode == 0)
+               out += sprintf(out, "max_gain:                unknown  %18s"
+                              "  %8d\n", tmpstr, 2); 
+       else
+               out += sprintf(out, "max_gain:               %8d  %18s  %8d\n", 
+                              1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+
+       switch(cam->params.exposure.expMode) {
+       case 1:
+       case 3:
+               sprintf(tmpstr, "manual");
+               break;
+       case 2:
+               sprintf(tmpstr, "auto");
+               break;
+       default:
+               sprintf(tmpstr, "unknown");
+               break;
+       }
+       out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
+                      "  %8s\n",  tmpstr, "manual", "auto", "auto");
+       out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
+                      (2-cam->params.exposure.centreWeight) ? "on" : "off",
+                      "off", "on", "on");
+       out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 
+possible\n",
+                      1<<cam->params.exposure.gain, 1, 1);
+       if (cam->params.version.firmwareVersion == 1 &&
+          cam->params.version.firmwareRevision == 2)
+               /* 1-02 firmware limits fineExp to 127 */
+               tmp = 255;
+       else
+               tmp = 511;
+
+       out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
+                      cam->params.exposure.fineExp*2, 0, tmp, 0);
+       if (cam->params.version.firmwareVersion == 1 &&
+          cam->params.version.firmwareRevision == 2)
+               /* 1-02 firmware limits coarseExpHi to 0 */
+               tmp = 255;
+       else
+               tmp = 65535;
+
+       out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
+                      "  %8d\n", cam->params.exposure.coarseExpLo+
+                      256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
+       out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
+                      cam->params.exposure.redComp, 220, 255, 220);
+       out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
+                      cam->params.exposure.green1Comp, 214, 255, 214);
+       out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
+                      cam->params.exposure.green2Comp, 214, 255, 214);
+       out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
+                      cam->params.exposure.blueComp, 230, 255, 230);
+       
+       out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
+                      cam->params.apcor.gain1, 0, 0xff, 0x1c);
+       out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
+                      cam->params.apcor.gain2, 0, 0xff, 0x1a);
+       out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
+                      cam->params.apcor.gain4, 0, 0xff, 0x2d);
+       out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
+                      cam->params.apcor.gain8, 0, 0xff, 0x2a);
+       out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
+                      cam->params.vlOffset.gain1, 0, 255, 24);
+       out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
+                      cam->params.vlOffset.gain2, 0, 255, 28);
+       out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
+                      cam->params.vlOffset.gain4, 0, 255, 30);
+       out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
+                      cam->params.vlOffset.gain8, 0, 255, 30);
+       out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
+                      cam->params.flickerControl.flickerMode ? "on" : "off",
+                      "off", "on", "off");
+       out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
+                      " only 50/60\n",
+                      cam->mainsFreq ? 60 : 50, 50, 60, 50);
+       out += sprintf(out, "allowable_overexposure: %8d  %8d  %8d  %8d\n",
+                      cam->params.flickerControl.allowableOverExposure, 0,
+                      255, 0);
+       out += sprintf(out, "compression_mode:       ");
+       switch(cam->params.compression.mode) {
+       case CPIA_COMPRESSION_NONE:
+               out += sprintf(out, "%8s", "none");
+               break;
+       case CPIA_COMPRESSION_AUTO:
+               out += sprintf(out, "%8s", "auto");
+               break;
+       case CPIA_COMPRESSION_MANUAL:
+               out += sprintf(out, "%8s", "manual");
+               break;
+       default:
+               out += sprintf(out, "%8s", "unknown");
+               break;
+       }
+       out += sprintf(out, "    none,auto,manual      auto\n");
+       out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
+                      cam->params.compression.decimation == 
+                      DECIMATION_ENAB ? "on":"off", "off", "off",
+                      "off");
+       out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
+                      cam->params.compressionTarget.frTargeting  == 
+                      CPIA_COMPRESSION_TARGET_FRAMERATE ?
+                      "framerate":"quality",
+                      "framerate", "quality", "quality");
+       out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionTarget.targetFR, 0, 30, 7);
+       out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionTarget.targetQ, 0, 255, 10);
+       out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
+                      cam->params.yuvThreshold.yThreshold, 0, 31, 15);
+       out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
+                      cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
+       out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.hysteresis, 0, 255, 3);
+       out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.threshMax, 0, 255, 11);
+       out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.smallStep, 0, 255, 1);
+       out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.largeStep, 0, 255, 3);
+       out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.decimationHysteresis,
+                      0, 255, 2);
+       out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.frDiffStepThresh,
+                      0, 255, 5);
+       out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.qDiffStepThresh,
+                      0, 255, 3);
+       out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
+                      cam->params.compressionParams.decimationThreshMod,
+                      0, 255, 2);
+       
+       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 cpia_write_proc(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+       struct cam_data *cam = data;
+       struct cam_params new_params;
+       int retval, find_colon;
+       int size = count;
+       unsigned long val;
+       u32 command_flags = 0;
+       u8 new_mains;
+       
+       if (down_interruptible(&cam->param_lock))
+               return -ERESTARTSYS;
+       
+       /*
+        * Skip over leading whitespace
+        */
+       while (count && isspace(*buffer)) {
+               --count;
+               ++buffer;
+       }
+       
+       memcpy(&new_params, &cam->params, sizeof(struct cam_params));
+       new_mains = cam->mainsFreq;
+       
+#define MATCH(x) \
+       ({ \
+               int _len = strlen(x), _ret, _colon_found; \
+               _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
+               if (_ret) { \
+                       buffer += _len; \
+                       count -= _len; \
+                       if (find_colon) { \
+                               _colon_found = 0; \
+                               while (count && (*buffer == ' ' || *buffer == '\t' || \
+                                      (!_colon_found && *buffer == ':'))) { \
+                                       if (*buffer == ':')  \
+                                               _colon_found = 1; \
+                                       --count; \
+                                       ++buffer; \
+                               } \
+                               if (!count || !_colon_found) \
+                                       retval = -EINVAL; \
+                               find_colon = 0; \
+                       } \
+               } \
+               _ret; \
+       })
+#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
+                               new_params.version.firmwareRevision == (y))
+#define VALUE \
+       ({ \
+               char *_p; \
+               unsigned long int _ret; \
+               _ret = simple_strtoul(buffer, &_p, 0); \
+               if (_p == buffer) \
+                       retval = -EINVAL; \
+               else { \
+                       count -= _p - buffer; \
+                       buffer = _p; \
+               } \
+               _ret; \
+       })
+
+       retval = 0;
+       while (count && !retval) {
+               find_colon = 1;
+               if (MATCH("brightness")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 100)
+                                       new_params.colourParams.brightness = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOLOURPARAMS;
+               } else if (MATCH("contrast")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 100) {
+                                       /* contrast is in steps of 8, so round*/
+                                       val = ((val + 3) / 8) * 8;
+                                       /* 1-02 firmware limits contrast to 80*/
+                                       if (FIRMWARE_VERSION(1,2) && val > 80)
+                                               val = 80;
+
+                                       new_params.colourParams.contrast = val;
+                               } else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOLOURPARAMS;
+               } else if (MATCH("saturation")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 100)
+                                       new_params.colourParams.saturation = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOLOURPARAMS;
+               } else if (MATCH("sensor_fps")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               /* find values so that sensorFPS is minimized,
+                                * but >= val */
+                               if (val > 30)
+                                       retval = -EINVAL;
+                               else if (val > 25) {
+                                       new_params.sensorFps.divisor = 0;
+                                       new_params.sensorFps.baserate = 1;
+                               } else if (val > 15) {
+                                       new_params.sensorFps.divisor = 0;
+                                       new_params.sensorFps.baserate = 0;
+                               } else if (val > 12) {
+                                       new_params.sensorFps.divisor = 1;
+                                       new_params.sensorFps.baserate = 1;
+                               } else if (val > 7) {
+                                       new_params.sensorFps.divisor = 1;
+                                       new_params.sensorFps.baserate = 0;
+                               } else if (val > 6) {
+                                       new_params.sensorFps.divisor = 2;
+                                       new_params.sensorFps.baserate = 1;
+                               } else if (val > 3) {
+                                       new_params.sensorFps.divisor = 2;
+                                       new_params.sensorFps.baserate = 0;
+                               } else {
+                                       new_params.sensorFps.divisor = 3;
+                                       /* Either base rate would work here */
+                                       new_params.sensorFps.baserate = 1;
+                               }
+                               new_params.flickerControl.coarseJump = 
+                                       flicker_jumps[new_mains]
+                                       [new_params.sensorFps.baserate]
+                                       [new_params.sensorFps.divisor];
+                               if (new_params.flickerControl.flickerMode)
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                       }
+                       command_flags |= COMMAND_SETSENSORFPS;
+               } else if (MATCH("stream_start_line")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               int max_line = 288;
+
+                               if (new_params.format.videoSize == VIDEOSIZE_QCIF)
+                                       max_line = 144;
+                               if (val <= max_line)
+                                       new_params.streamStartLine = val/2;
+                               else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("ecp_timing")) {
+                       if (!retval && MATCH("normal"))
+                               new_params.ecpTiming = 0;
+                       else if (!retval && MATCH("slow"))
+                               new_params.ecpTiming = 1;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETECPTIMING;
+               } else if (MATCH("color_balance_mode")) {
+                       if (!retval && MATCH("manual"))
+                               new_params.colourBalance.balanceModeIsAuto = 0;
+                       else if (!retval && MATCH("auto"))
+                               new_params.colourBalance.balanceModeIsAuto = 1;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETCOLOURBALANCE;
+               } else if (MATCH("red_gain")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 212)
+                                       new_params.colourBalance.redGain = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOLOURBALANCE;
+               } else if (MATCH("green_gain")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 212)
+                                       new_params.colourBalance.greenGain = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOLOURBALANCE;
+               } else if (MATCH("blue_gain")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 212)
+                                       new_params.colourBalance.blueGain = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOLOURBALANCE;
+               } else if (MATCH("max_gain")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               /* 1-02 firmware limits gain to 2 */
+                               if (FIRMWARE_VERSION(1,2) && val > 2)
+                                       val = 2;
+                               switch(val) {
+                               case 1:
+                                       new_params.exposure.gainMode = 1;
+                                       break;
+                               case 2:
+                                       new_params.exposure.gainMode = 2;
+                                       break;
+                               case 4:
+                                       new_params.exposure.gainMode = 3;
+                                       break;
+                               case 8:
+                                       new_params.exposure.gainMode = 4;
+                                       break;
+                               default:
+                                       retval = -EINVAL;
+                                       break;
+                               }
+                       }
+                       command_flags |= COMMAND_SETEXPOSURE;
+               } else if (MATCH("exposure_mode")) {
+                       if (!retval && MATCH("auto"))
+                               new_params.exposure.expMode = 2;
+                       else if (!retval && MATCH("manual")) {
+                               if (new_params.exposure.expMode == 2)
+                                       new_params.exposure.expMode = 3;
+                               new_params.flickerControl.flickerMode = 0;
+                               command_flags |= COMMAND_SETFLICKERCTRL;
+                       } else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETEXPOSURE;
+               } else if (MATCH("centre_weight")) {
+                       if (!retval && MATCH("on"))
+                               new_params.exposure.centreWeight = 1;
+                       else if (!retval && MATCH("off"))
+                               new_params.exposure.centreWeight = 2;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETEXPOSURE;
+               } else if (MATCH("gain")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               switch(val) {
+                               case 1:
+                                       new_params.exposure.gain = 0;
+                                       new_params.exposure.expMode = 1;
+                                       new_params.flickerControl.flickerMode = 0;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                                       break;
+                               case 2:
+                                       new_params.exposure.gain = 1;
+                                       new_params.exposure.expMode = 1;
+                                       new_params.flickerControl.flickerMode = 0;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                                       break;
+                               case 4:
+                                       new_params.exposure.gain = 2;
+                                       new_params.exposure.expMode = 1;
+                                       new_params.flickerControl.flickerMode = 0;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                                       break;
+                               case 8:
+                                       new_params.exposure.gain = 3;
+                                       new_params.exposure.expMode = 1;
+                                       new_params.flickerControl.flickerMode = 0;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                                       break;
+                               default:
+                                       retval = -EINVAL;
+                                       break;
+                               }
+                               command_flags |= COMMAND_SETEXPOSURE;
+                               if (new_params.exposure.gain >
+                                   new_params.exposure.gainMode-1)
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("fine_exp")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val < 256) {
+                                       /* 1-02 firmware limits fineExp to 127*/
+                                       if (FIRMWARE_VERSION(1,2) && val > 127)
+                                               val = 127;
+                                       new_params.exposure.fineExp = val;
+                                       new_params.exposure.expMode = 1;
+                                       command_flags |= COMMAND_SETEXPOSURE;
+                                       new_params.flickerControl.flickerMode = 0;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("coarse_exp")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val < 65536) {
+                                       /* 1-02 firmware limits
+                                        * coarseExp to 255 */
+                                       if (FIRMWARE_VERSION(1,2) && val > 255)
+                                               val = 255;
+                                       new_params.exposure.coarseExpLo =
+                                               val & 0xff;
+                                       new_params.exposure.coarseExpHi =
+                                               val >> 8;
+                                       new_params.exposure.expMode = 1;
+                                       command_flags |= COMMAND_SETEXPOSURE;
+                                       new_params.flickerControl.flickerMode = 0;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("red_comp")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val >= 220 && val <= 255) {
+                                       new_params.exposure.redComp = val;
+                                       command_flags |= COMMAND_SETEXPOSURE;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("green1_comp")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val >= 214 && val <= 255) {
+                                       new_params.exposure.green1Comp = val;
+                                       command_flags |= COMMAND_SETEXPOSURE;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("green2_comp")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val >= 214 && val <= 255) {
+                                       new_params.exposure.green2Comp = val;
+                                       command_flags |= COMMAND_SETEXPOSURE;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("blue_comp")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val >= 230 && val <= 255) {
+                                       new_params.exposure.blueComp = val;
+                                       command_flags |= COMMAND_SETEXPOSURE;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("apcor_gain1")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               command_flags |= COMMAND_SETAPCOR;
+                               if (val <= 0xff)
+                                       new_params.apcor.gain1 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("apcor_gain2")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               command_flags |= COMMAND_SETAPCOR;
+                               if (val <= 0xff)
+                                       new_params.apcor.gain2 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("apcor_gain4")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               command_flags |= COMMAND_SETAPCOR;
+                               if (val <= 0xff)
+                                       new_params.apcor.gain4 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("apcor_gain8")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               command_flags |= COMMAND_SETAPCOR;
+                               if (val <= 0xff)
+                                       new_params.apcor.gain8 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("vl_offset_gain1")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.vlOffset.gain1 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETVLOFFSET;
+               } else if (MATCH("vl_offset_gain2")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.vlOffset.gain2 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETVLOFFSET;
+               } else if (MATCH("vl_offset_gain4")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.vlOffset.gain4 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETVLOFFSET;
+               } else if (MATCH("vl_offset_gain8")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.vlOffset.gain8 = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETVLOFFSET;
+               } else if (MATCH("flicker_control")) {
+                       if (!retval && MATCH("on")) {
+                               new_params.flickerControl.flickerMode = 1;
+                               new_params.exposure.expMode = 2;
+                               command_flags |= COMMAND_SETEXPOSURE;
+                       } else if (!retval && MATCH("off"))
+                               new_params.flickerControl.flickerMode = 0;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETFLICKERCTRL;
+               } else if (MATCH("mains_frequency")) {
+                       if (!retval && MATCH("50")) {
+                               new_mains = 0;
+                               new_params.flickerControl.coarseJump = 
+                                       flicker_jumps[new_mains]
+                                       [new_params.sensorFps.baserate]
+                                       [new_params.sensorFps.divisor];
+                               if (new_params.flickerControl.flickerMode)
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                       } else if (!retval && MATCH("60")) {
+                               new_mains = 1;
+                               new_params.flickerControl.coarseJump = 
+                                       flicker_jumps[new_mains]
+                                       [new_params.sensorFps.baserate]
+                                       [new_params.sensorFps.divisor];
+                               if (new_params.flickerControl.flickerMode)
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                       } else
+                               retval = -EINVAL;
+               } else if (MATCH("allowable_overexposure")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff) {
+                                       new_params.flickerControl.
+                                               allowableOverExposure = val;
+                                       command_flags |= COMMAND_SETFLICKERCTRL;
+                               } else
+                                       retval = -EINVAL;
+                       }
+               } else if (MATCH("compression_mode")) {
+                       if (!retval && MATCH("none"))
+                               new_params.compression.mode =
+                                       CPIA_COMPRESSION_NONE;
+                       else if (!retval && MATCH("auto"))
+                               new_params.compression.mode =
+                                       CPIA_COMPRESSION_AUTO;
+                       else if (!retval && MATCH("manual"))
+                               new_params.compression.mode =
+                                       CPIA_COMPRESSION_MANUAL;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETCOMPRESSION;
+               } else if (MATCH("decimation_enable")) {
+                       if (!retval && MATCH("off"))
+                               new_params.compression.decimation = 0;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETCOMPRESSION;
+               } else if (MATCH("compression_target")) {
+                       if (!retval && MATCH("quality"))
+                               new_params.compressionTarget.frTargeting = 
+                                       CPIA_COMPRESSION_TARGET_QUALITY;
+                       else if (!retval && MATCH("framerate"))
+                               new_params.compressionTarget.frTargeting = 
+                                       CPIA_COMPRESSION_TARGET_FRAMERATE;
+                       else
+                               retval = -EINVAL;
+
+                       command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+               } else if (MATCH("target_framerate")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval)
+                               new_params.compressionTarget.targetFR = val;
+                       command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+               } else if (MATCH("target_quality")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval)
+                               new_params.compressionTarget.targetQ = val;
+
+                       command_flags |= COMMAND_SETCOMPRESSIONTARGET;
+               } else if (MATCH("y_threshold")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val < 32)
+                                       new_params.yuvThreshold.yThreshold = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETYUVTHRESH;
+               } else if (MATCH("uv_threshold")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val < 32)
+                                       new_params.yuvThreshold.uvThreshold = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETYUVTHRESH;
+               } else if (MATCH("hysteresis")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.compressionParams.hysteresis = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("threshold_max")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.compressionParams.threshMax = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("small_step")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.compressionParams.smallStep = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("large_step")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.compressionParams.largeStep = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("decimation_hysteresis")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       
+new_params.compressionParams.decimationHysteresis = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("fr_diff_step_thresh")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.compressionParams.frDiffStepThresh 
+= val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("q_diff_step_thresh")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       new_params.compressionParams.qDiffStepThresh = 
+val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else if (MATCH("decimation_thresh_mod")) {
+                       if (!retval)
+                               val = VALUE;
+
+                       if (!retval) {
+                               if (val <= 0xff)
+                                       
+new_params.compressionParams.decimationThreshMod = val;
+                               else
+                                       retval = -EINVAL;
+                       }
+                       command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+               } else {
+                       DBG("No match found\n");
+                       retval = -EINVAL;
+               }
+
+               if (!retval) {
+                       while (count && isspace(*buffer) && *buffer != '\n') {
+                               --count;
+                               ++buffer;
+                       }
+                       if (count) {
+                               if (*buffer != '\n' && *buffer != ';')
+                                       retval = -EINVAL;
+                               else {
+                                       --count;
+                                       ++buffer;
+                               }
+                       }
+               }
+       }
+#undef MATCH   
+#undef FIRMWARE_VERSION
+#undef VALUE
+#undef FIND_VALUE
+#undef FIND_END
+       if (!retval) {
+               if (command_flags & COMMAND_SETCOLOURPARAMS) {
+                       /* Adjust cam->vp to reflect these changes */
+                       cam->vp.brightness =
+                               new_params.colourParams.brightness*65535/100;
+                       cam->vp.contrast =
+                               new_params.colourParams.contrast*65535/100;
+                       cam->vp.colour =
+                               new_params.colourParams.saturation*65535/100;
+               }
+               
+               memcpy(&cam->params, &new_params, sizeof(struct cam_params));
+               cam->mainsFreq = new_mains;
+               cam->cmd_queue |= command_flags;
+               retval = size;
+       } else
+               DBG("error: %d\n", retval);
+       
+       up(&cam->param_lock);
+       
+       return retval;
+}
+
+static void create_proc_cpia_cam(struct cam_data *cam)
+{
+       char name[7];
+       struct proc_dir_entry *ent;
+       
+       if (!cpia_proc_root || !cam)
+               return;
+
+       sprintf(name, "video%d", cam->vdev.minor);
+       
+       ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
+       if (!ent)
+               return;
+
+       ent->data = cam;
+       ent->read_proc = cpia_read_proc;
+       ent->write_proc = cpia_write_proc;
+       ent->size = 3626;
+       cam->proc_entry = ent;
+}
+
+static void destroy_proc_cpia_cam(struct cam_data *cam)
+{
+       char name[7];
+       
+       if (!cam || !cam->proc_entry)
+               return;
+       
+       sprintf(name, "video%d", cam->vdev.minor);
+       remove_proc_entry(name, cpia_proc_root);
+       cam->proc_entry = NULL;
+}
+
+static void proc_cpia_create(void)
+{
+       cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
+
+       if (cpia_proc_root)
+               cpia_proc_root->owner = THIS_MODULE;
+       else
+               LOG("Unable to initialise /proc/cpia\n");
+}
+
+static void proc_cpia_destroy(void)
+{
+       remove_proc_entry("cpia", 0);
+}
+#endif /* CONFIG_PROC_FS */
+
+/* ----------------------- debug functions ---------------------- */
+
+#define printstatus(cam) \
+  DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
+       cam->params.status.systemState, cam->params.status.grabState, \
+       cam->params.status.streamState, cam->params.status.fatalError, \
+       cam->params.status.cmdError, cam->params.status.debugFlags, \
+       cam->params.status.vpStatus, cam->params.status.errorCode);
+
+/* ----------------------- v4l helpers -------------------------- */
+
+/* supported frame palettes and depths */
+static inline int valid_mode(u16 palette, u16 depth)
+{
+       return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
+              (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
+              (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
+              (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
+              (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
+              (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
+              (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
+              (palette == VIDEO_PALETTE_UYVY && depth == 16);
+}
+
+static int match_videosize( int width, int height )
+{
+       /* return the best match, where 'best' is as always
+        * the largest that is not bigger than what is requested. */
+       if (width>=352 && height>=288)
+               return VIDEOSIZE_352_288; /* CIF */
+
+       if (width>=320 && height>=240)
+               return VIDEOSIZE_320_240; /* SIF */
+
+       if (width>=288 && height>=216)
+               return VIDEOSIZE_288_216;
+
+       if (width>=256 && height>=192)
+               return VIDEOSIZE_256_192;
+
+       if (width>=224 && height>=168)
+               return VIDEOSIZE_224_168;
+
+       if (width>=192 && height>=144)
+               return VIDEOSIZE_192_144;
+
+       if (width>=176 && height>=144)
+               return VIDEOSIZE_176_144; /* QCIF */
+
+       if (width>=160 && height>=120)
+               return VIDEOSIZE_160_120; /* QSIF */
+
+       if (width>=128 && height>=96)
+               return VIDEOSIZE_128_96;
+
+       if (width>=88 && height>=72)
+               return VIDEOSIZE_88_72;
+
+       if (width>=64 && height>=48)
+               return VIDEOSIZE_64_48;
+
+       if (width>=48 && height>=48)
+               return VIDEOSIZE_48_48;
+
+       return -1;
+}
+
+/* these are the capture sizes we support */
+static void set_vw_size(struct cam_data *cam)
+{
+       /* the col/row/start/end values are the result of simple math    */
+       /* study the SetROI-command in cpia developers guide p 2-22      */
+       /* streamStartLine is set to the recommended value in the cpia   */
+       /*  developers guide p 3-37                                      */
+       switch(cam->video_size) {
+       case VIDEOSIZE_CIF:
+               cam->vw.width = 352;
+               cam->vw.height = 288;
+               cam->params.format.videoSize=VIDEOSIZE_CIF;
+               cam->params.roi.colStart=0;
+               cam->params.roi.colEnd=44;
+               cam->params.roi.rowStart=0;
+               cam->params.roi.rowEnd=72;
+               cam->params.streamStartLine = 120;
+               break;
+       case VIDEOSIZE_SIF:
+               cam->vw.width = 320;
+               cam->vw.height = 240;
+               cam->params.format.videoSize=VIDEOSIZE_CIF;
+               cam->params.roi.colStart=2;
+               cam->params.roi.colEnd=42;
+               cam->params.roi.rowStart=6;
+               cam->params.roi.rowEnd=66;
+               cam->params.streamStartLine = 120;
+               break;
+       case VIDEOSIZE_288_216:
+               cam->vw.width = 288;
+               cam->vw.height = 216;
+               cam->params.format.videoSize=VIDEOSIZE_CIF;
+               cam->params.roi.colStart=4;
+               cam->params.roi.colEnd=40;
+               cam->params.roi.rowStart=9;
+               cam->params.roi.rowEnd=63;
+               cam->params.streamStartLine = 120;
+               break;
+       case VIDEOSIZE_256_192:
+               cam->vw.width = 256;
+               cam->vw.height = 192;
+               cam->params.format.videoSize=VIDEOSIZE_CIF;
+               cam->params.roi.colStart=6;
+               cam->params.roi.colEnd=38;
+               cam->params.roi.rowStart=12;
+               cam->params.roi.rowEnd=60;
+               cam->params.streamStartLine = 120;
+               break;
+       case VIDEOSIZE_224_168:
+               cam->vw.width = 224;
+               cam->vw.height = 168;
+               cam->params.format.videoSize=VIDEOSIZE_CIF;
+               cam->params.roi.colStart=8;
+               cam->params.roi.colEnd=36;
+               cam->params.roi.rowStart=15;
+               cam->params.roi.rowEnd=57;
+               cam->params.streamStartLine = 120;
+               break;
+       case VIDEOSIZE_192_144:
+               cam->vw.width = 192;
+               cam->vw.height = 144;
+               cam->params.format.videoSize=VIDEOSIZE_CIF;
+               cam->params.roi.colStart=10;
+               cam->params.roi.colEnd=34;
+               cam->params.roi.rowStart=18;
+               cam->params.roi.rowEnd=54;
+               cam->params.streamStartLine = 120;
+               break;
+       case VIDEOSIZE_QCIF:
+               cam->vw.width = 176;
+               cam->vw.height = 144;
+               cam->params.format.videoSize=VIDEOSIZE_QCIF;
+               cam->params.roi.colStart=0;
+               cam->params.roi.colEnd=22;
+               cam->params.roi.rowStart=0;
+               cam->params.roi.rowEnd=36;
+               cam->params.streamStartLine = 60;
+               break;
+       case VIDEOSIZE_QSIF:
+               cam->vw.width = 160;
+               cam->vw.height = 120;
+               cam->params.format.videoSize=VIDEOSIZE_QCIF;
+               cam->params.roi.colStart=1;
+               cam->params.roi.colEnd=21;
+               cam->params.roi.rowStart=3;
+               cam->params.roi.rowEnd=33;
+               cam->params.streamStartLine = 60;
+               break;
+       case VIDEOSIZE_128_96:
+               cam->vw.width = 128;
+               cam->vw.height = 96;
+               cam->params.format.videoSize=VIDEOSIZE_QCIF;
+               cam->params.roi.colStart=3;
+               cam->params.roi.colEnd=19;
+               cam->params.roi.rowStart=6;
+               cam->params.roi.rowEnd=30;
+               cam->params.streamStartLine = 60;
+               break;
+       case VIDEOSIZE_88_72:
+               cam->vw.width = 88;
+               cam->vw.height = 72;
+               cam->params.format.videoSize=VIDEOSIZE_QCIF;
+               cam->params.roi.colStart=5;
+               cam->params.roi.colEnd=16;
+               cam->params.roi.rowStart=9;
+               cam->params.roi.rowEnd=27;
+               cam->params.streamStartLine = 60;
+               break;
+       case VIDEOSIZE_64_48:
+               cam->vw.width = 64;
+               cam->vw.height = 48;
+               cam->params.format.videoSize=VIDEOSIZE_QCIF;
+               cam->params.roi.colStart=7;
+               cam->params.roi.colEnd=15;
+               cam->params.roi.rowStart=12;
+               cam->params.roi.rowEnd=24;
+               cam->params.streamStartLine = 60;
+               break;
+       case VIDEOSIZE_48_48:
+               cam->vw.width = 48;
+               cam->vw.height = 48;
+               cam->params.format.videoSize=VIDEOSIZE_QCIF;
+               cam->params.roi.colStart=8;
+               cam->params.roi.colEnd=14;
+               cam->params.roi.rowStart=6;
+               cam->params.roi.rowEnd=30;
+               cam->params.streamStartLine = 60;
+               break;
+       default:
+               LOG("bad videosize value: %d\n", cam->video_size);
+       }
+
+       return;
+}
+
+static int allocate_frame_buf(struct cam_data *cam)
+{
+       int i;
+
+       cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
+       if (!cam->frame_buf)
+               return -ENOBUFS;
+
+       for (i = 0; i < FRAME_NUM; i++)
+               cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
+
+       return 0;
+}
+
+static int free_frame_buf(struct cam_data *cam)
+{
+       int i;
+       
+       rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
+       cam->frame_buf = 0;
+       for (i=0; i < FRAME_NUM; i++)
+               cam->frame[i].data = NULL;
+
+       return 0;
+}
+
+
+static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
+{
+       int i;
+
+       for (i=0; i < FRAME_NUM; i++)
+               frame[i].state = FRAME_UNUSED;
+       return;
+}
+
+/**********************************************************************
+ *
+ * General functions
+ *
+ **********************************************************************/
+/* send an arbitrary command to the camera */
+static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
+{
+       int retval, datasize;
+       u8 cmd[8], data[8];
+
+       switch(command) {
+       case CPIA_COMMAND_GetCPIAVersion:
+       case CPIA_COMMAND_GetPnPID:
+       case CPIA_COMMAND_GetCameraStatus:
+       case CPIA_COMMAND_GetVPVersion:
+               datasize=8;
+               break;
+       case CPIA_COMMAND_GetColourParams:
+       case CPIA_COMMAND_GetColourBalance:
+       case CPIA_COMMAND_GetExposure:
+               down(&cam->param_lock);
+               datasize=8;
+               break;
+       default:
+               datasize=0;
+               break;
+       }
+
+       cmd[0] = command>>8;
+       cmd[1] = command&0xff;
+       cmd[2] = a;
+       cmd[3] = b;
+       cmd[4] = c;
+       cmd[5] = d;
+       cmd[6] = datasize;
+       cmd[7] = 0;
+
+       retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+       if (retval)
+               DBG("%x - failed, retval=%d\n", command, retval);
+       else {
+               switch(command) {
+               case CPIA_COMMAND_GetCPIAVersion:
+                       cam->params.version.firmwareVersion = data[0];
+                       cam->params.version.firmwareRevision = data[1];
+                       cam->params.version.vcVersion = data[2];
+                       cam->params.version.vcRevision = data[3];
+                       break;
+               case CPIA_COMMAND_GetPnPID:
+                       cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
+                       cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
+                       cam->params.pnpID.deviceRevision =
+                               data[4]+(((u16)data[5])<<8);
+                       break;
+               case CPIA_COMMAND_GetCameraStatus:
+                       cam->params.status.systemState = data[0];
+                       cam->params.status.grabState = data[1];
+                       cam->params.status.streamState = data[2];
+                       cam->params.status.fatalError = data[3];
+                       cam->params.status.cmdError = data[4];
+                       cam->params.status.debugFlags = data[5];
+                       cam->params.status.vpStatus = data[6];
+                       cam->params.status.errorCode = data[7];
+                       break;
+               case CPIA_COMMAND_GetVPVersion:
+                       cam->params.vpVersion.vpVersion = data[0];
+                       cam->params.vpVersion.vpRevision = data[1];
+                       cam->params.vpVersion.cameraHeadID =
+                               data[2]+(((u16)data[3])<<8);
+                       break;
+               case CPIA_COMMAND_GetColourParams:
+                       cam->params.colourParams.brightness = data[0];
+                       cam->params.colourParams.contrast = data[1];
+                       cam->params.colourParams.saturation = data[2];
+                       up(&cam->param_lock);
+                       break;
+               case CPIA_COMMAND_GetColourBalance:
+                       cam->params.colourBalance.redGain = data[0];
+                       cam->params.colourBalance.greenGain = data[1];
+                       cam->params.colourBalance.blueGain = data[2];
+                       up(&cam->param_lock);
+                       break;
+               case CPIA_COMMAND_GetExposure:
+                       cam->params.exposure.gain = data[0];
+                       cam->params.exposure.fineExp = data[1];
+                       cam->params.exposure.coarseExpLo = data[2];
+                       cam->params.exposure.coarseExpHi = data[3];
+                       cam->params.exposure.redComp = data[4];
+                       cam->params.exposure.green1Comp = data[5];
+                       cam->params.exposure.green2Comp = data[6];
+                       cam->params.exposure.blueComp = data[7];
+                       /* If the *Comp parameters are wacko, generate
+                        * a warning, and reset them back to default
+                        * values.             - [EMAIL PROTECTED]
+                        */
+                       if (cam->params.exposure.redComp < 220 ||
+                           cam->params.exposure.redComp > 255 ||
+                           cam->params.exposure.green1Comp < 214 ||
+                           cam->params.exposure.green1Comp > 255 ||
+                           cam->params.exposure.green2Comp < 214 ||
+                           cam->params.exposure.green2Comp > 255 ||
+                           cam->params.exposure.blueComp < 230 ||
+                           cam->params.exposure.blueComp > 255)
+                         {
+                           printk (KERN_WARNING "*_comp parameters have gone AWOL 
+(%d/%d/%d/%d) - reseting them\n",
+                                   cam->params.exposure.redComp,
+                                   cam->params.exposure.green1Comp,
+                                   cam->params.exposure.green2Comp,
+                                   cam->params.exposure.blueComp);
+                           cam->params.exposure.redComp = 220;
+                           cam->params.exposure.green1Comp = 214;
+                           cam->params.exposure.green2Comp = 214;
+                           cam->params.exposure.blueComp = 230;
+                         }
+                       up(&cam->param_lock);
+                       break;
+               default:
+                       break;
+               }
+       }
+       return retval;
+}
+
+/* send a command  to the camera with an additional data transaction */
+static int do_command_extended(struct cam_data *cam, u16 command,
+                               u8 a, u8 b, u8 c, u8 d,
+                               u8 e, u8 f, u8 g, u8 h,
+                               u8 i, u8 j, u8 k, u8 l)
+{
+       int retval;
+       u8 cmd[8], data[8];
+
+       cmd[0] = command>>8;
+       cmd[1] = command&0xff;
+       cmd[2] = a;
+       cmd[3] = b;
+       cmd[4] = c;
+       cmd[5] = d;
+       cmd[6] = 8;
+       cmd[7] = 0;
+       data[0] = e;
+       data[1] = f;
+       data[2] = g;
+       data[3] = h;
+       data[4] = i;
+       data[5] = j;
+       data[6] = k;
+       data[7] = l;
+
+       retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
+       if (retval)
+               LOG("%x - failed\n", command);
+
+       return retval;
+}
+
+/**********************************************************************
+ *
+ * Colorspace conversion
+ *
+ **********************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+
+static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
+                      int in_uyvy, int mmap_kludge)
+{
+       int y, u, v, r, g, b, y1;
+
+       switch(out_fmt) {
+       case VIDEO_PALETTE_RGB555:
+       case VIDEO_PALETTE_RGB565:
+       case VIDEO_PALETTE_RGB24:
+       case VIDEO_PALETTE_RGB32:
+               if (in_uyvy) {
+                       u = *yuv++ - 128;
+                       y = (*yuv++ - 16) * 76310;
+                       v = *yuv++ - 128;
+                       y1 = (*yuv - 16) * 76310;
+               } else {
+                       y = (*yuv++ - 16) * 76310;
+                       u = *yuv++ - 128;
+                       y1 = (*yuv++ - 16) * 76310;
+                       v = *yuv - 128;
+               }
+               r = 104635 * v;
+               g = -25690 * u + -53294 * v;
+               b = 132278 * u;
+               break;
+       default:
+               y = *yuv++;
+               u = *yuv++;
+               y1 = *yuv++;
+               v = *yuv;
+               /* Just to avoid compiler warnings */
+               r = 0;
+               g = 0;
+               b = 0;
+               break;
+       }
+       switch(out_fmt) {
+       case VIDEO_PALETTE_RGB555:
+               *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
+               *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
+               *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
+               *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
+               return 4;
+       case VIDEO_PALETTE_RGB565:
+               *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
+               *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
+               *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
+               *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
+               return 4;
+       case VIDEO_PALETTE_RGB24:
+               if (mmap_kludge) {
+                       *rgb++ = LIMIT(b+y);
+                       *rgb++ = LIMIT(g+y);
+                       *rgb++ = LIMIT(r+y);
+                       *rgb++ = LIMIT(b+y1);
+                       *rgb++ = LIMIT(g+y1);
+                       *rgb = LIMIT(r+y1);
+               } else {
+                       *rgb++ = LIMIT(r+y);
+                       *rgb++ = LIMIT(g+y);
+                       *rgb++ = LIMIT(b+y);
+                       *rgb++ = LIMIT(r+y1);
+                       *rgb++ = LIMIT(g+y1);
+                       *rgb = LIMIT(b+y1);
+               }
+               return 6;
+       case VIDEO_PALETTE_RGB32:
+               if (mmap_kludge) {
+                       *rgb++ = LIMIT(b+y);
+                       *rgb++ = LIMIT(g+y);
+                       *rgb++ = LIMIT(r+y);
+                       rgb++;
+                       *rgb++ = LIMIT(b+y1);
+                       *rgb++ = LIMIT(g+y1);
+                       *rgb = LIMIT(r+y1);
+               } else {
+                       *rgb++ = LIMIT(r+y);
+                       *rgb++ = LIMIT(g+y);
+                       *rgb++ = LIMIT(b+y);
+                       rgb++;
+                       *rgb++ = LIMIT(r+y1);
+                       *rgb++ = LIMIT(g+y1);
+                       *rgb = LIMIT(b+y1);
+               }
+               return 8;
+       case VIDEO_PALETTE_GREY:
+               *rgb++ = y;
+               *rgb = y1;
+               return 2;
+       case VIDEO_PALETTE_YUV422:
+       case VIDEO_PALETTE_YUYV:
+               *rgb++ = y;
+               *rgb++ = u;
+               *rgb++ = y1;
+               *rgb = v;
+               return 4;
+       case VIDEO_PALETTE_UYVY:
+               *rgb++ = u;
+               *rgb++ = y;
+               *rgb++ = v;
+               *rgb = y1;
+               return 4;
+       default:
+               DBG("Empty: %d\n", out_fmt);
+               return 0;
+       }
+}
+
+static int skipcount(int count, int fmt)
+{
+       switch(fmt) {
+       case VIDEO_PALETTE_GREY:
+       case VIDEO_PALETTE_RGB555:
+       case VIDEO_PALETTE_RGB565:
+       case VIDEO_PALETTE_YUV422:
+       case VIDEO_PALETTE_YUYV:
+       case VIDEO_PALETTE_UYVY:
+               return 2*count;
+       case VIDEO_PALETTE_RGB24:
+               return 3*count;
+       case VIDEO_PALETTE_RGB32:
+               return 4*count;
+       default:
+               return 0;
+       }
+}
+
+static int parse_picture(struct cam_data *cam, int size)
+{
+       u8 *obuf, *ibuf, *end_obuf;
+       int ll, in_uyvy, compressed, origsize, out_fmt;
+
+       /* make sure params don't change while we are decoding */
+       down(&cam->param_lock);
+
+       obuf = cam->decompressed_frame.data;
+       end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
+       ibuf = cam->raw_image;
+       origsize = size;
+       out_fmt = cam->vp.palette;
+
+       if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
+               LOG("header not found\n");
+               up(&cam->param_lock);
+               return -1;
+       }
+
+       if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
+               LOG("wrong video size\n");
+               up(&cam->param_lock);
+               return -1;
+       }
+       
+       if (ibuf[17] != SUBSAMPLE_422) {
+               LOG("illegal subtype %d\n",ibuf[17]);
+               up(&cam->param_lock);
+               return -1;
+       }
+       
+       if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
+               LOG("illegal yuvorder %d\n",ibuf[18]);
+               up(&cam->param_lock);
+               return -1;
+       }
+       in_uyvy = ibuf[18] == YUVORDER_UYVY;
+       
+#if 0
+       /* FIXME: ROI mismatch occurs when switching capture sizes */
+       if ((ibuf[24] != cam->params.roi.colStart) ||
+           (ibuf[25] != cam->params.roi.colEnd) ||
+           (ibuf[26] != cam->params.roi.rowStart) ||
+           (ibuf[27] != cam->params.roi.rowEnd)) {
+               LOG("ROI mismatch\n");
+               up(&cam->param_lock);
+               return -1;
+       }
+#endif
+       
+       if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
+               LOG("illegal compression %d\n",ibuf[28]);
+               up(&cam->param_lock);
+               return -1;
+       }
+       compressed = (ibuf[28] == COMPRESSED);
+       
+       if (ibuf[29] != NO_DECIMATION) {
+               LOG("decimation not supported\n");
+               up(&cam->param_lock);
+               return -1;
+       }
+       
+       cam->params.yuvThreshold.yThreshold = ibuf[30];
+       cam->params.yuvThreshold.uvThreshold = ibuf[31];
+       cam->params.status.systemState = ibuf[32];
+       cam->params.status.grabState = ibuf[33];
+       cam->params.status.streamState = ibuf[34];
+       cam->params.status.fatalError = ibuf[35];
+       cam->params.status.cmdError = ibuf[36];
+       cam->params.status.debugFlags = ibuf[37];
+       cam->params.status.vpStatus = ibuf[38];
+       cam->params.status.errorCode = ibuf[39];
+       cam->fps = ibuf[41];
+       up(&cam->param_lock);
+       
+       ibuf += FRAME_HEADER_SIZE;
+       size -= FRAME_HEADER_SIZE;
+       ll = ibuf[0] | (ibuf[1] << 8);
+       ibuf += 2;
+
+       while (size > 0) {
+               size -= (ll+2);
+               if (size < 0) {
+                       LOG("Insufficient data in buffer\n");
+                       return -1;
+               }
+
+               while (ll > 1) {
+                       if (!compressed || (compressed && !(*ibuf & 1))) {
+                               obuf += yuvconvert(ibuf, obuf, out_fmt,
+                                                  in_uyvy, cam->mmap_kludge);
+                               ibuf += 4;
+                               ll -= 4;
+                       } else {
+                               /*skip compressed interval from previous frame*/
+                               int skipsize = skipcount(*ibuf >> 1, out_fmt);
+                               obuf += skipsize;
+                               if (obuf > end_obuf) {
+                                       LOG("Insufficient data in buffer\n");
+                                       return -1;
+                               }
+                               ++ibuf;
+                               ll--;
+                       }
+               }
+               if (ll == 1) {
+                       if (*ibuf != EOL) {
+                               LOG("EOL not found giving up after %d/%d"
+                                   " bytes\n", origsize-size, origsize);
+                               return -1;
+                       }
+
+                       ibuf++; /* skip over EOL */
+
+                       if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
+                          (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
+                               size -= 4;
+                               break;
+                       }
+
+                       if (size > 1) {
+                               ll = ibuf[0] | (ibuf[1] << 8);
+                               ibuf += 2; /* skip over line length */
+                       }
+               } else {
+                       LOG("line length was not 1 but %d after %d/%d bytes\n",
+                           ll, origsize-size, origsize);
+                       return -1;
+               }
+       }
+       
+       cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
+
+       return cam->decompressed_frame.count;
+}
+
+/* InitStreamCap wrapper to select correct start line */
+static inline int init_stream_cap(struct cam_data *cam)
+{
+       return do_command(cam, CPIA_COMMAND_InitStreamCap,
+                         0, cam->params.streamStartLine, 0, 0);
+}
+
+/* update various camera modes and settings */
+static void dispatch_commands(struct cam_data *cam)
+{
+       down(&cam->param_lock);
+       if (cam->cmd_queue==COMMAND_NONE) {
+               up(&cam->param_lock);
+               return;
+       }
+       DEB_BYTE(cam->cmd_queue);
+       DEB_BYTE(cam->cmd_queue>>8);
+       if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
+               do_command(cam, CPIA_COMMAND_SetColourParams,
+                          cam->params.colourParams.brightness,
+                          cam->params.colourParams.contrast,
+                          cam->params.colourParams.saturation, 0);
+
+       if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
+               do_command(cam, CPIA_COMMAND_SetCompression,
+                          cam->params.compression.mode,
+                          cam->params.compression.decimation, 0, 0);
+
+       if (cam->cmd_queue & COMMAND_SETFORMAT) {
+               do_command(cam, CPIA_COMMAND_SetFormat,
+                          cam->params.format.videoSize,
+                          cam->params.format.subSample,
+                          cam->params.format.yuvOrder, 0);
+               do_command(cam, CPIA_COMMAND_SetROI,
+                          cam->params.roi.colStart, cam->params.roi.colEnd,
+                          cam->params.roi.rowStart, cam->params.roi.rowEnd);
+               cam->first_frame = 1;
+       }
+
+       if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
+               do_command(cam, CPIA_COMMAND_SetCompressionTarget,
+                          cam->params.compressionTarget.frTargeting,
+                          cam->params.compressionTarget.targetFR,
+                          cam->params.compressionTarget.targetQ, 0);
+
+       if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
+               do_command(cam, CPIA_COMMAND_SetYUVThresh,
+                          cam->params.yuvThreshold.yThreshold,
+                          cam->params.yuvThreshold.uvThreshold, 0, 0);
+
+       if (cam->cmd_queue & COMMAND_SETECPTIMING)
+               do_command(cam, CPIA_COMMAND_SetECPTiming,
+                          cam->params.ecpTiming, 0, 0, 0);
+
+       if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
+               do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
+                           0, 0, 0, 0,
+                           cam->params.compressionParams.hysteresis,
+                           cam->params.compressionParams.threshMax,
+                           cam->params.compressionParams.smallStep,
+                           cam->params.compressionParams.largeStep,
+                           cam->params.compressionParams.decimationHysteresis,
+                           cam->params.compressionParams.frDiffStepThresh,
+                           cam->params.compressionParams.qDiffStepThresh,
+                           cam->params.compressionParams.decimationThreshMod);
+
+       if (cam->cmd_queue & COMMAND_SETEXPOSURE)
+               do_command_extended(cam, CPIA_COMMAND_SetExposure,
+                                   cam->params.exposure.gainMode,
+                                   cam->params.exposure.expMode,
+                                   cam->params.exposure.compMode,
+                                   cam->params.exposure.centreWeight,
+                                   cam->params.exposure.gain,
+                                   cam->params.exposure.fineExp,
+                                   cam->params.exposure.coarseExpLo,
+                                   cam->params.exposure.coarseExpHi,
+                                   cam->params.exposure.redComp,
+                                   cam->params.exposure.green1Comp,
+                                   cam->params.exposure.green2Comp,
+                                   cam->params.exposure.blueComp);
+
+       if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
+               if (cam->params.colourBalance.balanceModeIsAuto) {
+                       do_command(cam, CPIA_COMMAND_SetColourBalance,
+                                  2, 0, 0, 0);
+               } else {
+                       do_command(cam, CPIA_COMMAND_SetColourBalance,
+                                  1,
+                                  cam->params.colourBalance.redGain,
+                                  cam->params.colourBalance.greenGain,
+                                  cam->params.colourBalance.blueGain);
+                       do_command(cam, CPIA_COMMAND_SetColourBalance,
+                                  3, 0, 0, 0);
+               }
+       }
+
+       if (cam->cmd_queue & COMMAND_SETSENSORFPS)
+               do_command(cam, CPIA_COMMAND_SetSensorFPS,
+                          cam->params.sensorFps.divisor,
+                          cam->params.sensorFps.baserate, 0, 0);
+
+       if (cam->cmd_queue & COMMAND_SETAPCOR)
+               do_command(cam, CPIA_COMMAND_SetApcor,
+                          cam->params.apcor.gain1,
+                          cam->params.apcor.gain2,
+                          cam->params.apcor.gain4,
+                          cam->params.apcor.gain8);
+
+       if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
+               do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
+                          cam->params.flickerControl.flickerMode,
+                          cam->params.flickerControl.coarseJump,
+                          cam->params.flickerControl.allowableOverExposure, 0);
+
+       if (cam->cmd_queue & COMMAND_SETVLOFFSET)
+               do_command(cam, CPIA_COMMAND_SetVLOffset,
+                          cam->params.vlOffset.gain1,
+                          cam->params.vlOffset.gain2,
+                          cam->params.vlOffset.gain4,
+                          cam->params.vlOffset.gain8);
+
+       if (cam->cmd_queue & COMMAND_PAUSE)
+               do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
+
+       if (cam->cmd_queue & COMMAND_RESUME)
+               init_stream_cap(cam);
+
+       up(&cam->param_lock);
+       cam->cmd_queue = COMMAND_NONE;
+       return;
+}
+
+/* kernel thread function to read image from camera */
+static void fetch_frame(void *data)
+{
+       int image_size, retry;
+       struct cam_data *cam = (struct cam_data *)data;
+       unsigned long oldjif, rate, diff;
+
+       /* Allow up to two bad images in a row to be read and
+        * ignored before an error is reported */
+       for (retry = 0; retry < 3; ++retry) {
+               if (retry)
+                       DBG("retry=%d\n", retry);
+
+               if (!cam->ops)
+                       continue;
+
+               /* load first frame always uncompressed */
+               if (cam->first_frame &&
+                   cam->params.compression.mode != CPIA_COMPRESSION_NONE)
+                       do_command(cam, CPIA_COMMAND_SetCompression,
+                                  CPIA_COMPRESSION_NONE,
+                                  NO_DECIMATION, 0, 0);
+
+               /* init camera upload */
+               if (do_command(cam, CPIA_COMMAND_SetGrabMode,
+                              CPIA_GRAB_CONTINUOUS, 0, 0, 0))
+                       continue;
+
+               if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
+                              cam->params.streamStartLine, 0, 0))
+                       continue;
+
+               if (cam->ops->wait_for_stream_ready) {
+                       /* loop until image ready */
+                       do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
+                       while (cam->params.status.streamState != STREAM_READY) {
+                               if (current->need_resched)
+                                       schedule();
+
+                               current->state = TASK_INTERRUPTIBLE;
+
+                               /* sleep for 10 ms, hopefully ;) */
+                               schedule_timeout(10*HZ/1000);
+                               if (signal_pending(current))
+                                       return;
+
+                               do_command(cam, CPIA_COMMAND_GetCameraStatus,
+                                          0, 0, 0, 0);
+                       }
+               }
+
+               /* grab image from camera */
+               if (current->need_resched)
+                       schedule();
+
+               oldjif = jiffies;
+               image_size = cam->ops->streamRead(cam->lowlevel_data,
+                                                 cam->raw_image, 0);
+               if (image_size <= 0) {
+                       DBG("streamRead failed: %d\n", image_size);
+                       continue;
+               }
+
+               rate = image_size * HZ / 1024;
+               diff = jiffies-oldjif;
+               cam->transfer_rate = diff==0 ? rate : rate/diff;
+                       /* diff==0 ? unlikely but possible */
+
+               /* camera idle now so dispatch queued commands */
+               dispatch_commands(cam);
+
+               /* Update our knowledge of the camera state - FIXME: necessary? */
+               do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+               do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+               /* decompress and convert image to by copying it from
+                * raw_image to decompressed_frame
+                */
+               if (current->need_resched)
+                       schedule();
+
+               cam->image_size = parse_picture(cam, image_size);
+               if (cam->image_size <= 0)
+                       DBG("parse_picture failed %d\n", cam->image_size);
+               else
+                       break;
+       }
+
+       if (retry < 3) {
+               /* FIXME: this only works for double buffering */
+               if (cam->frame[cam->curframe].state == FRAME_READY) {
+                       memcpy(cam->frame[cam->curframe].data,
+                              cam->decompressed_frame.data,
+                              cam->decompressed_frame.count);
+                       cam->frame[cam->curframe].state = FRAME_DONE;
+               } else
+                       cam->decompressed_frame.state = FRAME_DONE;
+
+#if 0
+               if (cam->first_frame &&
+                   cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
+                       cam->first_frame = 0;
+                       cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+               }
+#else
+               if (cam->first_frame) {
+                       cam->first_frame = 0;
+                       cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+                       cam->cmd_queue |= COMMAND_SETEXPOSURE;
+               }
+#endif
+       }
+}
+
+static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
+{
+       int retval = 0;
+
+       if (!cam->frame_buf) {
+               /* we do lazy allocation */
+               if ((retval = allocate_frame_buf(cam)))
+                       return retval;
+       }
+       
+       /* FIXME: the first frame seems to be captured by the camera
+          without regards to any initial settings, so we throw away
+          that one, the next one is generated with our settings
+          (exposure, color balance, ...)
+       */
+       if (cam->first_frame) {
+               cam->curframe = vm->frame;
+               cam->frame[cam->curframe].state = FRAME_READY;
+               fetch_frame(cam);
+               if (cam->frame[cam->curframe].state != FRAME_DONE)
+                       retval = -EIO;
+       }
+       cam->curframe = vm->frame;
+       cam->frame[cam->curframe].state = FRAME_READY;
+       fetch_frame(cam);
+       if (cam->frame[cam->curframe].state != FRAME_DONE)
+               retval=-EIO;
+
+       return retval;
+}
+  
+static int goto_high_power(struct cam_data *cam)
+{
+       if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
+               return -1;
+       mdelay(100);            /* windows driver does it too */
+       if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+               return -1;
+       if (cam->params.status.systemState == HI_POWER_STATE) {
+               DBG("camera now in HIGH power state\n");
+               return 0;
+       }
+       printstatus(cam);
+       return -1;
+}
+
+static int goto_low_power(struct cam_data *cam)
+{
+       if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
+               return -1;
+       if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+               return -1;
+       if (cam->params.status.systemState == LO_POWER_STATE) {
+               DBG("camera now in LOW power state\n");
+               return 0;
+       }
+       printstatus(cam);
+       return -1;
+}
+
+static void save_camera_state(struct cam_data *cam)
+{
+       do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+       do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+
+       DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
+            cam->params.exposure.gain,
+            cam->params.exposure.fineExp,
+            cam->params.exposure.coarseExpLo,
+            cam->params.exposure.coarseExpHi,
+            cam->params.exposure.redComp,
+            cam->params.exposure.green1Comp,
+            cam->params.exposure.green2Comp,
+            cam->params.exposure.blueComp);
+       DBG("%d/%d/%d\n",
+            cam->params.colourBalance.redGain,
+            cam->params.colourBalance.greenGain,
+            cam->params.colourBalance.blueGain);
+}
+
+static void set_camera_state(struct cam_data *cam)
+{
+       if(cam->params.colourBalance.balanceModeIsAuto) {
+               do_command(cam, CPIA_COMMAND_SetColourBalance, 
+                          2, 0, 0, 0);
+       } else {
+               do_command(cam, CPIA_COMMAND_SetColourBalance, 
+                          1,
+                          cam->params.colourBalance.redGain,
+                          cam->params.colourBalance.greenGain,
+                          cam->params.colourBalance.blueGain);
+               do_command(cam, CPIA_COMMAND_SetColourBalance, 
+                          3, 0, 0, 0);
+       }
+
+
+       do_command_extended(cam, CPIA_COMMAND_SetExposure,
+                           cam->params.exposure.gainMode, 1, 1,
+                           cam->params.exposure.centreWeight,
+                           cam->params.exposure.gain,
+                           cam->params.exposure.fineExp,
+                           cam->params.exposure.coarseExpLo,
+                           cam->params.exposure.coarseExpHi,
+                           cam->params.exposure.redComp,
+                           cam->params.exposure.green1Comp,
+                           cam->params.exposure.green2Comp,
+                           cam->params.exposure.blueComp);
+       do_command_extended(cam, CPIA_COMMAND_SetExposure,
+                           0, 3, 0, 0,
+                           0, 0, 0, 0, 0, 0, 0, 0);
+
+       if (!cam->params.exposure.gainMode)
+               cam->params.exposure.gainMode = 2;
+       if (!cam->params.exposure.expMode)
+               cam->params.exposure.expMode = 2;
+       if (!cam->params.exposure.centreWeight)
+               cam->params.exposure.centreWeight = 1;
+       
+       cam->cmd_queue = COMMAND_SETCOMPRESSION |
+                        COMMAND_SETCOMPRESSIONTARGET |
+                        COMMAND_SETCOLOURPARAMS |
+                        COMMAND_SETFORMAT |
+                        COMMAND_SETYUVTHRESH |
+                        COMMAND_SETECPTIMING |
+                        COMMAND_SETCOMPRESSIONPARAMS |
+#if 0
+                        COMMAND_SETEXPOSURE |
+#endif
+                        COMMAND_SETCOLOURBALANCE |
+                        COMMAND_SETSENSORFPS |
+                        COMMAND_SETAPCOR |
+                        COMMAND_SETFLICKERCTRL |
+                        COMMAND_SETVLOFFSET;
+       dispatch_commands(cam);
+       save_camera_state(cam);
+
+       return;
+}
+
+static void get_version_information(struct cam_data *cam)
+{
+       /* GetCPIAVersion */
+       do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
+
+       /* GetPnPID */
+       do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
+}
+
+/* initialize camera */
+static int reset_camera(struct cam_data *cam)
+{
+       /* Start the camera in low power mode */
+       if (goto_low_power(cam)) {
+               if (cam->params.status.systemState != WARM_BOOT_STATE)
+                       return -ENODEV;
+
+               /* FIXME: this is just dirty trial and error */
+               reset_camera_struct(cam);
+               goto_high_power(cam);
+               do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
+               if (goto_low_power(cam))
+                       return -NODEV;
+       }
+       
+       /* procedure described in developer's guide p3-28 */
+       
+       /* Check the firmware version FIXME: should we check PNPID? */
+       cam->params.version.firmwareVersion = 0;
+       get_version_information(cam);
+       if (cam->params.version.firmwareVersion != 1)
+               return -ENODEV;
+       
+       /* The fatal error checking should be done after
+        * the camera powers up (developer's guide p 3-38) */
+
+       /* Set streamState before transition to high power to avoid bug
+        * in firmware 1-02 */
+       do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
+                  STREAM_NOT_READY, 0);
+       
+       /* GotoHiPower */
+       if (goto_high_power(cam))
+               return -ENODEV;
+
+       /* Check the camera status */
+       if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+               return -EIO;
+
+       if (cam->params.status.fatalError) {
+               DBG("fatal_error:              %#04x\n",
+                   cam->params.status.fatalError);
+               DBG("vp_status:                %#04x\n",
+                   cam->params.status.vpStatus);
+               if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
+                       /* Fatal error in camera */
+                       return -EIO;
+               } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
+                       /* Firmware 1-02 may do this for parallel port cameras,
+                        * just clear the flags (developer's guide p 3-38) */
+                       do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
+                                  FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
+               }
+       }
+       
+       /* Check the camera status again */
+       if (cam->params.status.fatalError) {
+               if (cam->params.status.fatalError)
+                       return -EIO;
+       }
+       
+       /* VPVersion can't be retrieved before the camera is in HiPower,
+        * so get it here instead of in get_version_information. */
+       do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
+
+       /* set camera to a known state */
+       set_camera_state(cam);
+       
+       return 0;
+}
+
+/* ------------------------- V4L interface --------------------- */
+static int cpia_open(struct video_device *dev, int flags)
+{
+       int i;
+       struct cam_data *cam = dev->priv;
+
+       if (!cam) {
+               DBG("Internal error, cam_data not found!\n");
+               return -EBUSY;
+       }
+           
+       if (cam->open_count > 0) {
+               DBG("Camera already open\n");
+               return -EBUSY;
+       }
+       
+       if (!cam->raw_image) {
+               cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
+               if (!cam->raw_image)
+                       return -ENOMEM;
+       }
+
+       if (!cam->decompressed_frame.data) {
+               cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
+               if (!cam->decompressed_frame.data) {
+                       rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+                       cam->raw_image = NULL;
+                       return -ENOMEM;
+               }
+       }
+       
+       /* open cpia */
+       if (cam->ops->open(cam->lowlevel_data)) {
+               rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+               cam->decompressed_frame.data = NULL;
+               rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+               cam->raw_image = NULL;
+               return -ENODEV;
+       }
+       
+       /* reset the camera */
+       if ((i = reset_camera(cam)) != 0) {
+               cam->ops->close(cam->lowlevel_data);
+               rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+               cam->decompressed_frame.data = NULL;
+               rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+               cam->raw_image = NULL;
+               return i;
+       }
+       
+       /* Set ownership of /proc/cpia/videoX to current user */
+       if(cam->proc_entry)
+               cam->proc_entry->uid = current->uid;
+
+       /* set mark for loading first frame uncompressed */
+       cam->first_frame = 1;
+
+       /* init it to something */
+       cam->mmap_kludge = 0;
+       
+       ++cam->open_count;
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+       return 0;
+}
+
+static void cpia_close(struct video_device *dev)
+{
+       struct cam_data *cam;
+
+       cam = dev->priv;
+
+       if (cam->ops) {
+               /* Return ownership of /proc/cpia/videoX to root */
+               if(cam->proc_entry)
+                       cam->proc_entry->uid = 0;
+       
+               /* save camera state for later open (developers guide ch 3.5.3) */
+               save_camera_state(cam);
+
+               /* GotoLoPower */
+               goto_low_power(cam);
+
+               /* Update the camera ststus */
+               do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+
+               /* cleanup internal state stuff */
+               free_frames(cam->frame);
+
+               /* close cpia */
+               cam->ops->close(cam->lowlevel_data);
+       }
+
+       if (--cam->open_count == 0) {
+               /* clean up capture-buffers */
+               if (cam->raw_image) {
+                       rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
+                       cam->raw_image = NULL;
+               }
+
+               if (cam->decompressed_frame.data) {
+                       rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
+                       cam->decompressed_frame.data = NULL;
+               }
+
+               if (cam->frame_buf)
+                       free_frame_buf(cam);
+
+               if (!cam->ops) {
+                       video_unregister_device(dev);
+                       kfree(cam);
+               }
+       }
+       
+
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+       return;
+}
+
+static long cpia_read(struct video_device *dev, char *buf,
+                      unsigned long count, int noblock)
+{
+       struct cam_data *cam = dev->priv;
+
+       /* make this _really_ smp and multithredi-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -EINTR;
+
+       if (!buf) {
+               DBG("buf NULL\n");
+               up(&cam->busy_lock);
+               return -EINVAL;
+       }
+
+       if (!count) {
+               DBG("count 0\n");
+               up(&cam->busy_lock);
+               return 0;
+       }
+
+       if (!cam->ops) {
+               DBG("ops NULL\n");
+               up(&cam->busy_lock);
+               return -ENODEV;
+       }
+
+       /* upload frame */
+       cam->decompressed_frame.state = FRAME_READY;
+       cam->mmap_kludge=0;
+       fetch_frame(cam);
+       if (cam->decompressed_frame.state != FRAME_DONE) {
+               DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
+                   cam->decompressed_frame.state);
+               up(&cam->busy_lock);
+               return -EIO;
+       }
+       cam->decompressed_frame.state = FRAME_UNUSED;
+
+       /* copy data to user space */
+       if (cam->decompressed_frame.count > count) {
+               DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
+                   count);
+               up(&cam->busy_lock);
+               return -EFAULT;
+       }
+       if (copy_to_user(buf, cam->decompressed_frame.data,
+                       cam->decompressed_frame.count)) {
+               DBG("copy_to_user failed\n");
+               up(&cam->busy_lock);
+               return -EFAULT;
+       }
+
+       up(&cam->busy_lock);
+       return cam->decompressed_frame.count;
+}
+
+static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
+{
+       struct cam_data *cam = dev->priv;
+       int retval = 0;
+
+       if (!cam || !cam->ops)
+               return -ENODEV;
+       
+       /* make this _really_ smp-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -EINTR;
+
+       //DBG("cpia_ioctl: %u\n", ioctlnr);
+
+       switch (ioctlnr) {
+       /* query capabilites */
+       case VIDIOCGCAP:
+       {
+               struct video_capability b;
+
+               DBG("VIDIOCGCAP\n");
+               strcpy(b.name, "CPiA Camera");
+               b.type = VID_TYPE_CAPTURE;
+               b.channels = 1;
+               b.audios = 0;
+               b.maxwidth = 352;       /* VIDEOSIZE_CIF */
+               b.maxheight = 288;
+               b.minwidth = 48;        /* VIDEOSIZE_48_48 */
+               b.minheight = 48;
+
+               if (copy_to_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, 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(arg, &v, sizeof(v)))
+                       retval = -EFAULT;
+               break;
+       }
+       
+       case VIDIOCSCHAN:
+       {
+               int v;
+
+               DBG("VIDIOCSCHAN\n");
+               if (copy_from_user(&v, arg, sizeof(v)))
+                       retval = -EFAULT;
+
+               if (retval == 0 && v != 0)
+                       retval = -EINVAL;
+
+               break;
+       }
+
+       /* image properties */
+       case VIDIOCGPICT:
+               DBG("VIDIOCGPICT\n");
+               if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
+                       retval = -EFAULT;
+               break;
+       
+       case VIDIOCSPICT:
+       {
+               struct video_picture vp;
+
+               DBG("VIDIOCSPICT\n");
+
+               /* copy_from_user */
+               if (copy_from_user(&vp, arg, sizeof(vp))) {
+                       retval = -EFAULT;
+                       break;
+               }
+
+               /* check validity */
+               DBG("palette: %d\n", vp.palette);
+               DBG("depth: %d\n", vp.depth);
+               if (!valid_mode(vp.palette, vp.depth)) {
+                       retval = -EINVAL;
+                       break;
+               }
+
+               down(&cam->param_lock);
+               /* brightness, colour, contrast need no check 0-65535 */
+               memcpy( &cam->vp, &vp, sizeof(vp) );
+               /* update cam->params.colourParams */
+               cam->params.colourParams.brightness = vp.brightness*100/65535;
+               cam->params.colourParams.contrast = vp.contrast*100/65535;
+               cam->params.colourParams.saturation = vp.colour*100/65535;
+               /* contrast is in steps of 8, so round */
+               cam->params.colourParams.contrast =
+                       ((cam->params.colourParams.contrast + 3) / 8) * 8;
+               if (cam->params.version.firmwareVersion == 1 &&
+                   cam->params.version.firmwareRevision == 2 &&
+                   cam->params.colourParams.contrast > 80) {
+                       /* 1-02 firmware limits contrast to 80 */
+                       cam->params.colourParams.contrast = 80;
+               }
+
+               /* queue command to update camera */
+               cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
+               up(&cam->param_lock);
+               DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
+                   vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
+                   vp.contrast);
+               break;
+       }
+
+       /* get/set capture window */
+       case VIDIOCGWIN:
+               DBG("VIDIOCGWIN\n");
+
+               if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
+                       retval = -EFAULT;
+               break;
+       
+       case VIDIOCSWIN:
+       {
+               /* copy_from_user, check validity, copy to internal structure */
+               struct video_window vw;
+               DBG("VIDIOCSWIN\n");
+               if (copy_from_user(&vw, arg, sizeof(vw))) {
+                       retval = -EFAULT;
+                       break;
+               }
+
+               if (vw.clipcount != 0) {    /* clipping not supported */
+                       retval = -EINVAL;
+                       break;
+               }
+               if (vw.clips != NULL) {     /* clipping not supported */
+                       retval = -EINVAL;
+                       break;
+               }
+
+               /* we set the video window to something smaller or equal to what
+               * is requested by the user???
+               */
+               down(&cam->param_lock);
+               if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
+                       int video_size = match_videosize(vw.width, vw.height);
+
+                       if (video_size < 0) {
+                               retval = -EINVAL;
+                               up(&cam->param_lock);
+                               break;
+                       }
+                       cam->video_size = video_size;
+                       set_vw_size(cam);
+                       DBG("%d / %d\n", cam->vw.width, cam->vw.height);
+                       cam->cmd_queue |= COMMAND_SETFORMAT;
+               }
+
+               // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
+               up(&cam->param_lock);
+
+               /* setformat ignored by camera during streaming,
+                * so stop/dispatch/start */
+               if (cam->cmd_queue & COMMAND_SETFORMAT) {
+                       DBG("\n");
+                       dispatch_commands(cam);
+               }
+               DBG("%d/%d:%d\n", cam->video_size,
+                   cam->vw.width, cam->vw.height);
+               break;
+       }
+
+       /* mmap interface */
+       case VIDIOCGMBUF:
+       {
+               struct video_mbuf vm;
+               int i;
+
+               DBG("VIDIOCGMBUF\n");
+               memset(&vm, 0, sizeof(vm));
+               vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
+               vm.frames = FRAME_NUM;
+               for (i = 0; i < FRAME_NUM; i++)
+                       vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
+
+               if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+                       retval = -EFAULT;
+
+               break;
+       }
+       
+       case VIDIOCMCAPTURE:
+       {
+               struct video_mmap vm;
+               int video_size;
+
+               if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
+                       retval = -EFAULT;
+                       break;
+               }
+#if 1
+               DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
+                   vm.width, vm.height);
+#endif
+               if (vm.frame<0||vm.frame>FRAME_NUM) {
+                       retval = -EINVAL;
+                       break;
+               }
+
+               /* set video format */
+               cam->vp.palette = vm.format;
+               switch(vm.format) {
+               case VIDEO_PALETTE_GREY:
+               case VIDEO_PALETTE_RGB555:
+               case VIDEO_PALETTE_RGB565:
+               case VIDEO_PALETTE_YUV422:
+               case VIDEO_PALETTE_YUYV:
+               case VIDEO_PALETTE_UYVY:
+                       cam->vp.depth = 16;
+                       break;
+               case VIDEO_PALETTE_RGB24:
+                       cam->vp.depth = 24;
+                       break;
+               case VIDEO_PALETTE_RGB32:
+                       cam->vp.depth = 32;
+                       break;
+               default:
+                       retval = -EINVAL;
+                       break;
+               }
+               if (retval)
+                       break;
+
+               /* set video size */
+               video_size = match_videosize(vm.width, vm.height);
+               if (cam->video_size < 0) {
+                       retval = -EINVAL;
+                       break;
+               }
+               if (video_size != cam->video_size) {
+                       cam->video_size = video_size;
+                       set_vw_size(cam);
+                       cam->cmd_queue |= COMMAND_SETFORMAT;
+                       dispatch_commands(cam);
+               }
+#if 0
+               DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
+                   cam->vw.width, cam->vw.height);
+#endif
+               /* according to v4l-spec we must start streaming here */
+               cam->mmap_kludge = 1;
+               retval = capture_frame(cam, &vm);
+
+               break;
+       }
+       
+       case VIDIOCSYNC:
+       {
+               int frame;
+
+               if (copy_from_user((void *)&frame, arg, sizeof(int))) {
+                       retval = -EFAULT;
+                       break;
+               }
+               //DBG("VIDIOCSYNC: %d\n", frame);
+
+               if (frame<0 || frame >= FRAME_NUM) {
+                       retval = -EINVAL;
+                       break;
+               }
+
+               switch (cam->frame[frame].state) {
+               case FRAME_UNUSED:
+               case FRAME_READY:
+               case FRAME_GRABBING:
+                       DBG("sync to unused frame %d\n", frame);
+                       retval = -EINVAL;
+                       break;
+
+               case FRAME_DONE:
+                       cam->frame[frame].state = FRAME_UNUSED;
+                       //DBG("VIDIOCSYNC: %d synced\n", frame);
+                       break;
+               }
+               if (retval == -EINTR) {
+                       /* FIXME - xawtv does not handle this nice */
+                       retval = 0;
+               }
+               break;
+       }
+
+       /* pointless to implement overlay with this camera */
+       case VIDIOCCAPTURE:
+               retval = -EINVAL;
+               break;
+       case VIDIOCGFBUF:
+               retval = -EINVAL;
+               break;
+       case VIDIOCSFBUF:
+               retval = -EINVAL;
+               break;
+       case VIDIOCKEY:
+               retval = -EINVAL;
+               break;
+
+       /* tuner interface - we have none */
+       case VIDIOCGTUNER:
+               retval = -EINVAL;
+               break;
+       case VIDIOCSTUNER:
+               retval = -EINVAL;
+               break;
+       case VIDIOCGFREQ:
+               retval = -EINVAL;
+               break;
+       case VIDIOCSFREQ:
+               retval = -EINVAL;
+               break;
+
+       /* audio interface - we have none */
+       case VIDIOCGAUDIO:
+               retval = -EINVAL;
+               break;
+       case VIDIOCSAUDIO:
+               retval = -EINVAL;
+               break;
+       default:
+               retval = -ENOIOCTLCMD;
+               break;
+       }
+
+       up(&cam->param_lock);
+       up(&cam->busy_lock);
+       return retval;
+} 
+
+/* FIXME */
+static int cpia_mmap(struct video_device *dev, const char *adr,
+                     unsigned long size)
+{
+       unsigned long start = (unsigned long)adr;
+       unsigned long page, pos;
+       struct cam_data *cam = dev->priv;
+       int retval;
+
+       if (!cam || !cam->ops)
+               return -ENODEV;
+       
+       DBG("cpia_mmap: %ld\n", size);
+
+       if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
+               return -EINVAL;
+
+       if (!cam || !cam->ops)
+               return -ENODEV;
+       
+       /* make this _really_ smp-safe */
+       if (down_interruptible(&cam->busy_lock))
+               return -EINTR;
+
+       if (!cam->frame_buf) {  /* we do lazy allocation */
+               if ((retval = allocate_frame_buf(cam))) {
+                       up(&cam->busy_lock);
+                       return retval;
+               }
+       }
+
+       pos = (unsigned long)(cam->frame_buf);
+       while (size > 0) {
+               page = kvirt_to_pa(pos);
+               if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+                       up(&cam->busy_lock);
+                       return -EAGAIN;
+               }
+               start += PAGE_SIZE;
+               pos += PAGE_SIZE;
+               if (size > PAGE_SIZE)
+                       size -= PAGE_SIZE;
+               else
+                       size = 0;
+       }
+
+       DBG("cpia_mmap: %ld\n", size);
+       up(&cam->busy_lock);
+
+       return 0;
+}
+
+int cpia_video_init(struct video_device *vdev)
+{
+#ifdef CONFIG_PROC_FS
+       create_proc_cpia_cam(vdev->priv);
+#endif
+       return 0;
+}
+
+static struct video_device cpia_template = {
+       "CPiA Camera",
+       VID_TYPE_CAPTURE,
+       VID_HARDWARE_CPIA,      /* FIXME */
+       cpia_open,              /* open */
+       cpia_close,             /* close */
+       cpia_read,              /* read */
+       NULL,                   /* no write */
+       NULL,                   /* no poll */
+       cpia_ioctl,             /* ioctl */
+       cpia_mmap,              /* mmap */
+       cpia_video_init,        /* initialize */
+       NULL,                   /* priv */
+       0,                      /* busy */
+       -1                      /* minor - unset */
+};
+
+/* initialise cam_data structure  */
+static void reset_camera_struct(struct cam_data *cam)
+{
+       /* The following parameter values are the defaults from
+        * "Software Developer's Guide for CPiA Cameras".  Any changes
+        * to the defaults are noted in comments. */
+       cam->params.colourParams.brightness = 50;
+       cam->params.colourParams.contrast = 48;
+       cam->params.colourParams.saturation = 50;
+       cam->params.exposure.gainMode = 2;
+       cam->params.exposure.expMode = 2;               /* AEC */
+       cam->params.exposure.compMode = 1;
+       cam->params.exposure.centreWeight = 1;
+       cam->params.exposure.gain = 0;
+       cam->params.exposure.fineExp = 0;
+       cam->params.exposure.coarseExpLo = 185;
+       cam->params.exposure.coarseExpHi = 0;
+       cam->params.exposure.redComp = 220;
+       cam->params.exposure.green1Comp = 214;
+       cam->params.exposure.green2Comp = 214;
+       cam->params.exposure.blueComp = 230;
+       cam->params.colourBalance.balanceModeIsAuto = 1;
+       cam->params.colourBalance.redGain = 32;
+       cam->params.colourBalance.greenGain = 6;
+       cam->params.colourBalance.blueGain = 92;
+       cam->params.apcor.gain1 = 0x1c;
+       cam->params.apcor.gain2 = 0x1a;
+       cam->params.apcor.gain4 = 0x2d;
+       cam->params.apcor.gain8 = 0x2a;
+       cam->params.flickerControl.flickerMode = 0;
+       cam->params.flickerControl.coarseJump = 
+               flicker_jumps[cam->mainsFreq]
+                            [cam->params.sensorFps.baserate]
+                            [cam->params.sensorFps.divisor];
+       cam->params.vlOffset.gain1 = 24;
+       cam->params.vlOffset.gain2 = 28;
+       cam->params.vlOffset.gain4 = 30;
+       cam->params.vlOffset.gain8 = 30;
+       cam->params.compressionParams.hysteresis = 3;
+       cam->params.compressionParams.threshMax = 11;
+       cam->params.compressionParams.smallStep = 1;
+       cam->params.compressionParams.largeStep = 3;
+       cam->params.compressionParams.decimationHysteresis = 2;
+       cam->params.compressionParams.frDiffStepThresh = 5;
+       cam->params.compressionParams.qDiffStepThresh = 3;
+       cam->params.compressionParams.decimationThreshMod = 2;
+       /* End of default values from Software Developer's Guide */
+       
+       cam->transfer_rate = 0;
+       
+       /* Set Sensor FPS to 15fps. This seems better than 30fps
+        * for indoor lighting. */
+       cam->params.sensorFps.divisor = 1;
+       cam->params.sensorFps.baserate = 1;
+       
+       cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
+       cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+       
+       cam->params.format.subSample = SUBSAMPLE_422;
+       cam->params.format.yuvOrder = YUVORDER_YUYV;
+       
+       cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
+       cam->params.compressionTarget.frTargeting =
+               CPIA_COMPRESSION_TARGET_QUALITY;
+       cam->params.compressionTarget.targetFR = 7; /* FIXME? */
+       cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+
+       cam->video_size = VIDEOSIZE_CIF;
+       
+       cam->vp.colour = 32768;      /* 50% */
+       cam->vp.hue = 32768;         /* 50% */
+       cam->vp.brightness = 32768;  /* 50% */
+       cam->vp.contrast = 32768;    /* 50% */
+       cam->vp.whiteness = 0;       /* not used -> grayscale only */
+       cam->vp.depth = 0;           /* FIXME: to be set by user? */
+       cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
+
+       cam->vw.x = 0;
+       cam->vw.y = 0;
+       set_vw_size(cam);
+       cam->vw.chromakey = 0;
+       /* PP NOTE: my extension to use vw.flags for this, bear it! */
+       cam->vw.flags = 0;
+       cam->vw.clipcount = 0;
+       cam->vw.clips = NULL;
+
+       cam->cmd_queue = COMMAND_NONE;
+       cam->first_frame = 0;
+
+       return;
+}
+
+/* initialize cam_data structure  */
+static void init_camera_struct(struct cam_data *cam,
+                               struct cpia_camera_ops *ops )
+{
+       int i;
+
+       /* Default everything to 0 */
+       memset(cam, 0, sizeof(struct cam_data));
+
+       cam->ops = ops;
+       init_MUTEX(&cam->param_lock);
+       init_MUTEX(&cam->busy_lock);
+
+       reset_camera_struct(cam);
+
+       cam->proc_entry = NULL;
+
+       memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
+       cam->vdev.priv = cam;
+       
+       cam->curframe = 0;
+       for (i = 0; i < FRAME_NUM; i++) {
+               cam->frame[i].width = 0;
+               cam->frame[i].height = 0;
+               cam->frame[i].state = FRAME_UNUSED;
+               cam->frame[i].data = NULL;
+       }
+       cam->decompressed_frame.width = 0;
+       cam->decompressed_frame.height = 0;
+       cam->decompressed_frame.state = FRAME_UNUSED;
+       cam->decompressed_frame.data = NULL;
+}
+
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
+{
+        struct cam_data *camera;
+       
+       /* Need a lock when adding/removing cameras.  This doesn't happen
+        * often and doesn't take very long, so grabbing the kernel lock
+        * should be OK. */
+       
+       if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
+               unlock_kernel();
+               return NULL;
+       }
+       
+       init_camera_struct( camera, ops );
+       camera->lowlevel_data = lowlevel;
+       
+       /* register v4l device */
+       if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
+               kfree(camera);
+               unlock_kernel();
+               printk(KERN_DEBUG "video_register_device failed\n");
+               return NULL;
+       }
+
+       /* get version information from camera: open/reset/close */
+
+       /* open cpia */
+       if (camera->ops->open(camera->lowlevel_data))
+               return camera;
+       
+       /* reset the camera */
+       if (reset_camera(camera) != 0) {
+               camera->ops->close(camera->lowlevel_data);
+               return camera;
+       }
+
+       /* close cpia */
+       camera->ops->close(camera->lowlevel_data);
+
+/* Eh? Feeling happy? - jerdfelt */
+/*
+       camera->ops->open(camera->lowlevel_data);
+       camera->ops->close(camera->lowlevel_data);
+*/
+       
+       printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
+              camera->params.version.firmwareVersion,
+              camera->params.version.firmwareRevision,
+              camera->params.version.vcVersion,
+              camera->params.version.vcRevision);
+       printk(KERN_INFO "  CPiA PnP-ID: %04x:%04x:%04x\n",
+              camera->params.pnpID.vendor,
+              camera->params.pnpID.product,
+              camera->params.pnpID.deviceRevision);
+       printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
+              camera->params.vpVersion.vpVersion,
+              camera->params.vpVersion.vpRevision,
+              camera->params.vpVersion.cameraHeadID);
+
+       return camera;
+}
+
+void cpia_unregister_camera(struct cam_data *cam)
+{
+       if (!cam->open_count) {
+               DBG("unregistering video\n");
+               video_unregister_device(&cam->vdev);
+       } else {
+               LOG("/dev/video%d removed while open, "
+                   "deferring video_unregister_device\n", cam->vdev.minor);
+               DBG("camera open -- setting ops to NULL\n");
+               cam->ops = NULL;
+       }
+       
+#ifdef CONFIG_PROC_FS
+       DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
+       destroy_proc_cpia_cam(cam);
+#endif 
+       if (!cam->open_count) {
+               DBG("freeing camera\n");
+               kfree(cam);
+       }
+}
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+#ifdef MODULE
+int init_module(void)
+{
+       printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+              CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
+       proc_cpia_create();
+#endif
+#ifdef CONFIG_KMOD
+#ifdef CONFIG_VIDEO_CPIA_PP_MODULE
+       request_module("cpia_pp");
+#endif
+#ifdef CONFIG_VIDEO_CPIA_USB_MODULE
+       request_module("cpia_usb");
+#endif
+#endif
+return 0;
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_PROC_FS
+       proc_cpia_destroy();
+#endif
+}
+
+#else
+
+int cpia_init(struct video_init *unused)
+{
+       printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
+              CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
+       proc_cpia_create();
+#endif
+
+#ifdef CONFIG_VIDEO_CPIA_PP
+       cpia_pp_init();
+#endif
+#ifdef CONFIG_KMOD
+#ifdef CONFIG_VIDEO_CPIA_PP_MODULE
+       request_module("cpia_pp");
+#endif
+
+#ifdef CONFIG_VIDEO_CPIA_USB_MODULE
+       request_module("cpia_usb");
+#endif
+#endif /* CONFIG_KMOD */
+#ifdef CONFIG_VIDEO_CPIA_USB
+       cpia_usb_init();
+#endif
+       return 0;
+}
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(cpia_register_camera);
+EXPORT_SYMBOL(cpia_unregister_camera);
+
+#endif
diff -urN linux-2.3.99-pre3.orig/drivers/char/cpia.h 
linux-2.3.99-pre3/drivers/char/cpia.h
--- linux-2.3.99-pre3.orig/drivers/char/cpia.h  Wed Dec 31 16:00:00 1969
+++ linux-2.3.99-pre3/drivers/char/cpia.h       Fri Mar 24 13:57:52 2000
@@ -0,0 +1,421 @@
+#ifndef cpia_h
+#define cpia_h
+
+/*
+ * CPiA Parallel Port Video4Linux driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman,
+ *                    Peter Pregler,
+ *                    Scott J. Bertin,
+ *                    VLSI Vision Ltd.
+ *
+ * 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.
+ */
+
+#define CPIA_MAJ_VER   0
+#define CPIA_MIN_VER    7
+#define CPIA_PATCH_VER 4
+
+#define CPIA_PP_MAJ_VER       0
+#define CPIA_PP_MIN_VER       7
+#define CPIA_PP_PATCH_VER     4
+
+#define CPIA_MAX_FRAME_SIZE_UNALIGNED  (352 * 288 * 4)   /* CIF at RGB32 */
+#define CPIA_MAX_FRAME_SIZE    ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & 
+~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
+
+#ifdef __KERNEL__
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+struct cpia_camera_ops
+{
+       /* open sets privdata to point to structure for this camera.
+         * Returns negative value on error, otherwise 0.
+        */
+       int (*open)(void *privdata);
+       
+       /* Registers callback function cb to be called with cbdata
+        * when an image is ready.  If cb is NULL, only single image grabs
+        * should be used.  cb should immediately call streamRead to read
+        * the data or data may be lost. Returns negative value on error,
+        * otherwise 0.
+        */
+       int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
+                               void *cbdata);
+       
+       /* transferCmd sends commands to the camera.  command MUST point to
+        * an  8 byte buffer in kernel space. data can be NULL if no extra
+        * data is needed.  The size of the data is given by the last 2
+        * bytes of comand.  data must also point to memory in kernel space.
+        * Returns negative value on error, otherwise 0.
+        */
+       int (*transferCmd)(void *privdata, u8 *command, u8 *data);
+
+       /* streamStart initiates stream capture mode.
+        * Returns negative value on error, otherwise 0.
+        */
+       int (*streamStart)(void *privdata);
+       
+       /* streamStop terminates stream capture mode.
+        * Returns negative value on error, otherwise 0.
+        */
+       int (*streamStop)(void *privdata);
+        
+       /* streamRead reads a frame from the camera.  buffer points to a
+         * buffer large enough to hold a complete frame in kernel space.
+         * noblock indicates if this should be a non blocking read.
+        * Returns the number of bytes read, or negative value on error.
+         */
+       int (*streamRead)(void *privdata, u8 *buffer, int noblock);
+       
+       /* close disables the device until open() is called again.
+        * Returns negative value on error, otherwise 0.
+        */
+       int (*close)(void *privdata);
+       
+       /* If wait_for_stream_ready is non-zero, wait until the streamState
+        * is STREAM_READY before calling streamRead.
+        */
+       int wait_for_stream_ready;
+};
+
+struct cpia_frame {
+       u8 *data;
+       int count;
+       int width;
+       int height;
+       volatile int state;
+};
+
+struct cam_params {
+       struct {
+               u8 firmwareVersion;
+               u8 firmwareRevision;
+               u8 vcVersion;
+               u8 vcRevision;
+       } version;
+       struct {
+               u16 vendor;
+               u16 product;
+               u16 deviceRevision;
+       } pnpID;
+       struct {
+               u8 vpVersion;
+               u8 vpRevision;
+               u16 cameraHeadID;
+       } vpVersion;
+       struct {
+               u8 systemState;
+               u8 grabState;
+               u8 streamState;
+               u8 fatalError;
+               u8 cmdError;
+               u8 debugFlags;
+               u8 vpStatus;
+               u8 errorCode;
+       } status;
+       struct {
+               u8 brightness;
+               u8 contrast;
+               u8 saturation;
+       } colourParams;
+       struct {
+               u8 gainMode;
+               u8 expMode;
+               u8 compMode;
+               u8 centreWeight;
+               u8 gain;
+               u8 fineExp;
+               u8 coarseExpLo;
+               u8 coarseExpHi;
+               u8 redComp;
+               u8 green1Comp;
+               u8 green2Comp;
+               u8 blueComp;
+       } exposure;
+       struct {
+               u8 balanceModeIsAuto;
+               u8 redGain;
+               u8 greenGain;
+               u8 blueGain;
+       } colourBalance;
+       struct {
+               u8 divisor;
+               u8 baserate;
+       } sensorFps;
+       struct {
+               u8 gain1;
+               u8 gain2;
+               u8 gain4;
+               u8 gain8;
+       } apcor;
+       struct {
+               u8 flickerMode;
+               u8 coarseJump;
+               u8 allowableOverExposure;
+       } flickerControl;
+       struct {
+               u8 gain1;
+               u8 gain2;
+               u8 gain4;
+               u8 gain8;
+       } vlOffset;
+       struct {
+               u8 mode;
+               u8 decimation;
+       } compression;
+       struct {
+               u8 frTargeting;
+               u8 targetFR;
+               u8 targetQ;
+       } compressionTarget;
+       struct {
+               u8 yThreshold;
+               u8 uvThreshold;
+       } yuvThreshold;
+       struct {
+               u8 hysteresis;
+               u8 threshMax;
+               u8 smallStep;
+               u8 largeStep;
+               u8 decimationHysteresis;
+               u8 frDiffStepThresh;
+               u8 qDiffStepThresh;
+               u8 decimationThreshMod;
+       } compressionParams;
+       struct {
+               u8 videoSize;           /* CIF/QCIF */
+               u8 subSample;
+               u8 yuvOrder;
+       } format;
+       struct {
+               u8 colStart;            /* skip first 8*colStart pixels */
+               u8 colEnd;              /* finish at 8*colEnd pixels */
+               u8 rowStart;            /* skip first 4*rowStart lines */
+               u8 rowEnd;              /* finish at 4*rowEnd lines */
+       } roi;
+       u8 ecpTiming;
+       u8 streamStartLine;
+};
+
+enum v4l_camstates {
+       CPIA_V4L_IDLE = 0,
+       CPIA_V4L_ERROR,
+       CPIA_V4L_COMMAND,
+       CPIA_V4L_GRABBING,
+       CPIA_V4L_STREAMING,
+       CPIA_V4L_STREAMING_PAUSED,
+};
+
+#define FRAME_NUM      2       /* double buffering for now */
+
+struct cam_data {
+       struct cam_data **previous;
+       struct cam_data *next;
+
+        struct semaphore busy_lock;     /* guard against SMP multithreading */
+       struct cpia_camera_ops *ops;    /* lowlevel driver operations */
+       void *lowlevel_data;            /* private data for lowlevel driver */
+       u8 *raw_image;                  /* buffer for raw image data */
+       struct cpia_frame decompressed_frame;
+                                        /* buffer to hold decompressed frame */
+       int image_size;                 /* sizeof last decompressed image */
+       int open_count;                 /* # of process that have camera open */
+
+                               /* camera status */
+       int fps;                        /* actual fps reported by the camera */
+       int transfer_rate;              /* transfer rate from camera in kB/s */
+       u8 mainsFreq;                   /* for flicker control */
+
+                               /* proc interface */
+       struct semaphore param_lock;    /* params lock for this camera */
+       struct cam_params params;       /* camera settings */
+       struct proc_dir_entry *proc_entry;      /* /proc/cpia/videoX */
+       
+                                       /* v4l */
+       int video_size;                 /* VIDEO_SIZE_ */
+       volatile enum v4l_camstates camstate;   /* v4l layer status */
+       struct video_device vdev;       /* v4l videodev */
+       struct video_picture vp;        /* v4l camera settings */
+       struct video_window vw;         /* v4l capture area */
+
+                               /* mmap interface */
+       int curframe;                   /* the current frame to grab into */
+       u8 *frame_buf;                  /* frame buffer data */
+        struct cpia_frame frame[FRAME_NUM];
+                               /* FRAME_NUM-buffering, so we need a array */
+
+       int first_frame;
+       int mmap_kludge;                /* 'wrong' byte order for mmap */
+       volatile u32 cmd_queue;         /* queued commands */
+};
+
+/* cpia_register_camera is called by low level driver for each camera.
+ * A unique camera number is returned, or a negative value on error */
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
+
+/* cpia_unregister_camera is called by low level driver when a camera
+ * is removed.  This must not fail. */
+void cpia_unregister_camera(struct cam_data *cam);
+
+/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
+ * one byte 16bit DMA alignment
+ */
+#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
+
+/* constant value's */
+#define MAGIC_0                0x19
+#define MAGIC_1                0x68
+#define DATA_IN                0xC0
+#define DATA_OUT       0x40
+#define VIDEOSIZE_QCIF 0       /* 176x144 */
+#define VIDEOSIZE_CIF  1       /* 352x288 */
+#define VIDEOSIZE_SIF  2       /* 320x240 */
+#define VIDEOSIZE_QSIF 3       /* 160x120 */
+#define VIDEOSIZE_48_48                4 /* where no one has gone before, iconsize! */
+#define VIDEOSIZE_64_48                5
+#define VIDEOSIZE_128_96       6
+#define VIDEOSIZE_160_120      VIDEOSIZE_QSIF
+#define VIDEOSIZE_176_144      VIDEOSIZE_QCIF
+#define VIDEOSIZE_192_144      7
+#define VIDEOSIZE_224_168      8
+#define VIDEOSIZE_256_192      9
+#define VIDEOSIZE_288_216      10
+#define VIDEOSIZE_320_240      VIDEOSIZE_SIF
+#define VIDEOSIZE_352_288      VIDEOSIZE_CIF
+#define VIDEOSIZE_88_72                11 /* quarter CIF */
+#define SUBSAMPLE_420  0
+#define SUBSAMPLE_422  1
+#define YUVORDER_YUYV  0
+#define YUVORDER_UYVY  1
+#define NOT_COMPRESSED 0
+#define COMPRESSED     1
+#define NO_DECIMATION  0
+#define DECIMATION_ENAB        1
+#define EOI            0xff    /* End Of Image */
+#define EOL            0xfd    /* End Of Line */
+#define FRAME_HEADER_SIZE      64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE       0
+#define CPIA_GRAB_CONTINUOUS   1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE  0
+#define CPIA_COMPRESSION_AUTO  1
+#define CPIA_COMPRESSION_MANUAL        2
+#define CPIA_COMPRESSION_TARGET_QUALITY         0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE       1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE    0
+#define GRABSTATE      1
+#define STREAMSTATE    2
+#define FATALERROR     3
+#define CMDERROR       4
+#define DEBUGFLAGS     5
+#define VPSTATUS       6
+#define ERRORCODE      7
+
+/* SystemState */
+#define UNINITIALISED_STATE    0
+#define PASS_THROUGH_STATE     1
+#define LO_POWER_STATE         2
+#define HI_POWER_STATE         3
+#define WARM_BOOT_STATE                4
+
+/* GrabState */
+#define GRAB_IDLE              0
+#define GRAB_ACTIVE            1
+#define GRAB_DONE              2
+
+/* StreamState */
+#define STREAM_NOT_READY       0
+#define STREAM_READY           1
+#define STREAM_OPEN            2
+#define STREAM_PAUSED          3
+#define STREAM_FINISHED                4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG        1
+#define SYSTEM_FLAG      2
+#define INT_CTRL_FLAG    4
+#define PROCESS_FLAG     8
+#define COM_FLAG        16
+#define VP_CTRL_FLAG    32
+#define CAPTURE_FLAG    64
+#define DEBUG_FLAG     128
+
+/* VPStatus */
+#define VP_STATE_OK                    0x00
+
+#define VP_STATE_FAILED_VIDEOINIT      0x01
+#define VP_STATE_FAILED_AECACBINIT     0x02
+#define VP_STATE_AEC_MAX               0x04
+#define VP_STATE_ACB_BMAX              0x08
+
+#define VP_STATE_ACB_RMIN              0x10
+#define VP_STATE_ACB_GMIN              0x20
+#define VP_STATE_ACB_RMAX              0x40
+#define VP_STATE_ACB_GMAX              0x80
+
+/* ErrorCode */
+#define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum 
+exposure */
+
+#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
+#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO 
+__FILE__":"__FUNCTION__"(%d):"fmt,##args)
+
+#ifdef _CPIA_DEBUG_
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG 
+__FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DEB_BYTE(p)\
+  DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
+      (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
+        (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+
+#define ADD_TO_LIST(l, drv) \
+  {\
+    lock_kernel();\
+    (drv)->next = l;\
+    (drv)->previous = &(l);\
+    (l) = drv;\
+    unlock_kernel();\
+  } while(0)
+
+#define REMOVE_FROM_LIST(drv) \
+  {\
+    if ((drv)->previous != NULL) {\
+      lock_kernel();\
+      if ((drv)->next != NULL)\
+        (drv)->next->previous = (drv)->previous;\
+      *((drv)->previous) = (drv)->next;\
+      (drv)->previous = NULL;\
+      (drv)->next = NULL;\
+      unlock_kernel();\
+    }\
+  } while (0)
+
+
+#endif /* __KERNEL__ */
+
+#endif /* cpia_h */
diff -urN linux-2.3.99-pre3.orig/drivers/char/cpia_pp.c 
linux-2.3.99-pre3/drivers/char/cpia_pp.c
--- linux-2.3.99-pre3.orig/drivers/char/cpia_pp.c       Wed Dec 31 16:00:00 1969
+++ linux-2.3.99-pre3/drivers/char/cpia_pp.c    Fri Mar 24 14:25:26 2000
@@ -0,0 +1,745 @@
+/*
+ * cpia_pp CPiA Parallel Port driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman <[EMAIL PROTECTED]>
+ * (C) Copyright 1999-2000 Scott J. Bertin <[EMAIL PROTECTED]>,
+ * (C) Copyright 1999-2000 Peter Pregler <[EMAIL PROTECTED]>
+ *
+ * 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/version.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+/* #define _CPIA_DEBUG_                define for verbose debug output */
+#include "cpia.h"
+
+static int cpia_pp_open(void *privdata);
+static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
+                                    void *cbdata);
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_pp_streamStart(void *privdata);
+static int cpia_pp_streamStop(void *privdata);
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
+static int cpia_pp_close(void *privdata);
+
+#define ABOUT "Parallel port driver for Vision CPiA based cameras"
+
+/* IEEE 1284 Compatiblity Mode signal names    */
+#define nStrobe                PARPORT_CONTROL_STROBE    /* inverted */
+#define nAutoFd                PARPORT_CONTROL_AUTOFD    /* inverted */
+#define nInit          PARPORT_CONTROL_INIT
+#define nSelectIn      PARPORT_CONTROL_SELECT
+#define IntrEnable     PARPORT_CONTROL_INTEN     /* normally zero for no IRQ */
+#define DirBit         PARPORT_CONTROL_DIRECTION /* 0 = Forward, 1 = Reverse   */
+
+#define nFault         PARPORT_STATUS_ERROR
+#define Select         PARPORT_STATUS_SELECT
+#define PError         PARPORT_STATUS_PAPEROUT
+#define nAck           PARPORT_STATUS_ACK
+#define Busy           PARPORT_STATUS_BUSY       /* inverted */        
+
+/* some more */
+#define HostClk                nStrobe
+#define HostAck                nAutoFd
+#define nReverseRequest        nInit
+#define Active_1284    nSelectIn
+#define nPeriphRequest nFault
+#define XFlag          Select
+#define nAckReverse    PError
+#define PeriphClk      nAck
+#define PeriphAck      Busy
+
+/* these can be used to correct for the inversion on some bits */
+#define STATUS_INVERSION_MASK  (Busy)
+#define CONTROL_INVERSION_MASK (nStrobe|nAutoFd|nSelectIn)
+
+#define ECR_empty      0x01
+#define ECR_full       0x02
+#define ECR_serviceIntr 0x04
+#define ECR_dmaEn      0x08
+#define ECR_nErrIntrEn 0x10
+
+#define ECR_mode_mask  0xE0
+#define ECR_SPP_mode   0x00
+#define ECR_PS2_mode   0x20
+#define ECR_FIFO_mode  0x40
+#define ECR_ECP_mode   0x60
+
+#define ECP_FIFO_SIZE  16
+#define DMA_BUFFER_SIZE               PAGE_SIZE
+       /* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */
+#define PARPORT_CHUNK_SIZE     PAGE_SIZE/* >=2.3.x */
+                               /* we read this many bytes at once */
+
+#define GetECRMasked(port,mask)        (parport_read_econtrol(port) & (mask))
+#define GetStatus(port)                
+((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8))
+#define SetStatus(port,val)    parport_write_status(port,(val)^STATUS_INVERSION_MASK)
+#define GetControl(port)       
+((parport_read_control(port)^CONTROL_INVERSION_MASK)&(0x3f))
+#define SetControl(port,val)   
+parport_write_control(port,(val)^CONTROL_INVERSION_MASK)
+
+#define GetStatusMasked(port,mask)     (GetStatus(port) & (mask))
+#define GetControlMasked(port,mask)    (GetControl(port) & (mask))
+#define SetControlMasked(port,mask)    SetControl(port,GetControl(port) | (mask));
+#define ClearControlMasked(port,mask)  SetControl(port,GetControl(port)&~(mask));
+#define FrobControlBit(port,mask,value)        
+SetControl(port,(GetControl(port)&~(mask))|((value)&(mask)));
+
+#define PACKET_LENGTH  8
+
+/* Magic numbers for defining port-device mappings */
+#define PPCPIA_PARPORT_UNSPEC -4
+#define PPCPIA_PARPORT_AUTO -3
+#define PPCPIA_PARPORT_OFF -2
+#define PPCPIA_PARPORT_NONE -1
+
+#ifdef MODULE
+static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = 
+PPCPIA_PARPORT_UNSPEC};
+static char *parport[PARPORT_MAX] = {NULL,};
+
+MODULE_AUTHOR("B. Huisman <[EMAIL PROTECTED]> & Peter Pregler 
+<[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
+MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s");
+MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
+#else
+static int parport_nr[PARPORT_MAX] __initdata =
+       {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static int parport_ptr = 0;
+#endif
+
+struct pp_cam_entry {
+       struct pardevice *pdev;
+       struct parport *port;
+       struct tq_struct cb_task;
+       int open_count;
+       wait_queue_head_t wq_stream;
+       /* image state flags */
+       int image_ready;        /* we got an interrupt */
+       int image_complete;     /* we have seen 4 EOI */
+
+       int streaming; /* we are in streaming mode */
+       int stream_irq;
+};
+
+static struct cpia_camera_ops cpia_pp_ops = 
+{
+       cpia_pp_open,
+       cpia_pp_registerCallback,
+       cpia_pp_transferCmd,
+       cpia_pp_streamStart,
+       cpia_pp_streamStop,
+       cpia_pp_streamRead,
+       cpia_pp_close,
+       1
+};
+
+static struct cam_data *cam_list;
+
+#ifdef _CPIA_DEBUG_
+#define DEB_PORT(port) { \
+u8 controll = GetControl(port); \
+u8 statusss = GetStatus(port); \
+DBG("nsel %c per %c naut %c nstrob %c nak %c busy %c nfaul %c sel %c init %c dir 
+%c\n",\
+((controll & nSelectIn)        ? 'U' : 'D'), \
+((statusss & PError)   ? 'U' : 'D'), \
+((controll & nAutoFd)  ? 'U' : 'D'), \
+((controll & nStrobe)  ? 'U' : 'D'), \
+((statusss & nAck)     ? 'U' : 'D'), \
+((statusss & Busy)     ? 'U' : 'D'), \
+((statusss & nFault)   ? 'U' : 'D'), \
+((statusss & Select)   ? 'U' : 'D'), \
+((controll & nInit)    ? 'U' : 'D'), \
+((controll & DirBit)   ? 'R' : 'F')  \
+); }
+#else
+#define DEB_PORT(port) {}
+#endif
+
+#define WHILE_OUT_TIMEOUT (HZ/10)
+#define DMA_TIMEOUT 10*HZ
+
+/* FIXME */
+static void cpia_parport_enable_irq( struct parport *port ) {
+       parport_enable_irq(port);
+       mdelay(10);
+       return;
+}
+
+static void cpia_parport_disable_irq( struct parport *port ) {
+       parport_disable_irq(port);
+       mdelay(10);
+       return;
+}
+
+/****************************************************************************
+ *
+ *  EndTransferMode
+ *
+ ***************************************************************************/
+static void EndTransferMode(struct pp_cam_entry *cam)
+{
+       parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+}
+
+/****************************************************************************
+ *
+ *  ForwardSetup
+ *
+ ***************************************************************************/
+static int ForwardSetup(struct pp_cam_entry *cam)
+{
+       int retry;
+       
+       /* After some commands the camera needs extra time before
+        * it will respond again, so we try up to 3 times */
+       for(retry=0; retry<3; ++retry) {
+               if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
+                       break;
+               }
+       }
+       if(retry == 3) {
+               DBG("Unable to negotiate ECP mode\n");
+               return -1;
+       }
+       return 0;
+}
+
+/****************************************************************************
+ *
+ *  ReverseSetup
+ *
+ ***************************************************************************/
+static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
+{
+       int retry;
+       int mode = IEEE1284_MODE_ECP;
+       if(extensibility) mode = 8|3|IEEE1284_EXT_LINK;
+
+       /* After some commands the camera needs extra time before
+        * it will respond again, so we try up to 3 times */
+       for(retry=0; retry<3; ++retry) {
+               if(!parport_negotiate(cam->port, mode)) {
+                       break;
+               }
+       }
+       if(retry == 3) {
+               if(extensibility)
+                       DBG("Unable to negotiate extensibility mode\n");
+               else
+                       DBG("Unable to negotiate ECP mode\n");
+               return -1;
+       }
+       if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP;
+       return 0;
+}
+
+/****************************************************************************
+ *
+ *  WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
+{
+       int retval=0;
+       int size_written;
+
+       if (packet == NULL) {
+               return -EINVAL;
+       }
+       if (ForwardSetup(cam)) {
+               DBG("Write failed in setup\n");
+               return -EIO;
+       }
+       size_written = parport_write(cam->port, packet, size);
+       if(size_written != size) {
+               DBG("Write failed, wrote %d/%d\n", size_written, size);
+               retval = -EIO;
+       }
+       EndTransferMode(cam);
+       return retval;
+}
+
+/****************************************************************************
+ *
+ *  ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
+{
+       int retval=0;
+       if (packet == NULL) {
+               return -EINVAL;
+       }
+       if (ReverseSetup(cam, 0)) {
+               return -EIO;
+       }
+       if(parport_read(cam->port, packet, size) != size) {
+               retval = -EIO;
+       }
+       EndTransferMode(cam);
+       return retval;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_streamStart
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStart(void *privdata)
+{
+       struct pp_cam_entry *cam = privdata;
+       DBG("\n");
+       cam->streaming=1;
+       cam->image_ready=0;
+       //if (ReverseSetup(cam,1)) return -EIO;
+       if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
+       return 0;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_streamStop
+ *
+ ***************************************************************************/
+static int cpia_pp_streamStop(void *privdata)
+{
+       struct pp_cam_entry *cam = privdata;
+
+       DBG("\n");
+       cam->streaming=0;
+       cpia_parport_disable_irq(cam->port);
+       //EndTransferMode(cam);
+
+       return 0;
+}
+
+static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
+{
+       int bytes_read, new_bytes;
+       for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
+               new_bytes = parport_read(port, buffer+bytes_read,
+                                        len-bytes_read);
+               if(new_bytes < 0) break;
+       }
+       return bytes_read;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_streamRead
+ *
+ ***************************************************************************/
+static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
+{
+       struct pp_cam_entry *cam = privdata;
+       int read_bytes = 0;
+       int i, endseen, block_size, new_bytes;
+
+       if(cam == NULL) {
+               DBG("Internal driver error: cam is NULL\n");
+               return -EINVAL;
+       }
+       if(buffer == NULL) {
+               DBG("Internal driver error: buffer is NULL\n");
+               return -EINVAL;
+       }
+       //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
+       if( cam->stream_irq ) {
+               DBG("%d\n", cam->image_ready);
+               cam->image_ready--;
+       }
+       cam->image_complete=0;
+       if (0/*cam->streaming*/) {
+               if(!cam->image_ready) {
+                       if(noblock) return -EWOULDBLOCK;
+                       interruptible_sleep_on(&cam->wq_stream);
+                       if( signal_pending(current) ) return -EINTR;
+                       DBG("%d\n", cam->image_ready);
+               }
+       } else {
+               if (ReverseSetup(cam, 1)) {
+                       DBG("unable to ReverseSetup\n");
+                       return -EIO;
+               }
+       }
+       endseen = 0;
+       block_size = PARPORT_CHUNK_SIZE;
+       while( !cam->image_complete ) {
+               if(current->need_resched)  schedule();
+               
+               new_bytes = cpia_pp_read(cam->port, buffer, block_size );
+               if( new_bytes <= 0 ) {
+                       break;
+               }
+               i=-1;
+               while(++i<new_bytes && endseen<4) {
+                       if(*buffer==EOI) {
+                               endseen++;
+                       } else {
+                               endseen=0;
+                       }
+                       buffer++;
+               }
+               read_bytes += i;
+               if( endseen==4 ) {
+                       cam->image_complete=1;
+                       break;
+               }
+               if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
+                       block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
+               }
+       }
+       EndTransferMode(cam);
+       return cam->image_complete ? read_bytes : -EIO;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_transferCmd
+ *
+ ***************************************************************************/
+static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+       int err;
+       int retval=0;
+       int databytes;
+       struct pp_cam_entry *cam = privdata;
+
+       if(cam == NULL) {
+               DBG("Internal driver error: cam is NULL\n");
+               return -EINVAL;
+       }
+       if(command == NULL) {
+               DBG("Internal driver error: command is NULL\n");
+               return -EINVAL;
+       }
+       databytes = (((int)command[7])<<8) | command[6];
+       if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
+               DBG("Error writing command\n");
+               return err;
+       }
+       if(command[0] == DATA_IN) {
+               u8 buffer[8];
+               if(data == NULL) {
+                       DBG("Internal driver error: data is NULL\n");
+                       return -EINVAL;
+               }
+               if((err = ReadPacket(cam, buffer, 8)) < 0) {
+                       return err;
+                       DBG("Error reading command result\n");
+               }
+               memcpy(data, buffer, databytes);
+       } else if(command[0] == DATA_OUT) {
+               if(databytes > 0) {
+                       if(data == NULL) {
+                               DBG("Internal driver error: data is NULL\n");
+                               retval = -EINVAL;
+                       } else {
+                               if((err=WritePacket(cam, data, databytes)) < 0){
+                                       DBG("Error writing command data\n");
+                                       return err;
+                               }
+                       }
+               }
+       } else {
+               DBG("Unexpected first byte of command: %x\n", command[0]);
+               retval = -EINVAL;
+       }
+       return retval;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_open
+ *
+ ***************************************************************************/
+static int cpia_pp_open(void *privdata)
+{
+       struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
+       
+       if (cam == NULL)
+               return -EINVAL;
+       
+       if(cam->open_count == 0) {
+               if (parport_claim(cam->pdev)) {
+                       DBG("failed to claim the port\n");
+                       return -EBUSY;
+               }
+               parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+               parport_data_forward(cam->port);
+               parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
+               udelay(50);
+               parport_write_control(cam->port,
+                                     PARPORT_CONTROL_SELECT
+                                     | PARPORT_CONTROL_INIT);
+       }
+       
+       ++cam->open_count;
+       
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+       return 0;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_registerCallback
+ *
+ ***************************************************************************/
+static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void 
+*cbdata)
+{
+       struct pp_cam_entry *cam = privdata;
+       int retval = 0;
+       
+       if(cam->port->irq != PARPORT_IRQ_NONE) {
+               cam->cb_task.routine = cb;
+               cam->cb_task.data = cbdata;
+       } else {
+               retval = -1;
+       }
+       return retval;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_close
+ *
+ ***************************************************************************/
+static int cpia_pp_close(void *privdata)
+{
+       struct pp_cam_entry *cam = privdata;
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+       if (--cam->open_count == 0) {
+               parport_release(cam->pdev);
+       }
+       return 0;
+}
+
+/****************************************************************************
+ *
+ *  cpia_pp_register
+ *
+ ***************************************************************************/
+static int cpia_pp_register(struct parport *port)
+{
+       struct pardevice *pdev = NULL;
+       struct pp_cam_entry *cam;
+       struct cam_data *cpia;
+
+       if (!(port->modes & PARPORT_MODE_ECP) &&
+           !(port->modes & PARPORT_MODE_TRISTATE)) {
+               LOG("port is not ECP capable\n");
+               return -ENXIO;
+       }
+
+       cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
+       if (cam == NULL) {
+               LOG("failed to allocate camera structure\n");
+               return -ENOMEM;
+       }
+       memset(cam,0,sizeof(struct pp_cam_entry));
+       
+       pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
+                                      NULL, 0, cam);
+
+       if (!pdev) {
+               LOG("failed to parport_register_device\n");
+               kfree(cam);
+               return -ENXIO;
+       }
+
+       cam->pdev = pdev;
+       cam->port = port;
+       init_waitqueue_head(&cam->wq_stream);
+
+       cam->streaming = 0;
+       cam->stream_irq = 0;
+
+       if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
+               LOG("failed to cpia_register_camera\n");
+               parport_unregister_device(pdev);
+               kfree(cam);
+               return -ENXIO;
+       }
+       ADD_TO_LIST(cam_list, cpia);
+
+       return 0;
+}
+
+static void cpia_pp_detach (struct parport *port)
+{
+       struct cam_data *cpia;
+
+       for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
+               struct pp_cam_entry *cam = cpia->lowlevel_data;
+               if (cam && cam->port->number == port->number) {
+                       REMOVE_FROM_LIST(cpia);
+                       
+                       cpia_unregister_camera(cpia);
+                       
+                       if(cam->open_count > 0) {
+                               cpia_pp_close(cam);
+                       }
+
+                       parport_unregister_device(cam->pdev);
+               
+                       kfree(cam);
+                       cpia->lowlevel_data = NULL;
+                       break;
+               }
+       }
+}
+
+static void cpia_pp_attach (struct parport *port)
+{
+       unsigned int i;
+
+       switch (parport_nr[0])
+       {
+       case PPCPIA_PARPORT_UNSPEC:
+       case PPCPIA_PARPORT_AUTO:
+               if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
+                   port->probe_info[0].cmdset == NULL ||
+                   strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
+                       return;
+
+               cpia_pp_register(port);
+
+               break;
+
+       default:
+               for (i = 0; i < PARPORT_MAX; ++i) {
+                       if (port->number == parport_nr[i]) {
+                               cpia_pp_register(port);
+                               break;
+                       }
+               }
+               break;
+       }
+}
+
+static struct parport_driver cpia_pp_driver = {
+       "cpia_pp",
+       cpia_pp_attach,
+       cpia_pp_detach,
+       NULL
+};
+
+int cpia_pp_init(void)
+{
+       printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, 
+              CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
+
+       if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
+               printk("  disabled\n");
+               return 0;
+       }
+       
+       if (parport_register_driver (&cpia_pp_driver)) {
+               LOG ("unable to register with parport\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       if (parport[0]) {
+               /* The user gave some parameters.  Let's see what they were. */
+               if (!strncmp(parport[0], "auto", 4)) {
+                       parport_nr[0] = PPCPIA_PARPORT_AUTO;
+               } else {
+                       int n;
+                       for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
+                               if (!strncmp(parport[n], "none", 4)) {
+                                       parport_nr[n] = PPCPIA_PARPORT_NONE;
+                               } else {
+                                       char *ep;
+                                       unsigned long r = simple_strtoul(parport[n], 
+&ep, 0);
+                                       if (ep != parport[n]) {
+                                               parport_nr[n] = r;
+                                       } else {
+                                               LOG("bad port specifier `%s'\n", 
+parport[n]);
+                                               return -ENODEV;
+                                       }
+                               }
+                       }
+               }
+       }
+#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE)
+       if(parport_enumerate() && !parport_enumerate()->probe_info.model) {
+               request_module("parport_probe");
+       }
+#endif
+       return cpia_pp_init();
+}
+
+void cleanup_module(void)
+{
+       parport_unregister_driver (&cpia_pp_driver);
+       return;
+}
+
+#else /* !MODULE */
+
+static int __init cpia_pp_setup(char *str)
+{
+#if 0
+       /* Is this only a 2.2ism? -jerdfelt */
+       if (!str) {
+               if (ints[0] == 0 || ints[1] == 0) {
+                       /* disable driver on "cpia_pp=" or "cpia_pp=0" */
+                       parport_nr[0] = PPCPIA_PARPORT_OFF;
+               }
+       } else
+#endif
+       if (!strncmp(str, "parport", 7)) {
+               int n = simple_strtoul(str + 7, NULL, 10);
+               if (parport_ptr < PARPORT_MAX) {
+                       parport_nr[parport_ptr++] = n;
+               } else {
+                       LOG("too many ports, %s ignored.\n", str);
+               }
+       } else if (!strcmp(str, "auto")) {
+               parport_nr[0] = PPCPIA_PARPORT_AUTO;
+       } else if (!strcmp(str, "none")) {
+               parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
+       }
+
+       return 0;
+}
+
+__setup("cpia_pp=", cpia_pp_setup);
+
+#endif /* !MODULE */
diff -urN linux-2.3.99-pre3.orig/drivers/char/cpia_usb.c 
linux-2.3.99-pre3/drivers/char/cpia_usb.c
--- linux-2.3.99-pre3.orig/drivers/char/cpia_usb.c      Wed Dec 31 16:00:00 1969
+++ linux-2.3.99-pre3/drivers/char/cpia_usb.c   Fri Mar 24 14:25:47 2000
@@ -0,0 +1,627 @@
+/*
+ * cpia_usb CPiA USB driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * Copyright (C) 1999        Jochen Scharrlach <[EMAIL PROTECTED]>
+ * Copyright (C) 1999, 2000  Johannes Erdfelt <[EMAIL PROTECTED]>
+ *
+ * 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/kernel.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+
+#include "cpia.h"
+
+#define USB_REQ_CPIA_GRAB_FRAME                        0xC1
+#define USB_REQ_CPIA_UPLOAD_FRAME              0xC2
+#define  WAIT_FOR_NEXT_FRAME                   0
+#define  FORCE_FRAME_UPLOAD                    1
+
+#define FRAMES_PER_DESC                10
+#define FRAME_SIZE_PER_DESC    960     /* Shouldn't be hardcoded */
+#define CPIA_NUMSBUF           2
+#define STREAM_BUF_SIZE                (PAGE_SIZE * 4)
+#define SCRATCH_BUF_SIZE       (STREAM_BUF_SIZE * 2)
+
+struct cpia_sbuf {
+       char *data;
+       urb_t *urb;
+};
+
+#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
+enum framebuf_status {
+       FRAME_EMPTY,
+       FRAME_READING,
+       FRAME_READY,
+       FRAME_ERROR,
+};
+
+struct framebuf {
+       int length;
+       enum framebuf_status status;
+       u8 data[FRAMEBUF_LEN];
+       struct framebuf *next;
+};
+
+struct usb_cpia {
+       /* Device structure */
+       struct usb_device *dev;
+
+       unsigned char iface;
+       wait_queue_head_t wq_stream;
+
+       int cursbuf;            /* Current receiving sbuf */
+       struct cpia_sbuf sbuf[CPIA_NUMSBUF];            /* Double buffering */
+
+       int streaming;
+       int open;
+       int present;
+       struct framebuf *buffers[3];
+       struct framebuf *curbuff, *workbuff;
+};
+
+static int cpia_usb_open(void *privdata);
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+                                    void *cbdata);
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_usb_streamStart(void *privdata);
+static int cpia_usb_streamStop(void *privdata);
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
+static int cpia_usb_close(void *privdata);
+
+#define ABOUT "USB driver for Vision CPiA based cameras"
+
+static struct cpia_camera_ops cpia_usb_ops = {
+       cpia_usb_open,
+       cpia_usb_registerCallback,
+       cpia_usb_transferCmd,
+       cpia_usb_streamStart,
+       cpia_usb_streamStop,
+       cpia_usb_streamRead,
+       cpia_usb_close,
+       0
+};
+
+static struct cam_data *cam_list;
+
+static void cpia_usb_complete(struct urb *urb)
+{
+       int i;
+       char *cdata;
+       struct usb_cpia *ucpia;
+
+       if (!urb || !urb->context)
+               return;
+
+       ucpia = (struct usb_cpia *) urb->context;
+
+       if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
+               return;
+
+       if (ucpia->workbuff->status == FRAME_EMPTY) {
+               ucpia->workbuff->status = FRAME_READING;
+               ucpia->workbuff->length = 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;
+
+               if (st)
+                       printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", 
+i, n, st);
+
+               if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
+                       printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: 
+%d\n", ucpia->workbuff->length, n);
+                       return;
+               }
+           
+               if (n) {
+                       if ((ucpia->workbuff->length > 0) || 
+                           (0x19 == cdata[0] && 0x68 == cdata[1])) {
+                               memcpy(ucpia->workbuff->data + 
+ucpia->workbuff->length, cdata, n);
+                               ucpia->workbuff->length += n;
+                       } else
+                               DBG("Ignoring packet!\n");
+               } else {
+                       if (ucpia->workbuff->length > 4 &&
+                           0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
+                           0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
+                           0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
+                           0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
+                               ucpia->workbuff->status = FRAME_READY;
+                               ucpia->curbuff = ucpia->workbuff;
+                               ucpia->workbuff = ucpia->workbuff->next;
+                               ucpia->workbuff->status = FRAME_EMPTY;
+                               ucpia->workbuff->length = 0;
+                 
+                               if (waitqueue_active(&ucpia->wq_stream))
+                                       wake_up_interruptible(&ucpia->wq_stream);
+                       }
+               }
+       }
+}
+
+static int cpia_usb_open(void *privdata)
+{
+       struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+       urb_t *urb;
+       int ret, retval = 0, fx, err;
+  
+       if (!ucpia)
+               return -EINVAL;
+
+       ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, 
+GFP_KERNEL);
+       if (!ucpia->sbuf[0].data)
+               return -EINVAL;
+
+       ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, 
+GFP_KERNEL);
+       if (!ucpia->sbuf[1].data) {
+               retval = -EINVAL;
+               goto error_0;
+       }
+       
+       ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
+       if (ret < 0) {
+               printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", 
+ret);
+               retval = -EBUSY;
+               goto error_all;
+       }
+
+       ucpia->buffers[0]->status = FRAME_EMPTY;
+       ucpia->buffers[0]->length = 0;
+       ucpia->buffers[1]->status = FRAME_EMPTY;
+       ucpia->buffers[1]->length = 0;
+       ucpia->buffers[2]->status = FRAME_EMPTY;
+       ucpia->buffers[2]->length = 0;
+       ucpia->curbuff = ucpia->buffers[0];
+       ucpia->workbuff = ucpia->buffers[1];
+
+       /* We double buffer the Iso lists */
+       urb = usb_alloc_urb(FRAMES_PER_DESC);
+       if (!urb) {
+               printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+               retval = -ENOMEM;
+               goto error_all;
+       }
+
+       ucpia->sbuf[0].urb = urb;
+       urb->dev = ucpia->dev;
+       urb->context = ucpia;
+       urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+       urb->transfer_flags = USB_ISO_ASAP;
+       urb->transfer_buffer = ucpia->sbuf[0].data;
+       urb->complete = cpia_usb_complete;
+       urb->number_of_packets = FRAMES_PER_DESC;
+       urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+       for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+               urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+               urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+       }
+
+       urb = usb_alloc_urb(FRAMES_PER_DESC);
+       if (!urb) {
+               printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+               retval = -ENOMEM;
+               goto error_all;
+       }
+
+       ucpia->sbuf[1].urb = urb;
+       urb->dev = ucpia->dev;
+       urb->context = ucpia;
+       urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+       urb->transfer_flags = USB_ISO_ASAP;
+       urb->transfer_buffer = ucpia->sbuf[1].data;
+       urb->complete = cpia_usb_complete;
+       urb->number_of_packets = FRAMES_PER_DESC;
+       urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+       for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+               urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+               urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+       }
+
+       ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb;
+       ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb;
+       
+       err = usb_submit_urb(ucpia->sbuf[0].urb);
+       if (err)
+               printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
+                       err);
+       err = usb_submit_urb(ucpia->sbuf[1].urb);
+       if (err)
+               printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
+                       err);
+
+       ucpia->streaming = 1;
+       ucpia->open = 1;
+
+       return 0;
+
+error_all:
+       kfree (ucpia->sbuf[1].data);
+error_0:
+       kfree (ucpia->sbuf[0].data);
+       
+       return retval;
+}
+
+//
+// convenience functions
+//
+
+/****************************************************************************
+ *
+ *  WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t 
+size)
+{
+       if (!packet)
+               return -EINVAL;
+
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                        packet[1] + (packet[0] << 8),
+                        USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                        packet[2] + (packet[3] << 8), 
+                        packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+/****************************************************************************
+ *
+ *  ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
+{
+       if (!packet || size <= 0)
+               return -EINVAL;
+
+       return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                        packet[1] + (packet[0] << 8),
+                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                        packet[2] + (packet[3] << 8), 
+                        packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+       int err = 0;
+       int databytes;
+       struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
+       struct usb_device *udev = ucpia->dev;
+
+       if (!udev) {
+               DBG("Internal driver error: udev is NULL\n");
+               return -EINVAL;
+       }
+
+       if (!command) {
+               DBG("Internal driver error: command is NULL\n");
+               return -EINVAL;
+       }
+
+       databytes = (((int)command[7])<<8) | command[6];
+
+       if (command[0] == DATA_IN) {
+               u8 buffer[8];
+
+               if (!data) {
+                       DBG("Internal driver error: data is NULL\n");
+                       return -EINVAL;
+               }
+
+               err = ReadPacket(udev, command, buffer, 8);
+               if (err < 0)
+                       return err;
+
+               memcpy(data, buffer, databytes);
+       } else if(command[0] == DATA_OUT)
+               WritePacket(udev, command, data, databytes);
+       else {
+               DBG("Unexpected first byte of command: %x\n", command[0]);
+               err = -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+       void *cbdata)
+{
+       return -ENODEV;
+}
+
+static int cpia_usb_streamStart(void *privdata)
+{
+       return -ENODEV;
+}
+
+static int cpia_usb_streamStop(void *privdata)
+{
+       return -ENODEV;
+}
+
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
+{
+       struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+       struct framebuf *mybuff;
+
+       if (!ucpia || !ucpia->present)
+               return -1;
+  
+       if (ucpia->curbuff->status != FRAME_READY)
+               interruptible_sleep_on(&ucpia->wq_stream);
+       else
+               DBG("Frame already waiting!\n");
+
+       mybuff = ucpia->curbuff;
+
+       if (!mybuff)
+               return -1;
+  
+       if (mybuff->status != FRAME_READY || mybuff->length < 4) {
+               DBG("Something went wrong!\n");
+               return -1;
+       }
+
+       memcpy(frame, mybuff->data, mybuff->length);
+       mybuff->status = FRAME_EMPTY;
+  
+/*   DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n",  */
+/*       mybuff->length, frame[0], frame[1], */
+/*       frame[mybuff->length-4], frame[mybuff->length-3],  */
+/*       frame[mybuff->length-2], frame[mybuff->length-1]); */
+
+       return mybuff->length;
+}
+
+static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
+{
+       if (!ucpia->streaming)
+               return;
+
+       ucpia->streaming = 0;
+
+       /* Set packet size to 0 */
+       if (try) {
+               int ret;
+
+               ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
+               if (ret < 0) {
+                       printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
+                       return;
+               }
+       }
+
+       /* Unschedule all of the iso td's */
+       if (ucpia->sbuf[1].urb) {
+               usb_unlink_urb(ucpia->sbuf[1].urb);
+               usb_free_urb(ucpia->sbuf[1].urb);
+               ucpia->sbuf[1].urb = NULL;
+       }
+
+       if (ucpia->sbuf[0].urb) {
+               usb_unlink_urb(ucpia->sbuf[0].urb);
+               usb_free_urb(ucpia->sbuf[0].urb);
+               ucpia->sbuf[0].urb = NULL;
+       }
+}
+
+static int cpia_usb_close(void *privdata)
+{
+       struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+
+       ucpia->open = 0;
+
+       cpia_usb_free_resources(ucpia, 1);
+
+       if (!ucpia->present)
+               kfree(ucpia);
+
+       return 0;
+}
+
+int cpia_usb_init(void)
+{
+       /* return -ENODEV; */
+       return 0;
+}
+
+/* Probing and initializing */
+
+static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
+{
+       struct usb_interface_descriptor *interface;
+       struct usb_cpia *ucpia;
+       struct cam_data *cam;
+       int ret;
+  
+       /* A multi-config CPiA camera? */
+       if (udev->descriptor.bNumConfigurations != 1)
+               return NULL;
+
+       interface = &udev->actconfig->interface[ifnum].altsetting[0];
+
+       /* Is it a CPiA? */
+       if (udev->descriptor.idVendor != 0x0553)
+               return NULL;
+       if (udev->descriptor.idProduct != 0x0002)
+               return NULL;
+
+       /* We found a CPiA */
+       printk(KERN_INFO "USB CPiA camera found\n");
+
+       ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL);
+       if (!ucpia) {
+               printk(KERN_ERR "couldn't kmalloc cpia struct\n");
+               return NULL;
+       }
+
+       memset(ucpia, 0, sizeof(*ucpia));
+
+       ucpia->dev = udev;
+       ucpia->iface = interface->bInterfaceNumber;
+       init_waitqueue_head(&ucpia->wq_stream);
+
+       ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
+       if (!ucpia->buffers[0]) {
+               printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
+               goto fail_alloc_0;
+       }
+
+       ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
+       if (!ucpia->buffers[1]) {
+               printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
+               goto fail_alloc_1;
+       }
+
+       ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
+       if (!ucpia->buffers[2]) {
+               printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
+               goto fail_alloc_2;
+       }
+
+       ucpia->buffers[0]->next = ucpia->buffers[1];
+       ucpia->buffers[1]->next = ucpia->buffers[2];
+       ucpia->buffers[2]->next = ucpia->buffers[0];
+
+       ret = usb_set_interface(udev, ucpia->iface, 0);
+       if (ret < 0) {
+               printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", 
+ret);
+               /* goto fail_all; */
+       }
+
+       /* Before register_camera, important */
+       ucpia->present = 1;
+  
+       cam = cpia_register_camera(&cpia_usb_ops, ucpia);
+       if (!cam) {
+               LOG("failed to cpia_register_camera\n");
+               goto fail_all;
+       }
+
+       ADD_TO_LIST(cam_list, cam);
+
+       return cam;
+
+fail_all:
+       vfree(ucpia->buffers[2]);
+       ucpia->buffers[2] = NULL;
+fail_alloc_2:
+       vfree(ucpia->buffers[1]);
+       ucpia->buffers[1] = NULL;
+fail_alloc_1:
+       vfree(ucpia->buffers[0]);
+       ucpia->buffers[0] = NULL;
+fail_alloc_0:
+
+       return NULL;
+}
+
+static void cpia_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver cpia_driver = {
+       "cpia",
+       cpia_probe,
+       cpia_disconnect,
+       { NULL, NULL }
+};
+
+/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
+/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */
+/* will do it for us as well as passing a udev structure - jerdfelt */
+static void cpia_disconnect(struct usb_device *udev, void *ptr)
+{
+       struct cam_data *cam = (struct cam_data *) ptr;
+       struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data;
+  
+       REMOVE_FROM_LIST(cam);
+
+       /* Don't even try to reset the altsetting if we're disconnected */
+       cpia_usb_free_resources(ucpia, 0);
+
+       ucpia->present = 0;
+
+       cpia_unregister_camera(cam);
+
+       ucpia->curbuff->status = FRAME_ERROR;
+
+       if (waitqueue_active(&ucpia->wq_stream))
+               wake_up_interruptible(&ucpia->wq_stream);
+
+       usb_driver_release_interface(&cpia_driver,
+                                    &udev->actconfig->interface[0]);
+
+       ucpia->curbuff = ucpia->workbuff = NULL;
+
+       if (ucpia->buffers[2]) {
+               vfree(ucpia->buffers[2]);
+               ucpia->buffers[2] = NULL;
+       }
+
+       if (ucpia->buffers[1]) {
+               vfree(ucpia->buffers[1]);
+               ucpia->buffers[1] = NULL;
+       }
+
+       if (ucpia->buffers[0]) {
+               vfree(ucpia->buffers[0]);
+               ucpia->buffers[0] = NULL;
+       }
+
+       if (!ucpia->open)
+               kfree(ucpia);
+}
+
+int usb_cpia_init(void)
+{
+       cam_list = NULL;
+
+       return usb_register(&cpia_driver);
+}
+
+void usb_cpia_cleanup(void)
+{
+/*
+       struct cam_data *cam;
+
+       while ((cam = cam_list) != NULL)
+               cpia_disconnect(NULL, cam);
+*/
+
+       usb_deregister(&cpia_driver);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_cpia_init();
+}
+
+void cleanup_module(void)
+{
+       usb_cpia_cleanup();
+}
+#endif /* !MODULE */
diff -urN linux-2.3.99-pre3.orig/drivers/char/videodev.c 
linux-2.3.99-pre3/drivers/char/videodev.c
--- linux-2.3.99-pre3.orig/drivers/char/videodev.c      Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/char/videodev.c   Fri Mar 24 13:57:52 2000
@@ -47,6 +47,9 @@
 #ifdef CONFIG_VIDEO_BWQCAM
 extern int init_bw_qcams(struct video_init *);
 #endif
+#ifdef CONFIG_VIDEO_CPIA
+extern int cpia_init(struct video_init *);
+#endif
 #ifdef CONFIG_VIDEO_PLANB
 extern int init_planbs(struct video_init *);
 #endif
@@ -61,6 +64,9 @@
 #endif 
 #ifdef CONFIG_VIDEO_BWQCAM
        {"bw-qcam", init_bw_qcams},
+#endif 
+#ifdef CONFIG_VIDEO_CPIA
+       {"cpia", cpia_init},
 #endif 
 #ifdef CONFIG_VIDEO_PLANB
        {"planb", init_planbs},
diff -urN linux-2.3.99-pre3.orig/drivers/usb/Config.in 
linux-2.3.99-pre3/drivers/usb/Config.in
--- linux-2.3.99-pre3.orig/drivers/usb/Config.in        Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/usb/Config.in     Fri Mar 24 13:57:52 2000
@@ -38,7 +38,6 @@
       fi
       bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
    fi
-   dep_tristate '  USB CPiA Camera support' CONFIG_USB_CPIA $CONFIG_USB
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM 
$CONFIG_USB
    dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB
    dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
diff -urN linux-2.3.99-pre3.orig/drivers/usb/Makefile 
linux-2.3.99-pre3/drivers/usb/Makefile
--- linux-2.3.99-pre3.orig/drivers/usb/Makefile Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/usb/Makefile      Fri Mar 24 13:57:52 2000
@@ -71,7 +71,6 @@
 obj-$(CONFIG_USB_ACM)          += acm.o
 obj-$(CONFIG_USB_PRINTER)      += printer.o
 obj-$(CONFIG_USB_AUDIO)                += audio.o
-obj-$(CONFIG_USB_CPIA)         += cpia.o
 obj-$(CONFIG_USB_IBMCAM)       += ibmcam.o
 obj-$(CONFIG_USB_DC2XX)                += dc2xx.o
 obj-$(CONFIG_USB_MDC800)   += mdc800.o
diff -urN linux-2.3.99-pre3.orig/drivers/usb/cpia.c 
linux-2.3.99-pre3/drivers/usb/cpia.c
--- linux-2.3.99-pre3.orig/drivers/usb/cpia.c   Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/usb/cpia.c        Wed Dec 31 16:00:00 1969
@@ -1,1425 +0,0 @@
-/*
- * USB CPiA Video Camera driver
- *
- * Supports CPiA based Video Cameras. Many manufacturers use this chipset.
- *
- * (C) Copyright 1999-2000 Johannes Erdfelt, [EMAIL PROTECTED]
- * (C) Copyright 1999 Randy Dunlap
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/videodev.h>
-#include <linux/vmalloc.h>
-#include <linux/wrapper.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <asm/io.h>
-
-#include "cpia.h"
-
-static int debug = 0;
-MODULE_PARM(debug, "i");
-
-/* Video Size 384 x 288 x 3 bytes for RGB */
-/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
-#define MAX_FRAME_SIZE (384 * 288 * 3)
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-
-#define MDEBUG(x)      do { } while(0)         /* Debug memory management */
-
-static struct usb_driver cpia_driver;
-
-/* Given PGD from the address space's page table, return the kernel
- * virtual mapping of the physical memory mapped at ADR.
- */
-static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
-{
-       unsigned long ret = 0UL;
-       pmd_t *pmd;
-       pte_t *ptep, pte;
-
-       if (!pgd_none(*pgd)) {
-               pmd = pmd_offset(pgd, adr);
-               if (!pmd_none(*pmd)) {
-                       ptep = pte_offset(pmd, adr);
-                       pte = *ptep;
-                       if (pte_present(pte))
-                               ret = page_address(pte_page(pte)) | (adr & 
(PAGE_SIZE-1));
-               }
-       }
-       MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-static inline unsigned long uvirt_to_bus(unsigned long adr)
-{
-       unsigned long kva, ret;
-
-       kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-       ret = virt_to_bus((void *)kva);
-       MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-static inline unsigned long kvirt_to_bus(unsigned long adr)
-{
-       unsigned long va, kva, ret;
-
-       va = VMALLOC_VMADDR(adr);
-       kva = uvirt_to_kva(pgd_offset_k(va), va);
-       ret = virt_to_bus((void *)kva);
-       MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the
- * area and marking the pages as reserved.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-       unsigned long va, kva, ret;
-
-       va = VMALLOC_VMADDR(adr);
-       kva = uvirt_to_kva(pgd_offset_k(va), va);
-       ret = __pa(kva);
-       MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
-       return ret;
-}
-
-static void *rvmalloc(unsigned long size)
-{
-       void *mem;
-       unsigned long adr, page;
-
-       /* Round it off to PAGE_SIZE */
-       size += (PAGE_SIZE - 1);
-       size &= ~(PAGE_SIZE - 1);
-
-       mem = vmalloc(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) {
-               page = kvirt_to_pa(adr);
-               mem_map_reserve(MAP_NR(__va(page)));
-               adr += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-
-       return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
-       unsigned long adr, page;
-
-       if (!mem)
-               return;
-
-       size += (PAGE_SIZE - 1);
-       size &= ~(PAGE_SIZE - 1);
-
-       adr=(unsigned long) mem;
-       while (size > 0) {
-               page = kvirt_to_pa(adr);
-               mem_map_unreserve(MAP_NR(__va(page)));
-               adr += PAGE_SIZE;
-               if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
-               else
-                       size = 0;
-       }
-       vfree(mem);
-}
-
-static int usb_cpia_get_version(struct usb_device *dev, void *buf)
-{
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-               USB_REQ_CPIA_GET_VERSION,
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0, 0, buf, 4, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf)
-{
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-               USB_REQ_CPIA_GET_PNP_ID,
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0, 0, buf, 6, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_get_camera_status(struct usb_device *dev, void *buf)
-{
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-               USB_REQ_CPIA_GET_CAMERA_STATUS,
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0, 0, buf, 8, HZ);
-}
-#endif
-
-static int usb_cpia_goto_hi_power(struct usb_device *dev)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf)
-{
-       return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-               USB_REQ_CPIA_GET_VP_VERSION,
-               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               0, 0, buf, 4, HZ);
-}
-
-static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int 
sensorclkdivisor)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_SET_SENSOR_FPS,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               (sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               streamstartline << 8, 0, NULL, 0, HZ);
-}
-#endif
-
-static int usb_cpia_upload_frame(struct usb_device *dev, int forceupload)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_UPLOAD_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               forceupload, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_SET_GRAB_MODE,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab,
-               0, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int 
order)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_SET_FORMAT,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               (subsample << 8) + size, order, NULL, 0, HZ);
-}
-
-static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int 
rowstart, int rowend)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_SET_ROI,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               (colend << 8) + colstart, (rowend << 8) + rowstart,
-               NULL, 0, HZ);
-}
-
-static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int 
decimation)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_SET_COMPRESSION,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               (decimation << 8) + compmode, 0, NULL, 0, HZ);
-}
-
-#ifdef NOTUSED
-static int usb_cpia_set_compression_target(struct usb_device *dev, int target, int 
targetfr, int targetq)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_SET_COMPRESSION_TARGET,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               (targetfr << 8) + target, targetq, NULL, 0, HZ);
-}
-#endif
-
-#ifdef NOTUSED
-static int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int 
streamstartline)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_INIT_STREAM_CAP,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-               (streamstartline << 8) + skipframes, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_finistreamcap(struct usb_device *dev)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_FINI_STREAM_CAP,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_startstreamcap(struct usb_device *dev)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_START_STREAM_CAP,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-
-static int usb_cpia_endstreamcap(struct usb_device *dev)
-{
-       return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-               USB_REQ_CPIA_END_STREAM_CAP,
-               USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);
-}
-#endif
-
-/* How much data is left in the scratch buf? */
-#define scratch_left(x)        (cpia->scratchlen - (int)((char *)x - (char 
*)cpia->scratch))
-
-static void cpia_parse_data(struct usb_cpia *cpia)
-{
-       struct cpia_frame *frame, *pframe;
-       unsigned char *data = cpia->scratch;
-       unsigned long left;
-       long copylen = 0;
-
-       /* Grab the current frame and the previous frame */
-       frame = &cpia->frame[cpia->curframe];
-       pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES];
-
-       while (1) {
-               if (!scratch_left(data))
-                       goto out;
-
-               switch (frame->scanstate) {
-               case STATE_SCANNING:
-               {
-                       struct cpia_frame_header *header;
-
-                       /* We need at least 2 bytes for the magic value */
-                       if (scratch_left(data) < 2)
-                               goto out;
-
-                       header = (struct cpia_frame_header *)data;
-
-                       if (be16_to_cpup(&header->magic) == CPIA_MAGIC) {
-                               frame->scanstate = STATE_HEADER;
-                               break;
-                       }
-
-                       /* Woops, lost the header, find the end of the frame */
-                       if (scratch_left(data) < 4)
-                               goto out;
-
-                       /* See if we found the end of the frame */
-                       while (scratch_left(data) >= 4) {
-                               if (*((__u32 *)data) == 0xFFFFFFFF) {
-                                       data += 4;
-                                       if (debug >= 1)
-                                               printk(KERN_INFO "cpia: EOF while 
scanning for magic\n");
-                                       goto error;
-                               }
-                               data++;
-                       }
-                       break;
-               }
-               case STATE_HEADER:
-                       /* We need at least 64 bytes for the header */
-                       if (scratch_left(data) <
-                           sizeof(struct cpia_frame_header))
-                               goto out;
-
-                       memcpy(&frame->header, data,
-                               sizeof(struct cpia_frame_header));
-
-                       /* Skip over the header */
-                       data += sizeof(struct cpia_frame_header);
-
-                       frame->hdrwidth = (frame->header.col_end -
-                               frame->header.col_start) * 8;
-                       frame->hdrheight = (frame->header.row_end -
-                               frame->header.row_start) * 4;
-                       if (debug >= 2) {
-                               printk(KERN_DEBUG "cpia: frame size %dx%d\n",
-                                       frame->hdrwidth, frame->hdrheight);
-                               printk(KERN_DEBUG "cpia: frame %scompressed\n",
-                                       frame->header.comp_enable ? "" : "not ");
-                       }
-
-                       frame->scanstate = STATE_LINES;
-                       frame->curline = 0;
-                       break;
-
-               case STATE_LINES:
-               {
-                       unsigned char *f, *end;
-                       unsigned int len;
-                       int i;
-                       int y, u, y1, v, r, g, b;
-
-                       /* We want at least 2 bytes for the length */
-                       if (scratch_left(data) < 2)
-                               goto out;
-
-                       /* Grab the length */
-                       len = data[0] + (data[1] << 8);
-
-                       /* Check to make sure it's nothing outrageous */
-                       if (len > (frame->hdrwidth * 2) + 1) {
-                               if (debug >= 1)
-                                       printk(KERN_DEBUG "cpia: bad length, 
resynching (expected %d, got %d)\n", (frame->hdrwidth * 2) + 1, len);
-                               goto error;
-                       }
-
-                       /* Make sure there's enough data for the entire line */
-                       if (scratch_left(data + 2) < len)
-                               goto out;
-
-                       /* Skip over the length */
-                       data += 2;
-
-                       /* Is the end of the line there */
-                       if (data[len - 1] != 0xFD) {
-                               if (debug >= 1)
-                                       printk(KERN_DEBUG "cpia: lost synch\n");
-                               goto error;
-                       }
-
-                       /* Start at the beginning */
-                       end = data + len - 1;
-
-                       f = frame->data + (frame->width * 3 * frame->curline);
-
-                       if (frame->header.comp_enable) {
-                               unsigned char *fp;
-
-                               /* We use the previous frame as a reference */
-                               fp = pframe->data +
-                                       (frame->width * 3 * frame->curline);
-
-                               while (data < end) {
-                                       if (*data & 1) {
-                                               /* Compress RLE data */
-                                               i = *data >> 1;
-                                               memcpy(f, fp, i * 3);
-                                               copylen += (i * 3);
-                                               f += (i * 3);
-                                               fp += (i * 3);
-                                               data++;
-                                       } else {
-                                               /* Raw data */
-
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-y =  *data++ - 16;
-u =  *data++ - 128;
-y1 = *data++ - 16;
-v =  *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y  *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-                                               fp += 6;
-                                               copylen += 6;
-                                       }
-                               }
-                       } else {
-                               /* Raw data */
-                               while (data < end) {
-y =  *data++ - 16;
-u =  *data++ - 128;
-y1 = *data++ - 16;
-v =  *data++ - 128;
-r = 104635 * v;
-g = -25690 * u + -53294 * v;
-b = 132278 * u;
-y  *= 76310;
-y1 *= 76310;
-*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
-*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1);
-copylen += 6;
-                               }
-                       }
-
-                       /* Skip the last byte */
-                       data++;
-
-                       if (++frame->curline >= frame->hdrheight)
-                               goto nextframe;
-
-                       break;
-               } /* end case STATE_LINES */
-               } /* end switch (scanstate) */
-       } /* end while (1) */
-
-nextframe:
-       if (debug >= 1)
-               printk(KERN_DEBUG "cpia: marking as success\n");
-
-       if (scratch_left(data) >= 4 && *((__u32 *)data) == 0xFFFFFFFF)
-               data += 4;
-
-       frame->grabstate = FRAME_DONE;
-
-       goto wakeup;
-
-error:
-       if (debug >= 1)
-               printk(KERN_DEBUG "cpia: marking as error\n");
-
-       frame->grabstate = FRAME_ERROR;
-
-       /* Get a fresh frame since this frame may have been important */
-       cpia->compress = 0;
-
-       copylen = 0;
-
-wakeup:
-       cpia->curframe = -1;
-
-       /* This will cause the process to request another frame. */
-       if (waitqueue_active(&frame->wq))
-               wake_up_interruptible(&frame->wq);
-
-out:
-       /* Grab the remaining */
-       left = scratch_left(data);
-       memmove(cpia->scratch, data, left);
-       cpia->scratchlen = left;
-
-       /* Update the frame's uncompressed length. */
-       frame->scanlength += copylen;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int cpia_compress_isochronous(struct usb_cpia *cpia, urb_t *urb)
-{
-       unsigned char *cdata, *data;
-       int i, totlen = 0;
-
-       data = cpia->scratch + cpia->scratchlen;
-       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;
-
-               if (st && debug >= 1)
-                       printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n",
-                               i, n, st);
-
-               if ((cpia->scratchlen + n) > SCRATCH_BUF_SIZE) {
-                       printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: 
%d\n",cpia->scratchlen, n );
-                       return totlen;
-               }
-
-               if (n) {
-                       memmove(data, cdata, n);
-                       data += n;
-                       totlen += n;
-                       cpia->scratchlen += n;
-               }
-       }
-
-       return totlen;
-}
-
-static void cpia_isoc_irq(struct urb *urb)
-{
-       int len;
-       struct usb_cpia *cpia = urb->context;
-       struct cpia_sbuf *sbuf;
-       int i;
-
-       if (!cpia->dev)
-               return;
-
-       if (!cpia->streaming) {
-               if (debug >= 1)
-                       printk(KERN_DEBUG "cpia: oops, not streaming, but 
interrupt\n");
-               return;
-       }
-       
-       sbuf = &cpia->sbuf[cpia->cursbuf];
-
-       /* Copy the data received into our scratch buffer */
-       len = cpia_compress_isochronous(cpia, urb);
-
-       /* If we don't have a frame we're current working on, complain */
-       if (cpia->scratchlen) {
-               if (cpia->curframe < 0) {
-                       if (debug >= 1)
-                               printk(KERN_DEBUG "cpia: received data, but no frame 
available\n");
-               } else
-                       cpia_parse_data(cpia);
-       }
-
-       for (i = 0; i < FRAMES_PER_DESC; i++) {
-               sbuf->urb->iso_frame_desc[i].status = 0;
-               sbuf->urb->iso_frame_desc[i].actual_length = 0;
-       }
-
-       /* Move to the next sbuf */
-       cpia->cursbuf = (cpia->cursbuf + 1) % CPIA_NUMSBUF;
-
-       return;
-}
-
-static int cpia_init_isoc(struct usb_cpia *cpia)
-{
-       urb_t *urb;
-       int fx, err;
-
-       cpia->compress = 0;
-       cpia->curframe = -1;
-       cpia->cursbuf = 0;
-       cpia->scratchlen = 0;
-
-       /* Alternate interface 3 is is the biggest frame size */
-       if (usb_set_interface(cpia->dev, cpia->iface, 3) < 0) {
-               printk(KERN_ERR "usb_set_interface error\n");
-               return -EBUSY;
-       }
-
-       /* We double buffer the Iso lists */
-       urb = usb_alloc_urb(FRAMES_PER_DESC);
-       
-       if (!urb) {
-               printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
-                       0);
-               return -ENOMEM;
-       }
-       cpia->sbuf[0].urb = urb;
-       urb->dev = cpia->dev;
-       urb->context = cpia;
-       urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
-       urb->transfer_flags = USB_ISO_ASAP;
-       urb->transfer_buffer = cpia->sbuf[0].data;
-       urb->complete = cpia_isoc_irq;
-       urb->number_of_packets = FRAMES_PER_DESC;
-       urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
-       for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-               urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
-               urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
-       }
-       urb = usb_alloc_urb(FRAMES_PER_DESC);
-       if (!urb) {
-               printk(KERN_ERR "cpia_init_isoc: usb_init_isoc ret %d\n",
-                       0);
-               return -ENOMEM;
-       }
-       cpia->sbuf[1].urb = urb;
-       urb->dev = cpia->dev;
-       urb->context = cpia;
-       urb->pipe = usb_rcvisocpipe(cpia->dev, 1);
-       urb->transfer_flags = USB_ISO_ASAP;
-       urb->transfer_buffer = cpia->sbuf[1].data;
-       urb->complete = cpia_isoc_irq;
-       urb->number_of_packets = FRAMES_PER_DESC;
-       urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
-       for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
-               urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
-               urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
-       }
-
-       cpia->sbuf[1].urb->next = cpia->sbuf[0].urb;
-       cpia->sbuf[0].urb->next = cpia->sbuf[1].urb;
-       
-       err = usb_submit_urb(cpia->sbuf[0].urb);
-       if (err)
-               printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(0) ret %d\n",
-                       err);
-       err = usb_submit_urb(cpia->sbuf[1].urb);
-       if (err)
-               printk(KERN_ERR "cpia_init_isoc: usb_submit_urb(1) ret %d\n",
-                       err);
-
-       cpia->streaming = 1;
-
-       return 0;
-}
-
-static void cpia_stop_isoc(struct usb_cpia *cpia)
-{
-       if (!cpia->streaming || !cpia->dev)
-               return;
-
-       /* Turn off continuous grab */
-       if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) {
-               printk(KERN_ERR "cpia_set_grab_mode error\n");
-               return /* -EBUSY */;
-       }
-
-       /* Set packet size to 0 */
-       if (usb_set_interface(cpia->dev, cpia->iface, 0) < 0) {
-               printk(KERN_ERR "usb_set_interface error\n");
-               return /* -EINVAL */;
-       }
-
-       cpia->streaming = 0;
-
-       /* Unschedule all of the iso td's */
-       if (cpia->sbuf[1].urb) {
-               cpia->sbuf[1].urb->next = NULL;
-               usb_unlink_urb(cpia->sbuf[1].urb);
-               usb_free_urb(cpia->sbuf[1].urb);
-               cpia->sbuf[1].urb = NULL;
-       }
-       if (cpia->sbuf[0].urb) {
-               cpia->sbuf[0].urb->next = NULL;
-               usb_unlink_urb(cpia->sbuf[0].urb);
-               usb_free_urb(cpia->sbuf[0].urb);
-               cpia->sbuf[0].urb = NULL;
-       }
-}
-
-static int cpia_new_frame(struct usb_cpia *cpia, int framenum)
-{
-       struct cpia_frame *frame;
-       int width, height;
-
-       if (!cpia->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 (cpia->curframe == -1) {
-               if (cpia->frame[(framenum - 1 + CPIA_NUMFRAMES) % 
CPIA_NUMFRAMES].grabstate == FRAME_READY)
-                       framenum = (framenum - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES;
-       } else
-               return 0;
-
-       frame = &cpia->frame[framenum];
-       width = frame->width;
-       height = frame->height;
-
-       frame->grabstate = FRAME_GRABBING;
-       frame->scanstate = STATE_SCANNING;
-       frame->scanlength = 0;          /* accumulated in cpia_parse_data() */
-
-       cpia->curframe = framenum;
-
-       /* Make sure it's not too big */
-       if (width > 352)
-               width = 352;
-       width = (width / 8) * 8;        /* Multiple of 8 */
-
-       if (height > 288)
-               height = 288;
-       height = (height / 4) * 4;      /* Multiple of 4 */
-
-       /* Set the ROI they want */
-       if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0)
-               return -EBUSY;
-
-       if (usb_cpia_set_compression(cpia->dev, cpia->compress ?
-                       COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) {
-               printk(KERN_ERR "cpia_set_compression error\n");
-               return -EBUSY;
-       }
-
-       /* We want a fresh frame every 30 we get */
-       cpia->compress = (cpia->compress + 1) % 30;
-
-       /* Grab the frame */
-       if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) {
-               printk(KERN_ERR "cpia_upload_frame error\n");
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-/* Video 4 Linux API */
-static int cpia_open(struct video_device *dev, int flags)
-{
-       int err = -EBUSY;
-       struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
-       down(&cpia->lock);
-       if (cpia->user)
-               goto out_unlock;
-
-       cpia->frame[0].grabstate = FRAME_UNUSED;
-       cpia->frame[1].grabstate = FRAME_UNUSED;
-
-       err = -ENOMEM;
-
-       /* Allocate memory for the frame buffers */
-       cpia->fbuf = rvmalloc(2 * MAX_FRAME_SIZE);
-       if (!cpia->fbuf)
-               goto open_err_ret;
-
-       cpia->frame[0].data = cpia->fbuf;
-       cpia->frame[1].data = cpia->fbuf + MAX_FRAME_SIZE;
-
-       cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, 
GFP_KERNEL);
-       if (!cpia->sbuf[0].data)
-               goto open_err_on0;
-
-       cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, 
GFP_KERNEL);
-       if (!cpia->sbuf[1].data)
-               goto open_err_on1;
-
-       /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
-        * (using read() instead). */
-       cpia->frame[0].width = 352;
-       cpia->frame[0].height = 288;
-       cpia->frame[0].bytes_read = 0;
-       cpia->frame[1].width = 352;
-       cpia->frame[1].height = 288;
-       cpia->frame[1].bytes_read = 0;
-
-       err = cpia_init_isoc(cpia);
-       if (err)
-               goto open_err_on2;
-
-       cpia->user++;
-       up(&cpia->lock);
-
-       MOD_INC_USE_COUNT;
-
-       return 0;
-
-open_err_on2:
-       kfree (cpia->sbuf[1].data);
-open_err_on1:
-       kfree (cpia->sbuf[0].data);
-open_err_on0:
-       rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-open_err_ret:
-       return err;
-
-out_unlock:
-       up(&cpia->lock);
-       return err;
-}
-
-static void cpia_close(struct video_device *dev)
-{
-       struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
-       down(&cpia->lock);      
-       cpia->user--;
-
-       MOD_DEC_USE_COUNT;
-
-       cpia_stop_isoc(cpia);
-
-       rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE);
-
-       kfree(cpia->sbuf[1].data);
-       kfree(cpia->sbuf[0].data);
-
-       up(&cpia->lock);
-
-       if (!cpia->dev) {
-               video_unregister_device(&cpia->vdev);
-               kfree(cpia);
-       }
-}
-
-static int cpia_init_done(struct video_device *dev)
-{
-       return 0;
-}
-
-static long cpia_write(struct video_device *dev, const char *buf, unsigned long 
count, int noblock)
-{
-       return -EINVAL;
-}
-
-static int cpia_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
-{
-       struct usb_cpia *cpia = (struct usb_cpia *)dev;
-
-       if (!cpia->dev)
-               return -EIO;
-
-       switch (cmd) {
-               case VIDIOCGCAP:
-               {
-                       struct video_capability b;
-
-                       strcpy(b.name, "CPiA USB Camera");
-                       b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
-                       b.channels = 1;
-                       b.audios = 0;
-                       b.maxwidth = 352;       /* CIF */
-                       b.maxheight = 288;      /*  "  */
-                       b.minwidth = 8;
-                       b.minheight = 4;
-
-                       if (copy_to_user(arg, &b, sizeof(b)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel v;
-
-                       if (copy_from_user(&v, arg, sizeof(v)))
-                               return -EFAULT;
-                       if (v.channel != 0)
-                               return -EINVAL;
-
-                       v.flags = 0;
-                       v.tuners = 0;
-                       v.type = VIDEO_TYPE_CAMERA;
-                       strcpy(v.name, "Camera");
-
-                       if (copy_to_user(arg, &v, sizeof(v)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCSCHAN:
-               {
-                       int v;
-
-                       if (copy_from_user(&v, arg, sizeof(v)))
-                               return -EFAULT;
-
-                       if (v != 0)
-                               return -EINVAL;
-
-                       return 0;
-               }
-               case VIDIOCGPICT:
-               {
-                       struct video_picture p;
-
-                       p.colour = 0x8000;      /* Damn British people :) */
-                       p.hue = 0x8000;
-                       p.brightness = 180 << 8;        /* XXX */
-                       p.contrast = 192 << 8;          /* XXX */
-                       p.whiteness = 105 << 8;         /* XXX */
-                       p.depth = 24;
-                       p.palette = VIDEO_PALETTE_RGB24;
-
-                       if (copy_to_user(arg, &p, sizeof(p)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCSPICT:
-               {
-                       struct video_picture p;
-
-                       if (copy_from_user(&p, arg, sizeof(p)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCSWIN:
-               {
-                       struct video_window vw;
-
-                       if (copy_from_user(&vw, arg, sizeof(vw)))
-                               return -EFAULT;
-                       if (vw.flags)
-                               return -EINVAL;
-                       if (vw.clipcount)
-                               return -EINVAL;
-                       if (vw.height != 288)
-                               return -EINVAL;
-                       if (vw.width != 352)
-                               return -EINVAL;
-
-                       cpia->compress = 0;
-
-                       return 0;
-               }
-               case VIDIOCGWIN:
-               {
-                       struct video_window vw;
-
-                       vw.x = 0;
-                       vw.y = 0;
-                       vw.width = 352;
-                       vw.height = 288;
-                       vw.chromakey = 0;
-                       vw.flags = 30;          /* 30 fps */
-
-                       if (copy_to_user(arg, &vw, sizeof(vw)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCGMBUF:
-               {
-                       struct video_mbuf vm;
-
-                       memset(&vm, 0, sizeof(vm));
-                       vm.size = MAX_FRAME_SIZE * 2;
-                       vm.frames = 2;
-                       vm.offsets[0] = 0;
-                       vm.offsets[1] = MAX_FRAME_SIZE;
-
-                       if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
-                               return -EFAULT;
-
-                       return 0;
-               }
-               case VIDIOCMCAPTURE:
-               {
-                       struct video_mmap vm;
-
-                       if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
-                               return -EFAULT;
-
-                       if (debug >= 1)
-                               printk(KERN_DEBUG "frame: %d, size: %dx%d, format: 
%d\n",
-                                       vm.frame, vm.width, vm.height, vm.format);
-
-                       if (vm.format != VIDEO_PALETTE_RGB24)
-                               return -EINVAL;
-
-                       if ((vm.frame != 0) && (vm.frame != 1))
-                               return -EINVAL;
-
-                       if (cpia->frame[vm.frame].grabstate == FRAME_GRABBING)
-                               return -EBUSY;
-
-                       /* Don't compress if the size changed */
-                       if ((cpia->frame[vm.frame].width != vm.width) ||
-                           (cpia->frame[vm.frame].height != vm.height))
-                               cpia->compress = 0;
-
-                       cpia->frame[vm.frame].width = vm.width;
-                       cpia->frame[vm.frame].height = vm.height;
-
-                       /* Mark it as ready */
-                       cpia->frame[vm.frame].grabstate = FRAME_READY;
-
-                       return cpia_new_frame(cpia, vm.frame);
-               }
-               case VIDIOCSYNC:
-               {
-                       int frame;
-
-                       if (copy_from_user((void *)&frame, arg, sizeof(int)))
-                               return -EFAULT;
-
-                       if (debug >= 1)
-                               printk(KERN_DEBUG "cpia: syncing to frame %d\n", 
frame);
-
-                       switch (cpia->frame[frame].grabstate) {
-                       case FRAME_UNUSED:
-                               return -EINVAL;
-                       case FRAME_READY:
-                       case FRAME_GRABBING:
-                       case FRAME_ERROR:
-redo:
-                               if (!cpia->dev)
-                                       return -EIO;
-
-                               do {
-                                       interruptible_sleep_on(&cpia->frame[frame].wq);
-                                       if (signal_pending(current))
-                                               return -EINTR;
-                               } while (cpia->frame[frame].grabstate == 
FRAME_GRABBING);
-
-                               if (cpia->frame[frame].grabstate == FRAME_ERROR) {
-                                       int ret;
-
-                                       if ((ret = cpia_new_frame(cpia, frame)) < 0)
-                                               return ret;
-                                       goto redo;
-                               }
-                       case FRAME_DONE:
-                               cpia->frame[frame].grabstate = FRAME_UNUSED;
-                               break;
-                       }
-
-                       cpia->frame[frame].grabstate = FRAME_UNUSED;
-
-                       return 0;
-               }
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer vb;
-
-                       memset(&vb, 0, sizeof(vb));
-                       vb.base = NULL; /* frame buffer not supported, not used */
-
-                       if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
-                               return -EFAULT;
-
-                       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;
-       }
-       return 0;
-}
-
-static long cpia_read(struct video_device *dev, char *buf, unsigned long count, int 
noblock)
-{
-       struct usb_cpia *cpia = (struct usb_cpia *)dev;
-       int frmx = -1;
-       volatile struct cpia_frame *frame;
-
-       if (debug >= 1)
-               printk(KERN_DEBUG "cpia_read: %ld bytes, noblock=%d\n", count, 
noblock);
-
-       if (!dev || !buf)
-               return -EFAULT;
-
-       if (!cpia->dev)
-               return -EIO;
-
-       /* See if a frame is completed, then use it. */
-       if (cpia->frame[0].grabstate >= FRAME_DONE)     /* _DONE or _ERROR */
-               frmx = 0;
-       else if (cpia->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
-               frmx = 1;
-
-       if (noblock && (frmx == -1))
-               return -EAGAIN;
-
-       /* 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 (cpia->frame[0].grabstate == FRAME_GRABBING)
-                       frmx = 0;
-               else if (cpia->frame[1].grabstate == FRAME_GRABBING)
-                       frmx = 1;
-       }
-
-       /* If no frame is active, start one. */
-       if (frmx == -1)
-               cpia_new_frame(cpia, frmx = 0);
-
-       frame = &cpia->frame[frmx];
-
-restart:
-       if (!cpia->dev)
-               return -EIO;
-
-       while (frame->grabstate == FRAME_GRABBING) {
-               interruptible_sleep_on(&frame->wq);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       if (frame->grabstate == FRAME_ERROR) {
-               frame->bytes_read = 0;
-printk("cpia_read: errored frame %d\n", cpia->curframe);
-               if (cpia_new_frame(cpia, frmx))
-                       printk(KERN_ERR "cpia_read: cpia_new_frame error\n");
-               goto restart;
-       }
-
-       if (debug >= 1)
-               printk(KERN_DEBUG "cpia_read: frmx=%d, bytes_read=%ld, 
scanlength=%ld\n",
-                       frmx, frame->bytes_read, frame->scanlength);
-
-       /* copy bytes to user space; we allow for partials reads */
-       if ((count + frame->bytes_read) > frame->scanlength)
-               count = frame->scanlength - frame->bytes_read;
-
-       if (copy_to_user(buf, frame->data + frame->bytes_read, count))
-               return -EFAULT;
-
-       frame->bytes_read += count;
-       if (debug >= 1)
-               printk(KERN_DEBUG "cpia_read: {copy} count used=%ld, new 
bytes_read=%ld\n",
-                       count, frame->bytes_read);
-
-       if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
-               frame->bytes_read = 0;
-
-               /* Mark it as available to be used again. */
-               cpia->frame[frmx].grabstate = FRAME_UNUSED;
-               if (cpia_new_frame(cpia, frmx ? 0 : 1))
-                       printk(KERN_ERR "cpia_read: cpia_new_frame returned error\n");
-       }
-
-       return count;
-}
-
-static int cpia_mmap(struct video_device *dev, const char *adr, unsigned long size)
-{
-       struct usb_cpia *cpia = (struct usb_cpia *)dev;
-       unsigned long start = (unsigned long)adr;
-       unsigned long page, pos;
-
-       if (!cpia->dev)
-               return -EIO;
-
-       if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
-               return -EINVAL;
-
-       pos = (unsigned long)cpia->fbuf;
-       while (size > 0) {
-               page = kvirt_to_pa(pos);
-               if (remap_page_range(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;
-}
-
-static struct video_device cpia_template = {
-       "CPiA USB Camera",
-       VID_TYPE_CAPTURE,
-       VID_HARDWARE_CPIA,
-       cpia_open,
-       cpia_close,
-       cpia_read,
-       cpia_write,
-       NULL,
-       cpia_ioctl,
-       cpia_mmap,
-       cpia_init_done,
-       NULL,
-       0,
-       0
-};
-
-static int usb_cpia_configure(struct usb_cpia *cpia)
-{
-       struct usb_device *dev = cpia->dev;
-       unsigned char version[4];
-
-       /* Set altsetting 0 */
-       if (usb_set_interface(dev, cpia->iface, 0) < 0) {
-               printk(KERN_ERR "usb_set_interface error\n");
-               return -EBUSY;
-       }
-
-       if (usb_cpia_get_version(dev, version) < 0) {
-               printk(KERN_ERR "cpia_get_version error\n");
-               return -EBUSY;
-       }
-
-       if (debug >= 1)
-               printk(KERN_DEBUG "cpia: Firmware v%d.%d, VC Hardware v%d.%d\n",
-                       version[0], version[1], version[2], version[3]);
-
-       memcpy(&cpia->vdev, &cpia_template, sizeof(cpia_template));
-
-       init_waitqueue_head(&cpia->frame[0].wq);
-       init_waitqueue_head(&cpia->frame[1].wq);
-
-       if (video_register_device(&cpia->vdev, VFL_TYPE_GRABBER) == -1) {
-               printk(KERN_ERR "video_register_device failed\n");
-               return -EBUSY;
-       }
-
-       if (usb_cpia_goto_hi_power(dev) < 0) {
-               printk(KERN_ERR "cpia_goto_hi_power error\n");
-               goto error;
-       }
-
-       if (usb_cpia_get_vp_version(dev, version) < 0) {
-               printk(KERN_ERR "cpia_get_vp_version error\n");
-               goto error;
-       }
-
-       if (debug >= 1) {
-               printk(KERN_DEBUG "cpia: VP v%d rev %d\n", version[0], version[1]);
-               printk(KERN_DEBUG "cpia: Camera Head ID %04X\n", (version[3] << 8) + 
version[2]);
-       }
-
-       /* Turn on continuous grab */
-       if (usb_cpia_set_grab_mode(dev, 1) < 0) {
-               printk(KERN_ERR "cpia_set_grab_mode error\n");
-               goto error;
-       }
-
-       /* Set up the sensor to be 30fps */
-       if (usb_cpia_set_sensor_fps(dev, 1, 0) < 0) {
-               printk(KERN_ERR "cpia_set_sensor_fps error\n");
-               goto error;
-       }
-
-       /* Set video into CIF mode, and order into YUYV mode */
-       if (usb_cpia_set_format(dev, FORMAT_CIF, FORMAT_422,
-                       FORMAT_YUYV) < 0) {
-               printk(KERN_ERR "cpia_set_format error\n");
-               goto error;
-       }
-
-       /* Turn off compression */
-       if (usb_cpia_set_compression(dev, COMP_DISABLED, DONT_DECIMATE) < 0) {
-               printk(KERN_ERR "cpia_set_compression error\n");
-               goto error;
-       }
-
-       cpia->compress = 0;
-
-       return 0;
-
-error:
-       video_unregister_device(&cpia->vdev);
-       usb_driver_release_interface(&cpia_driver,
-               &dev->actconfig->interface[0]);
-
-       kfree(cpia);
-
-       return -EBUSY;
-}
-
-static void * cpia_probe(struct usb_device *dev, unsigned int ifnum)
-{
-       struct usb_interface_descriptor *interface;
-       struct usb_cpia *cpia;
-
-       /* We don't handle multi-config cameras */
-       if (dev->descriptor.bNumConfigurations != 1)
-               return NULL;
-
-       interface = &dev->actconfig->interface[ifnum].altsetting[0];
-
-       /* Is it a CPiA? */
-       if (dev->descriptor.idVendor != 0x0553)
-               return NULL;
-       if (dev->descriptor.idProduct != 0x0002)
-               return NULL;
-
-       /* Checking vendor/product should be enough, but what the hell */
-       if (interface->bInterfaceClass != 0xFF)
-               return NULL;
-       if (interface->bInterfaceSubClass != 0x00)
-               return NULL;
-
-       /* We found a CPiA */
-       printk(KERN_INFO "USB CPiA camera found\n");
-
-       if ((cpia = kmalloc(sizeof(*cpia), GFP_KERNEL)) == NULL) {
-               printk(KERN_ERR "couldn't kmalloc cpia struct\n");
-               return NULL;
-       }
-
-       memset(cpia, 0, sizeof(*cpia));
-
-       cpia->dev = dev;
-       cpia->iface = interface->bInterfaceNumber;
-
-       if (!usb_cpia_configure(cpia)) {
-               cpia->user=0; 
-               init_MUTEX(&cpia->lock);        /* to 1 == available */
-
-               return cpia;
-       } else
-               return NULL;
-}
-
-static void cpia_disconnect(struct usb_device *dev, void *ptr)
-{
-       struct usb_cpia *cpia = (struct usb_cpia *) ptr;
-
-       /* We don't want people trying to open up the device */
-       if (!cpia->user)
-               video_unregister_device(&cpia->vdev);
-
-       usb_driver_release_interface(&cpia_driver,
-               &cpia->dev->actconfig->interface[0]);
-
-       cpia->dev = NULL;
-       cpia->frame[0].grabstate = FRAME_ERROR;
-       cpia->frame[1].grabstate = FRAME_ERROR;
-       cpia->curframe = -1;
-
-       /* This will cause the process to request another frame. */
-       if (waitqueue_active(&cpia->frame[0].wq))
-               wake_up_interruptible(&cpia->frame[0].wq);
-
-       if (waitqueue_active(&cpia->frame[1].wq))
-               wake_up_interruptible(&cpia->frame[1].wq);
-
-       cpia->streaming = 0;
-
-       /* Unschedule all of the iso td's */
-       if (cpia->sbuf[1].urb) {
-               cpia->sbuf[1].urb->next = NULL;
-               usb_unlink_urb(cpia->sbuf[1].urb);
-               usb_free_urb(cpia->sbuf[1].urb);
-               cpia->sbuf[1].urb = NULL;
-       }
-       if (cpia->sbuf[0].urb) {
-               cpia->sbuf[0].urb->next = NULL;
-               usb_unlink_urb(cpia->sbuf[0].urb);
-               usb_free_urb(cpia->sbuf[0].urb);
-               cpia->sbuf[0].urb = NULL;
-       }
-
-       /* Free the memory */
-       if (!cpia->user)
-               kfree(cpia);
-}
-
-static struct usb_driver cpia_driver = {
-       "cpia",
-       cpia_probe,
-       cpia_disconnect,
-       { NULL, NULL }
-};
-
-int usb_cpia_init(void)
-{
-       return usb_register(&cpia_driver);
-}
-
-void usb_cpia_cleanup(void)
-{
-       usb_deregister(&cpia_driver);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-       return usb_cpia_init();
-}
-
-void cleanup_module(void)
-{
-       usb_cpia_cleanup();
-}
-#endif
diff -urN linux-2.3.99-pre3.orig/drivers/usb/cpia.h 
linux-2.3.99-pre3/drivers/usb/cpia.h
--- linux-2.3.99-pre3.orig/drivers/usb/cpia.h   Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/usb/cpia.h        Wed Dec 31 16:00:00 1969
@@ -1,205 +0,0 @@
-#ifndef __LINUX_CPIA_H
-#define __LINUX_CPIA_H
-
-#include <linux/list.h>
-
-#define USB_REQ_CPIA_GET_VERSION               0x01
-#define USB_REQ_CPIA_GET_PNP_ID                        0x02
-#define USB_REQ_CPIA_GET_CAMERA_STATUS         0x03
-#define USB_REQ_CPIA_GOTO_HI_POWER             0x04
-#define USB_REQ_CPIA_GOTO_LO_POWER             0x05
-/* No 0x06 */
-#define USB_REQ_CPIA_GOTO_SUSPEND              0x07
-#define USB_REQ_CPIA_GOTO_PASS_THROUGH         0x08
-/* No 0x09 */
-#define USB_REQ_CPIA_MODIFY_CAMERA_STATUS      0x0A
-
-#define USB_REQ_CPIA_READ_VC_REGS              0x21
-#define USB_REQ_CPIA_WRITE_BC_REG              0x22
-#define USB_REQ_CPIA_READ_MC_PORTS             0x23
-#define USB_REQ_CPIA_WRITE_MC_PORT             0x24
-#define USB_REQ_CPIA_SET_BAUD_RATE             0x25
-#define USB_REQ_CPIA_SET_ECP_TIMING            0x26
-#define USB_REQ_CPIA_READ_IDATA                        0x27
-#define USB_REQ_CPIA_WRITE_IDATA               0x28
-#define USB_REQ_CPIA_GENERIC_CALL              0x29
-#define USB_REQ_CPIA_I2CSTART                  0x2A
-#define USB_REQ_CPIA_I2CSTOP                   0x2B
-#define USB_REQ_CPIA_I2CWRITE                  0x2C
-#define USB_REQ_CPIA_I2CREAD                   0x2D
-
-#define USB_REQ_CPIA_GET_VP_VERSION            0xA1
-#define USB_REQ_CPIA_SET_COLOUR_PARAMS         0xA3
-#define USB_REQ_CPIA_SET_EXPOSURE              0xA4
-/* No 0xA5 */
-#define USB_REQ_CPIA_SET_COLOUR_BALANCE                0xA6
-#define USB_REQ_CPIA_SET_SENSOR_FPS            0xA7
-#define USB_REQ_CPIA_SET_VP_DEFAULTS           0xA8
-#define USB_REQ_CPIA_SET_APCOR                 0xA9
-#define USB_REQ_CPIA_SET_FLICKER_CTRL          0xAA
-#define USB_REQ_CPIA_SET_VL_OFFSET             0xAB
-
-#define USB_REQ_CPIA_GET_COLOUR_PARAMETERS     0xB0
-#define USB_REQ_CPIA_GET_COLOUR_BALANCE                0xB1
-#define USB_REQ_CPIA_GET_EXPOSURE              0xB2
-#define USB_REQ_CPIA_SET_SENSOR_MATRIX         0xB3
-
-#define USB_REQ_CPIA_COLOUR_BARS               0xBD
-#define USB_REQ_CPIA_READ_VP_REGS              0xBE
-#define USB_REQ_CPIA_WRITE_VP_REGS             0xBF
-
-#define USB_REQ_CPIA_GRAB_FRAME                        0xC1
-#define USB_REQ_CPIA_UPLOAD_FRAME              0xC2
-#define  WAIT_FOR_NEXT_FRAME                   0
-#define  FORCE_FRAME_UPLOAD                    1
-#define USB_REQ_CPIA_SET_GRAB_MODE             0xC3
-#define USB_REQ_CPIA_INIT_STREAM_CAP           0xC4
-#define USB_REQ_CPIA_FINI_STREAM_CAP           0xC5
-#define USB_REQ_CPIA_START_STREAM_CAP          0xC6
-#define USB_REQ_CPIA_END_STREAM_CAP            0xC7
-#define USB_REQ_CPIA_SET_FORMAT                        0xC8
-#define  FORMAT_QCIF   0
-#define  FORMAT_CIF    1
-#define  FORMAT_YUYV   0
-#define  FORMAT_UYVY   1
-#define  FORMAT_420    0
-#define  FORMAT_422    1
-#define USB_REQ_CPIA_SET_ROI                   0xC9
-#define USB_REQ_CPIA_SET_COMPRESSION           0xCA
-#define  COMP_DISABLED 0
-#define  COMP_AUTO     1
-#define  COMP_MANUAL   2
-#define  DONT_DECIMATE 0
-#define  DECIMATE      1
-#define USB_REQ_CPIA_SET_COMPRESSION_TARGET    0xCB
-#define  TARGET_QUALITY                0
-#define  TARGET_FRAMERATE      1
-#define USB_REQ_CPIA_SET_YUV_THRESH            0xCC
-#define USB_REQ_CPIA_SET_COMPRESSION_PARAMS    0xCD
-#define USB_REQ_CPIA_DISCARD_FRAME             0xCE
-
-#define USB_REQ_CPIA_OUTPUT_RS232              0xE1
-#define USB_REQ_CPIA_ABORT_PROCESS             0xE4
-#define USB_REQ_CPIA_SET_DRAM_PAGE             0xE5
-#define USB_REQ_CPIA_START_DRAM_UPLOAD         0xE6
-#define USB_REQ_CPIA_START_DUMMY_STREAM                0xE8
-#define USB_REQ_CPIA_ABORT_STREAM              0xE9
-#define USB_REQ_CPIA_DOWNLOAD_DRAM             0xEA
-/* #define USB_REQ_CPIA_NULL_CMD               0x?? */
-
-#define STREAM_BUF_SIZE                (PAGE_SIZE * 4)
-/* #define STREAM_BUF_SIZE     (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC) */
-
-#define SCRATCH_BUF_SIZE       (STREAM_BUF_SIZE * 2)
-
-#define FRAMES_PER_DESC                10
-#define FRAME_SIZE_PER_DESC    960     /* Shouldn't be hardcoded */
-
-enum {
-       STATE_SCANNING,         /* Scanning for start */
-       STATE_HEADER,           /* Parsing header */
-       STATE_LINES,            /* Parsing lines */
-};
-
-#define CPIA_MAGIC     0x1968
-struct cpia_frame_header {
-       __u16 magic;            /* 0 - 1 */
-       __u16 timestamp;        /* 2 - 3 */
-       __u16 unused;           /* 4 - 5 */
-       __u16 timestamp1;       /* 6 - 7 */
-       __u8  unused1[8];       /* 8 - 15 */
-       __u8  video_size;       /* 16 0 = QCIF, 1 = CIF */
-       __u8  sub_sample;       /* 17 0 = 4:2:0, 1 = 4:2:2 */
-       __u8  yuv_order;        /* 18 0 = YUYV, 1 = UYVY */
-       __u8  unused2[5];       /* 19 - 23 */
-       __u8  col_start;        /* 24 */
-       __u8  col_end;          /* 25 */
-       __u8  row_start;        /* 26 */
-       __u8  row_end;          /* 27 */
-       __u8  comp_enable;      /* 28 0 = non compressed, 1 = compressed */
-       __u8  decimation;       /* 29 0 = no decimation, 1 = decimation */
-       __u8  y_thresh;         /* 30 */
-       __u8  uv_thresh;        /* 31 */
-       __u8  system_state;     /* 32 */
-       __u8  grab_state;       /* 33 */
-       __u8  stream_state;     /* 34 */
-       __u8  fatal_error;      /* 35 */
-       __u8  cmd_error;        /* 36 */
-       __u8  debug_flags;      /* 37 */
-       __u8  camera_state_7;   /* 38 */
-       __u8  camera_state_8;   /* 39 */
-       __u8  cr_achieved;      /* 40 */
-       __u8  fr_achieved;      /* 41 */
-       __u8  unused3[22];      /* 42 - 63 */
-};
-
-struct usb_device;
-
-struct cpia_sbuf {
-       char *data;
-       urb_t *urb;
-};
-
-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 cpia_frame {
-       char *data;             /* Frame buffer */
-
-       struct cpia_frame_header header;        /* Header from stream */
-
-       int width;              /* Width application is expecting */
-       int height;             /* Height */
-
-       int hdrwidth;           /* Width the frame actually is */
-       int hdrheight;          /* Height */
-
-       volatile int grabstate; /* State of grabbing */
-       int scanstate;          /* State of scanning */
-
-       int curline;            /* Line of frame we're working on */
-
-       long scanlength;        /* uncompressed, raw data length of frame */
-       long bytes_read;        /* amount of scanlength that has been read from *data 
*/
-
-       wait_queue_head_t wq;   /* Processes waiting */
-};
-
-#define CPIA_NUMFRAMES 2
-#define CPIA_NUMSBUF   2
-
-struct usb_cpia {
-       struct video_device vdev;
-
-       /* Device structure */
-       struct usb_device *dev;
-
-       unsigned char iface;
-
-       struct semaphore lock;
-       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? */
-
-       char *fbuf;             /* Videodev buffer area */
-
-       int curframe;
-       struct cpia_frame frame[CPIA_NUMFRAMES];        /* Double buffering */
-
-       int cursbuf;            /* Current receiving sbuf */
-       struct cpia_sbuf sbuf[CPIA_NUMSBUF];            /* Double buffering */
-
-       /* Scratch space from the Isochronous pipe */
-       unsigned char scratch[SCRATCH_BUF_SIZE];
-       int scratchlen;
-};
-
-#endif
diff -urN linux-2.3.99-pre3.orig/drivers/usb/usb-core.c 
linux-2.3.99-pre3/drivers/usb/usb-core.c
--- linux-2.3.99-pre3.orig/drivers/usb/usb-core.c       Fri Mar 24 13:58:02 2000
+++ linux-2.3.99-pre3/drivers/usb/usb-core.c    Fri Mar 24 13:57:52 2000
@@ -29,7 +29,6 @@
  */
 
 int usb_audio_init(void);
-int usb_cpia_init(void);
 int usb_ibmcam_init(void);
 int dabusb_init(void);
 int plusb_init(void);
@@ -70,9 +69,6 @@
 #ifndef CONFIG_USB_MODULE
 #ifdef CONFIG_USB_AUDIO
        usb_audio_init();
-#endif
-#ifdef CONFIG_USB_CPIA
-       usb_cpia_init();
 #endif
 #ifdef CONFIG_USB_IBMCAM
        usb_ibmcam_init();

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to