# HG changeset patch # User Yoshiki Yazawa # Date 1257512238 -32400 # Node ID 2dbe2489381e774fa4fc04360b78ddb71097e3b9 # Parent 1011e450be45806c3a9f1056852743c647de803f updated to 2.6.32 diff -r 1011e450be45 -r 2dbe2489381e vloopback.c --- a/vloopback.c Fri Sep 11 10:02:42 2009 +0000 +++ b/vloopback.c Fri Nov 06 21:57:18 2009 +0900 @@ -49,13 +49,13 @@ * IOC_IN instead. * Change the ioctlnr passing to 'unsigned long int' * Instead of just one byte. - * THIS BREAKS COMPATIBILITY WITH PREVIOUS VERSIONS!!! + * THIS BREAKS COMPATIBILITY WITH PREVIOUS VERSIONS!!! * 29.06.01 (J Vreeken) Added dev_offset module option * Made vloopback_template sane * Added double buffering support * Made vloopback less verbose * 20.11.01 (tibit) Made dev_offset option sane - * "Fixed" zerocopy mode by defining the ioctl + * "Fixed" zerocopy mode by defining the ioctl * VIDIOCSINVALID. An application which provides data * has to issue it when it encounters an error in * ioctl processing. See dummy.c for examples. @@ -79,7 +79,7 @@ * * 04.02.05 (Angel Carpintero) * Fixed version number to 0.93-pre1. - * Fixed warning for interruptible_sleep_on() deprecated and added + * Fixed warning for interruptible_sleep_on() deprecated and added * wait_event_interruptible compatible with 2.6.x and 2.7. * Fixed memory manager for kernel version > 2.6.9. * @@ -91,7 +91,7 @@ * Fixed error with wait_event_interruptible. * Fixed crash when pipe source was stopped before dest. * - * 20.02.05 (Angel Carpintero) + * 20.02.05 (Angel Carpintero) * Added install and uninstall in Makefile. * * @@ -101,14 +101,14 @@ * * 02.05.05 (Kenneth Lavrsen) * Released 0.95-snap2 formerly as 0.95 - * + * * 10.05.05 (Angel Carpintero) * Added MODULE_VERSION(), fixed create_pipes when video_register_device() returns - * -ENFILE . + * -ENFILE . * Fix warnings about checking return value from copy_to_user() and copy_from_user() functions. * * 14.11.05 (Angel Carpintero) - * Added that includes LINUX_VERSION_CODE and KERNEL_VERSION to fix + * Added that includes LINUX_VERSION_CODE and KERNEL_VERSION to fix * compilation agains kernel 2.6.14 , change version to 0.97-snap1 * * 19.12.05 (Angel Carpintero) @@ -116,7 +116,7 @@ * * 31.12.05 (Angel Carpintero) * Fixed examples, remove perror calls and add support to dummy.c for sysfs. - * + * * 04.06.06 (Angel Carpintero) * Add module_param() for kernel > 2.5 because MODULE_PARAM() macro is obsolete. * @@ -132,14 +132,14 @@ * Make compatible with new kernel stable version 2.6.18, Many functions and declarations has * been moved to media/v42l-dev.h and remove from videodev.h/videodev2.h * - * 18.01.07 (Angel Carpintero) + * 18.01.07 (Angel Carpintero) * Change -ENOIOCTLCMD by more appropiate error -ENOTTY. - * + * * 18.05.08 (Angel Carpintero) * Release 1.1-rc1 as 1.1 stable working with 2.6.24 * * 17.08.08 (Angel Carpintero) - * kill_proc() deprecated ,pid API changed , type and owner not available in + * kill_proc() deprecated ,pid API changed , type and owner not available in * video_device struct, added param debug. * * 24.08.08 (Angel Carpintero) @@ -147,66 +147,52 @@ * add number of buffers as module param. * * 13.10.08 (Stephan Berberig & Angel Carpintero) - * Release to work on 2.6.27 , allow v4l_compat_ioctl32 work in 2.6.27 and a little cleanup + * Release to work on 2.6.27 , allow v4l_compat_ioctl32 work in 2.6.27 and a little cleanup * in Makefile. * * 22.12.08 (Angel Carpintero) - * Allow build with kernel 2.6.28 and 2.6.27.git ( struct video_dev has not priv member anymore). - * - * 17.05.09 (Peter Holik) - * Patch to allow work with kernel 2.6.29 - * - * 05.08.09 (Angel Carpintero) - * Allow to compile with kernel 2.6.30.* - * - * 11.09.09 (Angel Carpintero) - * Allow to compile with kernel 2.6.31 + * Allow build with kernel 2.6.28 and 2.6.27.git ( struct video_dev has not priv member anymore). */ -#define VLOOPBACK_VERSION "1.3-trunk" +#define VLOOPBACK_VERSION "1.4" /* Include files common to 2.4 and 2.6 versions */ -#include /* >= 2.6.14 LINUX_VERSION_CODE */ +#include /* >= 2.6.14 LINUX_VERSION_CODE */ #include #include #include #include #ifndef CONFIG_VIDEO_V4L1_COMPAT -#error "need CONFIG_VIDEO_V4L1_COMPAT" + #error "need CONFIG_VIDEO_V4L1_COMPAT" #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) #include #endif -/* v4l_compat_ioctl32 */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - #ifdef __KERNEL__ - #undef __KERNEL__ - #endif - #include -#endif - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27) - #define vd_private_data dev.driver_data - #ifndef __KERNEL__ - #define __KERNEL__ - #endif -#else - #define vd_private_data priv -#endif - #include #include #include +/* v4l_compat_ioctl32 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + #include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) + #define video_get_drvdata(dev) (priv) + #define video_set_drvdata(dev, data) (priv = (data)) +#elseif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,31) + #define video_get_drvdata(dev) ((dev).driver_data) + #define video_set_drvdata(dev, data) ((dev) = (data)) +#endif /* Include files which are unique to versions */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) #include - #include + #include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) #ifndef remap_pfn_range @@ -226,7 +212,7 @@ #include #include #endif - + #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) #define verbose(format, arg...) if (printk_ratelimit()) \ @@ -237,7 +223,7 @@ printk(KERN_INFO "[%s] : " format "\n" "", \ __FUNCTION__, ## arg) -#define LOG_NODEBUG 0 +#define LOG_NODEBUG 0 #define LOG_FUNCTIONS 1 #define LOG_IOCTL 2 #define LOG_VERBOSE 3 @@ -264,11 +250,11 @@ struct semaphore lock; wait_queue_head_t wait; unsigned int frame; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) unsigned int pid; #else - struct pid *pid; -#endif + struct pid *pid; +#endif unsigned int zerocopy; unsigned long int ioctlnr; unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ @@ -299,7 +285,7 @@ * This is used when initializing the contents of the * area and marking the pages as reserved. */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +static inline unsigned long kvirt_to_pa(unsigned long adr) { unsigned long kva; @@ -386,7 +372,7 @@ wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else interruptible_sleep_on(&loops[nr]->wait); -#endif +#endif if (cmd & IOC_IN) { if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) return 1; @@ -401,26 +387,25 @@ #else static int vloopback_open(struct file *f) #endif -{ +{ struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; if (debug > LOG_NODEBUG) - info("Video loopback %d", nr); + info("Video loopback %d", nr); /* Only allow a output to be opened if there is someone feeding * the pipe. */ if (!ptr->in) { - if (loops[nr]->buffer == NULL) + if (loops[nr]->buffer == NULL) return -EINVAL; - + loops[nr]->framesread = 0; loops[nr]->ropen = 1; } else { - if (loops[nr]->ropen || loops[nr]->wopen) + if (loops[nr]->ropen || loops[nr]->wopen) return -EBUSY; loops[nr]->framesdumped = 0; @@ -442,13 +427,11 @@ } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) loops[nr]->pid = current->pid; -#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,30) - loops[nr]->pid = find_pid_ns(current->pid,0); +#elseif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + loops[nr]->pid = task_pid(find_task_by_vpid(current->pid)); #else - // TODO : Check in stable 2.6.27 - loops[nr]->pid = task_pid(find_task_by_vpid(current->pid)); - //loops[nr]->pid = task_pid(current); -#endif + loops[nr]->pid = task_pid(current); +#endif if (debug > LOG_NODEBUG) info("Current pid %d", current->pid); @@ -463,8 +446,7 @@ #endif { struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; if (debug > LOG_NODEBUG) @@ -479,7 +461,7 @@ up(&loops[nr]->lock); loops[nr]->frameswrite++; - + if (waitqueue_active(&loops[nr]->wait)) wake_up(&loops[nr]->wait); @@ -506,7 +488,7 @@ kill_proc(loops[nr]->pid, SIGIO, 1); #else kill_pid(loops[nr]->pid, SIGIO, 1); -#endif +#endif } } @@ -517,8 +499,7 @@ size_t count, loff_t *offset) { struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; unsigned long realcount = count; @@ -530,16 +511,16 @@ if (loops[nr]->zerocopy) return -EINVAL; - - if (loops[nr]->buffer == NULL) + + if (loops[nr]->buffer == NULL) return -EINVAL; - + /* Anybody want some pictures??? */ if (!waitqueue_active(&loops[nr]->wait)) { loops[nr]->framesdumped++; return realcount; } - + down(&loops[nr]->lock); if (!loops[nr]->buffer) { up(&loops[nr]->lock); @@ -548,12 +529,12 @@ if (realcount > loops[nr]->buflength) { realcount = loops[nr]->buflength; - info("Too much data for Video loopback %d ! Only %ld bytes used.", + info("Too much data for Video loopback %d ! Only %ld bytes used.", nr, realcount); } - - if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength, - buf, realcount)) + + if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength, + buf, realcount)) return -EFAULT; loops[nr]->frame = 0; @@ -565,12 +546,11 @@ return realcount; } -static ssize_t vloopback_read(struct file * f, char * buf, size_t count, +static ssize_t vloopback_read(struct file * f, char * buf, size_t count, loff_t *offset) { struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; unsigned long realcount = count; @@ -585,9 +565,9 @@ if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int))) return -EFAULT; - if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata, + if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata, realcount - sizeof(unsigned long int))) - return -EFAULT; + return -EFAULT; if (loops[nr]->ioctlnr == 0) loops[nr]->ioctlnr = -1; @@ -597,7 +577,7 @@ struct video_window vidwin; struct video_mmap vidmmap; struct video_picture vidpic; - + fake_ioctl(nr, VIDIOCGWIN, &vidwin); fake_ioctl(nr, VIDIOCGPICT, &vidpic); @@ -627,7 +607,7 @@ if (!loops[nr]->zerocopy) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) unsigned long fw = loops[nr]->frameswrite; - + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else interruptible_sleep_on(&loops[nr]->wait); @@ -652,8 +632,7 @@ static int vloopback_mmap(struct file *f, struct vm_area_struct *vma) { struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; unsigned long start = (unsigned long)vma->vm_start; long size = vma->vm_end - vma->vm_start; @@ -692,7 +671,7 @@ return -EINVAL; } - if (size > (((num_buffers * loops[nr]->buflength) + PAGE_SIZE - 1) + if (size > (((num_buffers * loops[nr]->buflength) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { up(&loops[nr]->lock); return -EINVAL; @@ -722,15 +701,14 @@ } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) -static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, +static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, unsigned long arg) #else static long vloopback_ioctl(struct file *f, unsigned int cmd, unsigned long arg) #endif { struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; int i; @@ -750,14 +728,14 @@ kill_proc(loops[nr]->pid, SIGIO, 1); #else kill_pid(loops[nr]->pid, SIGIO, 1); -#endif +#endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1); #else interruptible_sleep_on(&loops[nr]->wait); -#endif - +#endif + if (loops[nr]->invalid_ioctl) { info ("There was an invalid ioctl in Video loopback %d", nr); loops[nr]->invalid_ioctl = 0; @@ -765,11 +743,11 @@ } if (cmd & IOC_IN && !(cmd & IOC_OUT)) { - //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); - if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) + //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); + if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) return -EINVAL; - - //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); + + //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); return 0; } else { if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) @@ -786,7 +764,7 @@ if (cmd == VIDIOCSINVALID) { loops[nr]->invalid_ioctl = 1; - } else if (copy_from_user(loops[nr]->ioctlretdata, + } else if (copy_from_user(loops[nr]->ioctlretdata, (void*)arg, loops[nr]->ioctllength)) { return -EFAULT; } @@ -947,7 +925,7 @@ case VIDIOCSWIN: { struct video_window vw; - + if (copy_from_user(&vw, (void*)arg, sizeof(vw))) return -EFAULT; @@ -991,7 +969,7 @@ case VIDIOCGMBUF: { struct video_mbuf vm; - + vm.size = loops[nr]->buflength * num_buffers; vm.frames = num_buffers; for (i = 0; i < vm.frames; i++) @@ -1052,7 +1030,7 @@ wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else interruptible_sleep_on(&loops[nr]->wait); -#endif +#endif if (!loops[nr]->buffer) /* possibly released during sleep */ return -EINVAL; @@ -1064,7 +1042,7 @@ case VIDIOCGUNIT: { struct video_unit vu; - + if (ptr->in) vu.video = loops[nr]->vloopout->minor; else @@ -1101,7 +1079,7 @@ if (copy_from_user(&start, (void*)arg, sizeof(int))) return -EFAULT; - if (start) { + if (start) { info ("Video loopback %d Capture started", nr); } else { info ("Video loopback %d Capture stopped", nr); @@ -1126,8 +1104,7 @@ static unsigned int vloopback_poll(struct file *f, struct poll_table_struct *wait) { struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->vd_private_data; - //priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); + priv_ptr ptr = (priv_ptr)video_get_drvdata(loopdev); int nr = ptr->pipenr; if (debug > LOG_NODEBUG) @@ -1170,11 +1147,11 @@ static struct video_device vloopback_template = { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) owner: THIS_MODULE, type: VID_TYPE_CAPTURE, #endif - minor: -1, + minor: -1, name: "Video Loopback", fops: &fileops_template, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) @@ -1185,6 +1162,7 @@ static int create_pipe(int nr) { int minor_in, minor_out , ret; + priv_ptr ptr; if (debug > LOG_NODEBUG) info("Video loopback %d", nr); @@ -1207,34 +1185,34 @@ return -ENOMEM; *loops[nr]->vloopin = vloopback_template; - loops[nr]->vloopin->vd_private_data = kmalloc(sizeof(struct vloopback_private), - GFP_KERNEL); - - if (loops[nr]->vloopin->vd_private_data == NULL) { + ptr = kmalloc(sizeof(struct vloopback_private), GFP_KERNEL); + if(!ptr) { kfree(loops[nr]->vloopin); return -ENOMEM; } + video_set_drvdata(loops[nr]->vloopin, ptr); /* repeat for the output device */ loops[nr]->vloopout = video_device_alloc(); if (loops[nr]->vloopout == NULL) { - kfree(loops[nr]->vloopin->vd_private_data); + kfree(video_get_drvdata(loops[nr]->vloopin)); kfree(loops[nr]->vloopin); + loops[nr]->vloopin = NULL; return -ENOMEM; } *loops[nr]->vloopout = vloopback_template; - loops[nr]->vloopout->vd_private_data = kmalloc(sizeof(struct vloopback_private), - GFP_KERNEL); - - if (loops[nr]->vloopout->vd_private_data == NULL) { - kfree(loops[nr]->vloopin->vd_private_data); + ptr = kmalloc(sizeof(struct vloopback_private), GFP_KERNEL); + if(!ptr) { + kfree(video_get_drvdata(loops[nr]->vloopin)); kfree(loops[nr]->vloopin); kfree(loops[nr]->vloopout); return -ENOMEM; } + video_set_drvdata(loops[nr]->vloopout, ptr); - ((priv_ptr)loops[nr]->vloopin->vd_private_data)->pipenr = nr; - ((priv_ptr)loops[nr]->vloopout->vd_private_data)->pipenr = nr; + ((priv_ptr)video_get_drvdata(loops[nr]->vloopin))->pipenr = nr; + ((priv_ptr)video_get_drvdata(loops[nr]->vloopout))->pipenr = nr; + loops[nr]->invalid_ioctl = 0; /* tibit */ loops[nr]->buffer = NULL; loops[nr]->width = 0; @@ -1246,9 +1224,9 @@ loops[nr]->wopen = 0; loops[nr]->ropen = 0; loops[nr]->frame = 0; - - ((priv_ptr)loops[nr]->vloopin->vd_private_data)->in = 1; - ((priv_ptr)loops[nr]->vloopout->vd_private_data)->in = 0; + + ((priv_ptr)video_get_drvdata(loops[nr]->vloopin))->in = 1; + ((priv_ptr)video_get_drvdata(loops[nr]->vloopout))->in = 0; sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); @@ -1261,33 +1239,33 @@ init_waitqueue_head(&loops[nr]->wait); init_MUTEX(&loops[nr]->lock); - + ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER, minor_in); - + if ((ret == -1 ) || ( ret == -23 )) { info("error registering device %s", loops[nr]->vloopin->name); - kfree(loops[nr]->vloopin->vd_private_data); + kfree(video_get_drvdata(loops[nr]->vloopin)); kfree(loops[nr]->vloopin); - kfree(loops[nr]->vloopout->vd_private_data); + kfree(video_get_drvdata(loops[nr]->vloopout)); kfree(loops[nr]->vloopout); kfree(loops[nr]); loops[nr] = NULL; return ret; } - + ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER, minor_out); - + if ((ret ==-1) || (ret == -23)) { info("error registering device %s", loops[nr]->vloopout->name); - kfree(loops[nr]->vloopin->vd_private_data); + kfree(video_get_drvdata(loops[nr]->vloopin)); video_unregister_device(loops[nr]->vloopin); - kfree(loops[nr]->vloopout->vd_private_data); + kfree(video_get_drvdata(loops[nr]->vloopout)); kfree(loops[nr]->vloopout); kfree(loops[nr]); loops[nr] = NULL; return ret; } - + loops[nr]->ioctldata = kmalloc(1024, GFP_KERNEL); loops[nr]->ioctlretdata = kmalloc(1024, GFP_KERNEL); return 0; @@ -1353,7 +1331,7 @@ info("video4linux loopback driver v"VLOOPBACK_VERSION); - if (pipes == -1) + if (pipes == -1) pipes = 1; if (pipes > MAX_PIPES) { @@ -1367,14 +1345,14 @@ } for (i = 0; i < pipes; i++) { - + ret = create_pipe(i); if (ret == 0) { - info("Loopback %d registered, input: video%d," - " output: video%d", - i, loops[i]->vloopin->minor, - loops[i]->vloopout->minor); + info("Loopback %d registered, input: /dev/video%d minor %d," + " output: /dev/video%d minor %d", + i, loops[i]->vloopin->num, loops[i]->vloopin->minor, + loops[i]->vloopout->num, loops[i]->vloopout->minor); info("Loopback %d , Using %d buffers", i, num_buffers); nr_o_pipes = i + 1; } else { @@ -1392,19 +1370,19 @@ for (i = 0; i < nr_o_pipes; i++) { if (loops[i]) { - kfree(loops[i]->vloopin->vd_private_data); + kfree(video_get_drvdata(loops[i]->vloopin)); video_unregister_device(loops[i]->vloopin); - kfree(loops[i]->vloopout->vd_private_data); + kfree(video_get_drvdata(loops[i]->vloopout)); video_unregister_device(loops[i]->vloopout); - - if (loops[i]->buffer) + + if (loops[i]->buffer) rvfree(loops[i]->buffer, loops[i]->buflength * num_buffers); kfree(loops[i]->ioctldata); kfree(loops[i]->ioctlretdata); kfree(loops[i]); } - } + } } module_init(vloopback_init);