diff -Naur linux-2.4.0-test12-ov511-1.29/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt --- linux-2.4.0-test12-ov511-1.29/Documentation/usb/ov511.txt Thu Jan 4 03:55:50 2001 +++ linux/Documentation/usb/ov511.txt Thu Jan 4 03:56:18 2001 @@ -8,7 +8,7 @@ INTRODUCTION: This is a driver for the OV511, a USB-only chip used in many "webcam" devices. -Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It +Any camera using the OV511/OV511+ and the OV6620/OV7610/20/20AE CCD should work. It supports streaming and capture of color or monochrome video via the Video4Linux API. Most V4L apps are compatible with it, but a few video-conferencing programs do not work yet. The following resolutions are supported: 640x480, 448x336, @@ -29,14 +29,14 @@ You must have first compiled USB support, support for your specific USB host controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend -making them modules.) +making them modules.) Make sure "Enforce bandwidth allocation" is NOT enabled. -Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX): +Next, (as root): - insmod usb/usbcore.o - insmod usb/usb-uhci.o insmod usb/ohci-hcd.o - insmod misc/videodev.o - insmod usb/ov511.o + modprobe usbcore + modprobe usb-uhci modprobe usb-ohci + modprobe videodev + modprobe ov511 If it is not already there (it usually is), create the video device: @@ -60,21 +60,14 @@ [Using xawtv:] -You must make some modifications to the source and compile it before you use it. -(Note: this may not be applicable to versions other than 3.06) - -In src/Xawtv.ad, change xawtv.tv.width to 640 and xawtv.tv.height to 480. Next, -in src/grab-v4l.c, change SYNC_TIMEOUT from 1 to 2. Then, from the main xawtv -directory: +From the main xawtv directory: make clean ./configure make make install -Now you should be able to run xawtv. Right click for the options dialog. If -you get a scrambled image it is likely that you made a mistake in Xawtv.ad. -Try setting the size to 320x240 if all else fails. +Now you should be able to run xawtv. Right click for the options dialog. MODULE PARAMETERS: @@ -218,13 +211,11 @@ o Snapshot mode o GBR422 parsing o 160x120 + o OV6630 sensor support TO-DO: o Fix the noise / grainy image problem. - o Get compression working. It would be a nice addition as it improves - frame rate quite a bit. OmniVision wouldn't tell me how the algorithm works, - so we can't really work on that yet. Please kindly inform OmniVision that you - would like them to release their specifications to the Linux community. + o Get compression working. o YUV422 o Fix fixFrameRGBoffset(). It is not stable yet with streaming video. o V4L2 support (Probably not until it goes into the kernel) @@ -238,8 +229,9 @@ o The image should always be written properly to the mmap'ed buffer as long as the requested image size is at least the minimum size. This will likely require a rewrite of all the parsing code. - o OV6630 and OV8600 sensor support (both are undocumented and not in use yet) + o OV8600 sensor support (Not used in anything yet) o OV518+ support + o cams >= 3 not working HOW TO CONTACT ME: diff -Naur linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.c Thu Jan 4 03:56:03 2001 +++ linux/drivers/usb/ov511.c Thu Jan 4 04:11:02 2001 @@ -30,7 +30,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = "1.29"; +static const char version[] = "1.30"; #define __NO_VERSION__ @@ -155,8 +155,6 @@ MODULE_AUTHOR("Mark McClelland & Bret Wallach & Orion Sky Lawlor & Kevin Moore & Charl P. Botha & Claudio Matsuoka "); MODULE_DESCRIPTION("OV511 USB Camera Driver"); -char kernel_version[] = UTS_RELEASE; - static struct usb_driver ov511_driver; /* I know, I know, global variables suck. This is only a temporary hack */ @@ -186,7 +184,6 @@ { idVendor: 0x05a9, idProduct: 0xA511 }, /* OV511+ */ { idVendor: 0x05a9, idProduct: 0x0518 }, /* OV518+ */ { idVendor: 0x0813, idProduct: 0x0002 }, /* Intel Play Me2Cam OV511+ */ - { idVendor: 0x041e, idProduct: 0x4003 }, /* Creative Webcam Go Plus */ { } /* Terminating entry */ }; @@ -355,6 +352,7 @@ out += sprintf (out, "brightness : %d\n", ov511->brightness >> 8); out += sprintf (out, "colour : %d\n", ov511->colour >> 8); out += sprintf (out, "contrast : %d\n", ov511->contrast >> 8); + out += sprintf (out, "hue : %d\n", ov511->hue >> 8); out += sprintf (out, "num_frames : %d\n", OV511_NUMFRAMES); for (i = 0; i < OV511_NUMFRAMES; i++) { out += sprintf (out, "frame : %d\n", i); @@ -380,12 +378,16 @@ out += sprintf (out, "bridge : %s\n", ov511->bridge == BRG_OV511 ? "OV511" : ov511->bridge == BRG_OV511PLUS ? "OV511+" : + ov511->bridge == BRG_OV518PLUS ? "OV518+" : "unknown"); out += sprintf (out, "sensor : %s\n", ov511->sensor == SEN_OV6620 ? "OV6620" : + ov511->sensor == SEN_OV6630 ? "OV6630" : ov511->sensor == SEN_OV7610 ? "OV7610" : ov511->sensor == SEN_OV7620 ? "OV7620" : ov511->sensor == SEN_OV7620AE ? "OV7620AE" : + ov511->sensor == SEN_OV8600 ? "OV8600" : + ov511->sensor == SEN_KS0127 ? "KS0127" : "unknown"); out += sprintf (out, "packet_size : %d\n", ov511->packet_size); out += sprintf (out, "framebuffer : 0x%p\n", ov511->fbuf); @@ -522,6 +524,32 @@ } } +/* + * Writes bits at positions specified by mask to a reg. Bits that are in + * the same position as 1's in "mask" are cleared and set to "value". Bits + * that are in the same position as 0's in "mask" are preserved, regardless + * of their respective state in "value". + */ +static int ov511_reg_write_mask(struct usb_device *dev, + unsigned char reg, + unsigned char value, + unsigned char mask) +{ + int ret; + unsigned char oldval, newval; + + ret = ov511_reg_read(dev, reg); + if (ret < 0) + return ret; + + oldval = (unsigned char) ret; + oldval &= (~mask); /* Clear the masked bits */ + value &= mask; /* Enforce mask on value */ + newval = oldval | value; /* Set the desired bits */ + + return (ov511_reg_write(dev, reg, newval)); +} + static int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value) @@ -808,6 +836,19 @@ err("Set packet size: invalid size (%d)", size); return -EINVAL; } + } else if (ov511->bridge == BRG_OV518PLUS) { + if (size == 0) alt = OV518PLUS_ALT_SIZE_0; + else if (size == 128) alt = OV518PLUS_ALT_SIZE_128; + else if (size == 256) alt = OV518PLUS_ALT_SIZE_256; + else if (size == 384) alt = OV518PLUS_ALT_SIZE_384; + else if (size == 512) alt = OV518PLUS_ALT_SIZE_512; + else if (size == 640) alt = OV518PLUS_ALT_SIZE_640; + else if (size == 768) alt = OV518PLUS_ALT_SIZE_768; + else if (size == 896) alt = OV518PLUS_ALT_SIZE_896; + else { + err("Set packet size: invalid size (%d)", size); + return -EINVAL; + } } else { err("Set packet size: Invalid bridge type"); return -EINVAL; @@ -958,7 +999,7 @@ ov511_led_control(struct usb_ov511 *ov511, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); - if (ov511->bridge == BRG_OV511PLUS) + if (ov511->bridge == BRG_OV511PLUS) // FIXME: OV518+? ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_LED_CTL, enable ? 1 : 0); @@ -1027,7 +1068,7 @@ ov511_reg_write(dev, 0x16, 0x00); if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) { - /* these aren't valid on the OV6620/OV7620 */ + /* these aren't valid on the OV6620/OV7620/6630? */ ov511_i2c_write(dev, 0x0e, 0x44); } ov511_i2c_write_mask(dev, 0x13, autoadjust ? 0x21 : 0x20, 0x21); @@ -1039,7 +1080,7 @@ ov511_reg_write(dev, 0x16, 0x01); if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) { - /* not valid on the OV6620/OV7620 */ + /* not valid on the OV6620/OV7620/6630? */ ov511_i2c_write(dev, 0x0e, 0x04); } ov511_i2c_write_mask(dev, 0x13, autoadjust ? 0x01 : 0x00, 0x21); @@ -1058,6 +1099,7 @@ vwsbase = vwebase = 0x05; break; case SEN_OV6620: + case SEN_OV6630: // FIXME: Is this right? hwsbase = 0x38; hwebase = 0x3a; vwsbase = 0x05; @@ -1177,7 +1219,7 @@ if (ov511_i2c_write_mask(dev, 0x12, autoadjust ? 0x20 : 0x00, 0x20) < 0) return -1; - /* 7620/6620 don't have register 0x35, so play it safe */ + /* 7620/6620/6630? don't have register 0x35, so play it safe */ if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) ov511_i2c_write(dev, 0x35, mlist[i].common_L); @@ -1714,10 +1756,19 @@ int aPackNum[10]; struct ov511_frame *frame; unsigned char *pData; - int iPix; + int iPix, data_size, pn; PDEBUG (4, "Moving %d packets", urb->number_of_packets); + /* OV518+ has no packet numbering */ + if (ov511->bridge == BRG_OV518PLUS) { + pn = 0; + data_size = ov511->packet_size; + } else { + pn = 1; + data_size = ov511->packet_size - 1; + } + for (i = 0; i < urb->number_of_packets; i++) { int n = urb->iso_frame_desc[i].actual_length; int st = urb->iso_frame_desc[i].status; @@ -1727,7 +1778,8 @@ cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; + if (pn) + aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1; if (!n || ov511->curframe == -1) continue; @@ -1736,7 +1788,7 @@ PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st); frame = &ov511->frame[ov511->curframe]; - + /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th * byte non-zero. The EOF packet has image width/height in the * 10th and 11th bytes. The 9th bit is given as follows: @@ -1764,8 +1816,9 @@ ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE); do_gettimeofday (ts); - PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d", - ov511->curframe, (int)(cdata[ov511->packet_size - 1]), + PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d", + ov511->curframe, + (int)(pn ? cdata[ov511->packet_size - 1] : -1), (int)(cdata[9]), (int)(cdata[10])); if (frame->scanstate == STATE_LINES) { @@ -1839,7 +1892,7 @@ } /* Parse the segments */ - while (iPix <= (ov511->packet_size - 1) - frame->segsize && + while (iPix <= data_size - frame->segsize && frame->segment < frame->width * frame->height / 256) { int iSegY, iSegUV; int iY, jY, iUV, jUV; @@ -1923,7 +1976,7 @@ /* Save extra data for next time */ if (frame->segment < frame->width * frame->height / 256) { - ov511->scratchlen = (ov511->packet_size - 1) - iPix; + ov511->scratchlen = data_size - iPix; if (ov511->scratchlen < frame->segsize) memmove(ov511->scratch, pData, ov511->scratchlen); else @@ -1931,9 +1984,11 @@ } } - PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", - aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], - aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); + if (pn) { + PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d", + aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4], + aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]); + } return totlen; } @@ -1960,9 +2015,14 @@ PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } - + sbuf = &ov511->sbuf[ov511->cursbuf]; + if (sbuf == NULL) { + err("null scrath buffer pointer!"); + return; + } + /* Copy the data received into our scratch buffer */ if (ov511->curframe >= 0) { len = ov511_move_data(ov511, urb); @@ -1990,25 +2050,34 @@ ov511->cursbuf = 0; ov511->scratchlen = 0; - if (ov511->bridge == BRG_OV511) - if (cams == 1) size = 993; - else if (cams == 2) size = 513; - else if (cams == 3 || cams == 4) size = 257; + if (ov511->bridge == BRG_OV511) { + if (cams == 1) size = 993; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; else { err("\"cams\" parameter too high!"); return -1; } - else if (ov511->bridge == BRG_OV511PLUS) - if (cams == 1) size = 961; - else if (cams == 2) size = 513; - else if (cams == 3 || cams == 4) size = 257; - else if (cams >= 5 && cams <= 8) size = 129; - else if (cams >= 9 && cams <= 31) size = 33; + } else if (ov511->bridge == BRG_OV511PLUS) { + if (cams == 1) size = 961; + else if (cams == 2) size = 513; + else if (cams == 3 || cams == 4) size = 257; + else if (cams >= 5 && cams <= 8) size = 129; + else if (cams >= 9 && cams <= 31) size = 33; else { err("\"cams\" parameter too high!"); return -1; } - else { + } else if (ov511->bridge == BRG_OV518PLUS) { + if (cams == 1) size = 896; + else if (cams == 2) size = 512; + else if (cams == 3 || cams == 4) size = 256; + else if (cams >= 5 && cams <= 8) size = 128; + else { + err("\"cams\" parameter too high!"); + return -1; + } + } else { err("invalid bridge type"); return -1; } @@ -3118,6 +3187,86 @@ { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */ { OV511_I2C_BUS, 0x4e, 0xc1 }, { OV511_I2C_BUS, 0x4f, 0x04 }, +// Do 50-53 have any effect? +// Toggle 0x12[2] off and on here? + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + /* This chip is undocumented so many of these are guesses. OK=verified, + * A=Added since 6620, U=unknown function (not a 6620 reg) */ + static struct ov511_regvals aRegvalsNorm6x30[] = { + /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + /*00?*/ { OV511_I2C_BUS, 0x11, 0x01 }, + /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, + /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ +// { OV511_I2C_BUS, 0x07, 0xa8 }, /* Does 6630 have this? */ + /* The ratio of 0x0c and 0x0d controls the white point */ + /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, + /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, + /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, + /*24?*/ { OV511_I2C_BUS, 0x12, 0x28 }, /* Enable AGC */ + /*A*/ { OV511_I2C_BUS, 0x13, 0x21 }, + /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + /*03?*/ { OV511_I2C_BUS, 0x16, 0x06 }, +// /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ + // 21 & 22? The suggested values look wrong. Go with default + /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, + /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default + /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ + /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, /* Selects RGB format if RGB on */ + /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ + /*U*/ { OV511_I2C_BUS, 0x2c, 0xa0 }, + /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 + // Reg 0x34: More 6620 reserved junk + /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ + /*U*/ { OV511_I2C_BUS, 0x36, 0x8f }, // May not be necessary + /*U*/ { OV511_I2C_BUS, 0x37, 0x80 }, // May not be necessary + /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, + /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 + //Check these again + { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ + { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ + { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ + + /*OK*/ { OV511_I2C_BUS, 0x3d, 0x80 }, + /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, // Reserved bits on 6620. Default may be safer. + + /*U*/ { OV511_I2C_BUS, 0x40, 0x00 }, + /*U*/ { OV511_I2C_BUS, 0x41, 0x00 }, + /*U*/ { OV511_I2C_BUS, 0x42, 0x80 }, + /*U*/ { OV511_I2C_BUS, 0x43, 0x3f }, + /*U*/ { OV511_I2C_BUS, 0x44, 0x80 }, + /*U*/ { OV511_I2C_BUS, 0x45, 0x20 }, + /*U*/ { OV511_I2C_BUS, 0x46, 0x20 }, + /*U*/ { OV511_I2C_BUS, 0x47, 0x80 }, + /*U*/ { OV511_I2C_BUS, 0x48, 0x7f }, + /*U*/ { OV511_I2C_BUS, 0x49, 0x00 }, + + /* These next two registers (0x4a, 0x4b) are undocumented. They + * control the color balance */ + /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these + /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, + /*U*/ { OV511_I2C_BUS, 0x4c, 0xd0 }, // These high registers are always suspect + /*d2?*/ { OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */ + /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, + /*04?*/ { OV511_I2C_BUS, 0x4f, 0x07 }, + + /*U*/ { OV511_I2C_BUS, 0x50, 0xff }, // These are all undocumented (by 6620 docs) + /*U*/ { OV511_I2C_BUS, 0x54, 0x23 }, + /*U*/ { OV511_I2C_BUS, 0x55, 0xff }, + /*U*/ { OV511_I2C_BUS, 0x56, 0x12 }, + /*U*/ { OV511_I2C_BUS, 0x57, 0x81 }, + /*U*/ { OV511_I2C_BUS, 0x58, 0x75 }, + /*U*/ { OV511_I2C_BUS, 0x59, 0x01 }, + /*U*/ { OV511_I2C_BUS, 0x5a, 0x2c }, + /*U*/ { OV511_I2C_BUS, 0x5b, 0x0f }, + /*U*/ { OV511_I2C_BUS, 0x5c, 0x10 }, + +// Set 0x3d to 0x80 here? +// Set 0x27 to 0xa6 here? +// Toggle 0x12[2] off and on here? { OV511_DONE_BUS, 0x0, 0x00 }, }; @@ -3162,28 +3311,40 @@ return -1; } else if((rc & 3) == 0) { info("Sensor is an OV6630"); - ov511->sensor = SEN_OV6620; /* Closest match? */ + ov511->sensor = SEN_OV6630; } else if((rc & 3) == 1) { info("Sensor is an OV6620"); ov511->sensor = SEN_OV6620; - } else { - err("Sensor is an unknown OV6xx0 (version %d)", rc & 3); - err("Please email mwm@i.am to report this"); - return -1; - } + } else if((rc & 3) == 2) { + info("Sensor is an OV6630AE"); + ov511->sensor = SEN_OV6630; + } else if((rc & 3) == 3) { + info("Sensor is an OV6630AF"); + ov511->sensor = SEN_OV6630; + } } else { /* sensor != 0; user overrode detection */ ov511->sensor = sensor; info("Sensor set to type %d", ov511->sensor); } /* Set sensor-specific vars */ - ov511->maxwidth = 352; - ov511->maxheight = 288; + if (ov511->sensor == SEN_OV6620) { + ov511->maxwidth = 352; + ov511->maxheight = 288; - PDEBUG(4, "Writing 6x20 registers"); - if (ov511_write_regvals(dev, aRegvalsNorm6x20)) - return -1; + PDEBUG(4, "Writing 6x20 registers"); + if (ov511_write_regvals(dev, aRegvalsNorm6x20)) + return -1; + } else { + /* Oddly, 6630 series is 640x480 */ + ov511->maxwidth = 640; + ov511->maxheight = 480; + PDEBUG(4, "Writing 6x30 registers"); + if (ov511_write_regvals(dev, aRegvalsNorm6x30)) + return -1; + } + if (aperture < 0) { /* go with the default */ if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1; } else if (aperture <= 0xf) { /* user overrode default */ @@ -3195,10 +3356,10 @@ } if (autoadjust) { - if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1; + if (ov511_i2c_write_mask(dev, 0x13, 0x01, 0x01) < 0) return -1; if (ov511_i2c_write(dev, 0x2d, 0x99) < 0) return -1; } else { - if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1; + if (ov511_i2c_write_mask(dev, 0x13, 0x00, 0x01) < 0) return -1; if (ov511_i2c_write(dev, 0x2d, 0x89) < 0) return -1; if (ov511_i2c_write_mask(dev, 0x28, 0x08, 0x08) < 0) return -1; } @@ -3241,6 +3402,19 @@ { OV511_DONE_BUS, 0x0, 0x00 }, }; + static struct ov511_regvals aRegvalsNorm518Plus[] = { + { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x09 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 }, + { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x0f }, + { OV511_REG_BUS, 0x24, 0x9f }, + { OV511_REG_BUS, 0x25, 0x90 }, + { OV511_REG_BUS, OV511_REG_SYSTEM_CLOCK_DIVISOR, 0x04 }, /* ? */ + { OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x00 }, + { OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x00 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template)); for (i = 0; i < OV511_NUMFRAMES; i++) @@ -3258,7 +3432,13 @@ if (ov511->led_policy == LED_OFF || ov511->led_policy == LED_AUTO) ov511_led_control(ov511, 0); - if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error; + if (ov511->bridge == BRG_OV518PLUS) { + if (ov511_write_regvals(dev, aRegvalsNorm518Plus)) goto error; + /* The next setting may not be necessary */ + if (ov511_reg_write_mask(dev, 0x57,0x00, 0x02) < 0) goto error; + } else { + if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error; + } ov511_set_packet_size(ov511, 0); @@ -3342,6 +3522,13 @@ return 0; error: + err("Config failed"); + + #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) + /* Safe to call even if entry doesn't exist */ + destroy_proc_ov511_cam((struct usb_ov511 *)dev); + #endif + video_unregister_device(&ov511->vdev); usb_driver_release_interface(&ov511_driver, &dev->actconfig->interface[ov511->iface]); @@ -3402,9 +3589,7 @@ break; case 0x0518: info("USB OV518+ camera found"); - err("Warning: OV518+ not supported yet!"); - ov511->bridge = BRG_OV511PLUS; /* A safe default for now */ -// ov511->bridge = BRG_OV518PLUS; + ov511->bridge = BRG_OV518PLUS; break; case 0x0002: if (dev->descriptor.idVendor != 0x0813) @@ -3412,12 +3597,6 @@ info("Intel Play Me2Cam (OV511+) found"); ov511->bridge = BRG_OV511PLUS; break; - case 0x4003: - info("Creative WebCam Go Plus (OV518+) found"); - err("Warning: Creative WebCam Go Plus not supported yet!"); - ov511->bridge = BRG_OV511PLUS; /* A safe default for now */ -// ov511->bridge = BRG_OV518PLUS; - break; default: err("Unknown product ID"); goto error; @@ -3465,7 +3644,6 @@ init_MUTEX(&ov511->buf_lock); ov511->buf_state = BUF_NOT_ALLOCATED; } else { - err("Failed to configure camera"); goto error; } @@ -3473,6 +3651,7 @@ return ov511; error: + err("Camera initialization failed"); if (ov511) { kfree(ov511); ov511 = NULL; diff -Naur linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.h linux/drivers/usb/ov511.h --- linux-2.4.0-test12-ov511-1.29/drivers/usb/ov511.h Thu Jan 4 03:56:03 2001 +++ linux/drivers/usb/ov511.h Thu Jan 4 04:11:03 2001 @@ -119,6 +119,16 @@ #define OV511PLUS_ALT_SIZE_769 6 #define OV511PLUS_ALT_SIZE_961 7 +/* Alternate numbers for various max packet sizes (OV518+ only) */ +#define OV518PLUS_ALT_SIZE_0 0 +#define OV518PLUS_ALT_SIZE_128 1 +#define OV518PLUS_ALT_SIZE_256 2 +#define OV518PLUS_ALT_SIZE_384 3 +#define OV518PLUS_ALT_SIZE_512 4 +#define OV518PLUS_ALT_SIZE_640 5 +#define OV518PLUS_ALT_SIZE_768 6 +#define OV518PLUS_ALT_SIZE_896 7 + /* OV7610 registers */ #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */ #define OV7610_REG_BLUE 0x01 /* blue channel balance */ @@ -179,8 +189,7 @@ #define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */ -// CAMERA SPECIFIC -// FIXME - these can vary between specific models +/* CAMERA SPECIFIC */ #define OV7610_I2C_WRITE_ID 0x42 #define OV7610_I2C_READ_ID 0x43 #define OV6xx0_I2C_WRITE_ID 0xC0 @@ -213,6 +222,7 @@ SEN_OV6620, SEN_OV6630, SEN_OV8600, + SEN_KS0127, }; enum {