mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-26 20:44:32 +08:00
[media] gspca-mr97310a: 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:
parent
1bdee422cd
commit
3e0ed00903
@ -67,6 +67,7 @@
|
|||||||
#define MR97310A_CS_GAIN_MAX 0x7ff
|
#define MR97310A_CS_GAIN_MAX 0x7ff
|
||||||
#define MR97310A_CS_GAIN_DEFAULT 0x110
|
#define MR97310A_CS_GAIN_DEFAULT 0x110
|
||||||
|
|
||||||
|
#define MR97310A_CID_CLOCKDIV (V4L2_CTRL_CLASS_USER + 0x1000)
|
||||||
#define MR97310A_MIN_CLOCKDIV_MIN 3
|
#define MR97310A_MIN_CLOCKDIV_MIN 3
|
||||||
#define MR97310A_MIN_CLOCKDIV_MAX 8
|
#define MR97310A_MIN_CLOCKDIV_MAX 8
|
||||||
#define MR97310A_MIN_CLOCKDIV_DEFAULT 3
|
#define MR97310A_MIN_CLOCKDIV_DEFAULT 3
|
||||||
@ -84,17 +85,15 @@ MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");
|
|||||||
/* specific webcam descriptor */
|
/* specific webcam descriptor */
|
||||||
struct sd {
|
struct sd {
|
||||||
struct gspca_dev gspca_dev; /* !! must be the first item */
|
struct gspca_dev gspca_dev; /* !! must be the first item */
|
||||||
|
struct { /* exposure/min_clockdiv control cluster */
|
||||||
|
struct v4l2_ctrl *exposure;
|
||||||
|
struct v4l2_ctrl *min_clockdiv;
|
||||||
|
};
|
||||||
u8 sof_read;
|
u8 sof_read;
|
||||||
u8 cam_type; /* 0 is CIF and 1 is VGA */
|
u8 cam_type; /* 0 is CIF and 1 is VGA */
|
||||||
u8 sensor_type; /* We use 0 and 1 here, too. */
|
u8 sensor_type; /* We use 0 and 1 here, too. */
|
||||||
u8 do_lcd_stop;
|
u8 do_lcd_stop;
|
||||||
u8 adj_colors;
|
u8 adj_colors;
|
||||||
|
|
||||||
int brightness;
|
|
||||||
u16 exposure;
|
|
||||||
u32 gain;
|
|
||||||
u8 contrast;
|
|
||||||
u8 min_clockdiv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sensor_w_data {
|
struct sensor_w_data {
|
||||||
@ -105,132 +104,6 @@ struct sensor_w_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void sd_stopN(struct gspca_dev *gspca_dev);
|
static void sd_stopN(struct gspca_dev *gspca_dev);
|
||||||
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_setexposure(struct gspca_dev *gspca_dev, __s32 val);
|
|
||||||
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
|
|
||||||
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
|
|
||||||
static int sd_setcontrast(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_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val);
|
|
||||||
static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val);
|
|
||||||
static void setbrightness(struct gspca_dev *gspca_dev);
|
|
||||||
static void setexposure(struct gspca_dev *gspca_dev);
|
|
||||||
static void setgain(struct gspca_dev *gspca_dev);
|
|
||||||
static void setcontrast(struct gspca_dev *gspca_dev);
|
|
||||||
|
|
||||||
/* V4L2 controls supported by the driver */
|
|
||||||
static const struct ctrl sd_ctrls[] = {
|
|
||||||
/* Separate brightness control description for Argus QuickClix as it has
|
|
||||||
* different limits from the other mr97310a cameras, and separate gain
|
|
||||||
* control for Sakar CyberPix camera. */
|
|
||||||
{
|
|
||||||
#define NORM_BRIGHTNESS_IDX 0
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_BRIGHTNESS,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Brightness",
|
|
||||||
.minimum = -254,
|
|
||||||
.maximum = 255,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_BRIGHTNESS_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setbrightness,
|
|
||||||
.get = sd_getbrightness,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
#define ARGUS_QC_BRIGHTNESS_IDX 1
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_BRIGHTNESS,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Brightness",
|
|
||||||
.minimum = 0,
|
|
||||||
.maximum = 15,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_BRIGHTNESS_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setbrightness,
|
|
||||||
.get = sd_getbrightness,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
#define EXPOSURE_IDX 2
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_EXPOSURE,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Exposure",
|
|
||||||
.minimum = MR97310A_EXPOSURE_MIN,
|
|
||||||
.maximum = MR97310A_EXPOSURE_MAX,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_EXPOSURE_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setexposure,
|
|
||||||
.get = sd_getexposure,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
#define GAIN_IDX 3
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_GAIN,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Gain",
|
|
||||||
.minimum = MR97310A_GAIN_MIN,
|
|
||||||
.maximum = MR97310A_GAIN_MAX,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_GAIN_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setgain,
|
|
||||||
.get = sd_getgain,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
#define SAKAR_CS_GAIN_IDX 4
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_GAIN,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Gain",
|
|
||||||
.minimum = MR97310A_CS_GAIN_MIN,
|
|
||||||
.maximum = MR97310A_CS_GAIN_MAX,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_CS_GAIN_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setgain,
|
|
||||||
.get = sd_getgain,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
#define CONTRAST_IDX 5
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_CONTRAST,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Contrast",
|
|
||||||
.minimum = MR97310A_CONTRAST_MIN,
|
|
||||||
.maximum = MR97310A_CONTRAST_MAX,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_CONTRAST_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setcontrast,
|
|
||||||
.get = sd_getcontrast,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
#define MIN_CLOCKDIV_IDX 6
|
|
||||||
{
|
|
||||||
.id = V4L2_CID_PRIVATE_BASE,
|
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
|
||||||
.name = "Minimum Clock Divider",
|
|
||||||
.minimum = MR97310A_MIN_CLOCKDIV_MIN,
|
|
||||||
.maximum = MR97310A_MIN_CLOCKDIV_MAX,
|
|
||||||
.step = 1,
|
|
||||||
.default_value = MR97310A_MIN_CLOCKDIV_DEFAULT,
|
|
||||||
.flags = 0,
|
|
||||||
},
|
|
||||||
.set = sd_setmin_clockdiv,
|
|
||||||
.get = sd_getmin_clockdiv,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct v4l2_pix_format vga_mode[] = {
|
static const struct v4l2_pix_format vga_mode[] = {
|
||||||
{160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
|
{160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
|
||||||
@ -481,7 +354,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
struct cam *cam;
|
struct cam *cam;
|
||||||
int gain_default = MR97310A_GAIN_DEFAULT;
|
|
||||||
int err_code;
|
int err_code;
|
||||||
|
|
||||||
cam = &gspca_dev->cam;
|
cam = &gspca_dev->cam;
|
||||||
@ -615,52 +487,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
|
|||||||
sd->sensor_type);
|
sd->sensor_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup controls depending on camera type */
|
|
||||||
if (sd->cam_type == CAM_TYPE_CIF) {
|
|
||||||
/* No brightness for sensor_type 0 */
|
|
||||||
if (sd->sensor_type == 0)
|
|
||||||
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
|
|
||||||
(1 << ARGUS_QC_BRIGHTNESS_IDX) |
|
|
||||||
(1 << CONTRAST_IDX) |
|
|
||||||
(1 << SAKAR_CS_GAIN_IDX);
|
|
||||||
else
|
|
||||||
gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
|
|
||||||
(1 << CONTRAST_IDX) |
|
|
||||||
(1 << SAKAR_CS_GAIN_IDX) |
|
|
||||||
(1 << MIN_CLOCKDIV_IDX);
|
|
||||||
} else {
|
|
||||||
/* All controls need to be disabled if VGA sensor_type is 0 */
|
|
||||||
if (sd->sensor_type == 0)
|
|
||||||
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
|
|
||||||
(1 << ARGUS_QC_BRIGHTNESS_IDX) |
|
|
||||||
(1 << EXPOSURE_IDX) |
|
|
||||||
(1 << GAIN_IDX) |
|
|
||||||
(1 << CONTRAST_IDX) |
|
|
||||||
(1 << SAKAR_CS_GAIN_IDX) |
|
|
||||||
(1 << MIN_CLOCKDIV_IDX);
|
|
||||||
else if (sd->sensor_type == 2) {
|
|
||||||
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
|
|
||||||
(1 << ARGUS_QC_BRIGHTNESS_IDX) |
|
|
||||||
(1 << GAIN_IDX) |
|
|
||||||
(1 << MIN_CLOCKDIV_IDX);
|
|
||||||
gain_default = MR97310A_CS_GAIN_DEFAULT;
|
|
||||||
} else if (sd->do_lcd_stop)
|
|
||||||
/* Argus QuickClix has different brightness limits */
|
|
||||||
gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) |
|
|
||||||
(1 << CONTRAST_IDX) |
|
|
||||||
(1 << SAKAR_CS_GAIN_IDX);
|
|
||||||
else
|
|
||||||
gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) |
|
|
||||||
(1 << CONTRAST_IDX) |
|
|
||||||
(1 << SAKAR_CS_GAIN_IDX);
|
|
||||||
}
|
|
||||||
|
|
||||||
sd->brightness = MR97310A_BRIGHTNESS_DEFAULT;
|
|
||||||
sd->exposure = MR97310A_EXPOSURE_DEFAULT;
|
|
||||||
sd->gain = gain_default;
|
|
||||||
sd->contrast = MR97310A_CONTRAST_DEFAULT;
|
|
||||||
sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,11 +778,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
|
|||||||
if (err_code < 0)
|
if (err_code < 0)
|
||||||
return err_code;
|
return err_code;
|
||||||
|
|
||||||
setbrightness(gspca_dev);
|
|
||||||
setcontrast(gspca_dev);
|
|
||||||
setexposure(gspca_dev);
|
|
||||||
setgain(gspca_dev);
|
|
||||||
|
|
||||||
return isoc_enable(gspca_dev);
|
return isoc_enable(gspca_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,37 +792,25 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
|
|||||||
lcd_stop(gspca_dev);
|
lcd_stop(gspca_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setbrightness(struct gspca_dev *gspca_dev)
|
static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
u8 val;
|
|
||||||
u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */
|
u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */
|
||||||
u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
|
u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
|
||||||
static const u8 quick_clix_table[] =
|
static const u8 quick_clix_table[] =
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
|
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
|
||||||
{ 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15};
|
{ 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15};
|
||||||
/*
|
|
||||||
* This control is disabled for CIF type 1 and VGA type 0 cameras.
|
|
||||||
* It does not quite act linearly for the Argus QuickClix camera,
|
|
||||||
* but it does control brightness. The values are 0 - 15 only, and
|
|
||||||
* the table above makes them act consecutively.
|
|
||||||
*/
|
|
||||||
if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) &&
|
|
||||||
(gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sd->cam_type == CAM_TYPE_VGA) {
|
if (sd->cam_type == CAM_TYPE_VGA) {
|
||||||
sign_reg += 4;
|
sign_reg += 4;
|
||||||
value_reg += 4;
|
value_reg += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
|
/* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
|
||||||
if (sd->brightness > 0) {
|
if (val > 0) {
|
||||||
sensor_write1(gspca_dev, sign_reg, 0x00);
|
sensor_write1(gspca_dev, sign_reg, 0x00);
|
||||||
val = sd->brightness;
|
|
||||||
} else {
|
} else {
|
||||||
sensor_write1(gspca_dev, sign_reg, 0x01);
|
sensor_write1(gspca_dev, sign_reg, 0x01);
|
||||||
val = (257 - sd->brightness);
|
val = 257 - val;
|
||||||
}
|
}
|
||||||
/* Use lookup table for funky Argus QuickClix brightness */
|
/* Use lookup table for funky Argus QuickClix brightness */
|
||||||
if (sd->do_lcd_stop)
|
if (sd->do_lcd_stop)
|
||||||
@ -1010,23 +819,20 @@ static void setbrightness(struct gspca_dev *gspca_dev)
|
|||||||
sensor_write1(gspca_dev, value_reg, val);
|
sensor_write1(gspca_dev, value_reg, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setexposure(struct gspca_dev *gspca_dev)
|
static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
int exposure = MR97310A_EXPOSURE_DEFAULT;
|
int exposure = MR97310A_EXPOSURE_DEFAULT;
|
||||||
u8 buf[2];
|
u8 buf[2];
|
||||||
|
|
||||||
if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
|
if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
|
||||||
/* This cam does not like exposure settings < 300,
|
/* This cam does not like exposure settings < 300,
|
||||||
so scale 0 - 4095 to 300 - 4095 */
|
so scale 0 - 4095 to 300 - 4095 */
|
||||||
exposure = (sd->exposure * 9267) / 10000 + 300;
|
exposure = (expo * 9267) / 10000 + 300;
|
||||||
sensor_write1(gspca_dev, 3, exposure >> 4);
|
sensor_write1(gspca_dev, 3, exposure >> 4);
|
||||||
sensor_write1(gspca_dev, 4, exposure & 0x0f);
|
sensor_write1(gspca_dev, 4, exposure & 0x0f);
|
||||||
} else if (sd->sensor_type == 2) {
|
} else if (sd->sensor_type == 2) {
|
||||||
exposure = sd->exposure;
|
exposure = expo;
|
||||||
exposure >>= 3;
|
exposure >>= 3;
|
||||||
sensor_write1(gspca_dev, 3, exposure >> 8);
|
sensor_write1(gspca_dev, 3, exposure >> 8);
|
||||||
sensor_write1(gspca_dev, 4, exposure & 0xff);
|
sensor_write1(gspca_dev, 4, exposure & 0xff);
|
||||||
@ -1038,11 +844,11 @@ static void setexposure(struct gspca_dev *gspca_dev)
|
|||||||
|
|
||||||
Note our 0 - 4095 exposure is mapped to 0 - 511
|
Note our 0 - 4095 exposure is mapped to 0 - 511
|
||||||
milliseconds exposure time */
|
milliseconds exposure time */
|
||||||
u8 clockdiv = (60 * sd->exposure + 7999) / 8000;
|
u8 clockdiv = (60 * expo + 7999) / 8000;
|
||||||
|
|
||||||
/* Limit framerate to not exceed usb bandwidth */
|
/* Limit framerate to not exceed usb bandwidth */
|
||||||
if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320)
|
if (clockdiv < min_clockdiv && gspca_dev->width >= 320)
|
||||||
clockdiv = sd->min_clockdiv;
|
clockdiv = min_clockdiv;
|
||||||
else if (clockdiv < 2)
|
else if (clockdiv < 2)
|
||||||
clockdiv = 2;
|
clockdiv = 2;
|
||||||
|
|
||||||
@ -1051,7 +857,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
|
|||||||
|
|
||||||
/* Frame exposure time in ms = 1000 * clockdiv / 60 ->
|
/* Frame exposure time in ms = 1000 * clockdiv / 60 ->
|
||||||
exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
|
exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
|
||||||
exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv);
|
exposure = (60 * 511 * expo) / (8000 * clockdiv);
|
||||||
if (exposure > 511)
|
if (exposure > 511)
|
||||||
exposure = 511;
|
exposure = 511;
|
||||||
|
|
||||||
@ -1065,125 +871,148 @@ static void setexposure(struct gspca_dev *gspca_dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setgain(struct gspca_dev *gspca_dev)
|
static void setgain(struct gspca_dev *gspca_dev, s32 val)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
u8 gainreg;
|
u8 gainreg;
|
||||||
|
|
||||||
if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) &&
|
|
||||||
(gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1)
|
if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1)
|
||||||
sensor_write1(gspca_dev, 0x0e, sd->gain);
|
sensor_write1(gspca_dev, 0x0e, val);
|
||||||
else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2)
|
else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2)
|
||||||
for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
|
for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
|
||||||
sensor_write1(gspca_dev, gainreg, sd->gain >> 8);
|
sensor_write1(gspca_dev, gainreg, val >> 8);
|
||||||
sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff);
|
sensor_write1(gspca_dev, gainreg + 1, val & 0xff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sensor_write1(gspca_dev, 0x10, sd->gain);
|
sensor_write1(gspca_dev, 0x10, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setcontrast(struct gspca_dev *gspca_dev)
|
static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
sensor_write1(gspca_dev, 0x1c, val);
|
||||||
|
|
||||||
if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX))
|
|
||||||
return;
|
|
||||||
|
|
||||||
sensor_write1(gspca_dev, 0x1c, sd->contrast);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
|
|
||||||
{
|
{
|
||||||
|
struct gspca_dev *gspca_dev =
|
||||||
|
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
|
||||||
struct sd *sd = (struct sd *)gspca_dev;
|
struct sd *sd = (struct sd *)gspca_dev;
|
||||||
|
|
||||||
sd->brightness = val;
|
gspca_dev->usb_err = 0;
|
||||||
if (gspca_dev->streaming)
|
|
||||||
setbrightness(gspca_dev);
|
if (!gspca_dev->streaming)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
switch (ctrl->id) {
|
||||||
|
case V4L2_CID_BRIGHTNESS:
|
||||||
|
setbrightness(gspca_dev, ctrl->val);
|
||||||
|
break;
|
||||||
|
case V4L2_CID_CONTRAST:
|
||||||
|
setcontrast(gspca_dev, ctrl->val);
|
||||||
|
break;
|
||||||
|
case V4L2_CID_EXPOSURE:
|
||||||
|
setexposure(gspca_dev, sd->exposure->val,
|
||||||
|
sd->min_clockdiv ? sd->min_clockdiv->val : 0);
|
||||||
|
break;
|
||||||
|
case V4L2_CID_GAIN:
|
||||||
|
setgain(gspca_dev, ctrl->val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return gspca_dev->usb_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sd_getbrightness(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 sd *sd = (struct sd *)gspca_dev;
|
||||||
|
struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
|
||||||
|
static const struct v4l2_ctrl_config clockdiv = {
|
||||||
|
.ops = &sd_ctrl_ops,
|
||||||
|
.id = MR97310A_CID_CLOCKDIV,
|
||||||
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
|
.name = "Minimum Clock Divider",
|
||||||
|
.min = MR97310A_MIN_CLOCKDIV_MIN,
|
||||||
|
.max = MR97310A_MIN_CLOCKDIV_MAX,
|
||||||
|
.step = 1,
|
||||||
|
.def = MR97310A_MIN_CLOCKDIV_DEFAULT,
|
||||||
|
};
|
||||||
|
bool has_brightness = false;
|
||||||
|
bool has_argus_brightness = false;
|
||||||
|
bool has_contrast = false;
|
||||||
|
bool has_gain = false;
|
||||||
|
bool has_cs_gain = false;
|
||||||
|
bool has_exposure = false;
|
||||||
|
bool has_clockdiv = false;
|
||||||
|
|
||||||
*val = sd->brightness;
|
gspca_dev->vdev.ctrl_handler = hdl;
|
||||||
return 0;
|
v4l2_ctrl_handler_init(hdl, 4);
|
||||||
|
|
||||||
|
/* Setup controls depending on camera type */
|
||||||
|
if (sd->cam_type == CAM_TYPE_CIF) {
|
||||||
|
/* No brightness for sensor_type 0 */
|
||||||
|
if (sd->sensor_type == 0)
|
||||||
|
has_exposure = has_gain = has_clockdiv = true;
|
||||||
|
else
|
||||||
|
has_exposure = has_gain = has_brightness = true;
|
||||||
|
} else {
|
||||||
|
/* All controls need to be disabled if VGA sensor_type is 0 */
|
||||||
|
if (sd->sensor_type == 0)
|
||||||
|
; /* no controls! */
|
||||||
|
else if (sd->sensor_type == 2)
|
||||||
|
has_exposure = has_cs_gain = has_contrast = true;
|
||||||
|
else if (sd->do_lcd_stop)
|
||||||
|
has_exposure = has_gain = has_argus_brightness =
|
||||||
|
has_clockdiv = true;
|
||||||
|
else
|
||||||
|
has_exposure = has_gain = has_brightness =
|
||||||
|
has_clockdiv = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
|
/* Separate brightness control description for Argus QuickClix as it has
|
||||||
{
|
* different limits from the other mr97310a cameras, and separate gain
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
* control for Sakar CyberPix camera. */
|
||||||
|
/*
|
||||||
|
* This control is disabled for CIF type 1 and VGA type 0 cameras.
|
||||||
|
* It does not quite act linearly for the Argus QuickClix camera,
|
||||||
|
* but it does control brightness. The values are 0 - 15 only, and
|
||||||
|
* the table above makes them act consecutively.
|
||||||
|
*/
|
||||||
|
if (has_brightness)
|
||||||
|
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
|
||||||
|
V4L2_CID_BRIGHTNESS, -254, 255, 1,
|
||||||
|
MR97310A_BRIGHTNESS_DEFAULT);
|
||||||
|
else if (has_argus_brightness)
|
||||||
|
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
|
||||||
|
V4L2_CID_BRIGHTNESS, 0, 15, 1,
|
||||||
|
MR97310A_BRIGHTNESS_DEFAULT);
|
||||||
|
if (has_contrast)
|
||||||
|
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
|
||||||
|
V4L2_CID_CONTRAST, MR97310A_CONTRAST_MIN,
|
||||||
|
MR97310A_CONTRAST_MAX, 1, MR97310A_CONTRAST_DEFAULT);
|
||||||
|
if (has_gain)
|
||||||
|
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
|
||||||
|
V4L2_CID_GAIN, MR97310A_GAIN_MIN, MR97310A_GAIN_MAX,
|
||||||
|
1, MR97310A_GAIN_DEFAULT);
|
||||||
|
else if (has_cs_gain)
|
||||||
|
v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAIN,
|
||||||
|
MR97310A_CS_GAIN_MIN, MR97310A_CS_GAIN_MAX,
|
||||||
|
1, MR97310A_CS_GAIN_DEFAULT);
|
||||||
|
if (has_exposure)
|
||||||
|
sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
|
||||||
|
V4L2_CID_EXPOSURE, MR97310A_EXPOSURE_MIN,
|
||||||
|
MR97310A_EXPOSURE_MAX, 1, MR97310A_EXPOSURE_DEFAULT);
|
||||||
|
if (has_clockdiv)
|
||||||
|
sd->min_clockdiv = v4l2_ctrl_new_custom(hdl, &clockdiv, NULL);
|
||||||
|
|
||||||
sd->exposure = val;
|
if (hdl->error) {
|
||||||
if (gspca_dev->streaming)
|
pr_err("Could not initialize controls\n");
|
||||||
setexposure(gspca_dev);
|
return hdl->error;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
if (has_exposure && has_clockdiv)
|
||||||
static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
|
v4l2_ctrl_cluster(2, &sd->exposure);
|
||||||
{
|
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
|
||||||
|
|
||||||
*val = sd->exposure;
|
|
||||||
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_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);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val)
|
|
||||||
{
|
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
|
||||||
|
|
||||||
sd->min_clockdiv = val;
|
|
||||||
if (gspca_dev->streaming)
|
|
||||||
setexposure(gspca_dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val)
|
|
||||||
{
|
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
|
||||||
|
|
||||||
*val = sd->min_clockdiv;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1221,10 +1050,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
|
|||||||
/* sub-driver description */
|
/* sub-driver description */
|
||||||
static const struct sd_desc sd_desc = {
|
static const struct sd_desc sd_desc = {
|
||||||
.name = MODULE_NAME,
|
.name = MODULE_NAME,
|
||||||
.ctrls = sd_ctrls,
|
|
||||||
.nctrls = ARRAY_SIZE(sd_ctrls),
|
|
||||||
.config = sd_config,
|
.config = sd_config,
|
||||||
.init = sd_init,
|
.init = sd_init,
|
||||||
|
.init_controls = sd_init_controls,
|
||||||
.start = sd_start,
|
.start = sd_start,
|
||||||
.stopN = sd_stopN,
|
.stopN = sd_stopN,
|
||||||
.pkt_scan = sd_pkt_scan,
|
.pkt_scan = sd_pkt_scan,
|
||||||
|
Loading…
Reference in New Issue
Block a user