Mercurial > vloopback
changeset 8:80590d10a596
Added num of buffers as a module param, indent code using spaces instead of tabs
author | AngelCarpintero |
---|---|
date | Tue, 26 Aug 2008 11:50:37 +0000 |
parents | 2fce9e157b8d |
children | 00bb25bff577 |
files | Makefile vloopback.c |
diffstat | 2 files changed, 890 insertions(+), 860 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sun Aug 24 02:20:51 2008 +0000 +++ b/Makefile Tue Aug 26 11:50:37 2008 +0000 @@ -1,8 +1,9 @@ VERSION=trunk +MODULENAME=vloopback ifneq ($(KERNELRELEASE),) -obj-m := vloopback.o +obj-m := $(MODULENAME).o else @@ -29,12 +30,12 @@ install: install -d $(DEST) - install -m 644 -c vloopback.ko $(DEST) + install -m 644 -c $(MODULENAME).ko $(DEST) -/sbin/depmod -a uninstall: - rm -f $(DEST)/vloopback.ko + rm -f $(DEST)/$(MODULENAME).ko -/sbin/depmod -a clean: rm -f .*.cmd *.o *.mod.c *.ko .v* *~ core Modules.symvers Module.symvers
--- a/vloopback.c Sun Aug 24 02:20:51 2008 +0000 +++ b/vloopback.c Tue Aug 26 11:50:37 2008 +0000 @@ -1,153 +1,157 @@ /* - * vloopback.c + * vloopback.c * - * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2000 - * Additional copyright by the contributing authors in the - * change history below, 2000-2007 + * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2000 + * Additional copyright by the contributing authors in the + * change history below, 2000-2007 * - * Published under the GNU Public License. + * Published under the GNU Public License. * - * The Video loopback Loopback Device is no longer systematically maintained. - * The project is a secondary project for the project "motion" found at - * http://motion.sourceforge.net/ and - * http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome - * and with the vloopback stored at - * http://www.lavrsen.dk/twiki/bin/view/Motion/Video loopbackFourLinuxLoopbackDevice + * The Video loopback Loopback Device is no longer systematically maintained. + * The project is a secondary project for the project "motion" found at + * http://motion.sourceforge.net/ and + * http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome + * and with the vloopback stored at + * http://www.lavrsen.dk/twiki/bin/view/Motion/Video loopbackFourLinuxLoopbackDevice * - * CHANGE HISTORY + * CHANGE HISTORY * - * UPDATED: Jeroen Vreeken. - * Added locks for smp machines. UNTESTED! - * Made the driver much more cpu friendly by using - * a wait queue. - * Went from vmalloc to rvmalloc (yes, I stole the code - * like everybody else) and implemented mmap. - * Implemented VIDIOCGUNIT and removed size/palette checks - * in VIDIOCSYNC. - * Cleaned up a lot of code. - * Changed locks to semaphores. - * Disabled changing size while somebody is using mmap - * Changed mapped check to open check, also don't allow - * a open for write while somebody is reading. - * Added /proc support - * Set dumped count to zero at open. - * Modified /proc layout (added vloopbacks entry) + * UPDATED: Jeroen Vreeken. + * Added locks for smp machines. UNTESTED! + * Made the driver much more cpu friendly by using + * a wait queue. + * Went from vmalloc to rvmalloc (yes, I stole the code + * like everybody else) and implemented mmap. + * Implemented VIDIOCGUNIT and removed size/palette checks + * in VIDIOCSYNC. + * Cleaned up a lot of code. + * Changed locks to semaphores. + * Disabled changing size while somebody is using mmap + * Changed mapped check to open check, also don't allow + * a open for write while somebody is reading. + * Added /proc support + * Set dumped count to zero at open. + * Modified /proc layout (added vloopbacks entry) * - * 05.10.00 (MTS) Added Linux 2.2 support - * 06.10.00 (J Vreeken) Fixed 2.2 support to make things work under 2.4 again. - * 17.10.00 (J Vreeken) Added zero copy mode + * 05.10.00 (MTS) Added Linux 2.2 support + * 06.10.00 (J Vreeken) Fixed 2.2 support to make things work under 2.4 again. + * 17.10.00 (J Vreeken) Added zero copy mode * 19.10.00 (J Vreeken) Added SIGIO on device close. * 24.10.00 (J Vreeken) Modified 2.2 stuff and removed spinlock.h - * released 0.81 + * released 0.81 * 27.10.00 (J Vreeken) Implemented poll - * released 0.82 + * released 0.82 * 17.01.01 (J Vreeken) support for xawtv - * Implemented VIDIOCGFBUF - * Additional checks on framebuffer freeing. - * released 0.83 - * 31.01.01 (J Vreeken) Removed need for 'struct ioctl', use _IOC_SIZE() and - * IOC_IN instead. - * Change the ioctlnr passing to 'unsigned long int' - * Instead of just one byte. - * 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 - * VIDIOCSINVALID. An application which provides data - * has to issue it when it encounters an error in - * ioctl processing. See dummy.c for examples. - * 26.11.03 (Kenneth Lavrsen) - * released 0.91 - * 0.91 is the combination of the 0.90-tibit by - * Tilmann Bitterberg and an update of the Makefile by - * Roberto Carvajal. - * 23.01.05 (W Brack) - * (don't know what happened to the comments for 0.92 - * and 0.93, but I tentatively named this one as 0.99) - * enhanced for linux-2.6, with #ifdef to keep it - * compatible with linux-2.4. For linux versions - * > 2.5, I changed the memory management - * routines to the "more modern" way, most of it - * shamelessly copied from other drivers. I also - * added in the code necessary to avoid the "videodev - * has no release callback" message when installing. - * For versions < 2.5, I updated the routines to be - * closer to several other drivers. + * Implemented VIDIOCGFBUF + * Additional checks on framebuffer freeing. + * released 0.83 + * 31.01.01 (J Vreeken) Removed need for 'struct ioctl', use _IOC_SIZE() and + * IOC_IN instead. + * Change the ioctlnr passing to 'unsigned long int' + * Instead of just one byte. + * 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 + * VIDIOCSINVALID. An application which provides data + * has to issue it when it encounters an error in + * ioctl processing. See dummy.c for examples. + * 26.11.03 (Kenneth Lavrsen) + * released 0.91 + * 0.91 is the combination of the 0.90-tibit by + * Tilmann Bitterberg and an update of the Makefile by + * Roberto Carvajal. + * 23.01.05 (W Brack) + * (don't know what happened to the comments for 0.92 + * and 0.93, but I tentatively named this one as 0.99) + * enhanced for linux-2.6, with #ifdef to keep it + * compatible with linux-2.4. For linux versions + * > 2.5, I changed the memory management + * routines to the "more modern" way, most of it + * shamelessly copied from other drivers. I also + * added in the code necessary to avoid the "videodev + * has no release callback" message when installing. + * For versions < 2.5, I updated the routines to be + * closer to several other drivers. * - * 04.02.05 (Angel Carpintero) - * Fixed version number to 0.93-pre1. - * 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. + * 04.02.05 (Angel Carpintero) + * Fixed version number to 0.93-pre1. + * 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. * - * 07.02.05 (Kenneth Lavrsen) - * Changed version to 0.94. - * Released as formal released version + * 07.02.05 (Kenneth Lavrsen) + * Changed version to 0.94. + * Released as formal released version * - * 20.02.05 (W Brack) - * Fixed error with wait_event_interruptible. - * Fixed crash when pipe source was stopped before dest. + * 20.02.05 (W Brack) + * Fixed error with wait_event_interruptible. + * Fixed crash when pipe source was stopped before dest. * - * 20.02.05 (Angel Carpintero) - * Added install and uninstall in Makefile. + * 20.02.05 (Angel Carpintero) + * Added install and uninstall in Makefile. * * - * 25.04.05 (Angel Carpintero) - * Included Samuel Audet's patch, it checks if the input is already - * opened in write mode. + * 25.04.05 (Angel Carpintero) + * Included Samuel Audet's patch, it checks if the input is already + * opened in write mode. * - * 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 . - * Fix warnings about checking return value from copy_to_user() and copy_from_user() functions. + * 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 . + * Fix warnings about checking return value from copy_to_user() and copy_from_user() functions. * - * 14.11.05 (Angel Carpintero) - * Added <linux/version.h> that includes LINUX_VERSION_CODE and KERNEL_VERSION to fix - * compilation agains kernel 2.6.14 , change version to 0.97-snap1 + * 14.11.05 (Angel Carpintero) + * Added <linux/version.h> 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) - * Added to example option to choose between rgb24 or yuv420p palettes. + * 19.12.05 (Angel Carpintero) + * Added to example option to choose between rgb24 or yuv420p palettes. * - * 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. + * 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. * - * 17.06.06 (Angel Carpintero) - * Release version 1.0 with some fixes and code clean up. Added a Jack Bates contribution - * to allow build a kernel module in debian way. + * 17.06.06 (Angel Carpintero) + * Release version 1.0 with some fixes and code clean up. Added a Jack Bates contribution + * to allow build a kernel module in debian way. * - * 26.06.06 (Angel Carpintero) - * Added some improvements in Makefile. Fix a problem to compile in Suse. + * 26.06.06 (Angel Carpintero) + * Added some improvements in Makefile. Fix a problem to compile in Suse. * * - * 02.11.06 (Angel Carpintero) - * 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 + * 02.11.06 (Angel Carpintero) + * 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) - * 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 + * 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 - * video_device struct, added param debug. + * 17.08.08 (Angel Carpintero) + * kill_proc() deprecated ,pid API changed , type and owner not available in + * video_device struct, added param debug. + * + * 24.08.08 (Angel Carpintero) + * Added compat_iotcl32 init in fopsl, replace tabs by 4 spaces in source code, + * add number of buffers as module param. */ #define VLOOPBACK_VERSION "1.2-trunk" /* Include files common to 2.4 and 2.6 versions */ -#include <linux/version.h> /* >= 2.6.14 LINUX_VERSION_CODE */ +#include <linux/version.h> /* >= 2.6.14 LINUX_VERSION_CODE */ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> @@ -167,12 +171,12 @@ #include <asm/page.h> #include <asm/pgtable.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) - #ifndef remap_pfn_range - #define remap_pfn_range(a,b,c,d,e) \ - remap_page_range((a),(b),(c)<<PAGE_SHIFT,(d),(e)) + #ifndef remap_pfn_range + #define remap_pfn_range(a,b,c,d,e) \ + remap_page_range((a),(b),(c)<<PAGE_SHIFT,(d),(e)) #endif - #ifndef vmalloc_to_pfn - #define vmalloc_to_pfn(a) page_to_pfn(vmalloc_to_page((a))) + #ifndef vmalloc_to_pfn + #define vmalloc_to_pfn(a) page_to_pfn(vmalloc_to_page((a))) #endif #endif #include <asm/uaccess.h> @@ -185,7 +189,7 @@ #include <asm/io.h> #endif -#define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) +#define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) #define verbose(format, arg...) if (printk_ratelimit()) \ printk(KERN_INFO "[%s] %s: " format "\n" "", \ @@ -201,47 +205,48 @@ #define LOG_VERBOSE 3 struct vloopback_private { - int pipenr; - int in; /* bool , is being feed ? */ + int pipenr; + int in; /* bool , is being feed ? */ }; typedef struct vloopback_private *priv_ptr; struct vloopback_pipe { - struct video_device *vloopin; - struct video_device *vloopout; - char *buffer; - unsigned long buflength; - unsigned int width, height; - unsigned int palette; - unsigned long frameswrite; - unsigned long framesread; - unsigned long framesdumped; - unsigned int wopen; - unsigned int ropen; - struct semaphore lock; - wait_queue_head_t wait; - unsigned int frame; + struct video_device *vloopin; + struct video_device *vloopout; + char *buffer; + unsigned long buflength; + unsigned int width, height; + unsigned int palette; + unsigned long frameswrite; + unsigned long framesread; + unsigned long framesdumped; + unsigned int wopen; + unsigned int ropen; + struct semaphore lock; + wait_queue_head_t wait; + unsigned int frame; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - unsigned int pid; + unsigned int pid; #else struct pid *pid; #endif - unsigned int zerocopy; - unsigned long int ioctlnr; - unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ - unsigned int ioctllength; - char *ioctldata; - char *ioctlretdata; + unsigned int zerocopy; + unsigned long int ioctlnr; + unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ + unsigned int ioctllength; + char *ioctldata; + char *ioctlretdata; }; #define MAX_PIPES 16 -#define N_BUFFS 2 /* Number of buffers used for pipes */ +#define N_BUFFS 2 /* Number of buffers used for pipes */ static struct vloopback_pipe *loops[MAX_PIPES]; static int nr_o_pipes = 0; static int pipes = -1; static int spares = 0; +static unsigned int num_buffers = N_BUFFS; static int pipesused = 0; static int dev_offset = -1; static unsigned int debug = LOG_NODEBUG; @@ -260,62 +265,62 @@ { unsigned long kva; - kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); - kva |= adr & (PAGE_SIZE-1); /* restore the offset */ - return __pa(kva); + kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + return __pa(kva); } #endif static void *rvmalloc(unsigned long size) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - struct page *page; + struct page *page; #endif - void *mem; - unsigned long adr; + void *mem; + unsigned long adr; - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - page = vmalloc_to_page((void *)adr); - mem_map_reserve(page); + page = vmalloc_to_page((void *)adr); + mem_map_reserve(page); #else - SetPageReserved(vmalloc_to_page((void *)adr)); + SetPageReserved(vmalloc_to_page((void *)adr)); #endif - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } - return mem; + return mem; } static void rvfree(void *mem, unsigned long size) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - struct page *page; + struct page *page; #endif - unsigned long adr; + unsigned long adr; - if (!mem) - return; + if (!mem) + return; - adr = (unsigned long) mem; - while ((long) size > 0) { + adr = (unsigned long) mem; + while ((long) size > 0) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - page = vmalloc_to_page((void *)adr); - mem_map_unreserve(page); + page = vmalloc_to_page((void *)adr); + mem_map_unreserve(page); #else - ClearPageReserved(vmalloc_to_page((void *)adr)); + ClearPageReserved(vmalloc_to_page((void *)adr)); #endif - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); } @@ -323,14 +328,14 @@ static int fake_ioctl(int nr, unsigned long int cmd, void *arg) { - unsigned long fw; + unsigned long fw; if (debug > LOG_NODEBUG) info("Video loopback %d cmd %lu", nr, cmd); - loops[nr]->ioctlnr = cmd; - memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd)); - loops[nr]->ioctllength = _IOC_SIZE(cmd); + loops[nr]->ioctlnr = cmd; + memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd)); + loops[nr]->ioctllength = _IOC_SIZE(cmd); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */ @@ -339,59 +344,59 @@ #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - fw = loops[nr]->frameswrite; - wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); + fw = loops[nr]->frameswrite; + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else - interruptible_sleep_on(&loops[nr]->wait); -#endif - if (cmd & IOC_IN) { - if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) - return 1; - } else { - memcpy (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)); - } - return 0; + interruptible_sleep_on(&loops[nr]->wait); +#endif + if (cmd & IOC_IN) { + if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) + return 1; + } else { + memcpy (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)); + } + return 0; } static int vloopback_open(struct inode *inod, struct file *f) -{ - struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->priv; - int nr = ptr->pipenr; +{ + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; if (debug > LOG_NODEBUG) 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) - return -EINVAL; - - loops[nr]->framesread = 0; - loops[nr]->ropen = 1; - } else { - if (loops[nr]->ropen || loops[nr]->wopen) - return -EBUSY; + /* Only allow a output to be opened if there is someone feeding + * the pipe. + */ + if (!ptr->in) { + if (loops[nr]->buffer == NULL) + return -EINVAL; + + loops[nr]->framesread = 0; + loops[nr]->ropen = 1; + } else { + if (loops[nr]->ropen || loops[nr]->wopen) + return -EBUSY; - loops[nr]->framesdumped = 0; - loops[nr]->frameswrite = 0; - loops[nr]->wopen = 1; - loops[nr]->zerocopy = 0; - loops[nr]->ioctlnr = -1; - pipesused++; - if (nr_o_pipes-pipesused<spares) { - if (!create_pipe(nr_o_pipes)) { - info("Creating extra spare pipe"); - info("Loopback %d registered, input: video%d, output: video%d", - nr_o_pipes, - loops[nr_o_pipes]->vloopin->minor, - loops[nr_o_pipes]->vloopout->minor - ); - nr_o_pipes++; - } - } + loops[nr]->framesdumped = 0; + loops[nr]->frameswrite = 0; + loops[nr]->wopen = 1; + loops[nr]->zerocopy = 0; + loops[nr]->ioctlnr = -1; + pipesused++; + if (nr_o_pipes-pipesused<spares) { + if (!create_pipe(nr_o_pipes)) { + info("Creating extra spare pipe"); + info("Loopback %d registered, input: video%d, output: video%d", + nr_o_pipes, + loops[nr_o_pipes]->vloopin->minor, + loops[nr_o_pipes]->vloopout->minor + ); + nr_o_pipes++; + } + } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) loops[nr]->pid = current->pid; #else @@ -402,238 +407,243 @@ if (debug > LOG_NODEBUG) info("Current pid %d", current->pid); - } - return 0; + } + return 0; } static int vloopback_release(struct inode * inod, struct file *f) { - struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->priv; - int nr = ptr->pipenr; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; if (debug > LOG_NODEBUG) info("Video loopback %d", nr); - if (ptr->in) { - down(&loops[nr]->lock); - if (loops[nr]->buffer && !loops[nr]->ropen) { - rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); - loops[nr]->buffer = NULL; - } - up(&loops[nr]->lock); - loops[nr]->frameswrite++; - if (waitqueue_active(&loops[nr]->wait)) - wake_up(&loops[nr]->wait); + if (ptr->in) { + down(&loops[nr]->lock); + if (loops[nr]->buffer && !loops[nr]->ropen) { + rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); + loops[nr]->buffer = NULL; + } + + up(&loops[nr]->lock); + loops[nr]->frameswrite++; + + if (waitqueue_active(&loops[nr]->wait)) + wake_up(&loops[nr]->wait); - loops[nr]->width = 0; - loops[nr]->height = 0; - loops[nr]->palette = 0; - loops[nr]->wopen = 0; - pipesused--; - } else { - down(&loops[nr]->lock); - if (loops[nr]->buffer && !loops[nr]->wopen) { - rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); - loops[nr]->buffer = NULL; - } - up(&loops[nr]->lock); - loops[nr]->ropen = 0; - if (loops[nr]->zerocopy && loops[nr]->buffer) { - loops[nr]->ioctlnr = 0; - loops[nr]->ioctllength = 0; + loops[nr]->width = 0; + loops[nr]->height = 0; + loops[nr]->palette = 0; + loops[nr]->wopen = 0; + pipesused--; + } else { + down(&loops[nr]->lock); + + if (loops[nr]->buffer && !loops[nr]->wopen) { + rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); + loops[nr]->buffer = NULL; + } + + up(&loops[nr]->lock); + loops[nr]->ropen = 0; + + if (loops[nr]->zerocopy && loops[nr]->buffer) { + loops[nr]->ioctlnr = 0; + loops[nr]->ioctllength = 0; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) kill_proc(loops[nr]->pid, SIGIO, 1); #else kill_pid(loops[nr]->pid, SIGIO, 1); #endif - } - } + } + } - return 0; + return 0; } static ssize_t vloopback_write(struct file *f, const char *buf, size_t count, loff_t *offset) { - struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->priv; - int nr = ptr->pipenr; - unsigned long realcount = count; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + unsigned long realcount = count; if (debug > LOG_IOCTL) info("Video loopback %d", nr); - if (!ptr->in) - return -EINVAL; + if (!ptr->in) + return -EINVAL; - if (loops[nr]->zerocopy) - return -EINVAL; - - 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); - return -EINVAL; - } + if (loops[nr]->zerocopy) + return -EINVAL; + + 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); + return -EINVAL; + } - if (realcount > loops[nr]->buflength) { - realcount = loops[nr]->buflength; - info("Too much data for Video loopback %d ! Only %ld bytes used.", + if (realcount > loops[nr]->buflength) { + realcount = loops[nr]->buflength; + 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, + } + + if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength, buf, realcount)) return -EFAULT; - loops[nr]->frame = 0; - up(&loops[nr]->lock); + loops[nr]->frame = 0; + up(&loops[nr]->lock); - loops[nr]->frameswrite++; - wake_up(&loops[nr]->wait); + loops[nr]->frameswrite++; + wake_up(&loops[nr]->wait); - return realcount; + return realcount; } 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->priv; - int nr = ptr->pipenr; - unsigned long realcount = count; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + unsigned long realcount = count; if (debug > LOG_IOCTL) info("Video loopback %d", nr); - if (loops[nr]->zerocopy) { - if (ptr->in) { - if (realcount > loops[nr]->ioctllength + sizeof(unsigned long int)) - realcount = loops[nr]->ioctllength + sizeof(unsigned long int); + if (loops[nr]->zerocopy) { + if (ptr->in) { + if (realcount > loops[nr]->ioctllength + sizeof(unsigned long int)) + realcount = loops[nr]->ioctllength + sizeof(unsigned long int); - if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int))) - return -EFAULT; + 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, - realcount - sizeof(unsigned long int))) - return -EFAULT; + if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata, + realcount - sizeof(unsigned long int))) + return -EFAULT; - if (loops[nr]->ioctlnr == 0) - loops[nr]->ioctlnr = -1; + if (loops[nr]->ioctlnr == 0) + loops[nr]->ioctlnr = -1; - return realcount; - } else { - struct video_window vidwin; - struct video_mmap vidmmap; - struct video_picture vidpic; - - fake_ioctl(nr, VIDIOCGWIN, &vidwin); - fake_ioctl(nr, VIDIOCGPICT, &vidpic); + return realcount; + } else { + struct video_window vidwin; + struct video_mmap vidmmap; + struct video_picture vidpic; + + fake_ioctl(nr, VIDIOCGWIN, &vidwin); + fake_ioctl(nr, VIDIOCGPICT, &vidpic); - vidmmap.height = vidwin.height; - vidmmap.width = vidwin.width; - vidmmap.format = vidpic.palette; - vidmmap.frame = 0; + vidmmap.height = vidwin.height; + vidmmap.width = vidwin.width; + vidmmap.format = vidpic.palette; + vidmmap.frame = 0; - if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap)) - return 0; + if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap)) + return 0; - if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap)) - return 0; + if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap)) + return 0; - realcount = vidwin.height * vidwin.width * vidpic.depth; - } - } + realcount = vidwin.height * vidwin.width * vidpic.depth; + } + } - if (ptr->in) - return -EINVAL; + if (ptr->in) + return -EINVAL; - if (realcount > loops[nr]->buflength) { - realcount = loops[nr]->buflength; - info("Not so much data in buffer! for Video loopback %d", nr); - } + if (realcount > loops[nr]->buflength) { + realcount = loops[nr]->buflength; + info("Not so much data in buffer! for Video loopback %d", nr); + } - if (!loops[nr]->zerocopy) { + 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); + unsigned long fw = loops[nr]->frameswrite; + + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); #else - interruptible_sleep_on(&loops[nr]->wait); + interruptible_sleep_on(&loops[nr]->wait); #endif - } + } - down(&loops[nr]->lock); - if (!loops[nr]->buffer) { - up(&loops[nr]->lock); - return 0; - } + down(&loops[nr]->lock); + if (!loops[nr]->buffer) { + up(&loops[nr]->lock); + return 0; + } - if (copy_to_user(buf, loops[nr]->buffer, realcount)) - return -EFAULT; + if (copy_to_user(buf, loops[nr]->buffer, realcount)) + return -EFAULT; - up(&loops[nr]->lock); + up(&loops[nr]->lock); - loops[nr]->framesread++; - return realcount; + loops[nr]->framesread++; + return realcount; } 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->priv; - int nr = ptr->pipenr; - unsigned long start = (unsigned long)vma->vm_start; - long size = vma->vm_end - vma->vm_start; - unsigned long page, pos; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + unsigned long start = (unsigned long)vma->vm_start; + long size = vma->vm_end - vma->vm_start; + unsigned long page, pos; if (debug > LOG_NODEBUG) info("Video loopback %d", nr); - down(&loops[nr]->lock); + down(&loops[nr]->lock); - if (ptr->in) { - loops[nr]->zerocopy = 1; + if (ptr->in) { + loops[nr]->zerocopy = 1; - if (loops[nr]->ropen) { - info("Can't change size while opened for read in Video loopback %d", + if (loops[nr]->ropen) { + info("Can't change size while opened for read in Video loopback %d", nr); - up(&loops[nr]->lock); - return -EINVAL; - } + up(&loops[nr]->lock); + return -EINVAL; + } - if (!size) { - up(&loops[nr]->lock); + if (!size) { + up(&loops[nr]->lock); info("Invalid size Video loopback %d", nr); - return -EINVAL; - } + return -EINVAL; + } - if (loops[nr]->buffer) - rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); + if (loops[nr]->buffer) + rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); - loops[nr]->buflength = size; - loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS); - } + loops[nr]->buflength = size; + loops[nr]->buffer = rvmalloc(loops[nr]->buflength * num_buffers); + } if (loops[nr]->buffer == NULL) { - up(&loops[nr]->lock); + up(&loops[nr]->lock); return -EINVAL; - } + } - if (size > (((N_BUFFS * loops[nr]->buflength) + PAGE_SIZE - 1) + if (size > (((num_buffers * loops[nr]->buflength) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - up(&loops[nr]->lock); + up(&loops[nr]->lock); return -EINVAL; - } + } pos = (unsigned long)loops[nr]->buffer; @@ -642,42 +652,42 @@ page = kvirt_to_pa(pos); if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) { #else - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { #endif - up(&loops[nr]->lock); + up(&loops[nr]->lock); return -EAGAIN; - } + } start += PAGE_SIZE; pos += PAGE_SIZE; - size -= PAGE_SIZE; + size -= PAGE_SIZE; } - up(&loops[nr]->lock); + up(&loops[nr]->lock); - return 0; + return 0; } static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, unsigned long arg) { - struct video_device *loopdev = video_devdata(f); - priv_ptr ptr = (priv_ptr)loopdev->priv; - int nr = ptr->pipenr; - int i; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; + int i; if (debug > LOG_NODEBUG) info("Video loopback %d cmd %u", nr, cmd); - if (loops[nr]->zerocopy) { - if (!ptr->in) { - loops[nr]->ioctlnr = cmd; - loops[nr]->ioctllength = _IOC_SIZE(cmd); - /* info("DEBUG: vl_ioctl: !loop->in"); */ - /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ - /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ - if (copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) - return -EFAULT; + if (loops[nr]->zerocopy) { + if (!ptr->in) { + loops[nr]->ioctlnr = cmd; + loops[nr]->ioctllength = _IOC_SIZE(cmd); + /* info("DEBUG: vl_ioctl: !loop->in"); */ + /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ + /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ + if (copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) + return -EFAULT; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) kill_proc(loops[nr]->pid, SIGIO, 1); #else @@ -685,410 +695,414 @@ #endif #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1); + wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1); #else - interruptible_sleep_on(&loops[nr]->wait); -#endif - - if (loops[nr]->invalid_ioctl) { - info ("There was an invalid ioctl in Video loopback %d", nr); + interruptible_sleep_on(&loops[nr]->wait); +#endif + + if (loops[nr]->invalid_ioctl) { + info ("There was an invalid ioctl in Video loopback %d", nr); loops[nr]->invalid_ioctl = 0; - return -ENOTTY; - } + return -ENOTTY; + } - 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))) - return -EINVAL; - - //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); - return 0; - } else { - if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) - return -EFAULT; - //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1"); - return 0; - } - } else { - if ((loops[nr]->ioctlnr != cmd) && (cmd != (VIDIOCSINVALID))) { - /* wrong ioctl */ - info("Wrong IOCTL %u in Video loopback %d", cmd, nr); + 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))) + return -EINVAL; + + //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); + return 0; + } else { + if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) + return -EFAULT; + //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1"); return 0; - } + } + } else { + if ((loops[nr]->ioctlnr != cmd) && (cmd != (VIDIOCSINVALID))) { + /* wrong ioctl */ + info("Wrong IOCTL %u in Video loopback %d", cmd, nr); + return 0; + } - if (cmd == VIDIOCSINVALID) { - loops[nr]->invalid_ioctl = 1; - } else if (copy_from_user(loops[nr]->ioctlretdata, + if (cmd == VIDIOCSINVALID) { + loops[nr]->invalid_ioctl = 1; + } else if (copy_from_user(loops[nr]->ioctlretdata, (void*)arg, loops[nr]->ioctllength)) { - return -EFAULT; - } + return -EFAULT; + } - loops[nr]->ioctlnr = -1; + loops[nr]->ioctlnr = -1; - if (waitqueue_active(&loops[nr]->wait)) - wake_up(&loops[nr]->wait); + if (waitqueue_active(&loops[nr]->wait)) + wake_up(&loops[nr]->wait); - return 0; - } - } + return 0; + } + } - switch(cmd) - { - /* Get capabilities */ - case VIDIOCGCAP: - { - struct video_capability b; - if (ptr->in) { - sprintf(b.name, "Video loopback %d input", nr); - b.type = 0; - } else { - sprintf(b.name, "Video loopback %d output", nr); - b.type = VID_TYPE_CAPTURE; - } + switch(cmd) + { + /* Get capabilities */ + case VIDIOCGCAP: + { + struct video_capability b; + if (ptr->in) { + sprintf(b.name, "Video loopback %d input", nr); + b.type = 0; + } else { + sprintf(b.name, "Video loopback %d output", nr); + b.type = VID_TYPE_CAPTURE; + } - b.channels = 1; - b.audios = 0; - b.maxwidth = loops[nr]->width; - b.maxheight = loops[nr]->height; - b.minwidth = 20; - b.minheight = 20; + b.channels = 1; + b.audios = 0; + b.maxwidth = loops[nr]->width; + b.maxheight = loops[nr]->height; + b.minwidth = 20; + b.minheight = 20; - if (copy_to_user((void*)arg, &b, sizeof(b))) - return -EFAULT; + if (copy_to_user((void*)arg, &b, sizeof(b))) + return -EFAULT; - return 0; - } - /* Get channel info (sources) */ - case VIDIOCGCHAN: - { - struct video_channel v; - if (copy_from_user(&v, (void*)arg, sizeof(v))) - return -EFAULT; + return 0; + } + /* Get channel info (sources) */ + case VIDIOCGCHAN: + { + struct video_channel v; + if (copy_from_user(&v, (void*)arg, sizeof(v))) + return -EFAULT; - if (v.channel != 0) { - info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); - v.channel = 0; - //return -EINVAL; - } + if (v.channel != 0) { + info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); + v.channel = 0; + //return -EINVAL; + } - v.flags = 0; - v.tuners = 0; - v.norm = 0; - v.type = VIDEO_TYPE_CAMERA; - /*strcpy(v.name, "Loopback"); -- tibit */ - strcpy(v.name, "Composite1"); + v.flags = 0; + v.tuners = 0; + v.norm = 0; + v.type = VIDEO_TYPE_CAMERA; + /*strcpy(v.name, "Loopback"); -- tibit */ + strcpy(v.name, "Composite1"); - if (copy_to_user((void*)arg, &v, sizeof(v))) - return -EFAULT; + if (copy_to_user((void*)arg, &v, sizeof(v))) + return -EFAULT; - return 0; - } - /* Set channel */ - case VIDIOCSCHAN: - { - int v; + return 0; + } + /* Set channel */ + case VIDIOCSCHAN: + { + int v; - if (copy_from_user(&v, (void*)arg, sizeof(v))) - return -EFAULT; + if (copy_from_user(&v, (void*)arg, sizeof(v))) + return -EFAULT; - if (v != 0) { - info("VIDIOCSCHAN: Invalid Channel, was %d", v); - return -EINVAL; - } + if (v != 0) { + info("VIDIOCSCHAN: Invalid Channel, was %d", v); + return -EINVAL; + } - return 0; - } - /* Get tuner abilities */ - case VIDIOCGTUNER: - { - struct video_tuner v; + return 0; + } + /* Get tuner abilities */ + case VIDIOCGTUNER: + { + struct video_tuner v; - if (copy_from_user(&v, (void*)arg, sizeof(v)) != 0) - return -EFAULT; + if (copy_from_user(&v, (void*)arg, sizeof(v)) != 0) + return -EFAULT; - if (v.tuner) { - info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); - return -EINVAL; - } + if (v.tuner) { + info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); + return -EINVAL; + } - strcpy(v.name, "Format"); - v.rangelow = 0; - v.rangehigh = 0; - v.flags = 0; - v.mode = VIDEO_MODE_AUTO; + strcpy(v.name, "Format"); + v.rangelow = 0; + v.rangehigh = 0; + v.flags = 0; + v.mode = VIDEO_MODE_AUTO; - if (copy_to_user((void*)arg,&v, sizeof(v)) != 0) - return -EFAULT; + if (copy_to_user((void*)arg,&v, sizeof(v)) != 0) + return -EFAULT; - return 0; - } - /* Get picture properties */ - case VIDIOCGPICT: - { - struct video_picture p; + return 0; + } + /* Get picture properties */ + case VIDIOCGPICT: + { + struct video_picture p; - p.colour = 0x8000; - p.hue = 0x8000; - p.brightness = 0x8000; - p.contrast = 0x8000; - p.whiteness = 0x8000; - p.depth = 0x8000; - p.palette = loops[nr]->palette; + p.colour = 0x8000; + p.hue = 0x8000; + p.brightness = 0x8000; + p.contrast = 0x8000; + p.whiteness = 0x8000; + p.depth = 0x8000; + p.palette = loops[nr]->palette; - if (copy_to_user((void*)arg, &p, sizeof(p))) - return -EFAULT; + if (copy_to_user((void*)arg, &p, sizeof(p))) + return -EFAULT; - return 0; - } - /* Set picture properties */ - case VIDIOCSPICT: - { - struct video_picture p; + return 0; + } + /* Set picture properties */ + case VIDIOCSPICT: + { + struct video_picture p; - if (copy_from_user(&p, (void*)arg, sizeof(p))) - return -EFAULT; + if (copy_from_user(&p, (void*)arg, sizeof(p))) + return -EFAULT; - if (!ptr->in) { - if (p.palette != loops[nr]->palette) - return -EINVAL; - } else { - loops[nr]->palette = p.palette; + if (!ptr->in) { + if (p.palette != loops[nr]->palette) + return -EINVAL; + } else { + loops[nr]->palette = p.palette; } - return 0; - } - /* Get the video overlay window */ - case VIDIOCGWIN: - { - struct video_window vw; + return 0; + } + /* Get the video overlay window */ + case VIDIOCGWIN: + { + struct video_window vw; - vw.x = 0; - vw.y = 0; - vw.width = loops[nr]->width; - vw.height = loops[nr]->height; - vw.chromakey = 0; - vw.flags = 0; - vw.clipcount = 0; + vw.x = 0; + vw.y = 0; + vw.width = loops[nr]->width; + vw.height = loops[nr]->height; + vw.chromakey = 0; + vw.flags = 0; + vw.clipcount = 0; - if (copy_to_user((void*)arg, &vw, sizeof(vw))) - return -EFAULT; - - return 0; - } - /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ - case VIDIOCSWIN: - { - struct video_window vw; - - if (copy_from_user(&vw, (void*)arg, sizeof(vw))) - return -EFAULT; + if (copy_to_user((void*)arg, &vw, sizeof(vw))) + return -EFAULT; - if (vw.flags) - return -EINVAL; - - if (vw.clipcount) - return -EINVAL; - - if (loops[nr]->height == vw.height && - loops[nr]->width == vw.width) - return 0; + return 0; + } + /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ + case VIDIOCSWIN: + { + struct video_window vw; + + if (copy_from_user(&vw, (void*)arg, sizeof(vw))) + return -EFAULT; - if (!ptr->in) { - return -EINVAL; - } else { - loops[nr]->height = vw.height; - loops[nr]->width = vw.width; - /* Make sure nobody is using the buffer while we - fool around with it. - We are also not allowing changes while - somebody using mmap has the output open. - */ - down(&loops[nr]->lock); - if (loops[nr]->ropen) { - info("Can't change size while opened for read"); - up(&loops[nr]->lock); - return -EINVAL; - } + if (vw.flags) + return -EINVAL; - if (loops[nr]->buffer) - rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); + if (vw.clipcount) + return -EINVAL; + + if (loops[nr]->height == vw.height && + loops[nr]->width == vw.width) + return 0; - loops[nr]->buflength = vw.width * vw.height * 4; - loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS); - up(&loops[nr]->lock); - } - return 0; - } - /* Memory map buffer info */ - case VIDIOCGMBUF: - { - struct video_mbuf vm; - - vm.size = loops[nr]->buflength * N_BUFFS; - vm.frames = N_BUFFS; - for (i = 0; i < vm.frames; i++) - vm.offsets[i] = i * loops[nr]->buflength; + if (!ptr->in) { + return -EINVAL; + } else { + loops[nr]->height = vw.height; + loops[nr]->width = vw.width; + /* Make sure nobody is using the buffer while we + fool around with it. + We are also not allowing changes while + somebody using mmap has the output open. + */ + down(&loops[nr]->lock); + if (loops[nr]->ropen) { + info("Can't change size while opened for read"); + up(&loops[nr]->lock); + return -EINVAL; + } - if (copy_to_user((void*)arg, &vm, sizeof(vm))) - return -EFAULT; - - return 0; - } - /* Grab frames */ - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - - if (ptr->in) - return -EINVAL; + if (loops[nr]->buffer) + rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); - if (!loops[nr]->buffer) - return -EINVAL; - - if (copy_from_user(&vm, (void*)arg, sizeof(vm))) - return -EFAULT; - - if (vm.format != loops[nr]->palette) - return -EINVAL; - - if (vm.frame > N_BUFFS) - return -EINVAL; + loops[nr]->buflength = vw.width * vw.height * 4; + loops[nr]->buffer = rvmalloc(loops[nr]->buflength * num_buffers); + up(&loops[nr]->lock); + } + return 0; + } + /* Memory map buffer info */ + case VIDIOCGMBUF: + { + struct video_mbuf vm; + + vm.size = loops[nr]->buflength * num_buffers; + vm.frames = num_buffers; + for (i = 0; i < vm.frames; i++) + vm.offsets[i] = i * loops[nr]->buflength; - return 0; - } - /* Sync with mmap grabbing */ - case VIDIOCSYNC: - { - int frame; - unsigned long fw; - - if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) - return -EFAULT; + if (copy_to_user((void*)arg, &vm, sizeof(vm))) + return -EFAULT; - if (ptr->in) - return -EINVAL; + return 0; + } + /* Grab frames */ + case VIDIOCMCAPTURE: + { + struct video_mmap vm; - if (!loops[nr]->buffer) - return -EINVAL; + if (ptr->in) + return -EINVAL; - /* Ok, everything should be alright since the program - should have called VIDIOMCAPTURE and we are ready to - do the 'capturing' */ - if (frame > 1) + if (!loops[nr]->buffer) return -EINVAL; - loops[nr]->frame = frame; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - fw = loops[nr]->frameswrite; - wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); -#else - interruptible_sleep_on(&loops[nr]->wait); -#endif - if (!loops[nr]->buffer) /* possibly released during sleep */ - return -EINVAL; + if (copy_from_user(&vm, (void*)arg, sizeof(vm))) + return -EFAULT; + + if (vm.format != loops[nr]->palette) + return -EINVAL; + + if (vm.frame > num_buffers) + return -EINVAL; - loops[nr]->framesread++; + return 0; + } + /* Sync with mmap grabbing */ + case VIDIOCSYNC: + { + int frame; + unsigned long fw; + + if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) + return -EFAULT; - return 0; - } - /* Get attached units */ - case VIDIOCGUNIT: - { - struct video_unit vu; - - if (ptr->in) - vu.video = loops[nr]->vloopout->minor; - else - vu.video = loops[nr]->vloopin->minor; + if (ptr->in) + return -EINVAL; + + if (!loops[nr]->buffer) + return -EINVAL; + + /* Ok, everything should be alright since the program + should have called VIDIOMCAPTURE and we are ready to + do the 'capturing' */ + //if (frame > 1) + if (frame > num_buffers-1) + return -EINVAL; + + loops[nr]->frame = frame; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + fw = loops[nr]->frameswrite; + wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); +#else + interruptible_sleep_on(&loops[nr]->wait); +#endif + if (!loops[nr]->buffer) /* possibly released during sleep */ + return -EINVAL; + + loops[nr]->framesread++; - vu.vbi = VIDEO_NO_UNIT; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; + return 0; + } + /* Get attached units */ + case VIDIOCGUNIT: + { + struct video_unit vu; + + if (ptr->in) + vu.video = loops[nr]->vloopout->minor; + else + vu.video = loops[nr]->vloopin->minor; - if (copy_to_user((void*)arg, &vu, sizeof(vu))) - return -EFAULT; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; - return 0; - } - /* Get frame buffer */ - case VIDIOCGFBUF: - { - struct video_buffer vb; + if (copy_to_user((void*)arg, &vu, sizeof(vu))) + return -EFAULT; - memset(&vb, 0, sizeof(vb)); - vb.base = NULL; + return 0; + } + /* Get frame buffer */ + case VIDIOCGFBUF: + { + struct video_buffer vb; - if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) - return -EFAULT; + memset(&vb, 0, sizeof(vb)); + vb.base = NULL; - return 0; - } - /* Start, end capture */ - case VIDIOCCAPTURE: - { - int start; + if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) + return -EFAULT; - if (copy_from_user(&start, (void*)arg, sizeof(int))) - return -EFAULT; + return 0; + } + /* Start, end capture */ + case VIDIOCCAPTURE: + { + int start; - if (start) { + if (copy_from_user(&start, (void*)arg, sizeof(int))) + return -EFAULT; + + if (start) { info ("Video loopback %d Capture started", nr); } else { info ("Video loopback %d Capture stopped", nr); } - return 0; - } - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - case VIDIOCKEY: - return 0; - default: - return -ENOTTY; - //return -ENOIOCTLCMD; - } - return 0; + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return -EINVAL; + case VIDIOCKEY: + return 0; + default: + return -ENOTTY; + //return -ENOIOCTLCMD; + } + return 0; } 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->priv; - int nr = ptr->pipenr; + struct video_device *loopdev = video_devdata(f); + priv_ptr ptr = (priv_ptr)loopdev->priv; + int nr = ptr->pipenr; if (debug > LOG_NODEBUG) info("Video loopback %d", nr); - if (loopdev == NULL) - return -EFAULT; + if (loopdev == NULL) + return -EFAULT; - if (!ptr->in) - return 0; + if (!ptr->in) + return 0; - if (loops[nr]->ioctlnr != -1) { - if (loops[nr]->zerocopy) { - return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM); - } else { - return (POLLOUT); - } - } - return 0; + if (loops[nr]->ioctlnr != -1) { + if (loops[nr]->zerocopy) { + return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM); + } else { + return (POLLOUT); + } + } + return 0; } static struct file_operations fileops_template = { - owner: THIS_MODULE, - open: vloopback_open, - release: vloopback_release, - read: vloopback_read, - write: vloopback_write, - poll: vloopback_poll, - ioctl: vloopback_ioctl, - mmap: vloopback_mmap, + owner: THIS_MODULE, + open: vloopback_open, + release: vloopback_release, + read: vloopback_read, + write: vloopback_write, + poll: vloopback_poll, + ioctl: vloopback_ioctl, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) + compat_ioctl: v4l_compat_ioctl32, +#endif + mmap: vloopback_mmap, }; static struct video_device vloopback_template = @@ -1098,126 +1112,126 @@ type: VID_TYPE_CAPTURE, #endif minor: -1, - name: "Video Loopback", - fops: &fileops_template, + name: "Video Loopback", + fops: &fileops_template, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - release: video_device_release, + release: video_device_release, #endif }; static int create_pipe(int nr) { - int minor_in, minor_out , ret; + int minor_in, minor_out , ret; if (debug > LOG_NODEBUG) info("Video loopback %d", nr); - if (dev_offset == -1) { - minor_in = minor_out = -1; /* autoassign */ + if (dev_offset == -1) { + minor_in = minor_out = -1; /* autoassign */ } else { - minor_in = 2 * nr + dev_offset; - minor_out = 2 * nr + 1 + dev_offset; - } + minor_in = 2 * nr + dev_offset; + minor_out = 2 * nr + 1 + dev_offset; + } - /* allocate space for this pipe */ - loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); + /* allocate space for this pipe */ + loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); - if (!loops[nr]) - return -ENOMEM; - /* set up a new video device plus our private area */ - loops[nr]->vloopin = video_device_alloc(); + if (!loops[nr]) + return -ENOMEM; + /* set up a new video device plus our private area */ + loops[nr]->vloopin = video_device_alloc(); - if (loops[nr]->vloopin == NULL) - return -ENOMEM; - *loops[nr]->vloopin = vloopback_template; - loops[nr]->vloopin->priv = kmalloc(sizeof(struct vloopback_private), - GFP_KERNEL); - if (loops[nr]->vloopin->priv == NULL) { - kfree(loops[nr]->vloopin); - return -ENOMEM; - } - /* repeat for the output device */ - loops[nr]->vloopout = video_device_alloc(); + if (loops[nr]->vloopin == NULL) + return -ENOMEM; + *loops[nr]->vloopin = vloopback_template; + loops[nr]->vloopin->priv = kmalloc(sizeof(struct vloopback_private), + GFP_KERNEL); + if (loops[nr]->vloopin->priv == NULL) { + kfree(loops[nr]->vloopin); + return -ENOMEM; + } + /* repeat for the output device */ + loops[nr]->vloopout = video_device_alloc(); - if (loops[nr]->vloopout == NULL) { - kfree(loops[nr]->vloopin->priv); - kfree(loops[nr]->vloopin); - return -ENOMEM; - } - *loops[nr]->vloopout = vloopback_template; - loops[nr]->vloopout->priv = kmalloc(sizeof(struct vloopback_private), - GFP_KERNEL); + if (loops[nr]->vloopout == NULL) { + kfree(loops[nr]->vloopin->priv); + kfree(loops[nr]->vloopin); + return -ENOMEM; + } + *loops[nr]->vloopout = vloopback_template; + loops[nr]->vloopout->priv = kmalloc(sizeof(struct vloopback_private), + GFP_KERNEL); - if (loops[nr]->vloopout->priv == NULL) { - kfree(loops[nr]->vloopin->priv); - kfree(loops[nr]->vloopin); - kfree(loops[nr]->vloopout); - return -ENOMEM; - } + if (loops[nr]->vloopout->priv == NULL) { + kfree(loops[nr]->vloopin->priv); + kfree(loops[nr]->vloopin); + kfree(loops[nr]->vloopout); + return -ENOMEM; + } - ((priv_ptr)loops[nr]->vloopin->priv)->pipenr = nr; - ((priv_ptr)loops[nr]->vloopout->priv)->pipenr = nr; - loops[nr]->invalid_ioctl = 0; /* tibit */ - loops[nr]->buffer = NULL; - loops[nr]->width = 0; - loops[nr]->height = 0; - loops[nr]->palette = 0; - loops[nr]->frameswrite = 0; - loops[nr]->framesread = 0; - loops[nr]->framesdumped = 0; - loops[nr]->wopen = 0; - loops[nr]->ropen = 0; - loops[nr]->frame = 0; - - ((priv_ptr)loops[nr]->vloopin->priv)->in = 1; - ((priv_ptr)loops[nr]->vloopout->priv)->in = 0; + ((priv_ptr)loops[nr]->vloopin->priv)->pipenr = nr; + ((priv_ptr)loops[nr]->vloopout->priv)->pipenr = nr; + loops[nr]->invalid_ioctl = 0; /* tibit */ + loops[nr]->buffer = NULL; + loops[nr]->width = 0; + loops[nr]->height = 0; + loops[nr]->palette = 0; + loops[nr]->frameswrite = 0; + loops[nr]->framesread = 0; + loops[nr]->framesdumped = 0; + loops[nr]->wopen = 0; + loops[nr]->ropen = 0; + loops[nr]->frame = 0; + + ((priv_ptr)loops[nr]->vloopin->priv)->in = 1; + ((priv_ptr)loops[nr]->vloopout->priv)->in = 0; sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - loops[nr]->vloopin->type = 0; - loops[nr]->vloopout->type = VID_TYPE_CAPTURE; + loops[nr]->vloopin->type = 0; + loops[nr]->vloopout->type = VID_TYPE_CAPTURE; #endif loops[nr]->vloopout->minor = minor_out; loops[nr]->vloopin->minor = minor_in; - 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->priv); - kfree(loops[nr]->vloopin); - kfree(loops[nr]->vloopout->priv); - 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->priv); - video_unregister_device(loops[nr]->vloopin); - kfree(loops[nr]->vloopout->priv); - 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; + 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->priv); + kfree(loops[nr]->vloopin); + kfree(loops[nr]->vloopout->priv); + 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->priv); + video_unregister_device(loops[nr]->vloopin); + kfree(loops[nr]->vloopout->priv); + 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; } /**************************************************************************** - * init stuff + * init stuff ****************************************************************************/ @@ -1230,7 +1244,7 @@ MODULE_PARM(pipes, "i"); #endif -MODULE_PARM_DESC(pipes, "Nr of pipes to create (each pipe uses two video devices)"); +MODULE_PARM_DESC(pipes, " Nr of pipes to create (each pipe uses two video devices)"); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) module_param(spares, int, 000); @@ -1238,7 +1252,16 @@ MODULE_PARM(spares, "i"); #endif -MODULE_PARM_DESC(spares, "Nr of spare pipes that should be created"); +MODULE_PARM_DESC(spares, " Nr of spare pipes that should be created"); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +module_param(num_buffers, int, 000); +#else +MODULE_PARM(num_buffers, "i"); +#endif + +MODULE_PARM_DESC(num_buffers, " Prefered numbers of internal buffers to map (default 2)"); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) module_param(dev_offset, int, 000); @@ -1246,7 +1269,7 @@ MODULE_PARM(dev_offset_param, "i"); #endif -MODULE_PARM_DESC(dev_offset, "Prefered offset for video device numbers"); +MODULE_PARM_DESC(dev_offset, " Prefered offset for video device numbers"); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) @@ -1255,62 +1278,68 @@ MODULE_PARM(debug_param, "i"); #endif -MODULE_PARM_DESC(debug, "Enable module debug level 0-3 (by default 0)"); +MODULE_PARM_DESC(debug, " Enable module debug level 0-3 (by default 0)"); MODULE_LICENSE("GPL"); MODULE_VERSION( VLOOPBACK_VERSION ); static int __init vloopback_init(void) { - int i,ret; + int i, ret; - info("video4linux loopback driver v"VLOOPBACK_VERSION); + info("video4linux loopback driver v"VLOOPBACK_VERSION); - if (pipes == -1) + if (pipes == -1) pipes = 1; - if (pipes > MAX_PIPES) { - pipes = MAX_PIPES; - info("Nr of pipes is limited to: %d", MAX_PIPES); - } + if (pipes > MAX_PIPES) { + pipes = MAX_PIPES; + info("Nr of pipes is limited to: %d", MAX_PIPES); + } - for (i = 0; i < pipes; i++) { - - ret = create_pipe(i); + if (num_buffers < N_BUFFS) { + num_buffers = N_BUFFS; + info("Nr of buffer set to default value %d", N_BUFFS); + } - if (ret == 0) { - info("Loopback %d registered, input: video%d," - " output: video%d", - i, loops[i]->vloopin->minor, - loops[i]->vloopout->minor); - nr_o_pipes = i + 1; - } else { - return ret; - } - } - return 0; + 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 , Using %d buffers", i, num_buffers); + nr_o_pipes = i + 1; + } else { + return ret; + } + } + return 0; } static void __exit cleanup_vloopback_module(void) { - int i; + int i; - info("Unregistering video4linux loopback devices"); + info("Unregistering video4linux loopback devices"); for (i = 0; i < nr_o_pipes; i++) { if (loops[i]) { - kfree(loops[i]->vloopin->priv); - video_unregister_device(loops[i]->vloopin); - kfree(loops[i]->vloopout->priv); - video_unregister_device(loops[i]->vloopout); - + kfree(loops[i]->vloopin->priv); + video_unregister_device(loops[i]->vloopin); + kfree(loops[i]->vloopout->priv); + video_unregister_device(loops[i]->vloopout); + if (loops[i]->buffer) - rvfree(loops[i]->buffer, loops[i]->buflength * N_BUFFS); + rvfree(loops[i]->buffer, loops[i]->buflength * num_buffers); - kfree(loops[i]->ioctldata); - kfree(loops[i]->ioctlretdata); - kfree(loops[i]); - } + kfree(loops[i]->ioctldata); + kfree(loops[i]->ioctlretdata); + kfree(loops[i]); + } } }