V4L/DVB (3835): [PATCH] update pwc driver
Luc Saillard [Mon, 24 Apr 2006 13:29:46 +0000 (10:29 -0300)]
Add v4l2 compatibility
Include the decompressor (legal problem has been resolv by Alan Cox)
Faster decoder and easier to maintain, optimize, ...
Can export to userland compressed stream
Support more cameras, lot of bugs are fixed.

Signed-off-by: Luc Saillard <luc@saillard.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

18 files changed:
drivers/media/video/pwc/Kconfig
drivers/media/video/pwc/Makefile
drivers/media/video/pwc/pwc-ctrl.c
drivers/media/video/pwc/pwc-dec1.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-dec1.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-dec23.c [new file with mode: 0644]
drivers/media/video/pwc/pwc-dec23.h [new file with mode: 0644]
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-kiara.c
drivers/media/video/pwc/pwc-kiara.h
drivers/media/video/pwc/pwc-misc.c
drivers/media/video/pwc/pwc-timon.c
drivers/media/video/pwc/pwc-timon.h
drivers/media/video/pwc/pwc-uncompress.c
drivers/media/video/pwc/pwc-uncompress.h
drivers/media/video/pwc/pwc-v4l.c [new file with mode: 0644]
drivers/media/video/pwc/pwc.h
include/media/pwc-ioctl.h [new file with mode: 0644]

index 53cbc95..697145e 100644 (file)
@@ -7,6 +7,7 @@ config USB_PWC
           * 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'
@@ -19,10 +20,18 @@ config USB_PWC
          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.
index 33d6012..9db2260 100644 (file)
@@ -1,3 +1,12 @@
-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
+
+
index 4ba549b..93306c7 100644 (file)
@@ -2,7 +2,7 @@
    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
@@ -138,6 +152,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
 #include "pwc-nala.h"
 };
 
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 
 /****************************************************************************/
 
@@ -159,31 +174,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
                &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),
@@ -196,7 +187,7 @@ static inline int send_video_command(struct usb_device *udev, int index, void *b
 
 
 
-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;
@@ -229,34 +220,14 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
        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);
@@ -283,7 +254,7 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
 }
 
 
-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;
@@ -315,8 +286,8 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
        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);
@@ -336,7 +307,7 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
 }
 
 
-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;
@@ -350,21 +321,14 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
        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
        {
@@ -372,6 +336,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
                   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)
@@ -382,7 +347,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
        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);
@@ -394,8 +359,8 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
        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);
@@ -410,49 +375,13 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
                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
@@ -465,50 +394,78 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
 {
        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 */
 
@@ -520,7 +477,7 @@ int pwc_get_brightness(struct pwc_device *pdev)
        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)
@@ -545,7 +502,7 @@ int pwc_get_contrast(struct pwc_device *pdev)
        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)
@@ -570,7 +527,7 @@ int pwc_get_gamma(struct pwc_device *pdev)
        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)
@@ -588,37 +545,47 @@ 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;
@@ -643,7 +610,7 @@ static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
        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;
@@ -673,7 +640,7 @@ static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
        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;
@@ -691,23 +658,16 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
                        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);
@@ -715,6 +675,25 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
        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 */
 
@@ -736,19 +715,19 @@ int pwc_camera_power(struct pwc_device *pdev, int 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);
@@ -766,7 +745,7 @@ static inline int pwc_restore_factory(struct pwc_device *pdev)
   * 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;
@@ -786,7 +765,7 @@ static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
        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;
@@ -798,7 +777,7 @@ static inline int pwc_get_awb(struct pwc_device *pdev)
        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;
 
@@ -811,7 +790,7 @@ static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
        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;
@@ -824,7 +803,7 @@ static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
 }
 
 
-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;
 
@@ -837,7 +816,7 @@ static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
        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;
@@ -854,7 +833,7 @@ static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
    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;
@@ -866,7 +845,7 @@ static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
        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;
@@ -879,7 +858,7 @@ static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
 }
 
 
-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;
 
@@ -888,7 +867,7 @@ static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
        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;
@@ -901,7 +880,7 @@ static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
 }
 
 
-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;
 
@@ -910,7 +889,7 @@ static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
        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;
@@ -946,7 +925,7 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
        return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
 }
 
-static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
+int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
 {
        unsigned char buf[2];
        int ret;
@@ -965,7 +944,7 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
        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;
@@ -990,7 +969,7 @@ static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
        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;
@@ -1012,7 +991,7 @@ static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
 }
 
 
-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;
 
@@ -1023,7 +1002,7 @@ static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
        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;
@@ -1031,12 +1010,35 @@ static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
        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;
 
@@ -1047,7 +1049,7 @@ static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
        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;
@@ -1055,12 +1057,11 @@ static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
        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;
 
@@ -1072,7 +1073,7 @@ static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
        return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
 }
 
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
 {
        int ret;
        unsigned char buf;
@@ -1084,7 +1085,7 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
        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;
 
@@ -1092,7 +1093,18 @@ static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
        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];
 
@@ -1110,7 +1122,35 @@ static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
        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];
@@ -1151,6 +1191,26 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
  /* 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)
 {
@@ -1180,206 +1240,243 @@ 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;
        }
 
@@ -1387,14 +1484,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                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
                {
@@ -1407,8 +1500,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                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
                {
@@ -1423,48 +1518,23 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
                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
                {
@@ -1478,11 +1548,12 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
                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
                {
@@ -1495,8 +1566,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
        {
                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
                {
@@ -1507,22 +1580,24 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 
        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;
        }
        */
@@ -1538,4 +1613,4 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 }
 
 
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c
new file mode 100644 (file)
index 0000000..c29593f
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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;
+}
+
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h
new file mode 100644 (file)
index 0000000..8b62ddc
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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
+
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
new file mode 100644 (file)
index 0000000..f9096c7
--- /dev/null
@@ -0,0 +1,941 @@
+/* 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: */
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h
new file mode 100644 (file)
index 0000000..1c55298
--- /dev/null
@@ -0,0 +1,67 @@
+/* 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: */
+
index 4141829..98059c8 100644 (file)
@@ -1,7 +1,7 @@
 /* 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) },
@@ -81,9 +84,10 @@ static struct usb_device_id pwc_device_table [] = {
        { 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 */
@@ -94,8 +98,9 @@ static struct usb_device_id pwc_device_table [] = {
        { 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 */
@@ -122,11 +127,13 @@ static struct usb_driver pwc_driver = {
 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];
@@ -138,7 +145,7 @@ static struct {
 
 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,
@@ -153,7 +160,6 @@ static struct file_operations pwc_fops = {
        .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 = {
@@ -203,52 +209,44 @@ 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);
 }
 
 
@@ -256,100 +254,83 @@ static void rvfree(void * mem, unsigned long size)
 
 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;
 }
 
@@ -357,21 +338,14 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 {
        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;
                }
@@ -380,7 +354,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
        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;
                        }
@@ -391,20 +365,19 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 
        /* 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.
@@ -464,7 +437,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
 /**
   \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;
@@ -489,23 +462,17 @@ static inline int pwc_next_fill_frame(struct pwc_device *pdev)
        }
        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;
 }
@@ -521,6 +488,8 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
        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;
@@ -540,13 +509,15 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
        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;
@@ -556,41 +527,40 @@ static int pwc_handle_frame(struct pwc_device *pdev)
           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;
@@ -599,12 +569,114 @@ static int pwc_handle_frame(struct pwc_device *pdev)
 /**
   \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.
@@ -620,17 +692,12 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
        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) {
@@ -645,13 +712,13 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
                        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);
@@ -661,7 +728,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
 
        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;
        }
@@ -688,7 +755,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
 
                                        /* ...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++;
                                        }
@@ -704,96 +771,28 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
                                /* 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:
@@ -803,11 +802,11 @@ 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;
@@ -826,7 +825,6 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        /* 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);
@@ -836,20 +834,21 @@ static int pwc_isoc_init(struct pwc_device *pdev)
 
        /* 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;
@@ -857,12 +856,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        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 */
@@ -899,24 +898,26 @@ static int pwc_isoc_init(struct pwc_device *pdev)
        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++) {
@@ -925,10 +926,10 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
                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;
                }
@@ -938,12 +939,12 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
           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)
@@ -957,18 +958,18 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        /* 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 */
                }
        }
@@ -976,54 +977,129 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
        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);
                }
        }
 
@@ -1031,34 +1107,32 @@ static int pwc_video_open(struct inode *inode, struct file *file)
        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 */
@@ -1070,29 +1144,44 @@ static int pwc_video_open(struct inode *inode, struct file *file)
         */
        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;
 }
 
@@ -1103,35 +1192,23 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        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);
@@ -1140,15 +1217,15 @@ static int pwc_video_close(struct inode *inode, struct file *file)
        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;
 }
 
@@ -1164,7 +1241,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
                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;
@@ -1172,8 +1249,10 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
        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;
@@ -1214,16 +1293,19 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
                        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 */
@@ -1253,370 +1335,56 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
        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)
@@ -1624,7 +1392,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
                else
                        size = 0;
        }
-
        return 0;
 }
 
@@ -1645,10 +1412,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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
@@ -1658,61 +1427,63 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
@@ -1721,7 +1492,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
@@ -1733,32 +1504,33 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
@@ -1766,7 +1538,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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;
@@ -1782,15 +1554,20 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                 */
                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;
@@ -1799,12 +1576,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
@@ -1816,7 +1593,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
@@ -1829,7 +1606,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                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;
@@ -1842,12 +1619,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
@@ -1861,15 +1638,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
 
        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;
@@ -1900,17 +1677,18 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_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++) {
@@ -1920,7 +1698,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                        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;
                        }
                }
@@ -1929,21 +1707,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        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;
 }
 
@@ -1957,27 +1741,21 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        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;
        }
 
@@ -1987,7 +1765,8 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
        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) */
@@ -2021,58 +1800,64 @@ static int pwc_atoi(const char *s)
  * 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! */
@@ -2081,41 +1866,42 @@ static int __init usb_pwc_init(void)
                        }
                }
                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)
@@ -2146,14 +1932,14 @@ static int __init usb_pwc_init(void)
                                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 {
@@ -2178,28 +1964,27 @@ static int __init usb_pwc_init(void)
                                        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: */
index 4c96037..fec39cc 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -316,3 +316,576 @@ const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
    },
 };
 
+
+/*
+ * 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}
+  }
+ }
+};
+
index 12929ab..0bdb225 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -27,7 +27,7 @@
 #ifndef PWC_KIARA_H
 #define PWC_KIARA_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Kiara_table_entry
 {
@@ -37,8 +37,8 @@ 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
 
index 58fe797..589c687 100644 (file)
@@ -1,7 +1,7 @@
 /* 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_ */
@@ -52,7 +51,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
        {
                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;
                }
        }
@@ -60,7 +59,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
        {
                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;
                }
        }
@@ -81,9 +80,8 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
 /* 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;
@@ -95,10 +93,23 @@ void pwc_construct(struct pwc_device *pdev)
                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 */
@@ -111,30 +122,12 @@ void pwc_construct(struct pwc_device *pdev)
                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);
 }
 
 
index 175250d..be65bdc 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -314,3 +314,1133 @@ const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
    },
 };
 
+/*
+ * 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}
+  }
+ }
+};
index a86b378..eef9e2c 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -42,7 +42,7 @@
 #ifndef PWC_TIMON_H
 #define PWC_TIMON_H
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 struct Timon_table_entry
 {
@@ -52,8 +52,8 @@ 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
index b37a89a..5d82028 100644 (file)
@@ -1,7 +1,7 @@
 /* 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.
@@ -22,6 +22,8 @@
    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>
@@ -29,6 +31,8 @@
 
 #include "pwc.h"
 #include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
 
 int pwc_decompress(struct pwc_device *pdev)
 {
@@ -40,107 +44,95 @@ 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: */
index f75e1b6..041227f 100644 (file)
@@ -1,5 +1,5 @@
 /* (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.
@@ -32,7 +32,7 @@
 
 #include <linux/config.h>
 
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
 
 /* from pwc-dec.h */
 #define PWCX_FLAG_PLANAR        0x0001
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
new file mode 100644 (file)
index 0000000..68e7573
--- /dev/null
@@ -0,0 +1,1208 @@
+/* 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:
+                                     &n