MODULE_DESCRIPTION("Pixart PAC7302");
MODULE_LICENSE("GPL");
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ COLORS,
+ WHITE_BALANCE,
+ RED_BALANCE,
+ BLUE_BALANCE,
+ GAIN,
+ AUTOGAIN,
+ EXPOSURE,
+ VFLIP,
+ HFLIP,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor for pac7302 */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
- unsigned char contrast;
- unsigned char colors;
- unsigned char white_balance;
- unsigned char red_balance;
- unsigned char blue_balance;
- unsigned char gain;
- unsigned char autogain;
- unsigned short exposure;
- __u8 hflip;
- __u8 vflip;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 flags;
#define FL_HFLIP 0x01 /* mirrored by default */
#define FL_VFLIP 0x02 /* vertical flipped by default */
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightcont(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setwhitebalance(struct gspca_dev *gspca_dev);
+static void setredbalance(struct gspca_dev *gspca_dev);
+static void setbluebalance(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-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 void sethvflip(struct gspca_dev *gspca_dev);
static const struct ctrl sd_ctrls[] = {
- {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
#define BRIGHTNESS_MAX 0x20
.maximum = BRIGHTNESS_MAX,
.step = 1,
-#define BRIGHTNESS_DEF 0x10
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 0x10,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightcont
},
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
#define CONTRAST_MAX 255
.maximum = CONTRAST_MAX,
.step = 1,
-#define CONTRAST_DEF 127
- .default_value = CONTRAST_DEF,
+ .default_value = 127,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setbrightcont
},
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
#define COLOR_MAX 255
.maximum = COLOR_MAX,
.step = 1,
-#define COLOR_DEF 127
- .default_value = COLOR_DEF,
+ .default_value = 127
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors
},
- {
+[WHITE_BALANCE] = {
{
.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 255,
.step = 1,
-#define WHITEBALANCE_DEF 4
- .default_value = WHITEBALANCE_DEF,
+ .default_value = 4,
},
- .set = sd_setwhitebalance,
- .get = sd_getwhitebalance,
+ .set_control = setwhitebalance
},
- {
+[RED_BALANCE] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 3,
.step = 1,
-#define REDBALANCE_DEF 1
- .default_value = REDBALANCE_DEF,
+ .default_value = 1,
},
- .set = sd_setredbalance,
- .get = sd_getredbalance,
+ .set_control = setredbalance
},
- {
+[BLUE_BALANCE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 3,
.step = 1,
-#define BLUEBALANCE_DEF 1
- .default_value = BLUEBALANCE_DEF,
+ .default_value = 1,
},
- .set = sd_setbluebalance,
- .get = sd_getbluebalance,
+ .set_control = setbluebalance
},
- {
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
-#define GAIN_MAX 255
- .maximum = GAIN_MAX,
+ .maximum = 255,
.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,
+ .set_control = setgain
},
- {
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
.default_value = EXPOSURE_DEF,
},
- .set = sd_setexposure,
- .get = sd_getexposure,
+ .set_control = setexposure
},
- {
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
- .get = sd_getautogain,
},
- {
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEF 0
- .default_value = HFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = sethvflip,
},
- {
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEF 0
- .default_value = VFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = sethvflip
},
};
cam->cam_mode = vga_mode; /* only 640x480 */
cam->nmodes = ARRAY_SIZE(vga_mode);
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->white_balance = WHITEBALANCE_DEF;
- sd->red_balance = REDBALANCE_DEF;
- sd->blue_balance = BLUEBALANCE_DEF;
- sd->gain = GAIN_DEF;
- sd->exposure = EXPOSURE_DEF;
- sd->autogain = AUTOGAIN_DEF;
- sd->hflip = HFLIP_DEF;
- sd->vflip = VFLIP_DEF;
+ gspca_dev->cam.ctrls = sd->ctrls;
+
sd->flags = id->driver_info;
return 0;
}
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 10; i++) {
v = max[i];
- v += (sd->brightness - BRIGHTNESS_MAX)
+ v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
* 150 / BRIGHTNESS_MAX; /* 200 ? */
- v -= delta[i] * sd->contrast / CONTRAST_MAX;
+ v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
if (v < 0)
v = 0;
else if (v > 0xff)
reg_w(gspca_dev, 0x11, 0x01);
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 9; i++) {
- v = a[i] * sd->colors / COLOR_MAX + b[i];
+ v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
}
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc6, sd->white_balance);
+ reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
}
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc5, sd->red_balance);
+ reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
}
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc7, sd->blue_balance);
+ reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
}
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- reg_w(gspca_dev, 0x10, sd->gain >> 3);
+ reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
/* register 2 of frame 3 contains the clock divider configuring the
no fps according to the formula: 90 / reg. sd->exposure is the
desired exposure time in 0.5 ms. */
- clockdiv = (90 * sd->exposure + 1999) / 2000;
+ clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
/* Note clockdiv = 3 also works, but when running at 30 fps, depending
on the scene being recorded, the camera switches to another
/* frame exposure time in ms = 1000 * clockdiv / 90 ->
exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
- exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
+ exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
/* 0 = use full frametime, 448 = no exposure, reverse it */
exposure = 448 - exposure;
struct sd *sd = (struct sd *) gspca_dev;
u8 data, hflip, vflip;
- hflip = sd->hflip;
+ hflip = sd->ctrls[HFLIP].val;
if (sd->flags & FL_HFLIP)
hflip = !hflip;
- vflip = sd->vflip;
+ vflip = sd->ctrls[VFLIP].val;
if (sd->flags & FL_VFLIP)
vflip = !vflip;
/* Include pac common sof detection functions */
#include "pac_common.h"
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt flags
+#define exp_too_high_cnt sof_read
+#include "autogain_functions.h"
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
if (avg_lum == -1)
return;
- desired_lum = 270 + sd->brightness;
+ desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+ else if (auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
deadzone, GAIN_KNEE, EXPOSURE_KNEE))
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightcont(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-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)
- setbrightcont(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming)
- setcolors(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->colors;
- return 0;
-}
-
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->white_balance = val;
- if (gspca_dev->streaming)
- setwhitebalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->white_balance;
- return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->red_balance = val;
- if (gspca_dev->streaming)
- setredbalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->red_balance;
- return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->blue_balance = val;
- if (gspca_dev->streaming)
- setbluebalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->blue_balance;
- 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 gspca_dev->usb_err;
-}
-
-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 gspca_dev->usb_err;
-}
-
-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;
+ sd->ctrls[AUTOGAIN].val = 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 (sd->ctrls[AUTOGAIN].val) {
+ sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
+ sd->ctrls[GAIN].val = GAIN_DEF;
if (gspca_dev->streaming) {
sd->autogain_ignore_frames =
PAC_AUTOGAIN_IGNORE_FRAMES;
return gspca_dev->usb_err;
}
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->hflip;
- return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->vflip;
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)