Linux Media Controller development
 help / color / mirror / Atom feed
* [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2
@ 2015-04-19 18:52 Vasily Khoruzhick
  2015-04-19 18:52 ` [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls " Vasily Khoruzhick
  2015-04-21 14:21 ` [PATCH 1/2] gspca: sn9c2028: Add support for " Hans de Goede
  0 siblings, 2 replies; 7+ messages in thread
From: Vasily Khoruzhick @ 2015-04-19 18:52 UTC (permalink / raw)
  To: Hans de Goede, linux-media, Mauro Carvalho Chehab; +Cc: Vasily Khoruzhick

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/media/usb/gspca/sn9c2028.c | 120 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)

diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
index 39b6b2e..317b02c 100644
--- a/drivers/media/usb/gspca/sn9c2028.c
+++ b/drivers/media/usb/gspca/sn9c2028.c
@@ -2,6 +2,7 @@
  * SN9C2028 library
  *
  * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
+ * Copyright (C) 2015 Vasily Khoruzhick <anarsoul@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -128,7 +129,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
 	status = -1;
 	for (i = 0; i < 256 && status < 2; i++)
 		status = sn9c2028_read1(gspca_dev);
-	if (status != 2) {
+	if (status < 0) {
 		pr_err("long command status read error %d\n", status);
 		return (status < 0) ? status : -EIO;
 	}
@@ -178,6 +179,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
 	case 0x7005:
 		PDEBUG(D_PROBE, "Genius Smart 300 camera");
 		break;
+	case 0x7003:
+		PDEBUG(D_PROBE, "Genius Videocam Live v2");
+		break;
 	case 0x8000:
 		PDEBUG(D_PROBE, "DC31VC");
 		break;
@@ -530,6 +534,116 @@ static int start_genius_cam(struct gspca_dev *gspca_dev)
 				  ARRAY_SIZE(genius_start_commands));
 }
 
+static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
+{
+	int r;
+	struct sd *sd = (struct sd *) gspca_dev;
+	struct init_command genius_vcam_live_start_commands[] = {
+		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0},
+		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
+		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
+
+		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
+		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
+		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
+		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
+		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
+		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
+		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
+		{{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4},
+		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
+		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
+		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
+		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
+		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
+		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
+		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
+		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
+		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
+		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
+		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
+		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
+		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
+		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
+		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
+		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
+		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
+		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
+		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
+		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
+		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
+		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
+		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
+		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0},
+		/* Camera should start to capture now. */
+		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0},
+		{{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0},
+		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
+	};
+
+	r = run_start_commands(gspca_dev, genius_vcam_live_start_commands,
+				  ARRAY_SIZE(genius_vcam_live_start_commands));
+	if (r < 0)
+		return r;
+
+	return r;
+}
+
 static int start_vivitar_cam(struct gspca_dev *gspca_dev)
 {
 	struct init_command vivitar_start_commands[] = {
@@ -623,6 +737,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
 	case 0x7005:
 		err_code = start_genius_cam(gspca_dev);
 		break;
+	case 0x7003:
+		err_code = start_genius_videocam_live(gspca_dev);
+		break;
 	case 0x8001:
 		err_code = start_spy_cam(gspca_dev);
 		break;
@@ -701,6 +818,7 @@ static const struct sd_desc sd_desc = {
 /* -- module initialisation -- */
 static const struct usb_device_id device_table[] = {
 	{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
+	{USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2  */
 	/* The Genius Smart is untested. I can't find an owner ! */
 	/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
 	{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
  2015-04-19 18:52 [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2 Vasily Khoruzhick
@ 2015-04-19 18:52 ` Vasily Khoruzhick
  2015-04-19 21:09   ` Theodore Kilgore
  2015-04-21 14:32   ` Hans de Goede
  2015-04-21 14:21 ` [PATCH 1/2] gspca: sn9c2028: Add support for " Hans de Goede
  1 sibling, 2 replies; 7+ messages in thread
From: Vasily Khoruzhick @ 2015-04-19 18:52 UTC (permalink / raw)
  To: Hans de Goede, linux-media, Mauro Carvalho Chehab; +Cc: Vasily Khoruzhick

Autogain algorithm is very simple, if average luminance is low - increase gain,
if it's high - decrease gain. Gain granularity is low enough for this algo to
stabilize quickly.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/media/usb/gspca/sn9c2028.c | 121 +++++++++++++++++++++++++++++++++++++
 drivers/media/usb/gspca/sn9c2028.h |  20 +++++-
 2 files changed, 138 insertions(+), 3 deletions(-)

diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
index 317b02c..0ff390f 100644
--- a/drivers/media/usb/gspca/sn9c2028.c
+++ b/drivers/media/usb/gspca/sn9c2028.c
@@ -34,6 +34,16 @@ struct sd {
 	struct gspca_dev gspca_dev;  /* !! must be the first item */
 	u8 sof_read;
 	u16 model;
+
+#define MIN_AVG_LUM 8500
+#define MAX_AVG_LUM 10000
+	int avg_lum;
+	u8 avg_lum_l;
+
+	struct { /* autogain and gain control cluster */
+		struct v4l2_ctrl *autogain;
+		struct v4l2_ctrl *gain;
+	};
 };
 
 struct init_command {
@@ -252,6 +262,77 @@ static int run_start_commands(struct gspca_dev *gspca_dev,
 	return 0;
 }
 
+static void set_gain(struct gspca_dev *gspca_dev, s32 g)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	struct init_command genius_vcam_live_gain_cmds[] = {
+		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
+	};
+	if (!gspca_dev->streaming)
+		return;
+
+	switch (sd->model) {
+	case 0x7003:
+		genius_vcam_live_gain_cmds[0].instruction[2] = g;
+		run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,
+				   ARRAY_SIZE(genius_vcam_live_gain_cmds));
+		break;
+	default:
+		break;
+	}
+}
+
+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) {
+	/* standalone gain control */
+	case V4L2_CID_GAIN:
+		set_gain(gspca_dev, ctrl->val);
+		break;
+	/* autogain */
+	case V4L2_CID_AUTOGAIN:
+		set_gain(gspca_dev, sd->gain->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 v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+	struct sd *sd = (struct sd *)gspca_dev;
+
+	gspca_dev->vdev.ctrl_handler = hdl;
+	v4l2_ctrl_handler_init(hdl, 2);
+
+	switch (sd->model) {
+	case 0x7003:
+		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_GAIN, 0, 20, 1, 0);
+		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
 static int start_spy_cam(struct gspca_dev *gspca_dev)
 {
 	struct init_command spy_start_commands[] = {
@@ -641,6 +722,9 @@ static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
 	if (r < 0)
 		return r;
 
+	if (sd->gain)
+		set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
+
 	return r;
 }
 
@@ -757,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
 		return -ENXIO;
 	}
 
+	sd->avg_lum = -1;
+
 	return err_code;
 }
 
@@ -776,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 		PERR("Camera Stop command failed");
 }
 
+static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
+
+	if (avg_lum == -1)
+		return;
+
+	if (avg_lum < MIN_AVG_LUM) {
+		if (cur_gain == sd->gain->maximum)
+			return;
+		cur_gain++;
+		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
+	}
+	if (avg_lum > MAX_AVG_LUM) {
+		if (cur_gain == sd->gain->minimum)
+			return;
+		cur_gain--;
+		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
+	}
+
+}
+
+static void sd_dqcallback(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
+		return;
+
+	do_autogain(gspca_dev, sd->avg_lum);
+}
+
 /* Include sn9c2028 sof detection functions */
 #include "sn9c2028.h"
 
@@ -810,8 +929,10 @@ static const struct sd_desc sd_desc = {
 	.name = MODULE_NAME,
 	.config = sd_config,
 	.init = sd_init,
+	.init_controls = sd_init_controls,
 	.start = sd_start,
 	.stopN = sd_stopN,
+	.dq_callback = sd_dqcallback,
 	.pkt_scan = sd_pkt_scan,
 };
 
diff --git a/drivers/media/usb/gspca/sn9c2028.h b/drivers/media/usb/gspca/sn9c2028.h
index 8fd1d3e..6f20c0f 100644
--- a/drivers/media/usb/gspca/sn9c2028.h
+++ b/drivers/media/usb/gspca/sn9c2028.h
@@ -21,8 +21,17 @@
  *
  */
 
-static const unsigned char sn9c2028_sof_marker[5] =
-	{ 0xff, 0xff, 0x00, 0xc4, 0xc4 };
+static const unsigned char sn9c2028_sof_marker[] = {
+	0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96,
+	0x00,
+	0x00, /* seq */
+	0x00,
+	0x00,
+	0x00, /* avg luminance lower 8 bit */
+	0x00, /* avg luminance higher 8 bit */
+	0x00,
+	0x00,
+};
 
 static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
 					unsigned char *m, int len)
@@ -32,8 +41,13 @@ static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
 
 	/* Search for the SOF marker (fixed part) in the header */
 	for (i = 0; i < len; i++) {
-		if (m[i] == sn9c2028_sof_marker[sd->sof_read]) {
+		if ((m[i] == sn9c2028_sof_marker[sd->sof_read]) ||
+		    (sd->sof_read > 5)) {
 			sd->sof_read++;
+			if (sd->sof_read == 11)
+				sd->avg_lum_l = m[i];
+			if (sd->sof_read == 12)
+				sd->avg_lum = (m[i] << 8) + sd->avg_lum_l;
 			if (sd->sof_read == sizeof(sn9c2028_sof_marker)) {
 				PDEBUG(D_FRAM,
 					"SOF found, bytes to analyze: %u."
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
  2015-04-19 18:52 ` [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls " Vasily Khoruzhick
@ 2015-04-19 21:09   ` Theodore Kilgore
  2015-04-21 14:32   ` Hans de Goede
  1 sibling, 0 replies; 7+ messages in thread
From: Theodore Kilgore @ 2015-04-19 21:09 UTC (permalink / raw)
  To: Vasily Khoruzhick; +Cc: Hans de Goede, linux-media, Mauro Carvalho Chehab



On Sun, 19 Apr 2015, Vasily Khoruzhick wrote:

> Autogain algorithm is very simple, if average luminance is low - increase gain,
> if it's high - decrease gain. Gain granularity is low enough for this algo to
> stabilize quickly.
>
> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
> ---
> drivers/media/usb/gspca/sn9c2028.c | 121 +++++++++++++++++++++++++++++++++++++
> drivers/media/usb/gspca/sn9c2028.h |  20 +++++-
> 2 files changed, 138 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
> index 317b02c..0ff390f 100644
> --- a/drivers/media/usb/gspca/sn9c2028.c
> +++ b/drivers/media/usb/gspca/sn9c2028.c
> @@ -34,6 +34,16 @@ struct sd {
> 	struct gspca_dev gspca_dev;  /* !! must be the first item */
> 	u8 sof_read;
> 	u16 model;
> +
> +#define MIN_AVG_LUM 8500
> +#define MAX_AVG_LUM 10000
> +	int avg_lum;
> +	u8 avg_lum_l;
> +
> +	struct { /* autogain and gain control cluster */
> +		struct v4l2_ctrl *autogain;
> +		struct v4l2_ctrl *gain;
> +	};
> };
>
> struct init_command {
> @@ -252,6 +262,77 @@ static int run_start_commands(struct gspca_dev *gspca_dev,
> 	return 0;
> }
>
> +static void set_gain(struct gspca_dev *gspca_dev, s32 g)
> +{
> +	struct sd *sd = (struct sd *) gspca_dev;
> +
> +	struct init_command genius_vcam_live_gain_cmds[] = {
> +		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
> +	};
> +	if (!gspca_dev->streaming)
> +		return;
> +
> +	switch (sd->model) {
> +	case 0x7003:
> +		genius_vcam_live_gain_cmds[0].instruction[2] = g;
> +		run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,
> +				   ARRAY_SIZE(genius_vcam_live_gain_cmds));
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +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) {
> +	/* standalone gain control */
> +	case V4L2_CID_GAIN:
> +		set_gain(gspca_dev, ctrl->val);
> +		break;
> +	/* autogain */
> +	case V4L2_CID_AUTOGAIN:
> +		set_gain(gspca_dev, sd->gain->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 v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
> +	struct sd *sd = (struct sd *)gspca_dev;
> +
> +	gspca_dev->vdev.ctrl_handler = hdl;
> +	v4l2_ctrl_handler_init(hdl, 2);
> +
> +	switch (sd->model) {
> +	case 0x7003:
> +		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
> +			V4L2_CID_GAIN, 0, 20, 1, 0);
> +		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
> +			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> static int start_spy_cam(struct gspca_dev *gspca_dev)
> {
> 	struct init_command spy_start_commands[] = {
> @@ -641,6 +722,9 @@ static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
> 	if (r < 0)
> 		return r;
>
> +	if (sd->gain)
> +		set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
> +
> 	return r;
> }
>
> @@ -757,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
> 		return -ENXIO;
> 	}
>
> +	sd->avg_lum = -1;
> +
> 	return err_code;
> }
>
> @@ -776,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
> 		PERR("Camera Stop command failed");
> }
>
> +static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)
> +{
> +	struct sd *sd = (struct sd *) gspca_dev;
> +	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
> +
> +	if (avg_lum == -1)
> +		return;
> +
> +	if (avg_lum < MIN_AVG_LUM) {
> +		if (cur_gain == sd->gain->maximum)
> +			return;
> +		cur_gain++;
> +		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
> +	}
> +	if (avg_lum > MAX_AVG_LUM) {
> +		if (cur_gain == sd->gain->minimum)
> +			return;
> +		cur_gain--;
> +		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
> +	}
> +
> +}
> +
> +static void sd_dqcallback(struct gspca_dev *gspca_dev)
> +{
> +	struct sd *sd = (struct sd *) gspca_dev;
> +
> +	if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
> +		return;
> +
> +	do_autogain(gspca_dev, sd->avg_lum);
> +}
> +
> /* Include sn9c2028 sof detection functions */
> #include "sn9c2028.h"
>
> @@ -810,8 +929,10 @@ static const struct sd_desc sd_desc = {
> 	.name = MODULE_NAME,
> 	.config = sd_config,
> 	.init = sd_init,
> +	.init_controls = sd_init_controls,
> 	.start = sd_start,
> 	.stopN = sd_stopN,
> +	.dq_callback = sd_dqcallback,
> 	.pkt_scan = sd_pkt_scan,
> };
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.h b/drivers/media/usb/gspca/sn9c2028.h
> index 8fd1d3e..6f20c0f 100644
> --- a/drivers/media/usb/gspca/sn9c2028.h
> +++ b/drivers/media/usb/gspca/sn9c2028.h
> @@ -21,8 +21,17 @@
>  *
>  */
>
> -static const unsigned char sn9c2028_sof_marker[5] =
> -	{ 0xff, 0xff, 0x00, 0xc4, 0xc4 };
> +static const unsigned char sn9c2028_sof_marker[] = {
> +	0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96,
> +	0x00,
> +	0x00, /* seq */
> +	0x00,
> +	0x00,
> +	0x00, /* avg luminance lower 8 bit */
> +	0x00, /* avg luminance higher 8 bit */
> +	0x00,
> +	0x00,
> +};
>
> static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
> 					unsigned char *m, int len)
> @@ -32,8 +41,13 @@ static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
>
> 	/* Search for the SOF marker (fixed part) in the header */
> 	for (i = 0; i < len; i++) {
> -		if (m[i] == sn9c2028_sof_marker[sd->sof_read]) {
> +		if ((m[i] == sn9c2028_sof_marker[sd->sof_read]) ||
> +		    (sd->sof_read > 5)) {
> 			sd->sof_read++;
> +			if (sd->sof_read == 11)
> +				sd->avg_lum_l = m[i];
> +			if (sd->sof_read == 12)
> +				sd->avg_lum = (m[i] << 8) + sd->avg_lum_l;
> 			if (sd->sof_read == sizeof(sn9c2028_sof_marker)) {
> 				PDEBUG(D_FRAM,
> 					"SOF found, bytes to analyze: %u."
> -- 
> 2.3.5

Hello.

I do not know of this particular camera. But I am very pleased to see 
continued interest in the sn9c2028 cameras. Congratulations for these two 
patches.

Cheers,

Theodore Kilgore

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2
  2015-04-19 18:52 [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2 Vasily Khoruzhick
  2015-04-19 18:52 ` [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls " Vasily Khoruzhick
@ 2015-04-21 14:21 ` Hans de Goede
  2015-04-21 14:50   ` Vasily Khoruzhick
  1 sibling, 1 reply; 7+ messages in thread
From: Hans de Goede @ 2015-04-21 14:21 UTC (permalink / raw)
  To: Vasily Khoruzhick, linux-media, Mauro Carvalho Chehab

Hi Vasily,

Thanks for the patches.

On 19-04-15 20:52, Vasily Khoruzhick wrote:
> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
> ---
>   drivers/media/usb/gspca/sn9c2028.c | 120 ++++++++++++++++++++++++++++++++++++-
>   1 file changed, 119 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
> index 39b6b2e..317b02c 100644
> --- a/drivers/media/usb/gspca/sn9c2028.c
> +++ b/drivers/media/usb/gspca/sn9c2028.c
> @@ -2,6 +2,7 @@
>    * SN9C2028 library
>    *
>    * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
> + * Copyright (C) 2015 Vasily Khoruzhick <anarsoul@gmail.com>
>    *
>    * This program is free software; you can redistribute it and/or modify
>    * it under the terms of the GNU General Public License as published by
> @@ -128,7 +129,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
>   	status = -1;
>   	for (i = 0; i < 256 && status < 2; i++)
>   		status = sn9c2028_read1(gspca_dev);
> -	if (status != 2) {
> +	if (status < 0) {
>   		pr_err("long command status read error %d\n", status);
>   		return (status < 0) ? status : -EIO;
>   	}

Do you really need this change ? sn9c2028_read1 returns either a negative
error code, or the byte read from the sn9c2028 chip. This functions wait for
the sn9c2028 to return a read value of 2. I admit that the check in the for
vs the check in the error reporting is not chosen well, both should probably
be != 2. But checking for status < 0 is not good as this does not catch
a successful read from the chip not returning 2.

> @@ -178,6 +179,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
>   	case 0x7005:
>   		PDEBUG(D_PROBE, "Genius Smart 300 camera");
>   		break;
> +	case 0x7003:
> +		PDEBUG(D_PROBE, "Genius Videocam Live v2");
> +		break;
>   	case 0x8000:
>   		PDEBUG(D_PROBE, "DC31VC");
>   		break;
> @@ -530,6 +534,116 @@ static int start_genius_cam(struct gspca_dev *gspca_dev)
>   				  ARRAY_SIZE(genius_start_commands));
>   }
>
> +static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
> +{
> +	int r;
> +	struct sd *sd = (struct sd *) gspca_dev;
> +	struct init_command genius_vcam_live_start_commands[] = {
> +		{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0},
> +		{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
> +		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
> +
> +		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
> +		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
> +		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
> +		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
> +		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
> +		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
> +		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
> +		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
> +		{{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4},
> +		{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},
> +		{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},
> +		{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},
> +		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
> +		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
> +		{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},
> +		{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
> +		{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},
> +		{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},
> +		{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},
> +		{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},
> +		{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},
> +		{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},
> +		{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},
> +		{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},
> +		{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},
> +		{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},
> +		{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},
> +		{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},
> +		{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},
> +		{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},
> +		{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},
> +		{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},
> +		{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},
> +		{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0},
> +		/* Camera should start to capture now. */
> +		{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0},
> +		{{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0},
> +		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
> +	};
> +
> +	r = run_start_commands(gspca_dev, genius_vcam_live_start_commands,
> +				  ARRAY_SIZE(genius_vcam_live_start_commands));
> +	if (r < 0)
> +		return r;
> +
> +	return r;
> +}
> +
>   static int start_vivitar_cam(struct gspca_dev *gspca_dev)
>   {
>   	struct init_command vivitar_start_commands[] = {
> @@ -623,6 +737,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
>   	case 0x7005:
>   		err_code = start_genius_cam(gspca_dev);
>   		break;
> +	case 0x7003:
> +		err_code = start_genius_videocam_live(gspca_dev);
> +		break;
>   	case 0x8001:
>   		err_code = start_spy_cam(gspca_dev);
>   		break;
> @@ -701,6 +818,7 @@ static const struct sd_desc sd_desc = {
>   /* -- module initialisation -- */
>   static const struct usb_device_id device_table[] = {
>   	{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
> +	{USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2  */
>   	/* The Genius Smart is untested. I can't find an owner ! */
>   	/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
>   	{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */
>

Otherwise this patch looks good.

Regards,

Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
  2015-04-19 18:52 ` [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls " Vasily Khoruzhick
  2015-04-19 21:09   ` Theodore Kilgore
@ 2015-04-21 14:32   ` Hans de Goede
  2015-04-21 15:00     ` Vasily Khoruzhick
  1 sibling, 1 reply; 7+ messages in thread
From: Hans de Goede @ 2015-04-21 14:32 UTC (permalink / raw)
  To: Vasily Khoruzhick, linux-media, Mauro Carvalho Chehab

Hi,

On 19-04-15 20:52, Vasily Khoruzhick wrote:
> Autogain algorithm is very simple, if average luminance is low - increase gain,
> if it's high - decrease gain. Gain granularity is low enough for this algo to
> stabilize quickly.
>
> Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
> ---
>   drivers/media/usb/gspca/sn9c2028.c | 121 +++++++++++++++++++++++++++++++++++++
>   drivers/media/usb/gspca/sn9c2028.h |  20 +++++-
>   2 files changed, 138 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
> index 317b02c..0ff390f 100644
> --- a/drivers/media/usb/gspca/sn9c2028.c
> +++ b/drivers/media/usb/gspca/sn9c2028.c
> @@ -34,6 +34,16 @@ struct sd {
>   	struct gspca_dev gspca_dev;  /* !! must be the first item */
>   	u8 sof_read;
>   	u16 model;
> +
> +#define MIN_AVG_LUM 8500
> +#define MAX_AVG_LUM 10000
> +	int avg_lum;
> +	u8 avg_lum_l;
> +
> +	struct { /* autogain and gain control cluster */
> +		struct v4l2_ctrl *autogain;
> +		struct v4l2_ctrl *gain;
> +	};
>   };
>
>   struct init_command {
> @@ -252,6 +262,77 @@ static int run_start_commands(struct gspca_dev *gspca_dev,
>   	return 0;
>   }
>
> +static void set_gain(struct gspca_dev *gspca_dev, s32 g)
> +{
> +	struct sd *sd = (struct sd *) gspca_dev;
> +
> +	struct init_command genius_vcam_live_gain_cmds[] = {
> +		{{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},
> +	};
> +	if (!gspca_dev->streaming)
> +		return;
> +
> +	switch (sd->model) {
> +	case 0x7003:
> +		genius_vcam_live_gain_cmds[0].instruction[2] = g;
> +		run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,
> +				   ARRAY_SIZE(genius_vcam_live_gain_cmds));
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +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) {
> +	/* standalone gain control */
> +	case V4L2_CID_GAIN:
> +		set_gain(gspca_dev, ctrl->val);
> +		break;
> +	/* autogain */
> +	case V4L2_CID_AUTOGAIN:
> +		set_gain(gspca_dev, sd->gain->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 v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
> +	struct sd *sd = (struct sd *)gspca_dev;
> +
> +	gspca_dev->vdev.ctrl_handler = hdl;
> +	v4l2_ctrl_handler_init(hdl, 2);
> +
> +	switch (sd->model) {
> +	case 0x7003:
> +		sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
> +			V4L2_CID_GAIN, 0, 20, 1, 0);
> +		sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
> +			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
>   static int start_spy_cam(struct gspca_dev *gspca_dev)
>   {
>   	struct init_command spy_start_commands[] = {
> @@ -641,6 +722,9 @@ static int start_genius_videocam_live(struct gspca_dev *gspca_dev)
>   	if (r < 0)
>   		return r;
>
> +	if (sd->gain)
> +		set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
> +
>   	return r;
>   }
>
> @@ -757,6 +841,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
>   		return -ENXIO;
>   	}
>
> +	sd->avg_lum = -1;
> +
>   	return err_code;
>   }
>
> @@ -776,6 +862,39 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
>   		PERR("Camera Stop command failed");
>   }
>
> +static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)
> +{
> +	struct sd *sd = (struct sd *) gspca_dev;
> +	s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
> +
> +	if (avg_lum == -1)
> +		return;
> +
> +	if (avg_lum < MIN_AVG_LUM) {
> +		if (cur_gain == sd->gain->maximum)
> +			return;
> +		cur_gain++;
> +		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
> +	}
> +	if (avg_lum > MAX_AVG_LUM) {
> +		if (cur_gain == sd->gain->minimum)
> +			return;
> +		cur_gain--;
> +		v4l2_ctrl_s_ctrl(sd->gain, cur_gain);
> +	}
> +
> +}
> +
> +static void sd_dqcallback(struct gspca_dev *gspca_dev)
> +{
> +	struct sd *sd = (struct sd *) gspca_dev;
> +
> +	if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))
> +		return;
> +
> +	do_autogain(gspca_dev, sd->avg_lum);
> +}
> +
>   /* Include sn9c2028 sof detection functions */
>   #include "sn9c2028.h"
>
> @@ -810,8 +929,10 @@ static const struct sd_desc sd_desc = {
>   	.name = MODULE_NAME,
>   	.config = sd_config,
>   	.init = sd_init,
> +	.init_controls = sd_init_controls,
>   	.start = sd_start,
>   	.stopN = sd_stopN,
> +	.dq_callback = sd_dqcallback,
>   	.pkt_scan = sd_pkt_scan,
>   };
>
> diff --git a/drivers/media/usb/gspca/sn9c2028.h b/drivers/media/usb/gspca/sn9c2028.h
> index 8fd1d3e..6f20c0f 100644
> --- a/drivers/media/usb/gspca/sn9c2028.h
> +++ b/drivers/media/usb/gspca/sn9c2028.h
> @@ -21,8 +21,17 @@
>    *
>    */
>
> -static const unsigned char sn9c2028_sof_marker[5] =
> -	{ 0xff, 0xff, 0x00, 0xc4, 0xc4 };
> +static const unsigned char sn9c2028_sof_marker[] = {
> +	0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96,
> +	0x00,
> +	0x00, /* seq */
> +	0x00,
> +	0x00,
> +	0x00, /* avg luminance lower 8 bit */
> +	0x00, /* avg luminance higher 8 bit */
> +	0x00,
> +	0x00,
> +};
>

This seems wrong, the header is only 12 bytes the extra 2 0x00 bytes you add are
actually part of the compressed data and are parsed by the userspace code,
please drop them.

>   static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
>   					unsigned char *m, int len)
> @@ -32,8 +41,13 @@ static unsigned char *sn9c2028_find_sof(struct gspca_dev *gspca_dev,
>
>   	/* Search for the SOF marker (fixed part) in the header */
>   	for (i = 0; i < len; i++) {
> -		if (m[i] == sn9c2028_sof_marker[sd->sof_read]) {
> +		if ((m[i] == sn9c2028_sof_marker[sd->sof_read]) ||
> +		    (sd->sof_read > 5)) {
>   			sd->sof_read++;
> +			if (sd->sof_read == 11)
> +				sd->avg_lum_l = m[i];
> +			if (sd->sof_read == 12)
> +				sd->avg_lum = (m[i] << 8) + sd->avg_lum_l;
>   			if (sd->sof_read == sizeof(sn9c2028_sof_marker)) {
>   				PDEBUG(D_FRAM,
>   					"SOF found, bytes to analyze: %u."
>

Otherwise this looks good.

Regards,

Hans

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2
  2015-04-21 14:21 ` [PATCH 1/2] gspca: sn9c2028: Add support for " Hans de Goede
@ 2015-04-21 14:50   ` Vasily Khoruzhick
  0 siblings, 0 replies; 7+ messages in thread
From: Vasily Khoruzhick @ 2015-04-21 14:50 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Hi Hans,

On Tue, Apr 21, 2015 at 5:21 PM, Hans de Goede <hdegoede@redhat.com> wrote:
>> @@ -128,7 +129,7 @@ static int sn9c2028_long_command(struct gspca_dev
>> *gspca_dev, u8 *command)
>>         status = -1;
>>         for (i = 0; i < 256 && status < 2; i++)
>>                 status = sn9c2028_read1(gspca_dev);
>> -       if (status != 2) {
>> +       if (status < 0) {
>>                 pr_err("long command status read error %d\n", status);
>>                 return (status < 0) ? status : -EIO;
>>         }
>
>
> Do you really need this change ? sn9c2028_read1 returns either a negative
> error code, or the byte read from the sn9c2028 chip. This functions wait for
> the sn9c2028 to return a read value of 2. I admit that the check in the for
> vs the check in the error reporting is not chosen well, both should probably
> be != 2. But checking for status < 0 is not good as this does not catch
> a successful read from the chip not returning 2.

For this cam it returns 1 on some commands. Anyway, this value is not
used anywhere later, so I just extended condition.

Regards,
Vasily

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls Genius Videocam Live v2
  2015-04-21 14:32   ` Hans de Goede
@ 2015-04-21 15:00     ` Vasily Khoruzhick
  0 siblings, 0 replies; 7+ messages in thread
From: Vasily Khoruzhick @ 2015-04-21 15:00 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Linux Media Mailing List, Mauro Carvalho Chehab

Hi Hans,

On Tue, Apr 21, 2015 at 5:32 PM, Hans de Goede <hdegoede@redhat.com> wrote:

>> diff --git a/drivers/media/usb/gspca/sn9c2028.h
>> b/drivers/media/usb/gspca/sn9c2028.h
>> index 8fd1d3e..6f20c0f 100644
>> --- a/drivers/media/usb/gspca/sn9c2028.h
>> +++ b/drivers/media/usb/gspca/sn9c2028.h
>> @@ -21,8 +21,17 @@
>>    *
>>    */
>>
>> -static const unsigned char sn9c2028_sof_marker[5] =
>> -       { 0xff, 0xff, 0x00, 0xc4, 0xc4 };
>> +static const unsigned char sn9c2028_sof_marker[] = {
>> +       0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96,
>> +       0x00,
>> +       0x00, /* seq */
>> +       0x00,
>> +       0x00,
>> +       0x00, /* avg luminance lower 8 bit */
>> +       0x00, /* avg luminance higher 8 bit */
>> +       0x00,
>> +       0x00,
>> +};
>>
>
> This seems wrong, the header is only 12 bytes the extra 2 0x00 bytes you add
> are
> actually part of the compressed data and are parsed by the userspace code,
> please drop them.

OK, I've found average lumimance value in header heuristically,
based on info that it's present in header of sn9c1xx and sn9c201 cams,
and I didn't check actual header length - my fault.

Regards,
Vasily

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-04-21 15:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-19 18:52 [PATCH 1/2] gspca: sn9c2028: Add support for Genius Videocam Live v2 Vasily Khoruzhick
2015-04-19 18:52 ` [PATCH 2/2] gspca: sn9c2028: Add gain and autogain controls " Vasily Khoruzhick
2015-04-19 21:09   ` Theodore Kilgore
2015-04-21 14:32   ` Hans de Goede
2015-04-21 15:00     ` Vasily Khoruzhick
2015-04-21 14:21 ` [PATCH 1/2] gspca: sn9c2028: Add support for " Hans de Goede
2015-04-21 14:50   ` Vasily Khoruzhick

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox