MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 30)
-static const char version[] = "0.0.30";
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 1)
+static const char version[] = "0.1.1";
static int video_nr = -1;
PDEBUG(D_STREAM, "kill transfer");
for (i = 0; i < NURBS; ++i) {
- urb = gspca_dev->pktbuf[i].urb;
+ urb = gspca_dev->urb[i];
if (urb == NULL)
continue;
- gspca_dev->pktbuf[i].urb = NULL;
+ gspca_dev->urb[i] = NULL;
usb_kill_urb(urb);
-
- /* urb->transfer_buffer_length is not touched by USB core,
- * so we can use it here as the buffer length */
- if (gspca_dev->pktbuf[i].data) {
+ if (urb->transfer_buffer != 0)
usb_buffer_free(gspca_dev->dev,
urb->transfer_buffer_length,
- gspca_dev->pktbuf[i].data,
+ urb->transfer_buffer,
urb->transfer_dma);
- gspca_dev->pktbuf[i].data = NULL;
- }
usb_free_urb(urb);
}
return 0;
err("usb_alloc_urb failed");
return -ENOMEM;
}
- gspca_dev->pktbuf[n].data = usb_buffer_alloc(gspca_dev->dev,
+ urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev,
bsize,
GFP_KERNEL,
&urb->transfer_dma);
- if (gspca_dev->pktbuf[n].data == NULL) {
+ if (urb->transfer_buffer == NULL) {
usb_free_urb(urb);
gspca_kill_transfer(gspca_dev);
err("usb_buffer_urb failed");
return -ENOMEM;
}
- gspca_dev->pktbuf[n].urb = urb;
+ gspca_dev->urb[n] = urb;
urb->dev = gspca_dev->dev;
urb->context = gspca_dev;
urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
ep->desc.bEndpointAddress);
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_flags = URB_ISO_ASAP
+ | URB_NO_TRANSFER_DMA_MAP;
urb->interval = ep->desc.bInterval;
- urb->transfer_buffer = gspca_dev->pktbuf[n].data;
urb->complete = isoc_irq;
urb->number_of_packets = npkt;
urb->transfer_buffer_length = bsize;
/* submit the URBs */
for (n = 0; n < NURBS; n++) {
- ret = usb_submit_urb(gspca_dev->pktbuf[n].urb,
- GFP_KERNEL);
+ ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
if (ret < 0) {
PDEBUG(D_ERR|D_STREAM,
"usb_submit_urb [%d] err %d", n, ret);
return 0;
}
-static int try_fmt_cap(struct file *file,
- void *priv,
+static int try_fmt_cap(struct gspca_dev *gspca_dev,
struct v4l2_format *fmt)
{
- struct gspca_dev *gspca_dev = priv;
int w, h, mode, mode2, frsz;
- w = (int) fmt->fmt.pix.width;
- h = (int) fmt->fmt.pix.height;
+ w = fmt->fmt.pix.width;
+ h = fmt->fmt.pix.height;
#ifdef GSPCA_DEBUG
if (gspca_debug & D_CONF)
PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
void *priv,
struct v4l2_format *fmt)
{
+ struct gspca_dev *gspca_dev = priv;
int ret;
- ret = try_fmt_cap(file, priv, fmt);
+ ret = try_fmt_cap(gspca_dev, fmt);
if (ret < 0)
return ret;
return 0;
#endif
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
- ret = try_fmt_cap(file, priv, fmt);
+ ret = try_fmt_cap(gspca_dev, fmt);
if (ret < 0)
goto out;
if (ret == gspca_dev->curr_mode)
goto out; /* same mode */
was_streaming = gspca_dev->streaming;
- if (was_streaming != 0) {
+ if (was_streaming) {
+ if (gspca_dev->capt_file != 0
+ && gspca_dev->capt_file != file) {
+ ret = -EBUSY;
+ goto out;
+ }
if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
ret = -ERESTARTSYS;
goto out;
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
- gspca_dev->width = (int) fmt->fmt.pix.width;
- gspca_dev->height = (int) fmt->fmt.pix.height;
+ gspca_dev->width = fmt->fmt.pix.width;
+ gspca_dev->height = fmt->fmt.pix.height;
gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
gspca_dev->curr_mode = ret;
if (was_streaming)
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
gspca_dev->users--;
- if (gspca_dev->users > 0) {
- mutex_unlock(&gspca_dev->queue_lock);
- return 0;
- }
- if (gspca_dev->streaming)
- gspca_stream_off(gspca_dev);
- gspca_dev->sd_desc->close(gspca_dev);
-
- frame_free(gspca_dev);
- file->private_data = NULL;
+ /* if the file did capture, free the streaming resources */
+ if (gspca_dev->capt_file == file) {
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->streaming)
+ gspca_stream_off(gspca_dev);
+ gspca_dev->sd_desc->close(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ frame_free(gspca_dev);
+ file->private_data = NULL;
+ gspca_dev->capt_file = 0;
+ }
mutex_unlock(&gspca_dev->queue_lock);
PDEBUG(D_STREAM, "closed");
return 0;
return frsz;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
+ if (gspca_dev->capt_file != 0) { /* only one file may do capture */
+ ret = -EBUSY;
+ goto out;
+ }
ret = frame_alloc(gspca_dev,
rb->count,
(unsigned int) frsz,
rb->memory);
- if (ret == 0)
+ if (ret == 0) {
rb->count = gspca_dev->nframes;
+ gspca_dev->capt_file = file;
+ }
+out:
mutex_unlock(&gspca_dev->queue_lock);
PDEBUG(D_STREAM, "reqbufs st:%d c:%d", ret, rb->count);
return ret;
ret = -EINVAL;
goto out;
}
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
+ }
if (!gspca_dev->streaming) {
ret = gspca_init_transfer(gspca_dev);
if (ret < 0)
enum v4l2_buf_type buf_type)
{
struct gspca_dev *gspca_dev = priv;
+ int ret;
PDEBUG(D_STREAM, "stream off");
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (gspca_dev->streaming) {
- if (mutex_lock_interruptible(&gspca_dev->queue_lock))
- return -ERESTARTSYS;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
- mutex_unlock(&gspca_dev->queue_lock);
- return -ERESTARTSYS;
- }
- gspca_stream_off(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
- mutex_unlock(&gspca_dev->queue_lock);
+ if (!gspca_dev->streaming)
+ return 0;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
}
- return 0;
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out2;
+ }
+ gspca_stream_off(gspca_dev);
+ ret = 0;
+out2:
+ mutex_unlock(&gspca_dev->usb_lock);
+out:
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
}
static int vidioc_g_jpegcomp(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int n;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
n = parm->parm.capture.readbuffers;
if (n == 0 || n > GSPCA_MAX_FRAMES)
parm->parm.capture.readbuffers = gspca_dev->nbufread;
else
gspca_dev->nbufread = n;
- mutex_unlock(&gspca_dev->usb_lock);
return 0;
}
return -ERESTARTSYS;
if (!gspca_dev->present) {
ret = -ENODEV;
- goto done;
+ goto out;
+ }
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
}
for (i = 0; i < gspca_dev->nframes; ++i) {
if (frame == 0) {
PDEBUG(D_STREAM, "mmap no frame buffer found");
ret = -EINVAL;
- goto done;
+ goto out;
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
if (i == 0 && size == frame->v4l2_buf.length * gspca_dev->nframes)
if (size != frame->v4l2_buf.length) {
PDEBUG(D_STREAM, "mmap bad size");
ret = -EINVAL;
- goto done;
+ goto out;
}
/*
page = vmalloc_to_page((void *) addr);
ret = vm_insert_page(vma, start, page);
if (ret < 0)
- goto done;
+ goto out;
start += PAGE_SIZE;
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
#endif
ret = 0;
-done:
+out:
mutex_unlock(&gspca_dev->queue_lock);
return ret;
}
/* wait till a frame is ready */
for (;;) {
- ret = wait_event_interruptible(gspca_dev->wq,
- atomic_read(&gspca_dev->nevent) > 0);
- if (ret != 0)
- return ret;
+ ret = wait_event_interruptible_timeout(gspca_dev->wq,
+ atomic_read(&gspca_dev->nevent) > 0,
+ msecs_to_jiffies(3000));
+ if (ret <= 0) {
+ if (ret < 0)
+ return ret;
+ return -EIO;
+ }
if (!gspca_dev->streaming || !gspca_dev->present)
return -EIO;
i = gspca_dev->fr_o;
return -EINVAL;
if (!gspca_dev->streaming)
return -EINVAL;
+ if (gspca_dev->capt_file != file) {
+ ret = -EINVAL;
+ goto out;
+ }
/* only one read */
if (mutex_lock_interruptible(&gspca_dev->read_lock))
ret = gspca_frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
if (ret < 0)
- goto done;
+ goto out;
i = ret; /* frame index */
frame = &gspca_dev->frame[i];
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
PDEBUG(D_FRAM, "dqbuf %d", i);
ret = 0;
-done:
+out:
mutex_unlock(&gspca_dev->read_lock);
return ret;
}
PDEBUG(D_STREAM, "qbuf bad memory type");
return -EINVAL;
}
+ if (gspca_dev->capt_file != file)
+ return -EINVAL;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
return ret;
}
}
- }
+ } else if (gspca_dev->capt_file != file)
+ return -EINVAL;
+
if (!gspca_dev->streaming) {
ret = vidioc_streamon(file, gspca_dev,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
*/
void gspca_disconnect(struct usb_interface *intf)
{
- struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
if (!gspca_dev)
return;