[media] gspca-cpia1: convert to the control framework

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Hans Verkuil 2012-05-14 04:54:13 -03:00 committed by Mauro Carvalho Chehab
parent cbc1c94cc5
commit 1bfea3e49d
1 changed files with 134 additions and 365 deletions

View File

@ -225,6 +225,15 @@ MODULE_LICENSE("GPL");
#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \
sd->params.version.firmwareRevision == (y))
#define CPIA1_CID_COMP_TARGET (V4L2_CTRL_CLASS_USER + 0x1000)
#define BRIGHTNESS_DEF 50
#define CONTRAST_DEF 48
#define SATURATION_DEF 50
#define FREQ_DEF V4L2_CID_POWER_LINE_FREQUENCY_50HZ
#define ILLUMINATORS_1_DEF 0
#define ILLUMINATORS_2_DEF 0
#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY
/* Developer's Guide Table 5 p 3-34
* indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
static u8 flicker_jumps[2][2][4] =
@ -360,135 +369,9 @@ struct sd {
atomic_t fps;
int exposure_count;
u8 exposure_status;
struct v4l2_ctrl *freq;
u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */
u8 first_frame;
u8 freq;
};
/* 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_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val);
static const struct ctrl sd_ctrls[] = {
{
#define BRIGHTNESS_IDX 0
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
.maximum = 100,
.step = 1,
#define BRIGHTNESS_DEF 50
.default_value = BRIGHTNESS_DEF,
.flags = 0,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
#define CONTRAST_IDX 1
{
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
.maximum = 96,
.step = 8,
#define CONTRAST_DEF 48
.default_value = CONTRAST_DEF,
},
.set = sd_setcontrast,
.get = sd_getcontrast,
},
#define SATURATION_IDX 2
{
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Saturation",
.minimum = 0,
.maximum = 100,
.step = 1,
#define SATURATION_DEF 50
.default_value = SATURATION_DEF,
},
.set = sd_setsaturation,
.get = sd_getsaturation,
},
#define POWER_LINE_FREQUENCY_IDX 3
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Light frequency filter",
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
#define FREQ_DEF 1
.default_value = FREQ_DEF,
},
.set = sd_setfreq,
.get = sd_getfreq,
},
#define ILLUMINATORS_1_IDX 4
{
{
.id = V4L2_CID_ILLUMINATORS_1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Illuminator 1",
.minimum = 0,
.maximum = 1,
.step = 1,
#define ILLUMINATORS_1_DEF 0
.default_value = ILLUMINATORS_1_DEF,
},
.set = sd_setilluminator1,
.get = sd_getilluminator1,
},
#define ILLUMINATORS_2_IDX 5
{
{
.id = V4L2_CID_ILLUMINATORS_2,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Illuminator 2",
.minimum = 0,
.maximum = 1,
.step = 1,
#define ILLUMINATORS_2_DEF 0
.default_value = ILLUMINATORS_2_DEF,
},
.set = sd_setilluminator2,
.get = sd_getilluminator2,
},
#define COMP_TARGET_IDX 6
{
{
#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE
.id = V4L2_CID_COMP_TARGET,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Compression Target",
.minimum = 0,
.maximum = 1,
.step = 1,
#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY
.default_value = COMP_TARGET_DEF,
},
.set = sd_setcomptarget,
.get = sd_getcomptarget,
},
};
static const struct v4l2_pix_format mode[] = {
@ -770,15 +653,6 @@ static void reset_camera_params(struct gspca_dev *gspca_dev)
params->apcor.gain2 = 0x16;
params->apcor.gain4 = 0x24;
params->apcor.gain8 = 0x34;
params->flickerControl.flickerMode = 0;
params->flickerControl.disabled = 1;
params->flickerControl.coarseJump =
flicker_jumps[sd->mainsFreq]
[params->sensorFps.baserate]
[params->sensorFps.divisor];
params->flickerControl.allowableOverExposure =
find_over_exposure(params->colourParams.brightness);
params->vlOffset.gain1 = 20;
params->vlOffset.gain2 = 24;
params->vlOffset.gain4 = 26;
@ -798,6 +672,15 @@ static void reset_camera_params(struct gspca_dev *gspca_dev)
params->sensorFps.divisor = 1;
params->sensorFps.baserate = 1;
params->flickerControl.flickerMode = 0;
params->flickerControl.disabled = 1;
params->flickerControl.coarseJump =
flicker_jumps[sd->mainsFreq]
[params->sensorFps.baserate]
[params->sensorFps.divisor];
params->flickerControl.allowableOverExposure =
find_over_exposure(params->colourParams.brightness);
params->yuvThreshold.yThreshold = 6; /* From windows driver */
params->yuvThreshold.uvThreshold = 6; /* From windows driver */
@ -1110,9 +993,6 @@ static int command_setlights(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int ret, p1, p2;
if (!sd->params.qx3.qx3_detected)
return 0;
p1 = (sd->params.qx3.bottomlight == 0) << 1;
p2 = (sd->params.qx3.toplight == 0) << 3;
@ -1551,8 +1431,10 @@ static void restart_flicker(struct gspca_dev *gspca_dev)
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
reset_camera_params(gspca_dev);
PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)",
@ -1562,8 +1444,25 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = mode;
cam->nmodes = ARRAY_SIZE(mode);
sd_setfreq(gspca_dev, FREQ_DEF);
goto_low_power(gspca_dev);
/* Check the firmware version. */
sd->params.version.firmwareVersion = 0;
get_version_information(gspca_dev);
if (sd->params.version.firmwareVersion != 1) {
PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",
sd->params.version.firmwareVersion);
return -ENODEV;
}
/* A bug in firmware 1-02 limits gainMode to 2 */
if (sd->params.version.firmwareRevision <= 2 &&
sd->params.exposure.gainMode > 2) {
sd->params.exposure.gainMode = 2;
}
/* set QX3 detected flag */
sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 &&
sd->params.pnpID.product == 0x0001);
return 0;
}
@ -1602,21 +1501,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Check the firmware version. */
sd->params.version.firmwareVersion = 0;
get_version_information(gspca_dev);
if (sd->params.version.firmwareVersion != 1) {
PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",
sd->params.version.firmwareVersion);
return -ENODEV;
}
/* A bug in firmware 1-02 limits gainMode to 2 */
if (sd->params.version.firmwareRevision <= 2 &&
sd->params.exposure.gainMode > 2) {
sd->params.exposure.gainMode = 2;
}
/* set QX3 detected flag */
sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 &&
sd->params.pnpID.product == 0x0001);
/* The fatal error checking should be done after
* the camera powers up (developer's guide p 3-38) */
@ -1785,9 +1669,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
or disable the illuminator controls, if this isn't a QX3 */
if (sd->params.qx3.qx3_detected)
command_setlights(gspca_dev);
else
gspca_dev->ctrl_dis |=
((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX));
sd_stopN(gspca_dev);
@ -1871,235 +1752,123 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev)
do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
}
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
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;
int ret;
sd->params.colourParams.brightness = val;
gspca_dev->usb_err = 0;
if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY)
return 0;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
sd->params.colourParams.brightness = ctrl->val;
sd->params.flickerControl.allowableOverExposure =
find_over_exposure(sd->params.colourParams.brightness);
if (gspca_dev->streaming) {
ret = command_setcolourparams(gspca_dev);
if (ret)
return ret;
return command_setflickerctrl(gspca_dev);
}
return 0;
}
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->params.colourParams.brightness;
return 0;
}
static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->params.colourParams.contrast = val;
if (gspca_dev->streaming)
return command_setcolourparams(gspca_dev);
return 0;
}
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->params.colourParams.contrast;
return 0;
}
static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->params.colourParams.saturation = val;
if (gspca_dev->streaming)
return command_setcolourparams(gspca_dev);
return 0;
}
static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->params.colourParams.saturation;
return 0;
}
static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
int on;
switch (val) {
case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
on = 0;
gspca_dev->usb_err = command_setcolourparams(gspca_dev);
if (!gspca_dev->usb_err)
gspca_dev->usb_err = command_setflickerctrl(gspca_dev);
break;
case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
on = 1;
sd->mainsFreq = 0;
case V4L2_CID_CONTRAST:
sd->params.colourParams.contrast = ctrl->val;
gspca_dev->usb_err = command_setcolourparams(gspca_dev);
break;
case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
on = 1;
sd->mainsFreq = 1;
case V4L2_CID_SATURATION:
sd->params.colourParams.saturation = ctrl->val;
gspca_dev->usb_err = command_setcolourparams(gspca_dev);
break;
default:
return -EINVAL;
}
sd->freq = val;
case V4L2_CID_POWER_LINE_FREQUENCY:
sd->mainsFreq = ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
sd->params.flickerControl.coarseJump =
flicker_jumps[sd->mainsFreq]
[sd->params.sensorFps.baserate]
[sd->params.sensorFps.divisor];
return set_flicker(gspca_dev, on, gspca_dev->streaming);
gspca_dev->usb_err = set_flicker(gspca_dev,
ctrl->val != V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
gspca_dev->streaming);
break;
case V4L2_CID_ILLUMINATORS_1:
sd->params.qx3.bottomlight = ctrl->val;
gspca_dev->usb_err = command_setlights(gspca_dev);
break;
case V4L2_CID_ILLUMINATORS_2:
sd->params.qx3.toplight = ctrl->val;
gspca_dev->usb_err = command_setlights(gspca_dev);
break;
case CPIA1_CID_COMP_TARGET:
sd->params.compressionTarget.frTargeting = ctrl->val;
gspca_dev->usb_err = command_setcompressiontarget(gspca_dev);
break;
}
return gspca_dev->usb_err;
}
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
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;
static const char * const comp_target_menu[] = {
"Quality",
"Framerate",
NULL
};
static const struct v4l2_ctrl_config comp_target = {
.ops = &sd_ctrl_ops,
.id = CPIA1_CID_COMP_TARGET,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Compression Target",
.qmenu = comp_target_menu,
.max = 1,
.def = COMP_TARGET_DEF,
};
*val = sd->freq;
return 0;
gspca_dev->vdev.ctrl_handler = hdl;
v4l2_ctrl_handler_init(hdl, 7);
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 100, 1, BRIGHTNESS_DEF);
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_CONTRAST, 0, 96, 8, CONTRAST_DEF);
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_SATURATION, 0, 100, 1, SATURATION_DEF);
sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
V4L2_CID_POWER_LINE_FREQUENCY,
V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
FREQ_DEF);
if (sd->params.qx3.qx3_detected) {
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_ILLUMINATORS_1, 0, 1, 1,
ILLUMINATORS_1_DEF);
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_ILLUMINATORS_2, 0, 1, 1,
ILLUMINATORS_2_DEF);
}
v4l2_ctrl_new_custom(hdl, &comp_target, NULL);
static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->params.compressionTarget.frTargeting = val;
if (gspca_dev->streaming)
return command_setcompressiontarget(gspca_dev);
return 0;
}
static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
*val = sd->params.compressionTarget.frTargeting;
return 0;
}
static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n)
{
struct sd *sd = (struct sd *) gspca_dev;
int ret;
if (!sd->params.qx3.qx3_detected)
return -EINVAL;
switch (n) {
case 1:
sd->params.qx3.bottomlight = val ? 1 : 0;
break;
case 2:
sd->params.qx3.toplight = val ? 1 : 0;
break;
default:
return -EINVAL;
}
ret = command_setlights(gspca_dev);
if (ret && ret != -EINVAL)
ret = -EBUSY;
return ret;
}
static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
{
return sd_setilluminator(gspca_dev, val, 1);
}
static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
{
return sd_setilluminator(gspca_dev, val, 2);
}
static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n)
{
struct sd *sd = (struct sd *) gspca_dev;
if (!sd->params.qx3.qx3_detected)
return -EINVAL;
switch (n) {
case 1:
*val = sd->params.qx3.bottomlight;
break;
case 2:
*val = sd->params.qx3.toplight;
break;
default:
return -EINVAL;
if (hdl->error) {
pr_err("Could not initialize controls\n");
return hdl->error;
}
return 0;
}
static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val)
{
return sd_getilluminator(gspca_dev, val, 1);
}
static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val)
{
return sd_getilluminator(gspca_dev, val, 2);
}
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
switch (menu->index) {
case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
strcpy((char *) menu->name, "NoFliker");
return 0;
case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
strcpy((char *) menu->name, "50 Hz");
return 0;
case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
strcpy((char *) menu->name, "60 Hz");
return 0;
}
break;
case V4L2_CID_COMP_TARGET:
switch (menu->index) {
case CPIA_COMPRESSION_TARGET_QUALITY:
strcpy((char *) menu->name, "Quality");
return 0;
case CPIA_COMPRESSION_TARGET_FRAMERATE:
strcpy((char *) menu->name, "Framerate");
return 0;
}
break;
}
return -EINVAL;
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
.init_controls = sd_init_controls,
.start = sd_start,
.stopN = sd_stopN,
.dq_callback = sd_dq_callback,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.other_input = 1,
#endif