V4L/DVB (8825): gspca: More controls for pac73xx and new webcam 093a:2624.
authorHans de Goede <j.w.r.degoede@hhs.nl>
Wed, 3 Sep 2008 20:12:17 +0000 (17:12 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 3 Sep 2008 21:37:38 +0000 (18:37 -0300)
-Add usb id for 093a:2624 (pac7302)
-Report some controls to userspace with 7302 only, as they are 7302 only
-Add gain and exposure controls
-Add autogain
-Fix 7302 imaged being mirrored by default

Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Documentation/video4linux/gspca.txt
drivers/media/video/gspca/pac207.c
drivers/media/video/gspca/pac7311.c
drivers/media/video/gspca/pac_common.h

index 2dd2f774dd8e98b1c5414f006193c48f2583d788..c503467da25a886415d21078d07261aec3b558e5 100644 (file)
@@ -188,6 +188,7 @@ pac7311             093a:2608       Trust WB-3300p
 pac7311                093a:260e       Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
 pac7311                093a:260f       SnakeCam
 pac7311                093a:2621       PAC731x
+pac7311                093a:2624       PAC7302
 zc3xx          0ac8:0302       Z-star Vimicro zc0302
 vc032x         0ac8:0321       Vimicro generic vc0321
 vc032x         0ac8:0323       Vimicro Vc0323
index a15bccad947bb6368edfe0f8e292f65cba0ec1c5..83b5f740c9470960b3bf42aef54472726bbce098 100644 (file)
@@ -56,12 +56,6 @@ MODULE_LICENSE("GPL");
 #define PAC207_GAIN_KNEE               20
 
 #define PAC207_AUTOGAIN_DEADZONE       30
-/* We calculating the autogain at the end of the transfer of a frame, at this
-   moment a frame with the old settings is being transmitted, and a frame is
-   being captured with the old settings. So if we adjust the autogain we must
-   ignore atleast the 2 next frames for the new settings to come into effect
-   before doing any other adjustments */
-#define PAC207_AUTOGAIN_IGNORE_FRAMES  3
 
 /* specific webcam descriptor */
 struct sd {
@@ -338,6 +332,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 }
 
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
 static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -351,12 +348,9 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
        else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
                        100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
                        PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
-               sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
+               sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
-
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,
                        __u8 *data,
@@ -500,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
                sd->gain = PAC207_GAIN_DEFAULT;
                if (gspca_dev->streaming) {
                        sd->autogain_ignore_frames =
-                               PAC207_AUTOGAIN_IGNORE_FRAMES;
+                               PAC_AUTOGAIN_IGNORE_FRAMES;
                        setexposure(gspca_dev);
                        setgain(gspca_dev);
                }
index e22ca610334f02909b9839c24c6bc25bac560160..14b98111cd9dc128242f3dd9a6fbca8703393da5 100644 (file)
@@ -44,6 +44,9 @@
    0x10/-      Master gain 0-31
    -/0x10      Another gain 0-15, limited influence (1-2x gain I guess)
    0x21                Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+   -/0x27      Seems to toggle various gains on / off, Setting bit 7 seems to
+               completely disable the analog amplification block. Set to 0x68
+               for max gain, 0x14 for minimal gain.
 */
 
 #define MODULE_NAME "pac7311"
@@ -61,6 +64,8 @@ struct sd {
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
+       unsigned char gain;
+       unsigned char exposure;
        unsigned char autogain;
        __u8 hflip;
        __u8 vflip;
@@ -88,8 +93,14 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
+/* This control is pac7302 only */
+#define BRIGHTNESS_IDX 0
        {
            {
                .id      = V4L2_CID_BRIGHTNESS,
@@ -105,6 +116,7 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setbrightness,
            .get = sd_getbrightness,
        },
+/* This control is for both the 7302 and the 7311 */
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -120,6 +132,8 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcontrast,
            .get = sd_getcontrast,
        },
+/* This control is pac7302 only */
+#define SATURATION_IDX 2
        {
            {
                .id      = V4L2_CID_SATURATION,
@@ -135,6 +149,39 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setcolors,
            .get = sd_getcolors,
        },
+/* All controls below are for both the 7302 and the 7311 */
+       {
+           {
+               .id      = V4L2_CID_GAIN,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gain",
+               .minimum = 0,
+#define GAIN_MAX 255
+               .maximum = GAIN_MAX,
+               .step    = 1,
+#define GAIN_DEF 127
+#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+               .default_value = GAIN_DEF,
+           },
+           .set = sd_setgain,
+           .get = sd_getgain,
+       },
+       {
+           {
+               .id      = V4L2_CID_EXPOSURE,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Exposure",
+               .minimum = 0,
+#define EXPOSURE_MAX 255
+               .maximum = EXPOSURE_MAX,
+               .step    = 1,
+#define EXPOSURE_DEF  16 /*  32 ms / 30 fps */
+#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
+               .default_value = EXPOSURE_DEF,
+           },
+           .set = sd_setexposure,
+           .get = sd_getexposure,
+       },
        {
            {
                .id      = V4L2_CID_AUTOGAIN,
@@ -149,8 +196,6 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
-/* next controls work with pac7302 only */
-#define HFLIP_IDX 4
        {
            {
                .id      = V4L2_CID_HFLIP,
@@ -165,7 +210,6 @@ static struct ctrl sd_ctrls[] = {
            .set = sd_sethflip,
            .get = sd_gethflip,
        },
-#define VFLIP_IDX 5
        {
            {
                .id      = V4L2_CID_VFLIP,
@@ -345,7 +389,7 @@ static const __u8 page4_7311[] = {
        0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
        0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
-       0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
+       0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68,
        0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
        0x23, 0x28, 0x04, 0x11, 0x00, 0x00
 };
@@ -374,7 +418,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
                        usb_sndctrlpipe(gspca_dev->dev, 0),
                        0,                      /* request */
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, index, gspca_dev->usb_buf, 1,
+                       0, index, gspca_dev->usb_buf, 1,
                        500);
 }
 
@@ -469,20 +513,22 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
                cam->cam_mode = vga_mode;
                cam->nmodes = ARRAY_SIZE(vga_mode);
-               gspca_dev->ctrl_dis = (1 << HFLIP_IDX)
-                               | (1 << VFLIP_IDX);
+               gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
+                               | (1 << SATURATION_IDX);
        }
 
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
+       sd->gain = GAIN_DEF;
+       sd->exposure = EXPOSURE_DEF;
        sd->autogain = AUTOGAIN_DEF;
        sd->hflip = HFLIP_DEF;
        sd->vflip = VFLIP_DEF;
        return 0;
 }
 
-/* rev 12a only */
+/* This function is used by pac7302 only */
 static void setbrightcont(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -509,67 +555,95 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0xdc, 0x01);
 }
 
-/* This function is used by pac7302 only */
-static void setbrightness(struct gspca_dev *gspca_dev)
+/* This function is used by pac7311 only */
+static void setcontrast(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int brightness;
-
-       if (sd->sensor == SENSOR_PAC7302) {
-               setbrightcont(gspca_dev);
-               return;
-       }
-/* HDG: this is not brightness but gain, I'll add gain and exposure controls
-   in a next patch */
-       return;
 
-       brightness = BRIGHTNESS_MAX - sd->brightness;
        reg_w(gspca_dev, 0xff, 0x04);
-       reg_w(gspca_dev, 0x0e, 0x00);
-       reg_w(gspca_dev, 0x0f, brightness);
+       reg_w(gspca_dev, 0x10, sd->contrast >> 4);
        /* load registers to sensor (Bit 0, auto clear) */
        reg_w(gspca_dev, 0x11, 0x01);
-       PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
+/* This function is used by pac7302 only */
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       int i, v;
+       static const int a[9] =
+               {217, -212, 0, -101, 170, -67, -38, -315, 355};
+       static const int b[9] =
+               {19, 106, 0, 19, 106, 1, 19, 106, 1};
+
+       reg_w(gspca_dev, 0xff, 0x03);   /* page 3 */
+       reg_w(gspca_dev, 0x11, 0x01);
+       reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
+       reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
+       for (i = 0; i < 9; i++) {
+               v = a[i] * sd->colors / COLOR_MAX + b[i];
+               reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
+               reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
+       }
+       reg_w(gspca_dev, 0xdc, 0x01);
+       PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        if (sd->sensor == SENSOR_PAC7302) {
-               setbrightcont(gspca_dev);
-               return;
+               reg_w(gspca_dev, 0xff, 0x03);           /* page 3 */
+               reg_w(gspca_dev, 0x10, sd->gain >> 3);
+       } else {
+               int gain = GAIN_MAX - sd->gain;
+               if (gain < 1)
+                       gain = 1;
+               else if (gain > 245)
+                       gain = 245;
+               reg_w(gspca_dev, 0xff, 0x04);           /* page 4 */
+               reg_w(gspca_dev, 0x0e, 0x00);
+               reg_w(gspca_dev, 0x0f, gain);
        }
-       reg_w(gspca_dev, 0xff, 0x04);
-       reg_w(gspca_dev, 0x10, sd->contrast >> 4);
        /* load registers to sensor (Bit 0, auto clear) */
        reg_w(gspca_dev, 0x11, 0x01);
 }
 
-/* This function is used by pac7302 only */
-static void setcolors(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       __u8 reg;
+
+       /* register 2 of frame 3/4 contains the clock divider configuring the
+          no fps according to the formula: 60 / reg. sd->exposure is the
+          desired exposure time in ms. */
+       reg = 120 * sd->exposure / 1000;
+       if (reg < 2)
+               reg = 2;
+       else if (reg > 63)
+               reg = 63;
 
        if (sd->sensor == SENSOR_PAC7302) {
-               int i, v;
-               static const int a[9] =
-                       {217, -212, 0, -101, 170, -67, -38, -315, 355};
-               static const int b[9] =
-                       {19, 106, 0, 19, 106, 1, 19, 106, 1};
-
-               reg_w(gspca_dev, 0xff, 0x03);   /* page 3 */
-               reg_w(gspca_dev, 0x11, 0x01);
-               reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
-               reg_w(gspca_dev, 0xff, 0x00);   /* page 0 */
-               for (i = 0; i < 9; i++) {
-                       v = a[i] * sd->colors / COLOR_MAX + b[i];
-                       reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
-                       reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
-               }
-               reg_w(gspca_dev, 0xdc, 0x01);
-               PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
+               /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
+                  the nearest multiple of 3 */
+               reg = ((reg + 1) / 3) * 3;
+               reg_w(gspca_dev, 0xff, 0x03);           /* page 3 */
+               reg_w(gspca_dev, 0x02, reg);
+       } else {
+               reg_w(gspca_dev, 0xff, 0x04);           /* page 4 */
+               reg_w(gspca_dev, 0x02, reg);
+               /* Page 1 register 8 must always be 0x08 except when not in
+                  640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+               reg_w(gspca_dev, 0xff, 0x01);
+               if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
+                               reg <= 3)
+                       reg_w(gspca_dev, 0x08, 0x09);
+               else
+                       reg_w(gspca_dev, 0x08, 0x08);
        }
+       /* load registers to sensor (Bit 0, auto clear) */
+       reg_w(gspca_dev, 0x11, 0x01);
 }
 
 static void sethvflip(struct gspca_dev *gspca_dev)
@@ -579,14 +653,15 @@ static void sethvflip(struct gspca_dev *gspca_dev)
 
        if (sd->sensor == SENSOR_PAC7302) {
                reg_w(gspca_dev, 0xff, 0x03);           /* page 3 */
-               data = (sd->hflip ? 0x00 : 0x08)
+               data = (sd->hflip ? 0x08 : 0x00)
                        | (sd->vflip ? 0x04 : 0x00);
        } else {
-               reg_w(gspca_dev, 0xff, 0x04);           /* page 3 */
+               reg_w(gspca_dev, 0xff, 0x04);           /* page 4 */
                data = (sd->hflip ? 0x04 : 0x00)
                        | (sd->vflip ? 0x08 : 0x00);
        }
        reg_w(gspca_dev, 0x21, data);
+       /* load registers to sensor (Bit 0, auto clear) */
        reg_w(gspca_dev, 0x11, 0x01);
 }
 
@@ -602,61 +677,49 @@ static void sd_start(struct gspca_dev *gspca_dev)
 
        sd->sof_read = 0;
 
-       if (sd->sensor == SENSOR_PAC7302)
+       if (sd->sensor == SENSOR_PAC7302) {
                reg_w_var(gspca_dev, start_7302);
-       else
+               setbrightcont(gspca_dev);
+               setcolors(gspca_dev);
+       } else {
                reg_w_var(gspca_dev, start_7311);
-
-       setcontrast(gspca_dev);
-       setbrightness(gspca_dev);
-       setcolors(gspca_dev);
+               setcontrast(gspca_dev);
+       }
+       setgain(gspca_dev);
+       setexposure(gspca_dev);
+       sethvflip(gspca_dev);
 
        /* set correct resolution */
        switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
        case 2:                                 /* 160x120 pac7311 */
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x02, 0x03);
                reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x08, 0x09);
                reg_w(gspca_dev, 0x17, 0x20);
-               reg_w(gspca_dev, 0x1b, 0x00);
                reg_w(gspca_dev, 0x87, 0x10);
                break;
        case 1:                                 /* 320x240 pac7311 */
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x02, 0x03);
                reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x08, 0x09);
                reg_w(gspca_dev, 0x17, 0x30);
                reg_w(gspca_dev, 0x87, 0x11);
                break;
        case 0:                                 /* 640x480 */
                if (sd->sensor == SENSOR_PAC7302)
                        break;
-               reg_w(gspca_dev, 0xff, 0x04);
-               reg_w(gspca_dev, 0x02, 0x07);
                reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x08, 0x08);
                reg_w(gspca_dev, 0x17, 0x00);
                reg_w(gspca_dev, 0x87, 0x12);
                break;
        }
 
-       /* start stream */
-       reg_w(gspca_dev, 0xff, 0x01);
-       if (sd->sensor == SENSOR_PAC7302) {
-               sethvflip(gspca_dev);
-               reg_w(gspca_dev, 0x78, 0x01);
-               reg_w(gspca_dev, 0xff, 0x01);
-               reg_w(gspca_dev, 0x78, 0x01);
-       } else {
-               reg_w(gspca_dev, 0x78, 0x44);
-               reg_w(gspca_dev, 0x78, 0x45);
-       }
-
        sd->sof_read = 0;
        sd->autogain_ignore_frames = 0;
        atomic_set(&sd->avg_lum, -1);
+
+       /* start stream */
+       reg_w(gspca_dev, 0xff, 0x01);
+       if (sd->sensor == SENSOR_PAC7302)
+               reg_w(gspca_dev, 0x78, 0x01);
+       else
+               reg_w(gspca_dev, 0x78, 0x05);
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -691,8 +754,28 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
        }
 }
 
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
 static void do_autogain(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+       int avg_lum = atomic_read(&sd->avg_lum);
+       int desired_lum;
+
+       if (avg_lum == -1)
+               return;
+
+       if (sd->sensor == SENSOR_PAC7302)
+               desired_lum = 70 + sd->brightness * 2;
+       else
+               desired_lum = 200;
+
+       if (sd->autogain_ignore_frames > 0)
+               sd->autogain_ignore_frames--;
+       else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+                       10, GAIN_KNEE, EXPOSURE_KNEE))
+               sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 }
 
 static const unsigned char pac7311_jpeg_header1[] = {
@@ -704,9 +787,6 @@ static const unsigned char pac7311_jpeg_header2[] = {
   0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
 };
 
-/* Include pac common sof detection functions */
-#include "pac_common.h"
-
 /* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
@@ -790,7 +870,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 
        sd->brightness = val;
        if (gspca_dev->streaming)
-               setbrightness(gspca_dev);
+               setbrightcont(gspca_dev);
        return 0;
 }
 
@@ -807,8 +887,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->contrast = val;
-       if (gspca_dev->streaming)
-               setcontrast(gspca_dev);
+       if (gspca_dev->streaming) {
+               if (sd->sensor == SENSOR_PAC7302)
+                       setbrightcont(gspca_dev);
+               else
+                       setcontrast(gspca_dev);
+       }
        return 0;
 }
 
@@ -838,11 +922,61 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gain = val;
+       if (gspca_dev->streaming)
+               setgain(gspca_dev);
+       return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gain;
+       return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->exposure = val;
+       if (gspca_dev->streaming)
+               setexposure(gspca_dev);
+       return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->exposure;
+       return 0;
+}
+
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
        sd->autogain = val;
+       /* when switching to autogain set defaults to make sure
+          we are on a valid point of the autogain gain /
+          exposure knee graph, and give this change time to
+          take effect before doing autogain. */
+       if (sd->autogain) {
+               sd->exposure = EXPOSURE_DEF;
+               sd->gain = GAIN_DEF;
+               if (gspca_dev->streaming) {
+                       sd->autogain_ignore_frames =
+                               PAC_AUTOGAIN_IGNORE_FRAMES;
+                       setexposure(gspca_dev);
+                       setgain(gspca_dev);
+               }
+       }
 
        return 0;
 }
@@ -914,6 +1048,7 @@ static __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
        {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
        {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
+       {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
index a19b5d44c009dc297c9a807e685ffe514d88b189..34d4b1494cd5bd214f993cae4b1ef9e93a33d7b3 100644 (file)
  *
  */
 
+/* We calculate the autogain at the end of the transfer of a frame, at this
+   moment a frame with the old settings is being transmitted, and a frame is
+   being captured with the old settings. So if we adjust the autogain we must
+   ignore atleast the 2 next frames for the new settings to come into effect
+   before doing any other adjustments */
+#define PAC_AUTOGAIN_IGNORE_FRAMES     3
+
 static const unsigned char pac_sof_marker[5] =
                { 0xff, 0xff, 0x00, 0xff, 0x96 };
 
@@ -37,7 +44,7 @@ static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
                if (m[i] == pac_sof_marker[sd->sof_read]) {
                        sd->sof_read++;
                        if (sd->sof_read == sizeof(pac_sof_marker)) {
-                               PDEBUG(D_STREAM,
+                               PDEBUG(D_FRAM,
                                        "SOF found, bytes to analyze: %u."
                                        " Frame starts at byte #%u",
                                        len, i + 1);