Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2997a72 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8153): Subdriver pac207 added and minor changes.



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: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 63eb9546
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
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_main-objs := gspca.o
gspca_pac207-objs := pac207.o
gspca_stk014-objs := stk014.o
gspca_stk014-objs := stk014.o
+69 −52
Original line number Original line Diff line number Diff line
@@ -39,8 +39,8 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");


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


static int video_nr = -1;
static int video_nr = -1;


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


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


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


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


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


	/* set the max alternate setting and loop until urb submit succeeds */
	/* set the max alternate setting and loop until urb submit succeeds */
	intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
	intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
@@ -531,6 +528,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
			if (ret < 0) {
			if (ret < 0) {
				PDEBUG(D_ERR|D_STREAM,
				PDEBUG(D_ERR|D_STREAM,
					"usb_submit_urb [%d] err %d", n, ret);
					"usb_submit_urb [%d] err %d", n, ret);
				gspca_dev->streaming = 0;
				gspca_kill_transfer(gspca_dev);
				gspca_kill_transfer(gspca_dev);
				if (ret == -ENOSPC)
				if (ret == -ENOSPC)
					break;	/* try the previous alt */
					break;	/* try the previous alt */
@@ -555,9 +553,9 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
	return ret;
	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)
static void gspca_stream_off(struct gspca_dev *gspca_dev)
{
{
	mutex_lock_interruptible(&gspca_dev->usb_lock);
	gspca_dev->streaming = 0;
	gspca_dev->streaming = 0;
	if (gspca_dev->present) {
	if (gspca_dev->present) {
		gspca_dev->sd_desc->stopN(gspca_dev);
		gspca_dev->sd_desc->stopN(gspca_dev);
@@ -571,7 +569,6 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
		wake_up_interruptible(&gspca_dev->wq);
		wake_up_interruptible(&gspca_dev->wq);
		PDEBUG(D_ERR|D_STREAM, "stream off no device ??");
		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)
static int gspca_set_default_mode(struct gspca_dev *gspca_dev)
@@ -791,9 +788,7 @@ static int vidioc_try_fmt_cap(struct file *file,
{
{
	int ret;
	int ret;


/*	mutex_lock_interruptible(&gspca_dev->queue_lock); */
	ret = try_fmt_cap(file, priv, fmt);
	ret = try_fmt_cap(file, priv, fmt);
/*	mutex_unlock(&gspca_dev->queue_lock); */
	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;
	return 0;
	return 0;
@@ -812,7 +807,8 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
			fmt->fmt.pix.width, fmt->fmt.pix.height);
			fmt->fmt.pix.width, fmt->fmt.pix.height);
	}
	}
#endif
#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);
	ret = try_fmt_cap(file, priv, fmt);
	if (ret < 0)
	if (ret < 0)
		goto out;
		goto out;
@@ -820,8 +816,14 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
	if (ret == gspca_dev->curr_mode)
	if (ret == gspca_dev->curr_mode)
		goto out;			/* same mode */
		goto out;			/* same mode */
	was_streaming = gspca_dev->streaming;
	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);
		gspca_stream_off(gspca_dev);
		mutex_unlock(&gspca_dev->usb_lock);
	}
	gspca_dev->width = (int) fmt->fmt.pix.width;
	gspca_dev->width = (int) fmt->fmt.pix.width;
	gspca_dev->height = (int) fmt->fmt.pix.height;
	gspca_dev->height = (int) fmt->fmt.pix.height;
	gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
	gspca_dev->pixfmt = fmt->fmt.pix.pixelformat;
@@ -840,9 +842,8 @@ static int dev_open(struct inode *inode, struct file *file)


	PDEBUG(D_STREAM, "opening");
	PDEBUG(D_STREAM, "opening");
	gspca_dev = (struct gspca_dev *) video_devdata(file);
	gspca_dev = (struct gspca_dev *) video_devdata(file);
	ret = mutex_lock_interruptible(&gspca_dev->queue_lock);
	if (mutex_lock_interruptible(&gspca_dev->queue_lock))
	if (ret < 0)
		return -ERESTARTSYS;
		return ret;
	if (!gspca_dev->present) {
	if (!gspca_dev->present) {
		ret = -ENODEV;
		ret = -ENODEV;
		goto out;
		goto out;
@@ -850,16 +851,17 @@ static int dev_open(struct inode *inode, struct file *file)


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


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


	if (!gspca_dev->sd_desc->get_jcomp)
	if (!gspca_dev->sd_desc->get_jcomp)
		return -EINVAL;
		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);
	ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
	mutex_unlock(&gspca_dev->usb_lock);
	mutex_unlock(&gspca_dev->usb_lock);
	return ret;
	return ret;
@@ -1152,7 +1161,8 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
	struct gspca_dev *gspca_dev = priv;
	struct gspca_dev *gspca_dev = priv;
	int ret;
	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)
	if (!gspca_dev->sd_desc->set_jcomp)
		return -EINVAL;
		return -EINVAL;
	ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
	ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
@@ -1177,7 +1187,8 @@ static int vidioc_s_parm(struct file *filp, void *priv,
	struct gspca_dev *gspca_dev = priv;
	struct gspca_dev *gspca_dev = priv;
	int n;
	int n;


	mutex_lock_interruptible(&gspca_dev->usb_lock);
	if (mutex_lock_interruptible(&gspca_dev->usb_lock))
		return -ERESTARTSYS;
	n = parm->parm.capture.readbuffers;
	n = parm->parm.capture.readbuffers;
	if (n == 0 || n > GSPCA_MAX_FRAMES)
	if (n == 0 || n > GSPCA_MAX_FRAMES)
		parm->parm.capture.readbuffers = gspca_dev->nbufread;
		parm->parm.capture.readbuffers = gspca_dev->nbufread;
@@ -1230,10 +1241,8 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
	size = vma->vm_end - vma->vm_start;
	size = vma->vm_end - vma->vm_start;
	PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);
	PDEBUG(D_STREAM, "mmap start:%08x size:%d", (int) start, (int) size);


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

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

	return j;
	return j;
}
}


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


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

	if (frame->v4l2_buf.flags
	if (frame->v4l2_buf.flags
			& (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)) {
			& (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE)) {
		PDEBUG(D_STREAM, "qbuf bad state");
		PDEBUG(D_STREAM, "qbuf bad state");
@@ -1708,11 +1724,12 @@ void gspca_disconnect(struct usb_interface *intf)
	if (!gspca_dev)
	if (!gspca_dev)
		return;
		return;
	gspca_dev->present = 0;
	gspca_dev->present = 0;
	mutex_lock_interruptible(&gspca_dev->queue_lock);
	mutex_lock(&gspca_dev->queue_lock);
	mutex_lock_interruptible(&gspca_dev->usb_lock);
	mutex_lock(&gspca_dev->usb_lock);
	gspca_dev->streaming = 0;
	gspca_kill_transfer(gspca_dev);
	gspca_kill_transfer(gspca_dev);
	mutex_unlock(&gspca_dev->queue_lock);
	mutex_unlock(&gspca_dev->usb_lock);
	mutex_unlock(&gspca_dev->usb_lock);
	mutex_unlock(&gspca_dev->queue_lock);
	while (gspca_dev->users != 0) {		/* wait until fully closed */
	while (gspca_dev->users != 0) {		/* wait until fully closed */
		atomic_inc(&gspca_dev->nevent);
		atomic_inc(&gspca_dev->nevent);
		wake_up_interruptible(&gspca_dev->wq);	/* wake processes */
		wake_up_interruptible(&gspca_dev->wq);	/* wake processes */
+8 −9
Original line number Original line Diff line number Diff line
@@ -101,6 +101,7 @@ struct sd_desc {
	cam_v_op stopN;		/* called on stream off - main alt */
	cam_v_op stopN;		/* called on stream off - main alt */
	cam_v_op stop0;		/* called on stream off - alt 0 */
	cam_v_op stop0;		/* called on stream off - alt 0 */
	cam_v_op close;		/* called on close */
	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_pkt_op pkt_scan;
	cam_jpg_op get_jcomp;
	cam_jpg_op get_jcomp;
	cam_jpg_op set_jcomp;
	cam_jpg_op set_jcomp;
@@ -167,8 +168,6 @@ int gspca_dev_probe(struct usb_interface *intf,
		const struct usb_device_id *id,
		const struct usb_device_id *id,
		const struct sd_desc *sd_desc,
		const struct sd_desc *sd_desc,
		int dev_size);
		int dev_size);
int gspca_dev_init(struct gspca_dev *gspca_dev,
		   struct usb_interface *intf);
void gspca_disconnect(struct usb_interface *intf);
void gspca_disconnect(struct usb_interface *intf);
struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
				    int packet_type,
				    int packet_type,
+939 −0

File added.

Preview size limit exceeded, changes collapsed.