Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3e0ed009 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

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

parent 1bdee422
Loading
Loading
Loading
Loading
+133 −305
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@
#define MR97310A_CS_GAIN_MAX		0x7ff
#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_MAX	8
#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 */
struct sd {
	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 cam_type;	/* 0 is CIF and 1 is VGA */
	u8 sensor_type;	/* We use 0 and 1 here, too. */
	u8 do_lcd_stop;
	u8 adj_colors;

	int brightness;
	u16 exposure;
	u32 gain;
	u8 contrast;
	u8 min_clockdiv;
};

struct sensor_w_data {
@@ -105,132 +104,6 @@ struct sensor_w_data {
};

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[] = {
	{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 cam *cam;
	int gain_default = MR97310A_GAIN_DEFAULT;
	int err_code;

	cam = &gspca_dev->cam;
@@ -615,52 +487,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
		       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;
}

@@ -952,11 +778,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
	if (err_code < 0)
		return err_code;

	setbrightness(gspca_dev);
	setcontrast(gspca_dev);
	setexposure(gspca_dev);
	setgain(gspca_dev);

	return isoc_enable(gspca_dev);
}

@@ -971,37 +792,25 @@ static void sd_stopN(struct gspca_dev *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;
	u8 val;
	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 */
	static const u8 quick_clix_table[] =
	/*	  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};
	/*
	 * 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) {
		sign_reg += 4;
		value_reg += 4;
	}

	/* 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);
		val = sd->brightness;
	} else {
		sensor_write1(gspca_dev, sign_reg, 0x01);
		val = (257 - sd->brightness);
		val = 257 - val;
	}
	/* Use lookup table for funky Argus QuickClix brightness */
	if (sd->do_lcd_stop)
@@ -1010,23 +819,20 @@ static void setbrightness(struct gspca_dev *gspca_dev)
	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;
	int exposure = MR97310A_EXPOSURE_DEFAULT;
	u8 buf[2];

	if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
		return;

	if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
		/* This cam does not like exposure settings < 300,
		   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, 4, exposure & 0x0f);
	} else if (sd->sensor_type == 2) {
		exposure = sd->exposure;
		exposure = expo;
		exposure >>= 3;
		sensor_write1(gspca_dev, 3, exposure >> 8);
		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
		   milliseconds exposure time */
		u8 clockdiv = (60 * sd->exposure + 7999) / 8000;
		u8 clockdiv = (60 * expo + 7999) / 8000;

		/* Limit framerate to not exceed usb bandwidth */
		if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320)
			clockdiv = sd->min_clockdiv;
		if (clockdiv < min_clockdiv && gspca_dev->width >= 320)
			clockdiv = min_clockdiv;
		else if (clockdiv < 2)
			clockdiv = 2;

@@ -1051,7 +857,7 @@ static void setexposure(struct gspca_dev *gspca_dev)

		/* Frame exposure time in ms = 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)
			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;
	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)
		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)
		for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
			sensor_write1(gspca_dev, gainreg, sd->gain >> 8);
			sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff);
			sensor_write1(gspca_dev, gainreg, val >> 8);
			sensor_write1(gspca_dev, gainreg + 1, val & 0xff);
		}
	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;

	if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX))
		return;

	sensor_write1(gspca_dev, 0x1c, sd->contrast);
	sensor_write1(gspca_dev, 0x1c, val);
}


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;

	sd->brightness = val;
	if (gspca_dev->streaming)
		setbrightness(gspca_dev);
	return 0;
}
	gspca_dev->usb_err = 0;

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_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);
	if (!gspca_dev->streaming)
		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;
	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;
	}

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;
	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 const struct v4l2_ctrl_ops sd_ctrl_ops = {
	.s_ctrl = sd_s_ctrl,
};

static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
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 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;

	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;
	gspca_dev->vdev.ctrl_handler = hdl;
	v4l2_ctrl_handler_init(hdl, 4);

	*val = sd->contrast;
	return 0;
	/* 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_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;
	/* 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. */
	/*
	 * 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);

	if (hdl->error) {
		pr_err("Could not initialize controls\n");
		return hdl->error;
	}

static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	*val = sd->min_clockdiv;
	if (has_exposure && has_clockdiv)
		v4l2_ctrl_cluster(2, &sd->exposure);
	return 0;
}

@@ -1221,10 +1050,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* 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,
	.pkt_scan = sd_pkt_scan,