Commit c813bd3c authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] solo6x10: add control framework

Note that the MOTION_THRESHOLD functionality has been temporarily reduced:
only the global threshold can be set, not the per-block. This will be
addressed in a later patch: controls are not the proper way to do this.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d9ebd623
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/videobuf-core.h> #include <media/videobuf-core.h>
#include "registers.h" #include "registers.h"
...@@ -100,12 +101,12 @@ ...@@ -100,12 +101,12 @@
#define V4L2_BUF_FLAG_MOTION_ON 0x0400 #define V4L2_BUF_FLAG_MOTION_ON 0x0400
#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800
#endif #endif
#ifndef V4L2_CID_MOTION_ENABLE
#define PRIVATE_CIDS #define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0) #define V4L2_CID_MOTION_ENABLE (SOLO_CID_CUSTOM_BASE+0)
#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1) #define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1)
#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2) #define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2)
#endif #define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3)
enum SOLO_I2C_STATE { enum SOLO_I2C_STATE {
IIC_STATE_IDLE, IIC_STATE_IDLE,
...@@ -137,6 +138,7 @@ struct solo_p2m_dev { ...@@ -137,6 +138,7 @@ struct solo_p2m_dev {
struct solo_enc_dev { struct solo_enc_dev {
struct solo_dev *solo_dev; struct solo_dev *solo_dev;
/* V4L2 Items */ /* V4L2 Items */
struct v4l2_ctrl_handler hdl;
struct video_device *vfd; struct video_device *vfd;
/* General accounting */ /* General accounting */
struct mutex enable_lock; struct mutex enable_lock;
...@@ -207,6 +209,7 @@ struct solo_dev { ...@@ -207,6 +209,7 @@ struct solo_dev {
unsigned int frame_blank; unsigned int frame_blank;
u8 cur_disp_ch; u8 cur_disp_ch;
wait_queue_head_t disp_thread_wait; wait_queue_head_t disp_thread_wait;
struct v4l2_ctrl_handler disp_hdl;
/* V4L2 Encoder items */ /* V4L2 Encoder items */
struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS]; struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS];
......
...@@ -660,6 +660,11 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) ...@@ -660,6 +660,11 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev)
} }
#endif #endif
bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch)
{
return is_tw286x(solo_dev, ch / 4);
}
int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
s32 val) s32 val)
{ {
...@@ -676,8 +681,6 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, ...@@ -676,8 +681,6 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
switch (ctrl) { switch (ctrl) {
case V4L2_CID_SHARPNESS: case V4L2_CID_SHARPNESS:
/* Only 286x has sharpness */ /* Only 286x has sharpness */
if (val > 0x0f || val < 0)
return -ERANGE;
if (is_tw286x(solo_dev, chip_num)) { if (is_tw286x(solo_dev, chip_num)) {
u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(chip_num), TW_CHIP_OFFSET_ADDR(chip_num),
...@@ -687,8 +690,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, ...@@ -687,8 +690,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(chip_num), TW_CHIP_OFFSET_ADDR(chip_num),
TW286x_SHARPNESS(chip_num), v); TW286x_SHARPNESS(chip_num), v);
} else if (val != 0) } else {
return -ERANGE; return -EINVAL;
}
break; break;
case V4L2_CID_HUE: case V4L2_CID_HUE:
......
...@@ -55,6 +55,7 @@ int solo_tw28_init(struct solo_dev *solo_dev); ...@@ -55,6 +55,7 @@ int solo_tw28_init(struct solo_dev *solo_dev);
int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch);
u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
......
This diff is collapsed.
...@@ -687,64 +687,14 @@ static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) ...@@ -687,64 +687,14 @@ static int solo_s_std(struct file *file, void *priv, v4l2_std_id i)
return 0; return 0;
} }
static const u32 solo_motion_ctrls[] = { static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
V4L2_CID_MOTION_TRACE,
0
};
static const u32 *solo_ctrl_classes[] = {
solo_motion_ctrls,
NULL
};
static int solo_disp_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
if (!qc->id)
return -EINVAL;
switch (qc->id) {
#ifdef PRIVATE_CIDS
case V4L2_CID_MOTION_TRACE:
qc->type = V4L2_CTRL_TYPE_BOOLEAN;
qc->minimum = 0;
qc->maximum = qc->step = 1;
qc->default_value = 0;
strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
return 0;
#else
case V4L2_CID_MOTION_TRACE:
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
#endif
}
return -EINVAL;
}
static int solo_disp_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{ {
struct solo_filehandle *fh = priv; struct solo_dev *solo_dev =
struct solo_dev *solo_dev = fh->solo_dev; container_of(ctrl->handler, struct solo_dev, disp_hdl);
switch (ctrl->id) { switch (ctrl->id) {
case V4L2_CID_MOTION_TRACE: case V4L2_CID_MOTION_TRACE:
ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR) if (ctrl->val) {
? 1 : 0;
return 0;
}
return -EINVAL;
}
static int solo_disp_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct solo_filehandle *fh = priv;
struct solo_dev *solo_dev = fh->solo_dev;
switch (ctrl->id) {
case V4L2_CID_MOTION_TRACE:
if (ctrl->value) {
solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
SOLO_VI_MOTION_Y_ADD | SOLO_VI_MOTION_Y_ADD |
SOLO_VI_MOTION_Y_VALUE(0x20) | SOLO_VI_MOTION_Y_VALUE(0x20) |
...@@ -760,6 +710,8 @@ static int solo_disp_s_ctrl(struct file *file, void *priv, ...@@ -760,6 +710,8 @@ static int solo_disp_s_ctrl(struct file *file, void *priv,
solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
} }
return 0; return 0;
default:
break;
} }
return -EINVAL; return -EINVAL;
} }
...@@ -793,10 +745,6 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { ...@@ -793,10 +745,6 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
.vidioc_dqbuf = solo_dqbuf, .vidioc_dqbuf = solo_dqbuf,
.vidioc_streamon = solo_streamon, .vidioc_streamon = solo_streamon,
.vidioc_streamoff = solo_streamoff, .vidioc_streamoff = solo_streamoff,
/* Controls */
.vidioc_queryctrl = solo_disp_queryctrl,
.vidioc_g_ctrl = solo_disp_g_ctrl,
.vidioc_s_ctrl = solo_disp_s_ctrl,
}; };
static struct video_device solo_v4l2_template = { static struct video_device solo_v4l2_template = {
...@@ -810,6 +758,19 @@ static struct video_device solo_v4l2_template = { ...@@ -810,6 +758,19 @@ static struct video_device solo_v4l2_template = {
.current_norm = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M,
}; };
static const struct v4l2_ctrl_ops solo_ctrl_ops = {
.s_ctrl = solo_s_ctrl,
};
static const struct v4l2_ctrl_config solo_motion_trace_ctrl = {
.ops = &solo_ctrl_ops,
.id = V4L2_CID_MOTION_TRACE,
.name = "Motion Detection Trace",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.max = 1,
.step = 1,
};
int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
{ {
int ret; int ret;
...@@ -824,6 +785,11 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) ...@@ -824,6 +785,11 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
*solo_dev->vfd = solo_v4l2_template; *solo_dev->vfd = solo_v4l2_template;
solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
if (solo_dev->disp_hdl.error)
return solo_dev->disp_hdl.error;
solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
if (ret < 0) { if (ret < 0) {
...@@ -862,5 +828,6 @@ void solo_v4l2_exit(struct solo_dev *solo_dev) ...@@ -862,5 +828,6 @@ void solo_v4l2_exit(struct solo_dev *solo_dev)
return; return;
video_unregister_device(solo_dev->vfd); video_unregister_device(solo_dev->vfd);
v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
solo_dev->vfd = NULL; solo_dev->vfd = NULL;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment