comparison vloopback.c @ 7:2fce9e157b8d

Added some work around to work with kernel 2.6.27-rc3, added debug param.
author AngelCarpintero
date Sun, 24 Aug 2008 02:20:51 +0000
parents dc1f4ad7010c
children 80590d10a596
comparison
equal deleted inserted replaced
6:d3fdefea8bce 7:2fce9e157b8d
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 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/VideoFourLinuxLoopbackDevice 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!
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 *
141 * 17.08.08 (Angel Carpintero)
142 * kill_proc() deprecated ,pid API changed , type and owner not available in
143 * video_device struct, added param debug.
140 */ 144 */
141 145
142 146
143 #define VLOOPBACK_VERSION "1.2-trunk" 147 #define VLOOPBACK_VERSION "1.2-trunk"
144 148
148 #include <linux/kernel.h> 152 #include <linux/kernel.h>
149 #include <linux/module.h> 153 #include <linux/module.h>
150 #include <linux/pagemap.h> 154 #include <linux/pagemap.h>
151 155
152 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) 156 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
153 #include <media/v4l2-common.h> 157 #include <media/v4l2-common.h>
154 #endif 158 #endif
155 159
156 #include <linux/videodev.h> 160 #include <linux/videodev.h>
157 #include <linux/vmalloc.h> 161 #include <linux/vmalloc.h>
158 #include <linux/wait.h> 162 #include <linux/wait.h>
181 #include <asm/io.h> 185 #include <asm/io.h>
182 #endif 186 #endif
183 187
184 #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1) 188 #define VIDIOCSINVALID _IO('v',BASE_VIDIOCPRIVATE+1)
185 189
186 #define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" "", ## arg) 190 #define verbose(format, arg...) if (printk_ratelimit()) \
191 printk(KERN_INFO "[%s] %s: " format "\n" "", \
192 __FUNCTION__, __FILE__, ## arg)
193
194 #define info(format, arg...) if (printk_ratelimit()) \
195 printk(KERN_INFO "[%s] : " format "\n" "", \
196 __FUNCTION__, ## arg)
197
198 #define LOG_NODEBUG 0
199 #define LOG_FUNCTIONS 1
200 #define LOG_IOCTL 2
201 #define LOG_VERBOSE 3
187 202
188 struct vloopback_private { 203 struct vloopback_private {
189 int pipenr; 204 int pipenr;
190 int in; /* bool */ 205 int in; /* bool , is being feed ? */
191 }; 206 };
207
192 typedef struct vloopback_private *priv_ptr; 208 typedef struct vloopback_private *priv_ptr;
193 209
194 struct vloopback_pipe { 210 struct vloopback_pipe {
195 struct video_device *vloopin; 211 struct video_device *vloopin;
196 struct video_device *vloopout; 212 struct video_device *vloopout;
204 unsigned int wopen; 220 unsigned int wopen;
205 unsigned int ropen; 221 unsigned int ropen;
206 struct semaphore lock; 222 struct semaphore lock;
207 wait_queue_head_t wait; 223 wait_queue_head_t wait;
208 unsigned int frame; 224 unsigned int frame;
225 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
209 unsigned int pid; 226 unsigned int pid;
227 #else
228 struct pid *pid;
229 #endif
210 unsigned int zerocopy; 230 unsigned int zerocopy;
211 unsigned long int ioctlnr; 231 unsigned long int ioctlnr;
212 unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */ 232 unsigned int invalid_ioctl; /* 0 .. none invalid; 1 .. invalid */
213 unsigned int ioctllength; 233 unsigned int ioctllength;
214 char *ioctldata; 234 char *ioctldata;
217 237
218 #define MAX_PIPES 16 238 #define MAX_PIPES 16
219 #define N_BUFFS 2 /* Number of buffers used for pipes */ 239 #define N_BUFFS 2 /* Number of buffers used for pipes */
220 240
221 static struct vloopback_pipe *loops[MAX_PIPES]; 241 static struct vloopback_pipe *loops[MAX_PIPES];
222 static int nr_o_pipes=0; 242 static int nr_o_pipes = 0;
223 static int pipes=-1; 243 static int pipes = -1;
224 static int spares=0; 244 static int spares = 0;
225 static int pipesused=0; 245 static int pipesused = 0;
226 static int dev_offset=-1; 246 static int dev_offset = -1;
247 static unsigned int debug = LOG_NODEBUG;
227 248
228 /********************************************************************** 249 /**********************************************************************
229 * 250 *
230 * Memory management - revised for 2.6 kernels 251 * Memory management - revised for 2.6 kernels
231 * 252 *
235 * This is used when initializing the contents of the 256 * This is used when initializing the contents of the
236 * area and marking the pages as reserved. 257 * area and marking the pages as reserved.
237 */ 258 */
238 static inline unsigned long kvirt_to_pa(unsigned long adr) 259 static inline unsigned long kvirt_to_pa(unsigned long adr)
239 { 260 {
240 unsigned long kva; 261 unsigned long kva;
241 262
242 kva = (unsigned long)page_address(vmalloc_to_page((void *)adr)); 263 kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));
243 kva |= adr & (PAGE_SIZE-1); /* restore the offset */ 264 kva |= adr & (PAGE_SIZE-1); /* restore the offset */
244 return __pa(kva); 265 return __pa(kva);
245 } 266 }
301 static int create_pipe(int nr); 322 static int create_pipe(int nr);
302 323
303 static int fake_ioctl(int nr, unsigned long int cmd, void *arg) 324 static int fake_ioctl(int nr, unsigned long int cmd, void *arg)
304 { 325 {
305 unsigned long fw; 326 unsigned long fw;
306 327
307 loops[nr]->ioctlnr=cmd; 328 if (debug > LOG_NODEBUG)
329 info("Video loopback %d cmd %lu", nr, cmd);
330
331 loops[nr]->ioctlnr = cmd;
308 memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd)); 332 memcpy(loops[nr]->ioctldata, arg, _IOC_SIZE(cmd));
309 loops[nr]->ioctllength=_IOC_SIZE(cmd); 333 loops[nr]->ioctllength = _IOC_SIZE(cmd);
310 kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */ 334
335 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
336 kill_proc(loops[nr]->pid, SIGIO, 1); /* Signal the pipe feeder */
337 #else
338 kill_pid(loops[nr]->pid, SIGIO, 1);
339 #endif
340
311 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) 341 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
312 fw = loops[nr]->frameswrite; 342 fw = loops[nr]->frameswrite;
313 wait_event_interruptible(loops[nr]->wait, fw!=loops[nr]->frameswrite); 343 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite);
314 #else 344 #else
315 interruptible_sleep_on(&loops[nr]->wait); 345 interruptible_sleep_on(&loops[nr]->wait);
316 #endif 346 #endif
317 if (cmd & IOC_IN) { 347 if (cmd & IOC_IN) {
318 if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) 348 if (memcmp (arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)))
323 return 0; 353 return 0;
324 } 354 }
325 355
326 static int vloopback_open(struct inode *inod, struct file *f) 356 static int vloopback_open(struct inode *inod, struct file *f)
327 { 357 {
328 struct video_device *loopdev=video_devdata(f); 358 struct video_device *loopdev = video_devdata(f);
329 priv_ptr ptr=(priv_ptr)loopdev->priv; 359 priv_ptr ptr = (priv_ptr)loopdev->priv;
330 int nr=ptr->pipenr; 360 int nr = ptr->pipenr;
331 361
362 if (debug > LOG_NODEBUG)
363 info("Video loopback %d", nr);
332 364
333 /* Only allow a output to be opened if there is someone feeding 365 /* Only allow a output to be opened if there is someone feeding
334 * the pipe. 366 * the pipe.
335 */ 367 */
336 if (!ptr->in) { 368 if (!ptr->in) {
337 if (loops[nr]->buffer==NULL) { 369 if (loops[nr]->buffer == NULL)
338 return -EINVAL; 370 return -EINVAL;
339 } 371
340 loops[nr]->framesread=0; 372 loops[nr]->framesread = 0;
341 loops[nr]->ropen=1; 373 loops[nr]->ropen = 1;
342 } else { 374 } else {
343 if (loops[nr]->ropen || loops[nr]->wopen) 375 if (loops[nr]->ropen || loops[nr]->wopen)
344 return -EBUSY; 376 return -EBUSY;
345 loops[nr]->framesdumped=0; 377
346 loops[nr]->frameswrite=0; 378 loops[nr]->framesdumped = 0;
347 loops[nr]->wopen=1; 379 loops[nr]->frameswrite = 0;
348 loops[nr]->zerocopy=0; 380 loops[nr]->wopen = 1;
349 loops[nr]->ioctlnr=-1; 381 loops[nr]->zerocopy = 0;
382 loops[nr]->ioctlnr = -1;
350 pipesused++; 383 pipesused++;
351 if (nr_o_pipes-pipesused<spares) { 384 if (nr_o_pipes-pipesused<spares) {
352 if (!create_pipe(nr_o_pipes)) { 385 if (!create_pipe(nr_o_pipes)) {
353 info("Creating extra spare pipe"); 386 info("Creating extra spare pipe");
354 info("Loopback %d registered, input: video%d, output: video%d", 387 info("Loopback %d registered, input: video%d, output: video%d",
357 loops[nr_o_pipes]->vloopout->minor 390 loops[nr_o_pipes]->vloopout->minor
358 ); 391 );
359 nr_o_pipes++; 392 nr_o_pipes++;
360 } 393 }
361 } 394 }
362 loops[nr]->pid=current->pid; 395 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
396 loops[nr]->pid = current->pid;
397 #else
398 // TODO : Check in stable 2.6.27
399 loops[nr]->pid = task_pid(find_task_by_vpid(current->pid));
400 //loops[nr]->pid = task_pid(current);
401 #endif
402
403 if (debug > LOG_NODEBUG)
404 info("Current pid %d", current->pid);
363 } 405 }
364 return 0; 406 return 0;
365 } 407 }
366 408
367 static int vloopback_release(struct inode * inod, struct file *f) 409 static int vloopback_release(struct inode * inod, struct file *f)
368 { 410 {
369 struct video_device *loopdev=video_devdata(f); 411 struct video_device *loopdev = video_devdata(f);
370 priv_ptr ptr=(priv_ptr)loopdev->priv; 412 priv_ptr ptr = (priv_ptr)loopdev->priv;
371 int nr=ptr->pipenr; 413 int nr = ptr->pipenr;
372 414
415 if (debug > LOG_NODEBUG)
416 info("Video loopback %d", nr);
417
373 if (ptr->in) { 418 if (ptr->in) {
374 down(&loops[nr]->lock); 419 down(&loops[nr]->lock);
375 if (loops[nr]->buffer && !loops[nr]->ropen) { 420 if (loops[nr]->buffer && !loops[nr]->ropen) {
376 rvfree(loops[nr]->buffer, 421 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS);
377 loops[nr]->buflength*N_BUFFS); 422 loops[nr]->buffer = NULL;
378 loops[nr]->buffer=NULL;
379 } 423 }
380 up(&loops[nr]->lock); 424 up(&loops[nr]->lock);
381 loops[nr]->frameswrite++; 425 loops[nr]->frameswrite++;
382 if (waitqueue_active(&loops[nr]->wait)) 426 if (waitqueue_active(&loops[nr]->wait))
383 wake_up(&loops[nr]->wait); 427 wake_up(&loops[nr]->wait);
384 428
385 loops[nr]->width=0; 429 loops[nr]->width = 0;
386 loops[nr]->height=0; 430 loops[nr]->height = 0;
387 loops[nr]->palette=0; 431 loops[nr]->palette = 0;
388 loops[nr]->wopen=0; 432 loops[nr]->wopen = 0;
389 pipesused--; 433 pipesused--;
390 } else { 434 } else {
391 down(&loops[nr]->lock); 435 down(&loops[nr]->lock);
392 if (loops[nr]->buffer && !loops[nr]->wopen) { 436 if (loops[nr]->buffer && !loops[nr]->wopen) {
393 rvfree(loops[nr]->buffer, 437 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS);
394 loops[nr]->buflength*N_BUFFS); 438 loops[nr]->buffer = NULL;
395 loops[nr]->buffer=NULL;
396 } 439 }
397 up(&loops[nr]->lock); 440 up(&loops[nr]->lock);
398 loops[nr]->ropen=0; 441 loops[nr]->ropen = 0;
399 if (loops[nr]->zerocopy && loops[nr]->buffer) { 442 if (loops[nr]->zerocopy && loops[nr]->buffer) {
400 loops[nr]->ioctlnr=0; 443 loops[nr]->ioctlnr = 0;
401 loops[nr]->ioctllength=0; 444 loops[nr]->ioctllength = 0;
402 kill_proc(loops[nr]->pid, SIGIO, 1); 445 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
446 kill_proc(loops[nr]->pid, SIGIO, 1);
447 #else
448 kill_pid(loops[nr]->pid, SIGIO, 1);
449 #endif
403 } 450 }
404 } 451 }
405 452
406 return 0; 453 return 0;
407 } 454 }
408 455
409 static ssize_t vloopback_write(struct file *f, const char *buf, 456 static ssize_t vloopback_write(struct file *f, const char *buf,
410 size_t count, loff_t *offset) 457 size_t count, loff_t *offset)
411 { 458 {
412 struct video_device *loopdev=video_devdata(f); 459 struct video_device *loopdev = video_devdata(f);
413 priv_ptr ptr=(priv_ptr)loopdev->priv; 460 priv_ptr ptr = (priv_ptr)loopdev->priv;
414 int nr=ptr->pipenr; 461 int nr = ptr->pipenr;
415 unsigned long realcount=count; 462 unsigned long realcount = count;
416 463
464 if (debug > LOG_IOCTL)
465 info("Video loopback %d", nr);
466
417 if (!ptr->in) 467 if (!ptr->in)
418 return -EINVAL; 468 return -EINVAL;
469
419 if (loops[nr]->zerocopy) 470 if (loops[nr]->zerocopy)
420 return -EINVAL; 471 return -EINVAL;
421 472
422 if (loops[nr]->buffer==NULL) { 473 if (loops[nr]->buffer == NULL)
423 return -EINVAL; 474 return -EINVAL;
424 } 475
425
426 /* Anybody want some pictures??? */ 476 /* Anybody want some pictures??? */
427 if (!waitqueue_active(&loops[nr]->wait)) { 477 if (!waitqueue_active(&loops[nr]->wait)) {
428 loops[nr]->framesdumped++; 478 loops[nr]->framesdumped++;
429 return realcount; 479 return realcount;
430 } 480 }
432 down(&loops[nr]->lock); 482 down(&loops[nr]->lock);
433 if (!loops[nr]->buffer) { 483 if (!loops[nr]->buffer) {
434 up(&loops[nr]->lock); 484 up(&loops[nr]->lock);
435 return -EINVAL; 485 return -EINVAL;
436 } 486 }
487
437 if (realcount > loops[nr]->buflength) { 488 if (realcount > loops[nr]->buflength) {
438 realcount = loops[nr]->buflength; 489 realcount = loops[nr]->buflength;
439 info("Too much data! Only %ld bytes used.", realcount); 490 info("Too much data for Video loopback %d ! Only %ld bytes used.",
491 nr, realcount);
440 } 492 }
441 493
442 if (copy_from_user( 494 if (copy_from_user(loops[nr]->buffer + loops[nr]->frame * loops[nr]->buflength,
443 loops[nr]->buffer+loops[nr]->frame*loops[nr]->buflength, 495 buf, realcount))
444 buf, realcount 496 return -EFAULT;
445 )) return -EFAULT; 497
446 498 loops[nr]->frame = 0;
447 loops[nr]->frame=0;
448 up(&loops[nr]->lock); 499 up(&loops[nr]->lock);
449 500
450 loops[nr]->frameswrite++; 501 loops[nr]->frameswrite++;
451 wake_up(&loops[nr]->wait); 502 wake_up(&loops[nr]->wait);
452 503
453 return realcount; 504 return realcount;
454 } 505 }
455 506
456 static ssize_t vloopback_read (struct file * f, char * buf, size_t count, loff_t *offset) 507 static ssize_t vloopback_read(struct file * f, char * buf, size_t count,
457 { 508 loff_t *offset)
458 struct video_device *loopdev=video_devdata(f); 509 {
459 priv_ptr ptr=(priv_ptr)loopdev->priv; 510 struct video_device *loopdev = video_devdata(f);
460 int nr=ptr->pipenr; 511 priv_ptr ptr = (priv_ptr)loopdev->priv;
461 unsigned long realcount=count; 512 int nr = ptr->pipenr;
513 unsigned long realcount = count;
514
515 if (debug > LOG_IOCTL)
516 info("Video loopback %d", nr);
462 517
463 if (loops[nr]->zerocopy) { 518 if (loops[nr]->zerocopy) {
464 if (ptr->in) { 519 if (ptr->in) {
465 if (realcount > loops[nr]->ioctllength+sizeof(unsigned long int)) 520 if (realcount > loops[nr]->ioctllength + sizeof(unsigned long int))
466 realcount=loops[nr]->ioctllength+sizeof(unsigned long int); 521 realcount = loops[nr]->ioctllength + sizeof(unsigned long int);
522
467 if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int))) 523 if (copy_to_user(buf , &loops[nr]->ioctlnr, sizeof(unsigned long int)))
468 return -EFAULT; 524 return -EFAULT;
469 if (copy_to_user(buf+sizeof(unsigned long int) , loops[nr]->ioctldata, 525
470 realcount-sizeof(unsigned long int))) 526 if (copy_to_user(buf + sizeof(unsigned long int), loops[nr]->ioctldata,
527 realcount - sizeof(unsigned long int)))
471 return -EFAULT; 528 return -EFAULT;
472 if (loops[nr]->ioctlnr==0) 529
473 loops[nr]->ioctlnr=-1; 530 if (loops[nr]->ioctlnr == 0)
531 loops[nr]->ioctlnr = -1;
532
474 return realcount; 533 return realcount;
475 } else { 534 } else {
476 struct video_window vidwin; 535 struct video_window vidwin;
477 struct video_mmap vidmmap; 536 struct video_mmap vidmmap;
478 struct video_picture vidpic; 537 struct video_picture vidpic;
479 538
480 fake_ioctl(nr, VIDIOCGWIN, &vidwin); 539 fake_ioctl(nr, VIDIOCGWIN, &vidwin);
481 fake_ioctl(nr, VIDIOCGPICT, &vidpic); 540 fake_ioctl(nr, VIDIOCGPICT, &vidpic);
482 541
483 vidmmap.height=vidwin.height; 542 vidmmap.height = vidwin.height;
484 vidmmap.width=vidwin.width; 543 vidmmap.width = vidwin.width;
485 vidmmap.format=vidpic.palette; 544 vidmmap.format = vidpic.palette;
486 vidmmap.frame=0; 545 vidmmap.frame = 0;
546
487 if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap)) 547 if (fake_ioctl(nr, VIDIOCMCAPTURE, &vidmmap))
488 return 0; 548 return 0;
549
489 if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap)) 550 if (fake_ioctl(nr, VIDIOCSYNC, &vidmmap))
490 return 0; 551 return 0;
491 realcount=vidwin.height*vidwin.width*vidpic.depth; 552
492 } 553 realcount = vidwin.height * vidwin.width * vidpic.depth;
493 } 554 }
555 }
556
494 if (ptr->in) 557 if (ptr->in)
495 return -EINVAL; 558 return -EINVAL;
496 559
497 if (realcount > loops[nr]->buflength) { 560 if (realcount > loops[nr]->buflength) {
498 realcount = loops[nr]->buflength; 561 realcount = loops[nr]->buflength;
499 info("Not so much data in buffer!"); 562 info("Not so much data in buffer! for Video loopback %d", nr);
500 } 563 }
501 564
502 if (!loops[nr]->zerocopy) { 565 if (!loops[nr]->zerocopy) {
503 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) 566 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
504 unsigned long fw=loops[nr]->frameswrite; 567 unsigned long fw = loops[nr]->frameswrite;
505 568
506 wait_event_interruptible(loops[nr]->wait, fw!=loops[nr]->frameswrite); 569 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite);
507 #else 570 #else
508 interruptible_sleep_on(&loops[nr]->wait); 571 interruptible_sleep_on(&loops[nr]->wait);
509 #endif 572 #endif
510 } 573 }
511 574
512 down(&loops[nr]->lock); 575 down(&loops[nr]->lock);
513 if (!loops[nr]->buffer) { 576 if (!loops[nr]->buffer) {
514 up(&loops[nr]->lock); 577 up(&loops[nr]->lock);
515 return 0; 578 return 0;
516 } 579 }
580
517 if (copy_to_user(buf, loops[nr]->buffer, realcount)) 581 if (copy_to_user(buf, loops[nr]->buffer, realcount))
518 return -EFAULT; 582 return -EFAULT;
583
519 up(&loops[nr]->lock); 584 up(&loops[nr]->lock);
520 585
521 loops[nr]->framesread++; 586 loops[nr]->framesread++;
522 return realcount; 587 return realcount;
523 } 588 }
524 589
525 static int vloopback_mmap(struct file *f, struct vm_area_struct *vma) 590 static int vloopback_mmap(struct file *f, struct vm_area_struct *vma)
526 { 591 {
527 struct video_device *loopdev=video_devdata(f); 592 struct video_device *loopdev = video_devdata(f);
528 priv_ptr ptr=(priv_ptr)loopdev->priv; 593 priv_ptr ptr = (priv_ptr)loopdev->priv;
529 int nr=ptr->pipenr; 594 int nr = ptr->pipenr;
530 unsigned long start = (unsigned long)vma->vm_start; 595 unsigned long start = (unsigned long)vma->vm_start;
531 long size = vma->vm_end - vma->vm_start; 596 long size = vma->vm_end - vma->vm_start;
532 unsigned long page, pos; 597 unsigned long page, pos;
533 598
599 if (debug > LOG_NODEBUG)
600 info("Video loopback %d", nr);
601
534 down(&loops[nr]->lock); 602 down(&loops[nr]->lock);
603
535 if (ptr->in) { 604 if (ptr->in) {
536 loops[nr]->zerocopy=1; 605 loops[nr]->zerocopy = 1;
606
537 if (loops[nr]->ropen) { 607 if (loops[nr]->ropen) {
538 info("Can't change size while opened for read"); 608 info("Can't change size while opened for read in Video loopback %d",
609 nr);
539 up(&loops[nr]->lock); 610 up(&loops[nr]->lock);
540 return -EINVAL; 611 return -EINVAL;
541 } 612 }
613
542 if (!size) { 614 if (!size) {
543 up(&loops[nr]->lock); 615 up(&loops[nr]->lock);
544 return -EINVAL; 616 info("Invalid size Video loopback %d", nr);
545 } 617 return -EINVAL;
618 }
619
546 if (loops[nr]->buffer) 620 if (loops[nr]->buffer)
547 rvfree(loops[nr]->buffer, loops[nr]->buflength*N_BUFFS); 621 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS);
548 loops[nr]->buflength=size; 622
549 loops[nr]->buffer=rvmalloc(loops[nr]->buflength*N_BUFFS); 623 loops[nr]->buflength = size;
550 } 624 loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS);
551 if (loops[nr]->buffer == NULL) { 625 }
626
627 if (loops[nr]->buffer == NULL) {
552 up(&loops[nr]->lock); 628 up(&loops[nr]->lock);
553 return -EINVAL; 629 return -EINVAL;
554 } 630 }
555 631
556 if (size > (((N_BUFFS * loops[nr]->buflength) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { 632 if (size > (((N_BUFFS * loops[nr]->buflength) + PAGE_SIZE - 1)
633 & ~(PAGE_SIZE - 1))) {
557 up(&loops[nr]->lock); 634 up(&loops[nr]->lock);
558 return -EINVAL; 635 return -EINVAL;
559 } 636 }
560 637
561 pos = (unsigned long)loops[nr]->buffer; 638 pos = (unsigned long)loops[nr]->buffer;
562 while (size > 0) { 639
640 while (size > 0) {
563 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) 641 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
564 page = kvirt_to_pa(pos); 642 page = kvirt_to_pa(pos);
565 if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) { 643 if (remap_page_range(vma,start, page, PAGE_SIZE, PAGE_SHARED)) {
566 #else 644 #else
567 page = vmalloc_to_pfn((void *)pos); 645 page = vmalloc_to_pfn((void *)pos);
568 if (remap_pfn_range(vma, start, page, PAGE_SIZE, 646 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
569 PAGE_SHARED)) { 647 #endif
570 #endif 648 up(&loops[nr]->lock);
571 up(&loops[nr]->lock); 649 return -EAGAIN;
572 return -EAGAIN; 650 }
573 } 651 start += PAGE_SIZE;
574 start += PAGE_SIZE; 652 pos += PAGE_SIZE;
575 pos += PAGE_SIZE;
576 size -= PAGE_SIZE; 653 size -= PAGE_SIZE;
577 } 654 }
655
578 up(&loops[nr]->lock); 656 up(&loops[nr]->lock);
579 657
580 return 0; 658 return 0;
581 } 659 }
582 660
583 static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd, unsigned long arg) 661 static int vloopback_ioctl(struct inode *inod, struct file *f, unsigned int cmd,
584 { 662 unsigned long arg)
585 struct video_device *loopdev=video_devdata(f); 663 {
586 priv_ptr ptr=(priv_ptr)loopdev->priv; 664 struct video_device *loopdev = video_devdata(f);
587 int nr=ptr->pipenr; 665 priv_ptr ptr = (priv_ptr)loopdev->priv;
666 int nr = ptr->pipenr;
588 int i; 667 int i;
668
669 if (debug > LOG_NODEBUG)
670 info("Video loopback %d cmd %u", nr, cmd);
589 671
590 if (loops[nr]->zerocopy) { 672 if (loops[nr]->zerocopy) {
591 if (!ptr->in) { 673 if (!ptr->in) {
592 loops[nr]->ioctlnr=cmd; 674 loops[nr]->ioctlnr = cmd;
593 loops[nr]->ioctllength=_IOC_SIZE(cmd); 675 loops[nr]->ioctllength = _IOC_SIZE(cmd);
594 /* info("DEBUG: vl_ioctl: !loop->in"); */ 676 /* info("DEBUG: vl_ioctl: !loop->in"); */
595 /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */ 677 /* info("DEBUG: vl_ioctl: cmd %lu", cmd); */
596 /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */ 678 /* info("DEBUG: vl_ioctl: len %lu", loops[nr]->ioctllength); */
597 if(copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd))) 679 if (copy_from_user(loops[nr]->ioctldata, (void*)arg, _IOC_SIZE(cmd)))
598 return -EFAULT; 680 return -EFAULT;
599 kill_proc(loops[nr]->pid, SIGIO, 1); 681 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
682 kill_proc(loops[nr]->pid, SIGIO, 1);
683 #else
684 kill_pid(loops[nr]->pid, SIGIO, 1);
685 #endif
686
600 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) 687 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
601 wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr==-1); 688 wait_event_interruptible(loops[nr]->wait, loops[nr]->ioctlnr == -1);
602 #else 689 #else
603 interruptible_sleep_on(&loops[nr]->wait); 690 interruptible_sleep_on(&loops[nr]->wait);
604 #endif 691 #endif
605 692
606 if (loops[nr]->invalid_ioctl) { 693 if (loops[nr]->invalid_ioctl) {
607 //info ("DEBUG: There was an invalid ioctl"); 694 info ("There was an invalid ioctl in Video loopback %d", nr);
608 loops[nr]->invalid_ioctl = 0; 695 loops[nr]->invalid_ioctl = 0;
609 return -ENOTTY; 696 return -ENOTTY;
610 } 697 }
698
611 if (cmd & IOC_IN && !(cmd & IOC_OUT)) { 699 if (cmd & IOC_IN && !(cmd & IOC_OUT)) {
612 //info("DEBUG: vl_ioctl: cmd & IOC_IN 1"); 700 //info("DEBUG: vl_ioctl: cmd & IOC_IN 1");
613 if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd))) { 701 if (memcmp(loops[nr]->ioctlretdata, loops[nr]->ioctldata, _IOC_SIZE(cmd)))
614 return -EINVAL; 702 return -EINVAL;
615 } 703
616 //info("DEBUG: vl_ioctl: cmd & IOC_IN 2"); 704 //info("DEBUG: vl_ioctl: cmd & IOC_IN 2");
617 return 0; 705 return 0;
618 } else { 706 } else {
619 if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd))) 707 if (copy_to_user((void*)arg, loops[nr]->ioctlretdata, _IOC_SIZE(cmd)))
620 return -EFAULT; 708 return -EFAULT;
621 //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1"); 709 //info("DEBUG: vl_ioctl: !(cmd & IOC_IN) 1");
622 return 0; 710 return 0;
623 } 711 }
624 } else { 712 } else {
625 if ( (loops[nr]->ioctlnr!=cmd) && (cmd != (VIDIOCSINVALID))) { 713 if ((loops[nr]->ioctlnr != cmd) && (cmd != (VIDIOCSINVALID))) {
626 /* wrong ioctl */ 714 /* wrong ioctl */
627 info("DEBUG: vo_ioctl: Wrong IOCTL"); 715 info("Wrong IOCTL %u in Video loopback %d", cmd, nr);
628 return 0; 716 return 0;
629 } 717 }
718
630 if (cmd == VIDIOCSINVALID) { 719 if (cmd == VIDIOCSINVALID) {
631 loops[nr]->invalid_ioctl = 1; 720 loops[nr]->invalid_ioctl = 1;
632 } else { 721 } else if (copy_from_user(loops[nr]->ioctlretdata,
633 if (copy_from_user(loops[nr]->ioctlretdata, (void*)arg, loops[nr]->ioctllength)) 722 (void*)arg, loops[nr]->ioctllength)) {
634 return -EFAULT; 723 return -EFAULT;
635 } 724 }
636 loops[nr]->ioctlnr=-1; 725
726 loops[nr]->ioctlnr = -1;
727
637 if (waitqueue_active(&loops[nr]->wait)) 728 if (waitqueue_active(&loops[nr]->wait))
638 wake_up(&loops[nr]->wait); 729 wake_up(&loops[nr]->wait);
730
639 return 0; 731 return 0;
640 } 732 }
641 } 733 }
734
642 switch(cmd) 735 switch(cmd)
643 { 736 {
644 /* Get capabilities */ 737 /* Get capabilities */
645 case VIDIOCGCAP: 738 case VIDIOCGCAP:
646 { 739 {
647 struct video_capability b; 740 struct video_capability b;
648 if (ptr->in) { 741 if (ptr->in) {
649 sprintf(b.name, "Video loopback %d input", 742 sprintf(b.name, "Video loopback %d input", nr);
650 ptr->pipenr); 743 b.type = 0;
651 b.type = 0; 744 } else {
652 } else { 745 sprintf(b.name, "Video loopback %d output", nr);
653 sprintf(b.name, "Video loopback %d output", 746 b.type = VID_TYPE_CAPTURE;
654 ptr->pipenr); 747 }
655 b.type = VID_TYPE_CAPTURE; 748
656 } 749 b.channels = 1;
657 b.channels=1; 750 b.audios = 0;
658 b.audios=0; 751 b.maxwidth = loops[nr]->width;
659 b.maxwidth=loops[nr]->width; 752 b.maxheight = loops[nr]->height;
660 b.maxheight=loops[nr]->height; 753 b.minwidth = 20;
661 b.minwidth=20; 754 b.minheight = 20;
662 b.minheight=20; 755
663 if(copy_to_user((void*)arg, &b, sizeof(b))) 756 if (copy_to_user((void*)arg, &b, sizeof(b)))
664 return -EFAULT; 757 return -EFAULT;
758
759 return 0;
760 }
761 /* Get channel info (sources) */
762 case VIDIOCGCHAN:
763 {
764 struct video_channel v;
765 if (copy_from_user(&v, (void*)arg, sizeof(v)))
766 return -EFAULT;
767
768 if (v.channel != 0) {
769 info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel);
770 v.channel = 0;
771 //return -EINVAL;
772 }
773
774 v.flags = 0;
775 v.tuners = 0;
776 v.norm = 0;
777 v.type = VIDEO_TYPE_CAMERA;
778 /*strcpy(v.name, "Loopback"); -- tibit */
779 strcpy(v.name, "Composite1");
780
781 if (copy_to_user((void*)arg, &v, sizeof(v)))
782 return -EFAULT;
783
784 return 0;
785 }
786 /* Set channel */
787 case VIDIOCSCHAN:
788 {
789 int v;
790
791 if (copy_from_user(&v, (void*)arg, sizeof(v)))
792 return -EFAULT;
793
794 if (v != 0) {
795 info("VIDIOCSCHAN: Invalid Channel, was %d", v);
796 return -EINVAL;
797 }
798
799 return 0;
800 }
801 /* Get tuner abilities */
802 case VIDIOCGTUNER:
803 {
804 struct video_tuner v;
805
806 if (copy_from_user(&v, (void*)arg, sizeof(v)) != 0)
807 return -EFAULT;
808
809 if (v.tuner) {
810 info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner);
811 return -EINVAL;
812 }
813
814 strcpy(v.name, "Format");
815 v.rangelow = 0;
816 v.rangehigh = 0;
817 v.flags = 0;
818 v.mode = VIDEO_MODE_AUTO;
819
820 if (copy_to_user((void*)arg,&v, sizeof(v)) != 0)
821 return -EFAULT;
822
823 return 0;
824 }
825 /* Get picture properties */
826 case VIDIOCGPICT:
827 {
828 struct video_picture p;
829
830 p.colour = 0x8000;
831 p.hue = 0x8000;
832 p.brightness = 0x8000;
833 p.contrast = 0x8000;
834 p.whiteness = 0x8000;
835 p.depth = 0x8000;
836 p.palette = loops[nr]->palette;
837
838 if (copy_to_user((void*)arg, &p, sizeof(p)))
839 return -EFAULT;
840
841 return 0;
842 }
843 /* Set picture properties */
844 case VIDIOCSPICT:
845 {
846 struct video_picture p;
847
848 if (copy_from_user(&p, (void*)arg, sizeof(p)))
849 return -EFAULT;
850
851 if (!ptr->in) {
852 if (p.palette != loops[nr]->palette)
853 return -EINVAL;
854 } else {
855 loops[nr]->palette = p.palette;
856 }
857
858 return 0;
859 }
860 /* Get the video overlay window */
861 case VIDIOCGWIN:
862 {
863 struct video_window vw;
864
865 vw.x = 0;
866 vw.y = 0;
867 vw.width = loops[nr]->width;
868 vw.height = loops[nr]->height;
869 vw.chromakey = 0;
870 vw.flags = 0;
871 vw.clipcount = 0;
872
873 if (copy_to_user((void*)arg, &vw, sizeof(vw)))
874 return -EFAULT;
875
876 return 0;
877 }
878 /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
879 case VIDIOCSWIN:
880 {
881 struct video_window vw;
882
883 if (copy_from_user(&vw, (void*)arg, sizeof(vw)))
884 return -EFAULT;
885
886 if (vw.flags)
887 return -EINVAL;
888
889 if (vw.clipcount)
890 return -EINVAL;
891
892 if (loops[nr]->height == vw.height &&
893 loops[nr]->width == vw.width)
665 return 0; 894 return 0;
666 } 895
667 /* Get channel info (sources) */ 896 if (!ptr->in) {
668 case VIDIOCGCHAN: 897 return -EINVAL;
669 { 898 } else {
670 struct video_channel v; 899 loops[nr]->height = vw.height;
671 if(copy_from_user(&v, (void*)arg, sizeof(v))) 900 loops[nr]->width = vw.width;
672 return -EFAULT; 901 /* Make sure nobody is using the buffer while we
673 if(v.channel!=0) { 902 fool around with it.
674 info("VIDIOCGCHAN: Invalid Channel, was %d", v.channel); 903 We are also not allowing changes while
675 v.channel=0; 904 somebody using mmap has the output open.
676 //return -EINVAL; 905 */
677 } 906 down(&loops[nr]->lock);
678 v.flags=0; 907 if (loops[nr]->ropen) {
679 v.tuners=0; 908 info("Can't change size while opened for read");
680 v.norm=0; 909 up(&loops[nr]->lock);
681 v.type = VIDEO_TYPE_CAMERA;
682 /*strcpy(v.name, "Loopback"); -- tibit */
683 strcpy(v.name, "Composite1");
684 if(copy_to_user((void*)arg, &v, sizeof(v)))
685 return -EFAULT;
686 return 0;
687 }
688 /* Set channel */
689 case VIDIOCSCHAN:
690 {
691 int v;
692 if(copy_from_user(&v, (void*)arg, sizeof(v)))
693 return -EFAULT;
694 if(v!=0) {
695 info("VIDIOCSCHAN: Invalid Channel, was %d", v);
696 return -EINVAL; 910 return -EINVAL;
697 } 911 }
698 return 0; 912
699 } 913 if (loops[nr]->buffer)
700 /* Get tuner abilities */ 914 rvfree(loops[nr]->buffer, loops[nr]->buflength * N_BUFFS);
701 case VIDIOCGTUNER: 915
702 { 916 loops[nr]->buflength = vw.width * vw.height * 4;
703 struct video_tuner v; 917 loops[nr]->buffer = rvmalloc(loops[nr]->buflength * N_BUFFS);
704 if(copy_from_user(&v, (void*)arg, sizeof(v))!=0) 918 up(&loops[nr]->lock);
705 return -EFAULT; 919 }
706 if(v.tuner) { 920 return 0;
707 info("VIDIOCGTUNER: Invalid Tuner, was %d", v.tuner); 921 }
708 return -EINVAL; 922 /* Memory map buffer info */
709 } 923 case VIDIOCGMBUF:
710 strcpy(v.name, "Format"); 924 {
711 v.rangelow=0; 925 struct video_mbuf vm;
712 v.rangehigh=0;
713 v.flags=0;
714 v.mode=VIDEO_MODE_AUTO;
715 if(copy_to_user((void*)arg,&v, sizeof(v))!=0)
716 return -EFAULT;
717 return 0;
718 }
719 /* Get picture properties */
720 case VIDIOCGPICT:
721 {
722 struct video_picture p;
723 p.colour=0x8000;
724 p.hue=0x8000;
725 p.brightness=0x8000;
726 p.contrast=0x8000;
727 p.whiteness=0x8000;
728 p.depth=0x8000;
729 p.palette=loops[nr]->palette;
730 if(copy_to_user((void*)arg, &p, sizeof(p)))
731 return -EFAULT;
732 return 0;
733
734 }
735 /* Set picture properties */
736 case VIDIOCSPICT:
737 {
738 struct video_picture p;
739 if(copy_from_user(&p, (void*)arg, sizeof(p)))
740 return -EFAULT;
741 if (!ptr->in) {
742 if (p.palette!=loops[nr]->palette)
743 return -EINVAL;
744 } else
745 loops[nr]->palette=p.palette;
746 return 0;
747 }
748 /* Get the video overlay window */
749 case VIDIOCGWIN:
750 {
751 struct video_window vw;
752 vw.x=0;
753 vw.y=0;
754 vw.width=loops[nr]->width;
755 vw.height=loops[nr]->height;
756 vw.chromakey=0;
757 vw.flags=0;
758 vw.clipcount=0;
759 if(copy_to_user((void*)arg, &vw, sizeof(vw)))
760 return -EFAULT;
761 return 0;
762 }
763 /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */
764 case VIDIOCSWIN:
765 {
766 struct video_window vw;
767 926
768 if(copy_from_user(&vw, (void*)arg, sizeof(vw))) 927 vm.size = loops[nr]->buflength * N_BUFFS;
769 return -EFAULT; 928 vm.frames = N_BUFFS;
770 if(vw.flags) 929 for (i = 0; i < vm.frames; i++)
771 return -EINVAL; 930 vm.offsets[i] = i * loops[nr]->buflength;
772 if(vw.clipcount) 931
773 return -EINVAL; 932 if (copy_to_user((void*)arg, &vm, sizeof(vm)))
774 if (loops[nr]->height==vw.height && 933 return -EFAULT;
775 loops[nr]->width==vw.width) 934
776 return 0; 935 return 0;
777 if(!ptr->in) { 936 }
778 return -EINVAL; 937 /* Grab frames */
779 } else { 938 case VIDIOCMCAPTURE:
780 loops[nr]->height=vw.height; 939 {
781 loops[nr]->width=vw.width; 940 struct video_mmap vm;
782 /* Make sure nobody is using the buffer while we 941
783 fool around with it. 942 if (ptr->in)
784 We are also not allowing changes while 943 return -EINVAL;
785 somebody using mmap has the output open. 944
786 */ 945 if (!loops[nr]->buffer)
787 down(&loops[nr]->lock); 946 return -EINVAL;
788 if (loops[nr]->ropen) { 947
789 info("Can't change size while opened for read"); 948 if (copy_from_user(&vm, (void*)arg, sizeof(vm)))
790 up(&loops[nr]->lock); 949 return -EFAULT;
791 return -EINVAL; 950
792 } 951 if (vm.format != loops[nr]->palette)
793 if (loops[nr]->buffer) 952 return -EINVAL;
794 rvfree(loops[nr]->buffer, loops[nr]->buflength*N_BUFFS); 953
795 loops[nr]->buflength=vw.width*vw.height*4; 954 if (vm.frame > N_BUFFS)
796 loops[nr]->buffer=rvmalloc(loops[nr]->buflength*N_BUFFS); 955 return -EINVAL;
797 up(&loops[nr]->lock); 956
798 } 957 return 0;
799 return 0; 958 }
800 } 959 /* Sync with mmap grabbing */
801 /* Memory map buffer info */ 960 case VIDIOCSYNC:
802 case VIDIOCGMBUF: 961 {
803 { 962 int frame;
804 struct video_mbuf vm; 963 unsigned long fw;
964
965 if (copy_from_user((void *)&frame, (void*)arg, sizeof(int)))
966 return -EFAULT;
967
968 if (ptr->in)
969 return -EINVAL;
970
971 if (!loops[nr]->buffer)
972 return -EINVAL;
973
974 /* Ok, everything should be alright since the program
975 should have called VIDIOMCAPTURE and we are ready to
976 do the 'capturing' */
977 if (frame > 1)
978 return -EINVAL;
979
980 loops[nr]->frame = frame;
981 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
982 fw = loops[nr]->frameswrite;
983 wait_event_interruptible(loops[nr]->wait, fw != loops[nr]->frameswrite);
984 #else
985 interruptible_sleep_on(&loops[nr]->wait);
986 #endif
987 if (!loops[nr]->buffer) /* possibly released during sleep */
988 return -EINVAL;
989
990 loops[nr]->framesread++;
991
992 return 0;
993 }
994 /* Get attached units */
995 case VIDIOCGUNIT:
996 {
997 struct video_unit vu;
805 998
806 vm.size=loops[nr]->buflength*N_BUFFS; 999 if (ptr->in)
807 vm.frames=N_BUFFS; 1000 vu.video = loops[nr]->vloopout->minor;
808 for (i=0; i<vm.frames; i++) 1001 else
809 vm.offsets[i]=i*loops[nr]->buflength; 1002 vu.video = loops[nr]->vloopin->minor;
810 if(copy_to_user((void*)arg, &vm, sizeof(vm))) 1003
811 return -EFAULT; 1004 vu.vbi = VIDEO_NO_UNIT;
812 return 0; 1005 vu.radio = VIDEO_NO_UNIT;
813 } 1006 vu.audio = VIDEO_NO_UNIT;
814 /* Grab frames */ 1007 vu.teletext = VIDEO_NO_UNIT;
815 case VIDIOCMCAPTURE: 1008
816 { 1009 if (copy_to_user((void*)arg, &vu, sizeof(vu)))
817 struct video_mmap vm; 1010 return -EFAULT;
818 1011
819 if (ptr->in) 1012 return 0;
820 return -EINVAL; 1013 }
821 if (!loops[nr]->buffer) 1014 /* Get frame buffer */
822 return -EINVAL; 1015 case VIDIOCGFBUF:
823 if (copy_from_user(&vm, (void*)arg, sizeof(vm))) 1016 {
824 return -EFAULT; 1017 struct video_buffer vb;
825 if (vm.format!=loops[nr]->palette) 1018
826 return -EINVAL; 1019 memset(&vb, 0, sizeof(vb));
827 if (vm.frame > N_BUFFS) 1020 vb.base = NULL;
828 return -EINVAL; 1021
829 return 0; 1022 if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
830 } 1023 return -EFAULT;
831 /* Sync with mmap grabbing */ 1024
832 case VIDIOCSYNC: 1025 return 0;
833 { 1026 }
834 int frame; 1027 /* Start, end capture */
835 unsigned long fw; 1028 case VIDIOCCAPTURE:
836 1029 {
837 if (copy_from_user((void *)&frame, (void*)arg, sizeof(int))) 1030 int start;
838 return -EFAULT; 1031
839 if (ptr->in) 1032 if (copy_from_user(&start, (void*)arg, sizeof(int)))
840 return -EINVAL; 1033 return -EFAULT;
841 if (!loops[nr]->buffer) 1034
842 return -EINVAL; 1035 if (start) {
843 /* Ok, everything should be alright since the program 1036 info ("Video loopback %d Capture started", nr);
844 should have called VIDIOMCAPTURE and we are ready to 1037 } else {
845 do the 'capturing' */ 1038 info ("Video loopback %d Capture stopped", nr);
846 if (frame > 1) 1039 }
847 return -EINVAL; 1040
848 loops[nr]->frame=frame; 1041 return 0;
849 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) 1042 }
850 fw = loops[nr]->frameswrite; 1043 case VIDIOCGFREQ:
851 wait_event_interruptible(loops[nr]->wait, fw!=loops[nr]->frameswrite); 1044 case VIDIOCSFREQ:
852 #else 1045 case VIDIOCGAUDIO:
853 interruptible_sleep_on(&loops[nr]->wait); 1046 case VIDIOCSAUDIO:
854 #endif 1047 return -EINVAL;
855 if (!loops[nr]->buffer) /* possibly released during sleep */ 1048 case VIDIOCKEY:
856 return -EINVAL; 1049 return 0;
857 loops[nr]->framesread++; 1050 default:
858 return 0; 1051 return -ENOTTY;
859 } 1052 //return -ENOIOCTLCMD;
860 /* Get attached units */
861 case VIDIOCGUNIT:
862 {
863 struct video_unit vu;
864
865 if (ptr->in)
866 vu.video=loops[nr]->vloopout->minor;
867 else
868 vu.video=loops[nr]->vloopin->minor;
869 vu.vbi=VIDEO_NO_UNIT;
870 vu.radio=VIDEO_NO_UNIT;
871 vu.audio=VIDEO_NO_UNIT;
872 vu.teletext=VIDEO_NO_UNIT;
873 if (copy_to_user((void*)arg, &vu, sizeof(vu)))
874 return -EFAULT;
875 return 0;
876 }
877 /* Get frame buffer */
878 case VIDIOCGFBUF:
879 {
880 struct video_buffer vb;
881
882 memset(&vb, 0, sizeof(vb));
883 vb.base=NULL;
884
885 if(copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
886 return -EFAULT;
887
888 return 0;
889 }
890 /* Start, end capture */
891 case VIDIOCCAPTURE:
892 {
893 int start;
894 if (copy_from_user(&start, (void*)arg, sizeof(int)))
895 return -EFAULT;
896 if (start) info ("Capture started");
897 else info ("Capture stopped");
898
899 return 0;
900 }
901
902 case VIDIOCGFREQ:
903 case VIDIOCSFREQ:
904 case VIDIOCGAUDIO:
905 case VIDIOCSAUDIO:
906 return -EINVAL;
907 case VIDIOCKEY:
908 return 0;
909 default:
910 return -ENOTTY;
911 //return -ENOIOCTLCMD;
912 } 1053 }
913 return 0; 1054 return 0;
914 } 1055 }
915 1056
916 static unsigned int vloopback_poll(struct file *f, struct poll_table_struct *wait) 1057 static unsigned int vloopback_poll(struct file *f, struct poll_table_struct *wait)
917 { 1058 {
918 struct video_device *loopdev=video_devdata(f); 1059 struct video_device *loopdev = video_devdata(f);
919 priv_ptr ptr=(priv_ptr)loopdev->priv; 1060 priv_ptr ptr = (priv_ptr)loopdev->priv;
920 int nr=ptr->pipenr; 1061 int nr = ptr->pipenr;
921 1062
922 if (loopdev==NULL) 1063 if (debug > LOG_NODEBUG)
1064 info("Video loopback %d", nr);
1065
1066 if (loopdev == NULL)
923 return -EFAULT; 1067 return -EFAULT;
1068
924 if (!ptr->in) 1069 if (!ptr->in)
925 return 0; 1070 return 0;
926 1071
927 if (loops[nr]->ioctlnr!=-1) { 1072 if (loops[nr]->ioctlnr != -1) {
928 if (loops[nr]->zerocopy) { 1073 if (loops[nr]->zerocopy) {
929 return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM); 1074 return (POLLIN | POLLPRI | POLLOUT | POLLRDNORM);
930 } else { 1075 } else {
931 return (POLLOUT); 1076 return (POLLOUT);
932 } 1077 }
933 } 1078 }
934 return 0; 1079 return 0;
935 } 1080 }
936 1081
937 static struct file_operations fileops_template= 1082 static struct file_operations fileops_template =
938 { 1083 {
939 owner: THIS_MODULE, 1084 owner: THIS_MODULE,
940 open: vloopback_open, 1085 open: vloopback_open,
941 release: vloopback_release, 1086 release: vloopback_release,
942 read: vloopback_read, 1087 read: vloopback_read,
944 poll: vloopback_poll, 1089 poll: vloopback_poll,
945 ioctl: vloopback_ioctl, 1090 ioctl: vloopback_ioctl,
946 mmap: vloopback_mmap, 1091 mmap: vloopback_mmap,
947 }; 1092 };
948 1093
949 static struct video_device vloopback_template= 1094 static struct video_device vloopback_template =
950 { 1095 {
951 owner: THIS_MODULE, 1096 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
1097 owner: THIS_MODULE,
1098 type: VID_TYPE_CAPTURE,
1099 #endif
1100 minor: -1,
952 name: "Video Loopback", 1101 name: "Video Loopback",
953 type: VID_TYPE_CAPTURE,
954 fops: &fileops_template, 1102 fops: &fileops_template,
955 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) 1103 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
956 release: video_device_release, 1104 release: video_device_release,
957 #endif 1105 #endif
958 }; 1106 };
959 1107
960 static int create_pipe(int nr) 1108 static int create_pipe(int nr)
961 { 1109 {
962 int minor_in, minor_out , ret; 1110 int minor_in, minor_out , ret;
963 1111
964 if (dev_offset == -1) 1112 if (debug > LOG_NODEBUG)
1113 info("Video loopback %d", nr);
1114
1115 if (dev_offset == -1) {
965 minor_in = minor_out = -1; /* autoassign */ 1116 minor_in = minor_out = -1; /* autoassign */
966 else { 1117 } else {
967 minor_in = 2*nr + dev_offset; 1118 minor_in = 2 * nr + dev_offset;
968 minor_out = 2*nr+1 + dev_offset; 1119 minor_out = 2 * nr + 1 + dev_offset;
969 } 1120 }
970 1121
971 /* allocate space for this pipe */ 1122 /* allocate space for this pipe */
972 loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL); 1123 loops[nr]= kmalloc(sizeof(struct vloopback_pipe), GFP_KERNEL);
1124
973 if (!loops[nr]) 1125 if (!loops[nr])
974 return -ENOMEM; 1126 return -ENOMEM;
975 /* set up a new video device plus our private area */ 1127 /* set up a new video device plus our private area */
976 loops[nr]->vloopin= video_device_alloc(); 1128 loops[nr]->vloopin = video_device_alloc();
1129
977 if (loops[nr]->vloopin == NULL) 1130 if (loops[nr]->vloopin == NULL)
978 return -ENOMEM; 1131 return -ENOMEM;
979 *loops[nr]->vloopin = vloopback_template; 1132 *loops[nr]->vloopin = vloopback_template;
980 loops[nr]->vloopin->priv= kmalloc(sizeof(struct vloopback_private), 1133 loops[nr]->vloopin->priv = kmalloc(sizeof(struct vloopback_private),
981 GFP_KERNEL); 1134 GFP_KERNEL);
982 if (loops[nr]->vloopin->priv == NULL) { 1135 if (loops[nr]->vloopin->priv == NULL) {
983 kfree(loops[nr]->vloopin); 1136 kfree(loops[nr]->vloopin);
984 return -ENOMEM; 1137 return -ENOMEM;
985 } 1138 }
986 /* repeat for the output device */ 1139 /* repeat for the output device */
987 loops[nr]->vloopout= video_device_alloc(); 1140 loops[nr]->vloopout = video_device_alloc();
1141
988 if (loops[nr]->vloopout == NULL) { 1142 if (loops[nr]->vloopout == NULL) {
989 kfree(loops[nr]->vloopin->priv); 1143 kfree(loops[nr]->vloopin->priv);
990 kfree(loops[nr]->vloopin); 1144 kfree(loops[nr]->vloopin);
991 return -ENOMEM; 1145 return -ENOMEM;
992 } 1146 }
993 *loops[nr]->vloopout = vloopback_template; 1147 *loops[nr]->vloopout = vloopback_template;
994 loops[nr]->vloopout->priv= kmalloc(sizeof(struct vloopback_private), 1148 loops[nr]->vloopout->priv = kmalloc(sizeof(struct vloopback_private),
995 GFP_KERNEL); 1149 GFP_KERNEL);
1150
996 if (loops[nr]->vloopout->priv == NULL) { 1151 if (loops[nr]->vloopout->priv == NULL) {
997 kfree(loops[nr]->vloopin->priv); 1152 kfree(loops[nr]->vloopin->priv);
998 kfree(loops[nr]->vloopin); 1153 kfree(loops[nr]->vloopin);
999 kfree(loops[nr]->vloopout); 1154 kfree(loops[nr]->vloopout);
1000 return -ENOMEM; 1155 return -ENOMEM;
1001 } 1156 }
1002 1157
1003 ((priv_ptr)loops[nr]->vloopin->priv)->pipenr=nr; 1158 ((priv_ptr)loops[nr]->vloopin->priv)->pipenr = nr;
1004 ((priv_ptr)loops[nr]->vloopout->priv)->pipenr=nr; 1159 ((priv_ptr)loops[nr]->vloopout->priv)->pipenr = nr;
1005 loops[nr]->invalid_ioctl = 0; /* tibit */ 1160 loops[nr]->invalid_ioctl = 0; /* tibit */
1006 loops[nr]->buffer=NULL; 1161 loops[nr]->buffer = NULL;
1007 loops[nr]->width=0; 1162 loops[nr]->width = 0;
1008 loops[nr]->height=0; 1163 loops[nr]->height = 0;
1009 loops[nr]->palette=0; 1164 loops[nr]->palette = 0;
1010 loops[nr]->frameswrite=0; 1165 loops[nr]->frameswrite = 0;
1011 loops[nr]->framesread=0; 1166 loops[nr]->framesread = 0;
1012 loops[nr]->framesdumped=0; 1167 loops[nr]->framesdumped = 0;
1013 loops[nr]->wopen=0; 1168 loops[nr]->wopen = 0;
1014 loops[nr]->ropen=0; 1169 loops[nr]->ropen = 0;
1015 loops[nr]->frame=0; 1170 loops[nr]->frame = 0;
1016 1171
1017 ((priv_ptr)loops[nr]->vloopin->priv)->in=1; 1172 ((priv_ptr)loops[nr]->vloopin->priv)->in = 1;
1018 ((priv_ptr)loops[nr]->vloopout->priv)->in=0; 1173 ((priv_ptr)loops[nr]->vloopout->priv)->in = 0;
1019 loops[nr]->vloopin->type=0; 1174 sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr);
1020 sprintf(loops[nr]->vloopin->name, "Video loopback %d input", nr); 1175 sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr);
1021 loops[nr]->vloopout->type=VID_TYPE_CAPTURE; 1176
1022 sprintf(loops[nr]->vloopout->name, "Video loopback %d output", nr); 1177 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
1178 loops[nr]->vloopin->type = 0;
1179 loops[nr]->vloopout->type = VID_TYPE_CAPTURE;
1180 #endif
1181 loops[nr]->vloopout->minor = minor_out;
1182 loops[nr]->vloopin->minor = minor_in;
1183
1023 init_waitqueue_head(&loops[nr]->wait); 1184 init_waitqueue_head(&loops[nr]->wait);
1024 init_MUTEX(&loops[nr]->lock); 1185 init_MUTEX(&loops[nr]->lock);
1025 1186
1026 ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER,minor_in); 1187 ret = video_register_device(loops[nr]->vloopin, VFL_TYPE_GRABBER, minor_in);
1027 1188
1028 if ((ret == -1 ) || ( ret == -23 )) { 1189 if ((ret == -1 ) || ( ret == -23 )) {
1029 info("error registering device %s",loops[nr]->vloopin->name); 1190 info("error registering device %s", loops[nr]->vloopin->name);
1030 kfree(loops[nr]->vloopin->priv); 1191 kfree(loops[nr]->vloopin->priv);
1031 kfree(loops[nr]->vloopin); 1192 kfree(loops[nr]->vloopin);
1032 kfree(loops[nr]->vloopout->priv); 1193 kfree(loops[nr]->vloopout->priv);
1033 kfree(loops[nr]->vloopout); 1194 kfree(loops[nr]->vloopout);
1034 kfree(loops[nr]); 1195 kfree(loops[nr]);
1035 loops[nr]=NULL; 1196 loops[nr] = NULL;
1036 return ret; 1197 return ret;
1037 } 1198 }
1038 1199
1039 ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER,minor_out); 1200 ret = video_register_device(loops[nr]->vloopout, VFL_TYPE_GRABBER, minor_out);
1040 1201
1041 if ((ret ==-1) || (ret == -23)) { 1202 if ((ret ==-1) || (ret == -23)) {
1042 info("error registering device %s", loops[nr]->vloopout->name); 1203 info("error registering device %s", loops[nr]->vloopout->name);
1043 kfree(loops[nr]->vloopin->priv); 1204 kfree(loops[nr]->vloopin->priv);
1044 video_unregister_device(loops[nr]->vloopin); 1205 video_unregister_device(loops[nr]->vloopin);
1045 kfree(loops[nr]->vloopout->priv); 1206 kfree(loops[nr]->vloopout->priv);
1046 kfree(loops[nr]->vloopout); 1207 kfree(loops[nr]->vloopout);
1047 kfree(loops[nr]); 1208 kfree(loops[nr]);
1048 loops[nr]=NULL; 1209 loops[nr] = NULL;
1049 return ret; 1210 return ret;
1050 } 1211 }
1051 1212
1052 loops[nr]->ioctldata=kmalloc(1024, GFP_KERNEL); 1213 loops[nr]->ioctldata = kmalloc(1024, GFP_KERNEL);
1053 loops[nr]->ioctlretdata=kmalloc(1024, GFP_KERNEL); 1214 loops[nr]->ioctlretdata = kmalloc(1024, GFP_KERNEL);
1054 return 0; 1215 return 0;
1055 } 1216 }
1056 1217
1057 1218
1058 /**************************************************************************** 1219 /****************************************************************************
1084 #else 1245 #else
1085 MODULE_PARM(dev_offset_param, "i"); 1246 MODULE_PARM(dev_offset_param, "i");
1086 #endif 1247 #endif
1087 1248
1088 MODULE_PARM_DESC(dev_offset, "Prefered offset for video device numbers"); 1249 MODULE_PARM_DESC(dev_offset, "Prefered offset for video device numbers");
1250
1251
1252 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
1253 module_param(debug, int, 000);
1254 #else
1255 MODULE_PARM(debug_param, "i");
1256 #endif
1257
1258 MODULE_PARM_DESC(debug, "Enable module debug level 0-3 (by default 0)");
1259
1089 MODULE_LICENSE("GPL"); 1260 MODULE_LICENSE("GPL");
1090 MODULE_VERSION( VLOOPBACK_VERSION ); 1261 MODULE_VERSION( VLOOPBACK_VERSION );
1091 1262
1092 static int __init vloopback_init(void) 1263 static int __init vloopback_init(void)
1093 { 1264 {
1094 int i,ret; 1265 int i,ret;
1095 1266
1096 info("Video4linux loopback driver v"VLOOPBACK_VERSION); 1267 info("video4linux loopback driver v"VLOOPBACK_VERSION);
1097 1268
1098 if (pipes==-1) pipes=1; 1269 if (pipes == -1)
1270 pipes = 1;
1271
1099 if (pipes > MAX_PIPES) { 1272 if (pipes > MAX_PIPES) {
1100 pipes=MAX_PIPES; 1273 pipes = MAX_PIPES;
1101 info("Nr of pipes is limited to: %d", MAX_PIPES); 1274 info("Nr of pipes is limited to: %d", MAX_PIPES);
1102 } 1275 }
1103 1276
1104 for (i=0; i<pipes; i++) { 1277 for (i = 0; i < pipes; i++) {
1105 1278
1106 ret = create_pipe(i); 1279 ret = create_pipe(i);
1107 1280
1108 if (ret == 0) { 1281 if (ret == 0) {
1109 info("Loopback %d registered, input: video%d," 1282 info("Loopback %d registered, input: video%d,"
1110 "output: video%d", 1283 " output: video%d",
1111 i, loops[i]->vloopin->minor, 1284 i, loops[i]->vloopin->minor,
1112 loops[i]->vloopout->minor); 1285 loops[i]->vloopout->minor);
1113 nr_o_pipes=i+1; 1286 nr_o_pipes = i + 1;
1114 }else{ 1287 } else {
1115 return ret; 1288 return ret;
1116 } 1289 }
1117 } 1290 }
1118 return 0; 1291 return 0;
1119 } 1292 }
1121 static void __exit cleanup_vloopback_module(void) 1294 static void __exit cleanup_vloopback_module(void)
1122 { 1295 {
1123 int i; 1296 int i;
1124 1297
1125 info("Unregistering video4linux loopback devices"); 1298 info("Unregistering video4linux loopback devices");
1126 for (i=0; i<nr_o_pipes; i++) if (loops[i]) { 1299
1127 kfree(loops[i]->vloopin->priv); 1300 for (i = 0; i < nr_o_pipes; i++) {
1128 video_unregister_device(loops[i]->vloopin); 1301 if (loops[i]) {
1129 kfree(loops[i]->vloopout->priv); 1302 kfree(loops[i]->vloopin->priv);
1130 video_unregister_device(loops[i]->vloopout); 1303 video_unregister_device(loops[i]->vloopin);
1131 if (loops[i]->buffer) rvfree(loops[i]->buffer, loops[i]->buflength*N_BUFFS); 1304 kfree(loops[i]->vloopout->priv);
1132 kfree(loops[i]->ioctldata); 1305 video_unregister_device(loops[i]->vloopout);
1133 kfree(loops[i]->ioctlretdata); 1306
1134 kfree(loops[i]); 1307 if (loops[i]->buffer)
1135 } 1308 rvfree(loops[i]->buffer, loops[i]->buflength * N_BUFFS);
1309
1310 kfree(loops[i]->ioctldata);
1311 kfree(loops[i]->ioctlretdata);
1312 kfree(loops[i]);
1313 }
1314 }
1136 } 1315 }
1137 1316
1138 module_init(vloopback_init); 1317 module_init(vloopback_init);
1139 module_exit(cleanup_vloopback_module); 1318 module_exit(cleanup_vloopback_module);