All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chia-I Wu <olvaffe@gmail.com>
To: "Erik Andrén" <erik.andren@gmail.com>
Cc: video4linux-list@redhat.com, noodles@earth.li,
	qce-ga-devel@lists.sourceforge.net
Subject: Re: Please test the gspca-stv06xx branch
Date: Tue, 25 Nov 2008 16:20:02 +0800	[thread overview]
Message-ID: <20081125082002.GC18787@m500.domain> (raw)
In-Reply-To: <492B15E1.2080207@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]

Hi Erik,

On Mon, Nov 24, 2008 at 10:00:17PM +0100, Erik Andrén wrote:
> I've reworked the driver somewhat and added initial support for th
> pb0100.
> Please test with the latest version of the gspca-stv06xx tree and
> see if you can get an image. Ekiga works best for me at the moment.
I am trying to make gspca-stv06xx work with my QuickCam Express
(046d:0840).  It comes with the HDCS 1000 sensor.  So far, I am able to
receive frames using gstreamer (with libv4l).  The colors are wrong
though.

While working on it, I encounter two minor issues:

* stv06xx_write_sensor sends an extra packet unconditionally.  It causes
  the function call return error.
* Turning LED on/off kills the device.  I have to re-plug the device to
  make it work again.

I could put those functions inside an if clause:

	if (udev->descriptor.idProduct != 0x840)
		do_something;

and things work.  But as I do not have other cameras to test, I am not
sure if this is the right way.  Do you have any suggestion?

I will keep working on it.  But you can find a primitive patch and a
sample image in the attachments.

-- 
Regards,
olv

[-- Attachment #2: qc-ex-primitive.patch --]
[-- Type: text/x-diff, Size: 7510 bytes --]

diff -r 4e778359e610 -r 378675539541 linux/drivers/media/video/gspca/stv06xx/stv06xx.c
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c	Mon Nov 24 18:06:49 2008 +0100
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c	Tue Nov 25 15:55:12 2008 +0800
@@ -127,10 +127,12 @@
 			      STV06XX_URB_MSG_TIMEOUT);
 
 	/* Quickam Web needs an extra packet */
-	buf[0] = 0;
-	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-			      0x04, 0x40, 0x1704, 0, buf, 1,
-			      STV06XX_URB_MSG_TIMEOUT);
+	if (udev->descriptor.idProduct != 0x840) {
+		buf[0] = 0;
+		err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				      0x04, 0x40, 0x1704, 0, buf, 1,
+				      STV06XX_URB_MSG_TIMEOUT);
+	}
 
 	return (err < 0) ? err : 0;
 }
@@ -261,9 +263,11 @@
 		goto out;
 
 	/* Turn on LED */
-	err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
-	if (err < 0)
-		goto out;
+	if (sd->gspca_dev.dev->descriptor.idProduct != 0x840) {
+		err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
+		if (err < 0)
+			goto out;
+	}
 
 	/* Start isochronous streaming */
 	err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1);
@@ -283,9 +287,11 @@
 	struct sd *sd = (struct sd *) gspca_dev;
 
 	/* Turn off LED */
-	err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
-	if (err < 0)
-		goto out;
+	if (sd->gspca_dev.dev->descriptor.idProduct != 0x840) {
+		err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
+		if (err < 0)
+			goto out;
+	}
 
 	/* stop ISO-streaming */
 	err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0);
diff -r 4e778359e610 -r 378675539541 linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c	Mon Nov 24 18:06:49 2008 +0100
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c	Tue Nov 25 15:55:12 2008 +0800
@@ -57,16 +57,132 @@
 	return -ENODEV;
 }
 
+static int hdcs_set_exposure(struct sd *sd, int val)
+{
+	unsigned int rowexp;		/* rowexp,srowexp = 15 bits (0..32767) */
+	unsigned int srowexp;		/* sub-row exposure (smaller is brighter) */
+	unsigned int max_srowexp;	/* Maximum srowexp value + 1 */
+	int width = 360;
+
+	/* Absolute black at srowexp=2672,width=360; 2616, width=352; 1896, width=256 for hdcs1000 */
+
+	val *= 16;		/* 16 seems to be the smallest change that actually affects brightness */
+	max_srowexp = width * 15 / 2 - 104 + 1;
+	srowexp = max_srowexp - (val % max_srowexp) - 1;
+	rowexp  = val / max_srowexp;
+
+	/* Number of rows to expose */
+	stv06xx_write_sensor_b(sd, HDCS_ROWEXPL, rowexp & 0xff);
+	stv06xx_write_sensor_b(sd, HDCS_ROWEXPH, rowexp >> 8);
+
+	if (IS_1020(sd)) {
+		srowexp = 0;	//FIXME:need formula to compute srowexp for HDCS1020!
+		srowexp >>= 2;					/* Bits 0..1 are hardwired to 0 */
+
+		/* Number of pixels to expose */
+		stv06xx_write_sensor_b(sd, HDCS20_SROWEXP, srowexp & 0xff);
+	} else {
+		/* Number of pixels to expose */
+		stv06xx_write_sensor_b(sd, HDCS00_SROWEXPL, srowexp & 0xff);
+		stv06xx_write_sensor_b(sd, HDCS00_SROWEXPH, srowexp >> 8);
+	}
+
+	if (IS_1020(sd)) {
+		/* Reset exposure error flag */
+		stv06xx_write_sensor_b(sd, HDCS20_ERROR, BIT(0));
+	} else {
+		/* Reset exposure error flag */
+		stv06xx_write_sensor_b(sd, HDCS_STATUS, BIT(4));
+	}
+
+	return 0;
+}
+
+static int hdcs_set_gains(struct sd *sd, unsigned int hue, unsigned int sat, unsigned int val)
+{
+	static const unsigned int min_gain = 8;
+	unsigned int rgain, bgain, ggain;
+
+	//qc_hsv2rgb(hue, sat, val, &rgain, &bgain, &ggain);
+	rgain = hue;
+	ggain = sat;
+	bgain = val;
+
+	rgain >>= 8;					/* After this the values are 0..255 */
+	ggain >>= 8;
+	bgain >>= 8;
+
+	rgain = max(rgain, min_gain);			/* Do not allow very small values, they cause bad (low-contrast) image */
+	ggain = max(ggain, min_gain);
+	bgain = max(bgain, min_gain);
+
+	if (rgain > 127) rgain = rgain/2 | BIT(7);	/* Bit 7 doubles the programmed values */
+	if (ggain > 127) ggain = ggain/2 | BIT(7);	/* Double programmed value if necessary */
+	if (bgain > 127) bgain = bgain/2 | BIT(7);
+
+	stv06xx_write_sensor_b(sd, HDCS_ERECPGA, ggain);
+	stv06xx_write_sensor_b(sd, HDCS_EROCPGA, rgain);
+	stv06xx_write_sensor_b(sd, HDCS_ORECPGA, bgain);
+	stv06xx_write_sensor_b(sd, HDCS_OROCPGA, ggain);
+
+	return 0;
+}
+
+static int hdcs_set_size(struct sd *sd, unsigned int width, unsigned int height)
+{
+	/* The datasheet doesn't seem to say this, but HDCS-1000
+	 * has visible windows size of 360x296 pixels, the first upper-left
+	 * visible pixel is at 8,8.
+	 * From Andrey's test image: looks like HDCS-1020 upper-left
+	 * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
+	 * visible pixel at 375,299 (x maybe even larger?)
+	 */
+	unsigned int originx   = IS_1020(sd) ? 24 : 8;		/* First visible pixel */
+	unsigned int maxwidth  = IS_1020(sd) ? 352 : 360;	/* Visible sensor size */
+	unsigned int originy   = 8;
+	unsigned int maxheight = IS_1020(sd) ? 292 : 296;
+	unsigned int x, y;
+	int ret;
+
+	printk("set size\n");
+
+	width  = (width + 3) / 4 * 4;	/* Width must be multiple of 4 */
+	height = (height + 3)/ 4 * 4;	/* Height must be multiple of 4 */
+
+	x = (maxwidth - width) / 2;			/* Center image by computing upper-left corner */
+	y = (maxheight - height) / 2;
+	width /= 4;
+	height /= 4;
+	x = (x + originx) / 4;				/* Must be multiple of 4 (low bits wired to 0) */
+	y = (y + originy) / 4;
+
+	ret = stv06xx_write_sensor_b(sd, GET_CONTROL, 0);
+
+	stv06xx_write_sensor_b(sd, HDCS_FWROW, y);
+	stv06xx_write_sensor_b(sd, HDCS_FWCOL, x);
+	stv06xx_write_sensor_b(sd, HDCS_LWROW, y + height - 1);
+	stv06xx_write_sensor_b(sd, HDCS_LWCOL, x + width - 1);
+	
+	if (1)
+		hdcs_set_exposure(sd, 32768);
+
+	ret = stv06xx_write_sensor_b(sd, GET_CONTROL, HDCS_RUN_ENABLE);
+	printk("set gains: %d\n", ret);
+	hdcs_set_gains(sd, 32768, 32768, 32768);
+
+	return 0;
+}
+
 int hdcs_start(struct sd *sd)
 {
-	int err = stv06xx_write_sensor_b(sd, HDCS_RUN_ENABLE, GET_CONTROL);
+	int err = stv06xx_write_sensor_b(sd, GET_CONTROL, HDCS_RUN_ENABLE);
 	PDEBUG(D_STREAM, "Starting stream");
 	return (err < 0) ? err : 0;
 }
 
 int hdcs_stop(struct sd *sd)
 {
-	int err = stv06xx_write_sensor_b(sd, HDCS_SLEEP_MODE, GET_CONTROL);
+	int err = stv06xx_write_sensor_b(sd, GET_CONTROL, HDCS_SLEEP_MODE);
 	PDEBUG(D_STREAM, "Halting stream");
 	return (err < 0) ? err : 0;
 }
@@ -182,9 +298,17 @@
 
 	/* CONFIG: Bit 3: continous frame capture,
 	   bit 2: stop when frame complete */
-	stv06xx_write_sensor_b(sd, GET_CONTROL, BIT(3));
+	stv06xx_write_sensor_b(sd, GET_CONFIG, BIT(3));
 	/* ADC output resolution to 10 bits */
 	stv06xx_write_sensor_b(sd, HDCS_ADCCTRL, 10);
+
+	stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0);
+	hdcs_stop(sd);
+
+	hdcs_set_size(sd, 360, 296);
+
+	info("hdcs_inited");
+
 	return 0;
 }
 
diff -r 4e778359e610 -r 378675539541 linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h	Mon Nov 24 18:06:49 2008 +0100
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h	Tue Nov 25 15:55:12 2008 +0800
@@ -114,6 +114,7 @@
 
 #define IS_870(sd)	((sd)->gspca_dev.dev->descriptor.idProduct == 0x870)
 #define IS_1020(sd)	((sd)->sensor == &stv06xx_sensor_hdcs1020)
+#define GET_CONFIG	(IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG)
 #define GET_CONTROL	(IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL)
 
 int hdcs_probe(struct sd *sd);
@@ -126,6 +127,7 @@
 	.name = "HP HDCS-1000/1100",
 	.i2c_flush = 0,
 	.i2c_addr = HDCS_ADDR,
+	.i2c_len = 1,
 
 	.init = hdcs_init,
 	.probe = hdcs_probe,

[-- Attachment #3: qc.png --]
[-- Type: image/png, Size: 84574 bytes --]

[-- Attachment #4: Type: text/plain, Size: 164 bytes --]

--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

  reply	other threads:[~2008-11-25  8:20 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-11-24 21:00 Please test the gspca-stv06xx branch Erik Andrén
2008-11-25  8:20 ` Chia-I Wu [this message]
2008-11-25 11:22   ` Erik Andrén
2008-11-25 11:39     ` Chia-I Wu
2008-11-25 12:02       ` Erik Andrén
     [not found]   ` <492E7906.905@redhat.com>
2008-11-27 10:59     ` Chia-I Wu
2008-11-27 11:55       ` Erik Andrén
2008-11-27 16:00         ` Chia-I Wu
     [not found]           ` <492EE597.7010100@redhat.com>
2008-11-28  4:26             ` Chia-I Wu
2008-11-27 11:51     ` Erik Andrén
2008-11-27 18:08       ` Hans de Goede

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20081125082002.GC18787@m500.domain \
    --to=olvaffe@gmail.com \
    --cc=erik.andren@gmail.com \
    --cc=noodles@earth.li \
    --cc=qce-ga-devel@lists.sourceforge.net \
    --cc=video4linux-list@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.