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