patch-2.3.40 linux/drivers/usb/ov511.c
Next file: linux/drivers/usb/ov511.h
Previous file: linux/drivers/usb/ohci-hcd.h
Back to the patch index
Back to the overall index
- Lines: 1192
- Date:
Mon Jan 17 16:24:48 2000
- Orig file:
v2.3.39/linux/drivers/usb/ov511.c
- Orig date:
Tue Jan 11 22:31:42 2000
diff -u --recursive --new-file v2.3.39/linux/drivers/usb/ov511.c linux/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,6 +66,8 @@
#define OV511_I2C_RETRIES 3
+#define OV7610_AUTO_ADJUST 1
+
/* Video Size 640 x 480 x 3 bytes for RGB */
#define MAX_FRAME_SIZE (640 * 480 * 3)
@@ -201,7 +206,7 @@
0, (__u16)reg, &value, 1, HZ);
#if 0
- PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);
+ PDEBUG("reg write: 0x%02X:0x%02X", reg, value);
#endif
return rc;
@@ -220,7 +225,7 @@
0, (__u16)reg, buffer, 1, HZ);
#if 0
- PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);
+ PDEBUG("reg read: 0x%02X:0x%02X", reg, buffer[0]);
#endif
if(rc < 0)
@@ -234,7 +239,7 @@
int rc, retries;
#if 0
- PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);
+ PDEBUG("i2c write: 0x%02X:0x%02X", reg, value);
#endif
/* Three byte write cycle */
for(retries = OV511_I2C_RETRIES;;) {
@@ -316,7 +321,7 @@
value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
#if 0
- PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);
+ PDEBUG("i2c read: 0x%02X:0x%02X", reg, value);
#endif
/* This is needed to make ov511_i2c_write() work */
@@ -326,18 +331,22 @@
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\n");
+ PDEBUG("I2C REGS");
ov511_dump_i2c_range(dev, 0x00, 0x38);
}
@@ -347,54 +356,69 @@
int rc;
for(i=reg1; i<=regn; i++) {
rc = ov511_reg_read(dev, i);
- PDEBUG("OV511[0x%X] = 0x%X\n", i, rc);
+ PDEBUG("OV511[0x%X] = 0x%X", i, rc);
}
}
static void ov511_dump_regs( struct usb_device *dev)
{
- PDEBUG("CAMERA INTERFACE REGS\n");
+ PDEBUG("CAMERA INTERFACE REGS");
ov511_dump_reg_range(dev, 0x10, 0x1f);
- PDEBUG("DRAM INTERFACE REGS\n");
+ PDEBUG("DRAM INTERFACE REGS");
ov511_dump_reg_range(dev, 0x20, 0x23);
- PDEBUG("ISO FIFO REGS\n");
+ PDEBUG("ISO FIFO REGS");
ov511_dump_reg_range(dev, 0x30, 0x31);
- PDEBUG("PIO REGS\n");
+ PDEBUG("PIO REGS");
ov511_dump_reg_range(dev, 0x38, 0x39);
ov511_dump_reg_range(dev, 0x3e, 0x3e);
- PDEBUG("I2C REGS\n");
+ PDEBUG("I2C REGS");
ov511_dump_reg_range(dev, 0x40, 0x49);
- PDEBUG("SYSTEM CONTROL REGS\n");
+ PDEBUG("SYSTEM CONTROL REGS");
ov511_dump_reg_range(dev, 0x50, 0x53);
ov511_dump_reg_range(dev, 0x5e, 0x5f);
- PDEBUG("OmniCE REGS\n");
+ 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:
@@ -430,21 +454,19 @@
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;
}
@@ -455,21 +477,151 @@
return 0;
}
+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 images, data shows up in 1200 384 byte segments. The
-first 128 bytes of each segment are probably some combo of UV but I
-haven't figured it out yet. The next 256 bytes are apparently Y
-data and represent 4 squares of 8x8 pixels as follows:
+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
-Right now I'm only moving the Y data and haven't figured out
-the UV data.
-
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
@@ -478,42 +630,102 @@
this data is scrambled.
****************************************************************/
+#define HDIV 8
+#define WDIV (256/HDIV)
-static void ov511_parse_data(unsigned char * pIn,
- unsigned char * pOut,
- int iSegment)
+static void ov511_parse_data(unsigned char * pIn0,
+ unsigned char * pOut0,
+ int iWidth,
+ int iSegment)
{
-
#ifndef OV511_DUMPPIX
- int i, j, k, l, m;
- int iOut;
- unsigned char * pOut1;
-#define HDIV 8
-#define WDIV (256/HDIV)
- i = iSegment / (DEFAULT_WIDTH/ WDIV);
- j = iSegment - i * (DEFAULT_WIDTH/ WDIV);
- iOut = (i*HDIV*DEFAULT_WIDTH + j*WDIV) * 3;
- pOut += iOut;
- pIn += 128;
+ 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++ = *pIn;
- *pOut1++ = *pIn++;
+ *pOut1 = *pIn++;
+ pOut1 += 3;
}
- pOut1 += (DEFAULT_WIDTH - 8) * 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;
- pOut += iSegment * 384;
+ pOut0 += iSegment * 384;
for(i=0; i<384; i++) {
- *pOut++ = *pIn++;
+ *pOut0++ = *pIn0++;
}
#endif
}
@@ -539,11 +751,8 @@
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];
@@ -552,13 +761,18 @@
cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
(cdata[8] & 8) && (cdata[8] & 0x80)) {
- PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[992]));
- 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);
}
}
@@ -568,8 +782,10 @@
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[992]));
- PDEBUG("ov511: Frame Header Byte = 0x%x\n", (int)(cdata[8]));
+#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->segment = 0;
}
@@ -589,15 +805,18 @@
}
/* Parse the segments */
- while(iPix <= 992 - 384 && frame->segment < 1200) {
- ov511_parse_data(pData, frame->data, frame->segment);
+ 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 < 1200) {
+ if (frame->segment < frame->width * frame->height / 256) {
memmove(ov511->scratch, pData, 992 - iPix);
ov511->scratchlen = 992 - iPix;
}
@@ -619,18 +838,6 @@
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;
@@ -639,17 +846,10 @@
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;
@@ -672,185 +872,13 @@
ov511->cursbuf = 0;
ov511->scratchlen = 0;
- ov511_reg_write(ov511->dev, 0x10, 0x00);
- ov511_reg_write(ov511->dev, 0x11, 0x01);
- ov511_reg_write(ov511->dev, 0x12, 0x4f);
- ov511_reg_write(ov511->dev, 0x13, 0x3d);
- ov511_reg_write(ov511->dev, 0x14, 0x00);
- ov511_reg_write(ov511->dev, 0x15, 0x00);
- ov511_reg_write(ov511->dev, 0x16, 0x01); /* 01 */
- ov511_reg_write(ov511->dev, 0x17, 0x00);
- ov511_reg_write(ov511->dev, 0x18, 0x03);
- ov511_reg_write(ov511->dev, 0x19, 0x00);
- ov511_reg_write(ov511->dev, 0x1a, 0x4f);
- ov511_reg_write(ov511->dev, 0x1b, 0x3b);
- ov511_reg_write(ov511->dev, 0x1c, 0x00);
- ov511_reg_write(ov511->dev, 0x1d, 0x00);
- ov511_reg_write(ov511->dev, 0x1e, 0x01);
- ov511_reg_write(ov511->dev, 0x1f, 0x06);
-
- ov511_reg_write(ov511->dev, 0x20, 0x01);
- ov511_reg_write(ov511->dev, 0x21, 0x01);
- ov511_reg_write(ov511->dev, 0x22, 0x01);
- ov511_reg_write(ov511->dev, 0x23, 0x1a);
-
- ov511_reg_write(ov511->dev, 0x30, 0x1f);
- ov511_reg_write(ov511->dev, 0x31, 0x03);
- ov511_reg_write(ov511->dev, 0x38, 0x00);
- ov511_reg_write(ov511->dev, 0x39, 0x00);
- ov511_reg_write(ov511->dev, 0x3e, 0x00);
-
- ov511_reg_write(ov511->dev, 0x50, 0x00);
- ov511_reg_write(ov511->dev, 0x51, 0x00);
- ov511_reg_write(ov511->dev, 0x52, 0x01);
- ov511_reg_write(ov511->dev, 0x53, 0x01);
- ov511_reg_write(ov511->dev, 0x5e, 0x5a);
- ov511_reg_write(ov511->dev, 0x5f, 0x00);
-
- ov511_reg_write(ov511->dev, 0x70, 0x01); /* 3f */
- ov511_reg_write(ov511->dev, 0x71, 0x01); /* 3f */
- ov511_reg_write(ov511->dev, 0x72, 0x01);
- ov511_reg_write(ov511->dev, 0x73, 0x01);
- ov511_reg_write(ov511->dev, 0x74, 0x01);
- ov511_reg_write(ov511->dev, 0x75, 0x01);
- ov511_reg_write(ov511->dev, 0x76, 0x01);
- ov511_reg_write(ov511->dev, 0x77, 0x01);
- ov511_reg_write(ov511->dev, 0x78, 0x00);
- ov511_reg_write(ov511->dev, 0x79, 0x00); /* 03 */
-
- ov511_reg_write(ov511->dev, 0x80, 0x10);
- ov511_reg_write(ov511->dev, 0x81, 0x21);
- ov511_reg_write(ov511->dev, 0x82, 0x32);
- ov511_reg_write(ov511->dev, 0x83, 0x43);
- ov511_reg_write(ov511->dev, 0x84, 0x11);
- ov511_reg_write(ov511->dev, 0x85, 0x21);
- ov511_reg_write(ov511->dev, 0x86, 0x32);
- ov511_reg_write(ov511->dev, 0x87, 0x44);
- ov511_reg_write(ov511->dev, 0x88, 0x11);
- ov511_reg_write(ov511->dev, 0x89, 0x22);
- ov511_reg_write(ov511->dev, 0x8a, 0x43);
- ov511_reg_write(ov511->dev, 0x8b, 0x44);
- ov511_reg_write(ov511->dev, 0x8c, 0x22);
- ov511_reg_write(ov511->dev, 0x8d, 0x32);
- ov511_reg_write(ov511->dev, 0x8e, 0x44);
- ov511_reg_write(ov511->dev, 0x8f, 0x44);
- ov511_reg_write(ov511->dev, 0x90, 0x22);
- ov511_reg_write(ov511->dev, 0x91, 0x43);
- ov511_reg_write(ov511->dev, 0x92, 0x54);
- ov511_reg_write(ov511->dev, 0x93, 0x55);
- ov511_reg_write(ov511->dev, 0x94, 0x33);
- ov511_reg_write(ov511->dev, 0x95, 0x44);
- ov511_reg_write(ov511->dev, 0x96, 0x55);
- ov511_reg_write(ov511->dev, 0x97, 0x55);
- ov511_reg_write(ov511->dev, 0x98, 0x43);
- ov511_reg_write(ov511->dev, 0x99, 0x44);
- ov511_reg_write(ov511->dev, 0x9a, 0x55);
- ov511_reg_write(ov511->dev, 0x9b, 0x55);
- ov511_reg_write(ov511->dev, 0x9c, 0x44);
- ov511_reg_write(ov511->dev, 0x9d, 0x44);
- ov511_reg_write(ov511->dev, 0x9e, 0x55);
- ov511_reg_write(ov511->dev, 0x9f, 0x55);
-
- ov511_reg_write(ov511->dev, 0xa0, 0x20);
- ov511_reg_write(ov511->dev, 0xa1, 0x32);
- ov511_reg_write(ov511->dev, 0xa2, 0x44);
- ov511_reg_write(ov511->dev, 0xa3, 0x44);
- ov511_reg_write(ov511->dev, 0xa4, 0x22);
- ov511_reg_write(ov511->dev, 0xa5, 0x42);
- ov511_reg_write(ov511->dev, 0xa6, 0x44);
- ov511_reg_write(ov511->dev, 0xa7, 0x44);
- ov511_reg_write(ov511->dev, 0xa8, 0x22);
- ov511_reg_write(ov511->dev, 0xa9, 0x43);
- ov511_reg_write(ov511->dev, 0xaa, 0x44);
- ov511_reg_write(ov511->dev, 0xab, 0x44);
- ov511_reg_write(ov511->dev, 0xac, 0x43);
- ov511_reg_write(ov511->dev, 0xad, 0x44);
- ov511_reg_write(ov511->dev, 0xae, 0x44);
- ov511_reg_write(ov511->dev, 0xaf, 0x44);
- ov511_reg_write(ov511->dev, 0xb0, 0x44);
- ov511_reg_write(ov511->dev, 0xb1, 0x44);
- ov511_reg_write(ov511->dev, 0xb2, 0x44);
- ov511_reg_write(ov511->dev, 0xb3, 0x44);
- ov511_reg_write(ov511->dev, 0xb4, 0x44);
- ov511_reg_write(ov511->dev, 0xb5, 0x44);
- ov511_reg_write(ov511->dev, 0xb6, 0x44);
- ov511_reg_write(ov511->dev, 0xb7, 0x44);
- ov511_reg_write(ov511->dev, 0xb8, 0x44);
- ov511_reg_write(ov511->dev, 0xb9, 0x44);
- ov511_reg_write(ov511->dev, 0xba, 0x44);
- ov511_reg_write(ov511->dev, 0xbb, 0x44);
- ov511_reg_write(ov511->dev, 0xbc, 0x44);
- ov511_reg_write(ov511->dev, 0xbd, 0x44);
- ov511_reg_write(ov511->dev, 0xbe, 0x44);
- ov511_reg_write(ov511->dev, 0xbf, 0x44);
-
- ov511_i2c_write(ov511->dev, 0x13, 0x01); /* 01 */
- ov511_i2c_write(ov511->dev, 0x00, 0x1E); /* 1E */
- ov511_i2c_write(ov511->dev, 0x01, 0x80); /* 80 */
- ov511_i2c_write(ov511->dev, 0x02, 0x80); /* 80 */
- ov511_i2c_write(ov511->dev, 0x03, 0x86); /* 86 */
- ov511_i2c_write(ov511->dev, 0x04, 0x80);
- ov511_i2c_write(ov511->dev, 0x05, 0xff); /* ff */
- ov511_i2c_write(ov511->dev, 0x06, 0x5a);
- ov511_i2c_write(ov511->dev, 0x07, 0xd4);
- ov511_i2c_write(ov511->dev, 0x08, 0x80);
- ov511_i2c_write(ov511->dev, 0x09, 0x80);
- ov511_i2c_write(ov511->dev, 0x0a, 0x80);
- ov511_i2c_write(ov511->dev, 0x0b, 0xe0);
- ov511_i2c_write(ov511->dev, 0x0c, 0x1f); /* 1f */
- ov511_i2c_write(ov511->dev, 0x0d, 0x1f); /* 1f */
- ov511_i2c_write(ov511->dev, 0x0e, 0x15); /* 15 */
- ov511_i2c_write(ov511->dev, 0x0f, 0x03);
- ov511_i2c_write(ov511->dev, 0x10, 0xff);
- ov511_i2c_write(ov511->dev, 0x11, 0x01);
- ov511_i2c_write(ov511->dev, 0x12, 0x24); /* 24 */
- ov511_i2c_write(ov511->dev, 0x14, 0x04);
- ov511_i2c_write(ov511->dev, 0x15, 0x01);
- ov511_i2c_write(ov511->dev, 0x16, 0x06);
- ov511_i2c_write(ov511->dev, 0x17, 0x38);
- ov511_i2c_write(ov511->dev, 0x18, 0x03);
- ov511_i2c_write(ov511->dev, 0x19, 0x05);
- ov511_i2c_write(ov511->dev, 0x1a, 0xf4);
- ov511_i2c_write(ov511->dev, 0x1b, 0x28);
- ov511_i2c_write(ov511->dev, 0x1c, 0x7f);
- ov511_i2c_write(ov511->dev, 0x1d, 0xa2);
- ov511_i2c_write(ov511->dev, 0x1e, 0xc4);
- ov511_i2c_write(ov511->dev, 0x1f, 0x04);
- ov511_i2c_write(ov511->dev, 0x20, 0x1c);
- ov511_i2c_write(ov511->dev, 0x21, 0x80);
- ov511_i2c_write(ov511->dev, 0x22, 0x80);
- ov511_i2c_write(ov511->dev, 0x23, 0x2a);
- ov511_i2c_write(ov511->dev, 0x24, 0x10); /* 10 */
- ov511_i2c_write(ov511->dev, 0x25, 0x8a); /* 8a */
- ov511_i2c_write(ov511->dev, 0x26, 0x70);
- ov511_i2c_write(ov511->dev, 0x27, 0xc2);
- ov511_i2c_write(ov511->dev, 0x28, 0x24);
- ov511_i2c_write(ov511->dev, 0x29, 0x11);
- ov511_i2c_write(ov511->dev, 0x2a, 0x04);
- ov511_i2c_write(ov511->dev, 0x2b, 0xac);
- ov511_i2c_write(ov511->dev, 0x2c, 0xfe);
- ov511_i2c_write(ov511->dev, 0x2d, 0x93);
- ov511_i2c_write(ov511->dev, 0x2e, 0x80);
- ov511_i2c_write(ov511->dev, 0x2f, 0xb0);
- ov511_i2c_write(ov511->dev, 0x30, 0x71);
- ov511_i2c_write(ov511->dev, 0x31, 0x90);
- ov511_i2c_write(ov511->dev, 0x32, 0x22);
- ov511_i2c_write(ov511->dev, 0x33, 0x20);
- ov511_i2c_write(ov511->dev, 0x34, 0x8b);
- ov511_i2c_write(ov511->dev, 0x35, 0x9e);
- ov511_i2c_write(ov511->dev, 0x36, 0x7f);
- ov511_i2c_write(ov511->dev, 0x37, 0x7f);
- ov511_i2c_write(ov511->dev, 0x38, 0x81);
-
- ov511_dump_i2c_regs(ov511->dev);
-
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;
@@ -869,7 +897,7 @@
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;
@@ -891,12 +919,10 @@
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;
@@ -968,7 +994,7 @@
int err = -EBUSY;
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- PDEBUG("ov511_open\n");
+ PDEBUG("ov511_open");
down(&ov511->lock);
if (ov511->user)
@@ -987,8 +1013,8 @@
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)
@@ -997,17 +1023,8 @@
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)
@@ -1038,7 +1055,7 @@
{
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- PDEBUG("ov511_close\n");
+ PDEBUG("ov511_close");
down(&ov511->lock);
ov511->user--;
@@ -1066,12 +1083,12 @@
}
// 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:
{
@@ -1127,14 +1144,9 @@
{
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;
@@ -1146,6 +1158,9 @@
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
+
+ if (ov7610_set_picture(ov511, &p))
+ return -EIO;
return 0;
}
@@ -1206,9 +1221,11 @@
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;
@@ -1221,8 +1238,15 @@
/* 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;
@@ -1239,8 +1263,9 @@
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;
@@ -1312,7 +1337,7 @@
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;
@@ -1343,20 +1368,20 @@
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 */
@@ -1367,7 +1392,7 @@
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 */
@@ -1376,7 +1401,7 @@
/* 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;
@@ -1388,7 +1413,7 @@
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;
@@ -1428,14 +1453,52 @@
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;
}
@@ -1445,7 +1508,7 @@
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;
}
@@ -1455,7 +1518,7 @@
/* 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;
}
@@ -1463,36 +1526,31 @@
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:
@@ -1511,7 +1569,7 @@
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)
@@ -1535,7 +1593,7 @@
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;
}
@@ -1546,7 +1604,7 @@
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;
}
@@ -1567,9 +1625,9 @@
printk("ov511: Camera is a AverMedia InterCam Elite\n");
break;
default:
- 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");
+ err("Specific camera type (%d) not recognized", rc);
+ err("Please contact mmcclelland@delphi.com to request");
+ err("support for your camera.");
return NULL;
}
@@ -1579,7 +1637,7 @@
return ov511;
}
else {
- printk(KERN_ERR "ov511: Failed to configure camera\n");
+ err("Failed to configure camera");
return NULL;
}
@@ -1609,7 +1667,7 @@
int usb_ov511_init(void)
{
- PDEBUG("usb_ov511_init()\n");
+ PDEBUG("usb_ov511_init()");
EXPORT_NO_SYMBOLS;
@@ -1631,7 +1689,7 @@
{
usb_ov511_cleanup();
- PDEBUG("Module unloaded\n");
+ PDEBUG("Module unloaded");
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)