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); |