Commit 8a5b2e90 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

V4L/DVB (8825): gspca: More controls for pac73xx and new webcam 093a:2624.

-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: default avatarHans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a1e8288b
...@@ -188,6 +188,7 @@ pac7311 093a:2608 Trust WB-3300p ...@@ -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:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350
pac7311 093a:260f SnakeCam pac7311 093a:260f SnakeCam
pac7311 093a:2621 PAC731x pac7311 093a:2621 PAC731x
pac7311 093a:2624 PAC7302
zc3xx 0ac8:0302 Z-star Vimicro zc0302 zc3xx 0ac8:0302 Z-star Vimicro zc0302
vc032x 0ac8:0321 Vimicro generic vc0321 vc032x 0ac8:0321 Vimicro generic vc0321
vc032x 0ac8:0323 Vimicro Vc0323 vc032x 0ac8:0323 Vimicro Vc0323
......
...@@ -56,12 +56,6 @@ MODULE_LICENSE("GPL"); ...@@ -56,12 +56,6 @@ MODULE_LICENSE("GPL");
#define PAC207_GAIN_KNEE 20 #define PAC207_GAIN_KNEE 20
#define PAC207_AUTOGAIN_DEADZONE 30 #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 */ /* specific webcam descriptor */
struct sd { struct sd {
...@@ -338,6 +332,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -338,6 +332,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ 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) static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -351,12 +348,9 @@ static void pac207_do_auto_gain(struct gspca_dev *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, else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) 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, static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, struct gspca_frame *frame,
__u8 *data, __u8 *data,
...@@ -500,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) ...@@ -500,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
sd->gain = PAC207_GAIN_DEFAULT; sd->gain = PAC207_GAIN_DEFAULT;
if (gspca_dev->streaming) { if (gspca_dev->streaming) {
sd->autogain_ignore_frames = sd->autogain_ignore_frames =
PAC207_AUTOGAIN_IGNORE_FRAMES; PAC_AUTOGAIN_IGNORE_FRAMES;
setexposure(gspca_dev); setexposure(gspca_dev);
setgain(gspca_dev); setgain(gspca_dev);
} }
......
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
0x10/- Master gain 0-31 0x10/- Master gain 0-31
-/0x10 Another gain 0-15, limited influence (1-2x gain I guess) -/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 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" #define MODULE_NAME "pac7311"
...@@ -61,6 +64,8 @@ struct sd { ...@@ -61,6 +64,8 @@ struct sd {
unsigned char brightness; unsigned char brightness;
unsigned char contrast; unsigned char contrast;
unsigned char colors; unsigned char colors;
unsigned char gain;
unsigned char exposure;
unsigned char autogain; unsigned char autogain;
__u8 hflip; __u8 hflip;
__u8 vflip; __u8 vflip;
...@@ -88,8 +93,14 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); ...@@ -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_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setvflip(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_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[] = { static struct ctrl sd_ctrls[] = {
/* This control is pac7302 only */
#define BRIGHTNESS_IDX 0
{ {
{ {
.id = V4L2_CID_BRIGHTNESS, .id = V4L2_CID_BRIGHTNESS,
...@@ -105,6 +116,7 @@ static struct ctrl sd_ctrls[] = { ...@@ -105,6 +116,7 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setbrightness, .set = sd_setbrightness,
.get = sd_getbrightness, .get = sd_getbrightness,
}, },
/* This control is for both the 7302 and the 7311 */
{ {
{ {
.id = V4L2_CID_CONTRAST, .id = V4L2_CID_CONTRAST,
...@@ -120,6 +132,8 @@ static struct ctrl sd_ctrls[] = { ...@@ -120,6 +132,8 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcontrast, .set = sd_setcontrast,
.get = sd_getcontrast, .get = sd_getcontrast,
}, },
/* This control is pac7302 only */
#define SATURATION_IDX 2
{ {
{ {
.id = V4L2_CID_SATURATION, .id = V4L2_CID_SATURATION,
...@@ -135,6 +149,39 @@ static struct ctrl sd_ctrls[] = { ...@@ -135,6 +149,39 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setcolors, .set = sd_setcolors,
.get = sd_getcolors, .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, .id = V4L2_CID_AUTOGAIN,
...@@ -149,8 +196,6 @@ static struct ctrl sd_ctrls[] = { ...@@ -149,8 +196,6 @@ static struct ctrl sd_ctrls[] = {
.set = sd_setautogain, .set = sd_setautogain,
.get = sd_getautogain, .get = sd_getautogain,
}, },
/* next controls work with pac7302 only */
#define HFLIP_IDX 4
{ {
{ {
.id = V4L2_CID_HFLIP, .id = V4L2_CID_HFLIP,
...@@ -165,7 +210,6 @@ static struct ctrl sd_ctrls[] = { ...@@ -165,7 +210,6 @@ static struct ctrl sd_ctrls[] = {
.set = sd_sethflip, .set = sd_sethflip,
.get = sd_gethflip, .get = sd_gethflip,
}, },
#define VFLIP_IDX 5
{ {
{ {
.id = V4L2_CID_VFLIP, .id = V4L2_CID_VFLIP,
...@@ -345,7 +389,7 @@ static const __u8 page4_7311[] = { ...@@ -345,7 +389,7 @@ static const __u8 page4_7311[] = {
0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62, 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa, 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, 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
0x23, 0x28, 0x04, 0x11, 0x00, 0x00 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
}; };
...@@ -374,7 +418,7 @@ static void reg_w(struct gspca_dev *gspca_dev, ...@@ -374,7 +418,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
usb_sndctrlpipe(gspca_dev->dev, 0), usb_sndctrlpipe(gspca_dev->dev, 0),
0, /* request */ 0, /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, gspca_dev->usb_buf, 1, 0, index, gspca_dev->usb_buf, 1,
500); 500);
} }
...@@ -469,20 +513,22 @@ static int sd_config(struct gspca_dev *gspca_dev, ...@@ -469,20 +513,22 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = vga_mode; cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode); cam->nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->ctrl_dis = (1 << HFLIP_IDX) gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX)
| (1 << VFLIP_IDX); | (1 << SATURATION_IDX);
} }
sd->brightness = BRIGHTNESS_DEF; sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF; sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF; sd->colors = COLOR_DEF;
sd->gain = GAIN_DEF;
sd->exposure = EXPOSURE_DEF;
sd->autogain = AUTOGAIN_DEF; sd->autogain = AUTOGAIN_DEF;
sd->hflip = HFLIP_DEF; sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF; sd->vflip = VFLIP_DEF;
return 0; return 0;
} }
/* rev 12a only */ /* This function is used by pac7302 only */
static void setbrightcont(struct gspca_dev *gspca_dev) static void setbrightcont(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -509,67 +555,95 @@ static void setbrightcont(struct gspca_dev *gspca_dev) ...@@ -509,67 +555,95 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0xdc, 0x01); reg_w(gspca_dev, 0xdc, 0x01);
} }
/* This function is used by pac7302 only */ /* This function is used by pac7311 only */
static void setbrightness(struct gspca_dev *gspca_dev) static void setcontrast(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) 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, 0xff, 0x04);
reg_w(gspca_dev, 0x0e, 0x00); reg_w(gspca_dev, 0x10, sd->contrast >> 4);
reg_w(gspca_dev, 0x0f, brightness);
/* load registers to sensor (Bit 0, auto clear) */ /* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01); 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; struct sd *sd = (struct sd *) gspca_dev;
if (sd->sensor == SENSOR_PAC7302) { if (sd->sensor == SENSOR_PAC7302) {
setbrightcont(gspca_dev); reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
return; 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) */ /* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01); reg_w(gspca_dev, 0x11, 0x01);
} }
/* This function is used by pac7302 only */ static void setexposure(struct gspca_dev *gspca_dev)
static void setcolors(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) 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) { if (sd->sensor == SENSOR_PAC7302) {
int i, v; /* On the pac7302 reg2 MUST be a multiple of 3, so round it to
static const int a[9] = the nearest multiple of 3 */
{217, -212, 0, -101, 170, -67, -38, -315, 355}; reg = ((reg + 1) / 3) * 3;
static const int b[9] = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
{19, 106, 0, 19, 106, 1, 19, 106, 1}; reg_w(gspca_dev, 0x02, reg);
} else {
reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
reg_w(gspca_dev, 0x11, 0x01); reg_w(gspca_dev, 0x02, reg);
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ /* Page 1 register 8 must always be 0x08 except when not in
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
for (i = 0; i < 9; i++) { reg_w(gspca_dev, 0xff, 0x01);
v = a[i] * sd->colors / COLOR_MAX + b[i]; if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); reg <= 3)
reg_w(gspca_dev, 0x0f + 2 * i + 1, v); reg_w(gspca_dev, 0x08, 0x09);
} else
reg_w(gspca_dev, 0xdc, 0x01); reg_w(gspca_dev, 0x08, 0x08);
PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
} }
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
} }
static void sethvflip(struct gspca_dev *gspca_dev) static void sethvflip(struct gspca_dev *gspca_dev)
...@@ -579,14 +653,15 @@ 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) { if (sd->sensor == SENSOR_PAC7302) {
reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
data = (sd->hflip ? 0x00 : 0x08) data = (sd->hflip ? 0x08 : 0x00)
| (sd->vflip ? 0x04 : 0x00); | (sd->vflip ? 0x04 : 0x00);
} else { } else {
reg_w(gspca_dev, 0xff, 0x04); /* page 3 */ reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
data = (sd->hflip ? 0x04 : 0x00) data = (sd->hflip ? 0x04 : 0x00)
| (sd->vflip ? 0x08 : 0x00); | (sd->vflip ? 0x08 : 0x00);
} }
reg_w(gspca_dev, 0x21, data); reg_w(gspca_dev, 0x21, data);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01); reg_w(gspca_dev, 0x11, 0x01);
} }
...@@ -602,61 +677,49 @@ static void sd_start(struct gspca_dev *gspca_dev) ...@@ -602,61 +677,49 @@ static void sd_start(struct gspca_dev *gspca_dev)
sd->sof_read = 0; sd->sof_read = 0;
if (sd->sensor == SENSOR_PAC7302) if (sd->sensor == SENSOR_PAC7302) {
reg_w_var(gspca_dev, start_7302); reg_w_var(gspca_dev, start_7302);
else setbrightcont(gspca_dev);
setcolors(gspca_dev);
} else {
reg_w_var(gspca_dev, start_7311); reg_w_var(gspca_dev, start_7311);
setcontrast(gspca_dev);
setcontrast(gspca_dev); }
setbrightness(gspca_dev); setgain(gspca_dev);
setcolors(gspca_dev); setexposure(gspca_dev);
sethvflip(gspca_dev);
/* set correct resolution */ /* set correct resolution */
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
case 2: /* 160x120 pac7311 */ 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, 0xff, 0x01);
reg_w(gspca_dev, 0x08, 0x09);
reg_w(gspca_dev, 0x17, 0x20); reg_w(gspca_dev, 0x17, 0x20);
reg_w(gspca_dev, 0x1b, 0x00);
reg_w(gspca_dev, 0x87, 0x10); reg_w(gspca_dev, 0x87, 0x10);
break; break;
case 1: /* 320x240 pac7311 */ 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, 0xff, 0x01);
reg_w(gspca_dev, 0x08, 0x09);
reg_w(gspca_dev, 0x17, 0x30); reg_w(gspca_dev, 0x17, 0x30);
reg_w(gspca_dev, 0x87, 0x11); reg_w(gspca_dev, 0x87, 0x11);
break; break;
case 0: /* 640x480 */ case 0: /* 640x480 */
if (sd->sensor == SENSOR_PAC7302) if (sd->sensor == SENSOR_PAC7302)
break; break;
reg_w(gspca_dev, 0xff, 0x04);
reg_w(gspca_dev, 0x02, 0x07);
reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x08, 0x08);
reg_w(gspca_dev, 0x17, 0x00); reg_w(gspca_dev, 0x17, 0x00);
reg_w(gspca_dev, 0x87, 0x12); reg_w(gspca_dev, 0x87, 0x12);
break; 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->sof_read = 0;
sd->autogain_ignore_frames = 0; sd->autogain_ignore_frames = 0;
atomic_set(&sd->avg_lum, -1); 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) static void sd_stopN(struct gspca_dev *gspca_dev)
...@@ -691,8 +754,28 @@ static void sd_stop0(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) 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[] = { static const unsigned char pac7311_jpeg_header1[] = {
...@@ -704,9 +787,6 @@ static const unsigned char pac7311_jpeg_header2[] = { ...@@ -704,9 +787,6 @@ static const unsigned char pac7311_jpeg_header2[] = {
0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 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 */ /* this function is run at interrupt level */
static void sd_pkt_scan(struct gspca_dev *gspca_dev, static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */ struct gspca_frame *frame, /* target */
...@@ -790,7 +870,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) ...@@ -790,7 +870,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
sd->brightness = val; sd->brightness = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setbrightness(gspca_dev); setbrightcont(gspca_dev);
return 0; return 0;
} }
...@@ -807,8 +887,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) ...@@ -807,8 +887,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
sd->contrast = val; sd->contrast = val;
if (gspca_dev->streaming) if (gspca_dev->streaming) {
setcontrast(gspca_dev); if (sd->sensor == SENSOR_PAC7302)
setbrightcont(gspca_dev);
else
setcontrast(gspca_dev);
}
return 0; return 0;
} }
...@@ -838,11 +922,61 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) ...@@ -838,11 +922,61 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0; 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) static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
sd->autogain = val; 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; return 0;
} }
...@@ -914,6 +1048,7 @@ static __devinitdata struct usb_device_id device_table[] = { ...@@ -914,6 +1048,7 @@ static __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
{USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
{USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
{USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302},
{} {}
}; };
MODULE_DEVICE_TABLE(usb, device_table); MODULE_DEVICE_TABLE(usb, device_table);
......
...@@ -23,6 +23,13 @@ ...@@ -23,6 +23,13 @@
* *
*/ */
/* 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] = static const unsigned char pac_sof_marker[5] =
{ 0xff, 0xff, 0x00, 0xff, 0x96 }; { 0xff, 0xff, 0x00, 0xff, 0x96 };
...@@ -37,7 +44,7 @@ static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, ...@@ -37,7 +44,7 @@ static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev,
if (m[i] == pac_sof_marker[sd->sof_read]) { if (m[i] == pac_sof_marker[sd->sof_read]) {
sd->sof_read++; sd->sof_read++;
if (sd->sof_read == sizeof(pac_sof_marker)) { if (sd->sof_read == sizeof(pac_sof_marker)) {
PDEBUG(D_STREAM, PDEBUG(D_FRAM,
"SOF found, bytes to analyze: %u." "SOF found, bytes to analyze: %u."
" Frame starts at byte #%u", " Frame starts at byte #%u",
len, i + 1); len, i + 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment