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