Mercurial > vloopback
comparison vloopback.c @ 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 | bce647a9dd4b |
comparison
equal
deleted
inserted
replaced
| 7:2fce9e157b8d | 8:80590d10a596 |
|---|---|
| 1 /* | 1 /* |
| 2 * vloopback.c | 2 * vloopback.c |
| 3 * | 3 * |
| 4 * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2000 | 4 * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2000 |
| 5 * Additional copyright by the contributing authors in the | 5 * Additional copyright by the contributing authors in the |
| 6 * change history below, 2000-2007 | 6 * change history below, 2000-2007 |
| 7 * | 7 * |
| 8 * Published under the GNU Public License. | 8 * Published under the GNU Public License. |
| 9 * | 9 * |
| 10 * The Video loopback Loopback Device is no longer systematically maintained. | 10 * The Video loopback Loopback Device is no longer systematically maintained. |
| 11 * The project is a secondary project for the project "motion" found at | 11 * The project is a secondary project for the project "motion" found at |
| 12 * http://motion.sourceforge.net/ and | 12 * http://motion.sourceforge.net/ and |
| 13 * http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome | 13 * http://www.lavrsen.dk/twiki/bin/view/Motion/WebHome |
| 14 * and with the vloopback stored at | 14 * and with the vloopback stored at |
| 15 * http://www.lavrsen.dk/twiki/bin/view/Motion/Video loopbackFourLinuxLoopbackDevice | 15 * http://www.lavrsen.dk/twiki/bin/view/Motion/Video loopbackFourLinuxLoopbackDevice |
| 16 * | 16 * |
| 17 * CHANGE HISTORY | 17 * CHANGE HISTORY |
| 18 * | 18 * |
| 19 * UPDATED: Jeroen Vreeken. | 19 * UPDATED: Jeroen Vreeken. |
| 20 * Added locks for smp machines. UNTESTED! | 20 * Added locks for smp machines. UNTESTED! |
| 21 * Made the driver much more cpu friendly by using | 21 * Made the driver much more cpu friendly by using |
| 22 * a wait queue. | 22 * a wait queue. |
| 23 * Went from vmalloc to rvmalloc (yes, I stole the code | 23 * Went from vmalloc to rvmalloc (yes, I stole the code |
| 24 * like everybody else) and implemented mmap. | 24 * like everybody else) and implemented mmap. |
| 25 * Implemented VIDIOCGUNIT and removed size/palette checks | 25 * Implemented VIDIOCGUNIT and removed size/palette checks |
| 26 * in VIDIOCSYNC. | 26 * in VIDIOCSYNC. |
| 27 * Cleaned up a lot of code. | 27 * Cleaned up a lot of code. |
| 28 * Changed locks to semaphores. | 28 * Changed locks to semaphores. |
| 29 * Disabled changing size while somebody is using mmap | 29 * Disabled changing size while somebody is using mmap |
| 30 * Changed mapped check to open check, also don't allow | 30 * Changed mapped check to open check, also don't allow |
| 31 * a open for write while somebody is reading. | 31 * a open for write while somebody is reading. |
| 32 * Added /proc support | 32 * Added /proc support |
| 33 * Set dumped count to zero at open. | 33 * Set dumped count to zero at open. |
| 34 * Modified /proc layout (added vloopbacks entry) | 34 * Modified /proc layout (added vloopbacks entry) |
| 35 * | 35 * |
| 36 * 05.10.00 (MTS) Added Linux 2.2 support | 36 * 05.10.00 (MTS) Added Linux 2.2 support |
| 37 * 06.10.00 (J Vreeken) Fixed 2.2 support to make things work under 2.4 again. | 37 * 06.10.00 (J Vreeken) Fixed 2.2 support to make things work under 2.4 again. |
| 38 * 17.10.00 (J Vreeken) Added zero copy mode | 38 * 17.10.00 (J Vreeken) Added zero copy mode |
| 39 * 19.10.00 (J Vreeken) Added SIGIO on device close. | 39 * 19.10.00 (J Vreeken) Added SIGIO on device close. |
| 40 * 24.10.00 (J Vreeken) Modified 2.2 stuff and removed spinlock.h | 40 * 24.10.00 (J Vreeken) Modified 2.2 stuff and removed spinlock.h |
| 41 * released 0.81 | 41 * released 0.81 |
| 42 * 27.10.00 (J Vreeken) Implemented poll | 42 * 27.10.00 (J Vreeken) Implemented poll |
| 43 * released 0.82 | 43 * released 0.82 |
| 44 * 17.01.01 (J Vreeken) support for xawtv | 44 * 17.01.01 (J Vreeken) support for xawtv |
| 45 * Implemented VIDIOCGFBUF | 45 * Implemented VIDIOCGFBUF |
| 46 * Additional checks on framebuffer freeing. | 46 * Additional checks on framebuffer freeing. |
| 47 * released 0.83 | 47 * released 0.83 |
| 48 * 31.01.01 (J Vreeken) Removed need for 'struct ioctl', use _IOC_SIZE() and | 48 * 31.01.01 (J Vreeken) Removed need for 'struct ioctl', use _IOC_SIZE() and |
| 49 * IOC_IN instead. | 49 * IOC_IN instead. |
| 50 * Change the ioctlnr passing to 'unsigned long int' | 50 * Change the ioctlnr passing to 'unsigned long int' |
| 51 * Instead of just one byte. | 51 * Instead of just one byte. |
| 52 * THIS BREAKS COMPATIBILITY WITH PREVIOUS VERSIONS!!! | 52 * THIS BREAKS COMPATIBILITY WITH PREVIOUS VERSIONS!!! |
| 53 * 29.06.01 (J Vreeken) Added dev_offset module option | 53 * 29.06.01 (J Vreeken) Added dev_offset module option |
| 54 * Made vloopback_template sane | 54 * Made vloopback_template sane |
| 55 * Added double buffering support | 55 * Added double buffering support |
| 56 * Made vloopback less verbose | 56 * Made vloopback less verbose |
| 57 * 20.11.01 (tibit) Made dev_offset option sane | 57 * 20.11.01 (tibit) Made dev_offset option sane |
| 58 * "Fixed" zerocopy mode by defining the ioctl | 58 * "Fixed" zerocopy mode by defining the ioctl |
| 59 * VIDIOCSINVALID. An application which provides data | 59 * VIDIOCSINVALID. An application which provides data |
| 60 * has to issue it when it encounters an error in | 60 * has to issue it when it encounters an error in |
| 61 * ioctl processing. See dummy.c for examples. | 61 * ioctl processing. See dummy.c for examples. |
| 62 * 26.11.03 (Kenneth Lavrsen) | 62 * 26.11.03 (Kenneth Lavrsen) |
| 63 * released 0.91 | 63 * released 0.91 |
| 64 * 0.91 is the combination of the 0.90-tibit by | 64 * 0.91 is the combination of the 0.90-tibit by |
| 65 * Tilmann Bitterberg and an update of the Makefile by | 65 * Tilmann Bitterberg and an update of the Makefile by |
| 66 * Roberto Carvajal. | 66 * Roberto Carvajal. |
| 67 * 23.01.05 (W Brack) | 67 * 23.01.05 (W Brack) |
| 68 * (don't know what happened to the comments for 0.92 | 68 * (don't know what happened to the comments for 0.92 |
| 69 * and 0.93, but I tentatively named this one as 0.99) | 69 * and 0.93, but I tentatively named this one as 0.99) |
| 70 * enhanced for linux-2.6, with #ifdef to keep it | 70 * enhanced for linux-2.6, with #ifdef to keep it |
| 71 * compatible with linux-2.4. For linux versions | 71 * compatible with linux-2.4. For linux versions |
| 72 * > 2.5, I changed the memory management | 72 * > 2.5, I changed the memory management |
| 73 * routines to the "more modern" way, most of it | 73 * routines to the "more modern" way, most of it |
| 74 * shamelessly copied from other drivers. I also | 74 * shamelessly copied from other drivers. I also |
| 75 * added in the code necessary to avoid the "videodev | 75 * added in the code necessary to avoid the "videodev |
| 76 * has no release callback" message when installing. | 76 * has no release callback" message when installing. |
| 77 * For versions < 2.5, I updated the routines to be | 77 * For versions < 2.5, I updated the routines to be |
| 78 * closer to several other drivers. | 78 * closer to several other drivers. |
| 79 * | 79 * |
| 80 * 04.02.05 (Angel Carpintero) | 80 * 04.02.05 (Angel Carpintero) |
| 81 * Fixed version number to 0.93-pre1. | 81 * Fixed version number to 0.93-pre1. |
| 82 * Fixed warning for interruptible_sleep_on() deprecated and added | 82 * Fixed warning for interruptible_sleep_on() deprecated and added |
| 83 * wait_event_interruptible compatible with 2.6.x and 2.7. | 83 * wait_event_interruptible compatible with 2.6.x and 2.7. |
| 84 * Fixed memory manager for kernel version > 2.6.9. | 84 * Fixed memory manager for kernel version > 2.6.9. |
| 85 * | 85 * |
| 86 * 07.02.05 (Kenneth Lavrsen) | 86 * 07.02.05 (Kenneth Lavrsen) |
| 87 * Changed version to 0.94. | 87 * Changed version to 0.94. |
| 88 * Released as formal released version | 88 * Released as formal released version |
| 89 * | 89 * |
| 90 * 20.02.05 (W Brack) | 90 * 20.02.05 (W Brack) |
| 91 * Fixed error with wait_event_interruptible. | 91 * Fixed error with wait_event_interruptible. |
| 92 * Fixed crash when pipe source was stopped before dest. | 92 * Fixed crash when pipe source was stopped before dest. |
| 93 * | 93 * |
| 94 * 20.02.05 (Angel Carpintero) | 94 * 20.02.05 (Angel Carpintero) |
| 95 * Added install and uninstall in Makefile. | 95 * Added install and uninstall in Makefile. |
| 96 * | 96 * |
| 97 * | 97 * |
| 98 * 25.04.05 (Angel Carpintero) | 98 * 25.04.05 (Angel Carpintero) |
| 99 * Included Samuel Audet's patch, it checks if the input is already | 99 * Included Samuel Audet's patch, it checks if the input is already |
| 100 * opened in write mode. | 100 * opened in write mode. |
| 101 * | 101 * |
| 102 * 02.05.05 (Kenneth Lavrsen) | 102 * 02.05.05 (Kenneth Lavrsen) |
| 103 * Released 0.95-snap2 formerly as 0.95 | 103 * Released 0.95-snap2 formerly as 0.95 |
| 104 * | 104 * |
| 105 * 10.05.05 (Angel Carpintero) | 105 * 10.05.05 (Angel Carpintero) |
| 106 * Added MODULE_VERSION(), fixed create_pipes when video_register_device() returns | 106 * Added MODULE_VERSION(), fixed create_pipes when video_register_device() returns |
| 107 * -ENFILE . | 107 * -ENFILE . |
| 108 * Fix warnings about checking return value from copy_to_user() and copy_from_user() functions. | 108 * Fix warnings about checking return value from copy_to_user() and copy_from_user() functions. |
| 109 * | 109 * |
| 110 * 14.11.05 (Angel Carpintero) | 110 * 14.11.05 (Angel Carpintero) |
| 111 * Added <linux/version.h> that includes LINUX_VERSION_CODE and KERNEL_VERSION to fix | 111 * Added <linux/version.h> that includes LINUX_VERSION_CODE and KERNEL_VERSION to fix |
| 112 * compilation agains kernel 2.6.14 , change version to 0.97-snap1 | 112 * compilation agains kernel 2.6.14 , change version to 0.97-snap1 |
| 113 * | 113 * |
| 114 * 19.12.05 (Angel Carpintero) | 114 * 19.12.05 (Angel Carpintero) |
| 115 * Added to example option to choose between rgb24 or yuv420p palettes. | 115 * Added to example option to choose between rgb24 or yuv420p palettes. |
| 116 * | 116 * |
| 117 * 31.12.05 (Angel Carpintero) | 117 * 31.12.05 (Angel Carpintero) |
| 118 * Fixed examples, remove perror calls and add support to dummy.c for sysfs. | 118 * Fixed examples, remove perror calls and add support to dummy.c for sysfs. |
| 119 * | 119 * |
| 120 * 04.06.06 (Angel Carpintero) | 120 * 04.06.06 (Angel Carpintero) |
| 121 * Add module_param() for kernel > 2.5 because MODULE_PARAM() macro is obsolete. | 121 * Add module_param() for kernel > 2.5 because MODULE_PARAM() macro is obsolete. |
| 122 * | 122 * |
| 123 * 17.06.06 (Angel Carpintero) | 123 * 17.06.06 (Angel Carpintero) |
| 124 * Release version 1.0 with some fixes and code clean up. Added a Jack Bates contribution | 124 * Release version 1.0 with some fixes and code clean up. Added a Jack Bates contribution |
| 125 * to allow build a kernel module in debian way. | 125 * to allow build a kernel module in debian way. |
| 126 * | 126 * |
| 127 * 26.06.06 (Angel Carpintero) | 127 * 26.06.06 (Angel Carpintero) |
| 128 * Added some improvements in Makefile. Fix a problem to compile in Suse. | 128 * Added some improvements in Makefile. Fix a problem to compile in Suse. |
| 129 * | 129 * |
| 130 * | 130 * |
| 131 * 02.11.06 (Angel Carpintero) | 131 * 02.11.06 (Angel Carpintero) |
| 132 * Make compatible with new kernel stable version 2.6.18, Many functions and declarations has | 132 * Make compatible with new kernel stable version 2.6.18, Many functions and declarations has |
| 133 * been moved to media/v42l-dev.h and remove from videodev.h/videodev2.h | 133 * been moved to media/v42l-dev.h and remove from videodev.h/videodev2.h |
| 134 * | 134 * |
| 135 * 18.01.07 (Angel Carpintero) | 135 * 18.01.07 (Angel Carpintero) |
| 136 * Change -ENOIOCTLCMD by more appropiate error -ENOTTY. | 136 * Change -ENOIOCTLCMD by more appropiate error -ENOTTY. |
| 137 * | 137 * |
| 138 * 18.05.08 (Angel Carpintero) | 138 * 18.05.08 (Angel Carpintero) |
| 139 * Release 1.1-rc1 as 1.1 stable working with 2.6.24 | 139 * Release 1.1-rc1 as 1.1 stable working with 2.6.24 |
| 140 * | 140 * |
| 141 * 17.08.08 (Angel Carpintero) | 141 * 17.08.08 (Angel Carpintero) |
| 142 * kill_proc() deprecated ,pid API changed , type and owner not available in | 142 * kill_proc() deprecated ,pid API changed , type and owner not available in |
| 143 * video_device struct, added param debug. | 143 * video_device struct, added param debug. |
| 144 * | |
| 145 * 24.08.08 (Angel Carpintero) | |
| 146 * Added compat_iotcl32 init in fopsl, replace tabs by 4 spaces in source code, | |
| 147 * add number of buffers as module param. | |
| 144 */ | 148 */ |
| 145 | 149 |
| 146 | 150 |
| 147 #define VLOOPBACK_VERSION "1.2-trunk" | 151 #define VLOOPBACK_VERSION "1.2-trunk" |
| 148 | 152 |
| 149 /* Include files common to 2.4 and 2.6 versions */ | 153 /* Include files common to 2.4 and 2.6 versions */ |
| 150 #include <linux/version.h> /* >= 2.6.14 LINUX_VERSION_CODE */ | 154 #include <linux/version.h> /* >= 2.6.14 LINUX_VERSION_CODE */ |
| 151 #include <linux/errno.h> | 155 #include <linux/errno.h> |
| 152 #include <linux/kernel.h> | 156 #include <linux/kernel.h> |
| 153 #include <linux/module.h> | 157 #include <linux/module.h> |
| 154 #include <linux/pagemap.h> | 158 #include <linux/pagemap.h> |
| 155 | 159 |
| 165 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 169 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 166 #include <asm/ioctl.h> | 170 #include <asm/ioctl.h> |
| 167 #include <asm/page.h> | 171 #include <asm/page.h> |
| 168 #include <asm/pgtable.h> | 172 #include <asm/pgtable.h> |
| 169 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) | 173 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) |
| 170 #ifndef remap_pfn_range | 174 #ifndef remap_pfn_range |
| 171 #define remap_pfn_range(a,b,c,d,e) \ | 175 #define remap_pfn_range(a,b,c,d,e) \ |
| 172 remap_page_range((a),(b),(c)<<PAGE_SHIFT,(d),(e)) | 176 remap_page_range((a),(b),(c)<<PAGE_SHIFT,(d),(e)) |
| 173 #endif | 177 #endif |
| 174 #ifndef vmalloc_to_pfn | 178 #ifndef vmalloc_to_pfn |
| 175 #define vmalloc_to_pfn(a) page_to_pfn(vmalloc_to_page((a))) | 179 #define vmalloc_to_pfn(a) page_to_pfn(vmalloc_to_page((a))) |
| 176 #endif | 180 #endif |
| 177 #endif | 181 #endif |
| 178 #include <asm/uaccess.h> | 182 #include <asm/uaccess.h> |
| 179 #include <linux/init.h> | 183 #include <linux/init.h> |
| 180 #include <linux/device.h> | 184 #include <linux/device.h> |
| 183 #include <linux/slab.h> | 187 #include <linux/slab.h> |
| 184 #include <linux/wrapper.h> | 188 #include <linux/wrapper.h> |
| 185 #include <asm/io.h> | 189 #include <asm/io.h> |
| 186 #endif | 190 #endif |
| 187 | 191 |
| 188 #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) | 192 #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) |
| 189 | 193 |
| 190 #define verbose(format, arg...) if (printk_ratelimit()) \ | 194 #define verbose(format, arg...) if (printk_ratelimit()) \ |
| 191 printk(KERN_INFO "[%s] %s: " format "\n" "", \ | 195 printk(KERN_INFO "[%s] %s: " format "\n" "", \ |
| 192 __FUNCTION__, __FILE__, ## arg) | 196 __FUNCTION__, __FILE__, ## arg) |
| 193 | 197 |
| 199 #define LOG_FUNCTIONS 1 | 203 #define LOG_FUNCTIONS 1 |
| 200 #define LOG_IOCTL 2 | 204 #define LOG_IOCTL 2 |
| 201 #define LOG_VERBOSE 3 | 205 #define LOG_VERBOSE 3 |
| 202 | 206 |
| 203 struct vloopback_private { | 207 struct vloopback_private { |
| 204 int pipenr; | 208 int pipenr; |
| 205 int in; /* bool , is being feed ? */ | 209 int in; /* bool , is being feed ? */ |
| 206 }; | 210 }; |
| 207 | 211 |
| 208 typedef struct vloopback_private *priv_ptr; | 212 typedef struct vloopback_private *priv_ptr; |
| 209 | 213 |
| 210 struct vloopback_pipe { | 214 struct vloopback_pipe { |
| 211 struct video_device *vloopin; | 215 struct video_device *vloopin; |
| 212 struct video_device *vloopout; | 216 struct video_device *vloopout; |
| 213 char *buffer; | 217 char *buffer; |
| 214 unsigned long buflength; | 218 unsigned long buflength; |
| 215 unsigned int width, height; | 219 unsigned int width, height; |
| 216 unsigned int palette; | 220 unsigned int palette; |
| 217 unsigned long frameswrite; | 221 unsigned long frameswrite; |
| 218 unsigned long framesread; | 222 unsigned long framesread; |
| 219 unsigned long framesdumped; | 223 unsigned long framesdumped; |
| 220 unsigned int wopen; | 224 unsigned int wopen; |
| 221 unsigned int ropen; | 225 unsigned int ropen; |
| 222 struct semaphore lock; | 226 struct semaphore lock; |
| 223 wait_queue_head_t wait; | 227 wait_queue_head_t wait; |
| 224 unsigned int frame; | 228 unsigned int frame; |
| 225 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 229 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 226 unsigned int pid; | 230 unsigned int pid; |
| 227 #else | 231 #else |
| 228 struct pid *pid; | 232 struct pid *pid; |
| 229 #endif | 233 #endif |
| 230 unsigned int zerocopy; | 234 unsigned int zerocopy; |
| 231 unsigned long int ioctlnr; | 235 unsigned long int ioctlnr; |
| 232 unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ | 236 unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ |
| 233 unsigned int ioctllength; | 237 unsigned int ioctllength; |
| 234 char *ioctldata; | 238 char *ioctldata; |
| 235 char *ioctlretdata; | 239 char *ioctlretdata; |
| 236 }; | 240 }; |
| 237 | 241 |
| 238 #define MAX_PIPES 16 | 242 #define MAX_PIPES 16 |
| 239 #define N_BUFFS 2 /* Number of buffers used for pipes */ | 243 #define N_BUFFS 2 /* Number of buffers used for pipes */ |
| 240 | 244 |
| 241 static struct vloopback_pipe *loops[MAX_PIPES]; | 245 static struct vloopback_pipe *loops[MAX_PIPES]; |
| 242 static int nr_o_pipes = 0; | 246 static int nr_o_pipes = 0; |
| 243 static int pipes = -1; | 247 static int pipes = -1; |
| 244 static int spares = 0; | 248 static int spares = 0; |
| 249 static unsigned int num_buffers = N_BUFFS; | |
| 245 static int pipesused = 0; | 250 static int pipesused = 0; |
| 246 static int dev_offset = -1; | 251 static int dev_offset = -1; |
| 247 static unsigned int debug = LOG_NODEBUG; | 252 static unsigned int debug = LOG_NODEBUG; |
| 248 | 253 |
| 249 /********************************************************************** | 254 /********************************************************************** |
| 258 */ | 263 */ |
| 259 static inline unsigned long kvirt_to_pa(unsigned long adr) | 264 static inline unsigned long kvirt_to_pa(unsigned long adr) |
| 260 { | 265 { |
| 261 unsigned long kva; | 266 unsigned long kva; |
| 262 | 267 |
| 263 kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); | 268 kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); |
| 264 kva |= adr & (PAGE_SIZE-1); /* restore the offset */ | 269 kva |= adr & (PAGE_SIZE-1); /* restore the offset */ |
| 265 return __pa(kva); | 270 return __pa(kva); |
| 266 } | 271 } |
| 267 #endif | 272 #endif |
| 268 | 273 |
| 269 static void *rvmalloc(unsigned long size) | 274 static void *rvmalloc(unsigned long size) |
| 270 { | 275 { |
| 271 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 276 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) |
| 272 struct page *page; | 277 struct page *page; |
| 273 #endif | 278 #endif |
| 274 void *mem; | 279 void *mem; |
| 275 unsigned long adr; | 280 unsigned long adr; |
| 276 | 281 |
| 277 size = PAGE_ALIGN(size); | 282 size = PAGE_ALIGN(size); |
| 278 mem = vmalloc_32(size); | 283 mem = vmalloc_32(size); |
| 279 if (!mem) | 284 if (!mem) |
| 280 return NULL; | 285 return NULL; |
| 281 memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | 286 memset(mem, 0, size); /* Clear the ram out, no junk to the user */ |
| 282 adr = (unsigned long) mem; | 287 adr = (unsigned long) mem; |
| 283 while (size > 0) { | 288 while (size > 0) { |
| 284 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 289 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) |
| 285 page = vmalloc_to_page((void *)adr); | 290 page = vmalloc_to_page((void *)adr); |
| 286 mem_map_reserve(page); | 291 mem_map_reserve(page); |
| 287 #else | 292 #else |
| 288 SetPageReserved(vmalloc_to_page((void *)adr)); | 293 SetPageReserved(vmalloc_to_page((void *)adr)); |
| 289 #endif | 294 #endif |
| 290 adr += PAGE_SIZE; | 295 adr += PAGE_SIZE; |
| 291 size -= PAGE_SIZE; | 296 size -= PAGE_SIZE; |
| 292 } | 297 } |
| 293 | 298 |
| 294 return mem; | 299 return mem; |
| 295 } | 300 } |
| 296 | 301 |
| 297 static void rvfree(void *mem, unsigned long size) | 302 static void rvfree(void *mem, unsigned long size) |
| 298 { | 303 { |
| 299 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 304 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) |
| 300 struct page *page; | 305 struct page *page; |
| 301 #endif | 306 #endif |
| 302 unsigned long adr; | 307 unsigned long adr; |
| 303 | 308 |
| 304 if (!mem) | 309 if (!mem) |
| 305 return; | 310 return; |
| 306 | 311 |
| 307 adr = (unsigned long) mem; | 312 adr = (unsigned long) mem; |
| 308 while ((long) size > 0) { | 313 while ((long) size > 0) { |
| 309 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) | 314 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) |
| 310 page = vmalloc_to_page((void *)adr); | 315 page = vmalloc_to_page((void *)adr); |
| 311 mem_map_unreserve(page); | 316 mem_map_unreserve(page); |
| 312 #else | 317 #else |
| 313 ClearPageReserved(vmalloc_to_page((void *)adr)); | 318 ClearPageReserved(vmalloc_to_page((void *)adr)); |
| 314 #endif | 319 #endif |
| 315 adr += PAGE_SIZE; | 320 adr += PAGE_SIZE; |
| 316 size -= PAGE_SIZE; | 321 size -= PAGE_SIZE; |
| 317 } | 322 } |
| 318 vfree(mem); | 323 vfree(mem); |
| 319 } | 324 } |
| 320 | 325 |
| 321 | 326 |
| 322 static int create_pipe(int nr); | 327 static int create_pipe(int nr); |
| 323 | 328 |
| 324 static int fake_ioctl(int nr, unsigned long int cmd, void *arg) | 329 static int fake_ioctl(int nr, unsigned long int cmd, void *arg) |
| 325 { | 330 { |
| 326 unsigned long fw; | 331 unsigned long fw; |
| 327 | 332 |
| 328 if (debug > LOG_NODEBUG) | 333 if (debug > LOG_NODEBUG) |
| 329 info("Video loopback %d cmd %lu", nr, cmd); | 334 info("Video loopback %d cmd %lu", nr, cmd); |
| 330 | 335 |
| 331 loops[nr]->ioctlnr = cmd; | 336 loops[nr]->ioctlnr = cmd; |
| 332 memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd)); | 337 memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd)); |
| 333 loops[nr]->ioctllength = _IOC_SIZE(cmd); | 338 loops[nr]->ioctllength = _IOC_SIZE(cmd); |
| 334 | 339 |
| 335 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 340 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 336 kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */ | 341 kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */ |
| 337 #else | 342 #else |
| 338 kill_pid(loops[nr]->pid, SIGIO, 1); | 343 kill_pid(loops[nr]->pid, SIGIO, 1); |
| 339 #endif | 344 #endif |
| 340 | 345 |
| 341 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 346 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 342 fw = loops[nr]->frameswrite; | 347 fw = loops[nr]->frameswrite; |
| 343 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); | 348 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); |
| 344 #else | 349 #else |
| 345 interruptible_sleep_on(&loops[nr]->wait); | 350 interruptible_sleep_on(&loops[nr]->wait); |
| 346 #endif | 351 #endif |
| 347 if (cmd & IOC_IN) { | 352 if (cmd & IOC_IN) { |
| 348 if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) | 353 if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) |
| 349 return 1; | 354 return 1; |
| 350 } else { | 355 } else { |
| 351 memcpy (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)); | 356 memcpy (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)); |
| 352 } | 357 } |
| 353 return 0; | 358 return 0; |
| 354 } | 359 } |
| 355 | 360 |
| 356 static int vloopback_open(struct inode *inod, struct file *f) | 361 static int vloopback_open(struct inode *inod, struct file *f) |
| 357 { | 362 { |
| 358 struct video_device *loopdev = video_devdata(f); | 363 struct video_device *loopdev = video_devdata(f); |
| 359 priv_ptr ptr = (priv_ptr)loopdev->priv; | 364 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 360 int nr = ptr->pipenr; | 365 int nr = ptr->pipenr; |
| 361 | 366 |
| 362 if (debug > LOG_NODEBUG) | 367 if (debug > LOG_NODEBUG) |
| 363 info("Video loopback %d", nr); | 368 info("Video loopback %d", nr); |
| 364 | 369 |
| 365 /* Only allow a output to be opened if there is someone feeding | 370 /* Only allow a output to be opened if there is someone feeding |
| 366 * the pipe. | 371 * the pipe. |
| 367 */ | 372 */ |
| 368 if (!ptr->in) { | 373 if (!ptr->in) { |
| 369 if (loops[nr]->buffer == NULL) | 374 if (loops[nr]->buffer == NULL) |
| 370 return -EINVAL; | 375 return -EINVAL; |
| 371 | 376 |
| 372 loops[nr]->framesread = 0; | 377 loops[nr]->framesread = 0; |
| 373 loops[nr]->ropen = 1; | 378 loops[nr]->ropen = 1; |
| 374 } else { | 379 } else { |
| 375 if (loops[nr]->ropen || loops[nr]->wopen) | 380 if (loops[nr]->ropen || loops[nr]->wopen) |
| 376 return -EBUSY; | 381 return -EBUSY; |
| 377 | 382 |
| 378 loops[nr]->framesdumped = 0; | 383 loops[nr]->framesdumped = 0; |
| 379 loops[nr]->frameswrite = 0; | 384 loops[nr]->frameswrite = 0; |
| 380 loops[nr]->wopen = 1; | 385 loops[nr]->wopen = 1; |
| 381 loops[nr]->zerocopy = 0; | 386 loops[nr]->zerocopy = 0; |
| 382 loops[nr]->ioctlnr = -1; | 387 loops[nr]->ioctlnr = -1; |
| 383 pipesused++; | 388 pipesused++; |
| 384 if (nr_o_pipes-pipesused<spares) { | 389 if (nr_o_pipes-pipesused<spares) { |
| 385 if (!create_pipe(nr_o_pipes)) { | 390 if (!create_pipe(nr_o_pipes)) { |
| 386 info("Creating extra spare pipe"); | 391 info("Creating extra spare pipe"); |
| 387 info("Loopback %d registered, input: video%d, output: video%d", | 392 info("Loopback %d registered, input: video%d, output: video%d", |
| 388 nr_o_pipes, | 393 nr_o_pipes, |
| 389 loops[nr_o_pipes]->vloopin->minor, | 394 loops[nr_o_pipes]->vloopin->minor, |
| 390 loops[nr_o_pipes]->vloopout->minor | 395 loops[nr_o_pipes]->vloopout->minor |
| 391 ); | 396 ); |
| 392 nr_o_pipes++; | 397 nr_o_pipes++; |
| 393 } | 398 } |
| 394 } | 399 } |
| 395 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 400 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 396 loops[nr]->pid = current->pid; | 401 loops[nr]->pid = current->pid; |
| 397 #else | 402 #else |
| 398 // TODO : Check in stable 2.6.27 | 403 // TODO : Check in stable 2.6.27 |
| 399 loops[nr]->pid = task_pid(find_task_by_vpid(current->pid)); | 404 loops[nr]->pid = task_pid(find_task_by_vpid(current->pid)); |
| 400 //loops[nr]->pid = task_pid(current); | 405 //loops[nr]->pid = task_pid(current); |
| 401 #endif | 406 #endif |
| 402 | 407 |
| 403 if (debug > LOG_NODEBUG) | 408 if (debug > LOG_NODEBUG) |
| 404 info("Current pid %d", current->pid); | 409 info("Current pid %d", current->pid); |
| 405 } | 410 } |
| 406 return 0; | 411 return 0; |
| 407 } | 412 } |
| 408 | 413 |
| 409 static int vloopback_release(struct inode * inod, struct file *f) | 414 static int vloopback_release(struct inode * inod, struct file *f) |
| 410 { | 415 { |
| 411 struct video_device *loopdev = video_devdata(f); | 416 struct video_device *loopdev = video_devdata(f); |
| 412 priv_ptr ptr = (priv_ptr)loopdev->priv; | 417 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 413 int nr = ptr->pipenr; | 418 int nr = ptr->pipenr; |
| 414 | 419 |
| 415 if (debug > LOG_NODEBUG) | 420 if (debug > LOG_NODEBUG) |
| 416 info("Video loopback %d", nr); | 421 info("Video loopback %d", nr); |
| 417 | 422 |
| 418 if (ptr->in) { | 423 if (ptr->in) { |
| 419 down(&loops[nr]->lock); | 424 down(&loops[nr]->lock); |
| 420 if (loops[nr]->buffer && !loops[nr]->ropen) { | 425 if (loops[nr]->buffer && !loops[nr]->ropen) { |
| 421 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); | 426 rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); |
| 422 loops[nr]->buffer = NULL; | 427 loops[nr]->buffer = NULL; |
| 423 } | 428 } |
| 424 up(&loops[nr]->lock); | 429 |
| 425 loops[nr]->frameswrite++; | 430 up(&loops[nr]->lock); |
| 426 if (waitqueue_active(&loops[nr]->wait)) | 431 loops[nr]->frameswrite++; |
| 427 wake_up(&loops[nr]->wait); | 432 |
| 428 | 433 if (waitqueue_active(&loops[nr]->wait)) |
| 429 loops[nr]->width = 0; | 434 wake_up(&loops[nr]->wait); |
| 430 loops[nr]->height = 0; | 435 |
| 431 loops[nr]->palette = 0; | 436 loops[nr]->width = 0; |
| 432 loops[nr]->wopen = 0; | 437 loops[nr]->height = 0; |
| 433 pipesused--; | 438 loops[nr]->palette = 0; |
| 434 } else { | 439 loops[nr]->wopen = 0; |
| 435 down(&loops[nr]->lock); | 440 pipesused--; |
| 436 if (loops[nr]->buffer && !loops[nr]->wopen) { | 441 } else { |
| 437 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); | 442 down(&loops[nr]->lock); |
| 438 loops[nr]->buffer = NULL; | 443 |
| 439 } | 444 if (loops[nr]->buffer && !loops[nr]->wopen) { |
| 440 up(&loops[nr]->lock); | 445 rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); |
| 441 loops[nr]->ropen = 0; | 446 loops[nr]->buffer = NULL; |
| 442 if (loops[nr]->zerocopy && loops[nr]->buffer) { | 447 } |
| 443 loops[nr]->ioctlnr = 0; | 448 |
| 444 loops[nr]->ioctllength = 0; | 449 up(&loops[nr]->lock); |
| 450 loops[nr]->ropen = 0; | |
| 451 | |
| 452 if (loops[nr]->zerocopy && loops[nr]->buffer) { | |
| 453 loops[nr]->ioctlnr = 0; | |
| 454 loops[nr]->ioctllength = 0; | |
| 445 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 455 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 446 kill_proc(loops[nr]->pid, SIGIO, 1); | 456 kill_proc(loops[nr]->pid, SIGIO, 1); |
| 447 #else | 457 #else |
| 448 kill_pid(loops[nr]->pid, SIGIO, 1); | 458 kill_pid(loops[nr]->pid, SIGIO, 1); |
| 449 #endif | 459 #endif |
| 450 } | 460 } |
| 451 } | 461 } |
| 452 | 462 |
| 453 return 0; | 463 return 0; |
| 454 } | 464 } |
| 455 | 465 |
| 456 static ssize_t vloopback_write(struct file *f, const char *buf, | 466 static ssize_t vloopback_write(struct file *f, const char *buf, |
| 457 size_t count, loff_t *offset) | 467 size_t count, loff_t *offset) |
| 458 { | 468 { |
| 459 struct video_device *loopdev = video_devdata(f); | 469 struct video_device *loopdev = video_devdata(f); |
| 460 priv_ptr ptr = (priv_ptr)loopdev->priv; | 470 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 461 int nr = ptr->pipenr; | 471 int nr = ptr->pipenr; |
| 462 unsigned long realcount = count; | 472 unsigned long realcount = count; |
| 463 | 473 |
| 464 if (debug > LOG_IOCTL) | 474 if (debug > LOG_IOCTL) |
| 465 info("Video loopback %d", nr); | 475 info("Video loopback %d", nr); |
| 466 | 476 |
| 467 if (!ptr->in) | 477 if (!ptr->in) |
| 468 return -EINVAL; | 478 return -EINVAL; |
| 469 | 479 |
| 470 if (loops[nr]->zerocopy) | 480 if (loops[nr]->zerocopy) |
| 471 return -EINVAL; | 481 return -EINVAL; |
| 472 | 482 |
| 473 if (loops[nr]->buffer == NULL) | 483 if (loops[nr]->buffer == NULL) |
| 474 return -EINVAL; | 484 return -EINVAL; |
| 475 | 485 |
| 476 /* Anybody want some pictures??? */ | 486 /* Anybody want some pictures??? */ |
| 477 if (!waitqueue_active(&loops[nr]->wait)) { | 487 if (!waitqueue_active(&loops[nr]->wait)) { |
| 478 loops[nr]->framesdumped++; | 488 loops[nr]->framesdumped++; |
| 479 return realcount; | 489 return realcount; |
| 480 } | 490 } |
| 481 | 491 |
| 482 down(&loops[nr]->lock); | 492 down(&loops[nr]->lock); |
| 483 if (!loops[nr]->buffer) { | 493 if (!loops[nr]->buffer) { |
| 484 up(&loops[nr]->lock); | 494 up(&loops[nr]->lock); |
| 485 return -EINVAL; | 495 return -EINVAL; |
| 486 } | 496 } |
| 487 | 497 |
| 488 if (realcount > loops[nr]->buflength) { | 498 if (realcount > loops[nr]->buflength) { |
| 489 realcount = loops[nr]->buflength; | 499 realcount = loops[nr]->buflength; |
| 490 info("Too much data for Video loopback %d ! Only %ld bytes used.", | 500 info("Too much data for Video loopback %d ! Only %ld bytes used.", |
| 491 nr, realcount); | 501 nr, realcount); |
| 492 } | 502 } |
| 493 | 503 |
| 494 if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength, | 504 if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength, |
| 495 buf, realcount)) | 505 buf, realcount)) |
| 496 return -EFAULT; | 506 return -EFAULT; |
| 497 | 507 |
| 498 loops[nr]->frame = 0; | 508 loops[nr]->frame = 0; |
| 499 up(&loops[nr]->lock); | 509 up(&loops[nr]->lock); |
| 500 | 510 |
| 501 loops[nr]->frameswrite++; | 511 loops[nr]->frameswrite++; |
| 502 wake_up(&loops[nr]->wait); | 512 wake_up(&loops[nr]->wait); |
| 503 | 513 |
| 504 return realcount; | 514 return realcount; |
| 505 } | 515 } |
| 506 | 516 |
| 507 static ssize_t vloopback_read(struct file * f, char * buf, size_t count, | 517 static ssize_t vloopback_read(struct file * f, char * buf, size_t count, |
| 508 loff_t *offset) | 518 loff_t *offset) |
| 509 { | 519 { |
| 510 struct video_device *loopdev = video_devdata(f); | 520 struct video_device *loopdev = video_devdata(f); |
| 511 priv_ptr ptr = (priv_ptr)loopdev->priv; | 521 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 512 int nr = ptr->pipenr; | 522 int nr = ptr->pipenr; |
| 513 unsigned long realcount = count; | 523 unsigned long realcount = count; |
| 514 | 524 |
| 515 if (debug > LOG_IOCTL) | 525 if (debug > LOG_IOCTL) |
| 516 info("Video loopback %d", nr); | 526 info("Video loopback %d", nr); |
| 517 | 527 |
| 518 if (loops[nr]->zerocopy) { | 528 if (loops[nr]->zerocopy) { |
| 519 if (ptr->in) { | 529 if (ptr->in) { |
| 520 if (realcount > loops[nr]->ioctllength + sizeof(unsigned long int)) | 530 if (realcount > loops[nr]->ioctllength + sizeof(unsigned long int)) |
| 521 realcount = loops[nr]->ioctllength + sizeof(unsigned long int); | 531 realcount = loops[nr]->ioctllength + sizeof(unsigned long int); |
| 522 | 532 |
| 523 if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int))) | 533 if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int))) |
| 524 return -EFAULT; | 534 return -EFAULT; |
| 525 | 535 |
| 526 if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata, | 536 if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata, |
| 527 realcount - sizeof(unsigned long int))) | 537 realcount - sizeof(unsigned long int))) |
| 528 return -EFAULT; | 538 return -EFAULT; |
| 529 | 539 |
| 530 if (loops[nr]->ioctlnr == 0) | 540 if (loops[nr]->ioctlnr == 0) |
| 531 loops[nr]->ioctlnr = -1; | 541 loops[nr]->ioctlnr = -1; |
| 532 | 542 |
| 533 return realcount; | 543 return realcount; |
| 534 } else { | 544 } else { |
| 535 struct video_window vidwin; | 545 struct video_window vidwin; |
| 536 struct video_mmap vidmmap; | 546 struct video_mmap vidmmap; |
| 537 struct video_picture vidpic; | 547 struct video_picture vidpic; |
| 538 | 548 |
| 539 fake_ioctl(nr, VIDIOCGWIN, &vidwin); | 549 fake_ioctl(nr, VIDIOCGWIN, &vidwin); |
| 540 fake_ioctl(nr, VIDIOCGPICT, &vidpic); | 550 fake_ioctl(nr, VIDIOCGPICT, &vidpic); |
| 541 | 551 |
| 542 vidmmap.height = vidwin.height; | 552 vidmmap.height = vidwin.height; |
| 543 vidmmap.width = vidwin.width; | 553 vidmmap.width = vidwin.width; |
| 544 vidmmap.format = vidpic.palette; | 554 vidmmap.format = vidpic.palette; |
| 545 vidmmap.frame = 0; | 555 vidmmap.frame = 0; |
| 546 | 556 |
| 547 if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap)) | 557 if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap)) |
| 548 return 0; | 558 return 0; |
| 549 | 559 |
| 550 if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap)) | 560 if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap)) |
| 551 return 0; | 561 return 0; |
| 552 | 562 |
| 553 realcount = vidwin.height * vidwin.width * vidpic.depth; | 563 realcount = vidwin.height * vidwin.width * vidpic.depth; |
| 554 } | 564 } |
| 555 } | 565 } |
| 556 | 566 |
| 557 if (ptr->in) | 567 if (ptr->in) |
| 558 return -EINVAL; | 568 return -EINVAL; |
| 559 | 569 |
| 560 if (realcount > loops[nr]->buflength) { | 570 if (realcount > loops[nr]->buflength) { |
| 561 realcount = loops[nr]->buflength; | 571 realcount = loops[nr]->buflength; |
| 562 info("Not so much data in buffer! for Video loopback %d", nr); | 572 info("Not so much data in buffer! for Video loopback %d", nr); |
| 563 } | 573 } |
| 564 | 574 |
| 565 if (!loops[nr]->zerocopy) { | 575 if (!loops[nr]->zerocopy) { |
| 566 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 576 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 567 unsigned long fw = loops[nr]->frameswrite; | 577 unsigned long fw = loops[nr]->frameswrite; |
| 568 | 578 |
| 569 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); | 579 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); |
| 570 #else | 580 #else |
| 571 interruptible_sleep_on(&loops[nr]->wait); | 581 interruptible_sleep_on(&loops[nr]->wait); |
| 572 #endif | 582 #endif |
| 573 } | 583 } |
| 574 | 584 |
| 575 down(&loops[nr]->lock); | 585 down(&loops[nr]->lock); |
| 576 if (!loops[nr]->buffer) { | 586 if (!loops[nr]->buffer) { |
| 577 up(&loops[nr]->lock); | 587 up(&loops[nr]->lock); |
| 578 return 0; | 588 return 0; |
| 579 } | 589 } |
| 580 | 590 |
| 581 if (copy_to_user(buf, loops[nr]->buffer, realcount)) | 591 if (copy_to_user(buf, loops[nr]->buffer, realcount)) |
| 582 return -EFAULT; | 592 return -EFAULT; |
| 583 | 593 |
| 584 up(&loops[nr]->lock); | 594 up(&loops[nr]->lock); |
| 585 | 595 |
| 586 loops[nr]->framesread++; | 596 loops[nr]->framesread++; |
| 587 return realcount; | 597 return realcount; |
| 588 } | 598 } |
| 589 | 599 |
| 590 static int vloopback_mmap(struct file *f, struct vm_area_struct *vma) | 600 static int vloopback_mmap(struct file *f, struct vm_area_struct *vma) |
| 591 { | 601 { |
| 592 struct video_device *loopdev = video_devdata(f); | 602 struct video_device *loopdev = video_devdata(f); |
| 593 priv_ptr ptr = (priv_ptr)loopdev->priv; | 603 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 594 int nr = ptr->pipenr; | 604 int nr = ptr->pipenr; |
| 595 unsigned long start = (unsigned long)vma->vm_start; | 605 unsigned long start = (unsigned long)vma->vm_start; |
| 596 long size = vma->vm_end - vma->vm_start; | 606 long size = vma->vm_end - vma->vm_start; |
| 597 unsigned long page, pos; | 607 unsigned long page, pos; |
| 598 | 608 |
| 599 if (debug > LOG_NODEBUG) | 609 if (debug > LOG_NODEBUG) |
| 600 info("Video loopback %d", nr); | 610 info("Video loopback %d", nr); |
| 601 | 611 |
| 602 down(&loops[nr]->lock); | 612 down(&loops[nr]->lock); |
| 603 | 613 |
| 604 if (ptr->in) { | 614 if (ptr->in) { |
| 605 loops[nr]->zerocopy = 1; | 615 loops[nr]->zerocopy = 1; |
| 606 | 616 |
| 607 if (loops[nr]->ropen) { | 617 if (loops[nr]->ropen) { |
| 608 info("Can't change size while opened for read in Video loopback %d", | 618 info("Can't change size while opened for read in Video loopback %d", |
| 609 nr); | 619 nr); |
| 610 up(&loops[nr]->lock); | 620 up(&loops[nr]->lock); |
| 611 return -EINVAL; | 621 return -EINVAL; |
| 612 } | 622 } |
| 613 | 623 |
| 614 if (!size) { | 624 if (!size) { |
| 615 up(&loops[nr]->lock); | 625 up(&loops[nr]->lock); |
| 616 info("Invalid size Video loopback %d", nr); | 626 info("Invalid size Video loopback %d", nr); |
| 617 return -EINVAL; | 627 return -EINVAL; |
| 618 } | 628 } |
| 619 | 629 |
| 620 if (loops[nr]->buffer) | 630 if (loops[nr]->buffer) |
| 621 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); | 631 rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); |
| 622 | 632 |
| 623 loops[nr]->buflength = size; | 633 loops[nr]->buflength = size; |
| 624 loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS); | 634 loops[nr]->buffer = rvmalloc(loops[nr]->buflength * num_buffers); |
| 625 } | 635 } |
| 626 | 636 |
| 627 if (loops[nr]->buffer == NULL) { | 637 if (loops[nr]->buffer == NULL) { |
| 628 up(&loops[nr]->lock); | 638 up(&loops[nr]->lock); |
| 629 return -EINVAL; | 639 return -EINVAL; |
| 630 } | 640 } |
| 631 | 641 |
| 632 if (size > (((N_BUFFS * loops[nr]->buflength) + PAGE_SIZE - 1) | 642 if (size > (((num_buffers * loops[nr]->buflength) + PAGE_SIZE - 1) |
| 633 & ~(PAGE_SIZE - 1))) { | 643 & ~(PAGE_SIZE - 1))) { |
| 634 up(&loops[nr]->lock); | 644 up(&loops[nr]->lock); |
| 635 return -EINVAL; | 645 return -EINVAL; |
| 636 } | 646 } |
| 637 | 647 |
| 638 pos = (unsigned long)loops[nr]->buffer; | 648 pos = (unsigned long)loops[nr]->buffer; |
| 639 | 649 |
| 640 while (size > 0) { | 650 while (size > 0) { |
| 641 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) | 651 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) |
| 642 page = kvirt_to_pa(pos); | 652 page = kvirt_to_pa(pos); |
| 643 if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) { | 653 if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) { |
| 644 #else | 654 #else |
| 645 page = vmalloc_to_pfn((void *)pos); | 655 page = vmalloc_to_pfn((void *)pos); |
| 646 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { | 656 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { |
| 647 #endif | 657 #endif |
| 648 up(&loops[nr]->lock); | 658 up(&loops[nr]->lock); |
| 649 return -EAGAIN; | 659 return -EAGAIN; |
| 650 } | 660 } |
| 651 start += PAGE_SIZE; | 661 start += PAGE_SIZE; |
| 652 pos += PAGE_SIZE; | 662 pos += PAGE_SIZE; |
| 653 size -= PAGE_SIZE; | 663 size -= PAGE_SIZE; |
| 654 } | 664 } |
| 655 | 665 |
| 656 up(&loops[nr]->lock); | 666 up(&loops[nr]->lock); |
| 657 | 667 |
| 658 return 0; | 668 return 0; |
| 659 } | 669 } |
| 660 | 670 |
| 661 static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, | 671 static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, |
| 662 unsigned long arg) | 672 unsigned long arg) |
| 663 { | 673 { |
| 664 struct video_device *loopdev = video_devdata(f); | 674 struct video_device *loopdev = video_devdata(f); |
| 665 priv_ptr ptr = (priv_ptr)loopdev->priv; | 675 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 666 int nr = ptr->pipenr; | 676 int nr = ptr->pipenr; |
| 667 int i; | 677 int i; |
| 668 | 678 |
| 669 if (debug > LOG_NODEBUG) | 679 if (debug > LOG_NODEBUG) |
| 670 info("Video loopback %d cmd %u", nr, cmd); | 680 info("Video loopback %d cmd %u", nr, cmd); |
| 671 | 681 |
| 672 if (loops[nr]->zerocopy) { | 682 if (loops[nr]->zerocopy) { |
| 673 if (!ptr->in) { | 683 if (!ptr->in) { |
| 674 loops[nr]->ioctlnr = cmd; | 684 loops[nr]->ioctlnr = cmd; |
| 675 loops[nr]->ioctllength = _IOC_SIZE(cmd); | 685 loops[nr]->ioctllength = _IOC_SIZE(cmd); |
| 676 /* info("DEBUG: vl_ioctl: !loop->in"); */ | 686 /* info("DEBUG: vl_ioctl: !loop->in"); */ |
| 677 /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ | 687 /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ |
| 678 /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ | 688 /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ |
| 679 if (copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) | 689 if (copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) |
| 680 return -EFAULT; | 690 return -EFAULT; |
| 681 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 691 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 682 kill_proc(loops[nr]->pid, SIGIO, 1); | 692 kill_proc(loops[nr]->pid, SIGIO, 1); |
| 683 #else | 693 #else |
| 684 kill_pid(loops[nr]->pid, SIGIO, 1); | 694 kill_pid(loops[nr]->pid, SIGIO, 1); |
| 685 #endif | 695 #endif |
| 686 | 696 |
| 687 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 697 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 688 wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1); | 698 wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1); |
| 689 #else | 699 #else |
| 690 interruptible_sleep_on(&loops[nr]->wait); | 700 interruptible_sleep_on(&loops[nr]->wait); |
| 691 #endif | 701 #endif |
| 692 | 702 |
| 693 if (loops[nr]->invalid_ioctl) { | 703 if (loops[nr]->invalid_ioctl) { |
| 694 info ("There was an invalid ioctl in Video loopback %d", nr); | 704 info ("There was an invalid ioctl in Video loopback %d", nr); |
| 695 loops[nr]->invalid_ioctl = 0; | 705 loops[nr]->invalid_ioctl = 0; |
| 696 return -ENOTTY; | 706 return -ENOTTY; |
| 697 } | 707 } |
| 698 | 708 |
| 699 if (cmd & IOC_IN && !(cmd & IOC_OUT)) { | 709 if (cmd & IOC_IN && !(cmd & IOC_OUT)) { |
| 700 //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); | 710 //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); |
| 701 if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) | 711 if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) |
| 702 return -EINVAL; | 712 return -EINVAL; |
| 703 | 713 |
| 704 //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); | 714 //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); |
| 705 return 0; | |
| 706 } else { | |
| 707 if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) | |
| 708 return -EFAULT; | |
| 709 //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1"); | |
| 710 return 0; | |
| 711 } | |
| 712 } else { | |
| 713 if ((loops[nr]->ioctlnr != cmd) && (cmd != (VIDIOCSINVALID))) { | |
| 714 /* wrong ioctl */ | |
| 715 info("Wrong IOCTL %u in Video loopback %d", cmd, nr); | |
| 716 return 0; | 715 return 0; |
| 717 } | 716 } else { |
| 718 | 717 if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) |
| 719 if (cmd == VIDIOCSINVALID) { | 718 return -EFAULT; |
| 720 loops[nr]->invalid_ioctl = 1; | 719 //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1"); |
| 721 } else if (copy_from_user(loops[nr]->ioctlretdata, | 720 return 0; |
| 721 } | |
| 722 } else { | |
| 723 if ((loops[nr]->ioctlnr != cmd) && (cmd != (VIDIOCSINVALID))) { | |
| 724 /* wrong ioctl */ | |
| 725 info("Wrong IOCTL %u in Video loopback %d", cmd, nr); | |
| 726 return 0; | |
| 727 } | |
| 728 | |
| 729 if (cmd == VIDIOCSINVALID) { | |
| 730 loops[nr]->invalid_ioctl = 1; | |
| 731 } else if (copy_from_user(loops[nr]->ioctlretdata, | |
| 722 (void*)arg, loops[nr]->ioctllength)) { | 732 (void*)arg, loops[nr]->ioctllength)) { |
| 723 return -EFAULT; | 733 return -EFAULT; |
| 724 } | 734 } |
| 725 | 735 |
| 726 loops[nr]->ioctlnr = -1; | 736 loops[nr]->ioctlnr = -1; |
| 727 | 737 |
| 728 if (waitqueue_active(&loops[nr]->wait)) | 738 if (waitqueue_active(&loops[nr]->wait)) |
| 729 wake_up(&loops[nr]->wait); | 739 wake_up(&loops[nr]->wait); |
| 730 | 740 |
| 731 return 0; | 741 return 0; |
| 732 } | 742 } |
| 733 } | 743 } |
| 734 | 744 |
| 735 switch(cmd) | 745 switch(cmd) |
| 736 { | 746 { |
| 737 /* Get capabilities */ | 747 /* Get capabilities */ |
| 738 case VIDIOCGCAP: | 748 case VIDIOCGCAP: |
| 739 { | 749 { |
| 740 struct video_capability b; | 750 struct video_capability b; |
| 741 if (ptr->in) { | 751 if (ptr->in) { |
| 742 sprintf(b.name, "Video loopback %d input", nr); | 752 sprintf(b.name, "Video loopback %d input", nr); |
| 743 b.type = 0; | 753 b.type = 0; |
| 744 } else { | 754 } else { |
| 745 sprintf(b.name, "Video loopback %d output", nr); | 755 sprintf(b.name, "Video loopback %d output", nr); |
| 746 b.type = VID_TYPE_CAPTURE; | 756 b.type = VID_TYPE_CAPTURE; |
| 747 } | 757 } |
| 748 | 758 |
| 749 b.channels = 1; | 759 b.channels = 1; |
| 750 b.audios = 0; | 760 b.audios = 0; |
| 751 b.maxwidth = loops[nr]->width; | 761 b.maxwidth = loops[nr]->width; |
| 752 b.maxheight = loops[nr]->height; | 762 b.maxheight = loops[nr]->height; |
| 753 b.minwidth = 20; | 763 b.minwidth = 20; |
| 754 b.minheight = 20; | 764 b.minheight = 20; |
| 755 | 765 |
| 756 if (copy_to_user((void*)arg, &b, sizeof(b))) | 766 if (copy_to_user((void*)arg, &b, sizeof(b))) |
| 757 return -EFAULT; | 767 return -EFAULT; |
| 758 | 768 |
| 759 return 0; | 769 return 0; |
| 760 } | 770 } |
| 761 /* Get channel info (sources) */ | 771 /* Get channel info (sources) */ |
| 762 case VIDIOCGCHAN: | 772 case VIDIOCGCHAN: |
| 763 { | 773 { |
| 764 struct video_channel v; | 774 struct video_channel v; |
| 765 if (copy_from_user(&v, (void*)arg, sizeof(v))) | 775 if (copy_from_user(&v, (void*)arg, sizeof(v))) |
| 766 return -EFAULT; | 776 return -EFAULT; |
| 767 | 777 |
| 768 if (v.channel != 0) { | 778 if (v.channel != 0) { |
| 769 info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); | 779 info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); |
| 770 v.channel = 0; | 780 v.channel = 0; |
| 771 //return -EINVAL; | 781 //return -EINVAL; |
| 772 } | 782 } |
| 773 | 783 |
| 774 v.flags = 0; | 784 v.flags = 0; |
| 775 v.tuners = 0; | 785 v.tuners = 0; |
| 776 v.norm = 0; | 786 v.norm = 0; |
| 777 v.type = VIDEO_TYPE_CAMERA; | 787 v.type = VIDEO_TYPE_CAMERA; |
| 778 /*strcpy(v.name, "Loopback"); -- tibit */ | 788 /*strcpy(v.name, "Loopback"); -- tibit */ |
| 779 strcpy(v.name, "Composite1"); | 789 strcpy(v.name, "Composite1"); |
| 780 | 790 |
| 781 if (copy_to_user((void*)arg, &v, sizeof(v))) | 791 if (copy_to_user((void*)arg, &v, sizeof(v))) |
| 782 return -EFAULT; | 792 return -EFAULT; |
| 783 | 793 |
| 784 return 0; | 794 return 0; |
| 785 } | 795 } |
| 786 /* Set channel */ | 796 /* Set channel */ |
| 787 case VIDIOCSCHAN: | 797 case VIDIOCSCHAN: |
| 788 { | 798 { |
| 789 int v; | 799 int v; |
| 790 | 800 |
| 791 if (copy_from_user(&v, (void*)arg, sizeof(v))) | 801 if (copy_from_user(&v, (void*)arg, sizeof(v))) |
| 792 return -EFAULT; | 802 return -EFAULT; |
| 793 | 803 |
| 794 if (v != 0) { | 804 if (v != 0) { |
| 795 info("VIDIOCSCHAN: Invalid Channel, was %d", v); | 805 info("VIDIOCSCHAN: Invalid Channel, was %d", v); |
| 796 return -EINVAL; | 806 return -EINVAL; |
| 797 } | 807 } |
| 798 | 808 |
| 799 return 0; | 809 return 0; |
| 800 } | 810 } |
| 801 /* Get tuner abilities */ | 811 /* Get tuner abilities */ |
| 802 case VIDIOCGTUNER: | 812 case VIDIOCGTUNER: |
| 803 { | 813 { |
| 804 struct video_tuner v; | 814 struct video_tuner v; |
| 805 | 815 |
| 806 if (copy_from_user(&v, (void*)arg, sizeof(v)) != 0) | 816 if (copy_from_user(&v, (void*)arg, sizeof(v)) != 0) |
| 807 return -EFAULT; | 817 return -EFAULT; |
| 808 | 818 |
| 809 if (v.tuner) { | 819 if (v.tuner) { |
| 810 info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); | 820 info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); |
| 811 return -EINVAL; | 821 return -EINVAL; |
| 812 } | 822 } |
| 813 | 823 |
| 814 strcpy(v.name, "Format"); | 824 strcpy(v.name, "Format"); |
| 815 v.rangelow = 0; | 825 v.rangelow = 0; |
| 816 v.rangehigh = 0; | 826 v.rangehigh = 0; |
| 817 v.flags = 0; | 827 v.flags = 0; |
| 818 v.mode = VIDEO_MODE_AUTO; | 828 v.mode = VIDEO_MODE_AUTO; |
| 819 | 829 |
| 820 if (copy_to_user((void*)arg,&v, sizeof(v)) != 0) | 830 if (copy_to_user((void*)arg,&v, sizeof(v)) != 0) |
| 821 return -EFAULT; | 831 return -EFAULT; |
| 822 | 832 |
| 823 return 0; | 833 return 0; |
| 824 } | 834 } |
| 825 /* Get picture properties */ | 835 /* Get picture properties */ |
| 826 case VIDIOCGPICT: | 836 case VIDIOCGPICT: |
| 827 { | 837 { |
| 828 struct video_picture p; | 838 struct video_picture p; |
| 829 | 839 |
| 830 p.colour = 0x8000; | 840 p.colour = 0x8000; |
| 831 p.hue = 0x8000; | 841 p.hue = 0x8000; |
| 832 p.brightness = 0x8000; | 842 p.brightness = 0x8000; |
| 833 p.contrast = 0x8000; | 843 p.contrast = 0x8000; |
| 834 p.whiteness = 0x8000; | 844 p.whiteness = 0x8000; |
| 835 p.depth = 0x8000; | 845 p.depth = 0x8000; |
| 836 p.palette = loops[nr]->palette; | 846 p.palette = loops[nr]->palette; |
| 837 | 847 |
| 838 if (copy_to_user((void*)arg, &p, sizeof(p))) | 848 if (copy_to_user((void*)arg, &p, sizeof(p))) |
| 839 return -EFAULT; | 849 return -EFAULT; |
| 840 | 850 |
| 841 return 0; | 851 return 0; |
| 842 } | 852 } |
| 843 /* Set picture properties */ | 853 /* Set picture properties */ |
| 844 case VIDIOCSPICT: | 854 case VIDIOCSPICT: |
| 845 { | 855 { |
| 846 struct video_picture p; | 856 struct video_picture p; |
| 847 | 857 |
| 848 if (copy_from_user(&p, (void*)arg, sizeof(p))) | 858 if (copy_from_user(&p, (void*)arg, sizeof(p))) |
| 849 return -EFAULT; | 859 return -EFAULT; |
| 850 | 860 |
| 851 if (!ptr->in) { | 861 if (!ptr->in) { |
| 852 if (p.palette != loops[nr]->palette) | 862 if (p.palette != loops[nr]->palette) |
| 853 return -EINVAL; | 863 return -EINVAL; |
| 854 } else { | 864 } else { |
| 855 loops[nr]->palette = p.palette; | 865 loops[nr]->palette = p.palette; |
| 856 } | 866 } |
| 857 | 867 |
| 858 return 0; | 868 return 0; |
| 859 } | 869 } |
| 860 /* Get the video overlay window */ | 870 /* Get the video overlay window */ |
| 861 case VIDIOCGWIN: | 871 case VIDIOCGWIN: |
| 862 { | 872 { |
| 863 struct video_window vw; | 873 struct video_window vw; |
| 864 | 874 |
| 865 vw.x = 0; | 875 vw.x = 0; |
| 866 vw.y = 0; | 876 vw.y = 0; |
| 867 vw.width = loops[nr]->width; | 877 vw.width = loops[nr]->width; |
| 868 vw.height = loops[nr]->height; | 878 vw.height = loops[nr]->height; |
| 869 vw.chromakey = 0; | 879 vw.chromakey = 0; |
| 870 vw.flags = 0; | 880 vw.flags = 0; |
| 871 vw.clipcount = 0; | 881 vw.clipcount = 0; |
| 872 | 882 |
| 873 if (copy_to_user((void*)arg, &vw, sizeof(vw))) | 883 if (copy_to_user((void*)arg, &vw, sizeof(vw))) |
| 874 return -EFAULT; | 884 return -EFAULT; |
| 875 | 885 |
| 876 return 0; | 886 return 0; |
| 877 } | 887 } |
| 878 /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ | 888 /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ |
| 879 case VIDIOCSWIN: | 889 case VIDIOCSWIN: |
| 880 { | 890 { |
| 881 struct video_window vw; | 891 struct video_window vw; |
| 882 | 892 |
| 883 if (copy_from_user(&vw, (void*)arg, sizeof(vw))) | 893 if (copy_from_user(&vw, (void*)arg, sizeof(vw))) |
| 884 return -EFAULT; | 894 return -EFAULT; |
| 885 | 895 |
| 886 if (vw.flags) | 896 if (vw.flags) |
| 887 return -EINVAL; | 897 return -EINVAL; |
| 888 | 898 |
| 889 if (vw.clipcount) | 899 if (vw.clipcount) |
| 890 return -EINVAL; | 900 return -EINVAL; |
| 891 | 901 |
| 892 if (loops[nr]->height == vw.height && | 902 if (loops[nr]->height == vw.height && |
| 893 loops[nr]->width == vw.width) | 903 loops[nr]->width == vw.width) |
| 894 return 0; | 904 return 0; |
| 895 | 905 |
| 896 if (!ptr->in) { | 906 if (!ptr->in) { |
| 897 return -EINVAL; | 907 return -EINVAL; |
| 898 } else { | 908 } else { |
| 899 loops[nr]->height = vw.height; | 909 loops[nr]->height = vw.height; |
| 900 loops[nr]->width = vw.width; | 910 loops[nr]->width = vw.width; |
| 901 /* Make sure nobody is using the buffer while we | 911 /* Make sure nobody is using the buffer while we |
| 902 fool around with it. | 912 fool around with it. |
| 903 We are also not allowing changes while | 913 We are also not allowing changes while |
| 904 somebody using mmap has the output open. | 914 somebody using mmap has the output open. |
| 905 */ | 915 */ |
| 906 down(&loops[nr]->lock); | 916 down(&loops[nr]->lock); |
| 907 if (loops[nr]->ropen) { | 917 if (loops[nr]->ropen) { |
| 908 info("Can't change size while opened for read"); | 918 info("Can't change size while opened for read"); |
| 909 up(&loops[nr]->lock); | 919 up(&loops[nr]->lock); |
| 910 return -EINVAL; | 920 return -EINVAL; |
| 911 } | 921 } |
| 912 | 922 |
| 913 if (loops[nr]->buffer) | 923 if (loops[nr]->buffer) |
| 914 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS); | 924 rvfree(loops[nr]->buffer, loops[nr]->buflength * num_buffers); |
| 915 | 925 |
| 916 loops[nr]->buflength = vw.width * vw.height * 4; | 926 loops[nr]->buflength = vw.width * vw.height * 4; |
| 917 loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS); | 927 loops[nr]->buffer = rvmalloc(loops[nr]->buflength * num_buffers); |
| 918 up(&loops[nr]->lock); | 928 up(&loops[nr]->lock); |
| 919 } | 929 } |
| 920 return 0; | 930 return 0; |
| 921 } | 931 } |
| 922 /* Memory map buffer info */ | 932 /* Memory map buffer info */ |
| 923 case VIDIOCGMBUF: | 933 case VIDIOCGMBUF: |
| 924 { | 934 { |
| 925 struct video_mbuf vm; | 935 struct video_mbuf vm; |
| 926 | 936 |
| 927 vm.size = loops[nr]->buflength * N_BUFFS; | 937 vm.size = loops[nr]->buflength * num_buffers; |
| 928 vm.frames = N_BUFFS; | 938 vm.frames = num_buffers; |
| 929 for (i = 0; i < vm.frames; i++) | 939 for (i = 0; i < vm.frames; i++) |
| 930 vm.offsets[i] = i * loops[nr]->buflength; | 940 vm.offsets[i] = i * loops[nr]->buflength; |
| 931 | 941 |
| 932 if (copy_to_user((void*)arg, &vm, sizeof(vm))) | 942 if (copy_to_user((void*)arg, &vm, sizeof(vm))) |
| 933 return -EFAULT; | 943 return -EFAULT; |
| 934 | 944 |
| 935 return 0; | 945 return 0; |
| 936 } | 946 } |
| 937 /* Grab frames */ | 947 /* Grab frames */ |
| 938 case VIDIOCMCAPTURE: | 948 case VIDIOCMCAPTURE: |
| 939 { | 949 { |
| 940 struct video_mmap vm; | 950 struct video_mmap vm; |
| 941 | 951 |
| 942 if (ptr->in) | 952 if (ptr->in) |
| 943 return -EINVAL; | 953 return -EINVAL; |
| 944 | 954 |
| 945 if (!loops[nr]->buffer) | 955 if (!loops[nr]->buffer) |
| 946 return -EINVAL; | 956 return -EINVAL; |
| 947 | 957 |
| 948 if (copy_from_user(&vm, (void*)arg, sizeof(vm))) | 958 if (copy_from_user(&vm, (void*)arg, sizeof(vm))) |
| 949 return -EFAULT; | 959 return -EFAULT; |
| 950 | 960 |
| 951 if (vm.format != loops[nr]->palette) | 961 if (vm.format != loops[nr]->palette) |
| 952 return -EINVAL; | 962 return -EINVAL; |
| 953 | 963 |
| 954 if (vm.frame > N_BUFFS) | 964 if (vm.frame > num_buffers) |
| 955 return -EINVAL; | 965 return -EINVAL; |
| 956 | 966 |
| 957 return 0; | 967 return 0; |
| 958 } | 968 } |
| 959 /* Sync with mmap grabbing */ | 969 /* Sync with mmap grabbing */ |
| 960 case VIDIOCSYNC: | 970 case VIDIOCSYNC: |
| 961 { | 971 { |
| 962 int frame; | 972 int frame; |
| 963 unsigned long fw; | 973 unsigned long fw; |
| 964 | 974 |
| 965 if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) | 975 if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) |
| 966 return -EFAULT; | 976 return -EFAULT; |
| 967 | 977 |
| 968 if (ptr->in) | 978 if (ptr->in) |
| 969 return -EINVAL; | 979 return -EINVAL; |
| 970 | 980 |
| 971 if (!loops[nr]->buffer) | 981 if (!loops[nr]->buffer) |
| 972 return -EINVAL; | 982 return -EINVAL; |
| 973 | 983 |
| 974 /* Ok, everything should be alright since the program | 984 /* Ok, everything should be alright since the program |
| 975 should have called VIDIOMCAPTURE and we are ready to | 985 should have called VIDIOMCAPTURE and we are ready to |
| 976 do the 'capturing' */ | 986 do the 'capturing' */ |
| 977 if (frame > 1) | 987 //if (frame > 1) |
| 978 return -EINVAL; | 988 if (frame > num_buffers-1) |
| 979 | 989 return -EINVAL; |
| 980 loops[nr]->frame = frame; | 990 |
| 991 loops[nr]->frame = frame; | |
| 981 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 992 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 982 fw = loops[nr]->frameswrite; | 993 fw = loops[nr]->frameswrite; |
| 983 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); | 994 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite); |
| 984 #else | 995 #else |
| 985 interruptible_sleep_on(&loops[nr]->wait); | 996 interruptible_sleep_on(&loops[nr]->wait); |
| 986 #endif | 997 #endif |
| 987 if (!loops[nr]->buffer) /* possibly released during sleep */ | 998 if (!loops[nr]->buffer) /* possibly released during sleep */ |
| 988 return -EINVAL; | 999 return -EINVAL; |
| 989 | 1000 |
| 990 loops[nr]->framesread++; | 1001 loops[nr]->framesread++; |
| 991 | 1002 |
| 992 return 0; | 1003 return 0; |
| 993 } | 1004 } |
| 994 /* Get attached units */ | 1005 /* Get attached units */ |
| 995 case VIDIOCGUNIT: | 1006 case VIDIOCGUNIT: |
| 996 { | 1007 { |
| 997 struct video_unit vu; | 1008 struct video_unit vu; |
| 998 | 1009 |
| 999 if (ptr->in) | 1010 if (ptr->in) |
| 1000 vu.video = loops[nr]->vloopout->minor; | 1011 vu.video = loops[nr]->vloopout->minor; |
| 1001 else | 1012 else |
| 1002 vu.video = loops[nr]->vloopin->minor; | 1013 vu.video = loops[nr]->vloopin->minor; |
| 1003 | 1014 |
| 1004 vu.vbi = VIDEO_NO_UNIT; | 1015 vu.vbi = VIDEO_NO_UNIT; |
| 1005 vu.radio = VIDEO_NO_UNIT; | 1016 vu.radio = VIDEO_NO_UNIT; |
| 1006 vu.audio = VIDEO_NO_UNIT; | 1017 vu.audio = VIDEO_NO_UNIT; |
| 1007 vu.teletext = VIDEO_NO_UNIT; | 1018 vu.teletext = VIDEO_NO_UNIT; |
| 1008 | 1019 |
| 1009 if (copy_to_user((void*)arg, &vu, sizeof(vu))) | 1020 if (copy_to_user((void*)arg, &vu, sizeof(vu))) |
| 1010 return -EFAULT; | 1021 return -EFAULT; |
| 1011 | 1022 |
| 1012 return 0; | 1023 return 0; |
| 1013 } | 1024 } |
| 1014 /* Get frame buffer */ | 1025 /* Get frame buffer */ |
| 1015 case VIDIOCGFBUF: | 1026 case VIDIOCGFBUF: |
| 1016 { | 1027 { |
| 1017 struct video_buffer vb; | 1028 struct video_buffer vb; |
| 1018 | 1029 |
| 1019 memset(&vb, 0, sizeof(vb)); | 1030 memset(&vb, 0, sizeof(vb)); |
| 1020 vb.base = NULL; | 1031 vb.base = NULL; |
| 1021 | 1032 |
| 1022 if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) | 1033 if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb))) |
| 1023 return -EFAULT; | 1034 return -EFAULT; |
| 1024 | 1035 |
| 1025 return 0; | 1036 return 0; |
| 1026 } | 1037 } |
| 1027 /* Start, end capture */ | 1038 /* Start, end capture */ |
| 1028 case VIDIOCCAPTURE: | 1039 case VIDIOCCAPTURE: |
| 1029 { | 1040 { |
| 1030 int start; | 1041 int start; |
| 1031 | 1042 |
| 1032 if (copy_from_user(&start, (void*)arg, sizeof(int))) | 1043 if (copy_from_user(&start, (void*)arg, sizeof(int))) |
| 1033 return -EFAULT; | 1044 return -EFAULT; |
| 1034 | 1045 |
| 1035 if (start) { | 1046 if (start) { |
| 1036 info ("Video loopback %d Capture started", nr); | 1047 info ("Video loopback %d Capture started", nr); |
| 1037 } else { | 1048 } else { |
| 1038 info ("Video loopback %d Capture stopped", nr); | 1049 info ("Video loopback %d Capture stopped", nr); |
| 1039 } | 1050 } |
| 1040 | 1051 |
| 1041 return 0; | 1052 return 0; |
| 1042 } | 1053 } |
| 1043 case VIDIOCGFREQ: | 1054 case VIDIOCGFREQ: |
| 1044 case VIDIOCSFREQ: | 1055 case VIDIOCSFREQ: |
| 1045 case VIDIOCGAUDIO: | 1056 case VIDIOCGAUDIO: |
| 1046 case VIDIOCSAUDIO: | 1057 case VIDIOCSAUDIO: |
| 1047 return -EINVAL; | 1058 return -EINVAL; |
| 1048 case VIDIOCKEY: | 1059 case VIDIOCKEY: |
| 1049 return 0; | 1060 return 0; |
| 1050 default: | 1061 default: |
| 1051 return -ENOTTY; | 1062 return -ENOTTY; |
| 1052 //return -ENOIOCTLCMD; | 1063 //return -ENOIOCTLCMD; |
| 1053 } | 1064 } |
| 1054 return 0; | 1065 return 0; |
| 1055 } | 1066 } |
| 1056 | 1067 |
| 1057 static unsigned int vloopback_poll(struct file *f, struct poll_table_struct *wait) | 1068 static unsigned int vloopback_poll(struct file *f, struct poll_table_struct *wait) |
| 1058 { | 1069 { |
| 1059 struct video_device *loopdev = video_devdata(f); | 1070 struct video_device *loopdev = video_devdata(f); |
| 1060 priv_ptr ptr = (priv_ptr)loopdev->priv; | 1071 priv_ptr ptr = (priv_ptr)loopdev->priv; |
| 1061 int nr = ptr->pipenr; | 1072 int nr = ptr->pipenr; |
| 1062 | 1073 |
| 1063 if (debug > LOG_NODEBUG) | 1074 if (debug > LOG_NODEBUG) |
| 1064 info("Video loopback %d", nr); | 1075 info("Video loopback %d", nr); |
| 1065 | 1076 |
| 1066 if (loopdev == NULL) | 1077 if (loopdev == NULL) |
| 1067 return -EFAULT; | 1078 return -EFAULT; |
| 1068 | 1079 |
| 1069 if (!ptr->in) | 1080 if (!ptr->in) |
| 1070 return 0; | 1081 return 0; |
| 1071 | 1082 |
| 1072 if (loops[nr]->ioctlnr != -1) { | 1083 if (loops[nr]->ioctlnr != -1) { |
| 1073 if (loops[nr]->zerocopy) { | 1084 if (loops[nr]->zerocopy) { |
| 1074 return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM); | 1085 return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM); |
| 1075 } else { | 1086 } else { |
| 1076 return (POLLOUT); | 1087 return (POLLOUT); |
| 1077 } | 1088 } |
| 1078 } | 1089 } |
| 1079 return 0; | 1090 return 0; |
| 1080 } | 1091 } |
| 1081 | 1092 |
| 1082 static struct file_operations fileops_template = | 1093 static struct file_operations fileops_template = |
| 1083 { | 1094 { |
| 1084 owner: THIS_MODULE, | 1095 owner: THIS_MODULE, |
| 1085 open: vloopback_open, | 1096 open: vloopback_open, |
| 1086 release: vloopback_release, | 1097 release: vloopback_release, |
| 1087 read: vloopback_read, | 1098 read: vloopback_read, |
| 1088 write: vloopback_write, | 1099 write: vloopback_write, |
| 1089 poll: vloopback_poll, | 1100 poll: vloopback_poll, |
| 1090 ioctl: vloopback_ioctl, | 1101 ioctl: vloopback_ioctl, |
| 1091 mmap: vloopback_mmap, | 1102 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) |
| 1103 compat_ioctl: v4l_compat_ioctl32, | |
| 1104 #endif | |
| 1105 mmap: vloopback_mmap, | |
| 1092 }; | 1106 }; |
| 1093 | 1107 |
| 1094 static struct video_device vloopback_template = | 1108 static struct video_device vloopback_template = |
| 1095 { | 1109 { |
| 1096 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 1110 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 1097 owner: THIS_MODULE, | 1111 owner: THIS_MODULE, |
| 1098 type: VID_TYPE_CAPTURE, | 1112 type: VID_TYPE_CAPTURE, |
| 1099 #endif | 1113 #endif |
| 1100 minor: -1, | 1114 minor: -1, |
| 1101 name: "Video Loopback", | 1115 name: "Video Loopback", |
| 1102 fops: &fileops_template, | 1116 fops: &fileops_template, |
| 1103 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 1117 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 1104 release: video_device_release, | 1118 release: video_device_release, |
| 1105 #endif | 1119 #endif |
| 1106 }; | 1120 }; |
| 1107 | 1121 |
| 1108 static int create_pipe(int nr) | 1122 static int create_pipe(int nr) |
| 1109 { | 1123 { |
| 1110 int minor_in, minor_out , ret; | 1124 int minor_in, minor_out , ret; |
| 1111 | 1125 |
| 1112 if (debug > LOG_NODEBUG) | 1126 if (debug > LOG_NODEBUG) |
| 1113 info("Video loopback %d", nr); | 1127 info("Video loopback %d", nr); |
| 1114 | 1128 |
| 1115 if (dev_offset == -1) { | 1129 if (dev_offset == -1) { |
| 1116 minor_in = minor_out = -1; /* autoassign */ | 1130 minor_in = minor_out = -1; /* autoassign */ |
| 1117 } else { | 1131 } else { |
| 1118 minor_in = 2 * nr + dev_offset; | 1132 minor_in = 2 * nr + dev_offset; |
| 1119 minor_out = 2 * nr + 1 + dev_offset; | 1133 minor_out = 2 * nr + 1 + dev_offset; |
| 1120 } | 1134 } |
| 1121 | 1135 |
| 1122 /* allocate space for this pipe */ | 1136 /* allocate space for this pipe */ |
| 1123 loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); | 1137 loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); |
| 1124 | 1138 |
| 1125 if (!loops[nr]) | 1139 if (!loops[nr]) |
| 1126 return -ENOMEM; | 1140 return -ENOMEM; |
| 1127 /* set up a new video device plus our private area */ | 1141 /* set up a new video device plus our private area */ |
| 1128 loops[nr]->vloopin = video_device_alloc(); | 1142 loops[nr]->vloopin = video_device_alloc(); |
| 1129 | 1143 |
| 1130 if (loops[nr]->vloopin == NULL) | 1144 if (loops[nr]->vloopin == NULL) |
| 1131 return -ENOMEM; | 1145 return -ENOMEM; |
| 1132 *loops[nr]->vloopin = vloopback_template; | 1146 *loops[nr]->vloopin = vloopback_template; |
| 1133 loops[nr]->vloopin->priv = kmalloc(sizeof(struct vloopback_private), | 1147 loops[nr]->vloopin->priv = kmalloc(sizeof(struct vloopback_private), |
| 1134 GFP_KERNEL); | 1148 GFP_KERNEL); |
| 1135 if (loops[nr]->vloopin->priv == NULL) { | 1149 if (loops[nr]->vloopin->priv == NULL) { |
| 1136 kfree(loops[nr]->vloopin); | 1150 kfree(loops[nr]->vloopin); |
| 1137 return -ENOMEM; | 1151 return -ENOMEM; |
| 1138 } | 1152 } |
| 1139 /* repeat for the output device */ | 1153 /* repeat for the output device */ |
| 1140 loops[nr]->vloopout = video_device_alloc(); | 1154 loops[nr]->vloopout = video_device_alloc(); |
| 1141 | 1155 |
| 1142 if (loops[nr]->vloopout == NULL) { | 1156 if (loops[nr]->vloopout == NULL) { |
| 1143 kfree(loops[nr]->vloopin->priv); | 1157 kfree(loops[nr]->vloopin->priv); |
| 1144 kfree(loops[nr]->vloopin); | 1158 kfree(loops[nr]->vloopin); |
| 1145 return -ENOMEM; | 1159 return -ENOMEM; |
| 1146 } | 1160 } |
| 1147 *loops[nr]->vloopout = vloopback_template; | 1161 *loops[nr]->vloopout = vloopback_template; |
| 1148 loops[nr]->vloopout->priv = kmalloc(sizeof(struct vloopback_private), | 1162 loops[nr]->vloopout->priv = kmalloc(sizeof(struct vloopback_private), |
| 1149 GFP_KERNEL); | 1163 GFP_KERNEL); |
| 1150 | 1164 |
| 1151 if (loops[nr]->vloopout->priv == NULL) { | 1165 if (loops[nr]->vloopout->priv == NULL) { |
| 1152 kfree(loops[nr]->vloopin->priv); | 1166 kfree(loops[nr]->vloopin->priv); |
| 1153 kfree(loops[nr]->vloopin); | 1167 kfree(loops[nr]->vloopin); |
| 1154 kfree(loops[nr]->vloopout); | 1168 kfree(loops[nr]->vloopout); |
| 1155 return -ENOMEM; | 1169 return -ENOMEM; |
| 1156 } | 1170 } |
| 1157 | 1171 |
| 1158 ((priv_ptr)loops[nr]->vloopin->priv)->pipenr = nr; | 1172 ((priv_ptr)loops[nr]->vloopin->priv)->pipenr = nr; |
| 1159 ((priv_ptr)loops[nr]->vloopout->priv)->pipenr = nr; | 1173 ((priv_ptr)loops[nr]->vloopout->priv)->pipenr = nr; |
| 1160 loops[nr]->invalid_ioctl = 0; /* tibit */ | 1174 loops[nr]->invalid_ioctl = 0; /* tibit */ |
| 1161 loops[nr]->buffer = NULL; | 1175 loops[nr]->buffer = NULL; |
| 1162 loops[nr]->width = 0; | 1176 loops[nr]->width = 0; |
| 1163 loops[nr]->height = 0; | 1177 loops[nr]->height = 0; |
| 1164 loops[nr]->palette = 0; | 1178 loops[nr]->palette = 0; |
| 1165 loops[nr]->frameswrite = 0; | 1179 loops[nr]->frameswrite = 0; |
| 1166 loops[nr]->framesread = 0; | 1180 loops[nr]->framesread = 0; |
| 1167 loops[nr]->framesdumped = 0; | 1181 loops[nr]->framesdumped = 0; |
| 1168 loops[nr]->wopen = 0; | 1182 loops[nr]->wopen = 0; |
| 1169 loops[nr]->ropen = 0; | 1183 loops[nr]->ropen = 0; |
| 1170 loops[nr]->frame = 0; | 1184 loops[nr]->frame = 0; |
| 1171 | 1185 |
| 1172 ((priv_ptr)loops[nr]->vloopin->priv)->in = 1; | 1186 ((priv_ptr)loops[nr]->vloopin->priv)->in = 1; |
| 1173 ((priv_ptr)loops[nr]->vloopout->priv)->in = 0; | 1187 ((priv_ptr)loops[nr]->vloopout->priv)->in = 0; |
| 1174 sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); | 1188 sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); |
| 1175 sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); | 1189 sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); |
| 1176 | 1190 |
| 1177 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) | 1191 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) |
| 1178 loops[nr]->vloopin->type = 0; | 1192 loops[nr]->vloopin->type = 0; |
| 1179 loops[nr]->vloopout->type = VID_TYPE_CAPTURE; | 1193 loops[nr]->vloopout->type = VID_TYPE_CAPTURE; |
| 1180 #endif | 1194 #endif |
| 1181 loops[nr]->vloopout->minor = minor_out; | 1195 loops[nr]->vloopout->minor = minor_out; |
| 1182 loops[nr]->vloopin->minor = minor_in; | 1196 loops[nr]->vloopin->minor = minor_in; |
| 1183 | 1197 |
| 1184 init_waitqueue_head(&loops[nr]->wait); | 1198 init_waitqueue_head(&loops[nr]->wait); |
| 1185 init_MUTEX(&loops[nr]->lock); | 1199 init_MUTEX(&loops[nr]->lock); |
| 1186 | 1200 |
| 1187 ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER, minor_in); | 1201 ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER, minor_in); |
| 1188 | 1202 |
| 1189 if ((ret == -1 ) || ( ret == -23 )) { | 1203 if ((ret == -1 ) || ( ret == -23 )) { |
| 1190 info("error registering device %s", loops[nr]->vloopin->name); | 1204 info("error registering device %s", loops[nr]->vloopin->name); |
| 1191 kfree(loops[nr]->vloopin->priv); | 1205 kfree(loops[nr]->vloopin->priv); |
| 1192 kfree(loops[nr]->vloopin); | 1206 kfree(loops[nr]->vloopin); |
| 1193 kfree(loops[nr]->vloopout->priv); | 1207 kfree(loops[nr]->vloopout->priv); |
| 1194 kfree(loops[nr]->vloopout); | 1208 kfree(loops[nr]->vloopout); |
| 1195 kfree(loops[nr]); | 1209 kfree(loops[nr]); |
| 1196 loops[nr] = NULL; | 1210 loops[nr] = NULL; |
| 1197 return ret; | 1211 return ret; |
| 1198 } | 1212 } |
| 1199 | 1213 |
| 1200 ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER, minor_out); | 1214 ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER, minor_out); |
| 1201 | 1215 |
| 1202 if ((ret ==-1) || (ret == -23)) { | 1216 if ((ret ==-1) || (ret == -23)) { |
| 1203 info("error registering device %s", loops[nr]->vloopout->name); | 1217 info("error registering device %s", loops[nr]->vloopout->name); |
| 1204 kfree(loops[nr]->vloopin->priv); | 1218 kfree(loops[nr]->vloopin->priv); |
| 1205 video_unregister_device(loops[nr]->vloopin); | 1219 video_unregister_device(loops[nr]->vloopin); |
| 1206 kfree(loops[nr]->vloopout->priv); | 1220 kfree(loops[nr]->vloopout->priv); |
| 1207 kfree(loops[nr]->vloopout); | 1221 kfree(loops[nr]->vloopout); |
| 1208 kfree(loops[nr]); | 1222 kfree(loops[nr]); |
| 1209 loops[nr] = NULL; | 1223 loops[nr] = NULL; |
| 1210 return ret; | 1224 return ret; |
| 1211 } | 1225 } |
| 1212 | 1226 |
| 1213 loops[nr]->ioctldata = kmalloc(1024, GFP_KERNEL); | 1227 loops[nr]->ioctldata = kmalloc(1024, GFP_KERNEL); |
| 1214 loops[nr]->ioctlretdata = kmalloc(1024, GFP_KERNEL); | 1228 loops[nr]->ioctlretdata = kmalloc(1024, GFP_KERNEL); |
| 1215 return 0; | 1229 return 0; |
| 1216 } | 1230 } |
| 1217 | 1231 |
| 1218 | 1232 |
| 1219 /**************************************************************************** | 1233 /**************************************************************************** |
| 1220 * init stuff | 1234 * init stuff |
| 1221 ****************************************************************************/ | 1235 ****************************************************************************/ |
| 1222 | 1236 |
| 1223 | 1237 |
| 1224 MODULE_AUTHOR("J.B. Vreeken (pe1rxq@amsat.org)"); | 1238 MODULE_AUTHOR("J.B. Vreeken (pe1rxq@amsat.org)"); |
| 1225 MODULE_DESCRIPTION("Video4linux loopback device."); | 1239 MODULE_DESCRIPTION("Video4linux loopback device."); |
| 1228 module_param(pipes, int, 000); | 1242 module_param(pipes, int, 000); |
| 1229 #else | 1243 #else |
| 1230 MODULE_PARM(pipes, "i"); | 1244 MODULE_PARM(pipes, "i"); |
| 1231 #endif | 1245 #endif |
| 1232 | 1246 |
| 1233 MODULE_PARM_DESC(pipes, "Nr of pipes to create (each pipe uses two video devices)"); | 1247 MODULE_PARM_DESC(pipes, " Nr of pipes to create (each pipe uses two video devices)"); |
| 1234 | 1248 |
| 1235 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 1249 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 1236 module_param(spares, int, 000); | 1250 module_param(spares, int, 000); |
| 1237 #else | 1251 #else |
| 1238 MODULE_PARM(spares, "i"); | 1252 MODULE_PARM(spares, "i"); |
| 1239 #endif | 1253 #endif |
| 1240 | 1254 |
| 1241 MODULE_PARM_DESC(spares, "Nr of spare pipes that should be created"); | 1255 MODULE_PARM_DESC(spares, " Nr of spare pipes that should be created"); |
| 1256 | |
| 1257 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | |
| 1258 module_param(num_buffers, int, 000); | |
| 1259 #else | |
| 1260 MODULE_PARM(num_buffers, "i"); | |
| 1261 #endif | |
| 1262 | |
| 1263 MODULE_PARM_DESC(num_buffers, " Prefered numbers of internal buffers to map (default 2)"); | |
| 1264 | |
| 1242 | 1265 |
| 1243 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 1266 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 1244 module_param(dev_offset, int, 000); | 1267 module_param(dev_offset, int, 000); |
| 1245 #else | 1268 #else |
| 1246 MODULE_PARM(dev_offset_param, "i"); | 1269 MODULE_PARM(dev_offset_param, "i"); |
| 1247 #endif | 1270 #endif |
| 1248 | 1271 |
| 1249 MODULE_PARM_DESC(dev_offset, "Prefered offset for video device numbers"); | 1272 MODULE_PARM_DESC(dev_offset, " Prefered offset for video device numbers"); |
| 1250 | 1273 |
| 1251 | 1274 |
| 1252 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) | 1275 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) |
| 1253 module_param(debug, int, 000); | 1276 module_param(debug, int, 000); |
| 1254 #else | 1277 #else |
| 1255 MODULE_PARM(debug_param, "i"); | 1278 MODULE_PARM(debug_param, "i"); |
| 1256 #endif | 1279 #endif |
| 1257 | 1280 |
| 1258 MODULE_PARM_DESC(debug, "Enable module debug level 0-3 (by default 0)"); | 1281 MODULE_PARM_DESC(debug, " Enable module debug level 0-3 (by default 0)"); |
| 1259 | 1282 |
| 1260 MODULE_LICENSE("GPL"); | 1283 MODULE_LICENSE("GPL"); |
| 1261 MODULE_VERSION( VLOOPBACK_VERSION ); | 1284 MODULE_VERSION( VLOOPBACK_VERSION ); |
| 1262 | 1285 |
| 1263 static int __init vloopback_init(void) | 1286 static int __init vloopback_init(void) |
| 1264 { | 1287 { |
| 1265 int i,ret; | 1288 int i, ret; |
| 1266 | 1289 |
| 1267 info("video4linux loopback driver v"VLOOPBACK_VERSION); | 1290 info("video4linux loopback driver v"VLOOPBACK_VERSION); |
| 1268 | 1291 |
| 1269 if (pipes == -1) | 1292 if (pipes == -1) |
| 1270 pipes = 1; | 1293 pipes = 1; |
| 1271 | 1294 |
| 1272 if (pipes > MAX_PIPES) { | 1295 if (pipes > MAX_PIPES) { |
| 1273 pipes = MAX_PIPES; | 1296 pipes = MAX_PIPES; |
| 1274 info("Nr of pipes is limited to: %d", MAX_PIPES); | 1297 info("Nr of pipes is limited to: %d", MAX_PIPES); |
| 1275 } | 1298 } |
| 1276 | 1299 |
| 1277 for (i = 0; i < pipes; i++) { | 1300 if (num_buffers < N_BUFFS) { |
| 1278 | 1301 num_buffers = N_BUFFS; |
| 1279 ret = create_pipe(i); | 1302 info("Nr of buffer set to default value %d", N_BUFFS); |
| 1280 | 1303 } |
| 1281 if (ret == 0) { | 1304 |
| 1282 info("Loopback %d registered, input: video%d," | 1305 for (i = 0; i < pipes; i++) { |
| 1283 " output: video%d", | 1306 |
| 1284 i, loops[i]->vloopin->minor, | 1307 ret = create_pipe(i); |
| 1285 loops[i]->vloopout->minor); | 1308 |
| 1286 nr_o_pipes = i + 1; | 1309 if (ret == 0) { |
| 1287 } else { | 1310 info("Loopback %d registered, input: video%d," |
| 1288 return ret; | 1311 " output: video%d", |
| 1289 } | 1312 i, loops[i]->vloopin->minor, |
| 1290 } | 1313 loops[i]->vloopout->minor); |
| 1291 return 0; | 1314 info("Loopback %d , Using %d buffers", i, num_buffers); |
| 1315 nr_o_pipes = i + 1; | |
| 1316 } else { | |
| 1317 return ret; | |
| 1318 } | |
| 1319 } | |
| 1320 return 0; | |
| 1292 } | 1321 } |
| 1293 | 1322 |
| 1294 static void __exit cleanup_vloopback_module(void) | 1323 static void __exit cleanup_vloopback_module(void) |
| 1295 { | 1324 { |
| 1296 int i; | 1325 int i; |
| 1297 | 1326 |
| 1298 info("Unregistering video4linux loopback devices"); | 1327 info("Unregistering video4linux loopback devices"); |
| 1299 | 1328 |
| 1300 for (i = 0; i < nr_o_pipes; i++) { | 1329 for (i = 0; i < nr_o_pipes; i++) { |
| 1301 if (loops[i]) { | 1330 if (loops[i]) { |
| 1302 kfree(loops[i]->vloopin->priv); | 1331 kfree(loops[i]->vloopin->priv); |
| 1303 video_unregister_device(loops[i]->vloopin); | 1332 video_unregister_device(loops[i]->vloopin); |
| 1304 kfree(loops[i]->vloopout->priv); | 1333 kfree(loops[i]->vloopout->priv); |
| 1305 video_unregister_device(loops[i]->vloopout); | 1334 video_unregister_device(loops[i]->vloopout); |
| 1306 | 1335 |
| 1307 if (loops[i]->buffer) | 1336 if (loops[i]->buffer) |
| 1308 rvfree(loops[i]->buffer, loops[i]->buflength * N_BUFFS); | 1337 rvfree(loops[i]->buffer, loops[i]->buflength * num_buffers); |
| 1309 | 1338 |
| 1310 kfree(loops[i]->ioctldata); | 1339 kfree(loops[i]->ioctldata); |
| 1311 kfree(loops[i]->ioctlretdata); | 1340 kfree(loops[i]->ioctlretdata); |
| 1312 kfree(loops[i]); | 1341 kfree(loops[i]); |
| 1313 } | 1342 } |
| 1314 } | 1343 } |
| 1315 } | 1344 } |
| 1316 | 1345 |
| 1317 module_init(vloopback_init); | 1346 module_init(vloopback_init); |
| 1318 module_exit(cleanup_vloopback_module); | 1347 module_exit(cleanup_vloopback_module); |
