[media] vivi: convert to the control framework and add test controls
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
0eb73de019
commit
7e996afa81
1 changed files with 140 additions and 90 deletions
|
@ -30,6 +30,7 @@
|
||||||
#include <media/videobuf2-vmalloc.h>
|
#include <media/videobuf2-vmalloc.h>
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
#include <media/v4l2-ioctl.h>
|
#include <media/v4l2-ioctl.h>
|
||||||
|
#include <media/v4l2-ctrls.h>
|
||||||
#include <media/v4l2-common.h>
|
#include <media/v4l2-common.h>
|
||||||
|
|
||||||
#define VIVI_MODULE_NAME "vivi"
|
#define VIVI_MODULE_NAME "vivi"
|
||||||
|
@ -158,13 +159,20 @@ static LIST_HEAD(vivi_devlist);
|
||||||
struct vivi_dev {
|
struct vivi_dev {
|
||||||
struct list_head vivi_devlist;
|
struct list_head vivi_devlist;
|
||||||
struct v4l2_device v4l2_dev;
|
struct v4l2_device v4l2_dev;
|
||||||
|
struct v4l2_ctrl_handler ctrl_handler;
|
||||||
|
|
||||||
/* controls */
|
/* controls */
|
||||||
int brightness;
|
struct v4l2_ctrl *brightness;
|
||||||
int contrast;
|
struct v4l2_ctrl *contrast;
|
||||||
int saturation;
|
struct v4l2_ctrl *saturation;
|
||||||
int hue;
|
struct v4l2_ctrl *hue;
|
||||||
int volume;
|
struct v4l2_ctrl *volume;
|
||||||
|
struct v4l2_ctrl *button;
|
||||||
|
struct v4l2_ctrl *boolean;
|
||||||
|
struct v4l2_ctrl *int32;
|
||||||
|
struct v4l2_ctrl *int64;
|
||||||
|
struct v4l2_ctrl *menu;
|
||||||
|
struct v4l2_ctrl *string;
|
||||||
|
|
||||||
spinlock_t slock;
|
spinlock_t slock;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
@ -177,6 +185,7 @@ struct vivi_dev {
|
||||||
/* Several counters */
|
/* Several counters */
|
||||||
unsigned ms;
|
unsigned ms;
|
||||||
unsigned long jiffies;
|
unsigned long jiffies;
|
||||||
|
unsigned button_pressed;
|
||||||
|
|
||||||
int mv_count; /* Controls bars movement */
|
int mv_count; /* Controls bars movement */
|
||||||
|
|
||||||
|
@ -470,14 +479,30 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
|
||||||
dev->width, dev->height, dev->input);
|
dev->width, dev->height, dev->input);
|
||||||
gen_text(dev, vbuf, line++ * 16, 16, str);
|
gen_text(dev, vbuf, line++ * 16, 16, str);
|
||||||
|
|
||||||
|
mutex_lock(&dev->ctrl_handler.lock);
|
||||||
snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
|
snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
|
||||||
dev->brightness,
|
dev->brightness->cur.val,
|
||||||
dev->contrast,
|
dev->contrast->cur.val,
|
||||||
dev->saturation,
|
dev->saturation->cur.val,
|
||||||
dev->hue);
|
dev->hue->cur.val);
|
||||||
gen_text(dev, vbuf, line++ * 16, 16, str);
|
gen_text(dev, vbuf, line++ * 16, 16, str);
|
||||||
snprintf(str, sizeof(str), " volume %3d ", dev->volume);
|
snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val);
|
||||||
gen_text(dev, vbuf, line++ * 16, 16, str);
|
gen_text(dev, vbuf, line++ * 16, 16, str);
|
||||||
|
snprintf(str, sizeof(str), " int32 %d, int64 %lld ",
|
||||||
|
dev->int32->cur.val,
|
||||||
|
dev->int64->cur.val64);
|
||||||
|
gen_text(dev, vbuf, line++ * 16, 16, str);
|
||||||
|
snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
|
||||||
|
dev->boolean->cur.val,
|
||||||
|
dev->menu->qmenu[dev->menu->cur.val],
|
||||||
|
dev->string->cur.string);
|
||||||
|
mutex_unlock(&dev->ctrl_handler.lock);
|
||||||
|
gen_text(dev, vbuf, line++ * 16, 16, str);
|
||||||
|
if (dev->button_pressed) {
|
||||||
|
dev->button_pressed--;
|
||||||
|
snprintf(str, sizeof(str), " button pressed!");
|
||||||
|
gen_text(dev, vbuf, line++ * 16, 16, str);
|
||||||
|
}
|
||||||
|
|
||||||
dev->mv_count += 2;
|
dev->mv_count += 2;
|
||||||
|
|
||||||
|
@ -957,80 +982,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- controls ---------------------------------------------- */
|
/* --- controls ---------------------------------------------- */
|
||||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
|
||||||
struct v4l2_queryctrl *qc)
|
static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
switch (qc->id) {
|
struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
if (ctrl == dev->button)
|
||||||
struct v4l2_control *ctrl)
|
dev->button_pressed = 30;
|
||||||
{
|
return 0;
|
||||||
struct vivi_dev *dev = video_drvdata(file);
|
|
||||||
|
|
||||||
switch (ctrl->id) {
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
ctrl->value = dev->volume;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
ctrl->value = dev->brightness;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
ctrl->value = dev->contrast;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
ctrl->value = dev->saturation;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
ctrl->value = dev->hue;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
|
||||||
struct v4l2_control *ctrl)
|
|
||||||
{
|
|
||||||
struct vivi_dev *dev = video_drvdata(file);
|
|
||||||
struct v4l2_queryctrl qc;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
qc.id = ctrl->id;
|
|
||||||
err = vidioc_queryctrl(file, priv, &qc);
|
|
||||||
if (err < 0)
|
|
||||||
return err;
|
|
||||||
if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
|
|
||||||
return -ERANGE;
|
|
||||||
switch (ctrl->id) {
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
dev->volume = ctrl->value;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
dev->brightness = ctrl->value;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
dev->contrast = ctrl->value;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
dev->saturation = ctrl->value;
|
|
||||||
return 0;
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
dev->hue = ctrl->value;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
/* ------------------------------------------------------------------
|
||||||
|
@ -1094,6 +1053,79 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
|
||||||
|
.s_ctrl = vivi_s_ctrl,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_config vivi_ctrl_button = {
|
||||||
|
.ops = &vivi_ctrl_ops,
|
||||||
|
.id = VIVI_CID_CUSTOM_BASE + 0,
|
||||||
|
.name = "Button",
|
||||||
|
.type = V4L2_CTRL_TYPE_BUTTON,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
|
||||||
|
.ops = &vivi_ctrl_ops,
|
||||||
|
.id = VIVI_CID_CUSTOM_BASE + 1,
|
||||||
|
.name = "Boolean",
|
||||||
|
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||||
|
.min = 0,
|
||||||
|
.max = 1,
|
||||||
|
.step = 1,
|
||||||
|
.def = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
|
||||||
|
.ops = &vivi_ctrl_ops,
|
||||||
|
.id = VIVI_CID_CUSTOM_BASE + 2,
|
||||||
|
.name = "Integer 32 Bits",
|
||||||
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
|
.min = -2147483648,
|
||||||
|
.max = 2147483647,
|
||||||
|
.step = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
|
||||||
|
.ops = &vivi_ctrl_ops,
|
||||||
|
.id = VIVI_CID_CUSTOM_BASE + 3,
|
||||||
|
.name = "Integer 64 Bits",
|
||||||
|
.type = V4L2_CTRL_TYPE_INTEGER64,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const vivi_ctrl_menu_strings[] = {
|
||||||
|
"Menu Item 0 (Skipped)",
|
||||||
|
"Menu Item 1",
|
||||||
|
"Menu Item 2 (Skipped)",
|
||||||
|
"Menu Item 3",
|
||||||
|
"Menu Item 4",
|
||||||
|
"Menu Item 5 (Skipped)",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_config vivi_ctrl_menu = {
|
||||||
|
.ops = &vivi_ctrl_ops,
|
||||||
|
.id = VIVI_CID_CUSTOM_BASE + 4,
|
||||||
|
.name = "Menu",
|
||||||
|
.type = V4L2_CTRL_TYPE_MENU,
|
||||||
|
.min = 1,
|
||||||
|
.max = 4,
|
||||||
|
.def = 3,
|
||||||
|
.menu_skip_mask = 0x04,
|
||||||
|
.qmenu = vivi_ctrl_menu_strings,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_config vivi_ctrl_string = {
|
||||||
|
.ops = &vivi_ctrl_ops,
|
||||||
|
.id = VIVI_CID_CUSTOM_BASE + 5,
|
||||||
|
.name = "String",
|
||||||
|
.type = V4L2_CTRL_TYPE_STRING,
|
||||||
|
.min = 2,
|
||||||
|
.max = 4,
|
||||||
|
.step = 1,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct v4l2_file_operations vivi_fops = {
|
static const struct v4l2_file_operations vivi_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.open = vivi_open,
|
.open = vivi_open,
|
||||||
|
@ -1120,9 +1152,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
|
||||||
.vidioc_s_input = vidioc_s_input,
|
.vidioc_s_input = vidioc_s_input,
|
||||||
.vidioc_streamon = vidioc_streamon,
|
.vidioc_streamon = vidioc_streamon,
|
||||||
.vidioc_streamoff = vidioc_streamoff,
|
.vidioc_streamoff = vidioc_streamoff,
|
||||||
.vidioc_queryctrl = vidioc_queryctrl,
|
|
||||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
|
||||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct video_device vivi_template = {
|
static struct video_device vivi_template = {
|
||||||
|
@ -1153,6 +1182,7 @@ static int vivi_release(void)
|
||||||
video_device_node_name(dev->vfd));
|
video_device_node_name(dev->vfd));
|
||||||
video_unregister_device(dev->vfd);
|
video_unregister_device(dev->vfd);
|
||||||
v4l2_device_unregister(&dev->v4l2_dev);
|
v4l2_device_unregister(&dev->v4l2_dev);
|
||||||
|
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,6 +1193,7 @@ static int __init vivi_create_instance(int inst)
|
||||||
{
|
{
|
||||||
struct vivi_dev *dev;
|
struct vivi_dev *dev;
|
||||||
struct video_device *vfd;
|
struct video_device *vfd;
|
||||||
|
struct v4l2_ctrl_handler *hdl;
|
||||||
struct vb2_queue *q;
|
struct vb2_queue *q;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1179,11 +1210,29 @@ static int __init vivi_create_instance(int inst)
|
||||||
dev->fmt = &formats[0];
|
dev->fmt = &formats[0];
|
||||||
dev->width = 640;
|
dev->width = 640;
|
||||||
dev->height = 480;
|
dev->height = 480;
|
||||||
dev->volume = 200;
|
hdl = &dev->ctrl_handler;
|
||||||
dev->brightness = 127;
|
v4l2_ctrl_handler_init(hdl, 11);
|
||||||
dev->contrast = 16;
|
dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
|
||||||
dev->saturation = 127;
|
V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
|
||||||
dev->hue = 0;
|
dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
|
||||||
|
V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
|
||||||
|
dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
|
||||||
|
V4L2_CID_CONTRAST, 0, 255, 1, 16);
|
||||||
|
dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
|
||||||
|
V4L2_CID_SATURATION, 0, 255, 1, 127);
|
||||||
|
dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
|
||||||
|
V4L2_CID_HUE, -128, 127, 1, 0);
|
||||||
|
dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
|
||||||
|
dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
|
||||||
|
dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
|
||||||
|
dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
|
||||||
|
dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
|
||||||
|
dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
|
||||||
|
if (hdl->error) {
|
||||||
|
ret = hdl->error;
|
||||||
|
goto unreg_dev;
|
||||||
|
}
|
||||||
|
dev->v4l2_dev.ctrl_handler = hdl;
|
||||||
|
|
||||||
/* initialize locks */
|
/* initialize locks */
|
||||||
spin_lock_init(&dev->slock);
|
spin_lock_init(&dev->slock);
|
||||||
|
@ -1241,6 +1290,7 @@ static int __init vivi_create_instance(int inst)
|
||||||
rel_vdev:
|
rel_vdev:
|
||||||
video_device_release(vfd);
|
video_device_release(vfd);
|
||||||
unreg_dev:
|
unreg_dev:
|
||||||
|
v4l2_ctrl_handler_free(hdl);
|
||||||
v4l2_device_unregister(&dev->v4l2_dev);
|
v4l2_device_unregister(&dev->v4l2_dev);
|
||||||
free_dev:
|
free_dev:
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
|
|
Loading…
Reference in a new issue