diff options
Diffstat (limited to 'drivers/media/video/pwc/pwc-v4l.c')
-rw-r--r-- | drivers/media/video/pwc/pwc-v4l.c | 322 |
1 files changed, 11 insertions, 311 deletions
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 62d89b3113a4..7061a03f5cf1 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -216,7 +216,7 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma | |||
216 | f->fmt.pix.width = pdev->view.x; | 216 | f->fmt.pix.width = pdev->view.x; |
217 | f->fmt.pix.height = pdev->view.y; | 217 | f->fmt.pix.height = pdev->view.y; |
218 | f->fmt.pix.field = V4L2_FIELD_NONE; | 218 | f->fmt.pix.field = V4L2_FIELD_NONE; |
219 | if (pdev->vpalette == VIDEO_PALETTE_YUV420P) { | 219 | if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) { |
220 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; | 220 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; |
221 | f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; | 221 | f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2; |
222 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | 222 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; |
@@ -304,10 +304,10 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) | |||
304 | fps = pdev->vframes; | 304 | fps = pdev->vframes; |
305 | } | 305 | } |
306 | 306 | ||
307 | if (pixelformat == V4L2_PIX_FMT_YUV420) | 307 | if (pixelformat != V4L2_PIX_FMT_YUV420 && |
308 | pdev->vpalette = VIDEO_PALETTE_YUV420P; | 308 | pixelformat != V4L2_PIX_FMT_PWC1 && |
309 | else | 309 | pixelformat != V4L2_PIX_FMT_PWC2) |
310 | pdev->vpalette = VIDEO_PALETTE_RAW; | 310 | return -EINVAL; |
311 | 311 | ||
312 | PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d " | 312 | PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d " |
313 | "compression=%d snapshot=%d format=%c%c%c%c\n", | 313 | "compression=%d snapshot=%d format=%c%c%c%c\n", |
@@ -330,6 +330,8 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) | |||
330 | if (ret) | 330 | if (ret) |
331 | return ret; | 331 | return ret; |
332 | 332 | ||
333 | pdev->pixfmt = pixelformat; | ||
334 | |||
333 | pwc_vidioc_fill_fmt(pdev, f); | 335 | pwc_vidioc_fill_fmt(pdev, f); |
334 | 336 | ||
335 | return 0; | 337 | return 0; |
@@ -357,152 +359,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
357 | 359 | ||
358 | 360 | ||
359 | switch (cmd) { | 361 | switch (cmd) { |
360 | /* Query cabapilities */ | 362 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
361 | case VIDIOCGCAP: | ||
362 | { | ||
363 | struct video_capability *caps = arg; | ||
364 | |||
365 | strcpy(caps->name, vdev->name); | ||
366 | caps->type = VID_TYPE_CAPTURE; | ||
367 | caps->channels = 1; | ||
368 | caps->audios = 1; | ||
369 | caps->minwidth = pdev->view_min.x; | ||
370 | caps->minheight = pdev->view_min.y; | ||
371 | caps->maxwidth = pdev->view_max.x; | ||
372 | caps->maxheight = pdev->view_max.y; | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | /* Channel functions (simulate 1 channel) */ | ||
377 | case VIDIOCGCHAN: | ||
378 | { | ||
379 | struct video_channel *v = arg; | ||
380 | |||
381 | if (v->channel != 0) | ||
382 | return -EINVAL; | ||
383 | v->flags = 0; | ||
384 | v->tuners = 0; | ||
385 | v->type = VIDEO_TYPE_CAMERA; | ||
386 | strcpy(v->name, "Webcam"); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | case VIDIOCSCHAN: | ||
391 | { | ||
392 | /* The spec says the argument is an integer, but | ||
393 | the bttv driver uses a video_channel arg, which | ||
394 | makes sense becasue it also has the norm flag. | ||
395 | */ | ||
396 | struct video_channel *v = arg; | ||
397 | if (v->channel != 0) | ||
398 | return -EINVAL; | ||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | |||
403 | /* Picture functions; contrast etc. */ | ||
404 | case VIDIOCGPICT: | ||
405 | { | ||
406 | struct video_picture *p = arg; | ||
407 | int val; | ||
408 | |||
409 | val = pwc_get_brightness(pdev); | ||
410 | if (val >= 0) | ||
411 | p->brightness = (val<<9); | ||
412 | else | ||
413 | p->brightness = 0xffff; | ||
414 | val = pwc_get_contrast(pdev); | ||
415 | if (val >= 0) | ||
416 | p->contrast = (val<<10); | ||
417 | else | ||
418 | p->contrast = 0xffff; | ||
419 | /* Gamma, Whiteness, what's the difference? :) */ | ||
420 | val = pwc_get_gamma(pdev); | ||
421 | if (val >= 0) | ||
422 | p->whiteness = (val<<11); | ||
423 | else | ||
424 | p->whiteness = 0xffff; | ||
425 | if (pwc_get_saturation(pdev, &val)<0) | ||
426 | p->colour = 0xffff; | ||
427 | else | ||
428 | p->colour = 32768 + val * 327; | ||
429 | p->depth = 24; | ||
430 | p->palette = pdev->vpalette; | ||
431 | p->hue = 0xFFFF; /* N/A */ | ||
432 | break; | ||
433 | } | ||
434 | |||
435 | case VIDIOCSPICT: | ||
436 | { | ||
437 | struct video_picture *p = arg; | ||
438 | /* | ||
439 | * FIXME: Suppose we are mid read | ||
440 | ANSWER: No problem: the firmware of the camera | ||
441 | can handle brightness/contrast/etc | ||
442 | changes at _any_ time, and the palette | ||
443 | is used exactly once in the uncompress | ||
444 | routine. | ||
445 | */ | ||
446 | pwc_set_brightness(pdev, p->brightness); | ||
447 | pwc_set_contrast(pdev, p->contrast); | ||
448 | pwc_set_gamma(pdev, p->whiteness); | ||
449 | pwc_set_saturation(pdev, (p->colour-32768)/327); | ||
450 | if (p->palette && p->palette != pdev->vpalette) { | ||
451 | switch (p->palette) { | ||
452 | case VIDEO_PALETTE_YUV420P: | ||
453 | case VIDEO_PALETTE_RAW: | ||
454 | pdev->vpalette = p->palette; | ||
455 | return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
456 | break; | ||
457 | default: | ||
458 | return -EINVAL; | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | break; | ||
463 | } | ||
464 | |||
465 | /* Window/size parameters */ | ||
466 | case VIDIOCGWIN: | ||
467 | { | ||
468 | struct video_window *vw = arg; | ||
469 | |||
470 | vw->x = 0; | ||
471 | vw->y = 0; | ||
472 | vw->width = pdev->view.x; | ||
473 | vw->height = pdev->view.y; | ||
474 | vw->chromakey = 0; | ||
475 | vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | | ||
476 | (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); | ||
477 | break; | ||
478 | } | ||
479 | |||
480 | case VIDIOCSWIN: | ||
481 | { | ||
482 | struct video_window *vw = arg; | ||
483 | int fps, snapshot, ret; | ||
484 | |||
485 | fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; | ||
486 | snapshot = vw->flags & PWC_FPS_SNAPSHOT; | ||
487 | if (fps == 0) | ||
488 | fps = pdev->vframes; | ||
489 | if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) | ||
490 | return 0; | ||
491 | ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); | ||
492 | if (ret) | ||
493 | return ret; | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | /* We don't have overlay support (yet) */ | ||
498 | case VIDIOCGFBUF: | ||
499 | { | ||
500 | struct video_buffer *vb = arg; | ||
501 | |||
502 | memset(vb,0,sizeof(*vb)); | ||
503 | break; | ||
504 | } | ||
505 | |||
506 | /* mmap() functions */ | 363 | /* mmap() functions */ |
507 | case VIDIOCGMBUF: | 364 | case VIDIOCGMBUF: |
508 | { | 365 | { |
@@ -517,164 +374,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
517 | vm->offsets[i] = i * pdev->len_per_image; | 374 | vm->offsets[i] = i * pdev->len_per_image; |
518 | break; | 375 | break; |
519 | } | 376 | } |
520 | 377 | #endif | |
521 | case VIDIOCMCAPTURE: | ||
522 | { | ||
523 | /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ | ||
524 | struct video_mmap *vm = arg; | ||
525 | |||
526 | PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); | ||
527 | if (vm->frame < 0 || vm->frame >= pwc_mbufs) | ||
528 | return -EINVAL; | ||
529 | |||
530 | /* xawtv is nasty. It probes the available palettes | ||
531 | by setting a very small image size and trying | ||
532 | various palettes... The driver doesn't support | ||
533 | such small images, so I'm working around it. | ||
534 | */ | ||
535 | if (vm->format) | ||
536 | { | ||
537 | switch (vm->format) | ||
538 | { | ||
539 | case VIDEO_PALETTE_YUV420P: | ||
540 | case VIDEO_PALETTE_RAW: | ||
541 | break; | ||
542 | default: | ||
543 | return -EINVAL; | ||
544 | break; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && | ||
549 | (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { | ||
550 | int ret; | ||
551 | |||
552 | PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); | ||
553 | ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); | ||
554 | if (ret) | ||
555 | return ret; | ||
556 | } /* ... size mismatch */ | ||
557 | |||
558 | /* FIXME: should we lock here? */ | ||
559 | if (pdev->image_used[vm->frame]) | ||
560 | return -EBUSY; /* buffer wasn't available. Bummer */ | ||
561 | pdev->image_used[vm->frame] = 1; | ||
562 | |||
563 | /* Okay, we're done here. In the SYNC call we wait until a | ||
564 | frame comes available, then expand image into the given | ||
565 | buffer. | ||
566 | In contrast to the CPiA cam the Philips cams deliver a | ||
567 | constant stream, almost like a grabber card. Also, | ||
568 | we have separate buffers for the rawdata and the image, | ||
569 | meaning we can nearly always expand into the requested buffer. | ||
570 | */ | ||
571 | PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n"); | ||
572 | break; | ||
573 | } | ||
574 | |||
575 | case VIDIOCSYNC: | ||
576 | { | ||
577 | /* The doc says: "Whenever a buffer is used it should | ||
578 | call VIDIOCSYNC to free this frame up and continue." | ||
579 | |||
580 | The only odd thing about this whole procedure is | ||
581 | that MCAPTURE flags the buffer as "in use", and | ||
582 | SYNC immediately unmarks it, while it isn't | ||
583 | after SYNC that you know that the buffer actually | ||
584 | got filled! So you better not start a CAPTURE in | ||
585 | the same frame immediately (use double buffering). | ||
586 | This is not a problem for this cam, since it has | ||
587 | extra intermediate buffers, but a hardware | ||
588 | grabber card will then overwrite the buffer | ||
589 | you're working on. | ||
590 | */ | ||
591 | int *mbuf = arg; | ||
592 | int ret; | ||
593 | |||
594 | PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf); | ||
595 | |||
596 | /* bounds check */ | ||
597 | if (*mbuf < 0 || *mbuf >= pwc_mbufs) | ||
598 | return -EINVAL; | ||
599 | /* check if this buffer was requested anyway */ | ||
600 | if (pdev->image_used[*mbuf] == 0) | ||
601 | return -EINVAL; | ||
602 | |||
603 | /* Add ourselves to the frame wait-queue. | ||
604 | |||
605 | FIXME: needs auditing for safety. | ||
606 | QUESTION: In what respect? I think that using the | ||
607 | frameq is safe now. | ||
608 | */ | ||
609 | add_wait_queue(&pdev->frameq, &wait); | ||
610 | while (pdev->full_frames == NULL) { | ||
611 | /* Check for unplugged/etc. here */ | ||
612 | if (pdev->error_status) { | ||
613 | remove_wait_queue(&pdev->frameq, &wait); | ||
614 | set_current_state(TASK_RUNNING); | ||
615 | return -pdev->error_status; | ||
616 | } | ||
617 | |||
618 | if (signal_pending(current)) { | ||
619 | remove_wait_queue(&pdev->frameq, &wait); | ||
620 | set_current_state(TASK_RUNNING); | ||
621 | return -ERESTARTSYS; | ||
622 | } | ||
623 | schedule(); | ||
624 | set_current_state(TASK_INTERRUPTIBLE); | ||
625 | } | ||
626 | remove_wait_queue(&pdev->frameq, &wait); | ||
627 | set_current_state(TASK_RUNNING); | ||
628 | |||
629 | /* The frame is ready. Expand in the image buffer | ||
630 | requested by the user. I don't care if you | ||
631 | mmap() 5 buffers and request data in this order: | ||
632 | buffer 4 2 3 0 1 2 3 0 4 3 1 . . . | ||
633 | Grabber hardware may not be so forgiving. | ||
634 | */ | ||
635 | PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n"); | ||
636 | pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ | ||
637 | /* Decompress, etc */ | ||
638 | ret = pwc_handle_frame(pdev); | ||
639 | pdev->image_used[*mbuf] = 0; | ||
640 | if (ret) | ||
641 | return -EFAULT; | ||
642 | break; | ||
643 | } | ||
644 | |||
645 | case VIDIOCGAUDIO: | ||
646 | { | ||
647 | struct video_audio *v = arg; | ||
648 | |||
649 | strcpy(v->name, "Microphone"); | ||
650 | v->audio = -1; /* unknown audio minor */ | ||
651 | v->flags = 0; | ||
652 | v->mode = VIDEO_SOUND_MONO; | ||
653 | v->volume = 0; | ||
654 | v->bass = 0; | ||
655 | v->treble = 0; | ||
656 | v->balance = 0x8000; | ||
657 | v->step = 1; | ||
658 | break; | ||
659 | } | ||
660 | |||
661 | case VIDIOCSAUDIO: | ||
662 | { | ||
663 | /* Dummy: nothing can be set */ | ||
664 | break; | ||
665 | } | ||
666 | |||
667 | case VIDIOCGUNIT: | ||
668 | { | ||
669 | struct video_unit *vu = arg; | ||
670 | |||
671 | vu->video = pdev->vdev->minor & 0x3F; | ||
672 | vu->audio = -1; /* not known yet */ | ||
673 | vu->vbi = -1; | ||
674 | vu->radio = -1; | ||
675 | vu->teletext = -1; | ||
676 | break; | ||
677 | } | ||
678 | 378 | ||
679 | /* V4L2 Layer */ | 379 | /* V4L2 Layer */ |
680 | case VIDIOC_QUERYCAP: | 380 | case VIDIOC_QUERYCAP: |
@@ -1081,7 +781,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
1081 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 781 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
1082 | buf->index = index; | 782 | buf->index = index; |
1083 | buf->m.offset = index * pdev->len_per_image; | 783 | buf->m.offset = index * pdev->len_per_image; |
1084 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | 784 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) |
1085 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); | 785 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); |
1086 | else | 786 | else |
1087 | buf->bytesused = pdev->view.size; | 787 | buf->bytesused = pdev->view.size; |
@@ -1158,7 +858,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
1158 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); | 858 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); |
1159 | 859 | ||
1160 | buf->index = pdev->fill_image; | 860 | buf->index = pdev->fill_image; |
1161 | if (pdev->vpalette == VIDEO_PALETTE_RAW) | 861 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) |
1162 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); | 862 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); |
1163 | else | 863 | else |
1164 | buf->bytesused = pdev->view.size; | 864 | buf->bytesused = pdev->view.size; |