summaryrefslogtreecommitdiffstats
path: root/drivers/usb/ov511.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/ov511.c')
-rw-r--r--drivers/usb/ov511.c709
1 files changed, 531 insertions, 178 deletions
diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c
index d0da393f3..c26f96132 100644
--- a/drivers/usb/ov511.c
+++ b/drivers/usb/ov511.c
@@ -11,8 +11,11 @@
* DEBUG - Debugging code.
* FIXME - Something that is broken or needs improvement.
*
- * Version History:
- * Version 1.00 - Initial version
+ * Version: 1.05
+ *
+ * Please see the file: linux/Documentation/usb/ov511.txt
+ * and the website at: http://people.delphi.com/mmcclelland/linux/
+ * for more info.
*/
/*
@@ -63,13 +66,15 @@
#define OV511_I2C_RETRIES 3
-/* Video Size 384 x 288 x 3 bytes for RGB */
-#define MAX_FRAME_SIZE (320 * 240 * 3)
+#define OV7610_AUTO_ADJUST 1
+
+/* Video Size 640 x 480 x 3 bytes for RGB */
+#define MAX_FRAME_SIZE (640 * 480 * 3)
// FIXME - Force CIF to make some apps happy for the moment. Should find a
// better way to do this.
-#define DEFAULT_WIDTH 320
-#define DEFAULT_HEIGHT 240
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
char kernel_version[] = UTS_RELEASE;
@@ -200,7 +205,9 @@ int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char val
USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, &value, 1, HZ);
- PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);
+#if 0
+ PDEBUG("reg write: 0x%02X:0x%02X", reg, value);
+#endif
return rc;
}
@@ -217,7 +224,9 @@ int ov511_reg_read(struct usb_device *dev, unsigned char reg)
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
0, (__u16)reg, buffer, 1, HZ);
- PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);
+#if 0
+ PDEBUG("reg read: 0x%02X:0x%02X", reg, buffer[0]);
+#endif
if(rc < 0)
return rc;
@@ -229,7 +238,9 @@ int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char val
{
int rc, retries;
- PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);
+#if 0
+ PDEBUG("i2c write: 0x%02X:0x%02X", reg, value);
+#endif
/* Three byte write cycle */
for(retries = OV511_I2C_RETRIES;;) {
/* Select camera register */
@@ -309,7 +320,9 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
}
value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
- PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);
+#if 0
+ PDEBUG("i2c read: 0x%02X:0x%02X", reg, value);
+#endif
/* This is needed to make ov511_i2c_write() work */
rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
@@ -318,27 +331,94 @@ int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
return (value);
}
+#if 0
+static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
+{
+ int i;
+ int rc;
+ for(i=reg1; i<=regn; i++) {
+ rc = ov511_i2c_read(dev, i);
+#if 0
+ PDEBUG("OV7610[0x%X] = 0x%X", i, rc);
+#endif
+ }
+}
+
+static void ov511_dump_i2c_regs( struct usb_device *dev)
+{
+ PDEBUG("I2C REGS");
+ ov511_dump_i2c_range(dev, 0x00, 0x38);
+}
+
+static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
+{
+ int i;
+ int rc;
+ for(i=reg1; i<=regn; i++) {
+ rc = ov511_reg_read(dev, i);
+ PDEBUG("OV511[0x%X] = 0x%X", i, rc);
+ }
+}
+
+static void ov511_dump_regs( struct usb_device *dev)
+{
+ PDEBUG("CAMERA INTERFACE REGS");
+ ov511_dump_reg_range(dev, 0x10, 0x1f);
+ PDEBUG("DRAM INTERFACE REGS");
+ ov511_dump_reg_range(dev, 0x20, 0x23);
+ PDEBUG("ISO FIFO REGS");
+ ov511_dump_reg_range(dev, 0x30, 0x31);
+ PDEBUG("PIO REGS");
+ ov511_dump_reg_range(dev, 0x38, 0x39);
+ ov511_dump_reg_range(dev, 0x3e, 0x3e);
+ PDEBUG("I2C REGS");
+ ov511_dump_reg_range(dev, 0x40, 0x49);
+ PDEBUG("SYSTEM CONTROL REGS");
+ ov511_dump_reg_range(dev, 0x50, 0x53);
+ ov511_dump_reg_range(dev, 0x5e, 0x5f);
+ PDEBUG("OmniCE REGS");
+ ov511_dump_reg_range(dev, 0x70, 0x79);
+ ov511_dump_reg_range(dev, 0x80, 0x9f);
+ ov511_dump_reg_range(dev, 0xa0, 0xbf);
+
+}
+#endif
+
+int ov511_i2c_reset(struct usb_device *dev)
+{
+ int rc;
+
+ PDEBUG("Reset 7610");
+ rc = ov511_i2c_write(dev, 0x12, 0x80);
+ if (rc < 0)
+ err("i2c reset: command failed");
+
+ return rc;
+}
+
int ov511_reset(struct usb_device *dev, unsigned char reset_type)
{
int rc;
- PDEBUG("Reset: type=0x%X\n", reset_type);
+ PDEBUG("Reset: type=0x%X", reset_type);
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
if (rc < 0)
- printk(KERN_ERR "ov511: reset: command failed\n");
+ err("reset: command failed");
rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
if (rc < 0)
- printk(KERN_ERR "ov511: reset: command failed\n");
+ err("reset: command failed");
return rc;
}
int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
{
- int alt, multiplier, err;
+ int alt, multiplier, rc;
- PDEBUG("set packet size: %d\n", size);
+#if 0
+ PDEBUG("set packet size: %d", size);
+#endif
switch (size) {
case 992:
@@ -374,21 +454,19 @@ int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
multiplier = 1; // FIXME - is this correct?
break;
default:
- printk(KERN_ERR "ov511_set_packet_size: invalid size (%d)\n",
- size);
+ err("Set packet size: invalid size (%d)", size);
return -EINVAL;
}
- err = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
- multiplier);
- if (err < 0) {
- printk(KERN_ERR "ov511: Set packet size: Set FIFO size ret %d\n",
- err);
+ rc = ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE,
+ multiplier);
+ if (rc < 0) {
+ err("Set packet size: Set FIFO size ret %d", rc);
return -ENOMEM;
}
if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
- printk(KERN_ERR "ov511: Set packet size: set interface error\n");
+ err("Set packet size: set interface error");
return -EBUSY;
}
@@ -399,8 +477,258 @@ int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
return 0;
}
-/* How much data is left in the scratch buf? */
-#define scratch_left(x) (ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch))
+static inline int ov7610_set_picture(struct usb_ov511 *ov511,
+ struct video_picture *p)
+{
+ if(ov511_i2c_write(ov511->dev, OV7610_REG_SAT, p->colour >> 8) < 0)
+ return -EIO;
+
+ if(ov511_i2c_write(ov511->dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+ return -EIO;
+
+ if(ov511_i2c_write(ov511->dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static inline int ov7610_get_picture(struct usb_ov511 *ov511,
+ struct video_picture *p)
+{
+ int ret;
+
+ if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_SAT)) < 0) return -EIO;
+ p->colour = ret << 8;
+
+ if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_CNT)) < 0) return -EIO;
+ p->contrast = ret << 8;
+
+ if((ret = ov511_i2c_read(ov511->dev, OV7610_REG_BRT)) < 0) return -EIO;
+ p->brightness = ret << 8;
+
+ p->hue = 0x8000;
+ p->whiteness = 105 << 8;
+ p->depth = 24;
+ p->palette = VIDEO_PALETTE_RGB24;
+
+ return 0;
+}
+
+static int ov511_mode_init_regs(struct usb_ov511 *ov511,
+ int width, int height, int mode)
+{
+ int rc = 0;
+ struct usb_device *dev = ov511->dev;
+
+#if 0
+ PDEBUG("ov511_mode_init_regs(ov511, %d, %d, %d)", width, height, mode);
+#endif
+ ov511_set_packet_size(ov511, 0);
+
+ /* Set mode consistent registers */
+ ov511_i2c_write(dev, 0x0f, 0x03);
+ ov511_i2c_write(dev, 0x10, 0xff);
+ ov511_i2c_write(dev, 0x13, 0x01);
+ ov511_i2c_write(dev, 0x16, 0x06);
+ ov511_i2c_write(dev, 0x20, 0x1c);
+ ov511_i2c_write(dev, 0x24, 0x2e); /* 10 */
+ ov511_i2c_write(dev, 0x25, 0x7c); /* 8a */
+ ov511_i2c_write(dev, 0x26, 0x70);
+ ov511_i2c_write(dev, 0x28, 0x24); /* 24 */
+ ov511_i2c_write(dev, 0x2b, 0xac);
+ ov511_i2c_write(dev, 0x2c, 0xfe);
+ ov511_i2c_write(dev, 0x2d, 0x93);
+ ov511_i2c_write(dev, 0x34, 0x8b);
+
+ if (width == 640 && height == 480) {
+ ov511_reg_write(dev, 0x12, 0x4f);
+ ov511_reg_write(dev, 0x13, 0x3d);
+ ov511_reg_write(dev, 0x14, 0x00);
+ ov511_reg_write(dev, 0x15, 0x00);
+ ov511_reg_write(dev, 0x18, 0x03);
+
+ ov511_i2c_write(dev, 0x11, 0x01);
+ ov511_i2c_write(dev, 0x12, 0x24);
+ ov511_i2c_write(dev, 0x14, 0x04);
+ ov511_i2c_write(dev, 0x35, 0x9e);
+ } else if (width == 320 && height == 240) {
+ ov511_reg_write(dev, 0x12, 0x27);
+ ov511_reg_write(dev, 0x13, 0x1f);
+ ov511_reg_write(dev, 0x14, 0x00);
+ ov511_reg_write(dev, 0x15, 0x00);
+ ov511_reg_write(dev, 0x18, 0x03);
+
+ ov511_i2c_write(dev, 0x11, 0x00);
+ ov511_i2c_write(dev, 0x12, 0x04);
+ ov511_i2c_write(dev, 0x14, 0x24);
+ ov511_i2c_write(dev, 0x35, 0x1e);
+ } else {
+ err("Unknown mode (%d, %d): %d", width, height, mode);
+ rc = -EINVAL;
+ }
+ ov511_set_packet_size(ov511, 993);
+
+ return rc;
+}
+
+
+/*************************************************************
+
+Turn a YUV4:2:0 block into an RGB block
+
+*************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+static inline void ov511_move_420_block(int y00, int y01, int y10, int y11,
+ int u, int v, int w,
+ unsigned char * pOut)
+{
+ int r = 68911 * v;
+ int g = -16915 * u + -35101 * v;
+ int b = 87097 * u;
+ y00 *= 49152;
+ y01 *= 49152;
+ y10 *= 49152;
+ y11 *= 49152;
+ *(pOut+w*3) = LIMIT(r + y10);
+ *pOut++ = LIMIT(r + y00);
+ *(pOut+w*3) = LIMIT(g + y10);
+ *pOut++ = LIMIT(g + y00);
+ *(pOut+w*3) = LIMIT(b + y10);
+ *pOut++ = LIMIT(b + y00);
+ *(pOut+w*3) = LIMIT(r + y11);
+ *pOut++ = LIMIT(r + y01);
+ *(pOut+w*3) = LIMIT(g + y11);
+ *pOut++ = LIMIT(g + y01);
+ *(pOut+w*3) = LIMIT(b + y11);
+ *pOut++ = LIMIT(b + y01);
+}
+
+/***************************************************************
+
+For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments. The
+first 64 bytes of each segment are V, the next 64 are U. The V and
+U are arranged as follows:
+
+ 0 1 ... 7
+ 8 9 ... 15
+ ...
+ 56 57 ... 63
+
+The next 256 bytes are Y data and represent 4 squares of 8x8 pixels as
+follows:
+
+ 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
+ 8 9 ... 15 72 73 ... 79 200 201 ... 207
+ ... ... ...
+ 56 57 ... 63 120 121 127 248 249 ... 255
+
+If OV511_DUMPPIX is defined, _parse_data just dumps the
+incoming segments, 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.
+
+****************************************************************/
+#define HDIV 8
+#define WDIV (256/HDIV)
+
+static void ov511_parse_data(unsigned char * pIn0,
+ unsigned char * pOut0,
+ int iWidth,
+ int iSegment)
+
+{
+#ifndef OV511_DUMPPIX
+ int k, l, m;
+ unsigned char * pIn;
+ unsigned char * pOut, * pOut1;
+
+ int iHalf = (iSegment / (iWidth / 32)) & 1;
+ int iY = iSegment / (iWidth / WDIV);
+ int jY = iSegment - iY * (iWidth / WDIV);
+ int iOutY = (iY*HDIV*iWidth + jY*WDIV) * 3;
+ int iUV = iSegment / (iWidth / WDIV * 2);
+ int jUV = iSegment - iUV * (iWidth / WDIV * 2);
+ int iOutUV = (iUV*HDIV*2*iWidth + jUV*WDIV/2) * 3;
+
+ /* Just copy the Y's if in the first stripe */
+ if (!iHalf) {
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for(k=0; k<4; k++) {
+ pOut1 = pOut;
+ for(l=0; l<8; l++) {
+ for(m=0; m<8; m++) {
+ *pOut1 = *pIn++;
+ pOut1 += 3;
+ }
+ pOut1 += (iWidth - 8) * 3;
+ }
+ pOut += 8 * 3;
+ }
+ }
+
+ /* Use the first half of VUs to calculate value */
+ pIn = pIn0;
+ pOut = pOut0 + iOutUV;
+ for(l=0; l<4; l++) {
+ for(m=0; m<8; m++) {
+ int y00 = *(pOut);
+ int y01 = *(pOut+3);
+ int y10 = *(pOut+iWidth*3);
+ int y11 = *(pOut+iWidth*3+3);
+ int u = *(pIn+64) - 128;
+ int v = *pIn++ - 128;
+ ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut);
+ pOut += 6;
+ }
+ pOut += (iWidth*2 - 16) * 3;
+ }
+
+ /* Just copy the other UV rows */
+ for(l=0; l<4; l++) {
+ for(m=0; m<8; m++) {
+ *pOut++ = *(pIn + 64);
+ *pOut = *pIn++;
+ pOut += 5;
+ }
+ pOut += (iWidth*2 - 16) * 3;
+ }
+
+ /* Calculate values if it's the second half */
+ if (iHalf) {
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY;
+ for(k=0; k<4; k++) {
+ pOut1 = pOut;
+ for(l=0; l<4; l++) {
+ for(m=0; m<4; m++) {
+ int y10 = *(pIn+8);
+ int y00 = *pIn++;
+ int y11 = *(pIn+8);
+ int y01 = *pIn++;
+ int u = *pOut1 - 128;
+ int v = *(pOut1+1) - 128;
+ ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth, pOut1);
+ pOut1 += 6;
+ }
+ pOut1 += (iWidth*2 - 8) * 3;
+ pIn += 8;
+ }
+ pOut += 8 * 3;
+ }
+ }
+
+#else
+ /* Just dump pix data straight out for debug */
+ int i;
+ pOut0 += iSegment * 384;
+ for(i=0; i<384; i++) {
+ *pOut0++ = *pIn0++;
+ }
+#endif
+}
static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
{
@@ -421,13 +749,10 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
if (!n) continue;
- aPackNum[i] = n ? cdata[512] : -1;
+ aPackNum[i] = n ? cdata[992] : -1;
- if (st){
- // Macro - must be in braces!
- PDEBUG("data error: [%d] len=%d, status=%d\n",
- i, n, st);
- }
+ if (st)
+ PDEBUG("data error: [%d] len=%d, status=%d", i, n, st);
frame = &ov511->frame[ov511->curframe];
@@ -436,13 +761,18 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
(cdata[8] & 8) && (cdata[8] & 0x80)) {
- PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[512]));
- PDEBUG("Current frame = %d\n", ov511->curframe);
+#if 0
+ PDEBUG("Found Frame End!, packnum = %d", (int)(cdata[992]));
+ PDEBUG("Current frame = %d", ov511->curframe);
+#endif
if (frame->scanstate == STATE_LINES) {
if (waitqueue_active(&frame->wq)) {
- PDEBUG("About to wake up waiting processes\n");
+#if 0
+ PDEBUG("About to wake up waiting processes");
+#endif
frame->grabstate = FRAME_DONE;
+ ov511->curframe = -1;
wake_up_interruptible(&frame->wq);
}
}
@@ -452,35 +782,52 @@ static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] |
cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
(cdata[8] & 8)) {
- PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[512]));
+#if 0
+ PDEBUG("ov511: Found Frame Start!, packnum = %d", (int)(cdata[992]));
+ PDEBUG("ov511: Frame Header Byte = 0x%x", (int)(cdata[8]));
+#endif
frame->scanstate = STATE_LINES;
- frame->curpix = 0;
+ frame->segment = 0;
}
/* Are we in a frame? */
- else if (frame->scanstate == STATE_LINES) {
- unsigned char *f = frame->data + 3 * frame->curpix;
- int i;
- if (frame->curpix <= 320 * 240 - 256) {
- for (i=0; i<256; i++) {
- *f++ = *cdata;
- *f++ = *cdata;
- *f++ = *cdata++;
- *f++ = *cdata;
- *f++ = *cdata;
- *f++ = *cdata++;
- }
- frame->curpix += 512;
+ if (frame->scanstate == STATE_LINES) {
+ unsigned char * pData;
+ int iPix;
+
+ /* Deal with leftover from last segment, if any */
+ if (frame->segment) {
+ pData = ov511->scratch;
+ iPix = - ov511->scratchlen;
+ memmove(pData + ov511->scratchlen, cdata, iPix+384);
} else {
- PDEBUG("Too many pixels!\n");
+ pData = &cdata[iPix = 9];
}
+
+ /* Parse the segments */
+ while(iPix <= 992 - 384 &&
+ frame->segment < frame->width * frame->height / 256) {
+ ov511_parse_data(pData, frame->data,
+ frame->width,
+ frame->segment);
+ frame->segment++;
+ iPix += 384;
+ pData = &cdata[iPix];
}
+ /* Save extra data for next time */
+ if (frame->segment < frame->width * frame->height / 256) {
+ memmove(ov511->scratch, pData, 992 - iPix);
+ ov511->scratchlen = 992 - iPix;
+ }
+ }
}
+#if 0
PDEBUG("pn: %d %d %d %d %d %d %d %d %d %d\n",
aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
+#endif
return totlen;
}
@@ -491,18 +838,6 @@ static void ov511_isoc_irq(struct urb *urb)
struct ov511_sbuf *sbuf;
int i;
-#if 0
- static int last_status, last_error_count, last_actual_length;
- if (last_status != urb->status ||
- last_error_count != urb->error_count ||
- last_actual_length != urb->actual_length) {
- PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length);
- last_status = urb->status;
- last_error_count = urb->error_count;
- last_actual_length = urb->actual_length;
- }
-#endif
-
if (!ov511->streaming) {
PDEBUG("hmmm... not streaming, but got interrupt\n");
return;
@@ -511,17 +846,10 @@ static void ov511_isoc_irq(struct urb *urb)
sbuf = &ov511->sbuf[ov511->cursbuf];
/* Copy the data received into our scratch buffer */
- len = ov511_move_data(ov511, urb);
-#if 0
- /* If we don't have a frame we're current working on, complain */
- if (ov511->scratchlen) {
- if (ov511->curframe < 0) {
- // Macro - must be in braces!!
- PDEBUG("received data, but no frame available\n");
- } else
- ov511_parse_data(ov511);
+ if (ov511->curframe >= 0) {
+ len = ov511_move_data(ov511, urb);
}
-#endif
+
for (i = 0; i < FRAMES_PER_DESC; i++) {
sbuf->urb->iso_frame_desc[i].status = 0;
sbuf->urb->iso_frame_desc[i].actual_length = 0;
@@ -544,30 +872,13 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
ov511->cursbuf = 0;
ov511->scratchlen = 0;
- ov511_set_packet_size(ov511, 512);
-
-#define OV511_COLOR_BAR_TEST
-#ifdef OV511_COLOR_BAR_TEST
- {
- int rc;
- rc = ov511_i2c_read(ov511->dev, 0x12);
- rc = ov511_i2c_write(ov511->dev, 0x12, 0x3f);
- rc = ov511_i2c_read(ov511->dev, 0x12);
- rc = ov511_i2c_read(ov511->dev, 0x13);
- rc = ov511_i2c_write(ov511->dev, 0x14, 0x4);
- rc = ov511_i2c_read(ov511->dev, 0x14);
- rc = ov511_i2c_write(ov511->dev, 0x28, 0x60);
- rc = ov511_i2c_read(ov511->dev, 0x28);
- ov511_reg_write(ov511->dev, OV511_REG_CAMERA_DATA_INPUT_SELECT,
- 0);
- }
-#endif
+ ov511_set_packet_size(ov511, 993);
/* We double buffer the Iso lists */
urb = usb_alloc_urb(FRAMES_PER_DESC);
if (!urb) {
- printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n");
+ err("ov511_init_isoc: usb_alloc_urb ret. NULL");
return -ENOMEM;
}
ov511->sbuf[0].urb = urb;
@@ -586,7 +897,7 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
urb = usb_alloc_urb(FRAMES_PER_DESC);
if (!urb) {
- printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n");
+ err("ov511_init_isoc: usb_alloc_urb ret. NULL");
return -ENOMEM;
}
ov511->sbuf[1].urb = urb;
@@ -608,12 +919,10 @@ static int ov511_init_isoc(struct usb_ov511 *ov511)
err = usb_submit_urb(ov511->sbuf[0].urb);
if (err)
- printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(0) ret %d\n",
- err);
+ err("ov511_init_isoc: usb_run_isoc(0) ret %d", err);
err = usb_submit_urb(ov511->sbuf[1].urb);
if (err)
- printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n",
- err);
+ err("ov511_init_isoc: usb_run_isoc(1) ret %d\n", err);
ov511->streaming = 1;
@@ -685,7 +994,7 @@ static int ov511_open(struct video_device *dev, int flags)
int err = -EBUSY;
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- PDEBUG("ov511_open\n");
+ PDEBUG("ov511_open");
down(&ov511->lock);
if (ov511->user)
@@ -704,8 +1013,8 @@ static int ov511_open(struct video_device *dev, int flags)
ov511->frame[0].data = ov511->fbuf;
ov511->frame[1].data = ov511->fbuf + MAX_FRAME_SIZE;
- PDEBUG("frame [0] @ %p\n", ov511->frame[0].data);
- PDEBUG("frame [1] @ %p\n", ov511->frame[1].data);
+ PDEBUG("frame [0] @ %p", ov511->frame[0].data);
+ PDEBUG("frame [1] @ %p", ov511->frame[1].data);
ov511->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
if (!ov511->sbuf[0].data)
@@ -714,17 +1023,8 @@ static int ov511_open(struct video_device *dev, int flags)
if (!ov511->sbuf[1].data)
goto open_err_on1;
- PDEBUG("sbuf[0] @ %p\n", ov511->sbuf[0].data);
- PDEBUG("sbuf[1] @ %p\n", ov511->sbuf[1].data);
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- ov511->frame[0].width = DEFAULT_WIDTH;
- ov511->frame[0].height = DEFAULT_HEIGHT;
- ov511->frame[0].bytes_read = 0;
- ov511->frame[1].width = DEFAULT_WIDTH;
- ov511->frame[1].height = DEFAULT_HEIGHT;
- ov511->frame[1].bytes_read = 0;
+ PDEBUG("sbuf[0] @ %p", ov511->sbuf[0].data);
+ PDEBUG("sbuf[1] @ %p", ov511->sbuf[1].data);
err = ov511_init_isoc(ov511);
if (err)
@@ -755,7 +1055,7 @@ static void ov511_close(struct video_device *dev)
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- PDEBUG("ov511_close\n");
+ PDEBUG("ov511_close");
down(&ov511->lock);
ov511->user--;
@@ -783,12 +1083,12 @@ static long ov511_write(struct video_device *dev, const char *buf, unsigned long
}
// FIXME - Needs much work!!!
-static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
{
- struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
-
- PDEBUG("IOCtl: 0x%X\n", cmd);
-
+ struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
+#if 0
+ PDEBUG("IOCtl: 0x%X", cmd);
+#endif
switch (cmd) {
case VIDIOCGCAP:
{
@@ -844,14 +1144,9 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct video_picture p;
- p.colour = 0x8000; /* Damn British people :) */
- p.hue = 0x8000;
- p.brightness = 180 << 8; /* XXX */
- p.contrast = 192 << 8; /* XXX */
- p.whiteness = 105 << 8; /* XXX */
- p.depth = 24;
- p.palette = VIDEO_PALETTE_RGB24;
-
+ if (ov7610_get_picture(ov511, &p))
+ return -EIO;
+
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
@@ -863,6 +1158,9 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
+
+ if (ov7610_set_picture(ov511, &p))
+ return -EIO;
return 0;
}
@@ -923,9 +1221,11 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
- PDEBUG("MCAPTURE\n");
- PDEBUG("frame: %d, size: %dx%d, format: %d\n",
+#if 0
+ PDEBUG("MCAPTURE");
+ PDEBUG("frame: %d, size: %dx%d, format: %d",
vm.frame, vm.width, vm.height, vm.format);
+#endif
if (vm.format != VIDEO_PALETTE_RGB24)
return -EINVAL;
@@ -938,8 +1238,15 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
/* Don't compress if the size changed */
if ((ov511->frame[vm.frame].width != vm.width) ||
- (ov511->frame[vm.frame].height != vm.height))
+ (ov511->frame[vm.frame].height != vm.height)) {
ov511->compress = 0;
+ ov511_mode_init_regs(ov511,
+ vm.width, vm.height, 0);
+#if 0
+ PDEBUG("ov511: Setting frame %d to (%d, %d) : %d",
+ vm.frame, vm.width, vm.height, 0);
+#endif
+ }
ov511->frame[vm.frame].width = vm.width;
ov511->frame[vm.frame].height = vm.height;
@@ -956,8 +1263,9 @@ static int ov511_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (copy_from_user((void *)&frame, arg, sizeof(int)))
return -EFAULT;
- PDEBUG("syncing to frame %d\n", frame);
-
+#if 0
+ PDEBUG("syncing to frame %d", frame);
+#endif
switch (ov511->frame[frame].grabstate) {
case FRAME_UNUSED:
return -EINVAL;
@@ -1029,7 +1337,7 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
int frmx = -1;
volatile struct ov511_frame *frame;
- PDEBUG("ov511_read: %ld bytes, noblock=%d\n", count, noblock);
+ PDEBUG("ov511_read: %ld bytes, noblock=%d", count, noblock);
if (!dev || !buf)
return -EFAULT;
@@ -1060,20 +1368,20 @@ static long ov511_read(struct video_device *dev, char *buf, unsigned long count,
restart:
while (frame->grabstate == FRAME_GRABBING) {
- interruptible_sleep_on(&frame->wq);
+ interruptible_sleep_on(&ov511->frame[frmx].wq);
if (signal_pending(current))
return -EINTR;
}
if (frame->grabstate == FRAME_ERROR) {
frame->bytes_read = 0;
- printk(KERN_ERR "ov511_read: errored frame %d\n", ov511->curframe);
+ err("ov511_read: errored frame %d", ov511->curframe);
if (ov511_new_frame(ov511, frmx))
- printk(KERN_ERR "ov511_read: ov511_new_frame error\n");
+ err("ov511_read: ov511_new_frame error");
goto restart;
}
- PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n", frmx,
+ PDEBUG("ov511_read: frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
frame->bytes_read, frame->scanlength);
/* copy bytes to user space; we allow for partials reads */
@@ -1084,7 +1392,7 @@ restart:
return -EFAULT;
frame->bytes_read += count;
- PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld\n",
+ PDEBUG("ov511_read: {copy} count used=%ld, new bytes_read=%ld",
count, frame->bytes_read);
if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
@@ -1093,7 +1401,7 @@ restart:
/* Mark it as available to be used again. */
ov511->frame[frmx].grabstate = FRAME_UNUSED;
if (ov511_new_frame(ov511, frmx ? 0 : 1))
- printk(KERN_ERR "ov511_read: ov511_new_frame returned error\n");
+ err("ov511_read: ov511_new_frame returned error");
}
return count;
@@ -1105,7 +1413,7 @@ static int ov511_mmap(struct video_device *dev, const char *adr, unsigned long s
unsigned long start = (unsigned long)adr;
unsigned long page, pos;
- PDEBUG("mmap: %ld (%lX) bytes\n", size, size);
+ PDEBUG("mmap: %ld (%lX) bytes", size, size);
if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
return -EINVAL;
@@ -1145,14 +1453,52 @@ static struct video_device ov511_template = {
0
};
+static int ov7610_configure(struct usb_device *dev)
+{
+ if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+ OV7610_I2C_WRITE_ID) < 0)
+ return -1;
+
+ if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+ OV7610_I2C_READ_ID) < 0)
+ return -1;
+
+ /* Reset the camera chip */
+ if (ov511_i2c_reset(dev) < 0)
+ return -1;
+
+#if 0
+ if(usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER,
+ OV511_I2C_CLOCK_PRESCALER))
+ return -1;
+#endif
+
+ if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+ return -1;
+
+ /* Dummy read to sync I2C */
+ if(ov511_i2c_read(dev, 0x00) < 0)
+ return -1;
+
+
+ if((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) != 0x7F) ||
+ (ov511_i2c_read(dev, OV7610_REG_ID_LOW) != 0xA2)) {
+ err("Failed to read OV7610 ID. You might not have an OV7610,");
+ err("or it may be not responding. Report this to");
+ err("mmcclelland@delphi.com");
+ return -1;
+ }
+
+ return 0;
+}
+
static int ov511_configure(struct usb_ov511 *ov511)
{
struct usb_device *dev = ov511->dev;
- int temprc; // DEBUG CODE
/* Set altsetting 0 */
if (usb_set_interface(dev, ov511->iface, 0) < 0) {
- printk(KERN_ERR "ov511: usb_set_interface error\n");
+ err("usb_set_interface error");
return -EBUSY;
}
@@ -1162,7 +1508,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
init_waitqueue_head(&ov511->frame[1].wq);
if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
- printk(KERN_ERR "ov511: video_register_device failed\n");
+ err("video_register_device failed");
return -EBUSY;
}
@@ -1172,7 +1518,7 @@ static int ov511_configure(struct usb_ov511 *ov511)
/* Initialize system */
if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) {
- printk(KERN_ERR "ov511: enable system: command failed\n");
+ err("enable system: command failed");
goto error;
}
@@ -1180,36 +1526,31 @@ static int ov511_configure(struct usb_ov511 *ov511)
if (ov511_reset(dev, OV511_RESET_ALL) < 0)
goto error;
+ if(ov7610_configure(dev) < 0) {
+ err("failed to configure OV7610");
+ goto error;
+ }
+
/* Disable compression */
if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) {
- printk(KERN_ERR "ov511: disable compression: command failed\n");
+ err("disable compression: command failed");
goto error;
}
-// FIXME - error checking needed
- ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
- OV7610_I2C_WRITE_ID);
- ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
- OV7610_I2C_READ_ID);
-
-// DEBUG CODE
-// usb_ov511_reg_write(dev, OV511_REG_I2C_CLOCK_PRESCALER,
-// OV511_I2C_CLOCK_PRESCALER);
-
- if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
- goto error;
-
- /* Dummy read to sync I2C */
- ov511_i2c_read(dev, 0x1C);
-
-// DEBUG - TEST CODE FOR CAMERA REG READ
- temprc = ov511_i2c_read(dev, 0x1C);
-
- temprc = ov511_i2c_read(dev, 0x1D);
-// END DEBUG CODE
-
ov511->compress = 0;
+ /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
+ * (using read() instead). */
+ ov511->frame[0].width = DEFAULT_WIDTH;
+ ov511->frame[0].height = DEFAULT_HEIGHT;
+ ov511->frame[0].bytes_read = 0;
+ ov511->frame[1].width = DEFAULT_WIDTH;
+ ov511->frame[1].height = DEFAULT_HEIGHT;
+ ov511->frame[1].bytes_read = 0;
+
+ /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
+ ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0);
+
return 0;
error:
@@ -1228,7 +1569,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
struct usb_ov511 *ov511;
int rc;
- PDEBUG("probing for device...\n");
+ PDEBUG("probing for device...");
/* We don't handle multi-config cameras */
if (dev->descriptor.bNumConfigurations != 1)
@@ -1252,7 +1593,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
printk(KERN_INFO "ov511: USB OV511-based camera found\n");
if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "ov511: couldn't kmalloc ov511 struct\n");
+ err("couldn't kmalloc ov511 struct");
return NULL;
}
@@ -1263,18 +1604,30 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
if (rc < 0) {
- printk("ov511: Unable to read camera bridge registers\n");
+ err("Unable to read camera bridge registers");
return NULL;
- } else if (rc == 3) { /* D-Link DSB-C300 */
+ }
+
+ switch(ov511->customid = rc) {
+ case 0: /* This also means that no custom ID was set */
+ printk("ov511: Camera is probably a MediaForte MV300\n");
+ break;
+ case 3:
printk("ov511: Camera is a D-Link DSB-C300\n");
- ov511->customid = 3;
- } else if (rc == 21) { /* Creative Labs WebCam 3 */
+ break;
+ case 21:
printk("ov511: Camera is a Creative Labs WebCam 3\n");
- ov511->customid = 21;
- } else {
- printk("ov511: Specific camera type (%d) not recognized\n", rc);
- printk("ov511: Please contact mmcclelland@delphi.com to request\n");
- printk("ov511: support for your camera.\n");
+ break;
+ case 100:
+ printk("ov511: Camera is a Lifeview RoboCam\n");
+ break;
+ case 102:
+ printk("ov511: Camera is a AverMedia InterCam Elite\n");
+ break;
+ default:
+ err("Specific camera type (%d) not recognized", rc);
+ err("Please contact mmcclelland@delphi.com to request");
+ err("support for your camera.");
return NULL;
}
@@ -1284,7 +1637,7 @@ static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
return ov511;
}
else {
- printk(KERN_ERR "ov511: Failed to configure camera\n");
+ err("Failed to configure camera");
return NULL;
}
@@ -1314,7 +1667,7 @@ static struct usb_driver ov511_driver = {
int usb_ov511_init(void)
{
- PDEBUG("usb_ov511_init()\n");
+ PDEBUG("usb_ov511_init()");
EXPORT_NO_SYMBOLS;
@@ -1336,7 +1689,7 @@ void cleanup_module(void)
{
usb_ov511_cleanup();
- PDEBUG("Module unloaded\n");
+ PDEBUG("Module unloaded");
}
#endif