comparison vloopback.c @ 0:5f21a4dddc0c

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