* Philips PCA645, PCA646
           * Philips PCVC675, PCVC680, PCVC690
           * Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+          * Philips SPC900NC
           * Askey VC010
           * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
             and 'Orbit'/'Sphere'
          and never will be, but the 665 and 720/20 are supported by other
          drivers.
 
-         See <file:Documentation/usb/philips.txt> for more information and
-         installation instructions.
+         Some newer logitech webcams are not handled by this driver but by the
+         Usb Video Class driver (linux-uvc).
 
          The built-in microphone is enabled by selecting USB Audio support.
 
          To compile this driver as a module, choose M here: the
          module will be called pwc.
+
+config USB_PWC_DEBUG
+       bool "USB Philips Cameras verbose debug"
+       depends USB_PWC
+       help
+         Say Y here in order to have the pwc driver generate verbose debugging
+         messages.
+         A special module options 'trace' is used to control the verbosity.
 
-pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+pwc-objs       := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs       += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
 
 obj-$(CONFIG_USB_PWC) += pwc.o
+
+ifeq ($(CONFIG_USB_PWC_DEBUG),y)
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
+else
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
+endif
+
+
 
    Functions that send various control messages to the webcam, including
    video modes.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #include <asm/uaccess.h>
 #endif
 #include <asm/errno.h>
+#include <linux/version.h>
 
 #include "pwc.h"
-#include "pwc-ioctl.h"
 #include "pwc-uncompress.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 /* Request types: video */
 #define SET_LUM_CTL                    0x01
 #define GET_STATUS_CTL                 0x06
 #define SET_EP_STREAM_CTL              0x07
 #define GET_EP_STREAM_CTL              0x08
+#define GET_XX_CTL                     0x09
+#define SET_XX_CTL                     0x0A
+#define GET_XY_CTL                     0x0B
+#define SET_XY_CTL                     0x0C
 #define SET_MPT_CTL                    0x0D
 #define GET_MPT_CTL                    0x0E
 
 #define READ_SHUTTER_FORMATTER                 0x0600
 #define READ_RED_GAIN_FORMATTER                        0x0700
 #define READ_BLUE_GAIN_FORMATTER               0x0800
+#define GET_STATUS_B00                         0x0B00
 #define SENSOR_TYPE_FORMATTER1                 0x0C00
+#define GET_STATUS_3000                                0x3000
 #define READ_RAW_Y_MEAN_FORMATTER              0x3100
 #define SET_POWER_SAVE_MODE_FORMATTER          0x3200
 #define MIRROR_IMAGE_FORMATTER                 0x3300
 #define LED_FORMATTER                          0x3400
+#define LOWLIGHT                               0x3500
+#define GET_STATUS_3600                                0x3600
 #define SENSOR_TYPE_FORMATTER2                 0x3700
+#define GET_STATUS_3800                                0x3800
+#define GET_STATUS_4000                                0x4000
+#define GET_STATUS_4100                                0x4100  /* Get */
+#define CTL_STATUS_4200                                0x4200  /* [GS] 1 */
 
 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
 #define VIDEO_OUTPUT_CONTROL_FORMATTER         0x0100
 #include "pwc-nala.h"
 };
 
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 
 /****************************************************************************/
 
                &buf, buflen, 500)
 
 
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
-       int i;
-       unsigned char *s;
-       char buf[100], *d;
-
-       s = (unsigned char *)p;
-       d = buf;
-       *d = '\0';
-       Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
-       for (i = 0; i < len; i++) {
-               d += sprintf(d, "%02X ", *s++);
-               if ((i & 0xF) == 0xF) {
-                       Debug("%s\n", buf);
-                       d = buf;
-                       *d = '\0';
-               }
-       }
-       if ((i & 0xF) != 0)
-               Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
 {
        return usb_control_msg(udev,
                usb_sndctrlpipe(udev, 0),
 
 
 
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
 {
        unsigned char buf[3];
        int ret, fps;
        if (pEntry->alternate == 0)
                return -EINVAL;
 
-       if (pEntry->compressed)
-               return -ENOENT; /* Not supported. */
-
        memcpy(buf, pEntry->mode, 3);
        ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
        if (ret < 0) {
-               Debug("Failed to send video command... %d\n", ret);
+               PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
                return ret;
        }
        if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
-        {
-          switch(pdev->type) {
-            case 645:
-            case 646:
-/*            pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-              break;
-
-            case 675:
-            case 680:
-            case 690:
-            case 720:
-            case 730:
-            case 740:
-            case 750:
-/*            pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
-              break;
-          }
-       }
+               pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
 
        pdev->cmd_len = 3;
        memcpy(pdev->cmd_buf, buf, 3);
 }
 
 
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
 {
        unsigned char buf[13];
        const struct Timon_table_entry *pChoose;
        if (ret < 0)
                return ret;
 
-/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-          pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+       if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+               pwc_dec23_init(pdev, pdev->type, buf);
 
        pdev->cmd_len = 13;
        memcpy(pdev->cmd_buf, buf, 13);
 }
 
 
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
 {
        const struct Kiara_table_entry *pChoose = NULL;
        int fps, ret;
        fps = (frames / 5) - 1;
 
        /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
-       if (size == PSZ_VGA && frames == 5 && snapshot)
+       if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
        {
                /* Only available in case the raw palette is selected or
                   we have the decompressor available. This mode is
                   only available in compressed form
                */
-               if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               {
-                       Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
-                       pChoose = &RawEntry;
-               }
-               else
-               {
-                       Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
-               }
+               PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
+               pChoose = &RawEntry;
        }
        else
        {
                   if the preferred ratio is not available.
                   Skip this step when using RAW modes.
                */
+               snapshot = 0;
                while (compression <= 3) {
                        pChoose = &Kiara_table[size][fps][compression];
                        if (pChoose->alternate != 0)
        if (pChoose == NULL || pChoose->alternate == 0)
                return -ENOENT; /* Not supported. */
 
-       Debug("Using alternate setting %d.\n", pChoose->alternate);
+       PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
 
        /* usb_control_msg won't take staticly allocated arrays as argument?? */
        memcpy(buf, pChoose->mode, 12);
        if (ret < 0)
                return ret;
 
-/*     if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
-         pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+       if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+               pwc_dec23_init(pdev, pdev->type, buf);
 
        pdev->cmd_len = 12;
        memcpy(pdev->cmd_buf, buf, 12);
                pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
        else
                pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+       PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
+           pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
        return 0;
 }
 
 
 
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
-       int i, factor = 0, filler = 0;
-
-       /* for PALETTE_YUV420P */
-       switch(pdev->vpalette)
-       {
-       case VIDEO_PALETTE_YUV420P:
-               factor = 6;
-               filler = 128;
-               break;
-       case VIDEO_PALETTE_RAW:
-               factor = 6; /* can be uncompressed YUV420P */
-               filler = 0;
-               break;
-       }
-
-       /* Set sizes in bytes */
-       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
-       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
-
-       /* Align offset, or you'll get some very weird results in
-          YUV420 mode... x must be multiple of 4 (to get the Y's in
-          place), and y even (or you'll mixup U & V). This is less of a
-          problem for YUV420P.
-        */
-       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
-       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
-       /* Fill buffers with gray or black */
-       for (i = 0; i < MAX_IMAGES; i++) {
-               if (pdev->image_ptr[i] != NULL)
-                       memset(pdev->image_ptr[i], filler, pdev->view.size);
-       }
-}
-
-
-
 /**
    @pdev: device structure
    @width: viewport width
 {
        int ret, size;
 
-       Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+       PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
        size = pwc_decode_size(pdev, width, height);
        if (size < 0) {
-               Debug("Could not find suitable size.\n");
+               PWC_DEBUG_MODULE("Could not find suitable size.\n");
                return -ERANGE;
        }
-       Debug("decode_size = %d.\n", size);
+       PWC_TRACE("decode_size = %d.\n", size);
 
-       ret = -EINVAL;
-       switch(pdev->type) {
-       case 645:
-       case 646:
+       if (DEVICE_USE_CODEC1(pdev->type)) {
                ret = set_video_mode_Nala(pdev, size, frames);
-               break;
-
-       case 675:
-       case 680:
-       case 690:
-               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
-               break;
 
-       case 720:
-       case 730:
-       case 740:
-       case 750:
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
                ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
-               break;
+
+       } else {
+               ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
        }
        if (ret < 0) {
-               if (ret == -ENOENT)
-                       Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
-               else {
-                       Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
-               }
+               PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
                return ret;
        }
        pdev->view.x = width;
        pdev->view.y = height;
        pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
        pwc_set_image_buffer_size(pdev);
-       Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+       PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
        return 0;
 }
 
+#define BLACK_Y 0
+#define BLACK_U 128
+#define BLACK_V 128
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+       int i, factor = 0;
+
+       /* for PALETTE_YUV420P */
+       switch(pdev->vpalette)
+       {
+       case VIDEO_PALETTE_YUV420P:
+               factor = 6;
+               break;
+       case VIDEO_PALETTE_RAW:
+               factor = 6; /* can be uncompressed YUV420P */
+               break;
+       }
+
+       /* Set sizes in bytes */
+       pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+       pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
+
+       /* Align offset, or you'll get some very weird results in
+          YUV420 mode... x must be multiple of 4 (to get the Y's in
+          place), and y even (or you'll mixup U & V). This is less of a
+          problem for YUV420P.
+        */
+       pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+       pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+       /* Fill buffers with black colors */
+       for (i = 0; i < pwc_mbufs; i++) {
+               unsigned char *p = pdev->image_data + pdev->images[i].offset;
+               memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
+               p += pdev->view.x * pdev->view.y;
+               memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
+               p += pdev->view.x * pdev->view.y/4;
+               memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
+       }
+}
+
+
 
 /* BRIGHTNESS */
 
        ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       return buf << 9;
+       return buf;
 }
 
 int pwc_set_brightness(struct pwc_device *pdev, int value)
        ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       return buf << 10;
+       return buf;
 }
 
 int pwc_set_contrast(struct pwc_device *pdev, int value)
        ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       return buf << 11;
+       return buf;
 }
 
 int pwc_set_gamma(struct pwc_device *pdev, int value)
 
 /* SATURATION */
 
-int pwc_get_saturation(struct pwc_device *pdev)
+/* return a value between [-100 , 100] */
+int pwc_get_saturation(struct pwc_device *pdev, int *value)
 {
        char buf;
-       int ret;
+       int ret, saturation_register;
 
        if (pdev->type < 675)
-               return -1;
-       ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+               return -EINVAL;
+       if (pdev->type < 730)
+               saturation_register = SATURATION_MODE_FORMATTER2;
+       else
+               saturation_register = SATURATION_MODE_FORMATTER1;
+       ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1);
        if (ret < 0)
                return ret;
-       return 32768 + buf * 327;
+       *value = (signed)buf;
+       return 0;
 }
 
+/* @param value saturation color between [-100 , 100] */
 int pwc_set_saturation(struct pwc_device *pdev, int value)
 {
        char buf;
+       int saturation_register;
 
        if (pdev->type < 675)
                return -EINVAL;
-       if (value < 0)
-               value = 0;
-       if (value > 0xffff)
-               value = 0xffff;
-       /* saturation ranges from -100 to +100 */
-       buf = (value - 32768) / 327;
-       return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+       if (value < -100)
+               value = -100;
+       if (value > 100)
+               value = 100;
+       if (pdev->type < 730)
+               saturation_register = SATURATION_MODE_FORMATTER2;
+       else
+               saturation_register = SATURATION_MODE_FORMATTER1;
+       return SendControlMsg(SET_CHROM_CTL, saturation_register, 1);
 }
 
 /* AGC */
 
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
 {
        char buf;
        int ret;
        return 0;
 }
 
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_get_agc(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
        return 0;
 }
 
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
 {
        char buf[2];
        int speed, ret;
                        value = 0;
                if (value > 0xffff)
                        value = 0xffff;
-               switch(pdev->type) {
-               case 675:
-               case 680:
-               case 690:
+
+               if (DEVICE_USE_CODEC2(pdev->type)) {
                        /* speed ranges from 0x0 to 0x290 (656) */
                        speed = (value / 100);
                        buf[1] = speed >> 8;
                        buf[0] = speed & 0xff;
-                       break;
-               case 720:
-               case 730:
-               case 740:
-               case 750:
+               } else if (DEVICE_USE_CODEC3(pdev->type)) {
                        /* speed seems to range from 0x0 to 0xff */
                        buf[1] = 0;
                        buf[0] = value >> 8;
-                       break;
                }
 
                ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
        return ret;
 }
 
+/* This function is not exported to v4l1, so output values between 0 -> 256 */
+int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+{
+       unsigned char buf[2];
+       int ret;
+
+       ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2);
+       if (ret < 0)
+               return ret;
+       *value = buf[0] + (buf[1] << 8);
+       if (DEVICE_USE_CODEC2(pdev->type)) {
+               /* speed ranges from 0x0 to 0x290 (656) */
+               *value *= 256/656;
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
+               /* speed seems to range from 0x0 to 0xff */
+       }
+       return 0;
+}
+
 
 /* POWER */
 
 
 /* private calls */
 
-static inline int pwc_restore_user(struct pwc_device *pdev)
+int pwc_restore_user(struct pwc_device *pdev)
 {
        char buf; /* dummy */
        return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
 }
 
-static inline int pwc_save_user(struct pwc_device *pdev)
+int pwc_save_user(struct pwc_device *pdev)
 {
        char buf; /* dummy */
        return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
 }
 
-static inline int pwc_restore_factory(struct pwc_device *pdev)
+int pwc_restore_factory(struct pwc_device *pdev)
 {
        char buf; /* dummy */
        return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
   * 03: manual
   * 04: auto
   */
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+int pwc_set_awb(struct pwc_device *pdev, int mode)
 {
        char buf;
        int ret;
        return 0;
 }
 
-static inline int pwc_get_awb(struct pwc_device *pdev)
+int pwc_get_awb(struct pwc_device *pdev)
 {
        unsigned char buf;
        int ret;
        return buf;
 }
 
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+int pwc_set_red_gain(struct pwc_device *pdev, int value)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
 }
 
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+int pwc_get_red_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
 }
 
 
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+int pwc_set_blue_gain(struct pwc_device *pdev, int value)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
 }
 
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
    internal red/blue gains, which may be different from the manual
    gains set or read above.
  */
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
        return 0;
 }
 
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
 }
 
 
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
 }
 
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
 }
 
 
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
 }
 
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
 {
        unsigned char buf;
        int ret;
        return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
 }
 
-static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
+int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
 {
        unsigned char buf[2];
        int ret;
        return 0;
 }
 
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+int pwc_set_contour(struct pwc_device *pdev, int contour)
 {
        unsigned char buf;
        int ret;
        return 0;
 }
 
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+int pwc_get_contour(struct pwc_device *pdev, int *contour)
 {
        unsigned char buf;
        int ret;
 }
 
 
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+int pwc_set_backlight(struct pwc_device *pdev, int backlight)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
 }
 
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
 {
        int ret;
        unsigned char buf;
        ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       *backlight = buf;
+       *backlight = !!buf;
+       return 0;
+}
+
+int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
+{
+       unsigned char buf;
+
+       if (colour)
+               buf = 0xff;
+       else
+               buf = 0x0;
+       return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+}
+
+int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
+{
+       int ret;
+       unsigned char buf;
+
+       ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+       if (ret < 0)
+               return ret;
+       *colour = !!buf;
        return 0;
 }
 
 
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+int pwc_set_flicker(struct pwc_device *pdev, int flicker)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
 }
 
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
 {
        int ret;
        unsigned char buf;
        ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
        if (ret < 0)
                return ret;
-       *flicker = buf;
+       *flicker = !!buf;
        return 0;
 }
 
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
 }
 
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
 {
        int ret;
        unsigned char buf;
        return 0;
 }
 
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
 {
        unsigned char buf;
 
        return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
 }
 
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+       int ret;
+       ret = _pwc_mpt_reset(pdev, flags);
+       if (ret >= 0) {
+               pdev->pan_angle = 0;
+               pdev->tilt_angle = 0;
+       }
+       return ret;
+}
+
+static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
 {
        unsigned char buf[4];
 
        return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
 }
 
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+       int ret;
+
+       /* check absolute ranges */
+       if (pan  < pdev->angle_range.pan_min  ||
+           pan  > pdev->angle_range.pan_max  ||
+           tilt < pdev->angle_range.tilt_min ||
+           tilt > pdev->angle_range.tilt_max)
+               return -ERANGE;
+
+       /* go to relative range, check again */
+       pan  -= pdev->pan_angle;
+       tilt -= pdev->tilt_angle;
+       /* angles are specified in degrees * 100, thus the limit = 36000 */
+       if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
+               return -ERANGE;
+
+       ret = _pwc_mpt_set_angle(pdev, pan, tilt);
+       if (ret >= 0) {
+               pdev->pan_angle  += pan;
+               pdev->tilt_angle += tilt;
+       }
+       if (ret == -EPIPE) /* stall -> out of range */
+               ret = -ERANGE;
+       return ret;
+}
+
+static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
 {
        int ret;
        unsigned char buf[5];
  /* End of Add-Ons                                    */
  /* ************************************************* */
 
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+   and copy_to_user() calls. With these macros we circumvent this,
+   and let me maintain only one source file. The functionality is
+   exactly the same otherwise.
+ */
+
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+       ARG_type *ARG_name = arg;
+/* copy arg to local variable */
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
 
 int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 {
 
        case VIDIOCPWCSCQUAL:
        {
-               int *qual = arg;
+               ARG_DEF(int, qual)
 
-               if (*qual < 0 || *qual > 3)
+               ARG_IN(qual)
+               if (ARGR(qual) < 0 || ARGR(qual) > 3)
                        ret = -EINVAL;
                else
-                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+                       ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
                if (ret >= 0)
-                       pdev->vcompression = *qual;
+                       pdev->vcompression = ARGR(qual);
                break;
        }
 
        case VIDIOCPWCGCQUAL:
        {
-               int *qual = arg;
-               *qual = pdev->vcompression;
+               ARG_DEF(int, qual)
+
+               ARGR(qual) = pdev->vcompression;
+               ARG_OUT(qual)
                break;
        }
 
        case VIDIOCPWCPROBE:
        {
-               struct pwc_probe *probe = arg;
-               strcpy(probe->name, pdev->vdev->name);
-               probe->type = pdev->type;
+               ARG_DEF(struct pwc_probe, probe)
+
+               strcpy(ARGR(probe).name, pdev->vdev->name);
+               ARGR(probe).type = pdev->type;
+               ARG_OUT(probe)
                break;
        }
 
        case VIDIOCPWCGSERIAL:
        {
-               struct pwc_serial *serial = arg;
-               strcpy(serial->serial, pdev->serial);
+               ARG_DEF(struct pwc_serial, serial)
+
+               strcpy(ARGR(serial).serial, pdev->serial);
+               ARG_OUT(serial)
                break;
        }
 
        case VIDIOCPWCSAGC:
        {
-               int *agc = arg;
-               if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+               ARG_DEF(int, agc)
+
+               ARG_IN(agc)
+               if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
                        ret = -EINVAL;
                break;
        }
 
        case VIDIOCPWCGAGC:
        {
-               int *agc = arg;
+               ARG_DEF(int, agc)
 
-               if (pwc_get_agc(pdev, agc))
+               if (pwc_get_agc(pdev, ARGA(agc)))
                        ret = -EINVAL;
+               ARG_OUT(agc)
                break;
        }
 
        case VIDIOCPWCSSHUTTER:
        {
-               int *shutter_speed = arg;
-               ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+               ARG_DEF(int, shutter_speed)
+
+               ARG_IN(shutter_speed)
+               ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
                break;
        }
 
        case VIDIOCPWCSAWB:
        {
-               struct pwc_whitebalance *wb = arg;
+               ARG_DEF(struct pwc_whitebalance, wb)
 
-               ret = pwc_set_awb(pdev, wb->mode);
-               if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
-                       pwc_set_red_gain(pdev, wb->manual_red);
-                       pwc_set_blue_gain(pdev, wb->manual_blue);
+               ARG_IN(wb)
+               ret = pwc_set_awb(pdev, ARGR(wb).mode);
+               if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+                       pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+                       pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
                }
                break;
        }
 
        case VIDIOCPWCGAWB:
        {
-               struct pwc_whitebalance *wb = arg;
+               ARG_DEF(struct pwc_whitebalance, wb)
 
-               memset(wb, 0, sizeof(struct pwc_whitebalance));
-               wb->mode = pwc_get_awb(pdev);
-               if (wb->mode < 0)
+               memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+               ARGR(wb).mode = pwc_get_awb(pdev);
+               if (ARGR(wb).mode < 0)
                        ret = -EINVAL;
                else {
-                       if (wb->mode == PWC_WB_MANUAL) {
-                               ret = pwc_get_red_gain(pdev, &wb->manual_red);
+                       if (ARGR(wb).mode == PWC_WB_MANUAL) {
+                               ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
                                if (ret < 0)
                                        break;
-                               ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+                               ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
                                if (ret < 0)
                                        break;
                        }
-                       if (wb->mode == PWC_WB_AUTO) {
-                               ret = pwc_read_red_gain(pdev, &wb->read_red);
+                       if (ARGR(wb).mode == PWC_WB_AUTO) {
+                               ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
                                if (ret < 0)
                                        break;
-                               ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+                               ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
                                if (ret < 0)
                                        break;
                        }
                }
+               ARG_OUT(wb)
                break;
        }
 
        case VIDIOCPWCSAWBSPEED:
        {
-               struct pwc_wb_speed *wbs = arg;
+               ARG_DEF(struct pwc_wb_speed, wbs)
 
-               if (wbs->control_speed > 0) {
-                       ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+               if (ARGR(wbs).control_speed > 0) {
+                       ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
                }
-               if (wbs->control_delay > 0) {
-                       ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+               if (ARGR(wbs).control_delay > 0) {
+                       ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
                }
                break;
        }
 
        case VIDIOCPWCGAWBSPEED:
        {
-               struct pwc_wb_speed *wbs = arg;
+               ARG_DEF(struct pwc_wb_speed, wbs)
 
-               ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+               ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
                if (ret < 0)
                        break;
-               ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+               ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
                if (ret < 0)
                        break;
+               ARG_OUT(wbs)
                break;
        }
 
        case VIDIOCPWCSLED:
        {
-               struct pwc_leds *leds = arg;
-               ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
+               ARG_DEF(struct pwc_leds, leds)
+
+               ARG_IN(leds)
+               ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
                break;
        }
 
 
        case VIDIOCPWCGLED:
        {
-               struct pwc_leds *leds = arg;
-               ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+               ARG_DEF(struct pwc_leds, leds)
+
+               ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+               ARG_OUT(leds)
                break;
        }
 
        case VIDIOCPWCSCONTOUR:
        {
-               int *contour = arg;
-               ret = pwc_set_contour(pdev, *contour);
+               ARG_DEF(int, contour)
+
+               ARG_IN(contour)
+               ret = pwc_set_contour(pdev, ARGR(contour));
                break;
        }
 
        case VIDIOCPWCGCONTOUR:
        {
-               int *contour = arg;
-               ret = pwc_get_contour(pdev, contour);
+               ARG_DEF(int, contour)
+
+               ret = pwc_get_contour(pdev, ARGA(contour));
+               ARG_OUT(contour)
                break;
        }
 
        case VIDIOCPWCSBACKLIGHT:
        {
-               int *backlight = arg;
-               ret = pwc_set_backlight(pdev, *backlight);
+               ARG_DEF(int, backlight)
+
+               ARG_IN(backlight)
+               ret = pwc_set_backlight(pdev, ARGR(backlight));
                break;
        }
 
        case VIDIOCPWCGBACKLIGHT:
        {
-               int *backlight = arg;
-               ret = pwc_get_backlight(pdev, backlight);
+               ARG_DEF(int, backlight)
+
+               ret = pwc_get_backlight(pdev, ARGA(backlight));
+               ARG_OUT(backlight)
                break;
        }
 
        case VIDIOCPWCSFLICKER:
        {
-               int *flicker = arg;
-               ret = pwc_set_flicker(pdev, *flicker);
+               ARG_DEF(int, flicker)
+
+               ARG_IN(flicker)
+               ret = pwc_set_flicker(pdev, ARGR(flicker));
                break;
        }
 
        case VIDIOCPWCGFLICKER:
        {
-               int *flicker = arg;
-               ret = pwc_get_flicker(pdev, flicker);
+               ARG_DEF(int, flicker)
+
+               ret = pwc_get_flicker(pdev, ARGA(flicker));
+               ARG_OUT(flicker)
                break;
        }
 
        case VIDIOCPWCSDYNNOISE:
        {
-               int *dynnoise = arg;
-               ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+               ARG_DEF(int, dynnoise)
+
+               ARG_IN(dynnoise)
+               ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
                break;
        }
 
        case VIDIOCPWCGDYNNOISE:
        {
-               int *dynnoise = arg;
-               ret = pwc_get_dynamic_noise(pdev, dynnoise);
+               ARG_DEF(int, dynnoise)
+
+               ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+               ARG_OUT(dynnoise);
                break;
        }
 
        case VIDIOCPWCGREALSIZE:
        {
-               struct pwc_imagesize *size = arg;
-               size->width = pdev->image.x;
-               size->height = pdev->image.y;
+               ARG_DEF(struct pwc_imagesize, size)
+
+               ARGR(size).width = pdev->image.x;
+               ARGR(size).height = pdev->image.y;
+               ARG_OUT(size)
                break;
        }
 
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       int *flags = arg;
+                       ARG_DEF(int, flags)
 
-                       ret = pwc_mpt_reset(pdev, *flags);
-                       if (ret >= 0)
-                       {
-                               pdev->pan_angle = 0;
-                               pdev->tilt_angle = 0;
-                       }
+                       ARG_IN(flags)
+                       ret = pwc_mpt_reset(pdev, ARGR(flags));
                }
                else
                {
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_range *range = arg;
-                       *range = pdev->angle_range;
+                       ARG_DEF(struct pwc_mpt_range, range)
+
+                       ARGR(range) = pdev->angle_range;
+                       ARG_OUT(range)
                }
                else
                {
 
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_angles *angles = arg;
+                       ARG_DEF(struct pwc_mpt_angles, angles)
+
+                       ARG_IN(angles)
                        /* The camera can only set relative angles, so
                           do some calculations when getting an absolute angle .
                         */
-                       if (angles->absolute)
+                       if (ARGR(angles).absolute)
                        {
-                               new_pan  = angles->pan;
-                               new_tilt = angles->tilt;
+                               new_pan  = ARGR(angles).pan;
+                               new_tilt = ARGR(angles).tilt;
                        }
                        else
                        {
-                               new_pan  = pdev->pan_angle  + angles->pan;
-                               new_tilt = pdev->tilt_angle + angles->tilt;
-                       }
-                       /* check absolute ranges */
-                       if (new_pan  < pdev->angle_range.pan_min  ||
-                           new_pan  > pdev->angle_range.pan_max  ||
-                           new_tilt < pdev->angle_range.tilt_min ||
-                           new_tilt > pdev->angle_range.tilt_max)
-                       {
-                               ret = -ERANGE;
-                       }
-                       else
-                       {
-                               /* go to relative range, check again */
-                               new_pan  -= pdev->pan_angle;
-                               new_tilt -= pdev->tilt_angle;
-                               /* angles are specified in degrees * 100, thus the limit = 36000 */
-                               if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
-                                       ret = -ERANGE;
-                       }
-                       if (ret == 0) /* no errors so far */
-                       {
-                               ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
-                               if (ret >= 0)
-                               {
-                                       pdev->pan_angle  += new_pan;
-                                       pdev->tilt_angle += new_tilt;
-                               }
-                               if (ret == -EPIPE) /* stall -> out of range */
-                                       ret = -ERANGE;
+                               new_pan  = pdev->pan_angle  + ARGR(angles).pan;
+                               new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
                        }
+                       ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
                }
                else
                {
 
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_angles *angles = arg;
+                       ARG_DEF(struct pwc_mpt_angles, angles)
 
-                       angles->absolute = 1;
-                       angles->pan  = pdev->pan_angle;
-                       angles->tilt = pdev->tilt_angle;
+                       ARGR(angles).absolute = 1;
+                       ARGR(angles).pan  = pdev->pan_angle;
+                       ARGR(angles).tilt = pdev->tilt_angle;
+                       ARG_OUT(angles)
                }
                else
                {
        {
                if (pdev->features & FEATURE_MOTOR_PANTILT)
                {
-                       struct pwc_mpt_status *status = arg;
-                       ret = pwc_mpt_get_status(pdev, status);
+                       ARG_DEF(struct pwc_mpt_status, status)
+
+                       ret = pwc_mpt_get_status(pdev, ARGA(status));
+                       ARG_OUT(status)
                }
                else
                {
 
        case VIDIOCPWCGVIDCMD:
        {
-               struct pwc_video_command *cmd = arg;
-
-               cmd->type = pdev->type;
-               cmd->release = pdev->release;
-               cmd->command_len = pdev->cmd_len;
-               memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
-               cmd->bandlength = pdev->vbandlength;
-               cmd->frame_size = pdev->frame_size;
+               ARG_DEF(struct pwc_video_command, cmd);
+
+               ARGR(cmd).type = pdev->type;
+               ARGR(cmd).release = pdev->release;
+               ARGR(cmd).command_len = pdev->cmd_len;
+               memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+               ARGR(cmd).bandlength = pdev->vbandlength;
+               ARGR(cmd).frame_size = pdev->frame_size;
+               ARG_OUT(cmd)
                break;
        }
        /*
        case VIDIOCPWCGVIDTABLE:
        {
-               struct pwc_table_init_buffer *table = arg;
-               table->len = pdev->cmd_len;
-               memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+               ARG_DEF(struct pwc_table_init_buffer, table);
+               ARGR(table).len = pdev->cmd_len;
+               memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+               ARG_OUT(table)
                break;
        }
        */
 }
 
 
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
 
--- /dev/null
+/* Linux driver for Philips webcam
+   Decompression for chipset version 1
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+
+#include "pwc-dec1.h"
+
+
+void pwc_dec1_init(int type, int release, void *buffer, void *table)
+{
+
+}
+
+void pwc_dec1_exit(void)
+{
+
+
+
+}
+
+int pwc_dec1_alloc(struct pwc_device *pwc)
+{
+       pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+       if (pwc->decompress_data == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
 
--- /dev/null
+/* Linux driver for Philips webcam
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+
+#ifndef PWC_DEC1_H
+#define PWC_DEC1_H
+
+#include "pwc.h"
+
+struct pwc_dec1_private
+{
+       int version;
+
+};
+
+int  pwc_dec1_alloc(struct pwc_device *pwc);
+void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
+void pwc_dec1_exit(void);
+
+#endif
+
 
--- /dev/null
+/* Linux driver for Philips webcam
+   Decompression for chipset version 2 et 3
+   (C) 2004-2006  Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "pwc-timon.h"
+#include "pwc-kiara.h"
+#include "pwc-dec23.h"
+#include <media/pwc-ioctl.h>
+
+#include <linux/string.h>
+
+/*
+ * USE_LOOKUP_TABLE_TO_CLAMP
+ *   0: use a C version of this tests:  {  a<0?0:(a>255?255:a) }
+ *   1: use a faster lookup table for cpu with a big cache (intel)
+ */
+#define USE_LOOKUP_TABLE_TO_CLAMP      1
+/*
+ * UNROLL_LOOP_FOR_COPYING_BLOCK
+ *   0: use a loop for a smaller code (but little slower)
+ *   1: when unrolling the loop, gcc produces some faster code (perhaps only
+ *   valid for intel processor class). Activating this option, automaticaly
+ *   activate USE_LOOKUP_TABLE_TO_CLAMP
+ */
+#define UNROLL_LOOP_FOR_COPY           1
+#if UNROLL_LOOP_FOR_COPY
+# undef USE_LOOKUP_TABLE_TO_CLAMP
+# define USE_LOOKUP_TABLE_TO_CLAMP 1
+#endif
+
+/*
+ * ENABLE_BAYER_DECODER
+ *   0: bayer decoder is not build (save some space)
+ *   1: bayer decoder is build and can be used
+ */
+#define ENABLE_BAYER_DECODER 0
+
+static void build_subblock_pattern(struct pwc_dec23_private *pdec)
+{
+       static const unsigned int initial_values[12] = {
+               -0x526500, -0x221200, 0x221200, 0x526500,
+                          -0x3de200, 0x3de200,
+               -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
+                          -0x12c200, 0x12c200
+
+       };
+       static const unsigned int values_derivated[12] = {
+               0xa4ca, 0x4424, -0x4424, -0xa4ca,
+                       0x7bc4, -0x7bc4,
+               0xdb69, 0x5aba, -0x5aba, -0xdb69,
+                       0x2584, -0x2584
+       };
+       unsigned int temp_values[12];
+       int i, j;
+
+       memcpy(temp_values, initial_values, sizeof(initial_values));
+       for (i = 0; i < 256; i++) {
+               for (j = 0; j < 12; j++) {
+                       pdec->table_subblock[i][j] = temp_values[j];
+                       temp_values[j] += values_derivated[j];
+               }
+       }
+}
+
+static void build_bit_powermask_table(struct pwc_dec23_private *pdec)
+{
+       unsigned char *p;
+       unsigned int bit, byte, mask, val;
+       unsigned int bitpower = 1;
+
+       for (bit = 0; bit < 8; bit++) {
+               mask = bitpower - 1;
+               p = pdec->table_bitpowermask[bit];
+               for (byte = 0; byte < 256; byte++) {
+                       val = (byte & mask);
+                       if (byte & bitpower)
+                               val = -val;
+                       *p++ = val;
+               }
+               bitpower<<=1;
+       }
+}
+
+
+static void build_table_color(const unsigned int romtable[16][8],
+                             unsigned char p0004[16][1024],
+                             unsigned char p8004[16][256])
+{
+       int compression_mode, j, k, bit, pw;
+       unsigned char *p0, *p8;
+       const unsigned int *r;
+
+       /* We have 16 compressions tables */
+       for (compression_mode = 0; compression_mode < 16; compression_mode++) {
+               p0 = p0004[compression_mode];
+               p8 = p8004[compression_mode];
+               r  = romtable[compression_mode];
+
+               for (j = 0; j < 8; j++, r++, p0 += 128) {
+
+                       for (k = 0; k < 16; k++) {
+                               if (k == 0)
+                                       bit = 1;
+                               else if (k >= 1 && k < 3)
+                                       bit = (r[0] >> 15) & 7;
+                               else if (k >= 3 && k < 6)
+                                       bit = (r[0] >> 12) & 7;
+                               else if (k >= 6 && k < 10)
+                                       bit = (r[0] >> 9) & 7;
+                               else if (k >= 10 && k < 13)
+                                       bit = (r[0] >> 6) & 7;
+                               else if (k >= 13 && k < 15)
+                                       bit = (r[0] >> 3) & 7;
+                               else
+                                       bit = (r[0]) & 7;
+                               if (k == 0)
+                                       *p8++ = 8;
+                               else
+                                       *p8++ = j - bit;
+                               *p8++ = bit;
+
+                               pw = 1 << bit;
+                               p0[k + 0x00] = (1 * pw) + 0x80;
+                               p0[k + 0x10] = (2 * pw) + 0x80;
+                               p0[k + 0x20] = (3 * pw) + 0x80;
+                               p0[k + 0x30] = (4 * pw) + 0x80;
+                               p0[k + 0x40] = (-1 * pw) + 0x80;
+                               p0[k + 0x50] = (-2 * pw) + 0x80;
+                               p0[k + 0x60] = (-3 * pw) + 0x80;
+                               p0[k + 0x70] = (-4 * pw) + 0x80;
+                       }       /* end of for (k=0; k<16; k++, p8++) */
+               }       /* end of for (j=0; j<8; j++ , table++) */
+       } /* end of foreach compression_mode */
+}
+
+/*
+ *
+ */
+static void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
+{
+#define SCALEBITS 15
+#define ONE_HALF  (1UL << (SCALEBITS - 1))
+       int i;
+       unsigned int offset1 = ONE_HALF;
+       unsigned int offset2 = 0x0000;
+
+       for (i=0; i<256; i++) {
+               pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
+               pdec->table_d800[i] = offset2;
+
+               offset1 += 0x7bc4;
+               offset2 += 0x7bc4;
+       }
+}
+
+/*
+ * To decode the stream:
+ *   if look_bits(2) == 0:     # op == 2 in the lookup table
+ *      skip_bits(2)
+ *      end of the stream
+ *   elif look_bits(3) == 7:   # op == 1 in the lookup table
+ *      skip_bits(3)
+ *      yyyy = get_bits(4)
+ *      xxxx = get_bits(8)
+ *   else:                     # op == 0 in the lookup table
+ *      skip_bits(x)
+ *
+ * For speedup processing, we build a lookup table and we takes the first 6 bits.
+ *
+ * struct {
+ *   unsigned char op;     // operation to execute
+ *   unsigned char bits;    // bits use to perform operation
+ *   unsigned char offset1; // offset to add to access in the table_0004 % 16
+ *   unsigned char offset2; // offset to add to access in the table_0004
+ * }
+ *
+ * How to build this table ?
+ *   op == 2 when (i%4)==0
+ *   op == 1 when (i%8)==7
+ *   op == 0 otherwise
+ *
+ */
+static const unsigned char hash_table_ops[64*4] = {
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x01, 0x30,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x20,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x00,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x02, 0x10,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x60,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x40,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x40,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x01, 0x70,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x20,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x00,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x10,
+       0x00, 0x06, 0x02, 0x50,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x01, 0x60,
+       0x01, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x00,
+       0x00, 0x04, 0x01, 0x50,
+       0x00, 0x05, 0x02, 0x40,
+       0x02, 0x00, 0x00, 0x00,
+       0x00, 0x03, 0x01, 0x40,
+       0x00, 0x05, 0x03, 0x40,
+       0x01, 0x00, 0x00, 0x00
+};
+
+/*
+ *
+ */
+static const unsigned int MulIdx[16][16] = {
+       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+       {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
+       {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
+       {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
+       {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
+       {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
+       {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
+       {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
+       {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
+       {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
+       {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
+       {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
+       {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
+       {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
+       {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
+       {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
+};
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+#define MAX_OUTER_CROP_VALUE   (512)
+static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
+#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
+#else
+#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
+#endif
+
+
+/* If the type or the command change, we rebuild the lookup table */
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+{
+       int flags, version, shift, i;
+       struct pwc_dec23_private *pdec;
+
+       if (pwc->decompress_data == NULL) {
+               pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+               if (pdec == NULL)
+                       return -ENOMEM;
+               pwc->decompress_data = pdec;
+       }
+       pdec = pwc->decompress_data;
+
+       if (DEVICE_USE_CODEC3(type)) {
+               flags = cmd[2] & 0x18;
+               if (flags == 8)
+                       pdec->nbits = 7;        /* More bits, mean more bits to encode the stream, but better quality */
+               else if (flags == 0x10)
+                       pdec->nbits = 8;
+               else
+                       pdec->nbits = 6;
+
+               version = cmd[2] >> 5;
+               build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+               build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+
+       } else {
+
+               flags = cmd[2] & 6;
+               if (flags == 2)
+                       pdec->nbits = 7;
+               else if (flags == 4)
+                       pdec->nbits = 8;
+               else
+                       pdec->nbits = 6;
+
+               version = cmd[2] >> 3;
+               build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+               build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+       }
+
+       /* Informations can be coded on a variable number of bits but never less than 8 */
+       shift = 8 - pdec->nbits;
+       pdec->scalebits = SCALEBITS - shift;
+       pdec->nbitsmask = 0xFF >> shift;
+
+       fill_table_dc00_d800(pdec);
+       build_subblock_pattern(pdec);
+       build_bit_powermask_table(pdec);
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+       /* Build the static table to clamp value [0-255] */
+       for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
+               pwc_crop_table[i] = 0;
+       for (i=0; i<256; i++)
+               pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
+       for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
+               pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
+#endif
+
+       return 0;
+}
+
+/*
+ * Copy the 4x4 image block to Y plane buffer
+ */
+static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       const int *c = src;
+       unsigned char *d = dst;
+
+       *d++ = cm[c[0] >> scalebits];
+       *d++ = cm[c[1] >> scalebits];
+       *d++ = cm[c[2] >> scalebits];
+       *d++ = cm[c[3] >> scalebits];
+
+       d = dst + bytes_per_line;
+       *d++ = cm[c[4] >> scalebits];
+       *d++ = cm[c[5] >> scalebits];
+       *d++ = cm[c[6] >> scalebits];
+       *d++ = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line*2;
+       *d++ = cm[c[8] >> scalebits];
+       *d++ = cm[c[9] >> scalebits];
+       *d++ = cm[c[10] >> scalebits];
+       *d++ = cm[c[11] >> scalebits];
+
+       d = dst + bytes_per_line*3;
+       *d++ = cm[c[12] >> scalebits];
+       *d++ = cm[c[13] >> scalebits];
+       *d++ = cm[c[14] >> scalebits];
+       *d++ = cm[c[15] >> scalebits];
+#else
+       int i;
+       const int *c = src;
+       unsigned char *d = dst;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*2;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*3;
+       for (i = 0; i < 4; i++, c++)
+               *d++ = CLAMP((*c) >> scalebits);
+#endif
+}
+
+/*
+ * Copy the 4x4 image block to a CrCb plane buffer
+ *
+ */
+static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       /* Unroll all loops */
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       const int *c = src;
+       unsigned char *d = dst;
+
+       *d++ = cm[c[0] >> scalebits];
+       *d++ = cm[c[4] >> scalebits];
+       *d++ = cm[c[1] >> scalebits];
+       *d++ = cm[c[5] >> scalebits];
+       *d++ = cm[c[2] >> scalebits];
+       *d++ = cm[c[6] >> scalebits];
+       *d++ = cm[c[3] >> scalebits];
+       *d++ = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line;
+       *d++ = cm[c[12] >> scalebits];
+       *d++ = cm[c[8] >> scalebits];
+       *d++ = cm[c[13] >> scalebits];
+       *d++ = cm[c[9] >> scalebits];
+       *d++ = cm[c[14] >> scalebits];
+       *d++ = cm[c[10] >> scalebits];
+       *d++ = cm[c[15] >> scalebits];
+       *d++ = cm[c[11] >> scalebits];
+#else
+       int i;
+       const int *c1 = src;
+       const int *c2 = src + 4;
+       unsigned char *d = dst;
+
+       for (i = 0; i < 4; i++, c1++, c2++) {
+               *d++ = CLAMP((*c1) >> scalebits);
+               *d++ = CLAMP((*c2) >> scalebits);
+       }
+       c1 = src + 12;
+       d = dst + bytes_per_line;
+       for (i = 0; i < 4; i++, c1++, c2++) {
+               *d++ = CLAMP((*c1) >> scalebits);
+               *d++ = CLAMP((*c2) >> scalebits);
+       }
+#endif
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 8x2 pixels
+ *   . G . G . G . G . G . G . G
+ *   . . . . . . . . . . . . . .
+ *   . G . G . G . G . G . G . G
+ *   . . . . . . . . . . . . . .
+ *   or
+ *   . . . . . . . . . . . . . .
+ *   G . G . G . G . G . G . G .
+ *   . . . . . . . . . . . . . .
+ *   G . G . G . G . G . G . G .
+*/
+static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       /* Unroll all loops */
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       unsigned char *d = dst;
+       const int *c = src;
+
+       d[0] = cm[c[0] >> scalebits];
+       d[2] = cm[c[1] >> scalebits];
+       d[4] = cm[c[2] >> scalebits];
+       d[6] = cm[c[3] >> scalebits];
+       d[8] = cm[c[4] >> scalebits];
+       d[10] = cm[c[5] >> scalebits];
+       d[12] = cm[c[6] >> scalebits];
+       d[14] = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line;
+       d[0] = cm[c[8] >> scalebits];
+       d[2] = cm[c[9] >> scalebits];
+       d[4] = cm[c[10] >> scalebits];
+       d[6] = cm[c[11] >> scalebits];
+       d[8] = cm[c[12] >> scalebits];
+       d[10] = cm[c[13] >> scalebits];
+       d[12] = cm[c[14] >> scalebits];
+       d[14] = cm[c[15] >> scalebits];
+#else
+       int i;
+       unsigned char *d;
+       const int *c = src;
+
+       d = dst;
+       for (i = 0; i < 8; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line;
+       for (i = 0; i < 8; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 4x4 pixels
+ *   R . R . R . R
+ *   . B . B . B .
+ *   R . R . R . R
+ *   . B . B . B .
+ */
+static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+       /* Unroll all loops */
+       const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+       unsigned char *d = dst;
+       const int *c = src;
+
+       d[0] = cm[c[0] >> scalebits];
+       d[2] = cm[c[1] >> scalebits];
+       d[4] = cm[c[2] >> scalebits];
+       d[6] = cm[c[3] >> scalebits];
+
+       d = dst + bytes_per_line;
+       d[1] = cm[c[4] >> scalebits];
+       d[3] = cm[c[5] >> scalebits];
+       d[5] = cm[c[6] >> scalebits];
+       d[7] = cm[c[7] >> scalebits];
+
+       d = dst + bytes_per_line*2;
+       d[0] = cm[c[8] >> scalebits];
+       d[2] = cm[c[9] >> scalebits];
+       d[4] = cm[c[10] >> scalebits];
+       d[6] = cm[c[11] >> scalebits];
+
+       d = dst + bytes_per_line*3;
+       d[1] = cm[c[12] >> scalebits];
+       d[3] = cm[c[13] >> scalebits];
+       d[5] = cm[c[14] >> scalebits];
+       d[7] = cm[c[15] >> scalebits];
+#else
+       int i;
+       unsigned char *d;
+       const int *c = src;
+
+       d = dst;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2+1] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*2;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2] = CLAMP((*c) >> scalebits);
+
+       d = dst + bytes_per_line*3;
+       for (i = 0; i < 4; i++, c++)
+               d[i*2+1] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+/*
+ * To manage the stream, we keep bits in a 32 bits register.
+ * fill_nbits(n): fill the reservoir with at least n bits
+ * skip_bits(n): discard n bits from the reservoir
+ * get_bits(n): fill the reservoir, returns the first n bits and discard the
+ *              bits from the reservoir.
+ * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
+ *                 contains at least n bits. bits returned is discarded.
+ */
+#define fill_nbits(pdec, nbits_wanted) do { \
+   while (pdec->nbits_in_reservoir<(nbits_wanted)) \
+    { \
+      pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
+      pdec->nbits_in_reservoir += 8; \
+    } \
+}  while(0);
+
+#define skip_nbits(pdec, nbits_to_skip) do { \
+   pdec->reservoir >>= (nbits_to_skip); \
+   pdec->nbits_in_reservoir -= (nbits_to_skip); \
+}  while(0);
+
+#define get_nbits(pdec, nbits_wanted, result) do { \
+   fill_nbits(pdec, nbits_wanted); \
+   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+   skip_nbits(pdec, nbits_wanted); \
+}  while(0);
+
+#define __get_nbits(pdec, nbits_wanted, result) do { \
+   result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+   skip_nbits(pdec, nbits_wanted); \
+}  while(0);
+
+#define look_nbits(pdec, nbits_wanted) \
+   ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
+
+/*
+ * Decode a 4x4 pixel block
+ */
+static void decode_block(struct pwc_dec23_private *pdec,
+                        const unsigned char *ptable0004,
+                        const unsigned char *ptable8004)
+{
+       unsigned int primary_color;
+       unsigned int channel_v, offset1, op;
+       int i;
+
+       fill_nbits(pdec, 16);
+       __get_nbits(pdec, pdec->nbits, primary_color);
+
+       if (look_nbits(pdec,2) == 0) {
+               skip_nbits(pdec, 2);
+               /* Very simple, the color is the same for all pixels of the square */
+               for (i = 0; i < 16; i++)
+                       pdec->temp_colors[i] = pdec->table_dc00[primary_color];
+
+               return;
+       }
+
+       /* This block is encoded with small pattern */
+       for (i = 0; i < 16; i++)
+               pdec->temp_colors[i] = pdec->table_d800[primary_color];
+
+       __get_nbits(pdec, 3, channel_v);
+       channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
+
+       ptable0004 += (channel_v * 128);
+       ptable8004 += (channel_v * 32);
+
+       offset1 = 0;
+       do
+       {
+               unsigned int htable_idx, rows = 0;
+               const unsigned int *block;
+
+               /* [  zzzz y x x ]
+                *     xx == 00 :=> end of the block def, remove the two bits from the stream
+                *    yxx == 111
+                *    yxx == any other value
+                *
+                */
+               fill_nbits(pdec, 16);
+               htable_idx = look_nbits(pdec, 6);
+               op = hash_table_ops[htable_idx * 4];
+
+               if (op == 2) {
+                       skip_nbits(pdec, 2);
+
+               } else if (op == 1) {
+                       /* 15bits [ xxxx xxxx yyyy 111 ]
+                        * yyy => offset in the table8004
+                        * xxx => offset in the tabled004 (tree)
+                        */
+                       unsigned int mask, shift;
+                       unsigned int nbits, col1;
+                       unsigned int yyyy;
+
+                       skip_nbits(pdec, 3);
+                       /* offset1 += yyyy */
+                       __get_nbits(pdec, 4, yyyy);
+                       offset1 += 1 + yyyy;
+                       offset1 &= 0x0F;
+                       nbits = ptable8004[offset1 * 2];
+
+                       /* col1 = xxxx xxxx */
+                       __get_nbits(pdec, nbits+1, col1);
+
+                       /* Bit mask table */
+                       mask = pdec->table_bitpowermask[nbits][col1];
+                       shift = ptable8004[offset1 * 2 + 1];
+                       rows = ((mask << shift) + 0x80) & 0xFF;
+
+                       block = pdec->table_subblock[rows];
+                       for (i = 0; i < 16; i++)
+                               pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+               } else {
+                       /* op == 0
+                        * offset1 is coded on 3 bits
+                        */
+                       unsigned int shift;
+
+                       offset1 += hash_table_ops [htable_idx * 4 + 2];
+                       offset1 &= 0x0F;
+
+                       rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
+                       block = pdec->table_subblock[rows];
+                       for (i = 0; i < 16; i++)
+                               pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+                       shift = hash_table_ops[htable_idx * 4 + 1];
+                       skip_nbits(pdec, shift);
+               }
+
+       } while (op != 2);
+
+}
+
+static void DecompressBand23(struct pwc_dec23_private *pdec,
+                            const unsigned char *rawyuv,
+                            unsigned char *planar_y,
+                            unsigned char *planar_u,
+                            unsigned char *planar_v,
+                            unsigned int   compressed_image_width,
+                            unsigned int   real_image_width)
+{
+       int compression_index, nblocks;
+       const unsigned char *ptable0004;
+       const unsigned char *ptable8004;
+
+       pdec->reservoir = 0;
+       pdec->nbits_in_reservoir = 0;
+       pdec->stream = rawyuv + 1;      /* The first byte of the stream is skipped */
+
+       get_nbits(pdec, 4, compression_index);
+
+       /* pass 1: uncompress Y component */
+       nblocks = compressed_image_width / 4;
+
+       ptable0004 = pdec->table_0004_pass1[compression_index];
+       ptable8004 = pdec->table_8004_pass1[compression_index];
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
+               planar_y += 4;
+               nblocks--;
+       }
+
+       /* pass 2: uncompress UV component */
+       nblocks = compressed_image_width / 8;
+
+       ptable0004 = pdec->table_0004_pass2[compression_index];
+       ptable8004 = pdec->table_8004_pass2[compression_index];
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
+
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
+
+               planar_v += 8;
+               planar_u += 8;
+               nblocks -= 2;
+       }
+
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Size need to be a multiple of 8 in width
+ *
+ * Return a block of four line encoded like this:
+ *
+ *   G R G R G R G R G R G R G R G R
+ *   B G B G B G B G B G B G B G B G
+ *   G R G R G R G R G R G R G R G R
+ *   B G B G B G B G B G B G B G B G
+ *
+ */
+static void DecompressBandBayer(struct pwc_dec23_private *pdec,
+                               const unsigned char *rawyuv,
+                               unsigned char *rgbbayer,
+                               unsigned int   compressed_image_width,
+                               unsigned int   real_image_width)
+{
+       int compression_index, nblocks;
+       const unsigned char *ptable0004;
+       const unsigned char *ptable8004;
+       unsigned char *dest;
+
+       pdec->reservoir = 0;
+       pdec->nbits_in_reservoir = 0;
+       pdec->stream = rawyuv + 1;      /* The first byte of the stream is skipped */
+
+       get_nbits(pdec, 4, compression_index);
+
+       /* pass 1: uncompress RB component */
+       nblocks = compressed_image_width / 4;
+
+       ptable0004 = pdec->table_0004_pass1[compression_index];
+       ptable8004 = pdec->table_8004_pass1[compression_index];
+       dest = rgbbayer;
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
+               dest += 8;
+               nblocks--;
+       }
+
+       /* pass 2: uncompress G component */
+       nblocks = compressed_image_width / 8;
+
+       ptable0004 = pdec->table_0004_pass2[compression_index];
+       ptable8004 = pdec->table_8004_pass2[compression_index];
+
+       /* Each block decode a square of 4x4 */
+       while (nblocks) {
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
+
+               decode_block(pdec, ptable0004, ptable8004);
+               copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
+
+               rgbbayer += 16;
+               nblocks -= 2;
+       }
+}
+#endif
+
+
+/**
+ *
+ * Uncompress a pwc23 buffer.
+ *
+ * pwc.view: size of the image wanted
+ * pwc.image: size of the image returned by the camera
+ * pwc.offset: (x,y) to displayer image in the view
+ *
+ * src: raw data
+ * dst: image output
+ * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
+ */
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+                         const void *src,
+                         void *dst,
+                         int flags)
+{
+       int bandlines_left, stride, bytes_per_block;
+
+       bandlines_left = pwc->image.y / 4;
+       bytes_per_block = pwc->view.x * 4;
+
+       if (flags & PWCX_FLAG_BAYER) {
+#if ENABLE_BAYER_DECODER
+               /* RGB Bayer format */
+               unsigned char *rgbout;
+
+               stride = pwc->view.x * pwc->offset.y;
+               rgbout = dst + stride + pwc->offset.x;
+
+
+               while (bandlines_left--) {
+
+                       DecompressBandBayer(pwc->decompress_data,
+                                           src,
+                                           rgbout,
+                                           pwc->image.x, pwc->view.x);
+
+                       src += pwc->vbandlength;
+                       rgbout += bytes_per_block;
+
+               }
+#else
+               memcpy(dst, 0, pwc->view.x * pwc->view.y);
+#endif
+
+       } else {
+               /* YUV420P image format */
+               unsigned char *pout_planar_y;
+               unsigned char *pout_planar_u;
+               unsigned char *pout_planar_v;
+               unsigned int   plane_size;
+
+               plane_size = pwc->view.x * pwc->view.y;
+
+               /* offset in Y plane */
+               stride = pwc->view.x * pwc->offset.y;
+               pout_planar_y = dst + stride + pwc->offset.x;
+
+               /* offsets in U/V planes */
+               stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
+               pout_planar_u = dst + plane_size + stride;
+               pout_planar_v = dst + plane_size + plane_size / 4 + stride;
+
+               while (bandlines_left--) {
+
+                       DecompressBand23(pwc->decompress_data,
+                                        src,
+                                        pout_planar_y, pout_planar_u, pout_planar_v,
+                                        pwc->image.x, pwc->view.x);
+                       src += pwc->vbandlength;
+                       pout_planar_y += bytes_per_block;
+                       pout_planar_u += pwc->view.x;
+                       pout_planar_v += pwc->view.x;
+
+               }
+
+       }
+
+}
+
+void pwc_dec23_exit(void)
+{
+       /* Do nothing */
+
+}
+
+/**
+ * Allocate a private structure used by lookup table.
+ * You must call kfree() to free the memory allocated.
+ */
+int pwc_dec23_alloc(struct pwc_device *pwc)
+{
+       pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+       if (pwc->decompress_data == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
 
--- /dev/null
+/* Linux driver for Philips webcam
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef PWC_DEC23_H
+#define PWC_DEC23_H
+
+#include "pwc.h"
+
+struct pwc_dec23_private
+{
+  unsigned int scalebits;
+  unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
+
+  unsigned int reservoir;
+  unsigned int nbits_in_reservoir;
+  const unsigned char *stream;
+  int temp_colors[16];
+
+  unsigned char table_0004_pass1[16][1024];
+  unsigned char table_0004_pass2[16][1024];
+  unsigned char table_8004_pass1[16][256];
+  unsigned char table_8004_pass2[16][256];
+  unsigned int  table_subblock[256][12];
+
+  unsigned char table_bitpowermask[8][256];
+  unsigned int  table_d800[256];
+  unsigned int  table_dc00[256];
+
+};
+
+
+int pwc_dec23_alloc(struct pwc_device *pwc);
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
+void pwc_dec23_exit(void);
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+                         const void *src,
+                         void *dst,
+                         int flags);
+
+
+
+#endif
+
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+
 
 /* Linux driver for Philips webcam
    USB and Video4Linux interface part.
    (C) 1999-2004 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #include <linux/poll.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/version.h>
 #include <asm/io.h>
+#include <linux/moduleparam.h>
 
 #include "pwc.h"
-#include "pwc-ioctl.h"
 #include "pwc-kiara.h"
 #include "pwc-timon.h"
+#include "pwc-dec23.h"
+#include "pwc-dec1.h"
 #include "pwc-uncompress.h"
 
 /* Function prototypes and driver templates */
 
 /* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
+static const struct usb_device_id pwc_device_table [] = {
        { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
        { USB_DEVICE(0x0471, 0x0303) },
        { USB_DEVICE(0x0471, 0x0304) },
        { USB_DEVICE(0x0471, 0x0308) },
        { USB_DEVICE(0x0471, 0x030C) },
        { USB_DEVICE(0x0471, 0x0310) },
-       { USB_DEVICE(0x0471, 0x0311) },
+       { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
        { USB_DEVICE(0x0471, 0x0312) },
        { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+       { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
        { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
        { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
        { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
        { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
        { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
        { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
-       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
-       { USB_DEVICE(0x055D, 0x9001) },
+       { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
+       { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
+       { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
        { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
        { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
        { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_fbufs = 3;   /* Default number of frame buffers */
-static int default_mbufs = 2;  /* Default number of mmap() buffers */
-       int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+       int pwc_mbufs = 2;      /* Default number of mmap() buffers */
+#if CONFIG_PWC_DEBUG
+       int pwc_trace = PWC_DEBUG_LEVEL;
+#endif
 static int power_save = 0;
 static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+       int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
 static struct {
        int type;
        char serial_number[30];
 
 static int pwc_video_open(struct inode *inode, struct file *file);
 static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
                          size_t count, loff_t *ppos);
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
 static int  pwc_video_ioctl(struct inode *inode, struct file *file,
        .poll =         pwc_video_poll,
        .mmap =         pwc_video_mmap,
        .ioctl =        pwc_video_ioctl,
-       .compat_ioctl = v4l_compat_ioctl32,
        .llseek =       no_llseek,
 };
 static struct video_device pwc_template = {
 /* Here we want the physical address of the memory.
  * This is used when initializing the contents of the area.
  */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
-       unsigned long kva, ret;
 
-       kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
-       kva |= adr & (PAGE_SIZE-1); /* restore the offset */
-       ret = __pa(kva);
-       return ret;
-}
 
-static void * rvmalloc(unsigned long size)
+
+static void *pwc_rvmalloc(unsigned long size)
 {
        void * mem;
        unsigned long adr;
 
-       size=PAGE_ALIGN(size);
        mem=vmalloc_32(size);
-       if (mem)
-       {
-               memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-               adr=(unsigned long) mem;
-               while (size > 0)
-               {
-                       SetPageReserved(vmalloc_to_page((void *)adr));
-                       adr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-       }
+       if (!mem)
+               return NULL;
+
+       memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+       adr=(unsigned long) mem;
+       while (size > 0)
+        {
+          SetPageReserved(vmalloc_to_page((void *)adr));
+          adr  += PAGE_SIZE;
+          size -= PAGE_SIZE;
+        }
        return mem;
 }
 
-static void rvfree(void * mem, unsigned long size)
+static void pwc_rvfree(void * mem, unsigned long size)
 {
        unsigned long adr;
 
-       if (mem)
-       {
-               adr=(unsigned long) mem;
-               while ((long) size > 0)
-               {
-                       ClearPageReserved(vmalloc_to_page((void *)adr));
-                       adr+=PAGE_SIZE;
-                       size-=PAGE_SIZE;
-               }
-               vfree(mem);
-       }
+       if (!mem)
+               return;
+
+       adr=(unsigned long) mem;
+       while ((long) size > 0)
+        {
+          ClearPageReserved(vmalloc_to_page((void *)adr));
+          adr  += PAGE_SIZE;
+          size -= PAGE_SIZE;
+        }
+       vfree(mem);
 }
 
 
 
 static int pwc_allocate_buffers(struct pwc_device *pdev)
 {
-       int i;
+       int i, err;
        void *kbuf;
 
-       Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+       PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
 
        if (pdev == NULL)
                return -ENXIO;
 
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("allocate_buffers(): magic failed.\n");
-               return -ENXIO;
-       }
-#endif
-       /* Allocate Isochronous pipe buffers */
+       /* Allocate Isochronuous pipe buffers */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                if (pdev->sbuf[i].data == NULL) {
-                       kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+                       kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
                        if (kbuf == NULL) {
-                               Err("Failed to allocate iso buffer %d.\n", i);
+                               PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
                                return -ENOMEM;
                        }
-                       Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+                       PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
                        pdev->sbuf[i].data = kbuf;
-                       memset(kbuf, 0, ISO_BUFFER_SIZE);
                }
        }
 
        /* Allocate frame buffer structure */
        if (pdev->fbuf == NULL) {
-               kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+               kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
                if (kbuf == NULL) {
-                       Err("Failed to allocate frame buffer structure.\n");
+                       PWC_ERROR("Failed to allocate frame buffer structure.\n");
                        return -ENOMEM;
                }
-               Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+               PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
                pdev->fbuf = kbuf;
-               memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
        }
+
        /* create frame buffers, and make circular ring */
        for (i = 0; i < default_fbufs; i++) {
                if (pdev->fbuf[i].data == NULL) {
                        kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
                        if (kbuf == NULL) {
-                               Err("Failed to allocate frame buffer %d.\n", i);
+                               PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
                                return -ENOMEM;
                        }
-                       Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+                       PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
                        pdev->fbuf[i].data = kbuf;
-                       memset(kbuf, 128, PWC_FRAME_SIZE);
+                       memset(kbuf, 0, PWC_FRAME_SIZE);
                }
        }
 
        /* Allocate decompressor table space */
-       kbuf = NULL;
-       switch (pdev->type)
-        {
-         case 675:
-         case 680:
-         case 690:
-         case 720:
-         case 730:
-         case 740:
-         case 750:
-#if 0
-           Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
-           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);       /* Timon & Kiara */
-           break;
-         case 645:
-         case 646:
-           /* TODO & FIXME */
-           kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
-           break;
-#endif
-       ;
-        }
-       pdev->decompress_data = kbuf;
+       if (DEVICE_USE_CODEC1(pdev->type))
+               err = pwc_dec1_alloc(pdev);
+       else
+               err = pwc_dec23_alloc(pdev);
+
+       if (err) {
+               PWC_ERROR("Failed to allocate decompress table.\n");
+               return err;
+       }
 
        /* Allocate image buffer; double buffer for mmap() */
-       kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+       kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
        if (kbuf == NULL) {
-               Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+               PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
+                               pwc_mbufs * pdev->len_per_image);
                return -ENOMEM;
        }
-       Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+       PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
        pdev->image_data = kbuf;
-       for (i = 0; i < default_mbufs; i++)
-               pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
-       for (; i < MAX_IMAGES; i++)
-               pdev->image_ptr[i] = NULL;
+       for (i = 0; i < pwc_mbufs; i++) {
+               pdev->images[i].offset = i * pdev->len_per_image;
+               pdev->images[i].vma_use_count = 0;
+       }
+       for (; i < MAX_IMAGES; i++) {
+               pdev->images[i].offset = 0;
+       }
 
        kbuf = NULL;
 
-       Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+       PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
        return 0;
 }
 
 {
        int i;
 
-       Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+       PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
 
        if (pdev == NULL)
                return;
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("free_buffers(): magic failed.\n");
-               return;
-       }
-#endif
-
        /* Release Iso-pipe buffers */
        for (i = 0; i < MAX_ISO_BUFS; i++)
                if (pdev->sbuf[i].data != NULL) {
-                       Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+                       PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
                        kfree(pdev->sbuf[i].data);
                        pdev->sbuf[i].data = NULL;
                }
        if (pdev->fbuf != NULL) {
                for (i = 0; i < default_fbufs; i++) {
                        if (pdev->fbuf[i].data != NULL) {
-                               Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+                               PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
                                vfree(pdev->fbuf[i].data);
                                pdev->fbuf[i].data = NULL;
                        }
 
        /* Intermediate decompression buffer & tables */
        if (pdev->decompress_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+               PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
                kfree(pdev->decompress_data);
                pdev->decompress_data = NULL;
        }
-       pdev->decompressor = NULL;
 
        /* Release image buffers */
        if (pdev->image_data != NULL) {
-               Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
-               rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+               PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
+               pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
        }
        pdev->image_data = NULL;
 
-       Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+       PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
 }
 
 /* The frame & image buffer mess.
 /**
   \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
  */
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+static int pwc_next_fill_frame(struct pwc_device *pdev)
 {
        int ret;
        unsigned long flags;
        }
        else {
                /* Hmm. Take it from the full list */
-#if PWC_DEBUG
                /* sanity check */
                if (pdev->full_frames == NULL) {
-                       Err("Neither empty or full frames available!\n");
+                       PWC_ERROR("Neither empty or full frames available!\n");
                        spin_unlock_irqrestore(&pdev->ptrlock, flags);
                        return -EINVAL;
                }
-#endif
                pdev->fill_frame = pdev->full_frames;
                pdev->full_frames = pdev->full_frames->next;
                ret = 1;
        }
        pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
-       Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
-       pdev->fill_frame->sequence = pdev->sequence++;
-#endif
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
        return ret;
 }
        int i;
        unsigned long flags;
 
+       PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+
        spin_lock_irqsave(&pdev->ptrlock, flags);
        pdev->full_frames = NULL;
        pdev->full_frames_tail = NULL;
        pdev->image_read_pos = 0;
        pdev->fill_image = 0;
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
+
+       PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
 }
 
 
 /**
   \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
  */
-static int pwc_handle_frame(struct pwc_device *pdev)
+int pwc_handle_frame(struct pwc_device *pdev)
 {
        int ret = 0;
        unsigned long flags;
           we can release the lock after this without problems */
        if (pdev->read_frame != NULL) {
                /* This can't theoretically happen */
-               Err("Huh? Read frame still in use?\n");
+               PWC_ERROR("Huh? Read frame still in use?\n");
+               spin_unlock_irqrestore(&pdev->ptrlock, flags);
+               return ret;
+       }
+
+
+       if (pdev->full_frames == NULL) {
+               PWC_ERROR("Woops. No frames ready.\n");
        }
        else {
-               if (pdev->full_frames == NULL) {
-                       Err("Woops. No frames ready.\n");
+               pdev->read_frame = pdev->full_frames;
+               pdev->full_frames = pdev->full_frames->next;
+               pdev->read_frame->next = NULL;
+       }
+
+       if (pdev->read_frame != NULL) {
+               /* Decompression is a lenghty process, so it's outside of the lock.
+                  This gives the isoc_handler the opportunity to fill more frames
+                  in the mean time.
+               */
+               spin_unlock_irqrestore(&pdev->ptrlock, flags);
+               ret = pwc_decompress(pdev);
+               spin_lock_irqsave(&pdev->ptrlock, flags);
+
+               /* We're done with read_buffer, tack it to the end of the empty buffer list */
+               if (pdev->empty_frames == NULL) {
+                       pdev->empty_frames = pdev->read_frame;
+                       pdev->empty_frames_tail = pdev->empty_frames;
                }
                else {
-                       pdev->read_frame = pdev->full_frames;
-                       pdev->full_frames = pdev->full_frames->next;
-                       pdev->read_frame->next = NULL;
-               }
-
-               if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
-                       Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
-                       /* Decompression is a lenghty process, so it's outside of the lock.
-                          This gives the isoc_handler the opportunity to fill more frames
-                          in the mean time.
-                       */
-                       spin_unlock_irqrestore(&pdev->ptrlock, flags);
-                       ret = pwc_decompress(pdev);
-                       spin_lock_irqsave(&pdev->ptrlock, flags);
-
-                       /* We're done with read_buffer, tack it to the end of the empty buffer list */
-                       if (pdev->empty_frames == NULL) {
-                               pdev->empty_frames = pdev->read_frame;
-                               pdev->empty_frames_tail = pdev->empty_frames;
-                       }
-                       else {
-                               pdev->empty_frames_tail->next = pdev->read_frame;
-                               pdev->empty_frames_tail = pdev->read_frame;
-                       }
-                       pdev->read_frame = NULL;
+                       pdev->empty_frames_tail->next = pdev->read_frame;
+                       pdev->empty_frames_tail = pdev->read_frame;
                }
+               pdev->read_frame = NULL;
        }
        spin_unlock_irqrestore(&pdev->ptrlock, flags);
        return ret;
 /**
   \brief Advance pointers of image buffer (after each user request)
 */
-static inline void pwc_next_image(struct pwc_device *pdev)
+void pwc_next_image(struct pwc_device *pdev)
 {
        pdev->image_used[pdev->fill_image] = 0;
-       pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+       pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
 }
 
+/**
+ * Print debug information when a frame is discarded because all of our buffer
+ * is full
+ */
+static void pwc_frame_dumped(struct pwc_device *pdev)
+{
+       pdev->vframes_dumped++;
+       if (pdev->vframe_count < FRAME_LOWMARK)
+               return;
+
+       if (pdev->vframes_dumped < 20)
+               PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
+       else if (pdev->vframes_dumped == 20)
+               PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
+                               pdev->vframe_count);
+}
+
+static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+{
+       int awake = 0;
+
+       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+          frames on the USB wire after an exposure change. This conditition is
+          however detected  in the cam and a bit is set in the header.
+          */
+       if (pdev->type == 730) {
+               unsigned char *ptr = (unsigned char *)fbuf->data;
+
+               if (ptr[1] == 1 && ptr[0] & 0x10) {
+                       PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
+                       pdev->drop_frames += 2;
+                       pdev->vframes_error++;
+               }
+               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                       if (ptr[0] & 0x01) {
+                               pdev->snapshot_button_status = 1;
+                               PWC_TRACE("Snapshot button pressed.\n");
+                       }
+                       else {
+                               PWC_TRACE("Snapshot button released.\n");
+                       }
+               }
+               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+                       if (ptr[0] & 0x02)
+                               PWC_TRACE("Image is mirrored.\n");
+                       else
+                               PWC_TRACE("Image is normal.\n");
+               }
+               pdev->vmirror = ptr[0] & 0x03;
+               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+                  after a short frame; this condition is filtered out specifically. A 4 byte
+                  frame doesn't make sense anyway.
+                  So we get either this sequence:
+                  drop_bit set -> 4 byte frame -> short frame -> good frame
+                  Or this one:
+                  drop_bit set -> short frame -> good frame
+                  So we drop either 3 or 2 frames in all!
+                  */
+               if (fbuf->filled == 4)
+                       pdev->drop_frames++;
+       }
+       else if (pdev->type == 740 || pdev->type == 720) {
+               unsigned char *ptr = (unsigned char *)fbuf->data;
+               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+                       if (ptr[0] & 0x01) {
+                               pdev->snapshot_button_status = 1;
+                               PWC_TRACE("Snapshot button pressed.\n");
+                       }
+                       else
+                               PWC_TRACE("Snapshot button released.\n");
+               }
+               pdev->vmirror = ptr[0] & 0x03;
+       }
+
+       /* In case we were instructed to drop the frame, do so silently.
+          The buffer pointers are not updated either (but the counters are reset below).
+          */
+       if (pdev->drop_frames > 0)
+               pdev->drop_frames--;
+       else {
+               /* Check for underflow first */
+               if (fbuf->filled < pdev->frame_total_size) {
+                       PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
+                                      " discarded.\n", fbuf->filled);
+                       pdev->vframes_error++;
+               }
+               else {
+                       /* Send only once per EOF */
+                       awake = 1; /* delay wake_ups */
+
+                       /* Find our next frame to fill. This will always succeed, since we
+                        * nick a frame from either empty or full list, but if we had to
+                        * take it from the full list, it means a frame got dropped.
+                        */
+                       if (pwc_next_fill_frame(pdev))
+                               pwc_frame_dumped(pdev);
+
+               }
+       } /* !drop_frames */
+       pdev->vframe_count++;
+       return awake;
+}
 
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
        awake = 0;
        pdev = (struct pwc_device *)urb->context;
        if (pdev == NULL) {
-               Err("isoc_handler() called with NULL device?!\n");
+               PWC_ERROR("isoc_handler() called with NULL device?!\n");
                return;
        }
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("isoc_handler() called with bad magic!\n");
-               return;
-       }
-#endif
+
        if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
-               Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+               PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
                return;
        }
        if (urb->status != -EINPROGRESS && urb->status != 0) {
                        case -EILSEQ:           errmsg = "CRC/Timeout (could be anything)"; break;
                        case -ETIMEDOUT:        errmsg = "NAK (device does not respond)"; break;
                }
-               Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+               PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
                /* Give up after a number of contiguous errors on the USB bus.
                   Appearantly something is wrong so we simulate an unplug event.
                 */
                if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
                {
-                       Info("Too many ISOC errors, bailing out.\n");
+                       PWC_INFO("Too many ISOC errors, bailing out.\n");
                        pdev->error_status = EIO;
                        awake = 1;
                        wake_up_interruptible(&pdev->frameq);
 
        fbuf = pdev->fill_frame;
        if (fbuf == NULL) {
-               Err("pwc_isoc_handler without valid fill frame.\n");
+               PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
                awake = 1;
                goto handler_end;
        }
 
                                        /* ...copy data to frame buffer, if possible */
                                        if (flen + fbuf->filled > pdev->frame_total_size) {
-                                               Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+                                               PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
                                                pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
                                                pdev->vframes_error++;
                                        }
                                /* Shorter packet... We probably have the end of an image-frame;
                                   wake up read() process and let select()/poll() do something.
                                   Decompression is done in user time over there.
-                                */
+                                  */
                                if (pdev->vsync == 2) {
-                                       /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
-                                          frames on the USB wire after an exposure change. This conditition is
-                                          however detected  in the cam and a bit is set in the header.
-                                        */
-                                       if (pdev->type == 730) {
-                                               unsigned char *ptr = (unsigned char *)fbuf->data;
-
-                                               if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
-                                                       Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
-                                                       pdev->drop_frames += 2;
-                                                       pdev->vframes_error++;
-                                               }
-                                               if ((ptr[0] ^ pdev->vmirror) & 0x01) {
-                                                       if (ptr[0] & 0x01)
-                                                               Info("Snapshot button pressed.\n");
-                                                       else
-                                                               Info("Snapshot button released.\n");
-                                               }
-                                               if ((ptr[0] ^ pdev->vmirror) & 0x02) {
-                                                       if (ptr[0] & 0x02)
-                                                               Info("Image is mirrored.\n");
-                                                       else
-                                                               Info("Image is normal.\n");
-                                               }
-                                               pdev->vmirror = ptr[0] & 0x03;
-                                               /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
-                                                  after a short frame; this condition is filtered out specifically. A 4 byte
-                                                  frame doesn't make sense anyway.
-                                                  So we get either this sequence:
-                                                       drop_bit set -> 4 byte frame -> short frame -> good frame
-                                                  Or this one:
-                                                       drop_bit set -> short frame -> good frame
-                                                  So we drop either 3 or 2 frames in all!
-                                                */
-                                               if (fbuf->filled == 4)
-                                                       pdev->drop_frames++;
+                                       if (pwc_rcv_short_packet(pdev, fbuf)) {
+                                               awake = 1;
+                                               fbuf = pdev->fill_frame;
                                        }
-
-                                       /* In case we were instructed to drop the frame, do so silently.
-                                          The buffer pointers are not updated either (but the counters are reset below).
-                                        */
-                                       if (pdev->drop_frames > 0)
-                                               pdev->drop_frames--;
-                                       else {
-                                               /* Check for underflow first */
-                                               if (fbuf->filled < pdev->frame_total_size) {
-                                                       Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
-                                                       pdev->vframes_error++;
-                                               }
-                                               else {
-                                                       /* Send only once per EOF */
-                                                       awake = 1; /* delay wake_ups */
-
-                                                       /* Find our next frame to fill. This will always succeed, since we
-                                                        * nick a frame from either empty or full list, but if we had to
-                                                        * take it from the full list, it means a frame got dropped.
-                                                        */
-                                                       if (pwc_next_fill_frame(pdev)) {
-                                                               pdev->vframes_dumped++;
-                                                               if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
-                                                                       if (pdev->vframes_dumped < 20)
-                                                                               Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
-                                                                       if (pdev->vframes_dumped == 20)
-                                                                               Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
-                                                               }
-                                                       }
-                                                       fbuf = pdev->fill_frame;
-                                               }
-                                       } /* !drop_frames */
-                                       pdev->vframe_count++;
                                }
                                fbuf->filled = 0;
                                fillptr = fbuf->data;
                                pdev->vsync = 1;
-                       } /* .. flen < last_packet_size */
+                       }
+
                        pdev->vlast_packet_size = flen;
                } /* ..status == 0 */
-#if PWC_DEBUG
-               /* This is normally not interesting to the user, unless you are really debugging something */
                else {
+                       /* This is normally not interesting to the user, unless
+                        * you are really debugging something */
                        static int iso_error = 0;
                        iso_error++;
                        if (iso_error < 20)
-                               Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+                               PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
                }
-#endif
        }
 
 handler_end:
        urb->dev = pdev->udev;
        i = usb_submit_urb(urb, GFP_ATOMIC);
        if (i != 0)
-               Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+               PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
 }
 
 
-static int pwc_isoc_init(struct pwc_device *pdev)
+int pwc_isoc_init(struct pwc_device *pdev)
 {
        struct usb_device *udev;
        struct urb *urb;
        /* Get the current alternate interface, adjust packet size */
        if (!udev->actconfig)
                return -EFAULT;
-
        intf = usb_ifnum_to_if(udev, 0);
        if (intf)
                idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
 
        /* Search video endpoint */
        pdev->vmax_packet_size = -1;
-       for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+       for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
                if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
                        pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
                        break;
                }
+       }
 
        if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
-               Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+               PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
                return -ENFILE; /* Odd error, that should be noticeable */
        }
 
        /* Set alternate interface */
        ret = 0;
-       Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+       PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
        ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
        if (ret < 0)
                return ret;
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
                if (urb == NULL) {
-                       Err("Failed to allocate urb %d\n", i);
+                       PWC_ERROR("Failed to allocate urb %d\n", i);
                        ret = -ENOMEM;
                        break;
                }
                pdev->sbuf[i].urb = urb;
-               Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+               PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
        }
        if (ret) {
                /* De-allocate in reverse order */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
                if (ret)
-                       Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+                       PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
                else
-                       Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+                       PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
        }
 
        /* All is done... */
        pdev->iso_init = 1;
-       Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+       PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
        return 0;
 }
 
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
+void pwc_isoc_cleanup(struct pwc_device *pdev)
 {
        int i;
 
-       Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+       PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
        if (pdev == NULL)
                return;
+       if (pdev->iso_init == 0)
+               return;
 
        /* Unlinking ISOC buffers one by one */
        for (i = 0; i < MAX_ISO_BUFS; i++) {
                urb = pdev->sbuf[i].urb;
                if (urb != 0) {
                        if (pdev->iso_init) {
-                               Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+                               PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
                                usb_kill_urb(urb);
                        }
-                       Trace(TRACE_MEMORY, "Freeing URB\n");
+                       PWC_DEBUG_MEMORY("Freeing URB\n");
                        usb_free_urb(urb);
                        pdev->sbuf[i].urb = NULL;
                }
           is signalled by EPIPE)
         */
        if (pdev->error_status && pdev->error_status != EPIPE) {
-               Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+               PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
                usb_set_interface(pdev->udev, 0, 0);
        }
 
        pdev->iso_init = 0;
-       Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+       PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
 }
 
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
        /* Try to set video mode... */
        start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
        if (ret) {
-               Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+               PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
                /* That failed... restore old mode (we know that worked) */
                start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
                if (start) {
-                       Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+                       PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
                }
        }
        if (start == 0)
        {
                if (pwc_isoc_init(pdev) < 0)
                {
-                       Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+                       PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
                        ret = -EAGAIN; /* let's try again, who knows if it works a second time */
                }
        }
        return ret; /* Return original error code */
 }
 
+/*********
+ * sysfs
+ *********/
+static struct pwc_device *cd_to_pwc(struct class_device *cd)
+{
+       struct video_device *vdev = to_video_device(cd);
+       return video_get_drvdata(vdev);
+}
+
+static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+{
+       struct pwc_device *pdev = cd_to_pwc(class_dev);
+       return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
+}
+
+static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
+                        size_t count)
+{
+       struct pwc_device *pdev = cd_to_pwc(class_dev);
+       int pan, tilt;
+       int ret = -EINVAL;
+
+       if (strncmp(buf, "reset", 5) == 0)
+               ret = pwc_mpt_reset(pdev, 0x3);
+
+       else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
+               ret = pwc_mpt_set_angle(pdev, pan, tilt);
+
+       if (ret < 0)
+               return ret;
+       return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+                        store_pan_tilt);
+
+static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+{
+       struct pwc_device *pdev = cd_to_pwc(class_dev);
+       int status = pdev->snapshot_button_status;
+       pdev->snapshot_button_status = 0;
+       return sprintf(buf, "%d\n", status);
+}
+
+static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+                        NULL);
+
+static void pwc_create_sysfs_files(struct video_device *vdev)
+{
+       struct pwc_device *pdev = video_get_drvdata(vdev);
+       if (pdev->features & FEATURE_MOTOR_PANTILT)
+               video_device_create_file(vdev, &class_device_attr_pan_tilt);
+       video_device_create_file(vdev, &class_device_attr_button);
+}
+
+static void pwc_remove_sysfs_files(struct video_device *vdev)
+{
+       struct pwc_device *pdev = video_get_drvdata(vdev);
+       if (pdev->features & FEATURE_MOTOR_PANTILT)
+               video_device_remove_file(vdev, &class_device_attr_pan_tilt);
+       video_device_remove_file(vdev, &class_device_attr_button);
+}
+
+#if CONFIG_PWC_DEBUG
+static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
+{
+       switch(sensor_type) {
+               case 0x00:
+                       return "Hyundai CMOS sensor";
+               case 0x20:
+                       return "Sony CCD sensor + TDA8787";
+               case 0x2E:
+                       return "Sony CCD sensor + Exas 98L59";
+               case 0x2F:
+                       return "Sony CCD sensor + ADI 9804";
+               case 0x30:
+                       return "Sharp CCD sensor + TDA8787";
+               case 0x3E:
+                       return "Sharp CCD sensor + Exas 98L59";
+               case 0x3F:
+                       return "Sharp CCD sensor + ADI 9804";
+               case 0x40:
+                       return "UPA 1021 sensor";
+               case 0x100:
+                       return "VGA sensor";
+               case 0x101:
+                       return "PAL MR sensor";
+               default:
+                       return "unknown type of sensor";
+       }
+}
+#endif
 
 /***************************************************************************/
 /* Video4Linux functions */
 
 static int pwc_video_open(struct inode *inode, struct file *file)
 {
-       int i;
+       int i, ret;
        struct video_device *vdev = video_devdata(file);
        struct pwc_device *pdev;
 
-       Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+       PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
 
        pdev = (struct pwc_device *)vdev->priv;
        if (pdev == NULL)
                BUG();
-       if (pdev->vopen)
+       if (pdev->vopen) {
+               PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
                return -EBUSY;
+       }
 
        down(&pdev->modlock);
        if (!pdev->usb_init) {
-               Trace(TRACE_OPEN, "Doing first time initialization.\n");
+               PWC_DEBUG_OPEN("Doing first time initialization.\n");
                pdev->usb_init = 1;
 
-               if (pwc_trace & TRACE_OPEN)
+               /* Query sensor type */
+               ret = pwc_get_cmos_sensor(pdev, &i);
+               if (ret >= 0)
                {
-                       /* Query sensor type */
-                       const char *sensor_type = NULL;
-                       int ret;
-
-                       ret = pwc_get_cmos_sensor(pdev, &i);
-                       if (ret >= 0)
-                       {
-                               switch(i) {
-                               case 0x00:  sensor_type = "Hyundai CMOS sensor"; break;
-                               case 0x20:  sensor_type = "Sony CCD sensor + TDA8787"; break;
-                               case 0x2E:  sensor_type = "Sony CCD sensor + Exas 98L59"; break;
-                               case 0x2F:  sensor_type = "Sony CCD sensor + ADI 9804"; break;
-                               case 0x30:  sensor_type = "Sharp CCD sensor + TDA8787"; break;
-                               case 0x3E:  sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
-                               case 0x3F:  sensor_type = "Sharp CCD sensor + ADI 9804"; break;
-                               case 0x40:  sensor_type = "UPA 1021 sensor"; break;
-                               case 0x100: sensor_type = "VGA sensor"; break;
-                               case 0x101: sensor_type = "PAL MR sensor"; break;
-                               default:    sensor_type = "unknown type of sensor"; break;
-                               }
-                       }
-                       if (sensor_type != NULL)
-                               Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+                       PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+                                       pdev->vdev->name,
+                                       pwc_sensor_type_to_string(i), i);
                }
        }
 
        if (power_save) {
                i = pwc_camera_power(pdev, 1);
                if (i < 0)
-                       Info("Failed to restore power to the camera! (%d)\n", i);
+                       PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
        }
        /* Set LED on/off time */
        if (pwc_set_leds(pdev, led_on, led_off) < 0)
-               Info("Failed to set LED on/off time.\n");
+               PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
 
        pwc_construct(pdev); /* set min/max sizes correct */
 
        /* So far, so good. Allocate memory. */
        i = pwc_allocate_buffers(pdev);
        if (i < 0) {
-               Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+               PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
+               pwc_free_buffers(pdev);
                up(&pdev->modlock);
                return i;
        }
 
        /* Reset buffers & parameters */
        pwc_reset_buffers(pdev);
-       for (i = 0; i < default_mbufs; i++)
+       for (i = 0; i < pwc_mbufs; i++)
                pdev->image_used[i] = 0;
        pdev->vframe_count = 0;
        pdev->vframes_dumped = 0;
        pdev->vframes_error = 0;
        pdev->visoc_errors = 0;
        pdev->error_status = 0;
-#if PWC_DEBUG
-       pdev->sequence = 0;
-#endif
        pwc_construct(pdev); /* set min/max sizes correct */
 
        /* Set some defaults */
         */
        i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
        if (i)  {
-               Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
-               if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+               unsigned int default_resolution;
+               PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
+               if (pdev->type>= 730)
+                       default_resolution = PSZ_QSIF;
                else
-                       i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+                       default_resolution = PSZ_QCIF;
+
+               i = pwc_set_video_mode(pdev,
+                                      pwc_image_sizes[default_resolution].x,
+                                      pwc_image_sizes[default_resolution].y,
+                                      10,
+                                      pdev->vcompression,
+                                      0);
        }
        if (i) {
-               Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+               PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
+               pwc_free_buffers(pdev);
                up(&pdev->modlock);
                return i;
        }
 
        i = pwc_isoc_init(pdev);
        if (i) {
-               Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+               PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
+               pwc_isoc_cleanup(pdev);
+               pwc_free_buffers(pdev);
                up(&pdev->modlock);
                return i;
        }
 
+       /* Initialize the webcam to sane value */
+       pwc_set_brightness(pdev, 0x7fff);
+       pwc_set_agc(pdev, 1, 0);
+
        pdev->vopen++;
        file->private_data = vdev;
        up(&pdev->modlock);
-       Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+       PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
        return 0;
 }
 
        struct pwc_device *pdev;
        int i;
 
-       Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+       PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
        pdev = (struct pwc_device *)vdev->priv;
        if (pdev->vopen == 0)
-               Info("video_close() called on closed device?\n");
+               PWC_DEBUG_MODULE("video_close() called on closed device?\n");
 
        /* Dump statistics, but only if a reasonable amount of frames were
           processed (to prevent endless log-entries in case of snap-shot
           programs)
         */
        if (pdev->vframe_count > 20)
-               Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+               PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
 
-       switch (pdev->type)
-        {
-         case 675:
-         case 680:
-         case 690:
-         case 720:
-         case 730:
-         case 740:
-         case 750:
-/*         pwc_dec23_exit();   *//* Timon & Kiara */
-           break;
-         case 645:
-         case 646:
-/*         pwc_dec1_exit(); */
-           break;
-        }
+       if (DEVICE_USE_CODEC1(pdev->type))
+           pwc_dec1_exit();
+       else
+           pwc_dec23_exit();
 
        pwc_isoc_cleanup(pdev);
        pwc_free_buffers(pdev);
        if (pdev->error_status != EPIPE) {
                /* Turn LEDs off */
                if (pwc_set_leds(pdev, 0, 0) < 0)
-                       Info("Failed to set LED on/off time.\n");
+                       PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
                if (power_save) {
                        i = pwc_camera_power(pdev, 0);
                        if (i < 0)
-                               Err("Failed to power down camera (%d)\n", i);
+                               PWC_ERROR("Failed to power down camera (%d)\n", i);
                }
        }
-       pdev->vopen = 0;
-       Trace(TRACE_OPEN, "<< video_close()\n");
+       pdev->vopen--;
+       PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
        return 0;
 }
 
                device is tricky anyhow.
  */
 
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
                          size_t count, loff_t *ppos)
 {
        struct video_device *vdev = file->private_data;
        int noblock = file->f_flags & O_NONBLOCK;
        DECLARE_WAITQUEUE(wait, current);
        int bytes_to_read;
+       void *image_buffer_addr;
 
-       Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+       PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
+                       vdev, buf, count);
        if (vdev == NULL)
                return -EFAULT;
        pdev = vdev->priv;
                        return -EFAULT;
        }
 
-       Trace(TRACE_READ, "Copying data to user space.\n");
+       PWC_DEBUG_READ("Copying data to user space.\n");
        if (pdev->vpalette == VIDEO_PALETTE_RAW)
-               bytes_to_read = pdev->frame_size;
+               bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
        else
                bytes_to_read = pdev->view.size;
 
        /* copy bytes to user space; we allow for partial reads */
        if (count + pdev->image_read_pos > bytes_to_read)
                count = bytes_to_read - pdev->image_read_pos;
-       if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+       image_buffer_addr = pdev->image_data;
+       image_buffer_addr += pdev->images[pdev->fill_image].offset;
+       image_buffer_addr += pdev->image_read_pos;
+       if (copy_to_user(buf, image_buffer_addr, count))
                return -EFAULT;
        pdev->image_read_pos += count;
        if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
        return 0;
 }
 
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
-                             unsigned int cmd, void *arg)
-{
-       struct video_device *vdev = file->private_data;
-       struct pwc_device *pdev;
-       DECLARE_WAITQUEUE(wait, current);
-
-       if (vdev == NULL)
-               return -EFAULT;
-       pdev = vdev->priv;
-       if (pdev == NULL)
-               return -EFAULT;
-
-       switch (cmd) {
-               /* Query cabapilities */
-               case VIDIOCGCAP:
-               {
-                       struct video_capability *caps = arg;
-
-                       strcpy(caps->name, vdev->name);
-                       caps->type = VID_TYPE_CAPTURE;
-                       caps->channels = 1;
-                       caps->audios = 1;
-                       caps->minwidth  = pdev->view_min.x;
-                       caps->minheight = pdev->view_min.y;
-                       caps->maxwidth  = pdev->view_max.x;
-                       caps->maxheight = pdev->view_max.y;
-                       break;
-               }
-
-               /* Channel functions (simulate 1 channel) */
-               case VIDIOCGCHAN:
-               {
-                       struct video_channel *v = arg;
-
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       v->flags = 0;
-                       v->tuners = 0;
-                       v->type = VIDEO_TYPE_CAMERA;
-                       strcpy(v->name, "Webcam");
-                       return 0;
-               }
-
-               case VIDIOCSCHAN:
-               {
-                       /* The spec says the argument is an integer, but
-                          the bttv driver uses a video_channel arg, which
-                          makes sense becasue it also has the norm flag.
-                        */
-                       struct video_channel *v = arg;
-                       if (v->channel != 0)
-                               return -EINVAL;
-                       return 0;
-               }
-
-
-               /* Picture functions; contrast etc. */
-               case VIDIOCGPICT:
-               {
-                       struct video_picture *p = arg;
-                       int val;
-
-                       val = pwc_get_brightness(pdev);
-                       if (val >= 0)
-                               p->brightness = val;
-                       else
-                               p->brightness = 0xffff;
-                       val = pwc_get_contrast(pdev);
-                       if (val >= 0)
-                               p->contrast = val;
-                       else
-                               p->contrast = 0xffff;
-                       /* Gamma, Whiteness, what's the difference? :) */
-                       val = pwc_get_gamma(pdev);
-                       if (val >= 0)
-                               p->whiteness = val;
-                       else
-                               p->whiteness = 0xffff;
-                       val = pwc_get_saturation(pdev);
-                       if (val >= 0)
-                               p->colour = val;
-                       else
-                               p->colour = 0xffff;
-                       p->depth = 24;
-                       p->palette = pdev->vpalette;
-                       p->hue = 0xFFFF; /* N/A */
-                       break;
-               }
-
-               case VIDIOCSPICT:
-               {
-                       struct video_picture *p = arg;
-                       /*
-                        *      FIXME:  Suppose we are mid read
-                               ANSWER: No problem: the firmware of the camera
-                                       can handle brightness/contrast/etc
-                                       changes at _any_ time, and the palette
-                                       is used exactly once in the uncompress
-                                       routine.
-                        */
-                       pwc_set_brightness(pdev, p->brightness);
-                       pwc_set_contrast(pdev, p->contrast);
-                       pwc_set_gamma(pdev, p->whiteness);
-                       pwc_set_saturation(pdev, p->colour);
-                       if (p->palette && p->palette != pdev->vpalette) {
-                               switch (p->palette) {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               pdev->vpalette = p->palette;
-                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-                       break;
-               }
-
-               /* Window/size parameters */
-               case VIDIOCGWIN:
-               {
-                       struct video_window *vw = arg;
-
-                       vw->x = 0;
-                       vw->y = 0;
-                       vw->width = pdev->view.x;
-                       vw->height = pdev->view.y;
-                       vw->chromakey = 0;
-                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
-                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
-                       break;
-               }
-
-               case VIDIOCSWIN:
-               {
-                       struct video_window *vw = arg;
-                       int fps, snapshot, ret;
-
-                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
-                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
-                       if (fps == 0)
-                               fps = pdev->vframes;
-                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
-                               return 0;
-                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
-                       if (ret)
-                               return ret;
-                       break;
-               }
-
-               /* We don't have overlay support (yet) */
-               case VIDIOCGFBUF:
-               {
-                       struct video_buffer *vb = arg;
-
-                       memset(vb,0,sizeof(*vb));
-                       break;
-               }
-
-               /* mmap() functions */
-               case VIDIOCGMBUF:
-               {
-                       /* Tell the user program how much memory is needed for a mmap() */
-                       struct video_mbuf *vm = arg;
-                       int i;
-
-                       memset(vm, 0, sizeof(*vm));
-                       vm->size = default_mbufs * pdev->len_per_image;
-                       vm->frames = default_mbufs; /* double buffering should be enough for most applications */
-                       for (i = 0; i < default_mbufs; i++)
-                               vm->offsets[i] = i * pdev->len_per_image;
-                       break;
-               }
-
-               case VIDIOCMCAPTURE:
-               {
-                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
-                       struct video_mmap *vm = arg;
-
-                       Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
-                       if (vm->frame < 0 || vm->frame >= default_mbufs)
-                               return -EINVAL;
-
-                       /* xawtv is nasty. It probes the available palettes
-                          by setting a very small image size and trying
-                          various palettes... The driver doesn't support
-                          such small images, so I'm working around it.
-                        */
-                       if (vm->format)
-                       {
-                               switch (vm->format)
-                               {
-                                       case VIDEO_PALETTE_YUV420P:
-                                       case VIDEO_PALETTE_RAW:
-                                               break;
-                                       default:
-                                               return -EINVAL;
-                                               break;
-                               }
-                       }
-
-                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
-                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
-                               int ret;
-
-                               Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
-                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
-                               if (ret)
-                                       return ret;
-                       } /* ... size mismatch */
-
-                       /* FIXME: should we lock here? */
-                       if (pdev->image_used[vm->frame])
-                               return -EBUSY;  /* buffer wasn't available. Bummer */
-                       pdev->image_used[vm->frame] = 1;
-
-                       /* Okay, we're done here. In the SYNC call we wait until a
-                          frame comes available, then expand image into the given
-                          buffer.
-                          In contrast to the CPiA cam the Philips cams deliver a
-                          constant stream, almost like a grabber card. Also,
-                          we have separate buffers for the rawdata and the image,
-                          meaning we can nearly always expand into the requested buffer.
-                        */
-                       Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
-                       break;
-               }
-
-               case VIDIOCSYNC:
-               {
-                       /* The doc says: "Whenever a buffer is used it should
-                          call VIDIOCSYNC to free this frame up and continue."
-
-                          The only odd thing about this whole procedure is
-                          that MCAPTURE flags the buffer as "in use", and
-                          SYNC immediately unmarks it, while it isn't
-                          after SYNC that you know that the buffer actually
-                          got filled! So you better not start a CAPTURE in
-                          the same frame immediately (use double buffering).
-                          This is not a problem for this cam, since it has
-                          extra intermediate buffers, but a hardware
-                          grabber card will then overwrite the buffer
-                          you're working on.
-                        */
-                       int *mbuf = arg;
-                       int ret;
-
-                       Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
-                       /* bounds check */
-                       if (*mbuf < 0 || *mbuf >= default_mbufs)
-                               return -EINVAL;
-                       /* check if this buffer was requested anyway */
-                       if (pdev->image_used[*mbuf] == 0)
-                               return -EINVAL;
-
-                       /* Add ourselves to the frame wait-queue.
-
-                          FIXME: needs auditing for safety.
-                          QUESTION: In what respect? I think that using the
-                                    frameq is safe now.
-                        */
-                       add_wait_queue(&pdev->frameq, &wait);
-                       while (pdev->full_frames == NULL) {
-                               if (pdev->error_status) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -pdev->error_status;
-                               }
-
-                               if (signal_pending(current)) {
-                                       remove_wait_queue(&pdev->frameq, &wait);
-                                       set_current_state(TASK_RUNNING);
-                                       return -ERESTARTSYS;
-                               }
-                               schedule();
-                               set_current_state(TASK_INTERRUPTIBLE);
-                       }
-                       remove_wait_queue(&pdev->frameq, &wait);
-                       set_current_state(TASK_RUNNING);
-
-                       /* The frame is ready. Expand in the image buffer
-                          requested by the user. I don't care if you
-                          mmap() 5 buffers and request data in this order:
-                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
-                          Grabber hardware may not be so forgiving.
-                        */
-                       Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
-                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
-                       /* Decompress, etc */
-                       ret = pwc_handle_frame(pdev);
-                       pdev->image_used[*mbuf] = 0;
-                       if (ret)
-                               return -EFAULT;
-                       break;
-               }
-
-               case VIDIOCGAUDIO:
-               {
-                       struct video_audio *v = arg;
-
-                       strcpy(v->name, "Microphone");
-                       v->audio = -1; /* unknown audio minor */
-                       v->flags = 0;
-                       v->mode = VIDEO_SOUND_MONO;
-                       v->volume = 0;
-                       v->bass = 0;
-                       v->treble = 0;
-                       v->balance = 0x8000;
-                       v->step = 1;
-                       break;
-               }
-
-               case VIDIOCSAUDIO:
-               {
-                       /* Dummy: nothing can be set */
-                       break;
-               }
-
-               case VIDIOCGUNIT:
-               {
-                       struct video_unit *vu = arg;
-
-                       vu->video = pdev->vdev->minor & 0x3F;
-                       vu->audio = -1; /* not known yet */
-                       vu->vbi = -1;
-                       vu->radio = -1;
-                       vu->teletext = -1;
-                       break;
-               }
-               default:
-                       return pwc_ioctl(pdev, cmd, arg);
-       } /* ..switch */
-       return 0;
-}
-
 static int pwc_video_ioctl(struct inode *inode, struct file *file,
                           unsigned int cmd, unsigned long arg)
 {
        return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
 }
 
-
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct video_device *vdev = file->private_data;
        struct pwc_device *pdev;
-       unsigned long start = vma->vm_start;
-       unsigned long size  = vma->vm_end-vma->vm_start;
-       unsigned long page, pos;
+       unsigned long start;
+       unsigned long size;
+       unsigned long page, pos = 0;
+       int index;
 
-       Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+       PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
        pdev = vdev->priv;
+       size = vma->vm_end - vma->vm_start;
+       start = vma->vm_start;
 
-       vma->vm_flags |= VM_IO;
+       /* Find the idx buffer for this mapping */
+       for (index = 0; index < pwc_mbufs; index++) {
+               pos = pdev->images[index].offset;
+               if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
+                       break;
+       }
+       if (index == MAX_IMAGES)
+               return -EINVAL;
+       if (index == 0) {
+               /*
+                * Special case for v4l1. In v4l1, we map only one big buffer,
+                * but in v4l2 each buffer is mapped
+                */
+               unsigned long total_size;
+               total_size = pwc_mbufs * pdev->len_per_image;
+               if (size != pdev->len_per_image && size != total_size) {
+                       PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
+                                  size, pdev->len_per_image, total_size);
+                       return -EINVAL;
+               }
+       } else if (size > pdev->len_per_image)
+               return -EINVAL;
+
+       vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
 
-       pos = (unsigned long)pdev->image_data;
+       pos += (unsigned long)pdev->image_data;
        while (size > 0) {
                page = vmalloc_to_pfn((void *)pos);
                if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
                        return -EAGAIN;
-
                start += PAGE_SIZE;
                pos += PAGE_SIZE;
                if (size > PAGE_SIZE)
                else
                        size = 0;
        }
-
        return 0;
 }
 
        int video_nr = -1; /* default: use next available device */
        char serial_number[30], *name;
 
+       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+       product_id = le16_to_cpu(udev->descriptor.idProduct);
+
        /* Check if we can handle this device */
-       Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
-               le16_to_cpu(udev->descriptor.idVendor),
-               le16_to_cpu(udev->descriptor.idProduct),
+       PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
+               vendor_id, product_id,
                intf->altsetting->desc.bInterfaceNumber);
 
        /* the interfaces are probed one by one. We are only interested in the
        if (intf->altsetting->desc.bInterfaceNumber > 0)
                return -ENODEV;
 
-       vendor_id = le16_to_cpu(udev->descriptor.idVendor);
-       product_id = le16_to_cpu(udev->descriptor.idProduct);
-
        if (vendor_id == 0x0471) {
                switch (product_id) {
                case 0x0302:
-                       Info("Philips PCA645VC USB webcam detected.\n");
+                       PWC_INFO("Philips PCA645VC USB webcam detected.\n");
                        name = "Philips 645 webcam";
                        type_id = 645;
                        break;
                case 0x0303:
-                       Info("Philips PCA646VC USB webcam detected.\n");
+                       PWC_INFO("Philips PCA646VC USB webcam detected.\n");
                        name = "Philips 646 webcam";
                        type_id = 646;
                        break;
                case 0x0304:
-                       Info("Askey VC010 type 2 USB webcam detected.\n");
+                       PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
                        name = "Askey VC010 webcam";
                        type_id = 646;
                        break;
                case 0x0307:
-                       Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
                        name = "Philips 675 webcam";
                        type_id = 675;
                        break;
                case 0x0308:
-                       Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
                        name = "Philips 680 webcam";
                        type_id = 680;
                        break;
                case 0x030C:
-                       Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
                        name = "Philips 690 webcam";
                        type_id = 690;
                        break;
                case 0x0310:
-                       Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
                        name = "Philips 730 webcam";
                        type_id = 730;
                        break;
                case 0x0311:
-                       Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
                        name = "Philips 740 webcam";
                        type_id = 740;
                        break;
                case 0x0312:
-                       Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
                        name = "Philips 750 webcam";
                        type_id = 750;
                        break;
                case 0x0313:
-                       Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+                       PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
                        name = "Philips 720K/40 webcam";
                        type_id = 720;
                        break;
+               case 0x0329:
+                       PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
+                       name = "Philips SPC 900NC webcam";
+                       type_id = 720;
+                       break;
                default:
                        return -ENODEV;
                        break;
        else if (vendor_id == 0x069A) {
                switch(product_id) {
                case 0x0001:
-                       Info("Askey VC010 type 1 USB webcam detected.\n");
+                       PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
                        name = "Askey VC010 webcam";
                        type_id = 645;
                        break;
        else if (vendor_id == 0x046d) {
                switch(product_id) {
                case 0x08b0:
-                       Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
                        name = "Logitech QuickCam Pro 3000";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08b1:
-                       Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
                        name = "Logitech QuickCam Notebook Pro";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08b2:
-                       Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
                        name = "Logitech QuickCam Pro 4000";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08b3:
-                       Info("Logitech QuickCam Zoom USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x08B4:
-                       Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
                        name = "Logitech QuickCam Zoom";
                        type_id = 740; /* CCD sensor */
+                       power_save = 1;
                        break;
                case 0x08b5:
-                       Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+                       PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
                        name = "Logitech QuickCam Orbit";
                        type_id = 740; /* CCD sensor */
                        features |= FEATURE_MOTOR_PANTILT;
                case 0x08b6:
                case 0x08b7:
                case 0x08b8:
-                       Info("Logitech QuickCam detected (reserved ID).\n");
+                       PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
                        name = "Logitech QuickCam (res.)";
                        type_id = 730; /* Assuming CMOS */
                        break;
                 */
                switch(product_id) {
                case 0x9000:
-                       Info("Samsung MPC-C10 USB webcam detected.\n");
+                       PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
                        name = "Samsung MPC-C10";
                        type_id = 675;
                        break;
                case 0x9001:
-                       Info("Samsung MPC-C30 USB webcam detected.\n");
+                       PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
                        name = "Samsung MPC-C30";
                        type_id = 675;
                        break;
+               case 0x9002:
+                       PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
+                       name = "Samsung MPC-C30";
+                       type_id = 740;
+                       break;
                default:
                        return -ENODEV;
                        break;
        else if (vendor_id == 0x041e) {
                switch(product_id) {
                case 0x400c:
-                       Info("Creative Labs Webcam 5 detected.\n");
+                       PWC_INFO("Creative Labs Webcam 5 detected.\n");
                        name = "Creative Labs Webcam 5";
                        type_id = 730;
                        break;
                case 0x4011:
-                       Info("Creative Labs Webcam Pro Ex detected.\n");
+                       PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
                        name = "Creative Labs Webcam Pro Ex";
                        type_id = 740;
                        break;
        else if (vendor_id == 0x04cc) {
                switch(product_id) {
                case 0x8116:
-                       Info("Sotec Afina Eye USB webcam detected.\n");
+                       PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
                        name = "Sotec Afina Eye";
                        type_id = 730;
                        break;
                switch(product_id) {
                case 0x8116:
                        /* This is essentially the same cam as the Sotec Afina Eye */
-                       Info("AME Co. Afina Eye USB webcam detected.\n");
+                       PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
                        name = "AME Co. Afina Eye";
                        type_id = 750;
                        break;
        else if (vendor_id == 0x0d81) {
                switch(product_id) {
                case 0x1900:
-                       Info("Visionite VCS-UC300 USB webcam detected.\n");
+                       PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
                        name = "Visionite VCS-UC300";
                        type_id = 740; /* CCD sensor */
                        break;
                case 0x1910:
-                       Info("Visionite VCS-UM100 USB webcam detected.\n");
+                       PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
                        name = "Visionite VCS-UM100";
                        type_id = 730; /* CMOS sensor */
                        break;
 
        memset(serial_number, 0, 30);
        usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
-       Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+       PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
 
        if (udev->descriptor.bNumConfigurations > 1)
-               Info("Warning: more than 1 configuration available.\n");
+               PWC_WARNING("Warning: more than 1 configuration available.\n");
 
        /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
        pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
        if (pdev == NULL) {
-               Err("Oops, could not allocate memory for pwc_device.\n");
+               PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
                return -ENOMEM;
        }
        pdev->type = type_id;
        pdev->vdev = video_device_alloc();
        if (pdev->vdev == 0)
        {
-               Err("Err, cannot allocate video_device struture. Failing probe.");
+               PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
                kfree(pdev);
                return -ENOMEM;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+       pdev->vdev->dev = &(udev->dev);
        strcpy(pdev->vdev->name, name);
        pdev->vdev->owner = THIS_MODULE;
        video_set_drvdata(pdev->vdev, pdev);
 
        pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
-       Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+       PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
 
        /* Now search device_hint[] table for a match, so we can hint a node number. */
        for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
                        if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
                                /* match! */
                                video_nr = device_hint[hint].device_node;
-                               Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
+                               PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
                                break;
                        }
                }
        pdev->vdev->release = video_device_release;
        i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
        if (i < 0) {
-               Err("Failed to register as video device (%d).\n", i);
+               PWC_ERROR("Failed to register as video device (%d).\n", i);
                video_device_release(pdev->vdev); /* Drip... drip... drip... */
                kfree(pdev); /* Oops, no memory leaks please */
                return -EIO;
        }
        else {
-               Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+               PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
        }
 
        /* occupy slot */
        if (hint < MAX_DEV_HINTS)
                device_hint[hint].pdev = pdev;
 
-       Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+       PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
        usb_set_intfdata (intf, pdev);
+       pwc_create_sysfs_files(pdev->vdev);
+
+       /* Set the leds off */
+       pwc_set_leds(pdev, 0, 0);
+       pwc_camera_power(pdev, 0);
+
        return 0;
 }
 
        pdev = usb_get_intfdata (intf);
        usb_set_intfdata (intf, NULL);
        if (pdev == NULL) {
-               Err("pwc_disconnect() Called without private pointer.\n");
+               PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
                goto disconnect_out;
        }
        if (pdev->udev == NULL) {
-               Err("pwc_disconnect() already called for %p\n", pdev);
+               PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
                goto disconnect_out;
        }
        if (pdev->udev != interface_to_usbdev(intf)) {
-               Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
-               goto disconnect_out;
-       }
-#ifdef PWC_MAGIC
-       if (pdev->magic != PWC_MAGIC) {
-               Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+               PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
                goto disconnect_out;
        }
-#endif
 
        /* We got unplugged; this is signalled by an EPIPE error code */
        if (pdev->vopen) {
-               Info("Disconnected while webcam is in use!\n");
+               PWC_INFO("Disconnected while webcam is in use!\n");
                pdev->error_status = EPIPE;
        }
 
        while (pdev->vopen)
                schedule();
        /* Device is now closed, so we can safely unregister it */
-       Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+       PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+       pwc_remove_sysfs_files(pdev->vdev);
        video_unregister_device(pdev->vdev);
 
        /* Free memory (don't set pdev to 0 just yet) */
  * Initialization code & module stuff
  */
 
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
+static char *size;
+static int fps;
+static int fbufs;
+static int mbufs;
 static int compression = -1;
 static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
+static int leds_nargs;
+static char *dev_hint[MAX_DEV_HINTS];
+static int dev_hint_nargs;
+
+module_param(size, charp, 0444);
+module_param(fps, int, 0444);
+module_param(fbufs, int, 0444);
+module_param(mbufs, int, 0444);
+#if CONFIG_PWC_DEBUG
+module_param_named(trace, pwc_trace, int, 0644);
+#endif
+module_param(power_save, int, 0444);
+module_param(compression, int, 0444);
+module_param_array(leds, int, &leds_nargs, 0444);
+module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
 
-module_param_string(size, size, sizeof(size), 0);
 MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
 MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
 MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
 MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
 MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
 MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
 MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
 MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
 MODULE_PARM_DESC(dev_hint, "Device node hints");
 
 MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
 MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("pwcx");
+MODULE_VERSION( PWC_VERSION );
 
 static int __init usb_pwc_init(void)
 {
        int i, sz;
        char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
 
-       Info("Philips webcam module version " PWC_VERSION " loaded.\n");
-       Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
-       Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
-       Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+       PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
+       PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+       PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+       PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
 
        if (fps) {
                if (fps < 4 || fps > 30) {
-                       Err("Framerate out of bounds (4-30).\n");
+                       PWC_ERROR("Framerate out of bounds (4-30).\n");
                        return -EINVAL;
                }
                default_fps = fps;
-               Info("Default framerate set to %d.\n", default_fps);
+               PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
        }
 
-       if (size[0]) {
+       if (size) {
                /* string; try matching with array */
                for (sz = 0; sz < PSZ_MAX; sz++) {
                        if (!strcmp(sizenames[sz], size)) { /* Found! */
                        }
                }
                if (sz == PSZ_MAX) {
-                       Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+                       PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
                        return -EINVAL;
                }
-               Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+               PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
        }
        if (mbufs) {
                if (mbufs < 1 || mbufs > MAX_IMAGES) {
-                       Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+                       PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
                        return -EINVAL;
                }
-               default_mbufs = mbufs;
-               Info("Number of image buffers set to %d.\n", default_mbufs);
+               pwc_mbufs = mbufs;
+               PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
        }
        if (fbufs) {
                if (fbufs < 2 || fbufs > MAX_FRAMES) {
-                       Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+                       PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
                        return -EINVAL;
                }
                default_fbufs = fbufs;
-               Info("Number of frame buffers set to %d.\n", default_fbufs);
+               PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
        }
-       if (trace >= 0) {
-               Info("Trace options: 0x%04x\n", trace);
-               pwc_trace = trace;
+#if CONFIG_PWC_DEBUG
+       if (pwc_trace >= 0) {
+               PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
        }
+#endif
        if (compression >= 0) {
                if (compression > 3) {
-                       Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+                       PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
                        return -EINVAL;
                }
                pwc_preferred_compression = compression;
-               Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+               PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
        }
        if (power_save)
-               Info("Enabling power save on open/close.\n");
+               PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
        if (leds[0] >= 0)
                led_on = leds[0];
        if (leds[1] >= 0)
                                dot++;
                        /* Few sanity checks */
                        if (*dot != '\0' && dot > colon) {
-                               Err("Malformed camera hint: the colon must be after the dot.\n");
+                               PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
                                return -EINVAL;
                        }
 
                        if (*colon == '\0') {
                                /* No colon */
                                if (*dot != '\0') {
-                                       Err("Malformed camera hint: no colon + device node given.\n");
+                                       PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
                                        return -EINVAL;
                                }
                                else {
                                        device_hint[i].serial_number[k] = '\0';
                                }
                        }
-#if PWC_DEBUG
-                       Debug("device_hint[%d]:\n", i);
-                       Debug("  type    : %d\n", device_hint[i].type);
-                       Debug("  serial# : %s\n", device_hint[i].serial_number);
-                       Debug("  node    : %d\n", device_hint[i].device_node);
-#endif
+                       PWC_TRACE("device_hint[%d]:\n", i);
+                       PWC_TRACE("  type    : %d\n", device_hint[i].type);
+                       PWC_TRACE("  serial# : %s\n", device_hint[i].serial_number);
+                       PWC_TRACE("  node    : %d\n", device_hint[i].device_node);
                }
                else
                        device_hint[i].type = 0; /* not filled */
        } /* ..for MAX_DEV_HINTS */
 
-       Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+       PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
        return usb_register(&pwc_driver);
 }
 
 static void __exit usb_pwc_exit(void)
 {
-       Trace(TRACE_MODULE, "Deregistering driver.\n");
+       PWC_DEBUG_MODULE("Deregistering driver.\n");
        usb_deregister(&pwc_driver);
-       Info("Philips webcam module removed.\n");
+       PWC_INFO("Philips webcam module removed.\n");
 }
 
 module_init(usb_pwc_init);
 module_exit(usb_pwc_exit);
 
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
 
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
    },
 };
 
+
+/*
+ * Rom table for kiara chips
+ *
+ * 32 roms tables (one for each resolution ?)
+ *  2 tables per roms (one for each passes) (Y, and U&V)
+ * 128 bytes per passes
+ */
+
+const unsigned int KiaraRomTable [8][2][16][8] =
+{
+ { /* version 0 */
+  { /* version 0, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009292,0x00009292,0x00009493,0x000124db},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x0000a493,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x000124db,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 0, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000001,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009292,
+    0x00009492,0x00009493,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000126dc,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 1 */
+  { /* version 1, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 1, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000049,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 2 */
+  { /* version 2, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x0000a49b},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 2, passes 1 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x0000a49b,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 3 */
+  { /* version 3, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 3, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 4 */
+  { /* version 4, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 4, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 5 */
+  { /* version 5, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 5, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x00009252,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 6 */
+  { /* version 6, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 6, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 7 */
+  { /* version 7, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 7, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ }
+};
+
 
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #ifndef PWC_KIARA_H
 #define PWC_KIARA_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Kiara_table_entry
 {
        unsigned char mode[12];         /* precomputed mode settings for cam */
 };
 
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const unsigned int KiaraRomTable[8][2][16][8];
 
 #endif
 
 
 /* Linux driver for Philips webcam
    Various miscellaneous functions and tables.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#include <linux/slab.h>
 
 #include "pwc.h"
 
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
 {
-       { 128,  96, 0 },
-       { 160, 120, 0 },
-       { 176, 144, 0 },
-       { 320, 240, 0 },
-       { 352, 288, 0 },
-       { 640, 480, 0 },
+       { 128,  96, 0 }, /* sqcif */
+       { 160, 120, 0 }, /* qsif */
+       { 176, 144, 0 }, /* qcif */
+       { 320, 240, 0 }, /* sif */
+       { 352, 288, 0 }, /* cif */
+       { 640, 480, 0 }, /* vga */
 };
 
 /* x,y -> PSZ_ */
        {
                if (width > pdev->abs_max.x || height > pdev->abs_max.y)
                {
-                       Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+                       PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
                        return -1;
                }
        }
        {
                if (width > pdev->view_max.x || height > pdev->view_max.y)
                {
-                       Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+                       PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
                        return -1;
                }
        }
 /* initialize variables depending on type and decompressor*/
 void pwc_construct(struct pwc_device *pdev)
 {
-       switch(pdev->type) {
-       case 645:
-       case 646:
+       if (DEVICE_USE_CODEC1(pdev->type)) {
+
                pdev->view_min.x = 128;
                pdev->view_min.y =  96;
                pdev->view_max.x = 352;
                pdev->vendpoint = 4;
                pdev->frame_header_size = 0;
                pdev->frame_trailer_size = 0;
-               break;
-       case 675:
-       case 680:
-       case 690:
+
+       } else if (DEVICE_USE_CODEC3(pdev->type)) {
+
+               pdev->view_min.x = 160;
+               pdev->view_min.y = 120;
+               pdev->view_max.x = 640;
+               pdev->view_max.y = 480;
+               pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+               pdev->abs_max.x = 640;
+               pdev->abs_max.y = 480;
+               pdev->vcinterface = 3;
+               pdev->vendpoint = 5;
+               pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+               pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+
+       } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
+
                pdev->view_min.x = 128;
                pdev->view_min.y =  96;
                /* Anthill bug #38: PWC always reports max size, even without PWCX */
                pdev->vendpoint = 4;
                pdev->frame_header_size = 0;
                pdev->frame_trailer_size = 0;
-               break;
-       case 720:
-       case 730:
-       case 740:
-       case 750:
-               pdev->view_min.x = 160;
-               pdev->view_min.y = 120;
-               pdev->view_max.x = 640;
-               pdev->view_max.y = 480;
-               pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
-               pdev->abs_max.x = 640;
-               pdev->abs_max.y = 480;
-               pdev->vcinterface = 3;
-               pdev->vendpoint = 5;
-               pdev->frame_header_size = TOUCAM_HEADER_SIZE;
-               pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
-               break;
        }
-       Debug("type = %d\n",pdev->type);
        pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
        pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
        pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
        /* length of image, in YUV format; always allocate enough memory. */
-       pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+       pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
 }
 
 
 
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
    },
 };
 
+/*
+ * 16 versions:
+ *   2 tables  (one for Y, and one for U&V)
+ *   16 levels of details per tables
+ *   8 blocs
+ */
+
+const unsigned int TimonRomTable [16][2][16][8] =
+{
+ { /* version 0 */
+  { /* version 0, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000001,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000001,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 0, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000001,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000001,
+    0x00000001,0x00000009,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000009,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000009,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 1 */
+  { /* version 1, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000001,0x00000001,
+    0x00000001,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000009,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 1, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000001,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000001,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000049,0x00000249,0x00000009,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00000049,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 2 */
+  { /* version 2, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000009,0x00000009,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 2, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000009,
+    0x00000049,0x00000009,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000049,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x0000024a,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009292,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009292,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 3 */
+  { /* version 3, passes 0 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000001},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000049,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00009252,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009292,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 3, passes 1 */
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000},
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000001,0x00000000},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00000049,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00000001},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x00009292,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009252,0x00009292,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009292,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 4 */
+  { /* version 4, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x0000a49b},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 4, passes 1 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x0000a49b,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 5 */
+  { /* version 5, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x0000124a,0x00001252,0x00009292},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x0000124a,0x00009292,0x00009292,0x00009493},
+   {0x00000000,0x00000000,0x00000249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 5, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x000124db,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009493,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 6 */
+  { /* version 6, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x0000124a,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 6, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 7 */
+  { /* version 7, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x000124db,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x0002496e},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0002496d,0x00025bb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 7, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001b724,0x0001b925,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 8 */
+  { /* version 8, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009292,0x00009493,0x0000a49b,0x000124db},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x000124db,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000136e4},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000136e4,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x00024b76,0x00024b77},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x00024b76,0x00025bbf},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0001c92d,0x00024b76,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 8, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0002496d,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 9 */
+  { /* version 9, passes 0 */
+   {0x00000000,0x00000000,0x00000049,0x00000049,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000249,0x00000249,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x0000124a,0x00009252,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009252,0x00009493,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 9, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000049,
+    0x00000009,0x00000009,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000009,0x00000009},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000124db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 10 */
+  { /* version 10, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00000249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x00009493,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x000124db,0x000124db,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0001249b,0x000126dc,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000126dc,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009252,0x0000a49b,
+    0x000124db,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000126dc,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x000136e4,0x0002496d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 10, passes 1 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000049,0x00000049,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00000249,0x00000049,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x00009252,0x0000024a,0x00000049},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009493,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009252,
+    0x00009492,0x00009493,0x00001252,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009493,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009493,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009493,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009252,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 11 */
+  { /* version 11, passes 0 */
+   {0x00000000,0x00000000,0x00000249,0x00000249,
+    0x00000249,0x00000249,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 11, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00000249,
+    0x00000249,0x00000249,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009252,0x00009252,0x0000024a,0x0000024a},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x0000a49b,0x00009292,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 12 */
+  { /* version 12, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000126db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 12, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x00001249,0x00009292,
+    0x00009492,0x00009252,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000124db,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000126db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 13 */
+  { /* version 13, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x00009252,0x00009292,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x0000a49b,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 13, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x00009492,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0000a49b,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000124db,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000124db,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000136db,
+    0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 14 */
+  { /* version 14, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x0000924a,
+    0x00009292,0x00009493,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00001249,0x0000a49b,
+    0x0000a493,0x000124db,0x000126dc,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x000136e4,0x0001b725,0x000124db},
+   {0x00000000,0x00000000,0x00009292,0x000124db,
+    0x000126dc,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001c92d,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0002496d,0x00024b76,0x00024b77},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 14, passes 1 */
+   {0x00000000,0x00000000,0x00001249,0x00001249,
+    0x0000124a,0x0000124a,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x00009493,
+    0x0000a493,0x00009292,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x0000a49b,0x00001252,0x00001252},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000136e4,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x000136e4,0x00009493,0x00009292},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001b724,0x000136e4,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b724,0x000136e4,0x000126dc,0x000124db},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ },
+ { /* version 15 */
+  { /* version 15, passes 0 */
+   {0x00000000,0x00000000,0x00001249,0x00009493,
+    0x0000a493,0x0000a49b,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0001249b,0x000126dc,0x000136e4,0x000124db},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x000136e4,0x0001b925,0x0001c96e,0x000136e4},
+   {0x00000000,0x00000000,0x00009492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000124db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+   {0x00000000,0x00000000,0x0000a492,0x000126db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001b924,0x0002496d,0x00024b76,0x0002496e},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x00024b6d,0x00025bb6,0x00024b77},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  },
+  { /* version 15, passes 1 */
+   {0x00000000,0x00000000,0x0000924a,0x0000924a,
+    0x00009292,0x00009292,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+    0x0000a493,0x000124db,0x00009292,0x00009292},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000124db,0x0001b724,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000126dc,0x0001b724,0x00009493,0x00009493},
+   {0x00000000,0x00000000,0x0000924a,0x000124db,
+    0x000136e4,0x0001b724,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009292,0x000136db,
+    0x0001b724,0x0001b724,0x0000a49b,0x0000a49b},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001c924,0x0001b724,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x00009492,0x000136db,
+    0x0001c924,0x0001b724,0x000124db,0x000124db},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b724,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000126dc,0x000126dc},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+   {0x00000000,0x00000000,0x0000a492,0x000136db,
+    0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00012492,0x000136db,
+    0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+   {0x00000000,0x00000000,0x00012492,0x0001b6db,
+    0x00024924,0x0002496d,0x0001b92d,0x0001b925},
+   {0x00000000,0x00000000,0x00000000,0x00000000,
+    0x00000000,0x00000000,0x00000000,0x00000000}
+  }
+ }
+};
 
 /* Linux driver for Philips webcam
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #ifndef PWC_TIMON_H
 #define PWC_TIMON_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Timon_table_entry
 {
        unsigned char mode[13];         /* precomputed mode settings for cam */
 };
 
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const unsigned int TimonRomTable [16][2][16][8];
 
 
 #endif
 
 /* Linux driver for Philips webcam
    Decompression frontend.
    (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   vim: set ts=8:
 */
 
 #include <asm/current.h>
 
 #include "pwc.h"
 #include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 int pwc_decompress(struct pwc_device *pdev)
 {
 
        if (pdev == NULL)
                return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
-       if (pdev->magic != PWC_MAGIC) {
-               Err("pwc_decompress(): magic failed.\n");
-               return -EFAULT;
-       }
-#endif
 
        fbuf = pdev->read_frame;
        if (fbuf == NULL)
                return -EFAULT;
-       image = pdev->image_ptr[pdev->fill_image];
-       if (!image)
-               return -EFAULT;
+       image  = pdev->image_data;
+       image += pdev->images[pdev->fill_image].offset;
 
        yuv = fbuf->data + pdev->frame_header_size;  /* Skip header */
 
        /* Raw format; that's easy... */
        if (pdev->vpalette == VIDEO_PALETTE_RAW)
        {
-               memcpy(image, yuv, pdev->frame_size);
+               struct pwc_raw_frame *raw_frame = image;
+               raw_frame->type = cpu_to_le16(pdev->type);
+               raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength);
+                       /* cmd_buf is always 4 bytes, but sometimes, only the
+                        * first 3 bytes is filled (Nala case). We can
+                        * determine this using the type of the webcam */
+               memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
+               memcpy(raw_frame+1, yuv, pdev->frame_size);
                return 0;
        }
 
        if (pdev->vbandlength == 0) {
-               /* Uncompressed mode. We copy the data into the output buffer,
-                  using the viewport size (which may be larger than the image
-                  size). Unfortunately we have to do a bit of byte stuffing
-                  to get the desired output format/size.
+               /* Uncompressed mode.
+                * We copy the data into the output buffer, using the viewport
+                * size (which may be larger than the image size).
+                * Unfortunately we have to do a bit of byte stuffing to get
+                * the desired output format/size.
+                *
+                * We do some byte shuffling here to go from the
+                * native format to YUV420P.
                 */
-                       /*
-                        * We do some byte shuffling here to go from the
-                        * native format to YUV420P.
-                        */
-                       src = (u16 *)yuv;
-                       n = pdev->view.x * pdev->view.y;
-
-                       /* offset in Y plane */
-                       stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
-                       dsty = (u16 *)(image + stride);
-
-                       /* offsets in U/V planes */
-                       stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
-                       dstu = (u16 *)(image + n +         stride);
-                       dstv = (u16 *)(image + n + n / 4 + stride);
-
-                       /* increment after each line */
-                       stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
-                       for (line = 0; line < pdev->image.y; line++) {
-                               for (col = 0; col < pdev->image.x; col += 4) {
-                                       *dsty++ = *src++;
-                                       *dsty++ = *src++;
-                                       if (line & 1)
-                                               *dstv++ = *src++;
-                                       else
-                                               *dstu++ = *src++;
-                               }
-                               dsty += stride;
+               src = (u16 *)yuv;
+               n = pdev->view.x * pdev->view.y;
+
+               /* offset in Y plane */
+               stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+               dsty = (u16 *)(image + stride);
+
+               /* offsets in U/V planes */
+               stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+               dstu = (u16 *)(image + n +         stride);
+               dstv = (u16 *)(image + n + n / 4 + stride);
+
+               /* increment after each line */
+               stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+               for (line = 0; line < pdev->image.y; line++) {
+                       for (col = 0; col < pdev->image.x; col += 4) {
+                               *dsty++ = *src++;
+                               *dsty++ = *src++;
                                if (line & 1)
-                                       dstv += (stride >> 1);
+                                       *dstv++ = *src++;
                                else
-                                       dstu += (stride >> 1);
+                                       *dstu++ = *src++;
                        }
+                       dsty += stride;
+                       if (line & 1)
+                               dstv += (stride >> 1);
+                       else
+                               dstu += (stride >> 1);
+               }
+
+               return 0;
        }
-       else {
-               /* Compressed; the decompressor routines will write the data
-                  in planar format immediately.
-                */
-               int flags;
-
-               flags = PWCX_FLAG_PLANAR;
-               if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
-                {
-                  printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
-                  flags |= PWCX_FLAG_BAYER;
-                  return -ENXIO; /* No such device or address: missing decompressor */
-                }
-
-#if 0
-               switch (pdev->type)
-                {
-                 case 675:
-                 case 680:
-                 case 690:
-                 case 720:
-                 case 730:
-                 case 740:
-                 case 750:
-                   pwc_dec23_decompress(&pdev->image, &pdev->view,
-                               &pdev->offset, yuv, image, flags,
-                               pdev->decompress_data, pdev->vbandlength);
-                   break;
-                 case 645:
-                 case 646:
-                   /* TODO & FIXME */
-                   return -ENXIO; /* Missing decompressor */
-                   break;
-                }
-#endif
+
+       /*
+        * Compressed;
+        * the decompressor routines will write the data in planar format
+        * immediately.
+        */
+       if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
+               PWC_ERROR("Mode Bayer is not supported for now\n");
+               /* flags |= PWCX_FLAG_BAYER; */
+               return -ENXIO; /* No such device or address: missing decompressor */
+       }
+
+       if (DEVICE_USE_CODEC1(pdev->type)) {
+
+               /* TODO & FIXME */
+               PWC_ERROR("This chipset is not supported for now\n");
+               return -ENXIO; /* No such device or address: missing decompressor */
+
+       } else {
+               pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
        }
        return 0;
 }
 
 
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
 
 /* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 
 #include <linux/config.h>
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 /* from pwc-dec.h */
 #define PWCX_FLAG_PLANAR        0x0001
 
--- /dev/null
+/* Linux driver for Philips webcam
+   USB and Video4Linux interface part.
+   (C) 1999-2004 Nemosoft Unv.
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+
+static struct v4l2_queryctrl pwc_controls[] = {
+       {
+           .id      = V4L2_CID_BRIGHTNESS,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Brightness",
+           .minimum = 0,
+           .maximum = 128,
+           .step    = 1,
+           .default_value = 64,
+       },
+       {
+           .id      = V4L2_CID_CONTRAST,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Contrast",
+           .minimum = 0,
+           .maximum = 64,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_SATURATION,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Saturation",
+           .minimum = -100,
+           .maximum = 100,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_GAMMA,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Gamma",
+           .minimum = 0,
+           .maximum = 32,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_RED_BALANCE,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Red Gain",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_BLUE_BALANCE,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Blue Gain",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_AUTO_WHITE_BALANCE,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Auto White Balance",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_EXPOSURE,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Shutter Speed (Exposure)",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 200,
+       },
+       {
+           .id      = V4L2_CID_AUTOGAIN,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Auto Gain Enabled",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 1,
+       },
+       {
+           .id      = V4L2_CID_GAIN,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Gain Level",
+           .minimum = 0,
+           .maximum = 256,
+           .step    = 1,
+           .default_value = 0,
+       },
+#if XAWTV_HAS_BEEN_FIXED
+       {
+           .id      = V4L2_CID_PRIVATE_SAVE_USER,
+           .type    = V4L2_CTRL_TYPE_BUTTON,
+           .name    = "Save User Settings",
+           .minimum = 0,
+           .maximum = 0,
+           .step    = 0,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_RESTORE_USER,
+           .type    = V4L2_CTRL_TYPE_BUTTON,
+           .name    = "Restore User Settings",
+           .minimum = 0,
+           .maximum = 0,
+           .step    = 0,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_RESTORE_FACTORY,
+           .type    = V4L2_CTRL_TYPE_BUTTON,
+           .name    = "Restore Factory Settings",
+           .minimum = 0,
+           .maximum = 0,
+           .step    = 0,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_COLOUR_MODE,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Colour mode",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_AUTOCONTOUR,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Auto contour",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_CONTOUR,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Contour",
+           .minimum = 0,
+           .maximum = 63,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_BACKLIGHT,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Backlight compensation",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+         .id      = V4L2_CID_PRIVATE_FLICKERLESS,
+           .type    = V4L2_CTRL_TYPE_BOOLEAN,
+           .name    = "Flickerless",
+           .minimum = 0,
+           .maximum = 1,
+           .step    = 1,
+           .default_value = 0,
+       },
+       {
+           .id      = V4L2_CID_PRIVATE_NOISE_REDUCTION,
+           .type    = V4L2_CTRL_TYPE_INTEGER,
+           .name    = "Noise reduction",
+           .minimum = 0,
+           .maximum = 3,
+           .step    = 1,
+           .default_value = 0,
+       },
+#endif
+};
+
+#if CONFIG_PWC_DEBUG
+/* In 2.6.16-rc1 v4l_printk_ioctl is not defined but exported */
+extern void v4l_printk_ioctl(unsigned int cmd);
+#endif
+
+static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+{
+       memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+       f->fmt.pix.width        = pdev->view.x;
+       f->fmt.pix.height       = pdev->view.y;
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
+       if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+               f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
+               f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
+               f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+       } else {
+               /* vbandlength contains 4 lines ...  */
+               f->fmt.pix.bytesperline = pdev->vbandlength/4;
+               f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
+               if (DEVICE_USE_CODEC1(pdev->type))
+                       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
+               else
+                       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
+       }
+       PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
+                       "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
+                       f->fmt.pix.width,
+                       f->fmt.pix.height,
+                       f->fmt.pix.bytesperline,
+                       f->fmt.pix.sizeimage,
+                       (f->fmt.pix.pixelformat)&255,
+                       (f->fmt.pix.pixelformat>>8)&255,
+                       (f->fmt.pix.pixelformat>>16)&255,
+                       (f->fmt.pix.pixelformat>>24)&255);
+}
+
+/* ioctl(VIDIOC_TRY_FMT) */
+static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+               return -EINVAL;
+       }
+
+       switch (f->fmt.pix.pixelformat) {
+               case V4L2_PIX_FMT_YUV420:
+                       break;
+               case V4L2_PIX_FMT_PWC1:
+                       if (DEVICE_USE_CODEC23(pdev->type)) {
+                               PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
+                               return -EINVAL;
+                       }
+                       break;
+               case V4L2_PIX_FMT_PWC2:
+                       if (DEVICE_USE_CODEC1(pdev->type)) {
+                               PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       PWC_DEBUG_IOCTL("Unsupported pixel format\n");
+                       return -EINVAL;
+
+       }
+
+       if (f->fmt.pix.width > pdev->view_max.x)
+               f->fmt.pix.width = pdev->view_max.x;
+       else if (f->fmt.pix.width < pdev->view_min.x)
+               f->fmt.pix.width = pdev->view_min.x;
+
+       if (f->fmt.pix.height > pdev->view_max.y)
+               f->fmt.pix.height = pdev->view_max.y;
+       else if (f->fmt.pix.height < pdev->view_min.y)
+               f->fmt.pix.height = pdev->view_min.y;
+
+       return 0;
+}
+
+/* ioctl(VIDIOC_SET_FMT) */
+static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+       int ret, fps, snapshot, compression, pixelformat;
+
+       ret = pwc_vidioc_try_fmt(pdev, f);
+       if (ret<0)
+               return ret;
+
+       pixelformat = f->fmt.pix.pixelformat;
+       compression = pdev->vcompression;
+       snapshot = 0;
+       fps = pdev->vframes;
+       if (f->fmt.pix.priv) {
+               compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
+               snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
+               fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+               if (fps == 0)
+                       fps = pdev->vframes;
+       }
+
+       if (pixelformat == V4L2_PIX_FMT_YUV420)
+               pdev->vpalette = VIDEO_PALETTE_YUV420P;
+       else
+               pdev->vpalette = VIDEO_PALETTE_RAW;
+
+       PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+                       "compression=%d snapshot=%d format=%c%c%c%c\n",
+                       f->fmt.pix.width, f->fmt.pix.height, fps,
+                       compression, snapshot,
+                       (pixelformat)&255,
+                       (pixelformat>>8)&255,
+                       (pixelformat>>16)&255,
+                       (pixelformat>>24)&255);
+
+       ret = pwc_try_video_mode(pdev,
+                                f->fmt.pix.width,
+                                f->fmt.pix.height,
+                                fps,
+                                compression,
+                                snapshot);
+
+       PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+
+       if (ret)
+               return ret;
+
+       pwc_vidioc_fill_fmt(pdev, f);
+
+       return 0;
+
+}
+
+int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, void *arg)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct pwc_device *pdev;
+       DECLARE_WAITQUEUE(wait, current);
+
+       if (vdev == NULL)
+               return -EFAULT;
+       pdev = vdev->priv;
+       if (pdev == NULL)
+               return -EFAULT;
+
+#if CONFIG_PWC_DEBUG
+       if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+               v4l_printk_ioctl(cmd);
+#endif
+
+
+       switch (cmd) {
+               /* Query cabapilities */
+               case VIDIOCGCAP:
+               {
+                       struct video_capability *caps = arg;
+
+                       strcpy(caps->name, vdev->name);
+                       caps->type = VID_TYPE_CAPTURE;
+                       caps->channels = 1;
+                       caps->audios = 1;
+                       caps->minwidth  = pdev->view_min.x;
+                       caps->minheight = pdev->view_min.y;
+                       caps->maxwidth  = pdev->view_max.x;
+                       caps->maxheight = pdev->view_max.y;
+                       break;
+               }
+
+               /* Channel functions (simulate 1 channel) */
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel *v = arg;
+
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       v->flags = 0;
+                       v->tuners = 0;
+                       v->type = VIDEO_TYPE_CAMERA;
+                       strcpy(v->name, "Webcam");
+                       return 0;
+               }
+
+               case VIDIOCSCHAN:
+               {
+                       /* The spec says the argument is an integer, but
+                          the bttv driver uses a video_channel arg, which
+                          makes sense becasue it also has the norm flag.
+                        */
+                       struct video_channel *v = arg;
+                       if (v->channel != 0)
+                               return -EINVAL;
+                       return 0;
+               }
+
+
+               /* Picture functions; contrast etc. */
+               case VIDIOCGPICT:
+               {
+                       struct video_picture *p = arg;
+                       int val;
+
+                       val = pwc_get_brightness(pdev);
+                       if (val >= 0)
+                               p->brightness = (val<<9);
+                       else
+                               p->brightness = 0xffff;
+                       val = pwc_get_contrast(pdev);
+                       if (val >= 0)
+                               p->contrast = (val<<10);
+                       else
+                               p->contrast = 0xffff;
+                       /* Gamma, Whiteness, what's the difference? :) */
+                       val = pwc_get_gamma(pdev);
+                       if (val >= 0)
+                               p->whiteness = (val<<11);
+                       else
+                               p->whiteness = 0xffff;
+                       if (pwc_get_saturation(pdev, &val)<0)
+                               p->colour = 0xffff;
+                       else
+                               p->colour = 32768 + val * 327;
+                       p->depth = 24;
+                       p->palette = pdev->vpalette;
+                       p->hue = 0xFFFF; /* N/A */
+                       break;
+               }
+
+               case VIDIOCSPICT:
+               {
+                       struct video_picture *p = arg;
+                       /*
+                        *      FIXME:  Suppose we are mid read
+                               ANSWER: No problem: the firmware of the camera
+                                       can handle brightness/contrast/etc
+                                       changes at _any_ time, and the palette
+                                       is used exactly once in the uncompress
+                                       routine.
+                        */
+                       pwc_set_brightness(pdev, p->brightness);
+                       pwc_set_contrast(pdev, p->contrast);
+                       pwc_set_gamma(pdev, p->whiteness);
+                       pwc_set_saturation(pdev, (p->colour-32768)/327);
+                       if (p->palette && p->palette != pdev->vpalette) {
+                               switch (p->palette) {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               pdev->vpalette = p->palette;
+                                               return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+                       break;
+               }
+
+               /* Window/size parameters */
+               case VIDIOCGWIN:
+               {
+                       struct video_window *vw = arg;
+
+                       vw->x = 0;
+                       vw->y = 0;
+                       vw->width = pdev->view.x;
+                       vw->height = pdev->view.y;
+                       vw->chromakey = 0;
+                       vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+                                  (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+                       break;
+               }
+
+               case VIDIOCSWIN:
+               {
+                       struct video_window *vw = arg;
+                       int fps, snapshot, ret;
+
+                       fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+                       snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+                       if (fps == 0)
+                               fps = pdev->vframes;
+                       if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+                               return 0;
+                       ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+
+               /* We don't have overlay support (yet) */
+               case VIDIOCGFBUF:
+               {
+                       struct video_buffer *vb = arg;
+
+                       memset(vb,0,sizeof(*vb));
+                       break;
+               }
+
+               /* mmap() functions */
+               case VIDIOCGMBUF:
+               {
+                       /* Tell the user program how much memory is needed for a mmap() */
+                       struct video_mbuf *vm = arg;
+                       int i;
+
+                       memset(vm, 0, sizeof(*vm));
+                       vm->size = pwc_mbufs * pdev->len_per_image;
+                       vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
+                       for (i = 0; i < pwc_mbufs; i++)
+                               vm->offsets[i] = i * pdev->len_per_image;
+                       break;
+               }
+
+               case VIDIOCMCAPTURE:
+               {
+                       /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+                       struct video_mmap *vm = arg;
+
+                       PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+                       if (vm->frame < 0 || vm->frame >= pwc_mbufs)
+                               return -EINVAL;
+
+                       /* xawtv is nasty. It probes the available palettes
+                          by setting a very small image size and trying
+                          various palettes... The driver doesn't support
+                          such small images, so I'm working around it.
+                        */
+                       if (vm->format)
+                       {
+                               switch (vm->format)
+                               {
+                                       case VIDEO_PALETTE_YUV420P:
+                                       case VIDEO_PALETTE_RAW:
+                                               break;
+                                       default:
+                                               return -EINVAL;
+                                               break;
+                               }
+                       }
+
+                       if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+                           (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+                               int ret;
+
+                               PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+                               ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+                               if (ret)
+                                       return ret;
+                       } /* ... size mismatch */
+
+                       /* FIXME: should we lock here? */
+                       if (pdev->image_used[vm->frame])
+                               return -EBUSY;  /* buffer wasn't available. Bummer */
+                       pdev->image_used[vm->frame] = 1;
+
+                       /* Okay, we're done here. In the SYNC call we wait until a
+                          frame comes available, then expand image into the given
+                          buffer.
+                          In contrast to the CPiA cam the Philips cams deliver a
+                          constant stream, almost like a grabber card. Also,
+                          we have separate buffers for the rawdata and the image,
+                          meaning we can nearly always expand into the requested buffer.
+                        */
+                       PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
+                       break;
+               }
+
+               case VIDIOCSYNC:
+               {
+                       /* The doc says: "Whenever a buffer is used it should
+                          call VIDIOCSYNC to free this frame up and continue."
+
+                          The only odd thing about this whole procedure is
+                          that MCAPTURE flags the buffer as "in use", and
+                          SYNC immediately unmarks it, while it isn't
+                          after SYNC that you know that the buffer actually
+                          got filled! So you better not start a CAPTURE in
+                          the same frame immediately (use double buffering).
+                          This is not a problem for this cam, since it has
+                          extra intermediate buffers, but a hardware
+                          grabber card will then overwrite the buffer
+                          you're working on.
+                        */
+                       int *mbuf = arg;
+                       int ret;
+
+                       PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
+
+                       /* bounds check */
+                       if (*mbuf < 0 || *mbuf >= pwc_mbufs)
+                               return -EINVAL;
+                       /* check if this buffer was requested anyway */
+                       if (pdev->image_used[*mbuf] == 0)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               /* Check for unplugged/etc. here */
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+
+                               if (signal_pending(current)) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -ERESTARTSYS;
+                               }
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+
+                       /* The frame is ready. Expand in the image buffer
+                          requested by the user. I don't care if you
+                          mmap() 5 buffers and request data in this order:
+                          buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+                          Grabber hardware may not be so forgiving.
+                        */
+                       PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
+                       pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+                       /* Decompress, etc */
+                       ret = pwc_handle_frame(pdev);
+                       pdev->image_used[*mbuf] = 0;
+                       if (ret)
+                               return -EFAULT;
+                       break;
+               }
+
+               case VIDIOCGAUDIO:
+               {
+                       struct video_audio *v = arg;
+
+                       strcpy(v->name, "Microphone");
+                       v->audio = -1; /* unknown audio minor */
+                       v->flags = 0;
+                       v->mode = VIDEO_SOUND_MONO;
+                       v->volume = 0;
+                       v->bass = 0;
+                       v->treble = 0;
+                       v->balance = 0x8000;
+                       v->step = 1;
+                       break;
+               }
+
+               case VIDIOCSAUDIO:
+               {
+                       /* Dummy: nothing can be set */
+                       break;
+               }
+
+               case VIDIOCGUNIT:
+               {
+                       struct video_unit *vu = arg;
+
+                       vu->video = pdev->vdev->minor & 0x3F;
+                       vu->audio = -1; /* not known yet */
+                       vu->vbi = -1;
+                       vu->radio = -1;
+                       vu->teletext = -1;
+                       break;
+               }
+
+               /* V4L2 Layer */
+               case VIDIOC_QUERYCAP:
+               {
+                   struct v4l2_capability *cap = arg;
+
+                   PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
+                                      "try to use the v4l2 layer\n");
+                   strcpy(cap->driver,PWC_NAME);
+                   strlcpy(cap->card, vdev->name, sizeof(cap->card));
+                   usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
+                   cap->version = PWC_VERSION_CODE;
+                   cap->capabilities =
+                       V4L2_CAP_VIDEO_CAPTURE  |
+                       V4L2_CAP_STREAMING      |
+                       V4L2_CAP_READWRITE;
+                   return 0;
+               }
+
+               case VIDIOC_ENUMINPUT:
+               {
+                   struct v4l2_input *i = arg;
+
+                   if ( i->index )     /* Only one INPUT is supported */
+                         return -EINVAL;
+
+                   memset(i, 0, sizeof(struct v4l2_input));
+                   strcpy(i->name, "usb");
+                   return 0;
+               }
+
+               case VIDIOC_G_INPUT:
+               {
+                   int *i = arg;
+                   *i = 0;     /* Only one INPUT is supported */
+                   return 0;
+               }
+               case VIDIOC_S_INPUT:
+               {
+                       int *i = arg;
+
+                       if ( *i ) {     /* Only one INPUT is supported */
+                               PWC_DEBUG_IOCTL("Only one input source is"\
+                                       " supported with this webcam.\n");
+                               return -EINVAL;
+                       }
+                       return 0;
+               }
+
+               /* TODO: */
+               case VIDIOC_QUERYCTRL:
+               {
+                       struct v4l2_queryctrl *c = arg;
+                       int i;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
+                       for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
+                               if (pwc_controls[i].id == c->id) {
+                                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+                                       memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
+                                       return 0;
+                               }
+                       }
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+
+                       return -EINVAL;
+               }
+               case VIDIOC_G_CTRL:
+               {
+                       struct v4l2_control *c = arg;
+                       int ret;
+
+                       switch (c->id)
+                       {
+                               case V4L2_CID_BRIGHTNESS:
+                                       c->value = pwc_get_brightness(pdev);
+                                       if (c->value<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_CONTRAST:
+                                       c->value = pwc_get_contrast(pdev);
+                                       if (c->value<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_SATURATION:
+                                       ret = pwc_get_saturation(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_GAMMA:
+                                       c->value = pwc_get_gamma(pdev);
+                                       if (c->value<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_RED_BALANCE:
+                                       ret = pwc_get_red_gain(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value >>= 8;
+                                       return 0;
+                               case V4L2_CID_BLUE_BALANCE:
+                                       ret = pwc_get_blue_gain(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value >>= 8;
+                                       return 0;
+                               case V4L2_CID_AUTO_WHITE_BALANCE:
+                                       ret = pwc_get_awb(pdev);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value = (ret == PWC_WB_MANUAL)?0:1;
+                                       return 0;
+                               case V4L2_CID_GAIN:
+                                       ret = pwc_get_agc(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value >>= 8;
+                                       return 0;
+                               case V4L2_CID_AUTOGAIN:
+                                       ret = pwc_get_agc(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       c->value = (c->value < 0)?1:0;
+                                       return 0;
+                               case V4L2_CID_EXPOSURE:
+                                       ret = pwc_get_shutter_speed(pdev, &c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_COLOUR_MODE:
+                                       ret = pwc_get_colour_mode(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_AUTOCONTOUR:
+                                       ret = pwc_get_contour(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       c->value=(c->value == -1?1:0);
+                                       return 0;
+                               case V4L2_CID_PRIVATE_CONTOUR:
+                                       ret = pwc_get_contour(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       c->value >>= 10;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_BACKLIGHT:
+                                       ret = pwc_get_backlight(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_FLICKERLESS:
+                                       ret = pwc_get_flicker(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       c->value=(c->value?1:0);
+                                       return 0;
+                               case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+                                       ret = pwc_get_dynamic_noise(pdev, &c->value);
+                                       if (ret < 0)
+                                               return -EINVAL;
+                                       return 0;
+
+                               case V4L2_CID_PRIVATE_SAVE_USER:
+                               case V4L2_CID_PRIVATE_RESTORE_USER:
+                               case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+                                       return -EINVAL;
+                       }
+                       return -EINVAL;
+               }
+               case VIDIOC_S_CTRL:
+               {
+                       struct v4l2_control *c = arg;
+                       int ret;
+
+                       switch (c->id)
+                       {
+                               case V4L2_CID_BRIGHTNESS:
+                                       c->value <<= 9;
+                                       ret = pwc_set_brightness(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_CONTRAST:
+                                       c->value <<= 10;
+                                       ret = pwc_set_contrast(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_SATURATION:
+                                       ret = pwc_set_saturation(pdev, c->value);
+                                       if (ret<0)
+                                         return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_GAMMA:
+                                       c->value <<= 11;
+                                       ret = pwc_set_gamma(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_RED_BALANCE:
+                                       c->value <<= 8;
+                                       ret = pwc_set_red_gain(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_BLUE_BALANCE:
+                                       c->value <<= 8;
+                                       ret = pwc_set_blue_gain(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_AUTO_WHITE_BALANCE:
+                                       c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
+                                       ret = pwc_set_awb(pdev, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_EXPOSURE:
+                                       c->value <<= 8;
+                                       ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_AUTOGAIN:
+                                       /* autogain off means nothing without a gain */
+                                       if (c->value == 0)
+                                               return 0;
+                                       ret = pwc_set_agc(pdev, c->value, 0);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_GAIN:
+                                       c->value <<= 8;
+                                       ret = pwc_set_agc(pdev, 0, c->value);
+                                       if (ret<0)
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_SAVE_USER:
+                                       if (pwc_save_user(pdev))
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_RESTORE_USER:
+                                       if (pwc_restore_user(pdev))
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+                                       if (pwc_restore_factory(pdev))
+                                               return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_COLOUR_MODE:
+                                       ret = pwc_set_colour_mode(pdev, c->value);
+                                       if (ret < 0)
+                                         return -EINVAL;
+                                       return 0;
+                               case V4L2_CID_PRIVATE_AUTOCONTOUR:
+                                 c->value=(c->value == 1)?-1:0;
+                                 ret = pwc_set_contour(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+                               case V4L2_CID_PRIVATE_CONTOUR:
+                                 c->value <<= 10;
+                                 ret = pwc_set_contour(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+                               case V4L2_CID_PRIVATE_BACKLIGHT:
+                                 ret = pwc_set_backlight(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+                               case V4L2_CID_PRIVATE_FLICKERLESS:
+                                 ret = pwc_set_flicker(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                               case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+                                 ret = pwc_set_dynamic_noise(pdev, c->value);
+                                 if (ret < 0)
+                                   return -EINVAL;
+                                 return 0;
+
+                       }
+                       return -EINVAL;
+               }
+
+               case VIDIOC_ENUM_FMT:
+               {
+                       struct v4l2_fmtdesc *f = arg;
+                       int index;
+
+                       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                             return -EINVAL;
+
+                       /* We only support two format: the raw format, and YUV */
+                       index = f->index;
+                       memset(f,0,sizeof(struct v4l2_fmtdesc));
+                       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       f->index = index;
+                       switch(index)
+                       {
+                               case 0:
+                                       /* RAW format */
+                                       f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
+                                       f->flags = V4L2_FMT_FLAG_COMPRESSED;
+                                       strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
+                                       break;
+                               case 1:
+                                       f->pixelformat = V4L2_PIX_FMT_YUV420;
+                                       strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
+                                       break;
+                               default:
+                                       return -EINVAL;
+                       }
+                       return 0;
+               }
+
+               case VIDIOC_G_FMT:
+               {
+                       struct v4l2_format *f = arg;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
+                       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                             return -EINVAL;
+
+                       pwc_vidioc_fill_fmt(pdev, f);
+
+                       return 0;
+               }
+
+               case VIDIOC_TRY_FMT:
+                       return pwc_vidioc_try_fmt(pdev, arg);
+
+               case VIDIOC_S_FMT:
+                       return pwc_vidioc_set_fmt(pdev, arg);
+
+               case VIDIOC_G_STD:
+               {
+                       v4l2_std_id *std = arg;
+                       *std = V4L2_STD_UNKNOWN;
+                       return 0;
+               }
+
+               case VIDIOC_S_STD:
+               {
+                       v4l2_std_id *std = arg;
+                       if (*std != V4L2_STD_UNKNOWN)
+                               return -EINVAL;
+                       return 0;
+               }
+
+               case VIDIOC_ENUMSTD:
+               {
+                       struct v4l2_standard *std = arg;
+                       if (std->index != 0)
+                               return -EINVAL;
+                       std->id = V4L2_STD_UNKNOWN;
+                       strncpy(std->name, "webcam", sizeof(std->name));
+                       return 0;
+               }
+
+               case VIDIOC_REQBUFS:
+               {
+                       struct v4l2_requestbuffers *rb = arg;
+                       int nbuffers;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
+                       if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+                       if (rb->memory != V4L2_MEMORY_MMAP)
+                               return -EINVAL;
+
+                       nbuffers = rb->count;
+                       if (nbuffers < 2)
+                               nbuffers = 2;
+                       else if (nbuffers > pwc_mbufs)
+                               nbuffers = pwc_mbufs;
+                       /* Force to use our # of buffers */
+                       rb->count = pwc_mbufs;
+                       return 0;
+               }
+
+               case VIDIOC_QUERYBUF:
+               {
+                       struct v4l2_buffer *buf = arg;
+                       int index;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+                               return -EINVAL;
+                       }
+                       if (buf->memory != V4L2_MEMORY_MMAP) {
+                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
+                               return -EINVAL;
+                       }
+                       index = buf->index;
+                       if (index < 0 || index >= pwc_mbufs) {
+                               PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+                               return -EINVAL;
+                       }
+
+                       memset(buf, 0, sizeof(struct v4l2_buffer));
+                       buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       buf->index = index;
+                       buf->m.offset = index * pdev->len_per_image;
+                       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+                               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+                       else
+                               buf->bytesused = pdev->view.size;
+                       buf->field = V4L2_FIELD_NONE;
+                       buf->memory = V4L2_MEMORY_MMAP;
+                       //buf->flags = V4L2_BUF_FLAG_MAPPED;
+                       buf->length = pdev->len_per_image;
+
+                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
+                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
+                       PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+
+                       return 0;
+               }
+
+               case VIDIOC_QBUF:
+               {
+                       struct v4l2_buffer *buf = arg;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+                       if (buf->memory != V4L2_MEMORY_MMAP)
+                               return -EINVAL;
+                       if (buf->index < 0 || buf->index >= pwc_mbufs)
+                               return -EINVAL;
+
+                       buf->flags |= V4L2_BUF_FLAG_QUEUED;
+                       buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+                       return 0;
+               }
+
+               case VIDIOC_DQBUF:
+               {
+                       struct v4l2_buffer *buf = arg;
+                       int ret;
+
+                       PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+
+                       if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                               return -EINVAL;
+
+                       /* Add ourselves to the frame wait-queue.
+
+                          FIXME: needs auditing for safety.
+                          QUESTION: In what respect? I think that using the
+                                    frameq is safe now.
+                        */
+                       add_wait_queue(&pdev->frameq, &wait);
+                       while (pdev->full_frames == NULL) {
+                               if (pdev->error_status) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -pdev->error_status;
+                               }
+
+                               if (signal_pending(current)) {
+                                       remove_wait_queue(&pdev->frameq, &wait);
+                                       set_current_state(TASK_RUNNING);
+                                       return -ERESTARTSYS;
+                               }
+                               schedule();
+                               set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       remove_wait_queue(&pdev->frameq, &wait);
+                       set_current_state(TASK_RUNNING);
+
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+                       /* Decompress data in pdev->images[pdev->fill_image] */
+                       ret = pwc_handle_frame(pdev);
+                       if (ret)
+                               return -EFAULT;
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+                       buf->index = pdev->fill_image;
+                       if (pdev->vpalette == VIDEO_PALETTE_RAW)
+                               buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+                       else
+                               buf->bytesused = pdev->view.size;
+                       buf->flags = V4L2_BUF_FLAG_MAPPED;
+                       buf->field = V4L2_FIELD_NONE;
+                       do_gettimeofday(&buf->timestamp);
+                       buf->sequence = 0;
+                       buf->memory = V4L2_MEMORY_MMAP;
+                       buf->m.offset = pdev->fill_image * pdev->len_per_image;
+                       buf->length = buf->bytesused;
+                       pwc_next_image(pdev);
+
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
+                       PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+                       return 0;
+
+               }
+
+               case VIDIOC_STREAMON:
+               {
+                       /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
+                       pwc_isoc_init(pdev);
+                       return 0;
+               }
+
+               case VIDIOC_STREAMOFF:
+               {
+                       pwc_isoc_cleanup(pdev);
+                       return 0;
+               }
+
+               default:
+                       return pwc_ioctl(pdev, cmd, arg);
+       } /* ..switch */
+       return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
 
 /* (C) 1999-2003 Nemosoft Unv.
-   (C) 2004      Luc Saillard (luc@saillard.org)
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
 
    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
    driver and thus may have bugs that are not present in the original version.
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/spinlock.h>
-#include <linux/videodev.h>
 #include <linux/wait.h>
 #include <linux/smp_lock.h>
+#include <linux/version.h>
 #include <asm/semaphore.h>
 #include <asm/errno.h>
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
 
 #include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
+#include <media/pwc-ioctl.h>
 
 /* Turn some debugging options on/off */
-#define PWC_DEBUG 0
+#ifndef CONFIG_PWC_DEBUG
+#define CONFIG_PWC_DEBUG 1
+#endif
+
+/* Version block */
+#define PWC_MAJOR      10
+#define PWC_MINOR      0
+#define PWC_EXTRAMINOR 12
+#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
+#define PWC_VERSION    "10.0.12"
+#define PWC_NAME       "pwc"
+#define PFX            PWC_NAME ": "
+
 
 /* Trace certain actions in the driver */
-#define TRACE_MODULE   0x0001
-#define TRACE_PROBE    0x0002
-#define TRACE_OPEN     0x0004
-#define TRACE_READ     0x0008
-#define TRACE_MEMORY   0x0010
-#define TRACE_FLOW     0x0020
-#define TRACE_SIZE     0x0040
-#define TRACE_PWCX     0x0080
-#define TRACE_SEQUENCE 0x1000
-
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...)  printk(KERN_INFO  PWC_NAME " " A)
-#define Err(A...)   printk(KERN_ERR   PWC_NAME " " A)
+#define PWC_DEBUG_LEVEL_MODULE (1<<0)
+#define PWC_DEBUG_LEVEL_PROBE  (1<<1)
+#define PWC_DEBUG_LEVEL_OPEN   (1<<2)
+#define PWC_DEBUG_LEVEL_READ   (1<<3)
+#define PWC_DEBUG_LEVEL_MEMORY (1<<4)
+#define PWC_DEBUG_LEVEL_FLOW   (1<<5)
+#define PWC_DEBUG_LEVEL_SIZE   (1<<6)
+#define PWC_DEBUG_LEVEL_IOCTL  (1<<7)
+#define PWC_DEBUG_LEVEL_TRACE  (1<<8)
+
+#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
+#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
+#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args)
+#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args)
+#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args)
+#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args)
+#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args)
+#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args)
+#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+
+#if CONFIG_PWC_DEBUG
+
+#define PWC_DEBUG_LEVEL        (PWC_DEBUG_LEVEL_MODULE)
+
+#define PWC_DEBUG(level, fmt, args...) do {\
+         if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+            printk(KERN_DEBUG PFX fmt, ##args); \
+         } while(0)
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+#else /* if ! CONFIG_PWC_DEBUG */
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) do { } while(0)
+#define PWC_DEBUG(level, fmt, args...) do { } while(0)
+
+#define pwc_trace 0
 
+#endif
 
 /* Defines for ToUCam cameras */
 #define TOUCAM_HEADER_SIZE             8
 #define TOUCAM_TRAILER_SIZE            4
 
 #define FEATURE_MOTOR_PANTILT          0x0001
-
-/* Version block */
-#define PWC_MAJOR      9
-#define PWC_MINOR      0
-#define PWC_VERSION    "9.0.2-unofficial"
-#define PWC_NAME       "pwc"
+#define FEATURE_CODEC1                 0x0002
+#define FEATURE_CODEC2                 0x0004
 
 /* Turn certain features on/off */
 #define PWC_INT_PIPE 0
 /* Absolute maximum number of buffers available for mmap() */
 #define MAX_IMAGES             10
 
+/* Some macros to quickly find the type of a webcam */
+#define DEVICE_USE_CODEC1(x) ((x)<675)
+#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700)
+#define DEVICE_USE_CODEC3(x) ((x)>=700)
+#define DEVICE_USE_CODEC23(x) ((x)>=675)
+
+
+#ifndef V4L2_PIX_FMT_PWC1
+#define V4L2_PIX_FMT_PWC1      v4l2_fourcc('P','W','C','1')
+#define V4L2_PIX_FMT_PWC2      v4l2_fourcc('P','W','C','2')
+#endif
+
 /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
 struct pwc_iso_buf
 {
    void *data;
    volatile int filled;                /* number of bytes filled */
    struct pwc_frame_buf *next; /* list */
-#if PWC_DEBUG
-   int sequence;               /* Sequence number */
-#endif
+};
+
+/* additionnal informations used when dealing image between kernel and userland */
+struct pwc_imgbuf
+{
+       unsigned long offset;   /* offset of this buffer in the big array of image_data */
+       int   vma_use_count;    /* count the number of time this memory is mapped */
 };
 
 struct pwc_device
 {
    struct video_device *vdev;
-#ifdef PWC_MAGIC
-   int magic;
-#endif
+
    /* Pointer to our usb_device */
    struct usb_device *udev;
 
    int frame_size;
    int frame_total_size; /* including header & trailer */
    int drop_frames;
-#if PWC_DEBUG
-   int sequence;                       /* Debugging aid */
-#endif
 
    /* 3: decompression */
-   struct pwc_decompressor *decompressor;      /* function block with decompression routines */
    void *decompress_data;              /* private data for decompression engine */
 
    /* 4: image */
    struct pwc_coord offset;            /* offset within the viewport */
 
    void *image_data;                   /* total buffer, which is subdivided into ... */
-   void *image_ptr[MAX_IMAGES];                /* ...several images... */
+   struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */
    int fill_image;                     /* ...which are rotated. */
    int len_per_image;                  /* length per image */
    int image_read_pos;                 /* In case we read data in pieces, keep track of were we are in the imagebuffer */
    struct pwc_mpt_range angle_range;
    int pan_angle;                      /* in degrees * 100 */
    int tilt_angle;                     /* absolute angle; 0,0 is home position */
+   int snapshot_button_status;         /* set to 1 when the user push the button, reset to 0 when this value is read */
 
    /*** Misc. data ***/
    wait_queue_head_t frameq;           /* When waiting for a frame to finish... */
 #endif
 };
 
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/* Global variable */
+/* Global variables */
+#if CONFIG_PWC_DEBUG
 extern int pwc_trace;
+#endif
+extern int pwc_preferred_compression;
+extern int pwc_mbufs;
 
 /** functions in pwc-if.c */
 int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+int pwc_handle_frame(struct pwc_device *pdev);
+void pwc_next_image(struct pwc_device *pdev);
+int pwc_isoc_init(struct pwc_device *pdev);
+void pwc_isoc_cleanup(struct pwc_device *pdev);
 
 /** Functions in pwc-misc.c */
 /* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
 
 int pwc_decode_size(struct pwc_device *pdev, int width, int height);
 void pwc_construct(struct pwc_device *pdev);
 /** Functions in pwc-ctrl.c */
 /* Request a certain video mode. Returns < 0 if not possible */
 extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+/* Calculate the number of bytes per image (not frame) */
+extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
+extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
 
 /* Various controls; should be obvious. Value 0..65535, or < 0 on error */
 extern int pwc_get_brightness(struct pwc_device *pdev);
 extern int pwc_set_contrast(struct pwc_device *pdev, int value);
 extern int pwc_get_gamma(struct pwc_device *pdev);
 extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
 extern int pwc_set_saturation(struct pwc_device *pdev, int value);
 extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
+extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value);
 extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+extern int pwc_restore_user(struct pwc_device *pdev);
+extern int pwc_save_user(struct pwc_device *pdev);
+extern int pwc_restore_factory(struct pwc_device *pdev);
+
+/* exported for use by v4l2 controls */
+extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_awb(struct pwc_device *pdev);
+extern int pwc_set_awb(struct pwc_device *pdev, int mode);
+extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_agc(struct pwc_device *pdev, int *value);
+extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
+
+extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
+extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
+extern int pwc_set_contour(struct pwc_device *pdev, int contour);
+extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
+extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
+extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
+extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
+extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
+extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
+extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
 
 /* Power down or up the camera; not supported by all models */
 extern int pwc_camera_power(struct pwc_device *pdev, int power);
 /* Private ioctl()s; see pwc-ioctl.h */
 extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
 
+/** Functions in pwc-v4l.c */
+extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+                             unsigned int cmd, void *arg);
 
 /** pwc-uncompress.c */
 /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
 
 
 #endif
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
 
--- /dev/null
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+   (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+   driver and thus may have bugs that are not present in the original version.
+   Please send bug reports and support requests to <luc@saillard.org>.
+   The decompression routines have been implemented by reverse-engineering the
+   Nemosoft binary pwcx module. Caveat emptor.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 10.0.10
+   It contains structures and defines to communicate from user space
+   directly to the driver.
+ */
+
+/*
+   Changes
+   2001/08/03  Alvarado   Added ioctl constants to access methods for
+                         changing white balance and red/blue gains
+   2002/12/15  G. H. Fernandez-Toribio   VIDIOCGREALSIZE
+   2003/12/13  Nemosft Unv. Some modifications to make interfacing to
+              PWCX easier
+   2006/01/01  Luc Saillard Add raw format definition
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+   They contain functions not found in other webcams, and settings not
+   specified in the Video4Linux API.
+
+   The #define names are built up like follows:
+   VIDIOC              VIDeo IOCtl prefix
+        PWC            Philps WebCam
+           G           optional: Get
+           S           optional: Set
+            ...        the function
+ */
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF      0x00
+#define PSZ_QSIF       0x01
+#define PSZ_QCIF       0x02
+#define PSZ_SIF                0x03
+#define PSZ_CIF                0x04
+#define PSZ_VGA                0x05
+#define PSZ_MAX                6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+   the upper 16 bits, since some flags are defined nowadays. The following
+   defines provide a mask and shift to filter out this value.
+   This value can also be passing using the private flag when using v4l2 and
+   VIDIOC_S_FMT ioctl.
+
+   In 'Snapshot' mode the camera freezes its automatic exposure and colour
+   balance controls.
+ */
+#define PWC_FPS_SHIFT          16
+#define PWC_FPS_MASK           0x00FF0000
+#define PWC_FPS_FRMASK         0x003F0000
+#define PWC_FPS_SNAPSHOT       0x00400000
+#define PWC_QLT_MASK           0x03000000
+#define PWC_QLT_SHIFT          24
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+       int x, y;               /* guess what */
+       int size;               /* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+       char name[32];
+       int type;
+};
+
+struct pwc_serial
+{
+       char serial[30];        /* String with serial number. Contains terminating 0 */
+};
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR          0
+#define PWC_WB_OUTDOOR         1
+#define PWC_WB_FL              2
+#define PWC_WB_MANUAL          3
+#define PWC_WB_AUTO            4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+   Set mode to one of the PWC_WB_* values above.
+   *red and *blue are the respective gains of these colour components inside
+   the camera; range 0..65535
+   When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
+   otherwise undefined.
+   'read_red' and 'read_blue' are read-only.
+*/
+struct pwc_whitebalance
+{
+       int mode;
+       int manual_red, manual_blue;    /* R/W */
+       int read_red, read_blue;        /* R/O */
+};
+
+/*
+   'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+   and tell the camera how fast it should react to changes in lighting, and
+   with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+       int control_speed;
+       int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+       int led_on;                     /* Led on-time; range = 0..25000 */
+       int led_off;                    /* Led off-time; range = 0..25000  */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+       int width;
+       int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN            0x01
+#define PWC_MPT_TILT           0x02
+#define PWC_MPT_TIMEOUT                0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the
+   driver calculates the relative offset for you. This can only
+   be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+   absolute angles.
+ */
+struct pwc_mpt_angles
+{
+       int absolute;           /* write-only */
+       int pan;                /* degrees * 100 */
+       int tilt;               /* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+       int pan_min, pan_max;           /* degrees * 100 */
+       int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+       int status;
+       int time_pan;
+       int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+   all the necessary information to initialize and use the decompressor
+   routines in standalone applications.
+ */
+struct pwc_video_command
+{
+       int type;               /* camera type (645, 675, 730, etc.) */
+       int release;            /* release number */
+
+       int size;               /* one of PSZ_* */
+       int alternate;
+       int command_len;        /* length of USB video command */
+       unsigned char command_buf[13];  /* Actual USB video command */
+       int bandlength;         /* >0 = compressed */
+       int frame_size;         /* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR       0x0001
+#define PWCX_FLAG_BAYER                0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER         _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER         _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY       _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+    means use uncompressed modes when available; 1 is low compression, 2 is
+    medium and 3 is high compression preferred. Of course, the higher the
+    compression, the lower the bandwidth used but more chance of artefacts
+    in the image. The driver automatically chooses a higher compression when
+    the preferred mode is not available.
+  */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL                _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL                _IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL       _IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+    becomes difficult to include all the names in programs that want to
+    check for the enhanced Philips stuff. So in stead, try this PROBE;
+    it returns a structure with the original name, and the corresponding
+    Philips type.
+    To use, fill the structure with zeroes, call PROBE and if that succeeds,
+    compare the name with that returned from VIDIOCGCAP; they should be the
+    same. If so, you can be assured it is a Philips (OEM) cam and the type
+    is valid.
+ */
+#define VIDIOCPWCPROBE         _IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC          _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC          _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER      _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB           _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB           _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED     _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED     _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED           _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED           _IOR('v', 205, struct pwc_leds)
+
+  /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR      _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR      _IOR('v', 206, int)
+
+  /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT    _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT    _IOR('v', 207, int)
+
+  /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER      _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER      _IOR('v', 208, int)
+
+  /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE     _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE     _IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE     _IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */
+#define VIDIOCPWCMPTRESET      _IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE     _IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE     _IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE     _IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS     _IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD       _IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+   int len;
+   char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE     _IOR('v', 216, struct pwc_table_init_buffer)
+
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER       (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER    (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE     (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR     (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR         (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT       (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS     (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+   __le16 type;                /* type of the webcam */
+   __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
+   __u8   cmd[4];      /* the four byte of the command (in case of nala,
+                          only the first 3 bytes is filled) */
+   __u8   rawframe[0]; /* frame_size = H/4*vbandlength */
+} __attribute__ ((packed));
+
+
+#endif