From: Ronald Bultje <rbultje@ronald.bitfreak.net>

This patch adds a release callback which frees the video_device struct.
This is needed to prevent freeing memory before it's not in use anymore,
as described in http://lwn.net/Articles/36850/. Without this, the driver
will give a warning when loaded. It might crash when unloading (see
article), too. The video4linux patch (by Gerd Knorr) was accepted a week
(or 2?) ago, but I forgot to adapt my driver to it.



 drivers/media/video/zoran.h        |    2 +-
 drivers/media/video/zoran_card.c   |   26 ++++++++++++++++++++------
 drivers/media/video/zoran_card.h   |    1 +
 drivers/media/video/zoran_driver.c |    5 +++--
 4 files changed, 25 insertions(+), 9 deletions(-)

diff -puN drivers/media/video/zoran_card.c~zoran-release-callback drivers/media/video/zoran_card.c
--- 25/drivers/media/video/zoran_card.c~zoran-release-callback	2003-08-24 02:07:59.000000000 -0700
+++ 25-akpm/drivers/media/video/zoran_card.c	2003-08-24 02:07:59.000000000 -0700
@@ -987,6 +987,7 @@ static int __devinit
 zr36057_init (struct zoran *zr)
 {
 	unsigned long mem;
+	void *vdev;
 	unsigned mem_needed;
 	int j;
 	int two = 2;
@@ -1041,11 +1042,16 @@ zr36057_init (struct zoran *zr)
 	 * in case allocation fails */
 	mem_needed = BUZ_NUM_STAT_COM * 4;
 	mem = (unsigned long) kmalloc(mem_needed, GFP_KERNEL);
-	if (!mem) {
+	vdev = (void *) kmalloc(sizeof(struct video_device), GFP_KERNEL);
+	if (!mem || !vdev) {
 		dprintk(1,
 			KERN_ERR
 			"%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
 			ZR_DEVNAME(zr));
+		if (vdev)
+			kfree(vdev);
+		if (mem)
+			kfree((void *)mem);
 		return -ENOMEM;
 	}
 	memset((void *) mem, 0, mem_needed);
@@ -1057,12 +1063,14 @@ zr36057_init (struct zoran *zr)
 	/*
 	 *   Now add the template and register the device unit.
 	 */
-	memcpy(&zr->video_dev, &zoran_template, sizeof(zoran_template));
-	strcpy(zr->video_dev.name, ZR_DEVNAME(zr));
-	if (video_register_device
-	    (&zr->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {
+	zr->video_dev = vdev;
+	memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
+	strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
+	if (video_register_device(zr->video_dev, VFL_TYPE_GRABBER,
+				  video_nr) < 0) {
 		zoran_unregister_i2c(zr);
 		kfree((void *) zr->stat_com);
+		kfree(vdev);
 		return -1;
 	}
 
@@ -1110,7 +1118,13 @@ zoran_release (struct zoran *zr)
 	kfree((void *) zr->stat_com);
 	zoran_proc_cleanup(zr);
 	iounmap(zr->zr36057_mem);
-	video_unregister_device(&zr->video_dev);
+	video_unregister_device(zr->video_dev);
+}
+
+void
+zoran_vdev_release (struct video_device *vdev)
+{
+	kfree(vdev);
 }
 
 static struct videocodec_master * __devinit
diff -puN drivers/media/video/zoran_card.h~zoran-release-callback drivers/media/video/zoran_card.h
--- 25/drivers/media/video/zoran_card.h~zoran-release-callback	2003-08-24 02:07:59.000000000 -0700
+++ 25-akpm/drivers/media/video/zoran_card.h	2003-08-24 02:07:59.000000000 -0700
@@ -40,5 +40,6 @@ extern struct video_device zoran_templat
 extern int zoran_check_jpg_settings(struct zoran *zr,
 				    struct zoran_jpg_settings *settings);
 extern void zoran_open_init_params(struct zoran *zr);
+extern void zoran_vdev_release(struct video_device *vdev);
 
 #endif				/* __ZORAN_CARD_H__ */
diff -puN drivers/media/video/zoran_driver.c~zoran-release-callback drivers/media/video/zoran_driver.c
--- 25/drivers/media/video/zoran_driver.c~zoran-release-callback	2003-08-24 02:07:59.000000000 -0700
+++ 25-akpm/drivers/media/video/zoran_driver.c	2003-08-24 02:07:59.000000000 -0700
@@ -1268,7 +1268,7 @@ zoran_open (struct inode *inode,
 
 	/* find the device */
 	for (i = 0; i < zoran_num; i++) {
-		if (zoran[i].video_dev.minor == minor) {
+		if (zoran[i].video_dev->minor == minor) {
 			zr = &zoran[i];
 			break;
 		}
@@ -2358,7 +2358,7 @@ zoran_do_ioctl (struct inode *inode,
 		struct video_unit *vunit = arg;
 
 		dprintk(3, KERN_DEBUG "%s: VIDIOCGUNIT\n", ZR_DEVNAME(zr));
-		vunit->video = zr->video_dev.minor;
+		vunit->video = zr->video_dev->minor;
 		vunit->vbi = VIDEO_NO_UNIT;
 		vunit->radio = VIDEO_NO_UNIT;
 		vunit->audio = VIDEO_NO_UNIT;
@@ -4665,5 +4665,6 @@ struct video_device zoran_template __dev
 #endif
 	.hardware = ZORAN_HARDWARE,
 	.fops = &zoran_fops,
+	.release = &zoran_vdev_release,
 	.minor = -1
 };
diff -puN drivers/media/video/zoran.h~zoran-release-callback drivers/media/video/zoran.h
--- 25/drivers/media/video/zoran.h~zoran-release-callback	2003-08-24 02:07:59.000000000 -0700
+++ 25-akpm/drivers/media/video/zoran.h	2003-08-24 02:07:59.000000000 -0700
@@ -383,7 +383,7 @@ struct card_info {
 };
 
 struct zoran {
-	struct video_device video_dev;
+	struct video_device *video_dev;
 
 	struct i2c_adapter i2c_adapter;	/* */
 	struct i2c_algo_bit_data i2c_algo;	/* */

_