#define JPEG_HDR_SZ 521
};
-enum e_ctrl {
- EXPOSURE,
- QUALITY,
- SHARPNESS,
- RGAIN,
- GAIN,
- BGAIN,
- GAMMA,
- AUTOGAIN,
- NCTRLS /* number of controls */
-};
-
-#define AUTOGAIN_DEF 1
-
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
-
- struct gspca_ctrl ctrls[NCTRLS];
+ struct v4l2_ctrl *jpegqual;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *gamma;
+ struct v4l2_ctrl *blue;
+ struct v4l2_ctrl *red;
u8 framerate;
u8 quality; /* webcam current JPEG quality (0..16) */
}
/* set the gain and exposure */
-static void setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 gain,
+ s32 blue, s32 red)
{
struct sd *sd = (struct sd *) gspca_dev;
if (sd->sensor == SENSOR_CX0342) {
- int expo;
-
- expo = (sd->ctrls[EXPOSURE].val << 2) - 1;
+ expo = (expo << 2) - 1;
i2c_w(gspca_dev, CX0342_EXPO_LINE_L, expo);
i2c_w(gspca_dev, CX0342_EXPO_LINE_H, expo >> 8);
if (sd->bridge == BRIDGE_TP6800)
i2c_w(gspca_dev, CX0342_RAW_GBGAIN_H,
- sd->ctrls[GAIN].val >> 8);
- i2c_w(gspca_dev, CX0342_RAW_GBGAIN_L, sd->ctrls[GAIN].val);
+ gain >> 8);
+ i2c_w(gspca_dev, CX0342_RAW_GBGAIN_L, gain);
if (sd->bridge == BRIDGE_TP6800)
i2c_w(gspca_dev, CX0342_RAW_GRGAIN_H,
- sd->ctrls[GAIN].val >> 8);
- i2c_w(gspca_dev, CX0342_RAW_GRGAIN_L, sd->ctrls[GAIN].val);
- if (sd->bridge == BRIDGE_TP6800)
- i2c_w(gspca_dev, CX0342_RAW_BGAIN_H,
- sd->ctrls[BGAIN].val >> 8);
- i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, sd->ctrls[BGAIN].val);
- if (sd->bridge == BRIDGE_TP6800)
- i2c_w(gspca_dev, CX0342_RAW_RGAIN_H,
- sd->ctrls[RGAIN].val >> 8);
- i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, sd->ctrls[RGAIN].val);
+ gain >> 8);
+ i2c_w(gspca_dev, CX0342_RAW_GRGAIN_L, gain);
+ if (sd->sensor == SENSOR_CX0342) {
+ if (sd->bridge == BRIDGE_TP6800)
+ i2c_w(gspca_dev, CX0342_RAW_BGAIN_H,
+ blue >> 8);
+ i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, blue);
+ if (sd->bridge == BRIDGE_TP6800)
+ i2c_w(gspca_dev, CX0342_RAW_RGAIN_H,
+ red >> 8);
+ i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, red);
+ }
i2c_w(gspca_dev, CX0342_SYS_CTRL_0,
sd->bridge == BRIDGE_TP6800 ? 0x80 : 0x81);
return;
/* soi763a */
i2c_w(gspca_dev, 0x10, /* AEC_H (exposure time) */
- sd->ctrls[EXPOSURE].val);
+ expo);
/* i2c_w(gspca_dev, 0x76, 0x02); * AEC_L ([1:0] */
i2c_w(gspca_dev, 0x00, /* gain */
- sd->ctrls[GAIN].val);
+ gain);
}
/* set the JPEG quantization tables */
}
/* set the JPEG compression quality factor */
-static void setquality(struct gspca_dev *gspca_dev)
+static void setquality(struct gspca_dev *gspca_dev, s32 q)
{
struct sd *sd = (struct sd *) gspca_dev;
- u16 q;
- q = sd->ctrls[QUALITY].val;
if (q != 16)
q = 15 - q;
0xd5, 0x00, 0x46, 0x03, 0xdc, 0x03}, /* V R/G/B */
};
-static void setgamma(struct gspca_dev *gspca_dev)
+static void setgamma(struct gspca_dev *gspca_dev, s32 gamma)
{
struct sd *sd = (struct sd *) gspca_dev;
- int gamma;
#define NGAMMA 6
static const u8 gamma_tb[NGAMMA][3][1024] = {
{ /* gamma 0 - from tp6800 + soi763a */
if (sd->bridge == BRIDGE_TP6810)
reg_w(gspca_dev, 0x02, 0x28);
/* msleep(50); */
- gamma = sd->ctrls[GAMMA].val;
bulk_w(gspca_dev, 0x00, gamma_tb[gamma][0], 1024);
bulk_w(gspca_dev, 0x01, gamma_tb[gamma][1], 1024);
bulk_w(gspca_dev, 0x02, gamma_tb[gamma][2], 1024);
/* msleep(50); */
}
-static void setsharpness(struct gspca_dev *gspca_dev)
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
if (sd->bridge == BRIDGE_TP6800) {
- val = sd->ctrls[SHARPNESS].val
- | 0x08; /* grid compensation enable */
+ val |= 0x08; /* grid compensation enable */
if (gspca_dev->width == 640)
reg_w(gspca_dev, TP6800_R78_FORMAT, 0x00); /* vga */
else
val |= 0x04; /* scaling down enable */
reg_w(gspca_dev, TP6800_R5D_DEMOSAIC_CFG, val);
} else {
- val = (sd->ctrls[SHARPNESS].val << 5) | 0x08;
+ val = (val << 5) | 0x08;
reg_w(gspca_dev, 0x59, val);
}
}
-static void setautogain(struct gspca_dev *gspca_dev)
+static void setautogain(struct gspca_dev *gspca_dev, s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
- return;
- if (sd->ctrls[AUTOGAIN].val) {
- sd->ag_cnt = AG_CNT_START;
- gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
- } else {
- sd->ag_cnt = -1;
- gspca_dev->ctrl_inac &= ~((1 << EXPOSURE) | (1 << GAIN));
- }
+ sd->ag_cnt = val ? AG_CNT_START : -1;
}
/* set the resolution for sensor cx0342 */
static void set_resolution(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
reg_w(gspca_dev, TP6800_R21_ENDP_1_CTL, 0x00);
if (gspca_dev->width == 320) {
reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x06);
i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01);
bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342],
ARRAY_SIZE(color_gain[0]));
- setgamma(gspca_dev);
- setquality(gspca_dev);
+ setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
+ if (sd->sensor == SENSOR_SOI763A)
+ setquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual));
}
/* convert the frame rate to a tp68x0 value */
return i;
}
-static void setframerate(struct gspca_dev *gspca_dev)
+static void setframerate(struct gspca_dev *gspca_dev, s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 fr_idx;
reg_r(gspca_dev, 0x7b);
reg_w(gspca_dev, 0x7b,
sd->sensor == SENSOR_CX0342 ? 0x10 : 0x90);
- if (sd->ctrls[EXPOSURE].val >= 128)
+ if (val >= 128)
fr_idx = 0xf0; /* lower frame rate */
}
i2c_w(gspca_dev, CX0342_AUTO_ADC_CALIB, 0x01);
}
-static void setrgain(struct gspca_dev *gspca_dev)
+static void setrgain(struct gspca_dev *gspca_dev, s32 rgain)
{
- struct sd *sd = (struct sd *) gspca_dev;
- int rgain;
-
- rgain = sd->ctrls[RGAIN].val;
i2c_w(gspca_dev, CX0342_RAW_RGAIN_H, rgain >> 8);
i2c_w(gspca_dev, CX0342_RAW_RGAIN_L, rgain);
i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80);
}
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 val = gspca_dev->gain->val;
if (sd->sensor == SENSOR_CX0342) {
- sd->ctrls[BGAIN].val = sd->ctrls[BGAIN].val
- * val / sd->ctrls[GAIN].val;
- if (sd->ctrls[BGAIN].val > 4095)
- sd->ctrls[BGAIN].val = 4095;
- sd->ctrls[RGAIN].val = sd->ctrls[RGAIN].val
- * val / sd->ctrls[GAIN].val;
- if (sd->ctrls[RGAIN].val > 4095)
- sd->ctrls[RGAIN].val = 4095;
+ s32 old = gspca_dev->gain->cur.val ?
+ gspca_dev->gain->cur.val : 1;
+
+ sd->blue->val = sd->blue->val * val / old;
+ if (sd->blue->val > 4095)
+ sd->blue->val = 4095;
+ sd->red->val = sd->red->val * val / old;
+ if (sd->red->val > 4095)
+ sd->red->val = 4095;
+ }
+ if (gspca_dev->streaming) {
+ if (sd->sensor == SENSOR_CX0342)
+ setexposure(gspca_dev, gspca_dev->exposure->val,
+ gspca_dev->gain->val,
+ sd->blue->val, sd->red->val);
+ else
+ setexposure(gspca_dev, gspca_dev->exposure->val,
+ gspca_dev->gain->val, 0, 0);
}
- sd->ctrls[GAIN].val = val;
- if (gspca_dev->streaming)
- setexposure(gspca_dev);
return gspca_dev->usb_err;
}
-static void setbgain(struct gspca_dev *gspca_dev)
+static void setbgain(struct gspca_dev *gspca_dev, s32 bgain)
{
- struct sd *sd = (struct sd *) gspca_dev;
- int bgain;
-
- bgain = sd->ctrls[BGAIN].val;
i2c_w(gspca_dev, CX0342_RAW_BGAIN_H, bgain >> 8);
i2c_w(gspca_dev, CX0342_RAW_BGAIN_L, bgain);
i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x80);
framerates : framerates_6810;
sd->framerate = 30; /* default: 30 fps */
- gspca_dev->cam.ctrls = sd->ctrls;
return 0;
}
}
if (sd->sensor == SENSOR_SOI763A) {
pr_info("Sensor soi763a\n");
- sd->ctrls[GAMMA].def = sd->bridge == BRIDGE_TP6800 ? 0 : 1;
- sd->ctrls[GAIN].max = 15;
- sd->ctrls[GAIN].def = 3;
- gspca_dev->ctrl_dis = (1 << RGAIN) | (1 << BGAIN);
if (sd->bridge == BRIDGE_TP6810) {
soi763a_6810_init(gspca_dev);
-#if AUTOGAIN_DEF
- gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
-#endif
- } else {
- gspca_dev->ctrl_dis |= (1 << AUTOGAIN);
}
} else {
pr_info("Sensor cx0342\n");
if (sd->bridge == BRIDGE_TP6810) {
cx0342_6810_init(gspca_dev);
-#if AUTOGAIN_DEF
- gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
-#endif
- } else {
- gspca_dev->ctrl_dis |= (1 << AUTOGAIN);
}
}
- if (sd->bridge == BRIDGE_TP6810)
- sd->ctrls[QUALITY].def = 0; /* auto quality */
set_dqt(gspca_dev, 0);
return 0;
}
static void cx0342_6800_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
static const struct cmd reg_init[] = {
-/*fixme: is this usefull?*/
+ /* fixme: is this useful? */
{TP6800_R17_GPIO_IO, 0x9f},
{TP6800_R16_GPIO_PD, 0x40},
{TP6800_R10_SIF_TYPE, 0x00}, /* i2c 8 bits */
reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00);
i2c_w(gspca_dev, CX0342_EXPO_LINE_H, 0x00);
i2c_w(gspca_dev, CX0342_SYS_CTRL_0, 0x01);
- setexposure(gspca_dev);
+ if (sd->sensor == SENSOR_CX0342)
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain),
+ v4l2_ctrl_g_ctrl(sd->blue),
+ v4l2_ctrl_g_ctrl(sd->red));
+ else
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0);
set_led(gspca_dev, 1);
set_resolution(gspca_dev);
}
static void cx0342_6810_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
static const struct cmd sensor_init_2[] = {
{CX0342_EXPO_LINE_L, 0x6f},
{CX0342_EXPO_LINE_H, 0x02},
reg_w(gspca_dev, 0x07, 0x85);
reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */
}
- setgamma(gspca_dev);
+ setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
reg_w_buf(gspca_dev, tp6810_bridge_start,
ARRAY_SIZE(tp6810_bridge_start));
- setsharpness(gspca_dev);
+ setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));
bulk_w(gspca_dev, 0x03, color_gain[SENSOR_CX0342],
ARRAY_SIZE(color_gain[0]));
reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0x87);
i2c_w_buf(gspca_dev, sensor_init_5, ARRAY_SIZE(sensor_init_5));
set_led(gspca_dev, 1);
-/* setquality(gspca_dev); */
+/* setquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); */
}
static void soi763a_6800_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
static const struct cmd reg_init[] = {
{TP6800_R79_QUALITY, 0x04},
{TP6800_R79_QUALITY, 0x01},
reg_w(gspca_dev, TP6800_R5C_EDGE_THRLD, 0x10);
reg_w(gspca_dev, TP6800_R54_DARK_CFG, 0x00);
- setsharpness(gspca_dev);
+ setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));
bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A],
ARRAY_SIZE(color_gain[0]));
set_led(gspca_dev, 1);
- setexposure(gspca_dev);
- setquality(gspca_dev);
- setgamma(gspca_dev);
+ if (sd->sensor == SENSOR_CX0342)
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain),
+ v4l2_ctrl_g_ctrl(sd->blue),
+ v4l2_ctrl_g_ctrl(sd->red));
+ else
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0);
+ if (sd->sensor == SENSOR_SOI763A)
+ setquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual));
+ setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
}
static void soi763a_6810_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
static const struct cmd bridge_init_2[] = {
{TP6800_R7A_BLK_THRLD, 0x00},
{TP6800_R79_QUALITY, 0x04},
reg_w(gspca_dev, 0x22, gspca_dev->alt);
bulk_w(gspca_dev, 0x03, color_null, sizeof color_null);
reg_w(gspca_dev, 0x59, 0x40);
- setexposure(gspca_dev);
+ if (sd->sensor == SENSOR_CX0342)
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain),
+ v4l2_ctrl_g_ctrl(sd->blue),
+ v4l2_ctrl_g_ctrl(sd->red));
+ else
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0);
reg_w_buf(gspca_dev, bridge_init_2, ARRAY_SIZE(bridge_init_2));
reg_w_buf(gspca_dev, tp6810_ov_init_common,
ARRAY_SIZE(tp6810_ov_init_common));
reg_w(gspca_dev, 0x07, 0x85);
reg_w(gspca_dev, TP6800_R78_FORMAT, 0x01); /* qvga */
}
- setgamma(gspca_dev);
+ setgamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
reg_w_buf(gspca_dev, tp6810_bridge_start,
ARRAY_SIZE(tp6810_bridge_start));
reg_w(gspca_dev, 0x00, 0x00);
- setsharpness(gspca_dev);
+ setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));
bulk_w(gspca_dev, 0x03, color_gain[SENSOR_SOI763A],
ARRAY_SIZE(color_gain[0]));
set_led(gspca_dev, 1);
reg_w(gspca_dev, TP6800_R3F_FRAME_RATE, 0xf0);
- setexposure(gspca_dev);
+ if (sd->sensor == SENSOR_CX0342)
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain),
+ v4l2_ctrl_g_ctrl(sd->blue),
+ v4l2_ctrl_g_ctrl(sd->red));
+ else
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0);
reg_w_buf(gspca_dev, bridge_init_6, ARRAY_SIZE(bridge_init_6));
}
reg_w(gspca_dev, 0x80, 0x03);
reg_w(gspca_dev, 0x82, gspca_dev->curr_mode ? 0x0a : 0x0e);
- setexposure(gspca_dev);
- setquality(gspca_dev);
- setautogain(gspca_dev);
+ if (sd->sensor == SENSOR_CX0342)
+ setexposure(gspca_dev,
+ v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain),
+ v4l2_ctrl_g_ctrl(sd->blue),
+ v4l2_ctrl_g_ctrl(sd->red));
+ else
+ setexposure(gspca_dev,
+ v4l2_ctrl_g_ctrl(gspca_dev->exposure),
+ v4l2_ctrl_g_ctrl(gspca_dev->gain), 0, 0);
+ if (sd->sensor == SENSOR_SOI763A)
+ setquality(gspca_dev,
+ v4l2_ctrl_g_ctrl(sd->jpegqual));
+ if (sd->bridge == BRIDGE_TP6810)
+ setautogain(gspca_dev,
+ v4l2_ctrl_g_ctrl(gspca_dev->autogain));
}
- setframerate(gspca_dev);
+ setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
return gspca_dev->usb_err;
}
}
}
-/* -- do autogain -- */
-/* gain setting is done in setexposure() for tp6810 */
-static void setgain(struct gspca_dev *gspca_dev) {}
-#define WANT_REGULAR_AUTOGAIN
-#include "autogain_functions.h"
-
static void sd_dq_callback(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
luma /= 4;
reg_w(gspca_dev, 0x7d, 0x00);
- expo = sd->ctrls[EXPOSURE].val;
- ret = auto_gain_n_exposure(gspca_dev, luma,
+ expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+ ret = gspca_expo_autogain(gspca_dev, luma,
60, /* desired luma */
6, /* dead zone */
2, /* gain knee */
70); /* expo knee */
sd->ag_cnt = AG_CNT_START;
if (sd->bridge == BRIDGE_TP6810) {
- if ((expo >= 128 && sd->ctrls[EXPOSURE].val < 128)
- || (expo < 128 && sd->ctrls[EXPOSURE].val >= 128))
- setframerate(gspca_dev);
+ int new_expo = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+ if ((expo >= 128 && new_expo < 128)
+ || (expo < 128 && new_expo >= 128))
+ setframerate(gspca_dev, new_expo);
}
break;
}
sd->framerate = tpf->denominator / tpf->numerator;
if (gspca_dev->streaming)
- setframerate(gspca_dev);
+ setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
/* Return the actual framerate */
i = get_fr_idx(gspca_dev);
{
struct sd *sd = (struct sd *) gspca_dev;
- if (sd->sensor == SENSOR_SOI763A)
- jpeg_set_qual(sd->jpeg_hdr, jcomp->quality);
-/* else
- fixme: TODO
-*/
- return gspca_dev->usb_err;
+ if (sd->sensor != SENSOR_SOI763A)
+ return -ENOTTY;
+ v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
+ return 0;
}
static int sd_get_jcomp(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor != SENSOR_SOI763A)
+ return -ENOTTY;
memset(jcomp, 0, sizeof *jcomp);
- jcomp->quality = jpeg_q[sd->quality];
+ jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
| V4L2_JPEG_MARKER_DQT;
return 0;
}
-static struct ctrl sd_ctrls[NCTRLS] = {
-[EXPOSURE] = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0x01,
- .maximum = 0xdc,
- .step = 1,
- .default_value = 0x4e,
- },
- .set_control = setexposure
- },
-[QUALITY] = {
- {
- .id = V4L2_CID_PRIVATE_BASE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Compression quality",
- .minimum = 0,
- .maximum = 15,
- .step = 1,
- .default_value = 13,
- },
- .set_control = setquality
- },
-[RGAIN] = {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red balance",
- .minimum = 0,
- .maximum = 4095,
- .step = 1,
- .default_value = 256,
- },
- .set_control = setrgain
- },
-[GAIN] = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 4095,
- .step = 1,
- .default_value = 256,
- },
- .set = sd_setgain
- },
-[BGAIN] = {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue balance",
- .minimum = 0,
- .maximum = 4095,
- .step = 1,
- .default_value = 256,
- },
- .set_control = setbgain
- },
-[SHARPNESS] = {
- {
- .id = V4L2_CID_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sharpness",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 2,
- },
- .set_control = setsharpness
- },
-[GAMMA] = {
- {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 0,
- .maximum = NGAMMA - 1,
- .step = 1,
- .default_value = 1,
- },
- .set_control = setgamma
- },
-[AUTOGAIN] = {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = AUTOGAIN_DEF
- },
- .set_control = setautogain
- },
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *)gspca_dev;
+
+ gspca_dev->usb_err = 0;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_SHARPNESS:
+ setsharpness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAMMA:
+ setgamma(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ setbgain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ setrgain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ sd_setgain(gspca_dev);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if (ctrl->val)
+ break;
+ sd_setgain(gspca_dev);
+ break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ jpeg_set_qual(sd->jpeg_hdr, ctrl->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
};
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *)gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 1, 0xdc, 1, 0x4e);
+ if (sd->sensor == SENSOR_CX0342) {
+ sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 4095, 1, 256);
+ sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 4095, 1, 256);
+ }
+ if (sd->sensor == SENSOR_SOI763A)
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 0, 15, 1, 3);
+ else
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 0, 4095, 1, 256);
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 3, 1, 2);
+ sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAMMA, 0, NGAMMA - 1, 1,
+ (sd->sensor == SENSOR_SOI763A &&
+ sd->bridge == BRIDGE_TP6800) ? 0 : 1);
+ if (sd->bridge == BRIDGE_TP6810)
+ gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ if (sd->sensor == SENSOR_SOI763A)
+ sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ 0, 15, 1, (sd->bridge == BRIDGE_TP6810) ? 0 : 13);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ if (gspca_dev->autogain)
+ v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
+ else
+ v4l2_ctrl_cluster(2, &gspca_dev->exposure);
+ return 0;
+}
+
static const struct sd_desc sd_desc = {
.name = KBUILD_MODNAME,
- .ctrls = sd_ctrls,
- .nctrls = NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,