Commit 8130eca2 authored by Mark W. McClelland's avatar Mark W. McClelland Committed by Greg Kroah-Hartman

[PATCH] USB: ov511 bugfixes/cleanup

This patch updates the 2.5 ov511 driver to version 1.64. This fixes some
longstanding bugs and cleans the code up a bit.

Changes:
 - Eliminate remaining uses of sleep_on()
 - Remove unnecessary (and racy) calls to waitqueue_active()
 - Fix a memory leak in the open() error path
 - Remove some redundant and unused variables
 - Documentation fixes
parent d71942e8
/* /*
* OmniVision OV511 Camera-to-USB Bridge Driver * OmniVision OV511 Camera-to-USB Bridge Driver
* *
* Copyright (c) 1999-2002 Mark W. McClelland * Copyright (c) 1999-2003 Mark W. McClelland
* Original decompression code Copyright 1998-2000 OmniVision Technologies * Original decompression code Copyright 1998-2000 OmniVision Technologies
* Many improvements by Bret Wallach <bwallac1@san.rr.com> * Many improvements by Bret Wallach <bwallac1@san.rr.com>
* Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.63 for Linux 2.5" #define DRIVER_VERSION "v1.64 for Linux 2.5"
#define EMAIL "mark@alpha.dyndns.org" #define EMAIL "mark@alpha.dyndns.org"
#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \ #define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
...@@ -137,7 +137,7 @@ MODULE_PARM_DESC(snapshot, "Enable snapshot mode"); ...@@ -137,7 +137,7 @@ MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
MODULE_PARM(cams, "i"); MODULE_PARM(cams, "i");
MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
MODULE_PARM(compress, "i"); MODULE_PARM(compress, "i");
MODULE_PARM_DESC(compress, "Turn on compression (not reliable yet)"); MODULE_PARM_DESC(compress, "Turn on compression");
MODULE_PARM(testpat, "i"); MODULE_PARM(testpat, "i");
MODULE_PARM_DESC(testpat, MODULE_PARM_DESC(testpat,
"Replace image with vertical bar testpattern (only partially working)"); "Replace image with vertical bar testpattern (only partially working)");
...@@ -1349,6 +1349,13 @@ ov51x_restart(struct usb_ov511 *ov) ...@@ -1349,6 +1349,13 @@ ov51x_restart(struct usb_ov511 *ov)
return 0; return 0;
} }
/* Sleeps until no frames are active. Returns !0 if got signal */
static int
ov51x_wait_frames_inactive(struct usb_ov511 *ov)
{
return wait_event_interruptible(ov->wq, ov->curframe < 0);
}
/* Resets the hardware snapshot button */ /* Resets the hardware snapshot button */
static void static void
ov51x_clear_snapshot(struct usb_ov511 *ov) ov51x_clear_snapshot(struct usb_ov511 *ov)
...@@ -2121,7 +2128,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) ...@@ -2121,7 +2128,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
return 0; return 0;
} }
#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ #endif /* CONFIG_VIDEO_PROC_FS */
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
static void static void
...@@ -2486,8 +2493,6 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, ...@@ -2486,8 +2493,6 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
/******** Clock programming ********/ /******** Clock programming ********/
// FIXME: Test this with OV6630
/* The OV6620 needs special handling. This prevents the /* The OV6620 needs special handling. This prevents the
* severe banding that normally occurs */ * severe banding that normally occurs */
if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
...@@ -2995,6 +3000,7 @@ ov51x_set_default_params(struct usb_ov511 *ov) ...@@ -2995,6 +3000,7 @@ ov51x_set_default_params(struct usb_ov511 *ov)
ov->frame[i].format = force_palette; ov->frame[i].format = force_palette;
else else
ov->frame[i].format = VIDEO_PALETTE_YUV420; ov->frame[i].format = VIDEO_PALETTE_YUV420;
ov->frame[i].depth = get_depth(ov->frame[i].format); ov->frame[i].depth = get_depth(ov->frame[i].format);
} }
...@@ -3577,12 +3583,8 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n) ...@@ -3577,12 +3583,8 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
if (frame->scanstate == STATE_LINES) { if (frame->scanstate == STATE_LINES) {
int nextf; int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right? frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
/* If next frame is ready or grabbing, /* If next frame is ready or grabbing,
* point to it */ * point to it */
...@@ -3747,12 +3749,8 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n) ...@@ -3747,12 +3749,8 @@ ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
if (frame->scanstate == STATE_LINES) { if (frame->scanstate == STATE_LINES) {
int nextf; int nextf;
frame->grabstate = FRAME_DONE; // FIXME: Is this right? frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
if (waitqueue_active(&frame->wq)) {
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
}
/* If next frame is ready or grabbing, /* If next frame is ready or grabbing,
* point to it */ * point to it */
...@@ -4228,7 +4226,7 @@ ov51x_alloc(struct usb_ov511 *ov) ...@@ -4228,7 +4226,7 @@ ov51x_alloc(struct usb_ov511 *ov)
} }
static void static void
ov51x_dealloc(struct usb_ov511 *ov, int now) ov51x_dealloc(struct usb_ov511 *ov)
{ {
PDEBUG(4, "entered"); PDEBUG(4, "entered");
down(&ov->buf_lock); down(&ov->buf_lock);
...@@ -4258,10 +4256,6 @@ ov51x_v4l1_open(struct inode *inode, struct file *file) ...@@ -4258,10 +4256,6 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
if (ov->user) if (ov->user)
goto out; goto out;
err = ov51x_alloc(ov);
if (err < 0)
goto out;
ov->sub_flag = 0; ov->sub_flag = 0;
/* In case app doesn't set them... */ /* In case app doesn't set them... */
...@@ -4283,9 +4277,13 @@ ov51x_v4l1_open(struct inode *inode, struct file *file) ...@@ -4283,9 +4277,13 @@ ov51x_v4l1_open(struct inode *inode, struct file *file)
goto out; goto out;
} }
err = ov51x_alloc(ov);
if (err < 0)
goto out;
err = ov51x_init_isoc(ov); err = ov51x_init_isoc(ov);
if (err) { if (err) {
ov51x_dealloc(ov, 0); ov51x_dealloc(ov);
goto out; goto out;
} }
...@@ -4319,7 +4317,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) ...@@ -4319,7 +4317,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
ov51x_led_control(ov, 0); ov51x_led_control(ov, 0);
if (ov->dev) if (ov->dev)
ov51x_dealloc(ov, 0); ov51x_dealloc(ov);
up(&ov->lock); up(&ov->lock);
...@@ -4331,7 +4329,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) ...@@ -4331,7 +4329,7 @@ ov51x_v4l1_close(struct inode *inode, struct file *file)
ov->cbuf = NULL; ov->cbuf = NULL;
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
ov51x_dealloc(ov, 1); ov51x_dealloc(ov);
kfree(ov); kfree(ov);
ov = NULL; ov = NULL;
} }
...@@ -4449,7 +4447,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4449,7 +4447,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCSPICT: case VIDIOCSPICT:
{ {
struct video_picture *p = arg; struct video_picture *p = arg;
int i; int i, rc;
PDEBUG(4, "VIDIOCSPICT"); PDEBUG(4, "VIDIOCSPICT");
...@@ -4469,10 +4467,9 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4469,10 +4467,9 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
if (p->palette != ov->frame[0].format) { if (p->palette != ov->frame[0].format) {
PDEBUG(4, "Detected format change"); PDEBUG(4, "Detected format change");
/* If we're collecting previous frame wait rc = ov51x_wait_frames_inactive(ov);
before changing modes */ if (rc)
interruptible_sleep_on(&ov->wq); return rc;
if (signal_pending(current)) return -EINTR;
mode_init_regs(ov, ov->frame[0].width, mode_init_regs(ov, ov->frame[0].width,
ov->frame[0].height, p->palette, ov->sub_flag); ov->frame[0].height, p->palette, ov->sub_flag);
...@@ -4530,7 +4527,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4530,7 +4527,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCSWIN: case VIDIOCSWIN:
{ {
struct video_window *vw = arg; struct video_window *vw = arg;
int i, result; int i, rc;
PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height); PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
...@@ -4545,15 +4542,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4545,15 +4542,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return -EINVAL; return -EINVAL;
#endif #endif
/* If we're collecting previous frame wait rc = ov51x_wait_frames_inactive(ov);
before changing modes */ if (rc)
interruptible_sleep_on(&ov->wq); return rc;
if (signal_pending(current)) return -EINTR;
result = mode_init_regs(ov, vw->width, vw->height, rc = mode_init_regs(ov, vw->width, vw->height,
ov->frame[0].format, ov->sub_flag); ov->frame[0].format, ov->sub_flag);
if (result < 0) if (rc < 0)
return result; return rc;
for (i = 0; i < OV511_NUMFRAMES; i++) { for (i = 0; i < OV511_NUMFRAMES; i++) {
ov->frame[i].width = vw->width; ov->frame[i].width = vw->width;
...@@ -4600,7 +4596,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4600,7 +4596,7 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
case VIDIOCMCAPTURE: case VIDIOCMCAPTURE:
{ {
struct video_mmap *vm = arg; struct video_mmap *vm = arg;
int ret, depth; int rc, depth;
unsigned int f = vm->frame; unsigned int f = vm->frame;
PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width, PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
...@@ -4642,14 +4638,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4642,14 +4638,14 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
(ov->frame[f].depth != depth)) { (ov->frame[f].depth != depth)) {
PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters"); PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
/* If we're collecting previous frame wait rc = ov51x_wait_frames_inactive(ov);
before changing modes */ if (rc)
interruptible_sleep_on(&ov->wq); return rc;
if (signal_pending(current)) return -EINTR;
ret = mode_init_regs(ov, vm->width, vm->height, rc = mode_init_regs(ov, vm->width, vm->height,
vm->format, ov->sub_flag); vm->format, ov->sub_flag);
#if 0 #if 0
if (ret < 0) { if (rc < 0) {
PDEBUG(1, "Got error while initializing regs "); PDEBUG(1, "Got error while initializing regs ");
return ret; return ret;
} }
...@@ -4702,18 +4698,15 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file, ...@@ -4702,18 +4698,15 @@ ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
return rc; return rc;
if (frame->grabstate == FRAME_ERROR) { if (frame->grabstate == FRAME_ERROR) {
int ret; if ((rc = ov51x_new_frame(ov, fnum)) < 0)
return rc;
if ((ret = ov51x_new_frame(ov, fnum)) < 0)
return ret;
goto redo; goto redo;
} }
/* Fall through */ /* Fall through */
case FRAME_DONE: case FRAME_DONE:
if (ov->snap_enabled && !frame->snapshot) { if (ov->snap_enabled && !frame->snapshot) {
int ret; if ((rc = ov51x_new_frame(ov, fnum)) < 0)
if ((ret = ov51x_new_frame(ov, fnum)) < 0) return rc;
return ret;
goto redo; goto redo;
} }
...@@ -6089,7 +6082,6 @@ ov518_configure(struct usb_ov511 *ov) ...@@ -6089,7 +6082,6 @@ ov518_configure(struct usb_ov511 *ov)
return -EBUSY; return -EBUSY;
} }
/**************************************************************************** /****************************************************************************
* *
* USB routines * USB routines
...@@ -6097,11 +6089,10 @@ ov518_configure(struct usb_ov511 *ov) ...@@ -6097,11 +6089,10 @@ ov518_configure(struct usb_ov511 *ov)
***************************************************************************/ ***************************************************************************/
static int static int
ov51x_probe(struct usb_interface *intf, ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = interface_to_usbdev(intf);
struct usb_interface_descriptor *interface; struct usb_interface_descriptor *idesc;
struct usb_ov511 *ov; struct usb_ov511 *ov;
int i; int i;
int registered = 0; int registered = 0;
...@@ -6112,12 +6103,11 @@ ov51x_probe(struct usb_interface *intf, ...@@ -6112,12 +6103,11 @@ ov51x_probe(struct usb_interface *intf,
if (dev->descriptor.bNumConfigurations != 1) if (dev->descriptor.bNumConfigurations != 1)
return -ENODEV; return -ENODEV;
interface = &intf->altsetting[0].desc; idesc = &intf->altsetting[0].desc;
/* Checking vendor/product should be enough, but what the hell */ if (idesc->bInterfaceClass != 0xFF)
if (interface->bInterfaceClass != 0xFF)
return -ENODEV; return -ENODEV;
if (interface->bInterfaceSubClass != 0x00) if (idesc->bInterfaceSubClass != 0x00)
return -ENODEV; return -ENODEV;
if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) { if ((ov = kmalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
...@@ -6128,7 +6118,7 @@ ov51x_probe(struct usb_interface *intf, ...@@ -6128,7 +6118,7 @@ ov51x_probe(struct usb_interface *intf,
memset(ov, 0, sizeof(*ov)); memset(ov, 0, sizeof(*ov));
ov->dev = dev; ov->dev = dev;
ov->iface = interface->bInterfaceNumber; ov->iface = idesc->bInterfaceNumber;
ov->led_policy = led; ov->led_policy = led;
ov->compress = compress; ov->compress = compress;
ov->lightfreq = lightfreq; ov->lightfreq = lightfreq;
...@@ -6272,7 +6262,7 @@ ov51x_probe(struct usb_interface *intf, ...@@ -6272,7 +6262,7 @@ ov51x_probe(struct usb_interface *intf,
error_out: error_out:
err("Camera initialization failed"); err("Camera initialization failed");
return -ENOMEM; return -EIO;
} }
static void static void
...@@ -6284,6 +6274,7 @@ ov51x_disconnect(struct usb_interface *intf) ...@@ -6284,6 +6274,7 @@ ov51x_disconnect(struct usb_interface *intf)
PDEBUG(3, ""); PDEBUG(3, "");
usb_set_intfdata (intf, NULL); usb_set_intfdata (intf, NULL);
if (!ov) if (!ov)
return; return;
...@@ -6298,10 +6289,9 @@ ov51x_disconnect(struct usb_interface *intf) ...@@ -6298,10 +6289,9 @@ ov51x_disconnect(struct usb_interface *intf)
/* This will cause the process to request another frame */ /* This will cause the process to request another frame */
for (n = 0; n < OV511_NUMFRAMES; n++) for (n = 0; n < OV511_NUMFRAMES; n++)
if (waitqueue_active(&ov->frame[n].wq)) wake_up_interruptible(&ov->frame[n].wq);
wake_up_interruptible(&ov->frame[n].wq);
if (waitqueue_active(&ov->wq)) wake_up_interruptible(&ov->wq);
wake_up_interruptible(&ov->wq);
ov->streaming = 0; ov->streaming = 0;
ov51x_unlink_isoc(ov); ov51x_unlink_isoc(ov);
...@@ -6317,7 +6307,7 @@ ov51x_disconnect(struct usb_interface *intf) ...@@ -6317,7 +6307,7 @@ ov51x_disconnect(struct usb_interface *intf)
ov->cbuf = NULL; ov->cbuf = NULL;
up(&ov->cbuf_lock); up(&ov->cbuf_lock);
ov51x_dealloc(ov, 1); ov51x_dealloc(ov);
kfree(ov); kfree(ov);
ov = NULL; ov = NULL;
} }
...@@ -6333,7 +6323,6 @@ static struct usb_driver ov511_driver = { ...@@ -6333,7 +6323,6 @@ static struct usb_driver ov511_driver = {
.disconnect = ov51x_disconnect .disconnect = ov51x_disconnect
}; };
/**************************************************************************** /****************************************************************************
* *
* Module routines * Module routines
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment