forked from luck/tmp_suning_uos_patched
[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>
This commit is contained in:
parent
11d3793952
commit
1888e4a974
|
@ -9,6 +9,7 @@ if MEDIA_PARPORT_SUPPORT
|
||||||
config VIDEO_BWQCAM
|
config VIDEO_BWQCAM
|
||||||
tristate "Quickcam BW Video For Linux"
|
tristate "Quickcam BW Video For Linux"
|
||||||
depends on PARPORT && VIDEO_V4L2
|
depends on PARPORT && VIDEO_V4L2
|
||||||
|
select VIDEOBUF2_VMALLOC
|
||||||
help
|
help
|
||||||
Say Y have if you the black and white version of the QuickCam
|
Say Y have if you the black and white version of the QuickCam
|
||||||
camera. See the next option for the color version.
|
camera. See the next option for the color version.
|
||||||
|
|
|
@ -80,6 +80,7 @@ OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <media/v4l2-fh.h>
|
#include <media/v4l2-fh.h>
|
||||||
#include <media/v4l2-ctrls.h>
|
#include <media/v4l2-ctrls.h>
|
||||||
#include <media/v4l2-event.h>
|
#include <media/v4l2-event.h>
|
||||||
|
#include <media/videobuf2-vmalloc.h>
|
||||||
|
|
||||||
/* One from column A... */
|
/* One from column A... */
|
||||||
#define QC_NOTSET 0
|
#define QC_NOTSET 0
|
||||||
|
@ -107,9 +108,11 @@ struct qcam {
|
||||||
struct v4l2_device v4l2_dev;
|
struct v4l2_device v4l2_dev;
|
||||||
struct video_device vdev;
|
struct video_device vdev;
|
||||||
struct v4l2_ctrl_handler hdl;
|
struct v4l2_ctrl_handler hdl;
|
||||||
|
struct vb2_queue vb_vidq;
|
||||||
struct pardevice *pdev;
|
struct pardevice *pdev;
|
||||||
struct parport *pport;
|
struct parport *pport;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
struct mutex queue_lock;
|
||||||
int width, height;
|
int width, height;
|
||||||
int bpp;
|
int bpp;
|
||||||
int mode;
|
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
|
* n=2^(bit depth)-1. Ask me for more details if you don't understand
|
||||||
* this. */
|
* 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 i, j, k, yield;
|
||||||
int bytes;
|
int bytes;
|
||||||
|
@ -609,7 +612,7 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
|
||||||
if (o < len) {
|
if (o < len) {
|
||||||
u8 ch = invert - buffer[k];
|
u8 ch = invert - buffer[k];
|
||||||
got++;
|
got++;
|
||||||
put_user(ch << shift, buf + o);
|
buf[o] = ch << shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pixels_read += bytes;
|
pixels_read += bytes;
|
||||||
|
@ -639,6 +642,67 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
|
||||||
return 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
|
* 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->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
|
||||||
strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
|
strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
|
||||||
strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info));
|
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;
|
vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -731,6 +796,8 @@ static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (vb2_is_busy(&qcam->vb_vidq))
|
||||||
|
return -EBUSY;
|
||||||
qcam->width = 320;
|
qcam->width = 320;
|
||||||
qcam->height = 240;
|
qcam->height = 240;
|
||||||
if (pix->height == 60)
|
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
|
else
|
||||||
qcam->bpp = 4;
|
qcam->bpp = 4;
|
||||||
|
|
||||||
mutex_lock(&qcam->lock);
|
|
||||||
qc_setscanmode(qcam);
|
qc_setscanmode(qcam);
|
||||||
/* We must update the camera before we grab. We could
|
/* We must update the camera before we grab. We could
|
||||||
just have changed the grab size */
|
just have changed the grab size */
|
||||||
qcam->status |= QC_PARAM_CHANGE;
|
qcam->status |= QC_PARAM_CHANGE;
|
||||||
mutex_unlock(&qcam->lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,41 +859,12 @@ static int qcam_enum_framesizes(struct file *file, void *fh,
|
||||||
return 0;
|
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)
|
static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
struct qcam *qcam =
|
struct qcam *qcam =
|
||||||
container_of(ctrl->handler, struct qcam, hdl);
|
container_of(ctrl->handler, struct qcam, hdl);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&qcam->lock);
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_BRIGHTNESS:
|
case V4L2_CID_BRIGHTNESS:
|
||||||
qcam->brightness = ctrl->val;
|
qcam->brightness = ctrl->val;
|
||||||
|
@ -847,17 +883,17 @@ static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
qc_setscanmode(qcam);
|
qc_setscanmode(qcam);
|
||||||
qcam->status |= QC_PARAM_CHANGE;
|
qcam->status |= QC_PARAM_CHANGE;
|
||||||
}
|
}
|
||||||
mutex_unlock(&qcam->lock);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct v4l2_file_operations qcam_fops = {
|
static const struct v4l2_file_operations qcam_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = v4l2_fh_open,
|
.open = v4l2_fh_open,
|
||||||
.release = v4l2_fh_release,
|
.release = vb2_fop_release,
|
||||||
.poll = qcam_poll,
|
.poll = vb2_fop_poll,
|
||||||
.unlocked_ioctl = video_ioctl2,
|
.unlocked_ioctl = video_ioctl2,
|
||||||
.read = qcam_read,
|
.read = vb2_fop_read,
|
||||||
|
.mmap = vb2_fop_mmap,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
|
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_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
|
||||||
.vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
|
.vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
|
||||||
.vidioc_try_fmt_vid_cap = qcam_try_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_log_status = v4l2_ctrl_log_status,
|
||||||
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
||||||
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
||||||
|
@ -886,6 +930,8 @@ static struct qcam *qcam_init(struct parport *port)
|
||||||
{
|
{
|
||||||
struct qcam *qcam;
|
struct qcam *qcam;
|
||||||
struct v4l2_device *v4l2_dev;
|
struct v4l2_device *v4l2_dev;
|
||||||
|
struct vb2_queue *q;
|
||||||
|
int err;
|
||||||
|
|
||||||
qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
|
qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
|
||||||
if (qcam == NULL)
|
if (qcam == NULL)
|
||||||
|
@ -909,31 +955,45 @@ static struct qcam *qcam_init(struct parport *port)
|
||||||
V4L2_CID_GAMMA, 0, 255, 1, 105);
|
V4L2_CID_GAMMA, 0, 255, 1, 105);
|
||||||
if (qcam->hdl.error) {
|
if (qcam->hdl.error) {
|
||||||
v4l2_err(v4l2_dev, "couldn't register controls\n");
|
v4l2_err(v4l2_dev, "couldn't register controls\n");
|
||||||
v4l2_ctrl_handler_free(&qcam->hdl);
|
goto exit;
|
||||||
kfree(qcam);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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->pport = port;
|
||||||
qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
|
qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
|
||||||
NULL, 0, NULL);
|
NULL, 0, NULL);
|
||||||
if (qcam->pdev == NULL) {
|
if (qcam->pdev == NULL) {
|
||||||
v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
|
v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
|
||||||
v4l2_ctrl_handler_free(&qcam->hdl);
|
goto exit;
|
||||||
kfree(qcam);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
|
strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
|
||||||
qcam->vdev.v4l2_dev = v4l2_dev;
|
qcam->vdev.v4l2_dev = v4l2_dev;
|
||||||
qcam->vdev.ctrl_handler = &qcam->hdl;
|
qcam->vdev.ctrl_handler = &qcam->hdl;
|
||||||
qcam->vdev.fops = &qcam_fops;
|
qcam->vdev.fops = &qcam_fops;
|
||||||
|
qcam->vdev.lock = &qcam->lock;
|
||||||
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
|
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
|
||||||
set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
|
set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
|
||||||
qcam->vdev.release = video_device_release_empty;
|
qcam->vdev.release = video_device_release_empty;
|
||||||
video_set_drvdata(&qcam->vdev, qcam);
|
video_set_drvdata(&qcam->vdev, qcam);
|
||||||
|
|
||||||
mutex_init(&qcam->lock);
|
|
||||||
|
|
||||||
qcam->port_mode = (QC_ANY | QC_NOTSET);
|
qcam->port_mode = (QC_ANY | QC_NOTSET);
|
||||||
qcam->width = 320;
|
qcam->width = 320;
|
||||||
qcam->height = 240;
|
qcam->height = 240;
|
||||||
|
@ -947,6 +1007,11 @@ static struct qcam *qcam_init(struct parport *port)
|
||||||
qcam->mode = -1;
|
qcam->mode = -1;
|
||||||
qcam->status = QC_PARAM_CHANGE;
|
qcam->status = QC_PARAM_CHANGE;
|
||||||
return qcam;
|
return qcam;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
v4l2_ctrl_handler_free(&qcam->hdl);
|
||||||
|
kfree(qcam);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qc_calibrate(struct qcam *q)
|
static int qc_calibrate(struct qcam *q)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user