diff options
Diffstat (limited to 'drivers/media/video/gspca/gspca.c')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 137 |
1 files changed, 76 insertions, 61 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 23d3fb77691..4076f8e5a6f 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 7, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 8, 0) #ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; @@ -74,7 +74,7 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h) #define PDEBUG_MODE(txt, pixfmt, w, h) #endif -/* specific memory types - !! should different from V4L2_MEMORY_xxx */ +/* specific memory types - !! should be different from V4L2_MEMORY_xxx */ #define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */ #define GSPCA_MEMORY_READ 7 @@ -126,7 +126,6 @@ EXPORT_SYMBOL(gspca_get_i_frame); static void fill_frame(struct gspca_dev *gspca_dev, struct urb *urb) { - struct gspca_frame *frame; u8 *data; /* address of data in the iso message */ int i, len, st; cam_pkt_op pkt_scan; @@ -135,21 +134,16 @@ static void fill_frame(struct gspca_dev *gspca_dev, if (urb->status == -ESHUTDOWN) return; /* disconnection */ #ifdef CONFIG_PM - if (!gspca_dev->frozen) + if (gspca_dev->frozen) + return; #endif - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); - return; + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + urb->status = 0; + goto resubmit; } pkt_scan = gspca_dev->sd_desc->pkt_scan; for (i = 0; i < urb->number_of_packets; i++) { - /* check the availability of the frame buffer */ - frame = gspca_get_i_frame(gspca_dev); - if (!frame) { - gspca_dev->last_packet_type = DISCARD_PACKET; - break; - } - /* check the packet status and length */ len = urb->iso_frame_desc[i].actual_length; if (len == 0) { @@ -171,9 +165,10 @@ static void fill_frame(struct gspca_dev *gspca_dev, i, urb->iso_frame_desc[i].offset, len); data = (u8 *) urb->transfer_buffer + urb->iso_frame_desc[i].offset; - pkt_scan(gspca_dev, frame, data, len); + pkt_scan(gspca_dev, data, len); } +resubmit: /* resubmit the URB */ st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) @@ -201,7 +196,6 @@ static void isoc_irq(struct urb *urb) 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"); @@ -212,29 +206,22 @@ static void bulk_irq(struct urb *urb) break; case -ESHUTDOWN: return; /* disconnection */ - case -ECONNRESET: - urb->status = 0; - break; default: #ifdef CONFIG_PM - if (!gspca_dev->frozen) + if (gspca_dev->frozen) + return; #endif - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); - return; + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + urb->status = 0; + goto resubmit; } - /* check the availability of the frame buffer */ - frame = gspca_get_i_frame(gspca_dev); - if (!frame) { - gspca_dev->last_packet_type = DISCARD_PACKET; - } else { - PDEBUG(D_PACK, "packet l:%d", urb->actual_length); - gspca_dev->sd_desc->pkt_scan(gspca_dev, - frame, - urb->transfer_buffer, - urb->actual_length); - } + PDEBUG(D_PACK, "packet l:%d", urb->actual_length); + gspca_dev->sd_desc->pkt_scan(gspca_dev, + urb->transfer_buffer, + urb->actual_length); +resubmit: /* resubmit the URB */ if (gspca_dev->cam.bulk_nurbs != 0) { st = usb_submit_urb(urb, GFP_ATOMIC); @@ -255,24 +242,27 @@ static void bulk_irq(struct urb *urb) * DISCARD_PACKET invalidates the whole frame. * On LAST_PACKET, a new frame is returned. */ -struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, - enum gspca_packet_type packet_type, - struct gspca_frame *frame, - const __u8 *data, - int len) +void gspca_frame_add(struct gspca_dev *gspca_dev, + enum gspca_packet_type packet_type, + const u8 *data, + int len) { + struct gspca_frame *frame; int i, j; PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len); + /* check the availability of the frame buffer */ + frame = gspca_dev->cur_frame; + if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) + != V4L2_BUF_FLAG_QUEUED) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } + /* when start of a new frame, if the current frame buffer * is not queued, discard the whole frame */ if (packet_type == FIRST_PACKET) { - if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) - != V4L2_BUF_FLAG_QUEUED) { - gspca_dev->last_packet_type = DISCARD_PACKET; - return frame; - } frame->data_end = frame->data; jiffies_to_timeval(get_jiffies_64(), &frame->v4l2_buf.timestamp); @@ -280,7 +270,7 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, } else if (gspca_dev->last_packet_type == DISCARD_PACKET) { if (packet_type == LAST_PACKET) gspca_dev->last_packet_type = packet_type; - return frame; + return; } /* append the packet to the frame buffer */ @@ -312,9 +302,9 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, i, gspca_dev->fr_o); j = gspca_dev->fr_queue[i]; - frame = &gspca_dev->frame[j]; + gspca_dev->cur_frame = &gspca_dev->frame[j]; } - return frame; + return; } EXPORT_SYMBOL(gspca_frame_add); @@ -395,6 +385,7 @@ static int frame_alloc(struct gspca_dev *gspca_dev, frame->v4l2_buf.m.offset = i * frsz; } gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0; + gspca_dev->cur_frame = &gspca_dev->frame[0]; gspca_dev->last_packet_type = DISCARD_PACKET; gspca_dev->sequence = 0; return 0; @@ -475,10 +466,18 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_ISOC; i = gspca_dev->alt; /* previous alt setting */ - while (--i >= 0) { - ep = alt_xfer(&intf->altsetting[i], xfer); - if (ep) - break; + if (gspca_dev->cam.reverse_alts) { + while (++i < gspca_dev->nbalt) { + ep = alt_xfer(&intf->altsetting[i], xfer); + if (ep) + break; + } + } else { + while (--i >= 0) { + ep = alt_xfer(&intf->altsetting[i], xfer); + if (ep) + break; + } } if (ep == NULL) { err("no transfer endpoint found"); @@ -599,7 +598,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* set the higher alternate setting and * loop until urb submit succeeds */ - gspca_dev->alt = gspca_dev->nbalt; + if (gspca_dev->cam.reverse_alts) + gspca_dev->alt = 0; + else + gspca_dev->alt = gspca_dev->nbalt; + if (gspca_dev->sd_desc->isoc_init) { ret = gspca_dev->sd_desc->isoc_init(gspca_dev); if (ret < 0) @@ -641,15 +644,19 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) } if (ret >= 0) break; - PDEBUG(D_ERR|D_STREAM, - "usb_submit_urb alt %d err %d", gspca_dev->alt, ret); gspca_dev->streaming = 0; destroy_urbs(gspca_dev); - if (ret != -ENOSPC) + if (ret != -ENOSPC) { + PDEBUG(D_ERR|D_STREAM, + "usb_submit_urb alt %d err %d", + gspca_dev->alt, ret); goto out; + } /* the bandwidth is not wide enough * negociate or try a lower alternate setting */ + PDEBUG(D_ERR|D_STREAM, + "bandwidth not wide enough - trying again"); msleep(20); /* wait for kill complete */ if (gspca_dev->sd_desc->isoc_nego) { ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); @@ -980,7 +987,7 @@ static void gspca_release(struct video_device *vfd) { struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); - PDEBUG(D_STREAM, "device released"); + PDEBUG(D_PROBE, "/dev/video%d released", gspca_dev->vdev.num); kfree(gspca_dev->usb_buf); kfree(gspca_dev); @@ -991,7 +998,7 @@ static int dev_open(struct file *file) struct gspca_dev *gspca_dev; int ret; - PDEBUG(D_STREAM, "%s open", current->comm); + PDEBUG(D_STREAM, "[%s] open", current->comm); gspca_dev = (struct gspca_dev *) video_devdata(file); if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; @@ -1037,7 +1044,7 @@ static int dev_close(struct file *file) { struct gspca_dev *gspca_dev = file->private_data; - PDEBUG(D_STREAM, "%s close", current->comm); + PDEBUG(D_STREAM, "[%s] close", current->comm); if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; gspca_dev->users--; @@ -1138,10 +1145,13 @@ static int vidioc_queryctrl(struct file *file, void *priv, } } else { ctrls = get_ctrl(gspca_dev, id); + i = ctrls - gspca_dev->sd_desc->ctrls; } if (ctrls == NULL) return -EINVAL; memcpy(q_ctrl, ctrls, sizeof *q_ctrl); + if (gspca_dev->ctrl_inac & (1 << i)) + q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; } @@ -1603,7 +1613,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) size -= PAGE_SIZE; } - vma->vm_ops = &gspca_vm_ops; + vma->vm_ops = (struct vm_operations_struct *) &gspca_vm_ops; vma->vm_private_data = frame; gspca_vm_open(vma); ret = 0; @@ -2001,11 +2011,15 @@ int gspca_dev_probe(struct usb_interface *intf, PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct); /* we don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) + if (dev->descriptor.bNumConfigurations != 1) { + PDEBUG(D_ERR, "Too many config"); return -ENODEV; + } interface = &intf->cur_altsetting->desc; - if (interface->bInterfaceNumber > 0) + if (interface->bInterfaceNumber > 0) { + PDEBUG(D_ERR, "intf != 0"); return -ENODEV; + } /* create the device */ if (dev_size < sizeof *gspca_dev) @@ -2059,7 +2073,7 @@ int gspca_dev_probe(struct usb_interface *intf, } usb_set_intfdata(intf, gspca_dev); - PDEBUG(D_PROBE, "probe ok"); + PDEBUG(D_PROBE, "/dev/video%d created", gspca_dev->vdev.num); return 0; out: kfree(gspca_dev->usb_buf); @@ -2078,6 +2092,7 @@ void gspca_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + PDEBUG(D_PROBE, "/dev/video%d disconnect", gspca_dev->vdev.num); mutex_lock(&gspca_dev->usb_lock); gspca_dev->present = 0; @@ -2096,7 +2111,7 @@ void gspca_disconnect(struct usb_interface *intf) /* (this will call gspca_release() immediatly or on last close) */ video_unregister_device(&gspca_dev->vdev); - PDEBUG(D_PROBE, "disconnect complete"); +/* PDEBUG(D_PROBE, "disconnect complete"); */ } EXPORT_SYMBOL(gspca_disconnect); |