X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fgspca%2Fgspca.c;h=0d233c7248750e6d2ee2e336c7eb32ea4603daef;hb=fbb4c6d20f29f2b10daad31cc6238d91f93d70d4;hp=748a87e82e4423e2b9ecfb4c4ac621a339231e4a;hpb=b7d626606201c397319b40721ca558b7e54040d5;p=linux-2.6-omap-h63xx.git diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 748a87e82e4..0d233c72487 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -45,7 +44,7 @@ MODULE_AUTHOR("Jean-Francois Moine "); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 3, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 4, 0) static int video_nr = -1; @@ -150,8 +149,11 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ len = urb->iso_frame_desc[i].actual_length; - if (len == 0) + if (len == 0) { + if (gspca_dev->empty_packet == 0) + gspca_dev->empty_packet = 1; continue; + } st = urb->iso_frame_desc[i].status; if (st) { PDEBUG(D_ERR, @@ -170,7 +172,6 @@ static void fill_frame(struct gspca_dev *gspca_dev, } /* resubmit the URB */ - urb->status = 0; st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); @@ -200,11 +201,18 @@ static void bulk_irq(struct urb *urb { struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; struct gspca_frame *frame; + int st; PDEBUG(D_PACK, "bulk irq"); if (!gspca_dev->streaming) return; - if (urb->status != 0 && urb->status != -ECONNRESET) { + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + urb->status = 0; + break; + default: #ifdef CONFIG_PM if (!gspca_dev->frozen) #endif @@ -223,6 +231,13 @@ static void bulk_irq(struct urb *urb urb->transfer_buffer, urb->actual_length); } + + /* resubmit the URB */ + if (gspca_dev->cam.bulk_nurbs != 0) { + st = usb_submit_urb(urb, GFP_ATOMIC); + if (st < 0) + PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st); + } } /* @@ -520,11 +535,14 @@ static int create_urbs(struct gspca_dev *gspca_dev, nurbs = DEF_NURBS; } else { /* bulk */ npkt = 0; - bsize = gspca_dev->cam. bulk_size; + bsize = gspca_dev->cam.bulk_size; if (bsize == 0) bsize = psize; PDEBUG(D_STREAM, "bulk bsize:%d", bsize); - nurbs = 1; + if (gspca_dev->cam.bulk_nurbs != 0) + nurbs = gspca_dev->cam.bulk_nurbs; + else + nurbs = 1; } gspca_dev->nurbs = nurbs; @@ -597,6 +615,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) if (ret < 0) goto out; + /* clear the bulk endpoint */ + if (gspca_dev->alt == 0) /* if bulk transfer */ + usb_clear_halt(gspca_dev->dev, + usb_rcvintpipe(gspca_dev->dev, + gspca_dev->cam.epaddr)); + /* start the cam */ ret = gspca_dev->sd_desc->start(gspca_dev); if (ret < 0) { @@ -606,8 +630,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->streaming = 1; atomic_set(&gspca_dev->nevent, 0); - /* bulk transfers are started by the subdriver */ - if (gspca_dev->alt == 0) + /* some bulk transfers are started by the subdriver */ + if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0) break; /* submit the URBs */ @@ -727,7 +751,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, if (fmtdesc->index == index) break; /* new format */ index++; - if (index >= sizeof fmt_tb / sizeof fmt_tb[0]) + if (index >= ARRAY_SIZE(fmt_tb)) return -EINVAL; } } @@ -846,11 +870,11 @@ out: return ret; } -static void gspca_delete(struct kref *kref) +static void gspca_release(struct video_device *vfd) { - struct gspca_dev *gspca_dev = container_of(kref, struct gspca_dev, kref); + struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); - PDEBUG(D_STREAM, "device deleted"); + PDEBUG(D_STREAM, "device released"); kfree(gspca_dev->usb_buf); kfree(gspca_dev); @@ -862,7 +886,7 @@ static int dev_open(struct inode *inode, struct file *file) int ret; PDEBUG(D_STREAM, "%s open", current->comm); - gspca_dev = video_drvdata(file); + gspca_dev = (struct gspca_dev *) video_devdata(file); if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; if (!gspca_dev->present) { @@ -883,17 +907,14 @@ static int dev_open(struct inode *inode, struct file *file) gspca_dev->users++; - /* one more user */ - kref_get(&gspca_dev->kref); - file->private_data = gspca_dev; #ifdef GSPCA_DEBUG /* activate the v4l2 debug */ if (gspca_debug & D_V4L2) - gspca_dev->vdev->debug |= V4L2_DEBUG_IOCTL + gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; else - gspca_dev->vdev->debug &= ~(V4L2_DEBUG_IOCTL + gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG); #endif ret = 0; @@ -932,8 +953,6 @@ static int dev_close(struct inode *inode, struct file *file) PDEBUG(D_STREAM, "close done"); - kref_put(&gspca_dev->kref, gspca_delete); - return 0; } @@ -1264,10 +1283,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; int ret; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; if (!gspca_dev->sd_desc->set_jcomp) return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); mutex_unlock(&gspca_dev->usb_lock); return ret; @@ -1802,7 +1821,7 @@ static struct video_device gspca_template = { .name = "gspca main driver", .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, - .release = video_device_release, + .release = gspca_release, .minor = -1, }; @@ -1840,7 +1859,6 @@ int gspca_dev_probe(struct usb_interface *intf, err("couldn't kzalloc gspca struct"); return -ENOMEM; } - kref_init(&gspca_dev->kref); gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { err("out of memory"); @@ -1852,6 +1870,7 @@ int gspca_dev_probe(struct usb_interface *intf, gspca_dev->nbalt = intf->num_altsetting; gspca_dev->sd_desc = sd_desc; gspca_dev->nbufread = 2; + gspca_dev->empty_packet = -1; /* don't check the empty packets */ /* configure the subdriver and initialize the USB device */ ret = gspca_dev->sd_desc->config(gspca_dev, id); @@ -1876,13 +1895,11 @@ int gspca_dev_probe(struct usb_interface *intf, gspca_dev->vdev->parent = &dev->dev; gspca_dev->module = module; gspca_dev->present = 1; - video_set_drvdata(gspca_dev->vdev, gspca_dev); - ret = video_register_device(gspca_dev->vdev, + ret = video_register_device(&gspca_dev->vdev, VFL_TYPE_GRABBER, video_nr); if (ret < 0) { err("video_register_device err %d", ret); - video_device_release(gspca_dev->vdev); goto out; } @@ -1908,13 +1925,9 @@ void gspca_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); -/* We don't want people trying to open up the device */ - video_unregister_device(gspca_dev->vdev); - - gspca_dev->present = 0; - gspca_dev->streaming = 0; - - kref_put(&gspca_dev->kref, gspca_delete); + /* release the device */ + /* (this will call gspca_release() immediatly or on last close) */ + video_unregister_device(&gspca_dev->vdev); PDEBUG(D_PROBE, "disconnect complete"); } @@ -1992,7 +2005,7 @@ int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, desired lumination fast (with the risc of a slight overshoot) */ steps = abs(desired_avg_lum - avg_lum) / deadzone; - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n", + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", avg_lum, desired_avg_lum, steps); for (i = 0; i < steps; i++) {