ChangeSet 1.893.2.27, 2003/01/06 11:07:07-08:00, mark@alpha.dyndns.org

[PATCH] USB ov511: Convert to new V4L 1 interface

Here's a patch to switch ov511 over to the new V4L 1 interface
introduced in 2.4.19. Rather than storing the function pointers for
open(), ioctl(), etc in struct video_device, I just hand the V4L layer a
struct file_operations.

The advantages of this are:

- The driver more closely resembles its 2.5 counterpart.

- Multiple simultaneous opens will eventually be possible.

- The old interfaces required calling video_unregister_device() from
close() if the device was unplugged while open, causing a deadlock in
the V4L layer. Now we just call video_unregister_device()
unconditionally from disconnect(). (Credit goes to Duncan Haldane for
tracking that bug down)

This is just a backport of the changes made to the driver in ~2.5.10;
nothing new here. I've been using this version of the code under 2.4 for
months and it works well.


diff -Nru a/drivers/usb/ov511.c b/drivers/usb/ov511.c
--- a/drivers/usb/ov511.c	Mon Jan  6 11:29:19 2003
+++ b/drivers/usb/ov511.c	Mon Jan  6 11:29:19 2003
@@ -1,7 +1,7 @@
 /*
  * OmniVision OV511 Camera-to-USB Bridge Driver
  *
- * Copyright (c) 1999-2002 Mark W. McClelland
+ * Copyright (c) 1999-2003 Mark W. McClelland
  * Original decompression code Copyright 1998-2000 OmniVision Technologies
  * Many improvements by Bret Wallach <bwallac1@san.rr.com>
  * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
@@ -4529,8 +4529,9 @@
  ***************************************************************************/
 
 static int
-ov51x_v4l1_open(struct video_device *vdev, int flags)
+ov51x_v4l1_open(struct inode *inode, struct file *file)
 {
+	struct video_device *vdev = video_devdata(file);
 	struct usb_ov511 *ov = vdev->priv;
 	int err, i;
 
@@ -4574,6 +4575,7 @@
 	}
 
 	ov->user++;
+	file->private_data = vdev;
 
 	if (ov->led_policy == LED_AUTO)
 		ov51x_led_control(ov, 1);
@@ -4583,9 +4585,10 @@
 	return err;
 }
 
-static void
-ov51x_v4l1_close(struct video_device *vdev)
+static int
+ov51x_v4l1_close(struct inode *inode, struct file *file)
 {
+	struct video_device *vdev = file->private_data;
 	struct usb_ov511 *ov = vdev->priv;
 
 	PDEBUG(4, "ov511_close");
@@ -4614,19 +4617,22 @@
 		up(&ov->cbuf_lock);
 
 		ov51x_dealloc(ov, 1);
-		video_unregister_device(&ov->vdev);
 		kfree(ov);
 		ov = NULL;
 	}
 
-	return;
+	file->private_data = NULL;
+	return 0;
 }
 
 /* Do not call this function directly! */
 static int
-ov51x_v4l1_ioctl_internal(struct usb_ov511 *ov, unsigned int cmd,
-			  void *arg)
+ov51x_v4l1_ioctl_internal(struct inode *inode, struct file *file,
+			  unsigned int cmd, void *arg)
 {
+	struct video_device *vdev = file->private_data;
+	struct usb_ov511 *ov = vdev->priv;
+
 	PDEBUG(5, "IOCtl: 0x%X", cmd);
 
 	if (!ov->dev)
@@ -5066,80 +5072,29 @@
 	return 0;
 }
 
-/* This is implemented as video_generic_ioctl() in the new V4L's videodev.c */
 static int
-ov51x_v4l1_generic_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
-{
-	char	sbuf[128];
-	void    *mbuf = NULL;
-	void	*parg = NULL;
-	int	err  = -EINVAL;
-
-	/*  Copy arguments into temp kernel buffer  */
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:
-		parg = arg;
-		break;
-	case _IOC_READ: /* some v4l ioctls are marked wrong ... */
-	case _IOC_WRITE:
-	case (_IOC_WRITE | _IOC_READ):
-		if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-			parg = sbuf;
-		} else {
-			/* too big to allocate from stack */
-			mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
-			if (NULL == mbuf)
-				return -ENOMEM;
-			parg = mbuf;
-		}
-
-		err = -EFAULT;
-		if (copy_from_user(parg, arg, _IOC_SIZE(cmd)))
-			goto out;
-		break;
-	}
-
-	err = ov51x_v4l1_ioctl_internal(vdev->priv, cmd, parg);
-	if (err == -ENOIOCTLCMD)
-		err = -EINVAL;
-	if (err < 0)
-		goto out;
-
-	/*  Copy results into user buffer  */
-	switch (_IOC_DIR(cmd))
-	{
-	case _IOC_READ:
-	case (_IOC_WRITE | _IOC_READ):
-		if (copy_to_user(arg, parg, _IOC_SIZE(cmd)))
-			err = -EFAULT;
-		break;
-	}
-
-out:
-	if (mbuf)
-		kfree(mbuf);
-	return err;
-}
-
-static int
-ov51x_v4l1_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+ov51x_v4l1_ioctl(struct inode *inode, struct file *file,
+		 unsigned int cmd, unsigned long arg)
 {
+	struct video_device *vdev = file->private_data;
 	struct usb_ov511 *ov = vdev->priv;
 	int rc;
 
 	if (down_interruptible(&ov->lock))
 		return -EINTR;
 
-	rc = ov51x_v4l1_generic_ioctl(vdev, cmd, arg);
+	rc = video_usercopy(inode, file, cmd, arg, ov51x_v4l1_ioctl_internal);
 
 	up(&ov->lock);
 	return rc;
 }
 
-static inline long
-ov51x_v4l1_read(struct video_device *vdev, char *buf, unsigned long count,
-		int noblock)
+static int
+ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos)
 {
+	struct video_device *vdev = file->private_data;
+	int noblock = file->f_flags&O_NONBLOCK;
+	unsigned long count = cnt;
 	struct usb_ov511 *ov = vdev->priv;
 	int i, rc = 0, frmx = -1;
 	struct ov511_frame *frame;
@@ -5289,9 +5244,11 @@
 }
 
 static int
-ov51x_v4l1_mmap(struct video_device *vdev, const char *adr, unsigned long size)
+ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	unsigned long start = (unsigned long)adr;
+	struct video_device *vdev = file->private_data;
+	unsigned long start = vma->vm_start;
+	unsigned long size  = vma->vm_end - vma->vm_start;
 	struct usb_ov511 *ov = vdev->priv;
 	unsigned long page, pos;
 
@@ -5327,16 +5284,22 @@
 	return 0;
 }
 
+static struct file_operations ov511_fops = {
+	.owner =	THIS_MODULE,
+	.open =		ov51x_v4l1_open,
+	.release =	ov51x_v4l1_close,
+	.read =		ov51x_v4l1_read,
+	.mmap =		ov51x_v4l1_mmap,
+	.ioctl =	ov51x_v4l1_ioctl,
+	.llseek =	no_llseek,
+};
+
 static struct video_device vdev_template = {
-	owner:		THIS_MODULE,
-	name:		"OV511 USB Camera",
-	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_OV511,
-	open:		ov51x_v4l1_open,
-	close:		ov51x_v4l1_close,
-	read:		ov51x_v4l1_read,
-	ioctl:		ov51x_v4l1_ioctl,
-	mmap:		ov51x_v4l1_mmap,
+	.owner =	THIS_MODULE,
+	.name =		"OV511 USB Camera",
+	.type =		VID_TYPE_CAPTURE,
+	.hardware =	VID_HARDWARE_OV511,
+	.fops =		&ov511_fops,
 };
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -6621,10 +6584,8 @@
 
 	PDEBUG(3, "");
 
-	/* We don't want people trying to open up the device */
-	if (!ov->user)
-		video_unregister_device(&ov->vdev);
-	else
+	video_unregister_device(&ov->vdev);
+	if (ov->user)
 		PDEBUG(3, "Device open...deferring video_unregister_device");
 
 	for (n = 0; n < OV511_NUMFRAMES; n++)
