Skip to content

Commit

Permalink
V4L/DVB (8153): Subdriver pac207 added and minor changes.
Browse files Browse the repository at this point in the history
pac207 added.
Check status on mutex lock.
Call back on frame dequeue.
Free the resources on last close only.
Avoid URB and ISOC errors on close.



Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
  • Loading branch information
Hans de Goede authored and Mauro Carvalho Chehab committed Jul 20, 2008
1 parent 63eb954 commit e2997a7
Show file tree
Hide file tree
Showing 4 changed files with 1,018 additions and 62 deletions.
3 changes: 2 additions & 1 deletion drivers/media/video/gspca/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
obj-$(CONFIG_GSPCA) += gspca_main.o gspca_stk014.o
obj-$(CONFIG_GSPCA) += gspca_main.o gspca_pac207.o gspca_stk014.o

gspca_main-objs := gspca.o
gspca_pac207-objs := pac207.o
gspca_stk014-objs := stk014.o
121 changes: 69 additions & 52 deletions drivers/media/video/gspca/gspca.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");

#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 26)
static const char version[] = "0.0.26";
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 0, 30)
static const char version[] = "0.0.30";

static int video_nr = -1;

Expand Down Expand Up @@ -172,8 +172,7 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
{
int i, j;

PDEBUG(D_PACK, "add t:%d l:%d %02x %02x %02x %02x...",
packet_type, len, data[0], data[1], data[2], data[3]);
PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);

/* when start of a new frame, if the current frame buffer
* is not queued, discard the whole frame */
Expand Down Expand Up @@ -346,7 +345,6 @@ static int gspca_kill_transfer(struct gspca_dev *gspca_dev)
unsigned int i;

PDEBUG(D_STREAM, "kill transfer");
gspca_dev->streaming = 0;
for (i = 0; i < NURBS; ++i) {
urb = gspca_dev->pktbuf[i].urb;
if (urb == NULL)
Expand Down Expand Up @@ -501,9 +499,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
struct usb_host_endpoint *ep;
int n, ret;

ret = mutex_lock_interruptible(&gspca_dev->usb_lock);
if (ret < 0)
return ret;
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;

/* set the max alternate setting and loop until urb submit succeeds */
intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
Expand Down Expand Up @@ -531,6 +528,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
if (ret < 0) {
PDEBUG(D_ERR|D_STREAM,
"usb_submit_urb [%d] err %d", n, ret);
gspca_dev->streaming = 0;
gspca_kill_transfer(gspca_dev);
if (ret == -ENOSPC)
break; /* try the previous alt */
Expand All @@ -555,9 +553,9 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
return ret;
}

/* Note both the queue and the usb lock should be hold when calling this */
static void gspca_stream_off(struct gspca_dev *gspca_dev)
{
mutex_lock_interruptible(&gspca_dev->usb_lock);
gspca_dev->streaming = 0;
if (gspca_dev->present) {
gspca_dev->sd_desc->stopN(gspca_dev);
Expand All @@ -571,7 +569,6 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
wake_up_interruptible(&gspca_dev->wq);
PDEBUG(D_ERR|D_STREAM, "stream off no device ??");
}
mutex_unlock(&gspca_dev->usb_lock);
}

static int gspca_set_default_mode(struct gspca_dev *gspca_dev)
Expand Down Expand Up @@ -791,9 +788,7 @@ static int vidioc_try_fmt_cap(struct file *file,
{
int ret;

/* mutex_lock_interruptible(&gspca_dev->queue_lock); */
ret = try_fmt_cap(file, priv, fmt);
/* mutex_unlock(&gspca_dev->queue_lock); */
if (ret < 0)
return ret;
return 0;
Expand All @@ -812,16 +807,23 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
fmt->fmt.pix.width, fmt->fmt.pix.height);
}
#endif
mutex_lock_interruptible(&gspca_dev->queue_lock);
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
ret = try_fmt_cap(file, priv, 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 != 0) {
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->pixfmt = fmt->fmt.pix.pixelformat;
Expand All @@ -840,26 +842,26 @@ static int dev_open(struct inode *inode, struct file *file)

PDEBUG(D_STREAM, "opening");
gspca_dev = (struct gspca_dev *) video_devdata(file);
ret = mutex_lock_interruptible(&gspca_dev->queue_lock);
if (ret < 0)
return ret;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
if (!gspca_dev->present) {
ret = -ENODEV;
goto out;
}

/* if not done yet, initialize the sensor */
if (gspca_dev->users == 0) {
ret = mutex_lock_interruptible(&gspca_dev->usb_lock);
if (ret < 0)
if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
ret = -ERESTARTSYS;
goto out;
}
ret = gspca_dev->sd_desc->open(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
if (ret != 0) {
PDEBUG(D_ERR|D_CONF, "init device failed %d", ret);
goto out;
}
} else if (gspca_dev->users > 8) { /* (arbitrary value) */
} else if (gspca_dev->users > 4) { /* (arbitrary value) */
ret = -EBUSY;
goto out;
}
Expand All @@ -886,21 +888,20 @@ static int dev_close(struct inode *inode, struct file *file)
struct gspca_dev *gspca_dev = file->private_data;

PDEBUG(D_STREAM, "closing");
if (gspca_dev->streaming) {
mutex_lock_interruptible(&gspca_dev->queue_lock);
gspca_stream_off(gspca_dev);
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;
}
mutex_lock_interruptible(&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);
atomic_inc(&gspca_dev->nevent);
wake_up_interruptible(&gspca_dev->wq); /* wake blocked processes */
schedule();
mutex_lock_interruptible(&gspca_dev->queue_lock);

frame_free(gspca_dev);
file->private_data = NULL;
gspca_dev->users--;
mutex_unlock(&gspca_dev->queue_lock);
PDEBUG(D_STREAM, "closed");
return 0;
Expand Down Expand Up @@ -964,7 +965,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
&& ctrl->value > ctrls->qctrl.maximum)
return -ERANGE;
PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
mutex_lock_interruptible(&gspca_dev->usb_lock);
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
ret = ctrls->set(gspca_dev, ctrl->value);
mutex_unlock(&gspca_dev->usb_lock);
return ret;
Expand All @@ -985,7 +987,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
i++, ctrls++) {
if (ctrl->id != ctrls->qctrl.id)
continue;
mutex_lock_interruptible(&gspca_dev->usb_lock);
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
ret = ctrls->get(gspca_dev, &ctrl->value);
mutex_unlock(&gspca_dev->usb_lock);
return ret;
Expand Down Expand Up @@ -1047,9 +1050,8 @@ static int vidioc_reqbufs(struct file *file, void *priv,
frsz = gspca_get_buff_size(gspca_dev);
if (frsz < 0)
return frsz;
ret = mutex_lock_interruptible(&gspca_dev->queue_lock);
if (ret < 0)
return ret;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
ret = frame_alloc(gspca_dev,
rb->count,
(unsigned int) frsz,
Expand Down Expand Up @@ -1087,9 +1089,8 @@ static int vidioc_streamon(struct file *file, void *priv,
PDEBUG(D_STREAM, "stream on");
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
ret = mutex_lock_interruptible(&gspca_dev->queue_lock);
if (ret < 0)
return ret;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
if (!gspca_dev->present) {
ret = -ENODEV;
goto out;
Expand All @@ -1111,6 +1112,7 @@ static int vidioc_streamon(struct file *file, void *priv,
gspca_dev->height);
}
#endif
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
return ret;
Expand All @@ -1125,8 +1127,14 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (gspca_dev->streaming) {
mutex_lock_interruptible(&gspca_dev->queue_lock);
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);
}
return 0;
Expand All @@ -1140,7 +1148,8 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,

if (!gspca_dev->sd_desc->get_jcomp)
return -EINVAL;
mutex_lock_interruptible(&gspca_dev->usb_lock);
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
mutex_unlock(&gspca_dev->usb_lock);
return ret;
Expand All @@ -1152,7 +1161,8 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int ret;

mutex_lock_interruptible(&gspca_dev->usb_lock);
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
if (!gspca_dev->sd_desc->set_jcomp)
return -EINVAL;
ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
Expand All @@ -1177,7 +1187,8 @@ static int vidioc_s_parm(struct file *filp, void *priv,
struct gspca_dev *gspca_dev = priv;
int n;

mutex_lock_interruptible(&gspca_dev->usb_lock);
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;
Expand Down Expand Up @@ -1230,10 +1241,8 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
size = vma->vm_end - vma->vm_start;
PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);

ret = mutex_lock_interruptible(&gspca_dev->queue_lock);
if (ret < 0)
return ret;
/* sanity check disconnect, in use, no memory available */
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
if (!gspca_dev->present) {
ret = -ENODEV;
goto done;
Expand Down Expand Up @@ -1294,6 +1303,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
V4L2_BUF_FLAG_MAPPED;
}
#endif
ret = 0;
done:
mutex_unlock(&gspca_dev->queue_lock);
return ret;
Expand Down Expand Up @@ -1350,6 +1360,8 @@ static int gspca_frame_wait(struct gspca_dev *gspca_dev,
atomic_read(&gspca_dev->nevent) > 0);
if (ret != 0)
return ret;
if (!gspca_dev->streaming || !gspca_dev->present)
return -EIO;
i = gspca_dev->fr_o;
j = gspca_dev->fr_queue[i];
frame = &gspca_dev->frame[j];
Expand All @@ -1364,6 +1376,10 @@ static int gspca_frame_wait(struct gspca_dev *gspca_dev,
gspca_dev->fr_q,
gspca_dev->fr_i,
gspca_dev->fr_o);

if (gspca_dev->sd_desc->dq_callback)
gspca_dev->sd_desc->dq_callback(gspca_dev);

return j;
}

Expand Down Expand Up @@ -1435,9 +1451,9 @@ static int vidioc_qbuf(struct file *file, void *priv,
return -EINVAL;
}

ret = mutex_lock_interruptible(&gspca_dev->queue_lock);
if (ret < 0)
return ret;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;

if (frame->v4l2_buf.flags
& (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)) {
PDEBUG(D_STREAM, "qbuf bad state");
Expand Down Expand Up @@ -1708,11 +1724,12 @@ void gspca_disconnect(struct usb_interface *intf)
if (!gspca_dev)
return;
gspca_dev->present = 0;
mutex_lock_interruptible(&gspca_dev->queue_lock);
mutex_lock_interruptible(&gspca_dev->usb_lock);
mutex_lock(&gspca_dev->queue_lock);
mutex_lock(&gspca_dev->usb_lock);
gspca_dev->streaming = 0;
gspca_kill_transfer(gspca_dev);
mutex_unlock(&gspca_dev->queue_lock);
mutex_unlock(&gspca_dev->usb_lock);
mutex_unlock(&gspca_dev->queue_lock);
while (gspca_dev->users != 0) { /* wait until fully closed */
atomic_inc(&gspca_dev->nevent);
wake_up_interruptible(&gspca_dev->wq); /* wake processes */
Expand Down
17 changes: 8 additions & 9 deletions drivers/media/video/gspca/gspca.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,18 @@ struct ctrl {
/* subdriver description */
struct sd_desc {
/* information */
char *name; /* sub-driver name */
char *name; /* sub-driver name */
/* controls */
struct ctrl *ctrls;
int nctrls;
/* operations */
cam_cf_op config; /* called on probe */
cam_op open; /* called on open */
cam_v_op start; /* called on stream on */
cam_v_op stopN; /* called on stream off - main alt */
cam_v_op stop0; /* called on stream off - alt 0 */
cam_v_op close; /* called on close */
cam_cf_op config; /* called on probe */
cam_op open; /* called on open */
cam_v_op start; /* called on stream on */
cam_v_op stopN; /* called on stream off - main alt */
cam_v_op stop0; /* called on stream off - alt 0 */
cam_v_op close; /* called on close */
cam_v_op dq_callback; /* called when a frame has been dequeued */
cam_pkt_op pkt_scan;
cam_jpg_op get_jcomp;
cam_jpg_op set_jcomp;
Expand Down Expand Up @@ -167,8 +168,6 @@ int gspca_dev_probe(struct usb_interface *intf,
const struct usb_device_id *id,
const struct sd_desc *sd_desc,
int dev_size);
int gspca_dev_init(struct gspca_dev *gspca_dev,
struct usb_interface *intf);
void gspca_disconnect(struct usb_interface *intf);
struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
int packet_type,
Expand Down
Loading

0 comments on commit e2997a7

Please sign in to comment.