diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2013-01-30 12:10:14 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-05 15:20:06 -0500 |
commit | 1888e4a9742087df22ba64ea2e0e1064edeb8785 (patch) | |
tree | 6bca46be80986eee37d5fec34ec28afff69da755 /drivers/media | |
parent | 11d379395291609f95cf1e102f9f23892b83a493 (diff) |
[media] bw-qcam: convert to videobuf2
I know, nobody really cares about this black-and-white webcam anymore, but
it was fun to do.
Tested with an actual webcam.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/parport/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/parport/bw-qcam.c | 157 |
2 files changed, 112 insertions, 46 deletions
diff --git a/drivers/media/parport/Kconfig b/drivers/media/parport/Kconfig index ece13dcff07d..948c981d9f05 100644 --- a/drivers/media/parport/Kconfig +++ b/drivers/media/parport/Kconfig | |||
@@ -9,6 +9,7 @@ if MEDIA_PARPORT_SUPPORT | |||
9 | config VIDEO_BWQCAM | 9 | config VIDEO_BWQCAM |
10 | tristate "Quickcam BW Video For Linux" | 10 | tristate "Quickcam BW Video For Linux" |
11 | depends on PARPORT && VIDEO_V4L2 | 11 | depends on PARPORT && VIDEO_V4L2 |
12 | select VIDEOBUF2_VMALLOC | ||
12 | help | 13 | help |
13 | Say Y have if you the black and white version of the QuickCam | 14 | Say Y have if you the black and white version of the QuickCam |
14 | camera. See the next option for the color version. | 15 | camera. See the next option for the color version. |
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c index 497b342b0f72..d3fe34f14c0d 100644 --- a/drivers/media/parport/bw-qcam.c +++ b/drivers/media/parport/bw-qcam.c | |||
@@ -80,6 +80,7 @@ OTHER DEALINGS IN THE SOFTWARE. | |||
80 | #include <media/v4l2-fh.h> | 80 | #include <media/v4l2-fh.h> |
81 | #include <media/v4l2-ctrls.h> | 81 | #include <media/v4l2-ctrls.h> |
82 | #include <media/v4l2-event.h> | 82 | #include <media/v4l2-event.h> |
83 | #include <media/videobuf2-vmalloc.h> | ||
83 | 84 | ||
84 | /* One from column A... */ | 85 | /* One from column A... */ |
85 | #define QC_NOTSET 0 | 86 | #define QC_NOTSET 0 |
@@ -107,9 +108,11 @@ struct qcam { | |||
107 | struct v4l2_device v4l2_dev; | 108 | struct v4l2_device v4l2_dev; |
108 | struct video_device vdev; | 109 | struct video_device vdev; |
109 | struct v4l2_ctrl_handler hdl; | 110 | struct v4l2_ctrl_handler hdl; |
111 | struct vb2_queue vb_vidq; | ||
110 | struct pardevice *pdev; | 112 | struct pardevice *pdev; |
111 | struct parport *pport; | 113 | struct parport *pport; |
112 | struct mutex lock; | 114 | struct mutex lock; |
115 | struct mutex queue_lock; | ||
113 | int width, height; | 116 | int width, height; |
114 | int bpp; | 117 | int bpp; |
115 | int mode; | 118 | int mode; |
@@ -558,7 +561,7 @@ static inline int qc_readbytes(struct qcam *q, char buffer[]) | |||
558 | * n=2^(bit depth)-1. Ask me for more details if you don't understand | 561 | * n=2^(bit depth)-1. Ask me for more details if you don't understand |
559 | * this. */ | 562 | * this. */ |
560 | 563 | ||
561 | static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) | 564 | static long qc_capture(struct qcam *q, u8 *buf, unsigned long len) |
562 | { | 565 | { |
563 | int i, j, k, yield; | 566 | int i, j, k, yield; |
564 | int bytes; | 567 | int bytes; |
@@ -609,7 +612,7 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) | |||
609 | if (o < len) { | 612 | if (o < len) { |
610 | u8 ch = invert - buffer[k]; | 613 | u8 ch = invert - buffer[k]; |
611 | got++; | 614 | got++; |
612 | put_user(ch << shift, buf + o); | 615 | buf[o] = ch << shift; |
613 | } | 616 | } |
614 | } | 617 | } |
615 | pixels_read += bytes; | 618 | pixels_read += bytes; |
@@ -639,6 +642,67 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len) | |||
639 | return len; | 642 | return len; |
640 | } | 643 | } |
641 | 644 | ||
645 | /* ------------------------------------------------------------------ | ||
646 | Videobuf operations | ||
647 | ------------------------------------------------------------------*/ | ||
648 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, | ||
649 | unsigned int *nbuffers, unsigned int *nplanes, | ||
650 | unsigned int sizes[], void *alloc_ctxs[]) | ||
651 | { | ||
652 | struct qcam *dev = vb2_get_drv_priv(vq); | ||
653 | |||
654 | if (0 == *nbuffers) | ||
655 | *nbuffers = 3; | ||
656 | *nplanes = 1; | ||
657 | mutex_lock(&dev->lock); | ||
658 | if (fmt) | ||
659 | sizes[0] = fmt->fmt.pix.width * fmt->fmt.pix.height; | ||
660 | else | ||
661 | sizes[0] = (dev->width / dev->transfer_scale) * | ||
662 | (dev->height / dev->transfer_scale); | ||
663 | mutex_unlock(&dev->lock); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static void buffer_queue(struct vb2_buffer *vb) | ||
668 | { | ||
669 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
670 | } | ||
671 | |||
672 | static int buffer_finish(struct vb2_buffer *vb) | ||
673 | { | ||
674 | struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue); | ||
675 | void *vbuf = vb2_plane_vaddr(vb, 0); | ||
676 | int size = vb->vb2_queue->plane_sizes[0]; | ||
677 | int len; | ||
678 | |||
679 | mutex_lock(&qcam->lock); | ||
680 | parport_claim_or_block(qcam->pdev); | ||
681 | |||
682 | qc_reset(qcam); | ||
683 | |||
684 | /* Update the camera parameters if we need to */ | ||
685 | if (qcam->status & QC_PARAM_CHANGE) | ||
686 | qc_set(qcam); | ||
687 | |||
688 | len = qc_capture(qcam, vbuf, size); | ||
689 | |||
690 | parport_release(qcam->pdev); | ||
691 | mutex_unlock(&qcam->lock); | ||
692 | if (len != size) | ||
693 | vb->state = VB2_BUF_STATE_ERROR; | ||
694 | vb2_set_plane_payload(vb, 0, len); | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static struct vb2_ops qcam_video_qops = { | ||
699 | .queue_setup = queue_setup, | ||
700 | .buf_queue = buffer_queue, | ||
701 | .buf_finish = buffer_finish, | ||
702 | .wait_prepare = vb2_ops_wait_prepare, | ||
703 | .wait_finish = vb2_ops_wait_finish, | ||
704 | }; | ||
705 | |||
642 | /* | 706 | /* |
643 | * Video4linux interfacing | 707 | * Video4linux interfacing |
644 | */ | 708 | */ |
@@ -651,7 +715,8 @@ static int qcam_querycap(struct file *file, void *priv, | |||
651 | strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); | 715 | strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver)); |
652 | strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card)); | 716 | strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card)); |
653 | strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info)); | 717 | strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info)); |
654 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | 718 | vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
719 | V4L2_CAP_STREAMING; | ||
655 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; | 720 | vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; |
656 | return 0; | 721 | return 0; |
657 | } | 722 | } |
@@ -731,6 +796,8 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f | |||
731 | 796 | ||
732 | if (ret) | 797 | if (ret) |
733 | return ret; | 798 | return ret; |
799 | if (vb2_is_busy(&qcam->vb_vidq)) | ||
800 | return -EBUSY; | ||
734 | qcam->width = 320; | 801 | qcam->width = 320; |
735 | qcam->height = 240; | 802 | qcam->height = 240; |
736 | if (pix->height == 60) | 803 | if (pix->height == 60) |
@@ -744,12 +811,10 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f | |||
744 | else | 811 | else |
745 | qcam->bpp = 4; | 812 | qcam->bpp = 4; |
746 | 813 | ||
747 | mutex_lock(&qcam->lock); | ||
748 | qc_setscanmode(qcam); | 814 | qc_setscanmode(qcam); |
749 | /* We must update the camera before we grab. We could | 815 | /* We must update the camera before we grab. We could |
750 | just have changed the grab size */ | 816 | just have changed the grab size */ |
751 | qcam->status |= QC_PARAM_CHANGE; | 817 | qcam->status |= QC_PARAM_CHANGE; |
752 | mutex_unlock(&qcam->lock); | ||
753 | return 0; | 818 | return 0; |
754 | } | 819 | } |
755 | 820 | ||
@@ -794,41 +859,12 @@ static int qcam_enum_framesizes(struct file *file, void *fh, | |||
794 | return 0; | 859 | return 0; |
795 | } | 860 | } |
796 | 861 | ||
797 | static ssize_t qcam_read(struct file *file, char __user *buf, | ||
798 | size_t count, loff_t *ppos) | ||
799 | { | ||
800 | struct qcam *qcam = video_drvdata(file); | ||
801 | int len; | ||
802 | parport_claim_or_block(qcam->pdev); | ||
803 | |||
804 | mutex_lock(&qcam->lock); | ||
805 | |||
806 | qc_reset(qcam); | ||
807 | |||
808 | /* Update the camera parameters if we need to */ | ||
809 | if (qcam->status & QC_PARAM_CHANGE) | ||
810 | qc_set(qcam); | ||
811 | |||
812 | len = qc_capture(qcam, buf, count); | ||
813 | |||
814 | mutex_unlock(&qcam->lock); | ||
815 | |||
816 | parport_release(qcam->pdev); | ||
817 | return len; | ||
818 | } | ||
819 | |||
820 | static unsigned int qcam_poll(struct file *filp, poll_table *wait) | ||
821 | { | ||
822 | return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM; | ||
823 | } | ||
824 | |||
825 | static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) | 862 | static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) |
826 | { | 863 | { |
827 | struct qcam *qcam = | 864 | struct qcam *qcam = |
828 | container_of(ctrl->handler, struct qcam, hdl); | 865 | container_of(ctrl->handler, struct qcam, hdl); |
829 | int ret = 0; | 866 | int ret = 0; |
830 | 867 | ||
831 | mutex_lock(&qcam->lock); | ||
832 | switch (ctrl->id) { | 868 | switch (ctrl->id) { |
833 | case V4L2_CID_BRIGHTNESS: | 869 | case V4L2_CID_BRIGHTNESS: |
834 | qcam->brightness = ctrl->val; | 870 | qcam->brightness = ctrl->val; |
@@ -847,17 +883,17 @@ static int qcam_s_ctrl(struct v4l2_ctrl *ctrl) | |||
847 | qc_setscanmode(qcam); | 883 | qc_setscanmode(qcam); |
848 | qcam->status |= QC_PARAM_CHANGE; | 884 | qcam->status |= QC_PARAM_CHANGE; |
849 | } | 885 | } |
850 | mutex_unlock(&qcam->lock); | ||
851 | return ret; | 886 | return ret; |
852 | } | 887 | } |
853 | 888 | ||
854 | static const struct v4l2_file_operations qcam_fops = { | 889 | static const struct v4l2_file_operations qcam_fops = { |
855 | .owner = THIS_MODULE, | 890 | .owner = THIS_MODULE, |
856 | .open = v4l2_fh_open, | 891 | .open = v4l2_fh_open, |
857 | .release = v4l2_fh_release, | 892 | .release = vb2_fop_release, |
858 | .poll = qcam_poll, | 893 | .poll = vb2_fop_poll, |
859 | .unlocked_ioctl = video_ioctl2, | 894 | .unlocked_ioctl = video_ioctl2, |
860 | .read = qcam_read, | 895 | .read = vb2_fop_read, |
896 | .mmap = vb2_fop_mmap, | ||
861 | }; | 897 | }; |
862 | 898 | ||
863 | static const struct v4l2_ioctl_ops qcam_ioctl_ops = { | 899 | static const struct v4l2_ioctl_ops qcam_ioctl_ops = { |
@@ -870,6 +906,14 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = { | |||
870 | .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, | 906 | .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap, |
871 | .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, | 907 | .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap, |
872 | .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, | 908 | .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap, |
909 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
910 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
911 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
912 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
913 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
914 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
915 | .vidioc_streamon = vb2_ioctl_streamon, | ||
916 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
873 | .vidioc_log_status = v4l2_ctrl_log_status, | 917 | .vidioc_log_status = v4l2_ctrl_log_status, |
874 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | 918 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
875 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | 919 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
@@ -886,6 +930,8 @@ static struct qcam *qcam_init(struct parport *port) | |||
886 | { | 930 | { |
887 | struct qcam *qcam; | 931 | struct qcam *qcam; |
888 | struct v4l2_device *v4l2_dev; | 932 | struct v4l2_device *v4l2_dev; |
933 | struct vb2_queue *q; | ||
934 | int err; | ||
889 | 935 | ||
890 | qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); | 936 | qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL); |
891 | if (qcam == NULL) | 937 | if (qcam == NULL) |
@@ -909,31 +955,45 @@ static struct qcam *qcam_init(struct parport *port) | |||
909 | V4L2_CID_GAMMA, 0, 255, 1, 105); | 955 | V4L2_CID_GAMMA, 0, 255, 1, 105); |
910 | if (qcam->hdl.error) { | 956 | if (qcam->hdl.error) { |
911 | v4l2_err(v4l2_dev, "couldn't register controls\n"); | 957 | v4l2_err(v4l2_dev, "couldn't register controls\n"); |
912 | v4l2_ctrl_handler_free(&qcam->hdl); | 958 | goto exit; |
913 | kfree(qcam); | 959 | } |
914 | return NULL; | 960 | |
961 | mutex_init(&qcam->lock); | ||
962 | mutex_init(&qcam->queue_lock); | ||
963 | |||
964 | /* initialize queue */ | ||
965 | q = &qcam->vb_vidq; | ||
966 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
967 | q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | ||
968 | q->drv_priv = qcam; | ||
969 | q->ops = &qcam_video_qops; | ||
970 | q->mem_ops = &vb2_vmalloc_memops; | ||
971 | err = vb2_queue_init(q); | ||
972 | if (err < 0) { | ||
973 | v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name); | ||
974 | goto exit; | ||
915 | } | 975 | } |
976 | qcam->vdev.queue = q; | ||
977 | qcam->vdev.queue->lock = &qcam->queue_lock; | ||
978 | |||
916 | qcam->pport = port; | 979 | qcam->pport = port; |
917 | qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL, | 980 | qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL, |
918 | NULL, 0, NULL); | 981 | NULL, 0, NULL); |
919 | if (qcam->pdev == NULL) { | 982 | if (qcam->pdev == NULL) { |
920 | v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); | 983 | v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name); |
921 | v4l2_ctrl_handler_free(&qcam->hdl); | 984 | goto exit; |
922 | kfree(qcam); | ||
923 | return NULL; | ||
924 | } | 985 | } |
925 | 986 | ||
926 | strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); | 987 | strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name)); |
927 | qcam->vdev.v4l2_dev = v4l2_dev; | 988 | qcam->vdev.v4l2_dev = v4l2_dev; |
928 | qcam->vdev.ctrl_handler = &qcam->hdl; | 989 | qcam->vdev.ctrl_handler = &qcam->hdl; |
929 | qcam->vdev.fops = &qcam_fops; | 990 | qcam->vdev.fops = &qcam_fops; |
991 | qcam->vdev.lock = &qcam->lock; | ||
930 | qcam->vdev.ioctl_ops = &qcam_ioctl_ops; | 992 | qcam->vdev.ioctl_ops = &qcam_ioctl_ops; |
931 | set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags); | 993 | set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags); |
932 | qcam->vdev.release = video_device_release_empty; | 994 | qcam->vdev.release = video_device_release_empty; |
933 | video_set_drvdata(&qcam->vdev, qcam); | 995 | video_set_drvdata(&qcam->vdev, qcam); |
934 | 996 | ||
935 | mutex_init(&qcam->lock); | ||
936 | |||
937 | qcam->port_mode = (QC_ANY | QC_NOTSET); | 997 | qcam->port_mode = (QC_ANY | QC_NOTSET); |
938 | qcam->width = 320; | 998 | qcam->width = 320; |
939 | qcam->height = 240; | 999 | qcam->height = 240; |
@@ -947,6 +1007,11 @@ static struct qcam *qcam_init(struct parport *port) | |||
947 | qcam->mode = -1; | 1007 | qcam->mode = -1; |
948 | qcam->status = QC_PARAM_CHANGE; | 1008 | qcam->status = QC_PARAM_CHANGE; |
949 | return qcam; | 1009 | return qcam; |
1010 | |||
1011 | exit: | ||
1012 | v4l2_ctrl_handler_free(&qcam->hdl); | ||
1013 | kfree(qcam); | ||
1014 | return NULL; | ||
950 | } | 1015 | } |
951 | 1016 | ||
952 | static int qc_calibrate(struct qcam *q) | 1017 | static int qc_calibrate(struct qcam *q) |