From patchwork Fri Apr 24 21:16:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: kirin_e@users.sourceforge.net X-Patchwork-Id: 19871 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n3OLGIqf013774 for ; Fri, 24 Apr 2009 21:16:18 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752655AbZDXVQR (ORCPT ); Fri, 24 Apr 2009 17:16:17 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753308AbZDXVQR (ORCPT ); Fri, 24 Apr 2009 17:16:17 -0400 Received: from mail.foxt.com ([192.71.43.9]:52900 "EHLO milton.foxt.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752655AbZDXVQP (ORCPT ); Fri, 24 Apr 2009 17:16:15 -0400 X-Greylist: delayed 826 seconds by postgrey-1.27 at vger.kernel.org; Fri, 24 Apr 2009 17:16:14 EDT Date: Fri, 24 Apr 2009 23:16:12 +0200 (CEST) From: kirin_e@users.sourceforge.net To: linux-media@vger.kernel.org Subject: TV-8532A/ICM532B compression and modes Message-ID: MIME-Version: 1.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org 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; } --- 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)