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,