patch-2.4.0-test2 linux/drivers/usb/ov511.c
Next file: linux/drivers/usb/ov511.h
Previous file: linux/drivers/usb/mousedev.c
Back to the patch index
Back to the overall index
- Lines: 661
- Date:
Mon Jun 19 13:42:42 2000
- Orig file:
v2.4.0-test1/linux/drivers/usb/ov511.c
- Orig date:
Mon Jun 19 16:32:00 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
@@ -2,8 +2,8 @@
* OmniVision OV511 Camera-to-USB Bridge Driver
*
* Copyright (c) 1999-2000 Mark W. McClelland
- * Many improvements by Bret Wallach
- * Color fixes by by Orion Sky Lawlor, olawlor@acm.org, 2/26/2000
+ * Many improvements by Bret Wallach <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
* Snapshot code by Kevin Moore
* OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
* Changes by Claudio Matsuoka <claudio@conectiva.com>
@@ -30,7 +30,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-static const char version[] = "1.15";
+static const char version[] = "1.17";
#define __NO_VERSION__
@@ -55,6 +55,8 @@
#include "ov511.h"
+#undef OV511_GBR422 /* Experimental -- sets the 7610 to GBR422 */
+
#define OV511_I2C_RETRIES 3
/* Video Size 640 x 480 x 3 bytes for RGB */
@@ -64,8 +66,8 @@
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
-#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_RGB24 ? 384 : 256)
-#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_RGB24 ? 24 : 8)
+#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384)
+#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : 24)
/* PARAMETER VARIABLES: */
static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */
@@ -280,6 +282,7 @@
/* IMPORTANT: This output MUST be kept under PAGE_SIZE
* or we need to get more sophisticated. */
+ out += sprintf (out, "driver_version : %s\n", version);
out += sprintf (out, "custom_id : %d\n", ov511->customid);
out += sprintf (out, "model : %s\n", ov511->desc ?
clist[ov511->desc].description : "unknown");
@@ -300,10 +303,6 @@
ov511->frame[i].depth);
out += sprintf (out, " size : %d %d\n",
ov511->frame[i].width, ov511->frame[i].height);
-#if 0
- out += sprintf (out, " hdr_size : %d %d\n",
- ov511->frame[i].hdrwidth, ov511->frame[i].hdrheight);
-#endif
out += sprintf (out, " format : ");
for (j = 0; plist[j].num >= 0; j++) {
if (plist[j].num == ov511->frame[i].format) {
@@ -317,10 +316,6 @@
ov511->frame[i].segsize);
out += sprintf (out, " data_buffer : 0x%p\n",
ov511->frame[i].data);
-#if 0
- out += sprintf (out, " bytesread : %ld\n",
- ov511->frame[i].bytes_read);
-#endif
}
out += sprintf (out, "snap_enabled : %s\n", YES_NO (ov511->snap_enabled));
out += sprintf (out, "bridge : %s\n",
@@ -846,28 +841,20 @@
return 0;
}
-/* FIXME: add 400x300, 176x144, 160x140 */
+/* FIXME: 176x144, 160x140 */
+/* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */
static struct mode_list mlist[] = {
- { 640, 480, VIDEO_PALETTE_GREY, 0x4f, 0x3d, 0x00, 0x00,
- 0x4f, 0x3d, 0x00, 0x00, 0x04, 0x03, 0x24, 0x04, 0x9e },
- { 640, 480, VIDEO_PALETTE_RGB24,0x4f, 0x3d, 0x00, 0x00,
- 0x4f, 0x3d, 0x00, 0x00, 0x06, 0x03, 0x24, 0x04, 0x9e },
- { 320, 240, VIDEO_PALETTE_GREY, 0x27, 0x1f, 0x00, 0x00,
- 0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e },
- { 320, 240, VIDEO_PALETTE_RGB24,0x27, 0x1f, 0x00, 0x00,
- 0x27, 0x1f, 0x00, 0x00, 0x01, 0x03, 0x04, 0x24, 0x1e },
- { 352, 288, VIDEO_PALETTE_GREY, 0x2b, 0x25, 0x00, 0x00,
- 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
- { 352, 288, VIDEO_PALETTE_RGB24,0x2b, 0x25, 0x00, 0x00,
- 0x2b, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
- { 384, 288, VIDEO_PALETTE_GREY, 0x2f, 0x25, 0x00, 0x00,
- 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
- { 384, 288, VIDEO_PALETTE_RGB24,0x2f, 0x25, 0x00, 0x00,
- 0x2f, 0x25, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
- { 448, 336, VIDEO_PALETTE_GREY, 0x37, 0x29, 0x00, 0x00,
- 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
- { 448, 336, VIDEO_PALETTE_RGB24,0x37, 0x29, 0x00, 0x00,
- 0x37, 0x29, 0x00, 0x00, 0x01, 0x03, 0x04, 0x04, 0x1e },
+ /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COMC COML */
+ { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e },
+ { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e },
+ { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e },
+ { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e },
+ { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
+ { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
+ { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
+ { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
+ { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
+ { 448, 336, 1 ,0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
{ 0, 0 }
};
@@ -875,11 +862,9 @@
ov511_mode_init_regs(struct usb_ov511 *ov511,
int width, int height, int mode, int sub_flag)
{
- int rc = 0;
- struct usb_device *dev = ov511->dev;
- int hwsbase = 0;
- int hwebase = 0;
int i;
+ struct usb_device *dev = ov511->dev;
+ int hwsbase = 0, hwebase = 0;
PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
width, height, mode, sub_flag);
@@ -930,87 +915,55 @@
break;
}
-#if 0
- /* FIXME: subwindow support is currently broken!
- */
- if (width == 640 && height == 480) {
- if (sub_flag) {
- /* horizontal window start */
- ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
- /* horizontal window end */
- ov511_i2c_write(dev, 0x18,
- hwebase+((ov511->subx+ov511->subw)>>2));
- /* vertical window start */
- ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
- /* vertical window end */
- ov511_i2c_write(dev, 0x1a,
- 0x5+((ov511->suby+ov511->subh)>>1));
- ov511_reg_write(dev, 0x12, (ov511->subw>>3)-1);
- ov511_reg_write(dev, 0x13, (ov511->subh>>3)-1);
- /* clock rate control */
- ov511_i2c_write(dev, 0x11, 0x01);
-
- /* Snapshot additions */
- ov511_reg_write(dev, 0x1a, (ov511->subw>>3)-1);
- ov511_reg_write(dev, 0x1b, (ov511->subh>>3)-1);
- ov511_reg_write(dev, 0x1c, 0x00);
- ov511_reg_write(dev, 0x1d, 0x00);
- } else {
- ov511_i2c_write(dev, 0x17, hwsbase);
- ov511_i2c_write(dev, 0x18, hwebase + (640>>2));
- ov511_i2c_write(dev, 0x19, 0x5);
- ov511_i2c_write(dev, 0x1a, 5 + (480>>1));
- ov511_reg_write(dev, 0x12, 0x4f);
- ov511_reg_write(dev, 0x13, 0x3d);
-
- /* Snapshot additions */
- ov511_reg_write(dev, 0x1a, 0x4f);
- ov511_reg_write(dev, 0x1b, 0x3d);
- ov511_reg_write(dev, 0x1c, 0x00);
- ov511_reg_write(dev, 0x1d, 0x00);
-
- if (mode == VIDEO_PALETTE_GREY) {
- ov511_i2c_write(dev, 0x11, 4); /* check */
- } else {
- ov511_i2c_write(dev, 0x11, 6); /* check */
- }
- }
-
- ov511_reg_write(dev, 0x14, 0x00); /* Pixel divisor */
- ov511_reg_write(dev, 0x15, 0x00); /* Line divisor */
-
- /* FIXME?? Shouldn't below be true only for YUV420? */
- ov511_reg_write(dev, 0x18, 0x03); /* YUV420/422, YFIR */
+ if (sub_flag) {
+ ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2));
+ ov511_i2c_write(dev, 0x18, hwebase+((ov511->subx+ov511->subw)>>2));
+ ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1));
+ ov511_i2c_write(dev, 0x1a, 0x5+((ov511->suby+ov511->subh)>>1));
+ } else {
+ ov511_i2c_write(dev, 0x17, hwsbase);
+ ov511_i2c_write(dev, 0x18, hwebase + (640>>2));
+ ov511_i2c_write(dev, 0x19, 0x5);
+ ov511_i2c_write(dev, 0x1a, 5 + (480>>1));
+ }
- ov511_i2c_write(dev, 0x12, 0x24); /* Common A */
- ov511_i2c_write(dev, 0x14, 0x04); /* Common C */
+ for (i = 0; mlist[i].width; i++) {
+ int lncnt, pxcnt, clock;
- /* 7620 doesn't have register 0x35, so play it safe */
- if (ov511->sensor != SEN_OV7620)
- ov511_i2c_write(dev, 0x35, 0x9e);
-#endif
+ if (width != mlist[i].width || height != mlist[i].height)
+ continue;
- for (i = 0; mlist[i].width; i++) {
- if (width != mlist[i].width ||
- height != mlist[i].height ||
- mode != mlist[i].mode)
+ if (!mlist[i].color && mode != VIDEO_PALETTE_GREY)
continue;
- ov511_reg_write(dev, 0x12, mlist[i].pxcnt);
- ov511_reg_write(dev, 0x13, mlist[i].lncnt);
+ /* Here I'm assuming that snapshot size == image size.
+ * I hope that's always true. --claudio
+ */
+ pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt;
+ lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt;
+
+ ov511_reg_write(dev, 0x12, pxcnt);
+ ov511_reg_write(dev, 0x13, lncnt);
ov511_reg_write(dev, 0x14, mlist[i].pxdv);
ov511_reg_write(dev, 0x15, mlist[i].lndv);
ov511_reg_write(dev, 0x18, mlist[i].m420);
/* Snapshot additions */
- ov511_reg_write(dev, 0x1a, mlist[i].s_pxcnt);
- ov511_reg_write(dev, 0x1b, mlist[i].s_lncnt);
- ov511_reg_write(dev, 0x1c, mlist[i].s_pxdv);
- ov511_reg_write(dev, 0x1d, mlist[i].s_lndv);
-
- ov511_i2c_write(dev, 0x11, mlist[i].clock); /* check */
+ ov511_reg_write(dev, 0x1a, pxcnt);
+ ov511_reg_write(dev, 0x1b, lncnt);
+ ov511_reg_write(dev, 0x1c, mlist[i].pxdv);
+ ov511_reg_write(dev, 0x1d, mlist[i].lndv);
+
+ /* Calculate and set the clock divisor */
+ clock = ((sub_flag ? ov511->subw * ov511->subh : width * height)
+ * (mlist[i].color ? 3 : 2) / 2) / 66000;
+ ov511_i2c_write(dev, 0x11, clock);
+#ifdef OV511_GBR422
+ ov511_i2c_write(dev, 0x12, mlist[i].common_A | 0x08);
+#else
ov511_i2c_write(dev, 0x12, mlist[i].common_A);
+#endif
ov511_i2c_write(dev, 0x14, mlist[i].common_C);
/* 7620 doesn't have register 0x35, so play it safe */
@@ -1020,20 +973,20 @@
break;
}
+ if (ov511_restart(ov511->dev) < 0)
+ return -EIO;
+
if (mlist[i].width == 0) {
err("Unknown mode (%d, %d): %d", width, height, mode);
- rc = -EINVAL;
+ return -EINVAL;
}
- if (ov511_restart(ov511->dev) < 0)
- return -EIO;
-
#ifdef OV511_DEBUG
if (debug >= 5)
ov511_dump_i2c_regs(dev);
#endif
- return rc;
+ return 0;
}
/**********************************************************************
@@ -1115,7 +1068,7 @@
* 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
+ * 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.
@@ -1132,6 +1085,57 @@
#undef OV511_DUMPPIX
+#ifdef OV511_GBR422
+static void
+ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
+ int iOutY, int iOutUV, int iHalf, int iWidth)
+{
+ int k, l, m;
+ unsigned char *pIn;
+ unsigned char *pOut, *pOut1;
+
+ pIn = pIn0;
+ pOut = pOut0 + iOutUV + (force_rgb ? 2 : 0);
+
+ for (k = 0; k < 8; k++) {
+ pOut1 = pOut;
+ for (l = 0; l < 8; l++) {
+ *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) =
+ *(pOut1 + iWidth*3 + 3) = *pIn++;
+ pOut1 += 6;
+ }
+ pOut += iWidth*3*2;
+ }
+
+ pIn = pIn0 + 64;
+ pOut = pOut0 + iOutUV + (force_rgb ? 0 : 2);
+ for (k = 0; k < 8; k++) {
+ pOut1 = pOut;
+ for (l = 0; l < 8; l++) {
+ *pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) =
+ *(pOut1 + iWidth*3 + 3) = *pIn++;
+ pOut1 += 6;
+ }
+ pOut += iWidth*3*2;
+ }
+
+ pIn = pIn0 + 128;
+ pOut = pOut0 + iOutY + 1;
+ 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;
+ }
+}
+
+#else
+
static void
ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
int iOutY, int iOutUV, int iHalf, int iWidth)
@@ -1225,6 +1229,7 @@
}
#endif
}
+#endif
/*
* For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
@@ -1252,7 +1257,7 @@
for (m = 0; m < 8; m++) {
*pOut1++ = *pIn++;
}
- pOut1 += iWidth - WDIV;
+ pOut1 += iWidth - 8;
}
pOut += 8;
}
@@ -1350,12 +1355,10 @@
/* Frame end */
if (cdata[8] & 0x80) {
-#if 0
struct timeval *ts;
ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE);
- do_gettimeofday (ts);
-#endif
+ do_gettimeofday (ts);
PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d",
ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
@@ -1456,9 +1459,9 @@
}
/*
- * iY counts segment lines
- * jY counts segment columns
- * iOutY is the offset (in bytes) of the segment upper left corner
+ * i counts segment lines
+ * j counts segment columns
+ * iOut is the offset (in bytes) of the upper left corner
*/
iY = iSegY / (frame->width / WDIV);
jY = iSegY - iY * (frame->width / WDIV);
@@ -1467,11 +1470,15 @@
jUV = iSegUV - iUV * (frame->width / WDIV * 2);
iOutUV = (iUV*HDIV*2*frame->width + jUV*WDIV/2) * (frame->depth >> 3);
- if (frame->format == VIDEO_PALETTE_GREY)
+ switch (frame->format) {
+ case VIDEO_PALETTE_GREY:
ov511_parse_data_grey (pData, pOut, iOutY, frame->width);
- else if (frame->format == VIDEO_PALETTE_RGB24)
+ break;
+ case VIDEO_PALETTE_RGB24:
ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV,
iY & 1, frame->width);
+ break;
+ }
pData = &cdata[iPix];
}
@@ -1480,8 +1487,7 @@
if (frame->segment < frame->width * frame->height / 256) {
ov511->scratchlen = (ov511->packet_size - 1) - iPix;
if (ov511->scratchlen < frame->segsize)
- memmove(ov511->scratch, pData,
- ov511->scratchlen);
+ memmove(ov511->scratch, pData, ov511->scratchlen);
else
ov511->scratchlen = 0;
}
@@ -1677,25 +1683,23 @@
static int ov511_open(struct video_device *dev, int flags)
{
- int err = -EBUSY;
struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
- int i;
+ int i, err = 0;
+ MOD_INC_USE_COUNT;
PDEBUG(4, "opening");
-
down(&ov511->lock);
- if (ov511->user) {
- up(&ov511->lock);
- return -EBUSY;
- }
+ err = -EBUSY;
+ if (ov511->user)
+ goto out;
err = -ENOMEM;
/* Allocate memory for the frame buffers */
ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE);
if (!ov511->fbuf)
- return err;
+ goto out;
ov511->sub_flag = 0;
@@ -1710,7 +1714,7 @@
open_free_ret:
while (--i) kfree(ov511->sbuf[i].data);
rvfree(ov511->fbuf, 2 * MAX_DATA_SIZE);
- return err;
+ goto out;
}
PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data);
}
@@ -1720,11 +1724,14 @@
goto open_free_ret;
ov511->user++;
+
+out:
up(&ov511->lock);
- MOD_INC_USE_COUNT;
+ if (err)
+ MOD_DEC_USE_COUNT;
- return 0;
+ return err;
}
static void ov511_close(struct video_device *dev)
@@ -1737,8 +1744,6 @@
down(&ov511->lock);
ov511->user--;
- MOD_DEC_USE_COUNT;
-
ov511_stop_isoc(ov511);
rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);
@@ -1751,6 +1756,9 @@
video_unregister_device(&ov511->vdev);
kfree(ov511);
}
+
+ MOD_DEC_USE_COUNT;
+
}
static int ov511_init_done(struct video_device *dev)
@@ -1887,18 +1895,11 @@
return -EINVAL;
if (vc.decimation)
return -EINVAL;
-#if 0
- vc.x /= 4;
- vc.x *= 4;
- vc.y /= 2;
- vc.y *= 2;
- vc.width /= 32;
- vc.width *= 32;
-#else
+
vc.x &= ~3L;
vc.y &= ~1L;
vc.y &= ~31L;
-#endif
+
if (vc.width == 0)
vc.width = 32;
@@ -1989,6 +1990,7 @@
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
+ int ret;
if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
return -EFAULT;
@@ -2017,8 +2019,12 @@
before changing modes */
interruptible_sleep_on(&ov511->wq);
if (signal_pending(current)) return -EINTR;
- ov511_mode_init_regs(ov511, vm.width, vm.height,
+ ret = ov511_mode_init_regs(ov511, vm.width, vm.height,
vm.format, ov511->sub_flag);
+#if 0
+ if (ret < 0)
+ return ret;
+#endif
}
ov511->frame[vm.frame].width = vm.width;
@@ -2290,6 +2296,17 @@
int i, success;
int rc;
+ /* Lawrence Glaister <lg@jfm.bc.ca> reports:
+ *
+ * Register 0x0f in the 7610 has the following effects:
+ *
+ * 0x85 (AEC method 1): Best overall, good contrast range
+ * 0x45 (AEC method 2): Very overexposed
+ * 0xa5 (spec sheet default): Ok, but the black level is
+ * shifted resulting in loss of contrast
+ * 0x05 (old driver setting): very overexposed, too much
+ * contrast
+ */
static struct ov511_regvals aRegvalsNorm7610[] = {
{ OV511_I2C_BUS, 0x10, 0xff },
{ OV511_I2C_BUS, 0x16, 0x06 },
@@ -2299,16 +2316,16 @@
{ OV511_I2C_BUS, 0x06, 0x00 },
{ OV511_I2C_BUS, 0x12, 0x00 },
{ OV511_I2C_BUS, 0x38, 0x81 },
- { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */
+ { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */
{ OV511_I2C_BUS, 0x05, 0x00 },
- { OV511_I2C_BUS, 0x0f, 0x05 },
+ { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */
{ OV511_I2C_BUS, 0x15, 0x01 },
{ OV511_I2C_BUS, 0x20, 0x1c },
{ OV511_I2C_BUS, 0x23, 0x2a },
{ OV511_I2C_BUS, 0x24, 0x10 },
{ OV511_I2C_BUS, 0x25, 0x8a },
{ OV511_I2C_BUS, 0x27, 0xc2 },
- { OV511_I2C_BUS, 0x29, 0x03 }, /* 91 */
+ { OV511_I2C_BUS, 0x29, 0x03 }, /* 91 */
{ OV511_I2C_BUS, 0x2a, 0x04 },
{ OV511_I2C_BUS, 0x2c, 0xfe },
{ OV511_I2C_BUS, 0x30, 0x71 },
@@ -2331,7 +2348,7 @@
{ OV511_I2C_BUS, 0x12, 0x00 },
{ OV511_I2C_BUS, 0x28, 0x24 },
{ OV511_I2C_BUS, 0x05, 0x00 },
- { OV511_I2C_BUS, 0x0f, 0x05 },
+ { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */
{ OV511_I2C_BUS, 0x15, 0x01 },
{ OV511_I2C_BUS, 0x23, 0x00 },
{ OV511_I2C_BUS, 0x24, 0x10 },
@@ -2530,9 +2547,6 @@
usb_driver_release_interface(&ov511_driver,
&dev->actconfig->interface[ov511->iface]);
- kfree(ov511);
- ov511 = NULL;
-
return -EBUSY;
}
@@ -2570,9 +2584,12 @@
if (interface->bInterfaceSubClass != 0x00)
return NULL;
+ /* Since code below may sleep, we use this as a lock */
+ MOD_INC_USE_COUNT;
+
if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
err("couldn't kmalloc ov511 struct");
- return NULL;
+ goto error;
}
memset(ov511, 0, sizeof(*ov511));
@@ -2610,7 +2627,7 @@
/* Lifeview USB Life TV not supported */
if (clist[i].id == 38) {
err("This device is not supported yet.");
- return NULL;
+ goto error;
}
if (clist[i].id == -1) {
@@ -2627,12 +2644,12 @@
if (!ov511_configure(ov511)) {
ov511->user = 0;
init_MUTEX(&ov511->lock); /* to 1 == available */
- return ov511;
} else {
err("Failed to configure camera");
goto error;
}
+ MOD_DEC_USE_COUNT;
return ov511;
error:
@@ -2641,6 +2658,7 @@
ov511 = NULL;
}
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -2649,7 +2667,7 @@
{
struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
-// video_unregister_device(&ov511->vdev);
+ MOD_INC_USE_COUNT;
/* We don't want people trying to open up the device */
if (!ov511->user)
@@ -2692,10 +2710,12 @@
#endif
/* Free the memory */
- if (!ov511->user) {
+ if (ov511 && !ov511->user) {
kfree(ov511);
ov511 = NULL;
}
+
+ MOD_DEC_USE_COUNT;
}
static struct usb_driver ov511_driver = {
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)