ChangeSet 1.893.2.5, 2002/12/23 11:47:29-08:00, mark@hal9000.dyndns.org [PATCH] Update ov511 to version 1.63. This is a backport of the 2.5 driver, Notable changes: * Make use of usb_make_path() * Fix an oops when snapshot mode is enabled * Get rid of automagic resubmit * OV518 is closer to working * Clean up OV6x30 register settings * Remove some dead code diff -Nru a/Documentation/usb/ov511.txt b/Documentation/usb/ov511.txt --- a/Documentation/usb/ov511.txt Mon Jan 6 11:32:21 2003 +++ b/Documentation/usb/ov511.txt Mon Jan 6 11:32:21 2003 @@ -276,6 +276,15 @@ might be necessary if your camera has a custom lens assembly. This has no effect with video capture devices. + NAME: ov518_color + TYPE: integer (Boolean) + DEFAULT: 0 (off) + DESC: Enable OV518 color support. This is off by default since it doesn't + work most of the time. If you want to try it, you must also load + ov518_decomp with the "nouv=0" parameter. If you get improper colors or + diagonal lines through the image, restart your video app and try again. + Repeat as necessary. + WORKING FEATURES: o Color streaming/capture at most widths and heights that are multiples of 8. o RGB24, RGB565, YUV420/YUV420P, YUV422/YUYV, and YUV422P color @@ -285,6 +294,7 @@ o /proc status reporting o SAA7111A video capture support at 320x240 and 640x480 o Compression support + o SMP compatibility HOW TO CONTACT ME: diff -Nru a/drivers/usb/ov511.c b/drivers/usb/ov511.c --- a/drivers/usb/ov511.c Mon Jan 6 11:32:21 2003 +++ b/drivers/usb/ov511.c Mon Jan 6 11:32:21 2003 @@ -11,6 +11,7 @@ * Original SAA7111A code by Dave Perks * URB error messages from pwc driver by Nemosoft * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox + * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others * * Based on the Linux CPiA driver written by Peter Pregler, * Scott J. Bertin and Johannes Erdfelt. @@ -48,6 +49,7 @@ #include #include #include +#include #if defined (__i386__) #include @@ -58,9 +60,9 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.61 for Linux 2.4" +#define DRIVER_VERSION "v1.63 for Linux 2.4" #define EMAIL "mark@alpha.dyndns.org" -#define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ +#define DRIVER_AUTHOR "Mark McClelland & Bret Wallach \ & Orion Sky Lawlor & Kevin Moore & Charl P. Botha \ & Claudio Matsuoka " #define DRIVER_DESC "ov511 USB Camera Driver" @@ -97,7 +99,6 @@ static int cams = 1; static int compress; static int testpat; -static int sensor_gbr; static int dumppix; static int led = 1; static int dump_bridge; @@ -122,6 +123,7 @@ static int unit_video[OV511_MAX_UNIT_VIDEO]; static int remove_zeros; static int mirror; +static int ov518_color; MODULE_PARM(autobright, "i"); MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); @@ -199,6 +201,8 @@ "Remove zero-padding from uncompressed incoming data"); MODULE_PARM(mirror, "i"); MODULE_PARM_DESC(mirror, "Reverse image horizontally"); +MODULE_PARM(ov518_color, "i"); +MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -222,7 +226,7 @@ /* MMX support is present in kernel and CPU. Checked upon decomp module load. */ static int ov51x_mmx_available; -static __devinitdata struct usb_device_id device_table [] = { +static struct usb_device_id device_table [] = { { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) }, { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) }, { USB_DEVICE(VEND_OMNIVISION, PROD_OV518) }, @@ -261,7 +265,9 @@ { 100, "Lifeview RoboCam" }, { 102, "AverMedia InterCam Elite" }, { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ + { 134, "Ezonics EZCam II" }, { 192, "Webeye 2000B" }, + { 253, "Alpha Vision Tech. AlphaCam SE" }, { -1, NULL } }; @@ -294,6 +300,7 @@ { -1, NULL } }; +#if defined(CONFIG_VIDEO_PROC_FS) static struct symbolic_list senlist[] = { { SEN_OV76BE, "OV76BE" }, { SEN_OV7610, "OV7610" }, @@ -309,6 +316,7 @@ { SEN_SAA7111A, "SAA7111A" }, { -1, NULL } }; +#endif /* URB error codes: */ static struct symbolic_list urb_errlist[] = { @@ -403,7 +411,7 @@ extern struct proc_dir_entry *video_proc_entry; static struct file_operations ov511_control_fops = { - ioctl: ov51x_control_ioctl, + .ioctl = ov51x_control_ioctl, }; #define YES_NO(x) ((x) ? "yes" : "no") @@ -463,6 +471,8 @@ symbolic(senlist, ov->sensor)); out += sprintf(out, "packet_size : %d\n", ov->packet_size); out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf); + out += sprintf(out, "packet_numbering: %d\n", ov->packet_numbering); + out += sprintf(out, "topology : %s\n", ov->usb_path); len = out - page; len -= off; @@ -554,8 +564,8 @@ ov511_read_proc_button, ov); if (!ov->proc_button) return; + ov->proc_button->owner = THIS_MODULE; } - ov->proc_button->owner = THIS_MODULE; /* Create "control" entry (ioctl() interface) */ PDEBUG(4, "creating /proc/video/ov511/%s/control", dirname); @@ -1133,8 +1143,6 @@ return 0; } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - /* Write to a specific I2C slave ID and register, using the specified mask */ static int i2c_w_slave(struct usb_ov511 *ov, @@ -1190,8 +1198,6 @@ return rc; } -#endif /* defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) */ - /* Sets I2C read and write slave IDs. Returns <0 for error */ static int ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid) @@ -1237,8 +1243,7 @@ static void dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn) { - int i; - int rc; + int i, rc; for (i = reg1; i <= regn; i++) { rc = i2c_r(ov, i); @@ -1256,8 +1261,7 @@ static void dump_reg_range(struct usb_ov511 *ov, int reg1, int regn) { - int i; - int rc; + int i, rc; for (i = reg1; i <= regn; i++) { rc = reg_r(ov, i); @@ -1265,7 +1269,6 @@ } } -/* FIXME: Should there be an OV518 version of this? */ static void ov511_dump_regs(struct usb_ov511 *ov) { @@ -1291,6 +1294,31 @@ dump_reg_range(ov, 0xa0, 0xbf); } + +static void +ov518_dump_regs(struct usb_ov511 *ov) +{ + info("VIDEO MODE REGS"); + dump_reg_range(ov, 0x20, 0x2f); + info("DATA PUMP AND SNAPSHOT REGS"); + dump_reg_range(ov, 0x30, 0x3f); + info("I2C REGS"); + dump_reg_range(ov, 0x40, 0x4f); + info("SYSTEM CONTROL AND VENDOR REGS"); + dump_reg_range(ov, 0x50, 0x5f); + info("60 - 6F"); + dump_reg_range(ov, 0x60, 0x6f); + info("70 - 7F"); + dump_reg_range(ov, 0x70, 0x7f); + info("Y QUANTIZATION TABLE"); + dump_reg_range(ov, 0x80, 0x8f); + info("UV QUANTIZATION TABLE"); + dump_reg_range(ov, 0x90, 0x9f); + info("A0 - BF"); + dump_reg_range(ov, 0xa0, 0xbf); + info("CBR"); + dump_reg_range(ov, 0xc0, 0xcf); +} #endif /*****************************************************************************/ @@ -1332,9 +1360,9 @@ ov51x_clear_snapshot(struct usb_ov511 *ov) { if (ov->bclass == BCL_OV511) { - reg_w(ov, R51x_SYS_SNAP, 0x01); - reg_w(ov, R51x_SYS_SNAP, 0x03); - reg_w(ov, R51x_SYS_SNAP, 0x01); + reg_w(ov, R51x_SYS_SNAP, 0x00); + reg_w(ov, R51x_SYS_SNAP, 0x02); + reg_w(ov, R51x_SYS_SNAP, 0x00); } else if (ov->bclass == BCL_OV518) { warn("snapshot reset not supported yet on OV518(+)"); } else { @@ -1379,7 +1407,7 @@ if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO; /* Wait for it to initialize */ - schedule_timeout (1 + 150 * HZ / 1000); + schedule_timeout(1 + 150 * HZ / 1000); for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) && @@ -2014,10 +2042,6 @@ p->whiteness = 105 << 8; - /* Can we get these from frame[0]? -claudio? */ - p->depth = ov->frame[0].depth; - p->palette = ov->frame[0].format; - return 0; } @@ -2425,9 +2449,10 @@ #endif break; case SEN_OV6620: - case SEN_OV6630: i2c_w(ov, 0x14, qvga?0x24:0x04); - /* No special settings yet */ + break; + case SEN_OV6630: + i2c_w(ov, 0x14, qvga?0xa0:0x80); break; default: err("Invalid sensor"); @@ -2441,13 +2466,33 @@ /* these aren't valid on the OV6620/OV7620/6630? */ i2c_w_mask(ov, 0x0e, 0x40, 0x40); } - i2c_w_mask(ov, 0x13, 0x20, 0x20); + + if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 + && ov518_color) { + i2c_w_mask(ov, 0x12, 0x00, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } else { + i2c_w_mask(ov, 0x13, 0x20, 0x20); + } } else { if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { /* not valid on the OV6620/OV7620/6630? */ i2c_w_mask(ov, 0x0e, 0x00, 0x40); } - i2c_w_mask(ov, 0x13, 0x00, 0x20); + + /* The OV518 needs special treatment. Although both the OV518 + * and the OV6630 support a 16-bit video bus, only the 8 bit Y + * bus is actually used. The UV bus is tied to ground. + * Therefore, the OV6630 needs to be in 8-bit multiplexed + * output mode */ + + if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 + && ov518_color) { + i2c_w_mask(ov, 0x12, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x20, 0x20); + } else { + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } } /******** Clock programming ********/ @@ -2505,19 +2550,11 @@ if (framedrop >= 0) i2c_w(ov, 0x16, framedrop); - if (sensor_gbr) - i2c_w_mask(ov, 0x12, 0x08, 0x08); - else - i2c_w_mask(ov, 0x12, 0x00, 0x08); - /* Test Pattern */ i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02); - /* Auto white balance */ -// if (awb) - i2c_w_mask(ov, 0x12, 0x04, 0x04); -// else -// i2c_w_mask(ov, 0x12, 0x00, 0x04); + /* Enable auto white balance */ + i2c_w_mask(ov, 0x12, 0x04, 0x04); // This will go away as soon as ov51x_mode_init_sensor_regs() // is fully tested. @@ -2706,7 +2743,7 @@ reg_w(ov, R511_CAM_PXDIV, 0x00); reg_w(ov, R511_CAM_LNDIV, 0x00); - /* YUV420, low pass filer on */ + /* YUV420, low pass filter on */ reg_w(ov, R511_CAM_OPTS, 0x03); /* Snapshot additions */ @@ -2782,8 +2819,29 @@ reg_w(ov, 0x3d, 0); reg_w(ov, 0x3e, 0); - reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); - reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + if (ov->bridge == BRG_OV518 && ov518_color) { + /* OV518 needs U and V swapped */ + i2c_w_mask(ov, 0x15, 0x00, 0x01); + + if (mode == VIDEO_PALETTE_GREY) { + /* Set 16-bit input format (UV data are ignored) */ + reg_w_mask(ov, 0x20, 0x00, 0x08); + + /* Set 8-bit (4:0:0) output format */ + reg_w_mask(ov, 0x28, 0x00, 0xf0); + reg_w_mask(ov, 0x38, 0x00, 0xf0); + } else { + /* Set 8-bit (YVYU) input format */ + reg_w_mask(ov, 0x20, 0x08, 0x08); + + /* Set 12-bit (4:2:0) output format */ + reg_w_mask(ov, 0x28, 0x80, 0xf0); + reg_w_mask(ov, 0x38, 0x80, 0xf0); + } + } else { + reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + } hsegs = width / 16; vsegs = height / 4; @@ -3176,7 +3234,7 @@ } /* - * For RAW BW (YUV400) images, data shows up in 256 byte segments. + * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. * The segments represent 4 squares of 8x8 pixels as follows: * * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 @@ -3207,7 +3265,7 @@ } /* - * For YUV4:2:0 images, the data shows up in 384 byte segments. + * For YUV 4:2:0 images, the data show up in 384 byte segments. * The first 64 bytes of each segment are U, the next 64 are V. The U and * V are arranged as follows: * @@ -3226,8 +3284,8 @@ * ... ... ... * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 * - * Note that the U and V data in one segment represents a 16 x 16 pixel - * area, but the Y data represents a 32 x 8 pixel area. If the width is not an + * Note that the U and V data in one segment represent a 16 x 16 pixel + * area, but the Y data represent a 32 x 8 pixel area. If the width is not an * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the * next horizontal stripe. * @@ -3235,7 +3293,7 @@ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 * this puts the data on the standard output and can be analyzed with the * parseppm.c utility I wrote. That's a much faster way for figuring out how - * this data is scrambled. + * these data are scrambled. */ /* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. @@ -4144,7 +4202,10 @@ } } + /* Resubmit this URB */ urb->dev = ov->dev; + if ((i = usb_submit_urb(urb)) != 0) + err("usb_submit_urb() ret %d", i); return; } @@ -4216,6 +4277,7 @@ for (n = 0; n < OV511_NUMSBUF; n++) { urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { err("init isoc: usb_alloc_urb ret. NULL"); return -ENOMEM; @@ -4229,6 +4291,7 @@ urb->complete = ov51x_isoc_irq; urb->number_of_packets = FRAMES_PER_DESC; urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC; + urb->interval = 1; for (fx = 0; fx < FRAMES_PER_DESC; fx++) { urb->iso_frame_desc[fx].offset = ov->packet_size * fx; urb->iso_frame_desc[fx].length = ov->packet_size; @@ -4237,10 +4300,6 @@ ov->streaming = 1; - ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb; - for (n = 0; n < OV511_NUMSBUF - 1; n++) - ov->sbuf[n].urb->next = ov->sbuf[n+1].urb; - for (n = 0; n < OV511_NUMSBUF; n++) { ov->sbuf[n].urb->dev = ov->dev; err = usb_submit_urb(ov->sbuf[n].urb); @@ -4398,11 +4457,6 @@ PDEBUG(4, "entered"); down(&ov->buf_lock); - if (ov->buf_state == BUF_PEND_DEALLOC) { - ov->buf_state = BUF_ALLOCATED; - del_timer(&ov->buf_timer); - } - if (ov->buf_state == BUF_ALLOCATED) goto out; @@ -4666,6 +4720,10 @@ if (sensor_get_picture(ov, p)) return -EIO; + /* Can we get these from frame[0]? -claudio? */ + p->depth = ov->frame[0].depth; + p->palette = ov->frame[0].format; + return 0; } case VIDIOCSPICT: @@ -4830,8 +4888,8 @@ depth = get_depth(vm->format); if (!depth) { - err("VIDIOCMCAPTURE: invalid format (%s)", - symbolic(v4l1_plist, vm->format)); + PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)", + symbolic(v4l1_plist, vm->format)); return -EINVAL; } @@ -4852,8 +4910,8 @@ } if (force_palette && (vm->format != force_palette)) { - info("palette rejected (%s)", - symbolic(v4l1_plist, vm->format)); + PDEBUG(2, "palette rejected (%s)", + symbolic(v4l1_plist, vm->format)); return -EINVAL; } @@ -4982,6 +5040,24 @@ return 0; } + case OV511IOC_WI2C: + { + struct ov511_i2c_struct *w = arg; + + return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask); + } + case OV511IOC_RI2C: + { + struct ov511_i2c_struct *r = arg; + int rc; + + rc = i2c_r_slave(ov, r->slave, r->reg); + if (rc < 0) + return rc; + + r->value = rc; + return 0; + } default: PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd); return -ENOIOCTLCMD; @@ -5188,7 +5264,7 @@ PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", count, frame->bytes_read); - /* If all data has been read... */ + /* If all data have been read... */ if (frame->bytes_read >= get_frame_length(frame)) { frame->bytes_read = 0; @@ -5450,8 +5526,7 @@ if (copy_from_user(&w, arg, sizeof(w))) return -EFAULT; - return i2c_w_slave(ov, w.slave, w.reg, w.value, - w.mask); + return i2c_w_slave(ov, w.slave, w.reg, w.value, w.mask); } case OV511IOC_RI2C: { @@ -5657,19 +5732,16 @@ ov->sensor = SEN_OV7610; } else if ((rc & 3) == 1) { /* I don't know what's different about the 76BE yet. */ - if (i2c_r(ov, 0x15) & 1) { + if (i2c_r(ov, 0x15) & 1) info("Sensor is an OV7620AE"); - info("PLEASE REPORT THE EXISTENCE OF THIS SENSOR TO"); - info("THE DRIVER AUTHOR"); - } else { + else info("Sensor is an OV76BE"); - } /* OV511+ will return all zero isoc data unless we * configure the sensor as a 7620. Someone needs to * find the exact reg. setting that causes this. */ if (ov->bridge == BRG_OV511PLUS) { - info("Enabling 511+/76BE workaround"); + info("Enabling 511+/7620AE workaround"); ov->sensor = SEN_OV7620; } else { ov->sensor = SEN_OV76BE; @@ -5754,86 +5826,61 @@ { OV511_I2C_BUS, 0x4f, 0x04 }, // Do 50-53 have any effect? // Toggle 0x12[2] off and on here? - { OV511_DONE_BUS, 0x0, 0x00 }, + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ }; - /* 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, 0x12, 0x80 }, /* reset */ + { OV511_I2C_BUS, 0x11, 0x00 }, + { OV511_I2C_BUS, 0x03, 0x60 }, + { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ { OV511_I2C_BUS, 0x07, 0xa8 }, /* 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 */ -// { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ - -// /*A*/ { OV511_I2C_BUS, 0x13, 0x21 }, -// /*A*/ { OV511_I2C_BUS, 0x13, 0x25 }, /* Tristate Y and UV busses */ - -// /*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 */ + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x0e, 0x20 }, +// { OV511_I2C_BUS, 0x14, 0x80 }, + { OV511_I2C_BUS, 0x16, 0x03 }, +// { 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 */ + { OV511_I2C_BUS, 0x23, 0xc0 }, + { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default +// { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */ /* 0x28: 0x05 Selects RGB format if RGB on */ -// /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 }, -// /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus +// { OV511_I2C_BUS, 0x28, 0x05 }, +// { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus - /*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 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ +// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ { OV511_I2C_BUS, 0x2d, 0x99 }, -// /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 -// /*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 +// { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 +// { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ +// { OV511_I2C_BUS, 0x38, 0x83 }, +// { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 // { 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 }, -// /*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 }, + { OV511_I2C_BUS, 0x3d, 0x80 }, +// { OV511_I2C_BUS, 0x3f, 0x0e }, /* 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 }, - /*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 }, - /*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 }, - { OV511_DONE_BUS, 0x0, 0x00 }, +// { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these +// { OV511_I2C_BUS, 0x4b, 0x80 }, + { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + { OV511_I2C_BUS, 0x4e, 0x40 }, + + /* UV average mode, color killer: strongest */ + { OV511_I2C_BUS, 0x4f, 0x07 }, + + { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ + { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ + { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ + { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ +// { OV511_I2C_BUS, 0x5c, 0x10 }, + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ }; PDEBUG(4, "starting sensor configuration"); @@ -5854,16 +5901,19 @@ return -1; } - if ((rc & 3) == 0) + if ((rc & 3) == 0) { ov->sensor = SEN_OV6630; - else if ((rc & 3) == 1) + info("Sensor is an OV6630"); + } else if ((rc & 3) == 1) { ov->sensor = SEN_OV6620; - else if ((rc & 3) == 2) + info("Sensor is an OV6620"); + } else if ((rc & 3) == 2) { ov->sensor = SEN_OV6630; - else if ((rc & 3) == 3) + info("Sensor is an OV6630AE"); + } else if ((rc & 3) == 3) { ov->sensor = SEN_OV6630; - - info("Sensor is an %s", symbolic(senlist, ov->sensor)); + info("Sensor is an OV6630AF"); + } /* Set sensor-specific vars */ ov->maxwidth = 352; @@ -6061,9 +6111,9 @@ static struct ov511_regvals aRegvalsNorm511[] = { { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f }, { OV511_REG_BUS, R511_COMP_EN, 0x00 }, { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, @@ -6072,9 +6122,9 @@ static struct ov511_regvals aRegvalsNorm511Plus[] = { { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x03 }, - { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, + { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 }, { OV511_REG_BUS, R511_FIFO_OPTS, 0xff }, { OV511_REG_BUS, R511_COMP_EN, 0x00 }, { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 }, @@ -6223,7 +6273,7 @@ { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_REG_BUS, 0x24, 0x9f }, { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x20, 0x00 }, { OV511_REG_BUS, 0x51, 0x04 }, { OV511_REG_BUS, 0x71, 0x19 }, { OV511_DONE_BUS, 0x0, 0x00 }, @@ -6236,7 +6286,7 @@ { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_REG_BUS, 0x24, 0x9f }, { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x60 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x20, 0x60 }, { OV511_REG_BUS, 0x51, 0x02 }, { OV511_REG_BUS, 0x71, 0x19 }, { OV511_REG_BUS, 0x40, 0xff }, @@ -6286,11 +6336,20 @@ if (ov518_init_compression(ov)) goto error; - /* OV518+ has packet numbering turned on by default */ if (ov->bridge == BRG_OV518) - ov->packet_numbering = 0; - else + { + struct usb_interface *ifp = &ov->dev->config[0].interface[0]; + __u16 mxps = ifp->altsetting[7].endpoint[0].wMaxPacketSize; + + /* Some OV518s have packet numbering by default, some don't */ + if (mxps == 897) + ov->packet_numbering = 1; + else + ov->packet_numbering = 0; + } else { + /* OV518+ has packet numbering turned on by default */ ov->packet_numbering = 1; + } ov518_set_packet_size(ov, 0); @@ -6450,7 +6509,13 @@ ov->buf_state = BUF_NOT_ALLOCATED; - /* Must be kmalloc()'ed, for DMA accessibility */ + if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { + err("usb_make_path error"); + goto error_dealloc; + } + + /* Allocate control transfer buffer. */ + /* Must be kmalloc()'ed, for DMA compatibility */ ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); if (!ov->cbuf) goto error; @@ -6480,8 +6545,12 @@ goto error; #ifdef OV511_DEBUG - if (dump_bridge) - ov511_dump_regs(ov); + if (dump_bridge) { + if (ov->bclass == BCL_OV511) + ov511_dump_regs(ov); + else + ov518_dump_regs(ov); + } #endif memcpy(&ov->vdev, &vdev_template, sizeof(vdev_template)); @@ -6506,7 +6575,8 @@ goto error; } - info("Device registered on minor %d", ov->vdev.minor); + info("Device at %s registered to minor %d", ov->usb_path, + ov->vdev.minor); #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) create_proc_ov511_cam(ov); @@ -6592,13 +6662,15 @@ } MOD_DEC_USE_COUNT; + + PDEBUG(3, "Disconnect complete"); } static struct usb_driver ov511_driver = { - name: "ov511", - id_table: device_table, - probe: ov51x_probe, - disconnect: ov51x_disconnect + .name = "ov511", + .id_table = device_table, + .probe = ov51x_probe, + .disconnect = ov51x_disconnect }; diff -Nru a/drivers/usb/ov511.h b/drivers/usb/ov511.h --- a/drivers/usb/ov511.h Mon Jan 6 11:32:21 2003 +++ b/drivers/usb/ov511.h Mon Jan 6 11:32:21 2003 @@ -253,6 +253,9 @@ /* Control transfers use up to 4 bytes */ #define OV511_CBUF_SIZE 4 +/* Size of usb_make_path() buffer */ +#define OV511_USB_PATH_LEN 64 + /* Bridge types */ enum { BRG_UNKNOWN, @@ -286,21 +289,6 @@ SEN_SAA7111A, }; -// Not implemented yet -#if 0 -/* Sensor classes */ -enum { - SCL_UNKNOWN, - SCL_OV7610, /* 7610, 76BE, 7620AE (for now) */ - SCL_OV7620, - SCL_OV6620, - SCL_OV6630, /* 6630, 6630AE, 6630AF */ - SCL_OV8600, - SCL_KS0127, /* SEN_KS0127, SEN_KS0127B */ - SCL_SAA7111A, -}; -#endif - enum { STATE_SCANNING, /* Scanning for start */ STATE_HEADER, /* Parsing header */ @@ -311,7 +299,6 @@ enum { BUF_NOT_ALLOCATED, BUF_ALLOCATED, - BUF_PEND_DEALLOC, /* ov511->buf_timer is set */ }; /* --------- Definition of ioctl interface --------- */ @@ -466,6 +453,7 @@ int customid; char *desc; unsigned char iface; + char usb_path[OV511_USB_PATH_LEN]; /* Determined by sensor type */ int maxwidth; @@ -521,7 +509,6 @@ int bridge; /* Type of bridge (BRG_*) */ int bclass; /* Class of bridge (BCL_*) */ int sensor; /* Type of image sensor chip (SEN_*) */ - int sclass; /* Type of image sensor chip (SCL_*) */ int packet_size; /* Frame size per isoc desc */ int packet_numbering; /* Is ISO frame numbering enabled? */ @@ -537,7 +524,6 @@ /* Framebuffer/sbuf management */ int buf_state; struct semaphore buf_lock; - struct timer_list buf_timer; struct ov51x_decomp_ops *decomp_ops;