diff mbox

TV-8532A/ICM532B compression and modes

Message ID Pine.GSO.4.58.0904242256500.7228@zvygba.sbkg.pbz (mailing list archive)
State Not Applicable
Headers show

Commit Message

kirin_e@users.sourceforge.net April 24, 2009, 9:16 p.m. UTC
Hi,

a couple of months ago i did some hacking on the tv8532 gspca driver for
my TV-8532A/ICM532B based webcam, to the point where i got decompression
and most modes working. But i've kind of lost interest at this point, so
haven't bothered to clean everything up for a real patch(also noticed it
doesn't apply cleanly on 2.6.29 anymore).

In case it could be of help to someone else i've attached my two patches
against the 2.6.28 kernel driver. First one fixes packet handling so it
works with the different modes, the second add the actual modes i've been
using + some misc changes i've been playing around with. Feel free to use
or ignore as you will.

And probably the more useful part of my hacking, here's my notes on the
compression used(got working decompression code, but not in a state i'd
like to release):

Compressed ICM532B/TV-8532A output:

- first 2 pixels in a line are uncompressed followed by compressed diffs
  from the previous same bayer color pixel, edge directional left or up
- count bits set, max 8 - quantization, single zero added if short of max,
  followed by the same number of bits making a length[+0]+value pair:

  11111111XXXXXXXX   = XXXXXXXX
  11111110XXXXXXX    = XXXXXXX
  1111110XXXXXX      = XXXXXX
  111110XXXXX        = XXXXX
  11110XXXX          = XXXX
  1110XXX            = XXX
  110XX              = XX
  10X                = X
  0                  =

- 1's complement with sign bit inverted and included in value, ie use value
  as is if 1st bit set else flip bits and treat as negative, 0 if no bits
- diff = value << quantization


//kirin

--- ../bak/tv8532.c	2009-04-24 21:28:37.000000000 +0200
+++ tv8532.c	2009-04-24 21:31:57.000000000 +0200
@@ -35,7 +35,8 @@ struct sd {
 	__u8 tmpbuf2[352 * 288];		/* no protection... */
 
 	unsigned short brightness;
-	unsigned short contrast;
+	unsigned short exposure;
+	unsigned short gain;
 
 	unsigned int packet;
 };
@@ -43,8 +44,10 @@ struct sd {
 /* V4L2 controls supported by the driver */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
 
 static struct ctrl sd_ctrls[] = {
 #define SD_BRIGHTNESS 0
@@ -61,39 +64,100 @@ static struct ctrl sd_ctrls[] = {
 	 .set = sd_setbrightness,
 	 .get = sd_getbrightness,
 	 },
-#define SD_CONTRAST 1
+#define SD_EXPOSURE 1
 	{
 	 {
-	  .id = V4L2_CID_CONTRAST,
+	  .id = V4L2_CID_EXPOSURE,
 	  .type = V4L2_CTRL_TYPE_INTEGER,
-	  .name = "Contrast",
+	  .name = "Exposure",
 	  .minimum = 0,
 	  .maximum = 0xffff,
 	  .step = 1,
 	  .default_value = 0x7fff,
 	  },
-	 .set = sd_setcontrast,
-	 .get = sd_getcontrast,
+	 .set = sd_setexposure,
+	 .get = sd_getexposure,
+	 },
+#define SD_GAIN 2
+	{
+	 {
+	  .id = V4L2_CID_GAIN,
+	  .type = V4L2_CTRL_TYPE_INTEGER,
+	  .name = "Gain",
+	  .minimum = 0,
+	  .maximum = 0x0007,
+	  .step = 1,
+	  .default_value = 0x0000,
+	  },
+	 .set = sd_setgain,
+	 .get = sd_getgain,
 	 },
 };
 
 static struct v4l2_pix_format sif_mode[] = {
-	{176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+	{176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
 		.bytesperline = 176,
 		.sizeimage = 176 * 144,
 		.colorspace = V4L2_COLORSPACE_SRGB,
 		.priv = 1},
-	{352, 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+	{320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+		.bytesperline = 320,
+		.sizeimage = 320 * 240,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.priv = 0},
+	{352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
 		.bytesperline = 352,
 		.sizeimage = 352 * 288,
 		.colorspace = V4L2_COLORSPACE_SRGB,
-		.priv = 0},
+		.priv = 2},
 };
 
 /*
  * Initialization data: this is the first set-up data written to the
  * device (before the open data).
  */
+
+#if 1
+static int tv8532_modes[][8] = {
+	/* LINES, CLOCK, WIDTHL, WIDTHH, TESTPTL, TESTPTH, TESTPTBL, TESTPTBH */
+	{ 0x81, 0x12, 0xe8, 0x03, 0x14, 0x01, 0x0a, 0x01 }, /* 2 @ 2MHz */
+	{ 0x83, 0x08, 0xe8, 0x03, 0x38, 0x03, 0x04, 0x03 }, /* 4 @ 4MHz */
+	{ 0x84, 0x08, 0x20, 0x03, 0x38, 0x04, 0x04, 0x04 }, /* 5 @ 4MHz */
+	{ 0x85, 0x08, 0x9b, 0x02, 0x01, 0x05, 0x96, 0x04 }, /* 6 @ 4MHz */
+	{ 0x87, 0x08, 0xf4, 0x01, 0x01, 0x06, 0x96, 0x04 }, /* 8 @ 4MHz */
+	{ 0x89, 0x28, 0x58, 0x02, 0x01, 0x06, 0x01, 0x05 }, /* 10 @ 6MHz */
+	{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* test */
+};
+
+#define MODE		0x00
+#define COMPRESS	0x80
+#define QUANT		0x04
+#define GAIN		0x00
+
+#define TESTCOMP	(COMPRESS | QUANT)
+#define TESTLINE	(tv8532_modes[MODE][0])
+#define TESTCLK		(tv8532_modes[MODE][1])
+#define ADWIDTHL	(tv8532_modes[MODE][2])
+#define ADWIDTHH	(tv8532_modes[MODE][3])
+#define TESTPTL		(tv8532_modes[MODE][4])
+#define TESTPTH		(tv8532_modes[MODE][5])
+#define TESTPTBL	(tv8532_modes[MODE][6])
+#define TESTPTBH	(tv8532_modes[MODE][7])
+
+#define ADHEIGHL	0x40
+#define ADHEIGHH	0x01
+#define EXPOL		0x3f
+#define EXPOH		0x01
+
+#define ADCBEGINL	0x46
+#define ADCBEGINH	(0x00 | (GAIN << 5))	/* bit 2 mirror, bit 5-7 gain */
+#define ADRBEGINL	0x0a
+#define ADRBEGINH	0x00
+
+#define QCIFLINE	0x4b
+
+#else
+
 #define TESTCLK 0x10		/* reg 0x2c -> 0x12 //10 */
 #define TESTCOMP 0x90		/* reg 0x28 -> 0x80 */
 #define TESTLINE 0x81		/* reg 0x29 -> 0x81 */
@@ -112,9 +176,37 @@ static struct v4l2_pix_format sif_mode[]
 #define ADCBEGINH 0x00		/* reg 0x11 -> 0x00 */
 #define ADRBEGINL 0x0a		/* reg 0x14 -> 0x0b //0x0c */
 #define ADRBEGINH 0x00		/* reg 0x15 -> 0x00 */
-#define TV8532_CMD_UPDATE 0x84
+#endif
+
+#define HIGHBUDGET 0x00		/* reg 0x2a */
+#define LOWBUDGET 0x01		/* reg 0x2b */
+#define BLACKLEVEL 0x00		/* reg 0x90 */
+#define TV8532_CMD_UPDATE 0x84		/* bit 1 (auto?) slope adjustment */
+
+#define TV8532_HSYNC_ENDL 0x18
+#define TV8532_HSYNC_ENDH 0x19
+#define TV8532_VSYNC_ENDL 0x1a
+#define TV8532_VSYNC_ENDH 0x1b
+
+#define TV8532_M1_L 0x20		/* G1 */
+#define TV8532_M1_H 0x21
+#define TV8532_M2_L 0x22		/* R */
+#define TV8532_M2_H 0x23
+#define TV8532_M3_L 0x24		/* B */
+#define TV8532_M3_H 0x25
+#define TV8532_M4_L 0x26		/* G2 */
+#define TV8532_M4_H 0x27
+
+#define TV8532_DARK_DATA 0x90
+#define TV8532_SLOPE_END_TIME_L 0x95	/* autoslope val */
+#define TV8532_SLOPE_END_TIME_H 0x96
+#define TV8532_RAMPSEL 0x53
+#define TV8532_DSLOWL 0x58
+#define TV8532_DSLOWH 0x59
+#define TV8532_DSHIGHL 0x5a
+#define TV8532_DSHIGHH 0x5b
 
-#define TV8532_EEprom_Add 0x03
+#define TV8532_EEprom_Addr 0x03
 #define TV8532_EEprom_DataL 0x04
 #define TV8532_EEprom_DataM 0x05
 #define TV8532_EEprom_DataH 0x06
@@ -122,8 +214,9 @@ static struct v4l2_pix_format sif_mode[]
 #define TV8532_EEprom_Write 0x08
 #define TV8532_PART_CTRL 0x00
 #define TV8532_CTRL 0x01
+#define TV8532_CTRL_H 0x02
 #define TV8532_CMD_EEprom_Open 0x30
-#define TV8532_CMD_EEprom_Close 0x29
+#define TV8532_CMD_EEprom_Close 0x29	/* bit 3 auto dark correction */
 #define TV8532_UDP_UPDATE 0x31
 #define TV8532_GPIO 0x39
 #define TV8532_GPIO_OE 0x3B
@@ -142,8 +235,8 @@ static struct v4l2_pix_format sif_mode[]
 #define TV8532_POINT_H 0x2E
 #define TV8532_POINTB_L 0x2F
 #define TV8532_POINTB_H 0x30
-#define TV8532_BUDGET_L 0x2A
-#define TV8532_BUDGET_H 0x2B
+#define TV8532_HIGHBUDGET 0x2A
+#define TV8532_LOWBUDGET 0x2B
 #define TV8532_VID_L 0x34
 #define TV8532_VID_H 0x35
 #define TV8532_PID_L 0x36
@@ -157,7 +250,7 @@ static struct v4l2_pix_format sif_mode[]
 #define TV8532_AD_ROWBEGIN_H 0x15
 
 static const __u32 tv_8532_eeprom_data[] = {
-/*	add		dataL	   dataM	dataH */
+/*	addr		dataL	   dataM	dataH */
 	0x00010001, 0x01018011, 0x02050014, 0x0305001c,
 	0x040d001e, 0x0505001f, 0x06050519, 0x0705011b,
 	0x0805091e, 0x090d892e, 0x0a05892f, 0x0b050dd9,
@@ -209,12 +302,11 @@ static void tv_8532WriteEEprom(struct gs
 	int i = 0;
 	__u8 reg, data0, data1, data2;
 
-	reg_w_1(gspca_dev, TV8532_GPIO, 0xb0);
 	reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Open);
 /*	msleep(1); */
 	while (tv_8532_eeprom_data[i]) {
 		reg = (tv_8532_eeprom_data[i] & 0xff000000) >> 24;
-		reg_w_1(gspca_dev, TV8532_EEprom_Add, reg);
+		reg_w_1(gspca_dev, TV8532_EEprom_Addr, reg);
 		/* msleep(1); */
 		data0 = (tv_8532_eeprom_data[i] & 0x000000ff);
 		reg_w_1(gspca_dev, TV8532_EEprom_DataL, data0);
@@ -232,7 +324,9 @@ static void tv_8532WriteEEprom(struct gs
 	reg_w_1(gspca_dev, TV8532_EEprom_TableLength, i);
 /*	msleep(1); */
 	reg_w_1(gspca_dev, TV8532_CTRL, TV8532_CMD_EEprom_Close);
-	msleep(10);
+	/* msleep(10); */
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
+	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
 }
 
 /* this function is called at probe time */
@@ -242,7 +336,12 @@ static int sd_config(struct gspca_dev *g
 	struct sd *sd = (struct sd *) gspca_dev;
 	struct cam *cam;
 
+	reg_w_1(gspca_dev, 0x39, 0xb0);
+	msleep(60);
+
+	if (reg_r(gspca_dev, 0x83) >> 7) {
 	tv_8532WriteEEprom(gspca_dev);
+	}
 
 	cam = &gspca_dev->cam;
 	cam->epaddr = 1;
@@ -250,7 +349,8 @@ static int sd_config(struct gspca_dev *g
 	cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
 
 	sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
-	sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+	sd->exposure = sd_ctrls[SD_EXPOSURE].qctrl.default_value;
+	sd->gain = sd_ctrls[SD_GAIN].qctrl.default_value;
 	return 0;
 }
 
@@ -271,8 +371,8 @@ static void tv_8532ReadRegisters(struct 
 	reg_r(gspca_dev, TV8532_POINT_H);
 	reg_r(gspca_dev, TV8532_POINTB_L);
 	reg_r(gspca_dev, TV8532_POINTB_H);
-	reg_r(gspca_dev, TV8532_BUDGET_L);
-	reg_r(gspca_dev, TV8532_BUDGET_H);
+	reg_r(gspca_dev, TV8532_HIGHBUDGET);
+	reg_r(gspca_dev, TV8532_LOWBUDGET);
 	reg_r(gspca_dev, TV8532_VID_L);
 	reg_r(gspca_dev, TV8532_VID_H);
 	reg_r(gspca_dev, TV8532_PID_L);
@@ -333,8 +433,16 @@ static void tv_8532_PollReg(struct gspca
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
-	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
+#if 1
+	reg_r(gspca_dev, TV8532_PID_L);
+	reg_r(gspca_dev, TV8532_PID_H);
+	msleep(1000);
+	reg_r(gspca_dev, TV8532_PID_L);
+	reg_r(gspca_dev, TV8532_PID_H);
+#else
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);	/* 0x91 */
+	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);	/* 0x94 */
+
 	tv_8532ReadRegisters(gspca_dev);
 	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
 	reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL,
@@ -375,6 +483,7 @@ static int sd_init(struct gspca_dev *gsp
 	tv_8532_setReg(gspca_dev);
 	/*************************************************/
 	tv_8532_PollReg(gspca_dev);
+#endif
 	return 0;
 }
 
@@ -383,14 +492,101 @@ static void setbrightness(struct gspca_d
 	struct sd *sd = (struct sd *) gspca_dev;
 	int brightness = sd->brightness;
 
-	reg_w_2(gspca_dev, TV8532_EXPOSURE,
-		brightness >> 8, brightness);		/* 1c */
-	reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+	//reg_w_1(gspca_dev, TV8532_DARK_DATA, brightness);
+	//reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int exposure = sd->exposure;
+
+	//reg_w_2(gspca_dev, TV8532_EXPOSURE,
+	//	exposure & 0xff, exposure >> 8);
+	//reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+	int gain = sd->gain;
+
+	//reg_w_1(gspca_dev, TV8532_AD_COLBEGIN_H,
+	//	(ADCBEGINH & (1 << 4)) + (gain << 5));
+	//reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
 }
 
 /* -- start the camera -- */
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+	int i;
+
+	sd->packet = 0;
+
+	TESTLINE = (TESTLINE & 0x3f) |
+		   (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv << 6);
+#if 1
+	reg_w_1(gspca_dev, 0x3b, 0x0a);
+
+	reg_w_1(gspca_dev, TV8532_POINTB_H, 0x00); /* something to look for */
+	reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);
+        for (i = 0; i < 100; i++) { /* loop until set */
+		if (reg_r(gspca_dev, TV8532_POINTB_H) == 0x00) {
+			break;
+		}
+		msleep(1);
+        };
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);
+
+	reg_w_1(gspca_dev, 0x3b, 0x0b);
+        //reg_w_1(gspca_dev, 0x3a, reg_r(gspca_dev, 0x3a) | 0x01); /* ??? */
+        //reg_w_1(gspca_dev, 0x38, reg_r(gspca_dev, 0x3a) & 0xfe); /* ??? */
+	reg_w_1(gspca_dev, 0x3b, 0x0a);
+	reg_w_2(gspca_dev, TV8532_ADHEIGHT_L, ADHEIGHL, ADHEIGHH);
+	reg_w_2(gspca_dev, TV8532_EXPOSURE, EXPOL, EXPOH);
+	reg_w_1(gspca_dev, TV8532_DARK_DATA, BLACKLEVEL);
+	reg_w_2(gspca_dev, TV8532_AD_COLBEGIN_L, ADCBEGINL, ADCBEGINH);
+	reg_w_2(gspca_dev, TV8532_AD_ROWBEGIN_L, ADRBEGINL, ADRBEGINH);
+
+	reg_w_1(gspca_dev, TV8532_HIGHBUDGET, HIGHBUDGET);
+	reg_w_1(gspca_dev, TV8532_LOWBUDGET, LOWBUDGET);
+
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x26); /* 0x06? 0x20/0x26 0x40/0x4a */
+	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x02);
+	reg_w_1(gspca_dev, TV8532_CTRL, 0x29); /* 0x2X -> 0x29, 0x4X -> 0x19 */
+
+	/* start of mode stuff */
+	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x26); /* 0x20/0x2f/0x26 0x40/0x4f/0x4a */
+if (1) { /*something to change */
+	reg_w_1(gspca_dev, TV8532_ADWIDTH_L, ADWIDTHL);
+	reg_w_1(gspca_dev, TV8532_ADWIDTH_H, ADWIDTHH);
+	reg_w_1(gspca_dev, TV8532_QUANT_COMP, TESTCOMP);
+	reg_w_1(gspca_dev, TV8532_MODE_PACKET, TESTLINE);
+	reg_w_1(gspca_dev, TV8532_SETCLK, TESTCLK);
+
+	reg_w_1(gspca_dev, TV8532_POINT_L, TESTPTL);
+	reg_w_1(gspca_dev, TV8532_POINT_H, TESTPTH);
+	reg_w_1(gspca_dev, TV8532_POINTB_L, TESTPTBL);
+	reg_w_1(gspca_dev, TV8532_POINTB_H, TESTPTBH);
+
+	reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x01);
+        for (i = 0; i < 100; i++) { /* loop until set */
+		if (reg_r(gspca_dev, TV8532_POINTB_H) == TESTPTBH) {
+			break;
+		}
+		msleep(1);
+        };
+	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);
+} else {
+	reg_w_1(gspca_dev, TV8532_PART_CTRL, TV8532_CMD_UPDATE);
+}
+	/* end of mode stuff */
+
+#else
 	reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32);
 	reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00);
 	tv_8532ReadRegisters(gspca_dev);
@@ -442,14 +638,19 @@ static int sd_start(struct gspca_dev *gs
 	/************************************************/
 	tv_8532_PollReg(gspca_dev);
 	reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00);	/* 0x31 */
+#endif
 	return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
+	reg_w_1(gspca_dev, 0x3b, 0x0b);
+        //reg_w_1(gspca_dev, 0x3a, reg_r(gspca_dev, 0x3a) | 0x01); /* ??? */
+        //reg_w_1(gspca_dev, 0x38, reg_r(gspca_dev, 0x38) | 0x01); /* ??? */
 }
 
+//#include "icm532_decode.h"
+
 #define MAX_PKT_LENGTH 1023
 #define WIDTH ((TESTLINE & 0x80) ? 352 : (TESTLINE & 0x40) ? 176 : 320)
 #define LINES_PER_PKT ((TESTLINE & 0x0f) + 1)
@@ -600,10 +801,6 @@ static void sd_pkt_scan(struct gspca_dev
 	sd->packet++;
 }
 
-static void setcontrast(struct gspca_dev *gspca_dev)
-{
-}
-
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
@@ -622,21 +819,39 @@ static int sd_getbrightness(struct gspca
 	return 0;
 }
 
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->exposure = val;
+	if (gspca_dev->streaming)
+		setexposure(gspca_dev);
+	return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	*val = sd->exposure;
+	return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	sd->contrast = val;
+	sd->gain = val;
 	if (gspca_dev->streaming)
-		setcontrast(gspca_dev);
+		setgain(gspca_dev);
 	return 0;
 }
 
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
 
-	*val = sd->contrast;
+	*val = sd->gain;
 	return 0;
 }

Comments

Jean-Francois Moine April 26, 2009, 10:05 a.m. UTC | #1
On Fri, 24 Apr 2009 23:16:12 +0200 (CEST)
kirin_e@users.sourceforge.net wrote:

> Hi,

Hi Kirin,

> a couple of months ago i did some hacking on the tv8532 gspca driver
> for my TV-8532A/ICM532B based webcam, to the point where i got
> decompression and most modes working. But i've kind of lost interest
> at this point, so haven't bothered to clean everything up for a real
> patch(also noticed it doesn't apply cleanly on 2.6.29 anymore).
> 
> In case it could be of help to someone else i've attached my two
> patches against the 2.6.28 kernel driver. First one fixes packet
> handling so it works with the different modes, the second add the
> actual modes i've been using + some misc changes i've been playing
> around with. Feel free to use or ignore as you will.
> 
> And probably the more useful part of my hacking, here's my notes on
> the compression used(got working decompression code, but not in a
> state i'd like to release):
	[snip]

Your patches seem very interesting! I would have merge it by myself,
but I have too much work. May you do patches for my test repository
(http://linuxtv.org/hg/~jfrancois/gspca)?

Cheers.
kirin_e@users.sourceforge.net April 28, 2009, 9:05 a.m. UTC | #2
On Sun, 26 Apr 2009, Jean-Francois Moine wrote:

> On Fri, 24 Apr 2009 23:16:12 +0200 (CEST)
> kirin_e@users.sourceforge.net wrote:
>
> > Hi,
>
> Hi Kirin,
>
> > a couple of months ago i did some hacking on the tv8532 gspca driver
> > for my TV-8532A/ICM532B based webcam, to the point where i got
> > decompression and most modes working. But i've kind of lost interest
> > at this point, so haven't bothered to clean everything up for a real
> > patch(also noticed it doesn't apply cleanly on 2.6.29 anymore).
> >=20
> > In case it could be of help to someone else i've attached my two
> > patches against the 2.6.28 kernel driver. First one fixes packet
> > handling so it works with the different modes, the second add the
> > actual modes i've been using + some misc changes i've been playing
> > around with. Feel free to use or ignore as you will.
> >=20
> > And probably the more useful part of my hacking, here's my notes on
> > the compression used(got working decompression code, but not in a
> > state i'd like to release):
>                [snip]
>
> Your patches seem very interesting! I would have merge it by myself,
> but I have too much work. May you do patches for my test repository
> (http://linuxtv.org/hg/~jfrancois/gspca)?

Hi Jean-Francois,

i'll see if can get around to making a working patch against your
repository sometime. At the moment i have the same problem as you, too
much other stuff taking my time and interest.

Btw, if you've been working with the gspca drivers do you have any opinion
on where to put the decompression code? I know libv4lconvert exists so it
shouldn't be done in the kernel. But what to do if decompression is
depending on driver state like quantization settings and packet headers,
should the settings just be sent along with the image data to
libv4lconvert so it can do the correct thing? For now i've been doing it
all in the driver.

//kirin
p]
>
> Your patches seem very interesting! I would have merge it by myself,
> but I have too much work. May you do patches for my test repository
> (http://linuxtv.org/hg/~jfrancois/gspca)?

Hi Jean-Francois,

i'll see if can get around to making a working patch against your
repository sometime. At the moment i have the same problem as you, too
much other stuff taking my time and interest.

Btw, if you've been working with the gspca drivers do you have any opinion
on where to put the decompression code? I know libv4lconvert exists so it
shouldn't be done in the kernel. But what to do if decompression is
depending on driver state like quantization settings and packet headers,
should the settings just be sent along with the image data to
libv4lconvert so it can do the correct thing? For now i've been doing it
all in the driver.

//kirin
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

--- 2/linux-2.6.28/drivers/media/video/gspca/tv8532.c	2008-12-25 00:26:37.000000000 +0100
+++ tv8532_2.c	2009-03-05 22:24:05.000000000 +0100
@@ -37,8 +37,7 @@ 
 	unsigned short brightness;
 	unsigned short contrast;
 
-	char packet;
-	char synchro;
+	unsigned int packet;
 };
 
 /* V4L2 controls supported by the driver */
@@ -451,35 +450,45 @@ 
 	reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b);
 }
 
+#define MAX_PKT_LENGTH 1023
+#define WIDTH ((TESTLINE & 0x80) ? 352 : (TESTLINE & 0x40) ? 176 : 320)
+#define LINES_PER_PKT ((TESTLINE & 0x0f) + 1)
+#define PKT_LENGTH ((TESTCOMP & 0x80) ? \
+	(3 + (2 + WIDTH + 3 + WIDTH + 2)) : \
+	(3 + (((16 + WIDTH - 2) * LINES_PER_PKT + 7) >> 3)))
+
+static const int num_pkts[][17] = { /* ceil(height / lines_per_pkt) */
+	{ 0, 240, 120, 80, 60, 48, 40, 34, 30, 26, 24, 21, 20, 18, 17, 16, 15 },
+	{ 0, 144, 72, 48, 36, 29, 24, 21, 18, 16, 15, 14, 12, 12, 11, 10, 9 },
+	{ 0, 288, 144, 96, 72, 58, 48, 42, 36, 32, 29, 27, 24, 23, 21, 20, 18 },
+	{ 0, 288, 144, 96, 72, 58, 48, 42, 36, 32, 29, 27, 24, 23, 21, 20, 18 },
+};
+
 static void tv8532_preprocess(struct gspca_dev *gspca_dev)
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-/* we should received a whole frame with header and EOL marker
- * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2
- * sequence 2bytes header the Alternate pixels bayer GB 4 bytes
- * Alternate pixels bayer RG 4 bytes EOL */
-	int width = gspca_dev->width;
-	int height = gspca_dev->height;
-	unsigned char *dst = sd->tmpbuf2;
-	unsigned char *data = sd->tmpbuf;
-	int i;
-
-	/* precompute where is the good bayer line */
-	if (((data[3] + data[width + 7]) >> 1)
-	    + (data[4] >> 2)
-	    + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1)
-	    + (data[3] >> 2)
-	    + (data[width + 5] >> 1))
-		data += 3;
-	else
-		data += 2;
-	for (i = 0; i < height / 2; i++) {
-		memcpy(dst, data, width);
-		data += width + 3;
-		dst += width;
-		memcpy(dst, data, width);
-		data += width + 7;
-		dst += width;
+	int pkts_needed = num_pkts[TESTLINE >> 6][LINES_PER_PKT];
+	int i, j;
+	__u8 *dst = sd->tmpbuf2;
+	__u8 *src = sd->tmpbuf;
+	__u8 *max;
+
+	if (TESTCOMP & 0x80) {
+		for (i = 0; i < pkts_needed; i++) {
+			max = src + MAX_PKT_LENGTH;
+			src++;
+			for (j = 0; j < LINES_PER_PKT; j++) {
+				src++;
+				memcpy(dst, src, WIDTH);
+				src += WIDTH + 2;
+				dst += WIDTH;
+			}
+			src += 3;
+			src = (src > max) ? max : src;
+		}
+	} else {
+		//icm532_decode(dst, src, width, height,
+		//	      QUANT, LINES_PER_PKT, MAX_PKT_LENGTH, 0);
 	}
 }
 
@@ -489,73 +498,106 @@ 
 			int len)			/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
+	int pkts_needed = num_pkts[TESTLINE >> 6][LINES_PER_PKT];
 
-	if (data[0] != 0x80) {
-		sd->packet++;
-		if (sd->buflen + len > sizeof sd->tmpbuf) {
-			if (gspca_dev->last_packet_type != DISCARD_PACKET) {
-				PDEBUG(D_PACK, "buffer overflow");
-				gspca_dev->last_packet_type = DISCARD_PACKET;
-			}
+	//printk("packet: %d id: 0x%02x size: %d "
+	//	"start: %02x %02x %02x %02x end: %02x %02x %02x %02x\n",
+	//	sd->packet, data[0], len,
+	//	data[1], data[2], data[3], data[4],
+	//	data[len - 4], data[len - 3], data[len - 2], data[len - 1]);
+
+	/* 6-bit counter wraps after 64 packets or on a new frame */
+
+	while ((sd->packet & 0x3f) > (data[0] & 0x3f)) {
+		if ((sd->packet & 0x3f) < (data[0] & 0x3f) + 2) {
+			//printk("dropped duplicate packet %d(0x%02x)\n",
+			//	sd->packet, data[0]);
 			return;
 		}
-		memcpy(&sd->tmpbuf[sd->buflen], data, len);
-		sd->buflen += len;
-		return;
-	}
-
-	/* here we detect 0x80 */
-	/* counter is limited so we need few header for a frame :) */
 
-	/* header 0x80 0x80 0x80 0x80 0x80 */
-	/* packet  00   63  127  145  00   */
-	/* sof     0     1   1    0    0   */
-
-	/* update sequence */
-	if (sd->packet == 63 || sd->packet == 127)
-		sd->synchro = 1;
-
-	/* is there a frame start ? */
-	if (sd->packet >= (gspca_dev->height >> 1) - 1) {
-		PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro,
-		       sd->packet);
-		if (!sd->synchro) {	/* start of frame */
+		if ((sd->packet >= pkts_needed)) {
 			if (gspca_dev->last_packet_type == FIRST_PACKET) {
 				tv8532_preprocess(gspca_dev);
 				frame = gspca_frame_add(gspca_dev,
 							LAST_PACKET,
 							frame, sd->tmpbuf2,
 							gspca_dev->width *
-							    gspca_dev->width);
+							gspca_dev->height);
 			}
 			gspca_frame_add(gspca_dev, FIRST_PACKET,
 					frame, data, 0);
-			memcpy(sd->tmpbuf, data, len);
-			sd->buflen = len;
+			sd->buflen = 0;
+			sd->packet = 0;
+			break;
+		}
+
+		//printk("over %d\n", sd->packet);
+		if (sd->buflen + PKT_LENGTH > sizeof sd->tmpbuf) {
+			if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+				PDEBUG(D_PACK, "buffer overflow");
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+			}
+			sd->buflen = 0;
 			sd->packet = 0;
 			return;
 		}
-		if (gspca_dev->last_packet_type != DISCARD_PACKET) {
-			PDEBUG(D_PACK,
-			       "Warning wrong TV8532 frame detection %d",
-			       sd->packet);
-			gspca_dev->last_packet_type = DISCARD_PACKET;
+		sd->tmpbuf[sd->buflen + 0] = 0x80 | (sd->packet & 0x3f);
+		sd->tmpbuf[sd->buflen + 1] = 0xff;
+		sd->tmpbuf[sd->buflen + 2] = 0x00;
+		memset(&sd->tmpbuf[sd->buflen + 3], 0x00, PKT_LENGTH - 5);
+		sd->tmpbuf[sd->buflen + PKT_LENGTH - 2] = 0xff;
+		sd->tmpbuf[sd->buflen + PKT_LENGTH - 1] = 0xff;
+		sd->buflen += PKT_LENGTH;
+		sd->packet++;
+
+		sd->packet = sd->packet & 0x3f;
+	}
+
+	while ((sd->packet & 0x3f) < (data[0] & 0x3f)) {
+		if (sd->packet >= pkts_needed) {
+			break;
 		}
-		return;
+
+		//printk("under %d\n", sd->packet);
+		if (sd->buflen + PKT_LENGTH > sizeof sd->tmpbuf) {
+			if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+				PDEBUG(D_PACK, "buffer overflow");
+				gspca_dev->last_packet_type = DISCARD_PACKET;
+			}
+			sd->buflen = 0;
+			sd->packet = 0;
+			return;
+		}
+		sd->tmpbuf[sd->buflen + 0] = 0x80 | (sd->packet & 0x3f);
+		sd->tmpbuf[sd->buflen + 1] = 0x00;
+		sd->tmpbuf[sd->buflen + 2] = 0xff;
+		memset(&sd->tmpbuf[sd->buflen + 3], 0x00, PKT_LENGTH - 5);
+		sd->tmpbuf[sd->buflen + PKT_LENGTH - 2] = 0xff;
+		sd->tmpbuf[sd->buflen + PKT_LENGTH - 1] = 0xff;
+		sd->buflen += PKT_LENGTH;
+		sd->packet++;
 	}
 
-	if (!sd->synchro) {
-		/* Drop packet frame corrupt */
-		PDEBUG(D_PACK, "DROP SOF %d packet %d",
-		       sd->synchro, sd->packet);
+	if (sd->packet >= pkts_needed) {
+		//printk("dropped packet %d(0x%02x)\n", sd->packet, data[0]);
+		sd->packet = pkts_needed;
+		return;
+	}
+	
+	if (sd->buflen + len > sizeof sd->tmpbuf) {
+		if (gspca_dev->last_packet_type != DISCARD_PACKET) {
+			PDEBUG(D_PACK, "buffer overflow");
+			gspca_dev->last_packet_type = DISCARD_PACKET;
+		}
+		sd->buflen = 0;
 		sd->packet = 0;
-		gspca_dev->last_packet_type = DISCARD_PACKET;
 		return;
 	}
-	sd->synchro = 1;
-	sd->packet++;
+
+	//printk("saved packet %d(0x%02x)\n", sd->packet, data[0]);
 	memcpy(&sd->tmpbuf[sd->buflen], data, len);
 	sd->buflen += len;
+	sd->packet++;
 }
 
 static void setcontrast(struct gspca_dev *gspca_dev)