Re: Please test the gspca-stv06xx branch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


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
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: qc.png
Description: PNG image

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

[Linux Media]     [Older V4L]     [Linux DVB]     [Video Disk Recorder]     [Linux Kernel]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [SSH]     [DVB Maintainers]     [Linux USB]     [Yosemite Information]

Add to Google Powered by Linux