summaryrefslogtreecommitdiff
path: root/drivers/media/video/bw-qcam.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/bw-qcam.c')
-rw-r--r--drivers/media/video/bw-qcam.c177
1 files changed, 98 insertions, 79 deletions
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index f09df9dffaae..5b75a64b199b 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -77,6 +77,9 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
/* One from column A... */
#define QC_NOTSET 0
@@ -103,6 +106,7 @@ OTHER DEALINGS IN THE SOFTWARE.
struct qcam {
struct v4l2_device v4l2_dev;
struct video_device vdev;
+ struct v4l2_ctrl_handler hdl;
struct pardevice *pdev;
struct parport *pport;
struct mutex lock;
@@ -603,8 +607,9 @@ static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
}
o = i * pixels_per_line + pixels_read + k;
if (o < len) {
+ u8 ch = invert - buffer[k];
got++;
- put_user((invert - buffer[k]) << shift, buf + o);
+ put_user(ch << shift, buf + o);
}
}
pixels_read += bytes;
@@ -644,9 +649,10 @@ static int qcam_querycap(struct file *file, void *priv,
struct qcam *qcam = video_drvdata(file);
strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
- strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
- strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
- vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ 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->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -674,72 +680,6 @@ static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
return (inp > 0) ? -EINVAL : 0;
}
-static int qcam_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
- case V4L2_CID_GAMMA:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105);
- }
- return -EINVAL;
-}
-
-static int qcam_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct qcam *qcam = video_drvdata(file);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = qcam->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = qcam->contrast;
- break;
- case V4L2_CID_GAMMA:
- ctrl->value = qcam->whitebal;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int qcam_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct qcam *qcam = video_drvdata(file);
- int ret = 0;
-
- mutex_lock(&qcam->lock);
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- qcam->brightness = ctrl->value;
- break;
- case V4L2_CID_CONTRAST:
- qcam->contrast = ctrl->value;
- break;
- case V4L2_CID_GAMMA:
- qcam->whitebal = ctrl->value;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret == 0) {
- qc_setscanmode(qcam);
- qcam->status |= QC_PARAM_CHANGE;
- }
- mutex_unlock(&qcam->lock);
- return ret;
-}
-
static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct qcam *qcam = video_drvdata(file);
@@ -749,8 +689,8 @@ static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
pix->height = qcam->height / qcam->transfer_scale;
pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = qcam->width;
- pix->sizeimage = qcam->width * qcam->height;
+ pix->bytesperline = pix->width;
+ pix->sizeimage = pix->width * pix->height;
/* Just a guess */
pix->colorspace = V4L2_COLORSPACE_SRGB;
return 0;
@@ -818,7 +758,7 @@ static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes
"4-Bit Monochrome", V4L2_PIX_FMT_Y4,
{ 0, 0, 0, 0 }
},
- { 0, 0, 0,
+ { 1, 0, 0,
"6-Bit Monochrome", V4L2_PIX_FMT_Y6,
{ 0, 0, 0, 0 }
},
@@ -833,6 +773,25 @@ static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes
return 0;
}
+static int qcam_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ static const struct v4l2_frmsize_discrete sizes[] = {
+ { 80, 60 },
+ { 160, 120 },
+ { 320, 240 },
+ };
+
+ if (fsize->index > 2)
+ return -EINVAL;
+ if (fsize->pixel_format != V4L2_PIX_FMT_Y4 &&
+ fsize->pixel_format != V4L2_PIX_FMT_Y6)
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete = sizes[fsize->index];
+ return 0;
+}
+
static ssize_t qcam_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -856,8 +815,45 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
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;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->val;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ 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,
.unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
@@ -867,13 +863,18 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
.vidioc_g_input = qcam_g_input,
.vidioc_s_input = qcam_s_input,
.vidioc_enum_input = qcam_enum_input,
- .vidioc_queryctrl = qcam_queryctrl,
- .vidioc_g_ctrl = qcam_g_ctrl,
- .vidioc_s_ctrl = qcam_s_ctrl,
.vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
+ .vidioc_enum_framesizes = qcam_enum_framesizes,
.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_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+ .s_ctrl = qcam_s_ctrl,
};
/* Initialize the QuickCam driver control structure. This is where
@@ -889,27 +890,43 @@ static struct qcam *qcam_init(struct parport *port)
return NULL;
v4l2_dev = &qcam->v4l2_dev;
- strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name));
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%d", num_cams);
- if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+ if (v4l2_device_register(port->dev, v4l2_dev) < 0) {
v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
kfree(qcam);
return NULL;
}
+ v4l2_ctrl_handler_init(&qcam->hdl, 3);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 180);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 192);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ 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;
+ }
qcam->pport = port;
- qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
+ 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;
}
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.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);
@@ -984,6 +1001,7 @@ static int init_bwqcam(struct parport *port)
return -ENODEV;
}
qc_calibrate(qcam);
+ v4l2_ctrl_handler_setup(&qcam->hdl);
parport_release(qcam->pdev);
@@ -1003,6 +1021,7 @@ static int init_bwqcam(struct parport *port)
static void close_bwqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
+ v4l2_ctrl_handler_free(&qcam->hdl);
parport_unregister_device(qcam->pdev);
kfree(qcam);
}