[media] bw-qcam: convert to videobuf2
authorHans Verkuil <hans.verkuil@cisco.com>
Wed, 30 Jan 2013 17:10:14 +0000 (14:10 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 5 Feb 2013 20:20:06 +0000 (18:20 -0200)
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>
drivers/media/parport/Kconfig
drivers/media/parport/bw-qcam.c

index ece13dcff07dfa062b3dde11b7d69afa0da27da3..948c981d9f05ae00cd2ec347d601acd5469e54ca 100644 (file)
@@ -9,6 +9,7 @@ if MEDIA_PARPORT_SUPPORT
 config VIDEO_BWQCAM
        tristate "Quickcam BW Video For Linux"
        depends on PARPORT && VIDEO_V4L2
+       select VIDEOBUF2_VMALLOC
        help
          Say Y have if you the black and white version of the QuickCam
          camera. See the next option for the color version.
index 497b342b0f72d6d5332180e54f371f74185d5d24..d3fe34f14c0dfcbe41c2755daa6437813d446ad7 100644 (file)
@@ -80,6 +80,7 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
 
 /* One from column A... */
 #define QC_NOTSET 0
@@ -107,9 +108,11 @@ struct qcam {
        struct v4l2_device v4l2_dev;
        struct video_device vdev;
        struct v4l2_ctrl_handler hdl;
+       struct vb2_queue vb_vidq;
        struct pardevice *pdev;
        struct parport *pport;
        struct mutex lock;
+       struct mutex queue_lock;
        int width, height;
        int bpp;
        int mode;
@@ -558,7 +561,7 @@ static inline int qc_readbytes(struct qcam *q, char buffer[])
  * n=2^(bit depth)-1.  Ask me for more details if you don't understand
  * this. */
 
-static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *q, u8 *buf, unsigned long len)
 {
        int i, j, k, yield;
        int bytes;
@@ -609,7 +612,7 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
                                if (o < len) {
                                        u8 ch = invert - buffer[k];
                                        got++;
-                                       put_user(ch << shift, buf + o);
+                                       buf[o] = ch << shift;
                                }
                        }
                        pixels_read += bytes;
@@ -639,6 +642,67 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
        return len;
 }
 
+/* ------------------------------------------------------------------
+       Videobuf operations
+   ------------------------------------------------------------------*/
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct qcam *dev = vb2_get_drv_priv(vq);
+
+       if (0 == *nbuffers)
+               *nbuffers = 3;
+       *nplanes = 1;
+       mutex_lock(&dev->lock);
+       if (fmt)
+               sizes[0] = fmt->fmt.pix.width * fmt->fmt.pix.height;
+       else
+               sizes[0] = (dev->width / dev->transfer_scale) *
+                  (dev->height / dev->transfer_scale);
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
+static int buffer_finish(struct vb2_buffer *vb)
+{
+       struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue);
+       void *vbuf = vb2_plane_vaddr(vb, 0);
+       int size = vb->vb2_queue->plane_sizes[0];
+       int len;
+
+       mutex_lock(&qcam->lock);
+       parport_claim_or_block(qcam->pdev);
+
+       qc_reset(qcam);
+
+       /* Update the camera parameters if we need to */
+       if (qcam->status & QC_PARAM_CHANGE)
+               qc_set(qcam);
+
+       len = qc_capture(qcam, vbuf, size);
+
+       parport_release(qcam->pdev);
+       mutex_unlock(&qcam->lock);
+       if (len != size)
+               vb->state = VB2_BUF_STATE_ERROR;
+       vb2_set_plane_payload(vb, 0, len);
+       return 0;
+}
+
+static struct vb2_ops qcam_video_qops = {
+       .queue_setup            = queue_setup,
+       .buf_queue              = buffer_queue,
+       .buf_finish             = buffer_finish,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
 /*
  *     Video4linux interfacing
  */
@@ -651,7 +715,8 @@ static int qcam_querycap(struct file *file, void  *priv,
        strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
        strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
        strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info));
-       vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+       vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+                               V4L2_CAP_STREAMING;
        vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
@@ -731,6 +796,8 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
 
        if (ret)
                return ret;
+       if (vb2_is_busy(&qcam->vb_vidq))
+               return -EBUSY;
        qcam->width = 320;
        qcam->height = 240;
        if (pix->height == 60)
@@ -744,12 +811,10 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
        else
                qcam->bpp = 4;
 
-       mutex_lock(&qcam->lock);
        qc_setscanmode(qcam);
        /* We must update the camera before we grab. We could
           just have changed the grab size */
        qcam->status |= QC_PARAM_CHANGE;
-       mutex_unlock(&qcam->lock);
        return 0;
 }
 
@@ -794,41 +859,12 @@ static int qcam_enum_framesizes(struct file *file, void *fh,
        return 0;
 }
 
-static ssize_t qcam_read(struct file *file, char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       struct qcam *qcam = video_drvdata(file);
-       int len;
-       parport_claim_or_block(qcam->pdev);
-
-       mutex_lock(&qcam->lock);
-
-       qc_reset(qcam);
-
-       /* Update the camera parameters if we need to */
-       if (qcam->status & QC_PARAM_CHANGE)
-               qc_set(qcam);
-
-       len = qc_capture(qcam, buf, count);
-
-       mutex_unlock(&qcam->lock);
-
-       parport_release(qcam->pdev);
-       return len;
-}
-
-static unsigned int qcam_poll(struct file *filp, poll_table *wait)
-{
-       return v4l2_ctrl_poll(filp, wait) | POLLIN | POLLRDNORM;
-}
-
 static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct qcam *qcam =
                container_of(ctrl->handler, struct qcam, hdl);
        int ret = 0;
 
-       mutex_lock(&qcam->lock);
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                qcam->brightness = ctrl->val;
@@ -847,17 +883,17 @@ static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
                qc_setscanmode(qcam);
                qcam->status |= QC_PARAM_CHANGE;
        }
-       mutex_unlock(&qcam->lock);
        return ret;
 }
 
 static const struct v4l2_file_operations qcam_fops = {
        .owner          = THIS_MODULE,
        .open           = v4l2_fh_open,
-       .release        = v4l2_fh_release,
-       .poll           = qcam_poll,
+       .release        = vb2_fop_release,
+       .poll           = vb2_fop_poll,
        .unlocked_ioctl = video_ioctl2,
-       .read           = qcam_read,
+       .read           = vb2_fop_read,
+       .mmap           = vb2_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
@@ -870,6 +906,14 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
        .vidioc_g_fmt_vid_cap               = qcam_g_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap               = qcam_s_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap             = qcam_try_fmt_vid_cap,
+       .vidioc_reqbufs                     = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs                 = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf                 = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf                    = vb2_ioctl_querybuf,
+       .vidioc_qbuf                        = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                       = vb2_ioctl_dqbuf,
+       .vidioc_streamon                    = vb2_ioctl_streamon,
+       .vidioc_streamoff                   = vb2_ioctl_streamoff,
        .vidioc_log_status                  = v4l2_ctrl_log_status,
        .vidioc_subscribe_event             = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event           = v4l2_event_unsubscribe,
@@ -886,6 +930,8 @@ static struct qcam *qcam_init(struct parport *port)
 {
        struct qcam *qcam;
        struct v4l2_device *v4l2_dev;
+       struct vb2_queue *q;
+       int err;
 
        qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
        if (qcam == NULL)
@@ -909,31 +955,45 @@ static struct qcam *qcam_init(struct parport *port)
                          V4L2_CID_GAMMA, 0, 255, 1, 105);
        if (qcam->hdl.error) {
                v4l2_err(v4l2_dev, "couldn't register controls\n");
-               v4l2_ctrl_handler_free(&qcam->hdl);
-               kfree(qcam);
-               return NULL;
+               goto exit;
+       }
+
+       mutex_init(&qcam->lock);
+       mutex_init(&qcam->queue_lock);
+
+       /* initialize queue */
+       q = &qcam->vb_vidq;
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+       q->drv_priv = qcam;
+       q->ops = &qcam_video_qops;
+       q->mem_ops = &vb2_vmalloc_memops;
+       err = vb2_queue_init(q);
+       if (err < 0) {
+               v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name);
+               goto exit;
        }
+       qcam->vdev.queue = q;
+       qcam->vdev.queue->lock = &qcam->queue_lock;
+
        qcam->pport = port;
        qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
                        NULL, 0, NULL);
        if (qcam->pdev == NULL) {
                v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
-               v4l2_ctrl_handler_free(&qcam->hdl);
-               kfree(qcam);
-               return NULL;
+               goto exit;
        }
 
        strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
        qcam->vdev.v4l2_dev = v4l2_dev;
        qcam->vdev.ctrl_handler = &qcam->hdl;
        qcam->vdev.fops = &qcam_fops;
+       qcam->vdev.lock = &qcam->lock;
        qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
        set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
        qcam->vdev.release = video_device_release_empty;
        video_set_drvdata(&qcam->vdev, qcam);
 
-       mutex_init(&qcam->lock);
-
        qcam->port_mode = (QC_ANY | QC_NOTSET);
        qcam->width = 320;
        qcam->height = 240;
@@ -947,6 +1007,11 @@ static struct qcam *qcam_init(struct parport *port)
        qcam->mode = -1;
        qcam->status = QC_PARAM_CHANGE;
        return qcam;
+
+exit:
+       v4l2_ctrl_handler_free(&qcam->hdl);
+       kfree(qcam);
+       return NULL;
 }
 
 static int qc_calibrate(struct qcam *q)