--- linux-2.3.36-pre6/drivers/usb/ov511.c Tue Jan 4 01:39:26 2000 +++ linux-2.3.36-pre6-devel/drivers/usb/ov511.c Sun Jan 2 04:50:46 2000 @@ -46,13 +46,15 @@ #include "usb.h" #include "ov511.h" +#define OV511_I2C_RETRIES 3 + /* Video Size 384 x 288 x 3 bytes for RGB */ -#define MAX_FRAME_SIZE (384 * 288 * 3) +#define MAX_FRAME_SIZE (320 * 240 * 3) // FIXME - Force CIF to make some apps happy for the moment. Should find a // better way to do this. -#define DEFAULT_WIDTH 384 -#define DEFAULT_HEIGHT 288 +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 char kernel_version[] = UTS_RELEASE; @@ -173,7 +175,7 @@ vfree(mem); } -int usb_ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +int ov511_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) { int rc; @@ -189,7 +191,7 @@ } /* returns: negative is error, pos or zero is data */ -int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg) +int ov511_reg_read(struct usb_device *dev, unsigned char reg) { int rc; unsigned char buffer[1]; @@ -208,89 +210,120 @@ return buffer[0]; } -int usb_ov511_cam_reg_write(struct usb_device *dev, unsigned char reg, unsigned char value) +int ov511_i2c_write(struct usb_device *dev, unsigned char reg, unsigned char value) { - int rc; - - // Three byte write cycle - - // Set slave ID (This might only need to be done once) - // (CAMERA SPECIFIC (OV7610/OV7110)) - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, - OV7610_I2C_WRITE_ID); - if (rc < 0) return rc; - - // Select camera register (I2C sub-address) - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); - if (rc < 0) return rc; - - // Write "value" to I2C data port of OV511 - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); - if (rc < 0) return rc; - - // FIXME - should ensure bus is idle before continuing - - // Initiate 3-byte write cycle - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + int rc, retries; - return rc; + /* Three byte write cycle */ + for(retries = OV511_I2C_RETRIES;;) { +// ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, +// OV7610_I2C_WRITE_ID); +// if (rc < 0) return rc; + + /* Select camera register */ + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg); + if (rc < 0) return rc; + + /* Write "value" to I2C data port of OV511 */ + rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value); + if (rc < 0) return rc; + + /* Initiate 3-byte write cycle */ + rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01); + if (rc < 0) return rc; + + do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */ + if (rc < 0) return rc; + + if((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + + if (--retries < 0) return -1; + } + + return 0; } /* returns: negative is error, pos or zero is data */ -int usb_ov511_cam_reg_read(struct usb_device *dev, unsigned char reg) +int ov511_i2c_read(struct usb_device *dev, unsigned char reg) { - int rc; + int rc, retries; - // Two byte write cycle - - // Set slave ID (This might only need to be done once) - // (CAMERA SPECIFIC (OV7610/OV7110)) - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, OV7610_I2C_WRITE_ID); - if (rc < 0) return rc; - - // Select camera register (I2C sub-address) - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); - if (rc < 0) return rc; - - // Initiate 2-byte write cycle - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); - if (rc < 0) return rc; - - // Two byte read cycle - - // Set slave ID (This might only need to be done once) - // (CAMERA SPECIFIC (OV7610/OV7110)) - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, - OV7610_I2C_READ_ID); - if (rc < 0) return rc; - - // Initiate 2-byte read cycle - rc = usb_ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); - if (rc < 0) return rc; - - // FIXME - should check I2C bus status here before reading data! - - // Write "value" to I2C data port of OV511 - return usb_ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT); + /* Two byte write cycle */ + for(retries = OV511_I2C_RETRIES;;) { +// ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, +// OV7610_I2C_WRITE_ID); +// if (rc < 0) return rc; + + /* Select camera register */ + rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg); + if (rc < 0) return rc; + + /* Initiate 2-byte write cycle */ + rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03); + if (rc < 0) return rc; + + do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */ + if (rc < 0) return rc; + + if((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + + if (--retries < 0) return -1; + } + + /* Two byte read cycle */ + for(retries = OV511_I2C_RETRIES;;) { +// ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, +// OV7610_I2C_READ_ID); +// if (rc < 0) return rc; + + /* Initiate 2-byte read cycle */ + rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05); + if (rc < 0) return rc; + + do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL); + while(rc > 0 && ((rc&1) == 0)); /* Retry until idle */ + if (rc < 0) return rc; + + if((rc&2) == 0) /* Ack? */ + break; + + /* I2C abort */ + rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10); + if (rc < 0) return rc; + + if (--retries < 0) return -1; + } + + return(ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT)); } -int usb_ov511_reset(struct usb_device *dev, unsigned char reset_type) +int ov511_reset(struct usb_device *dev, unsigned char reset_type) { int rc; PDEBUG("Reset: type=0x%X\n", reset_type); - rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type); + rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type); if (rc < 0) printk(KERN_ERR "ov511: reset: command failed\n"); - rc = usb_ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0); + rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0); if (rc < 0) printk(KERN_ERR "ov511: reset: command failed\n"); return rc; } -int usb_ov511_set_packet_size(struct usb_ov511 *ov511, int size) +int ov511_set_packet_size(struct usb_ov511 *ov511, int size) { int alt, multiplier, err; @@ -303,7 +336,7 @@ break; case 993: alt = 1; - multiplier = 32; + multiplier = 31; break; case 768: alt = 2; @@ -311,7 +344,7 @@ break; case 769: alt = 3; - multiplier = 25; + multiplier = 24; break; case 512: alt = 4; @@ -319,11 +352,11 @@ break; case 513: alt = 5; - multiplier = 17; + multiplier = 16; break; case 257: alt = 6; - multiplier = 9; + multiplier = 8; break; case 0: alt = 7; @@ -335,7 +368,7 @@ return -EINVAL; } - err = usb_ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, + 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", @@ -349,7 +382,7 @@ } // FIXME - Should we only reset the FIFO? - if (usb_ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0) + if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0) return -ENOMEM; return 0; @@ -366,46 +399,46 @@ static int ov511_compress_isochronous(struct usb_ov511 *ov511, urb_t *urb) { - unsigned char *cdata, *data; + unsigned char *cdata, *data; int i, totlen = 0; - data = ov511->scratch + ov511->scratchlen; - 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; - - cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (st) { + data = ov511->scratch + ov511->scratchlen; + 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; + + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) { // Macro - must be in braces! - PDEBUG("data error: [%d] len=%d, status=%d\n", - i, n, st); - } - - if ((ov511->scratchlen + n) > SCRATCH_BUF_SIZE) { - PDEBUG("scratch buf overflow!scr_len: %d, n: %d\n", ov511->scratchlen, n ); - return totlen; - } - - if (n) { - memmove(data, cdata, n); - data += n; - totlen += n; - ov511->scratchlen += n; - } - } - - return totlen; + PDEBUG("data error: [%d] len=%d, status=%d\n", + i, n, st); + } + + if ((ov511->scratchlen + n) > SCRATCH_BUF_SIZE) { + PDEBUG("scratch buf overflow!scr_len: %d, n: %d\n", ov511->scratchlen, n ); + return totlen; + } + + if (n) { + memmove(data, cdata, n); + data += n; + totlen += n; + ov511->scratchlen += n; + } + } + + return totlen; } static void ov511_isoc_irq(struct urb *urb) { - int len; - struct usb_ov511 *ov511 = urb->context; - struct ov511_sbuf *sbuf; - int i; + int len; + struct usb_ov511 *ov511 = urb->context; + struct ov511_sbuf *sbuf; + int i; - PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length); + PDEBUG("ov511_isoc_irq: %p status %d, errcount = %d, length = %d\n", urb, urb->status, urb->error_count, urb->actual_length); if (!ov511->streaming) { PDEBUG("hmmm... not streaming, but got interrupt\n"); @@ -428,8 +461,8 @@ } 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; + sbuf->urb->iso_frame_desc[i].status = 0; + sbuf->urb->iso_frame_desc[i].actual_length = 0; } /* Move to the next sbuf */ @@ -452,64 +485,63 @@ ov511->cursbuf = 0; ov511->scratchlen = 0; - // FIXME - is this the proper size? - usb_ov511_set_packet_size(ov511, 512); + ov511_set_packet_size(ov511, 512); /* We double buffer the Iso lists */ - urb = usb_alloc_urb(FRAMES_PER_DESC); + urb = usb_alloc_urb(FRAMES_PER_DESC); if (!urb) { printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); return -ENOMEM; } - ov511->sbuf[0].urb = urb; - urb->dev = dev; - urb->context = ov511; - urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ov511->sbuf[0].data; - urb->complete = ov511_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; - urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; - } - - urb = usb_alloc_urb(FRAMES_PER_DESC); - if (!urb) { - printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); - return -ENOMEM; - } - ov511->sbuf[1].urb = urb; - urb->dev = dev; - urb->context = ov511; - urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); - urb->transfer_flags = USB_ISO_ASAP; - urb->transfer_buffer = ov511->sbuf[1].data; - urb->complete = ov511_isoc_irq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; - for (fx = 0; fx < FRAMES_PER_DESC; fx++) { - urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; - urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; - } - - ov511->sbuf[1].urb->next = ov511->sbuf[0].urb; - ov511->sbuf[0].urb->next = ov511->sbuf[1].urb; - - 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 = usb_submit_urb(ov511->sbuf[1].urb); - if (err) - printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n", - err); - - ov511->streaming = 1; - - return 0; + ov511->sbuf[0].urb = urb; + urb->dev = dev; + urb->context = ov511; + urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ov511->sbuf[0].data; + urb->complete = ov511_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + urb = usb_alloc_urb(FRAMES_PER_DESC); + if (!urb) { + printk(KERN_ERR "ov511_init_isoc: usb_alloc_urb ret. NULL\n"); + return -ENOMEM; + } + ov511->sbuf[1].urb = urb; + urb->dev = dev; + urb->context = ov511; + urb->pipe = usb_rcvisocpipe(dev, OV511_ENDPOINT_ADDRESS); + urb->transfer_flags = USB_ISO_ASAP; + urb->transfer_buffer = ov511->sbuf[1].data; + urb->complete = ov511_isoc_irq; + urb->number_of_packets = FRAMES_PER_DESC; + urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + + ov511->sbuf[1].urb->next = ov511->sbuf[0].urb; + ov511->sbuf[0].urb->next = ov511->sbuf[1].urb; + + 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 = usb_submit_urb(ov511->sbuf[1].urb); + if (err) + printk(KERN_ERR "ov511_init_isoc: usb_run_isoc(1) ret %d\n", + err); + + ov511->streaming = 1; + + return 0; } @@ -518,24 +550,17 @@ if (!ov511->streaming) return; -// FIXME - Figure out how to do this with the ov511 (Does the below do it?) -// /* Turn off continuous grab */ -// if (usb_cpia_set_grab_mode(cpia->dev, 0) < 0) { -// printk(KERN_ERR "cpia_set_grab_mode error\n"); -// return /* -EBUSY */; -// } - - usb_ov511_set_packet_size(ov511, 0); + ov511_set_packet_size(ov511, 0); /* Unschedule all of the iso td's */ - usb_unlink_urb(ov511->sbuf[1].urb); - usb_unlink_urb(ov511->sbuf[0].urb); - - ov511->streaming = 0; - - /* Delete them all */ - usb_free_urb(ov511->sbuf[1].urb); - usb_free_urb(ov511->sbuf[0].urb); + usb_unlink_urb(ov511->sbuf[1].urb); + usb_unlink_urb(ov511->sbuf[0].urb); + + ov511->streaming = 0; + + /* Delete them all */ + usb_free_urb(ov511->sbuf[1].urb); + usb_free_urb(ov511->sbuf[0].urb); } static int ov511_new_frame(struct usb_ov511 *ov511, int framenum) @@ -570,25 +595,8 @@ height = DEFAULT_HEIGHT; height = (height / 4) * 4; /* Multiple of 4 */ -// FIXME - Don't know how to implement the equivalent of this for the ov511 -// /* Set the ROI they want */ -// if (usb_cpia_set_roi(cpia->dev, 0, width / 8, 0, height / 4) < 0) -// return -EBUSY; - -// if (usb_cpia_set_compression(cpia->dev, cpia->compress ? -// COMP_AUTO : COMP_DISABLED, DONT_DECIMATE) < 0) { -// printk(KERN_ERR "cpia_set_compression error\n"); -// return -EBUSY; -// } - - /* We want a fresh frame every 30 we get */ - ov511->compress = (ov511->compress + 1) % 30; - -// /* Grab the frame */ -// if (usb_cpia_upload_frame(cpia->dev, WAIT_FOR_NEXT_FRAME) < 0) { -// printk(KERN_ERR "cpia_upload_frame error\n"); -// return -EBUSY; -// } +// /* We want a fresh frame every 30 we get */ +// ov511->compress = (ov511->compress + 1) % 30; return 0; } @@ -1061,11 +1069,11 @@ 0 }; -static int usb_ov511_configure(struct usb_ov511 *ov511) +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"); @@ -1082,28 +1090,49 @@ return -EBUSY; } - // Disable compression - if (usb_ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) { - printk(KERN_ERR "ov511: disable compression: command failed\n"); + /* Reset in case driver was unloaded and reloaded without unplug */ + if (ov511_reset(dev, OV511_RESET_ALL) < 0) goto error; - } - - // Initialize system - // FIXME - This should be moved to a function - if (usb_ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) { + + /* Initialize system */ + if (ov511_reg_write(dev, OV511_REG_SYSTEM_INIT, 0x01) < 0) { printk(KERN_ERR "ov511: enable system: command failed\n"); goto error; } + + /* This seems to be necessary */ + if (ov511_reset(dev, OV511_RESET_ALL) < 0) + goto error; + + /* Disable compression */ + if (ov511_reg_write(dev, OV511_OMNICE_ENABLE, 0x00) < 0) { + printk(KERN_ERR "ov511: disable compression: command failed\n"); + 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, 3); - if (usb_ov511_reset(dev, OV511_RESET_NOREGS) < 0) + 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 = usb_ov511_cam_reg_read(dev, 0x1D); + temprc = ov511_i2c_read(dev, 0x1C); + PDEBUG("Camera reg 0x1C: 0x%X\n", temprc); + temprc = ov511_i2c_read(dev, 0x1D); PDEBUG("Camera reg 0x1D: 0x%X\n", temprc); // END DEBUG CODE - ov511->compress = 0; + ov511->compress = 0; return 0; @@ -1137,7 +1166,7 @@ if (dev->descriptor.idProduct != 0x0511) return NULL; - /* Checking vendor/product should be enough, but what the hell */ + /* Checking vendor/product should be enough, but what the hell */ if (interface->bInterfaceClass != 0xFF) return NULL; if (interface->bInterfaceSubClass != 0x00) @@ -1156,14 +1185,14 @@ ov511->dev = dev; ov511->iface = interface->bInterfaceNumber; - rc = usb_ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); + rc = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); if (rc < 0) { printk("ov511: Unable to read camera bridge registers\n"); return NULL; - } else if (rc == 3) { // D-Link DSB-C300 + } else if (rc == 3) { /* D-Link DSB-C300 */ printk("ov511: Camera is a D-Link DSB-C300\n"); ov511->customid = 3; - } else if (rc == 21) { // Creative Labs WebCam 3 + } else if (rc == 21) { /* Creative Labs WebCam 3 */ printk("ov511: Camera is a Creative Labs WebCam 3\n"); ov511->customid = 21; } else { @@ -1173,11 +1202,7 @@ return NULL; } - // Reset in case driver was unloaded and reloaded without unplug - if (usb_ov511_reset(dev, OV511_RESET_ALL) < 0) - return NULL; - - if (!usb_ov511_configure(ov511)) { + if (!ov511_configure(ov511)) { ov511->user=0; init_MUTEX(&ov511->lock); /* to 1 == available */ return ov511;