diff -Nur vloopback-0.90/example/dummy.c vloopback-0.90-tibit/example/dummy.c --- vloopback-0.90/example/dummy.c Fri Nov 23 10:40:43 2001 +++ vloopback-0.90-tibit/example/dummy.c Fri Nov 23 23:31:47 2001 @@ -29,14 +29,14 @@ char ioctlbuf[MAXIOCTL]; int v4ldev; char *image_out; -char colour; int get_frame(void) { int i; + char colour = 0; - memset(image_out, 0, width*height*3); + memset(image_out, 0x128, width*height*3); for (i=10; ichannel!=0) - return 1; + ;//return 1; + vidchan->channel=0; vidchan->flags=0; vidchan->tuners=0; - vidchan->type= VIDEO_TYPE_CAMERA; - strcpy(vidchan->name, "Composite1"); + vidchan->norm=0; + vidchan->type=VIDEO_TYPE_CAMERA; + strcpy(vidchan->name, "Loopback"); return 0; } @@ -100,16 +106,32 @@ return 1; return 0; } + case VIDIOCGTUNER: + { + struct video_tuner *v = arg; + + if(v->tuner) { + printf("VIDIOCGTUNER: Invalid Tuner, was %d\n", v->tuner); + //return -EINVAL; + } + v->tuner=0; + strcpy(v->name, "Format"); + v->rangelow=0; + v->rangehigh=0; + v->flags=0; + v->mode=VIDEO_MODE_AUTO; + return 1; + } case VIDIOCGPICT: { struct video_picture *vidpic=arg; - vidpic->colour=0xffff; - vidpic->hue=0xffff; - vidpic->brightness=0xffff; - vidpic->contrast=0xffff; - vidpic->whiteness=0xffff; - vidpic->depth=3; + vidpic->colour=0x8000; + vidpic->hue=0x8000; + vidpic->brightness=0x8000; + vidpic->contrast=0x8000; + vidpic->whiteness=0x8000; + vidpic->depth=0x8000; vidpic->palette=fmt; return 0; } @@ -189,12 +211,14 @@ default: { printf("unknown ioctl: %ld\n", cmd & 0xff); - return -1; + return 1; } } return 0; } +#define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) + void sighandler(int signo) { int size, ret; @@ -221,9 +245,10 @@ ret=v4l_ioctl(cmd, ioctlbuf+sizeof(unsigned long int)); if (ret) { memset(ioctlbuf+sizeof(unsigned long int), MAXIOCTL-sizeof(unsigned long int), 0xff); - printf("ioctl %ld unsuccesfull\n", cmd & 0xff); - } - ioctl(v4ldev, cmd, ioctlbuf+sizeof(unsigned long int)); + printf("ioctl %lx unsuccesfull, lets issue VIDIOCSINVALID (%x)\n", cmd, VIDIOCSINVALID); + ioctl(v4ldev, VIDIOCSINVALID); + } else + ioctl(v4ldev, cmd, ioctlbuf+sizeof(unsigned long int)); } return; } diff -Nur vloopback-0.90/example/invert.c vloopback-0.90-tibit/example/invert.c --- vloopback-0.90/example/invert.c Fri Jun 29 14:52:06 2001 +++ vloopback-0.90-tibit/example/invert.c Mon Nov 19 11:49:39 2001 @@ -177,13 +177,13 @@ devin=open (argv[1], O_RDWR); if (devin < 0) { - perror ("Failed to open video device"); + perror ("Failed to open input video device"); exit(1); } devout=open (argv[2], O_RDWR); if (devout < 0) { - perror ("Failed to open video device"); + perror ("Failed to open output video device"); exit(1); } diff -Nur vloopback-0.90/vloopback.c vloopback-0.90-tibit/vloopback.c --- vloopback-0.90/vloopback.c Fri Jun 29 14:52:06 2001 +++ vloopback-0.90-tibit/vloopback.c Mon Nov 26 20:53:33 2001 @@ -44,13 +44,19 @@ * Made vloopback_template sane * Added double buffering support * Made vloopback less verbose + * 20.11.01 (tibit) Made dev_offset option sane + * "Fixed" zerocopy mode by defining the ioctl + * VIDIOCSINVALID. An application which provides data + * has to issue it when it encounters an error in + * ioctl processing. See dummy.c for examples. */ -#define VLVER "0.90" + +#define VLVER "0.90-tibit1" #include #include -#include +#include #include #include #include @@ -58,7 +64,9 @@ #include #include #include +#include +#define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) /************************************************************ 2.2 support @@ -83,7 +91,7 @@ struct vloopback_device { struct video_device viddev; int pipenr; - int in; + int in; /* bool */ }; struct vloopback_pipe { @@ -105,6 +113,7 @@ unsigned int pid; unsigned int zerocopy; unsigned long int ioctlnr; + unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ unsigned int ioctllength; char *ioctldata; char *ioctlretdata; @@ -387,10 +396,14 @@ if (loops[nr]->zerocopy) { if (loopdev->in) { + //info("DEBUG: vl_read: ->in: pipenr: %d", nr); if (realcount > loops[nr]->ioctllength+sizeof(unsigned long int)) realcount=loops[nr]->ioctllength+sizeof(unsigned long int); + //info("DEBUG: vl_read: ->in: realcount: %lu", realcount); copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int)); - copy_to_user(buf+sizeof(unsigned long int) , loops[nr]->ioctldata, realcount-sizeof(unsigned long int)); + //info("DEBUG: vl_read: ->in: ioctlnr: %lu", loops[nr]->ioctlnr); + copy_to_user(buf+sizeof(unsigned long int) , loops[nr]->ioctldata, + realcount-sizeof(unsigned long int)); if (loops[nr]->ioctlnr==0) loops[nr]->ioctlnr=-1; return realcount; @@ -398,6 +411,7 @@ struct video_window vidwin; struct video_mmap vidmmap; struct video_picture vidpic; + //info("DEBUG: vl_read: ->out: pipenr: %d", nr); fake_ioctl(nr, VIDIOCGWIN, &vidwin); fake_ioctl(nr, VIDIOCGPICT, &vidpic); @@ -444,8 +458,10 @@ unsigned long page, pos; down(&loops[nr]->lock); + //info("DEBUG: vloopback_mmap: Enter"); if (loopdev->in) { /* Zero copy mode */ + //info("DEBUG: vloopback_mmap: Zero copy mode"); loops[nr]->zerocopy=1; if (loops[nr]->ropen) { info("Can't change size while opened for read"); @@ -500,34 +516,54 @@ if (!loopdev->in) { loops[nr]->ioctlnr=cmd; loops[nr]->ioctllength=_IOC_SIZE(cmd); + /* info("DEBUG: vl_ioctl: !loop->in"); */ + /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ + /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ if(copy_from_user(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd))) return -EFAULT; kill_proc(loops[nr]->pid, SIGIO, 1); interruptible_sleep_on(&loops[nr]->wait); - if (cmd & IOC_IN) { + if (loops[nr]->invalid_ioctl) { + //info ("DEBUG: There was an invalid ioctl"); + loops[nr]->invalid_ioctl = 0; + return -ENOTTY; + } + if (cmd & IOC_IN && !(cmd & IOC_OUT)) { + //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) { return -EINVAL; } + //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); return 0; } else { copy_to_user(arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)); + //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1"); return 0; } } else { - if (loops[nr]->ioctlnr!=cmd) + if ( (loops[nr]->ioctlnr!=cmd) && (cmd != (VIDIOCSINVALID))) { /* wrong ioctl */ + info("DEBUG: vo_ioctl: Wrong IOCTL"); return 0; - if (copy_from_user(loops[nr]->ioctlretdata, arg, loops[nr]->ioctllength)) - return -EFAULT; + } + if (cmd == VIDIOCSINVALID) { + loops[nr]->invalid_ioctl = 1; + } else { + if (copy_from_user(loops[nr]->ioctlretdata, arg, loops[nr]->ioctllength)) + return -EFAULT; + //info("DEBUG: vl_ioctl: loopdev->in: 1"); + } if (waitqueue_active(&loops[nr]->wait)) wake_up(&loops[nr]->wait); + //info("DEBUG: vl_ioctl: loopdev->in: 2"); loops[nr]->ioctlnr=-1; return 0; } } switch(cmd) { + /* Get capabilities */ case VIDIOCGCAP: { struct video_capability b; @@ -544,43 +580,55 @@ b.audios=0; b.maxwidth=loops[nr]->width; b.maxheight=loops[nr]->height; - b.minwidth=loops[nr]->width; - b.minheight=loops[nr]->height; + b.minwidth=20; + b.minheight=20; if(copy_to_user(arg, &b, sizeof(b))) return -EFAULT; return 0; } + /* Get channel info (sources) */ case VIDIOCGCHAN: { struct video_channel v; if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if(v.channel!=0) - return -EINVAL; + if(v.channel!=0) { + info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); + v.channel=0; + //return -EINVAL; + } v.flags=0; v.tuners=0; + v.norm=0; v.type = VIDEO_TYPE_CAMERA; - strcpy(v.name, "Loopback"); + /*strcpy(v.name, "Loopback"); -- tibit */ + strcpy(v.name, "Composite1"); if(copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; } + /* Set channel */ case VIDIOCSCHAN: { int v; if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; - if(v!=0) + if(v!=0) { + info("VIDIOCSCHAN: Invalid Channel, was %d", v); return -EINVAL; + } return 0; } + /* Get tuner abilities */ case VIDIOCGTUNER: { struct video_tuner v; if(copy_from_user(&v, arg, sizeof(v))!=0) return -EFAULT; - if(v.tuner) + if(v.tuner) { + info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); return -EINVAL; + } strcpy(v.name, "Format"); v.rangelow=0; v.rangehigh=0; @@ -590,6 +638,7 @@ return -EFAULT; return 0; } + /* Get picture properties */ case VIDIOCGPICT: { struct video_picture p; @@ -605,6 +654,7 @@ return 0; } + /* Set picture properties */ case VIDIOCSPICT: { struct video_picture p; @@ -617,6 +667,22 @@ loops[nr]->palette=p.palette; return 0; } + /* Get the video overlay window */ + case VIDIOCGWIN: + { + struct video_window vw; + vw.x=0; + vw.y=0; + vw.width=loops[nr]->width; + vw.height=loops[nr]->height; + vw.chromakey=0; + vw.flags=0; + vw.clipcount=0; + if(copy_to_user(arg, &vw, sizeof(vw))) + return -EFAULT; + return 0; + } + /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ case VIDIOCSWIN: { struct video_window vw; @@ -654,20 +720,7 @@ } return 0; } - case VIDIOCGWIN: - { - struct video_window vw; - vw.x=0; - vw.y=0; - vw.width=loops[nr]->width; - vw.height=loops[nr]->height; - vw.chromakey=0; - vw.flags=0; - vw.clipcount=0; - if(copy_to_user(arg, &vw, sizeof(vw))) - return -EFAULT; - return 0; - } + /* Memory map buffer info */ case VIDIOCGMBUF: { struct video_mbuf vm; @@ -680,6 +733,7 @@ return -EFAULT; return 0; } + /* Grab frames */ case VIDIOCMCAPTURE: { struct video_mmap vm; @@ -695,12 +749,15 @@ if (vm.frame > 2) return -EINVAL; /* Dirty xawtv hack :( */ + /* is this needed anymore? if (vm.width > 64 || vm.height > 64) if (vm.height!=loops[nr]->height || vm.width!=loops[nr]->width) return -EINVAL; + */ return 0; } + /* Sync with mmap grabbing */ case VIDIOCSYNC: { int frame; @@ -721,6 +778,7 @@ loops[nr]->framesread++; return 0; } + /* Get attached units */ case VIDIOCGUNIT: { struct video_unit vu; @@ -737,6 +795,7 @@ return -EFAULT; return 0; } + /* Get frame buffer */ case VIDIOCGFBUF: { struct video_buffer vb; @@ -749,7 +808,18 @@ return 0; } + /* Start, end capture */ case VIDIOCCAPTURE: + { + int start; + if (copy_from_user(&start, arg, sizeof(int))) + return -EFAULT; + if (start) info ("Capture started"); + else info ("Capture stopped"); + + return 0; + } + case VIDIOCGFREQ: case VIDIOCSFREQ: case VIDIOCGAUDIO: @@ -783,6 +853,7 @@ return 0; } + static struct video_device vloopback_template= { owner: THIS_MODULE, @@ -965,11 +1036,26 @@ static int create_pipe(int nr) { + int minor_in, minor_out; + if (dev_offset == -1) + minor_in = minor_out = -1; /* autoassign */ + else { + minor_in = 2*nr + dev_offset; + minor_out = 2*nr+1 + dev_offset; + } + loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); + if (!loops[nr]) + return -ENOMEM; loops[nr]->vloopin= kmalloc(sizeof(struct vloopback_device), GFP_KERNEL); + if (!loops[nr]->vloopin) + return -ENOMEM; loops[nr]->vloopout= kmalloc(sizeof(struct vloopback_device), GFP_KERNEL); + if (!loops[nr]->vloopout) + return -ENOMEM; loops[nr]->vloopin->pipenr=nr; loops[nr]->vloopout->pipenr=nr; + loops[nr]->invalid_ioctl = 0; /* tibit */ loops[nr]->buffer=NULL; loops[nr]->width=0; loops[nr]->height=0; @@ -990,7 +1076,7 @@ sprintf(((struct video_device *)loops[nr]->vloopout)->name, "Video loopback %d output", nr); init_waitqueue_head(&loops[nr]->wait); init_MUTEX(&loops[nr]->lock); - if (video_register_device(&loops[nr]->vloopin->viddev, VFL_TYPE_GRABBER, nr*2+dev_offset)==-1) { + if (video_register_device(&loops[nr]->vloopin->viddev, VFL_TYPE_GRABBER, minor_in)==-1) { kfree(loops[nr]->vloopin); kfree(loops[nr]->vloopout); kfree(loops[nr]); @@ -998,7 +1084,7 @@ info("error registering device"); return -ENODEV; } - if (video_register_device(&loops[nr]->vloopout->viddev, VFL_TYPE_GRABBER, nr*2+1+dev_offset)==-1) { + if (video_register_device(&loops[nr]->vloopout->viddev, VFL_TYPE_GRABBER, minor_out)==-1) { video_unregister_device(&loops[nr]->vloopin->viddev); kfree(loops[nr]->vloopin); kfree(loops[nr]->vloopout); @@ -1029,6 +1115,10 @@ MODULE_PARM_DESC(spares, "Nr of spare pipes that should be created"); MODULE_PARM(dev_offset, "i"); MODULE_PARM_DESC(dev_offset, "Prefered offset for video device numbers"); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 10) +MODULE_LICENSE("GPL"); +#endif EXPORT_NO_SYMBOLS;