* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.