V4L/DVB (6753): Fix vivi to support non-zero minor node

There were a trouble at vivi driver when using non-zero inodes. This where due
to not properly preserving the minor inode after calling video_register. Since
this driver is a reference for newer drivers, and it is possible to have more
than one video device inside the machine, this patch makes vivi to dynamically
allocate video_device struct.

Thanks to Gregor Jasny <jasny@vidsoft.de> for pointing the issue.

Also, this patch removes a very anoying (but useless) message of not having a
proper release call.

CC: Gregor Jasny <jasny@vidsoft.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index fe9784a..5ddaaa3 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -170,7 +170,7 @@
 	int                        users;
 
 	/* various device info */
-	struct video_device        vfd;
+	struct video_device        *vfd;
 
 	struct vivi_dmaqueue       vidq;
 
@@ -986,7 +986,7 @@
 	printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
 
 	list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
-		if (dev->vfd.minor == minor)
+		if (dev->vfd->minor == minor)
 			goto found;
 	return -ENODEV;
 found:
@@ -1067,7 +1067,7 @@
 	return videobuf_poll_stream(file, q, wait);
 }
 
-static int vivi_release(struct inode *inode, struct file *file)
+static int vivi_close(struct inode *inode, struct file *file)
 {
 	struct vivi_fh         *fh = file->private_data;
 	struct vivi_dev *dev       = fh->dev;
@@ -1088,6 +1088,18 @@
 	return 0;
 }
 
+static int vivi_release(struct vivi_dev *dev)
+{
+	if (-1 != dev->vfd->minor)
+		video_unregister_device(dev->vfd);
+	else
+		video_device_release(dev->vfd);
+
+	dev->vfd = NULL;
+
+	return 0;
+}
+
 static int
 vivi_mmap(struct file *file, struct vm_area_struct * vma)
 {
@@ -1109,7 +1121,7 @@
 static const struct file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
 	.open           = vivi_open,
-	.release        = vivi_release,
+	.release        = vivi_close,
 	.read           = vivi_read,
 	.poll		= vivi_poll,
 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
@@ -1117,12 +1129,12 @@
 	.llseek         = no_llseek,
 };
 
-static struct video_device vivi = {
+static struct video_device vivi_template = {
 	.name		= "vivi",
 	.type		= VID_TYPE_CAPTURE,
 	.fops           = &vivi_fops,
 	.minor		= -1,
-//	.release	= video_device_release,
+	.release	= video_device_release,
 
 	.vidioc_querycap      = vidioc_querycap,
 	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
@@ -1156,6 +1168,7 @@
 {
 	int ret;
 	struct vivi_dev *dev;
+	struct video_device *vfd;
 
 	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
 	if (NULL == dev)
@@ -1174,7 +1187,18 @@
 	dev->vidq.timeout.data     = (unsigned long)dev;
 	init_timer(&dev->vidq.timeout);
 
-	ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return -ENOMEM;
+
+	*vfd = vivi_template;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+	snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
+		 vivi_template.name, vfd->minor);
+
+	dev->vfd = vfd;
+
 	printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
 	return ret;
 }
@@ -1188,9 +1212,9 @@
 		list = vivi_devlist.next;
 		list_del(list);
 		h = list_entry(list, struct vivi_dev, vivi_devlist);
+		vivi_release(h);
 		kfree (h);
 	}
-	video_unregister_device(&vivi);
 }
 
 module_init(vivi_init);