[media] cx18: Use the control framework
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
34a078da8e
commit
a75b9be1c2
@@ -342,17 +342,6 @@ void cx18_av_audio_set_path(struct cx18 *cx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_volume(struct cx18 *cx)
|
|
||||||
{
|
|
||||||
/* Volume runs +18dB to -96dB in 1/2dB steps
|
|
||||||
* change to fit the msp3400 -114dB to +12dB range */
|
|
||||||
|
|
||||||
/* check PATH1_VOLUME */
|
|
||||||
int vol = 228 - cx18_av_read(cx, 0x8d4);
|
|
||||||
vol = (vol / 2) + 23;
|
|
||||||
return vol << 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_volume(struct cx18 *cx, int volume)
|
static void set_volume(struct cx18 *cx, int volume)
|
||||||
{
|
{
|
||||||
/* First convert the volume to msp3400 values (0-127) */
|
/* First convert the volume to msp3400 values (0-127) */
|
||||||
@@ -369,52 +358,18 @@ static void set_volume(struct cx18 *cx, int volume)
|
|||||||
cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
|
cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_bass(struct cx18 *cx)
|
|
||||||
{
|
|
||||||
/* bass is 49 steps +12dB to -12dB */
|
|
||||||
|
|
||||||
/* check PATH1_EQ_BASS_VOL */
|
|
||||||
int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
|
|
||||||
bass = (((48 - bass) * 0xffff) + 47) / 48;
|
|
||||||
return bass;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_bass(struct cx18 *cx, int bass)
|
static void set_bass(struct cx18 *cx, int bass)
|
||||||
{
|
{
|
||||||
/* PATH1_EQ_BASS_VOL */
|
/* PATH1_EQ_BASS_VOL */
|
||||||
cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
|
cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_treble(struct cx18 *cx)
|
|
||||||
{
|
|
||||||
/* treble is 49 steps +12dB to -12dB */
|
|
||||||
|
|
||||||
/* check PATH1_EQ_TREBLE_VOL */
|
|
||||||
int treble = cx18_av_read(cx, 0x8db) & 0x3f;
|
|
||||||
treble = (((48 - treble) * 0xffff) + 47) / 48;
|
|
||||||
return treble;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_treble(struct cx18 *cx, int treble)
|
static void set_treble(struct cx18 *cx, int treble)
|
||||||
{
|
{
|
||||||
/* PATH1_EQ_TREBLE_VOL */
|
/* PATH1_EQ_TREBLE_VOL */
|
||||||
cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
|
cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_balance(struct cx18 *cx)
|
|
||||||
{
|
|
||||||
/* balance is 7 bit, 0 to -96dB */
|
|
||||||
|
|
||||||
/* check PATH1_BAL_LEVEL */
|
|
||||||
int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
|
|
||||||
/* check PATH1_BAL_LEFT */
|
|
||||||
if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
|
|
||||||
balance = 0x80 - balance;
|
|
||||||
else
|
|
||||||
balance = 0x80 + balance;
|
|
||||||
return balance << 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_balance(struct cx18 *cx, int balance)
|
static void set_balance(struct cx18 *cx, int balance)
|
||||||
{
|
{
|
||||||
int bal = balance >> 8;
|
int bal = balance >> 8;
|
||||||
@@ -431,12 +386,6 @@ static void set_balance(struct cx18 *cx, int balance)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_mute(struct cx18 *cx)
|
|
||||||
{
|
|
||||||
/* check SRC1_MUTE_EN */
|
|
||||||
return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_mute(struct cx18 *cx, int mute)
|
static void set_mute(struct cx18 *cx, int mute)
|
||||||
{
|
{
|
||||||
struct cx18_av_state *state = &cx->av_state;
|
struct cx18_av_state *state = &cx->av_state;
|
||||||
@@ -490,23 +439,26 @@ int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
|
static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
|
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||||
|
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
||||||
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
case V4L2_CID_AUDIO_VOLUME:
|
||||||
ctrl->value = get_volume(cx);
|
set_volume(cx, ctrl->val);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_AUDIO_BASS:
|
case V4L2_CID_AUDIO_BASS:
|
||||||
ctrl->value = get_bass(cx);
|
set_bass(cx, ctrl->val);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
case V4L2_CID_AUDIO_TREBLE:
|
||||||
ctrl->value = get_treble(cx);
|
set_treble(cx, ctrl->val);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
case V4L2_CID_AUDIO_BALANCE:
|
||||||
ctrl->value = get_balance(cx);
|
set_balance(cx, ctrl->val);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
case V4L2_CID_AUDIO_MUTE:
|
||||||
ctrl->value = get_mute(cx);
|
set_mute(cx, ctrl->val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -514,26 +466,6 @@ int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
|
const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = {
|
||||||
{
|
.s_ctrl = cx18_av_audio_s_ctrl,
|
||||||
switch (ctrl->id) {
|
};
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
set_volume(cx, ctrl->value);
|
|
||||||
break;
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
set_bass(cx, ctrl->value);
|
|
||||||
break;
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
set_treble(cx, ctrl->value);
|
|
||||||
break;
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
set_balance(cx, ctrl->value);
|
|
||||||
break;
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
set_mute(cx, ctrl->value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
@@ -129,6 +129,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
|
|||||||
{
|
{
|
||||||
struct cx18_av_state *state = to_cx18_av_state(sd);
|
struct cx18_av_state *state = to_cx18_av_state(sd);
|
||||||
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
||||||
|
int default_volume;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
|
||||||
cx18_av_loadfw(cx);
|
cx18_av_loadfw(cx);
|
||||||
@@ -247,8 +248,23 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
|
|||||||
/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
|
/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
|
||||||
/* } */
|
/* } */
|
||||||
cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
|
cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
|
||||||
state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
|
default_volume = cx18_av_read(cx, 0x8d4);
|
||||||
state->default_volume = ((state->default_volume / 2) + 23) << 9;
|
/*
|
||||||
|
* Enforce the legacy volume scale mapping limits to avoid
|
||||||
|
* -ERANGE errors when initializing the volume control
|
||||||
|
*/
|
||||||
|
if (default_volume > 228) {
|
||||||
|
/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
|
||||||
|
default_volume = 228;
|
||||||
|
cx18_av_write(cx, 0x8d4, 228);
|
||||||
|
} else if (default_volume < 20) {
|
||||||
|
/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
|
||||||
|
default_volume = 20;
|
||||||
|
cx18_av_write(cx, 0x8d4, 20);
|
||||||
|
}
|
||||||
|
default_volume = (((228 - default_volume) >> 1) + 23) << 9;
|
||||||
|
state->volume->cur.val = state->volume->default_value = default_volume;
|
||||||
|
v4l2_ctrl_handler_setup(&state->hdl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
|
static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
|
||||||
@@ -901,126 +917,35 @@ static int cx18_av_s_radio(struct v4l2_subdev *sd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
|
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||||
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
||||||
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_BRIGHTNESS:
|
case V4L2_CID_BRIGHTNESS:
|
||||||
if (ctrl->value < 0 || ctrl->value > 255) {
|
cx18_av_write(cx, 0x414, ctrl->val - 128);
|
||||||
CX18_ERR_DEV(sd, "invalid brightness setting %d\n",
|
|
||||||
ctrl->value);
|
|
||||||
return -ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cx18_av_write(cx, 0x414, ctrl->value - 128);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_CONTRAST:
|
case V4L2_CID_CONTRAST:
|
||||||
if (ctrl->value < 0 || ctrl->value > 127) {
|
cx18_av_write(cx, 0x415, ctrl->val << 1);
|
||||||
CX18_ERR_DEV(sd, "invalid contrast setting %d\n",
|
|
||||||
ctrl->value);
|
|
||||||
return -ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cx18_av_write(cx, 0x415, ctrl->value << 1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_SATURATION:
|
case V4L2_CID_SATURATION:
|
||||||
if (ctrl->value < 0 || ctrl->value > 127) {
|
cx18_av_write(cx, 0x420, ctrl->val << 1);
|
||||||
CX18_ERR_DEV(sd, "invalid saturation setting %d\n",
|
cx18_av_write(cx, 0x421, ctrl->val << 1);
|
||||||
ctrl->value);
|
|
||||||
return -ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cx18_av_write(cx, 0x420, ctrl->value << 1);
|
|
||||||
cx18_av_write(cx, 0x421, ctrl->value << 1);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_HUE:
|
case V4L2_CID_HUE:
|
||||||
if (ctrl->value < -128 || ctrl->value > 127) {
|
cx18_av_write(cx, 0x422, ctrl->val);
|
||||||
CX18_ERR_DEV(sd, "invalid hue setting %d\n",
|
|
||||||
ctrl->value);
|
|
||||||
return -ERANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
cx18_av_write(cx, 0x422, ctrl->value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
return cx18_av_audio_s_ctrl(cx, ctrl);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|
||||||
{
|
|
||||||
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
|
||||||
|
|
||||||
switch (ctrl->id) {
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
|
|
||||||
break;
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
ctrl->value = cx18_av_read(cx, 0x415) >> 1;
|
|
||||||
break;
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
ctrl->value = cx18_av_read(cx, 0x420) >> 1;
|
|
||||||
break;
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
ctrl->value = (s8)cx18_av_read(cx, 0x422);
|
|
||||||
break;
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
return cx18_av_audio_g_ctrl(cx, ctrl);
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
|
|
||||||
{
|
|
||||||
struct cx18_av_state *state = to_cx18_av_state(sd);
|
|
||||||
|
|
||||||
switch (qc->id) {
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (qc->id) {
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 65535,
|
|
||||||
65535 / 100, state->default_volume);
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
|
static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
|
||||||
{
|
{
|
||||||
struct cx18_av_state *state = to_cx18_av_state(sd);
|
struct cx18_av_state *state = to_cx18_av_state(sd);
|
||||||
@@ -1356,14 +1281,22 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
|
||||||
|
.s_ctrl = cx18_av_s_ctrl,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
|
static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
|
||||||
.g_chip_ident = cx18_av_g_chip_ident,
|
.g_chip_ident = cx18_av_g_chip_ident,
|
||||||
.log_status = cx18_av_log_status,
|
.log_status = cx18_av_log_status,
|
||||||
.load_fw = cx18_av_load_fw,
|
.load_fw = cx18_av_load_fw,
|
||||||
.reset = cx18_av_reset,
|
.reset = cx18_av_reset,
|
||||||
.queryctrl = cx18_av_queryctrl,
|
.g_ctrl = v4l2_subdev_g_ctrl,
|
||||||
.g_ctrl = cx18_av_g_ctrl,
|
.s_ctrl = v4l2_subdev_s_ctrl,
|
||||||
.s_ctrl = cx18_av_s_ctrl,
|
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
|
||||||
|
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
|
||||||
|
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
|
||||||
|
.queryctrl = v4l2_subdev_queryctrl,
|
||||||
|
.querymenu = v4l2_subdev_querymenu,
|
||||||
.s_std = cx18_av_s_std,
|
.s_std = cx18_av_s_std,
|
||||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
.g_register = cx18_av_g_register,
|
.g_register = cx18_av_g_register,
|
||||||
@@ -1427,8 +1360,42 @@ int cx18_av_probe(struct cx18 *cx)
|
|||||||
snprintf(sd->name, sizeof(sd->name),
|
snprintf(sd->name, sizeof(sd->name),
|
||||||
"%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
|
"%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
|
||||||
sd->grp_id = CX18_HW_418_AV;
|
sd->grp_id = CX18_HW_418_AV;
|
||||||
|
v4l2_ctrl_handler_init(&state->hdl, 9);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
|
||||||
|
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
|
||||||
|
V4L2_CID_CONTRAST, 0, 127, 1, 64);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
|
||||||
|
V4L2_CID_SATURATION, 0, 127, 1, 64);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
|
||||||
|
V4L2_CID_HUE, -128, 127, 1, 0);
|
||||||
|
|
||||||
|
state->volume = v4l2_ctrl_new_std(&state->hdl,
|
||||||
|
&cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
|
||||||
|
0, 65535, 65535 / 100, 0);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl,
|
||||||
|
&cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
|
||||||
|
0, 1, 1, 0);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
|
||||||
|
V4L2_CID_AUDIO_BALANCE,
|
||||||
|
0, 65535, 65535 / 100, 32768);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
|
||||||
|
V4L2_CID_AUDIO_BASS,
|
||||||
|
0, 65535, 65535 / 100, 32768);
|
||||||
|
v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
|
||||||
|
V4L2_CID_AUDIO_TREBLE,
|
||||||
|
0, 65535, 65535 / 100, 32768);
|
||||||
|
sd->ctrl_handler = &state->hdl;
|
||||||
|
if (state->hdl.error) {
|
||||||
|
int err = state->hdl.error;
|
||||||
|
|
||||||
|
v4l2_ctrl_handler_free(&state->hdl);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
|
err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
|
||||||
if (!err)
|
if (err)
|
||||||
|
v4l2_ctrl_handler_free(&state->hdl);
|
||||||
|
else
|
||||||
cx18_av_init(cx);
|
cx18_av_init(cx);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#define _CX18_AV_CORE_H_
|
#define _CX18_AV_CORE_H_
|
||||||
|
|
||||||
#include <media/v4l2-device.h>
|
#include <media/v4l2-device.h>
|
||||||
|
#include <media/v4l2-ctrls.h>
|
||||||
|
|
||||||
struct cx18;
|
struct cx18;
|
||||||
|
|
||||||
@@ -95,13 +96,14 @@ enum cx18_av_audio_input {
|
|||||||
|
|
||||||
struct cx18_av_state {
|
struct cx18_av_state {
|
||||||
struct v4l2_subdev sd;
|
struct v4l2_subdev sd;
|
||||||
|
struct v4l2_ctrl_handler hdl;
|
||||||
|
struct v4l2_ctrl *volume;
|
||||||
int radio;
|
int radio;
|
||||||
v4l2_std_id std;
|
v4l2_std_id std;
|
||||||
enum cx18_av_video_input vid_input;
|
enum cx18_av_video_input vid_input;
|
||||||
enum cx18_av_audio_input aud_input;
|
enum cx18_av_audio_input aud_input;
|
||||||
u32 audclk_freq;
|
u32 audclk_freq;
|
||||||
int audmode;
|
int audmode;
|
||||||
int default_volume;
|
|
||||||
u32 id;
|
u32 id;
|
||||||
u32 rev;
|
u32 rev;
|
||||||
int is_initialized;
|
int is_initialized;
|
||||||
@@ -347,6 +349,11 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
|
|||||||
return container_of(sd, struct cx18_av_state, sd);
|
return container_of(sd, struct cx18_av_state, sd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* cx18_av-core.c */
|
/* cx18_av-core.c */
|
||||||
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
|
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
|
||||||
@@ -369,10 +376,9 @@ int cx18_av_loadfw(struct cx18 *cx);
|
|||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* cx18_av-audio.c */
|
/* cx18_av-audio.c */
|
||||||
int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
|
|
||||||
int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
|
|
||||||
int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
|
int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
|
||||||
void cx18_av_audio_set_path(struct cx18 *cx);
|
void cx18_av_audio_set_path(struct cx18 *cx);
|
||||||
|
extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops;
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
/* ----------------------------------------------------------------------- */
|
||||||
/* cx18_av-vbi.c */
|
/* cx18_av-vbi.c */
|
||||||
|
@@ -30,152 +30,11 @@
|
|||||||
#include "cx18-mailbox.h"
|
#include "cx18-mailbox.h"
|
||||||
#include "cx18-controls.h"
|
#include "cx18-controls.h"
|
||||||
|
|
||||||
/* Must be sorted from low to high control ID! */
|
static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
|
||||||
static const u32 user_ctrls[] = {
|
|
||||||
V4L2_CID_USER_CLASS,
|
|
||||||
V4L2_CID_BRIGHTNESS,
|
|
||||||
V4L2_CID_CONTRAST,
|
|
||||||
V4L2_CID_SATURATION,
|
|
||||||
V4L2_CID_HUE,
|
|
||||||
V4L2_CID_AUDIO_VOLUME,
|
|
||||||
V4L2_CID_AUDIO_BALANCE,
|
|
||||||
V4L2_CID_AUDIO_BASS,
|
|
||||||
V4L2_CID_AUDIO_TREBLE,
|
|
||||||
V4L2_CID_AUDIO_MUTE,
|
|
||||||
V4L2_CID_AUDIO_LOUDNESS,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u32 *ctrl_classes[] = {
|
|
||||||
user_ctrls,
|
|
||||||
cx2341x_mpeg_ctrls,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
|
|
||||||
{
|
{
|
||||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
|
||||||
const char *name;
|
int type = cxhdl->stream_type->val;
|
||||||
|
|
||||||
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
|
|
||||||
if (qctrl->id == 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
switch (qctrl->id) {
|
|
||||||
/* Standard V4L2 controls */
|
|
||||||
case V4L2_CID_USER_CLASS:
|
|
||||||
return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
|
|
||||||
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
case V4L2_CID_AUDIO_LOUDNESS:
|
|
||||||
if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl))
|
|
||||||
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (cx2341x_ctrl_query(&cx->params, qctrl))
|
|
||||||
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
|
|
||||||
qctrl->name[sizeof(qctrl->name) - 1] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
|
|
||||||
{
|
|
||||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
|
||||||
struct v4l2_queryctrl qctrl;
|
|
||||||
|
|
||||||
qctrl.id = qmenu->id;
|
|
||||||
cx18_queryctrl(file, fh, &qctrl);
|
|
||||||
return v4l2_ctrl_query_menu(qmenu, &qctrl,
|
|
||||||
cx2341x_ctrl_get_menu(&cx->params, qmenu->id));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cx18_try_ctrl(struct file *file, void *fh,
|
|
||||||
struct v4l2_ext_control *vctrl)
|
|
||||||
{
|
|
||||||
struct v4l2_queryctrl qctrl;
|
|
||||||
const char * const *menu_items = NULL;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
qctrl.id = vctrl->id;
|
|
||||||
err = cx18_queryctrl(file, fh, &qctrl);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
if (qctrl.type == V4L2_CTRL_TYPE_MENU)
|
|
||||||
menu_items = v4l2_ctrl_get_menu(qctrl.id);
|
|
||||||
return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
|
||||||
{
|
|
||||||
switch (vctrl->id) {
|
|
||||||
/* Standard V4L2 controls */
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
|
|
||||||
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
case V4L2_CID_AUDIO_LOUDNESS:
|
|
||||||
return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl);
|
|
||||||
|
|
||||||
default:
|
|
||||||
CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
|
|
||||||
{
|
|
||||||
switch (vctrl->id) {
|
|
||||||
/* Standard V4L2 controls */
|
|
||||||
case V4L2_CID_BRIGHTNESS:
|
|
||||||
case V4L2_CID_HUE:
|
|
||||||
case V4L2_CID_SATURATION:
|
|
||||||
case V4L2_CID_CONTRAST:
|
|
||||||
return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
|
|
||||||
|
|
||||||
case V4L2_CID_AUDIO_VOLUME:
|
|
||||||
case V4L2_CID_AUDIO_MUTE:
|
|
||||||
case V4L2_CID_AUDIO_BALANCE:
|
|
||||||
case V4L2_CID_AUDIO_BASS:
|
|
||||||
case V4L2_CID_AUDIO_TREBLE:
|
|
||||||
case V4L2_CID_AUDIO_LOUDNESS:
|
|
||||||
return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl);
|
|
||||||
|
|
||||||
default:
|
|
||||||
CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cx18_setup_vbi_fmt(struct cx18 *cx,
|
|
||||||
enum v4l2_mpeg_stream_vbi_fmt fmt,
|
|
||||||
enum v4l2_mpeg_stream_type type)
|
|
||||||
{
|
|
||||||
if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
|
|
||||||
return -EINVAL;
|
|
||||||
if (atomic_read(&cx->ana_capturing) > 0)
|
if (atomic_read(&cx->ana_capturing) > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
@@ -230,121 +89,43 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
|
||||||
{
|
{
|
||||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
|
||||||
struct v4l2_control ctrl;
|
int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
|
||||||
|
struct v4l2_mbus_framefmt fmt;
|
||||||
|
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
/* fix videodecoder resolution */
|
||||||
int i;
|
fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
|
||||||
int err = 0;
|
fmt.height = cxhdl->height;
|
||||||
|
fmt.code = V4L2_MBUS_FMT_FIXED;
|
||||||
for (i = 0; i < c->count; i++) {
|
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
|
||||||
ctrl.id = c->controls[i].id;
|
return 0;
|
||||||
ctrl.value = c->controls[i].value;
|
|
||||||
err = cx18_g_ctrl(cx, &ctrl);
|
|
||||||
c->controls[i].value = ctrl.value;
|
|
||||||
if (err) {
|
|
||||||
c->error_idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
|
||||||
return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
|
||||||
{
|
{
|
||||||
struct cx18_open_id *id = fh;
|
static const u32 freqs[3] = { 44100, 48000, 32000 };
|
||||||
struct cx18 *cx = id->cx;
|
struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
|
||||||
int ret;
|
|
||||||
struct v4l2_control ctrl;
|
|
||||||
|
|
||||||
ret = v4l2_prio_check(&cx->prio, id->prio);
|
/* The audio clock of the digitizer must match the codec sample
|
||||||
if (ret)
|
rate otherwise you get some very strange effects. */
|
||||||
return ret;
|
if (idx < ARRAY_SIZE(freqs))
|
||||||
|
cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
return 0;
|
||||||
int i;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < c->count; i++) {
|
|
||||||
ctrl.id = c->controls[i].id;
|
|
||||||
ctrl.value = c->controls[i].value;
|
|
||||||
err = cx18_s_ctrl(cx, &ctrl);
|
|
||||||
c->controls[i].value = ctrl.value;
|
|
||||||
if (err) {
|
|
||||||
c->error_idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
|
|
||||||
static u32 freqs[3] = { 44100, 48000, 32000 };
|
|
||||||
struct cx18_api_func_private priv;
|
|
||||||
struct cx2341x_mpeg_params p = cx->params;
|
|
||||||
int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
|
|
||||||
c, VIDIOC_S_EXT_CTRLS);
|
|
||||||
unsigned int idx;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (p.video_encoding != cx->params.video_encoding) {
|
|
||||||
int is_mpeg1 = p.video_encoding ==
|
|
||||||
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
|
|
||||||
struct v4l2_mbus_framefmt fmt;
|
|
||||||
|
|
||||||
/* fix videodecoder resolution */
|
|
||||||
fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1);
|
|
||||||
fmt.height = cx->params.height;
|
|
||||||
fmt.code = V4L2_MBUS_FMT_FIXED;
|
|
||||||
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
|
|
||||||
}
|
|
||||||
priv.cx = cx;
|
|
||||||
priv.s = &cx->streams[id->type];
|
|
||||||
err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
|
|
||||||
if (!err &&
|
|
||||||
(cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
|
|
||||||
cx->params.stream_type != p.stream_type))
|
|
||||||
err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
|
|
||||||
p.stream_type);
|
|
||||||
cx->params = p;
|
|
||||||
cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
|
|
||||||
idx = p.audio_properties & 0x03;
|
|
||||||
/* The audio clock of the digitizer must match the codec sample
|
|
||||||
rate otherwise you get some very strange effects. */
|
|
||||||
if (idx < ARRAY_SIZE(freqs))
|
|
||||||
cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
|
static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
|
||||||
{
|
{
|
||||||
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
|
struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
|
||||||
|
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
|
cx->dualwatch_stereo_mode = val;
|
||||||
int i;
|
return 0;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < c->count; i++) {
|
|
||||||
err = cx18_try_ctrl(file, fh, &c->controls[i]);
|
|
||||||
if (err) {
|
|
||||||
c->error_idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
|
|
||||||
return cx2341x_ext_ctrls(&cx->params,
|
|
||||||
atomic_read(&cx->ana_capturing),
|
|
||||||
c, VIDIOC_TRY_EXT_CTRLS);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cx2341x_handler_ops cx18_cxhdl_ops = {
|
||||||
|
.s_audio_mode = cx18_s_audio_mode,
|
||||||
|
.s_audio_sampling_freq = cx18_s_audio_sampling_freq,
|
||||||
|
.s_video_encoding = cx18_s_video_encoding,
|
||||||
|
.s_stream_vbi_fmt = cx18_s_stream_vbi_fmt,
|
||||||
|
};
|
||||||
|
@@ -21,9 +21,4 @@
|
|||||||
* 02111-1307 USA
|
* 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
|
extern struct cx2341x_handler_ops cx18_cxhdl_ops;
|
||||||
int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
|
|
||||||
int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
|
|
||||||
int cx18_try_ext_ctrls(struct file *file, void *fh,
|
|
||||||
struct v4l2_ext_controls *a);
|
|
||||||
int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
|
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "cx18-scb.h"
|
#include "cx18-scb.h"
|
||||||
#include "cx18-mailbox.h"
|
#include "cx18-mailbox.h"
|
||||||
#include "cx18-ioctl.h"
|
#include "cx18-ioctl.h"
|
||||||
|
#include "cx18-controls.h"
|
||||||
#include "tuner-xc2028.h"
|
#include "tuner-xc2028.h"
|
||||||
|
|
||||||
#include <media/tveeprom.h>
|
#include <media/tveeprom.h>
|
||||||
@@ -729,15 +730,21 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
|
|||||||
cx->open_id = 1;
|
cx->open_id = 1;
|
||||||
|
|
||||||
/* Initial settings */
|
/* Initial settings */
|
||||||
cx2341x_fill_defaults(&cx->params);
|
cx->cxhdl.port = CX2341X_PORT_MEMORY;
|
||||||
cx->temporal_strength = cx->params.video_temporal_filter;
|
cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
|
||||||
cx->spatial_strength = cx->params.video_spatial_filter;
|
cx->cxhdl.ops = &cx18_cxhdl_ops;
|
||||||
cx->filter_mode = cx->params.video_spatial_filter_mode |
|
cx->cxhdl.func = cx18_api_func;
|
||||||
(cx->params.video_temporal_filter_mode << 1) |
|
ret = cx2341x_handler_init(&cx->cxhdl, 50);
|
||||||
(cx->params.video_median_filter_type << 2);
|
if (ret)
|
||||||
cx->params.port = CX2341X_PORT_MEMORY;
|
return ret;
|
||||||
cx->params.capabilities =
|
cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
|
||||||
CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
|
|
||||||
|
cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
|
||||||
|
cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
|
||||||
|
cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
|
||||||
|
(cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
|
||||||
|
(cx->cxhdl.video_median_filter_type->cur.val << 2);
|
||||||
|
|
||||||
init_waitqueue_head(&cx->cap_w);
|
init_waitqueue_head(&cx->cap_w);
|
||||||
init_waitqueue_head(&cx->mb_apu_waitq);
|
init_waitqueue_head(&cx->mb_apu_waitq);
|
||||||
init_waitqueue_head(&cx->mb_cpu_waitq);
|
init_waitqueue_head(&cx->mb_cpu_waitq);
|
||||||
@@ -1049,7 +1056,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
|
|||||||
else
|
else
|
||||||
cx->is_50hz = 1;
|
cx->is_50hz = 1;
|
||||||
|
|
||||||
cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
|
cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
|
||||||
|
|
||||||
if (cx->options.radio > 0)
|
if (cx->options.radio > 0)
|
||||||
cx->v4l2_cap |= V4L2_CAP_RADIO;
|
cx->v4l2_cap |= V4L2_CAP_RADIO;
|
||||||
@@ -1095,7 +1102,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
|
|||||||
|
|
||||||
/* Load cx18 submodules (cx18-alsa) */
|
/* Load cx18 submodules (cx18-alsa) */
|
||||||
request_modules(cx);
|
request_modules(cx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_streams:
|
free_streams:
|
||||||
@@ -1278,6 +1284,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
|
|||||||
for (i = 0; i < CX18_VBI_FRAMES; i++)
|
for (i = 0; i < CX18_VBI_FRAMES; i++)
|
||||||
kfree(cx->vbi.sliced_mpeg_data[i]);
|
kfree(cx->vbi.sliced_mpeg_data[i]);
|
||||||
|
|
||||||
|
v4l2_ctrl_handler_free(&cx->av_state.hdl);
|
||||||
|
|
||||||
CX18_INFO("Removed %s\n", cx->card_name);
|
CX18_INFO("Removed %s\n", cx->card_name);
|
||||||
|
|
||||||
v4l2_device_unregister(v4l2_dev);
|
v4l2_device_unregister(v4l2_dev);
|
||||||
|
@@ -565,7 +565,7 @@ struct cx18 {
|
|||||||
struct cx18_av_state av_state;
|
struct cx18_av_state av_state;
|
||||||
|
|
||||||
/* codec settings */
|
/* codec settings */
|
||||||
struct cx2341x_mpeg_params params;
|
struct cx2341x_handler cxhdl;
|
||||||
u32 filter_mode;
|
u32 filter_mode;
|
||||||
u32 temporal_strength;
|
u32 temporal_strength;
|
||||||
u32 spatial_strength;
|
u32 spatial_strength;
|
||||||
|
@@ -160,13 +160,10 @@ EXPORT_SYMBOL(cx18_release_stream);
|
|||||||
static void cx18_dualwatch(struct cx18 *cx)
|
static void cx18_dualwatch(struct cx18 *cx)
|
||||||
{
|
{
|
||||||
struct v4l2_tuner vt;
|
struct v4l2_tuner vt;
|
||||||
u32 new_bitmap;
|
|
||||||
u32 new_stereo_mode;
|
u32 new_stereo_mode;
|
||||||
const u32 stereo_mask = 0x0300;
|
|
||||||
const u32 dual = 0x0200;
|
const u32 dual = 0x0200;
|
||||||
u32 h;
|
|
||||||
|
|
||||||
new_stereo_mode = cx->params.audio_properties & stereo_mask;
|
new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
|
||||||
memset(&vt, 0, sizeof(vt));
|
memset(&vt, 0, sizeof(vt));
|
||||||
cx18_call_all(cx, tuner, g_tuner, &vt);
|
cx18_call_all(cx, tuner, g_tuner, &vt);
|
||||||
if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
|
if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
|
||||||
@@ -176,25 +173,10 @@ static void cx18_dualwatch(struct cx18 *cx)
|
|||||||
if (new_stereo_mode == cx->dualwatch_stereo_mode)
|
if (new_stereo_mode == cx->dualwatch_stereo_mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
new_bitmap = new_stereo_mode
|
CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
|
||||||
| (cx->params.audio_properties & ~stereo_mask);
|
cx->dualwatch_stereo_mode, new_stereo_mode);
|
||||||
|
if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))
|
||||||
CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
|
CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
|
||||||
"new audio_bitmask=0x%ux\n",
|
|
||||||
cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
|
|
||||||
|
|
||||||
h = cx18_find_handle(cx);
|
|
||||||
if (h == CX18_INVALID_TASK_HANDLE) {
|
|
||||||
CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cx18_vapi(cx,
|
|
||||||
CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
|
|
||||||
cx->dualwatch_stereo_mode = new_stereo_mode;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -724,8 +706,8 @@ int cx18_v4l2_close(struct file *filp)
|
|||||||
if (atomic_read(&cx->ana_capturing) > 0) {
|
if (atomic_read(&cx->ana_capturing) > 0) {
|
||||||
/* Undo video mute */
|
/* Undo video mute */
|
||||||
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
|
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
|
||||||
cx->params.video_mute |
|
(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) |
|
||||||
(cx->params.video_mute_yuv << 8));
|
(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8)));
|
||||||
}
|
}
|
||||||
/* Done! Unmute and continue. */
|
/* Done! Unmute and continue. */
|
||||||
cx18_unmute(cx);
|
cx18_unmute(cx);
|
||||||
|
@@ -152,8 +152,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
|
|||||||
struct cx18 *cx = id->cx;
|
struct cx18 *cx = id->cx;
|
||||||
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
|
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
|
||||||
|
|
||||||
pixfmt->width = cx->params.width;
|
pixfmt->width = cx->cxhdl.width;
|
||||||
pixfmt->height = cx->params.height;
|
pixfmt->height = cx->cxhdl.height;
|
||||||
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||||
pixfmt->field = V4L2_FIELD_INTERLACED;
|
pixfmt->field = V4L2_FIELD_INTERLACED;
|
||||||
pixfmt->priv = 0;
|
pixfmt->priv = 0;
|
||||||
@@ -287,14 +287,14 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
|
|||||||
w = fmt->fmt.pix.width;
|
w = fmt->fmt.pix.width;
|
||||||
h = fmt->fmt.pix.height;
|
h = fmt->fmt.pix.height;
|
||||||
|
|
||||||
if (cx->params.width == w && cx->params.height == h)
|
if (cx->cxhdl.width == w && cx->cxhdl.height == h)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (atomic_read(&cx->ana_capturing) > 0)
|
if (atomic_read(&cx->ana_capturing) > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
mbus_fmt.width = cx->params.width = w;
|
mbus_fmt.width = cx->cxhdl.width = w;
|
||||||
mbus_fmt.height = cx->params.height = h;
|
mbus_fmt.height = cx->cxhdl.height = h;
|
||||||
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
|
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
|
||||||
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
|
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
|
||||||
return cx18_g_fmt_vid_cap(file, fh, fmt);
|
return cx18_g_fmt_vid_cap(file, fh, fmt);
|
||||||
@@ -696,9 +696,10 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
|
|||||||
|
|
||||||
cx->std = *std;
|
cx->std = *std;
|
||||||
cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
|
cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
|
||||||
cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
|
cx->is_50hz = !cx->is_60hz;
|
||||||
cx->params.width = 720;
|
cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
|
||||||
cx->params.height = cx->is_50hz ? 576 : 480;
|
cx->cxhdl.width = 720;
|
||||||
|
cx->cxhdl.height = cx->is_50hz ? 576 : 480;
|
||||||
cx->vbi.count = cx->is_50hz ? 18 : 12;
|
cx->vbi.count = cx->is_50hz ? 18 : 12;
|
||||||
cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
|
cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
|
||||||
cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
|
cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
|
||||||
@@ -1035,7 +1036,7 @@ static int cx18_log_status(struct file *file, void *fh)
|
|||||||
mutex_unlock(&cx->gpio_lock);
|
mutex_unlock(&cx->gpio_lock);
|
||||||
CX18_INFO("Tuner: %s\n",
|
CX18_INFO("Tuner: %s\n",
|
||||||
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
|
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV");
|
||||||
cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
|
v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
|
||||||
CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
|
CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
|
||||||
for (i = 0; i < CX18_MAX_STREAMS; i++) {
|
for (i = 0; i < CX18_MAX_STREAMS; i++) {
|
||||||
struct cx18_stream *s = &cx->streams[i];
|
struct cx18_stream *s = &cx->streams[i];
|
||||||
@@ -1136,11 +1137,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
|
|||||||
.vidioc_s_register = cx18_s_register,
|
.vidioc_s_register = cx18_s_register,
|
||||||
#endif
|
#endif
|
||||||
.vidioc_default = cx18_default,
|
.vidioc_default = cx18_default,
|
||||||
.vidioc_queryctrl = cx18_queryctrl,
|
|
||||||
.vidioc_querymenu = cx18_querymenu,
|
|
||||||
.vidioc_g_ext_ctrls = cx18_g_ext_ctrls,
|
|
||||||
.vidioc_s_ext_ctrls = cx18_s_ext_ctrls,
|
|
||||||
.vidioc_try_ext_ctrls = cx18_try_ext_ctrls,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void cx18_set_funcs(struct video_device *vdev)
|
void cx18_set_funcs(struct video_device *vdev)
|
||||||
|
@@ -716,9 +716,8 @@ static int cx18_set_filter_param(struct cx18_stream *s)
|
|||||||
int cx18_api_func(void *priv, u32 cmd, int in, int out,
|
int cx18_api_func(void *priv, u32 cmd, int in, int out,
|
||||||
u32 data[CX2341X_MBOX_MAX_DATA])
|
u32 data[CX2341X_MBOX_MAX_DATA])
|
||||||
{
|
{
|
||||||
struct cx18_api_func_private *api_priv = priv;
|
struct cx18_stream *s = priv;
|
||||||
struct cx18 *cx = api_priv->cx;
|
struct cx18 *cx = s->cx;
|
||||||
struct cx18_stream *s = api_priv->s;
|
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case CX2341X_ENC_SET_OUTPUT_PORT:
|
case CX2341X_ENC_SET_OUTPUT_PORT:
|
||||||
|
@@ -81,11 +81,6 @@ struct cx18_mailbox {
|
|||||||
|
|
||||||
struct cx18_stream;
|
struct cx18_stream;
|
||||||
|
|
||||||
struct cx18_api_func_private {
|
|
||||||
struct cx18 *cx;
|
|
||||||
struct cx18_stream *s;
|
|
||||||
};
|
|
||||||
|
|
||||||
int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
|
int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
|
||||||
int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
|
int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
|
||||||
int args, ...);
|
int args, ...);
|
||||||
|
@@ -572,7 +572,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
|
|||||||
* Set the MDL size to the exact size needed for one frame.
|
* Set the MDL size to the exact size needed for one frame.
|
||||||
* Use enough buffers per MDL to cover the MDL size
|
* Use enough buffers per MDL to cover the MDL size
|
||||||
*/
|
*/
|
||||||
s->mdl_size = 720 * s->cx->params.height * 3 / 2;
|
s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
|
||||||
s->bufs_per_mdl = s->mdl_size / s->buf_size;
|
s->bufs_per_mdl = s->mdl_size / s->buf_size;
|
||||||
if (s->mdl_size % s->buf_size)
|
if (s->mdl_size % s->buf_size)
|
||||||
s->bufs_per_mdl++;
|
s->bufs_per_mdl++;
|
||||||
@@ -607,7 +607,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
|
|||||||
u32 data[MAX_MB_ARGUMENTS];
|
u32 data[MAX_MB_ARGUMENTS];
|
||||||
struct cx18 *cx = s->cx;
|
struct cx18 *cx = s->cx;
|
||||||
int captype = 0;
|
int captype = 0;
|
||||||
struct cx18_api_func_private priv;
|
|
||||||
struct cx18_stream *s_idx;
|
struct cx18_stream *s_idx;
|
||||||
|
|
||||||
if (!cx18_stream_enabled(s))
|
if (!cx18_stream_enabled(s))
|
||||||
@@ -620,7 +619,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
|
|||||||
captype = CAPTURE_CHANNEL_TYPE_MPEG;
|
captype = CAPTURE_CHANNEL_TYPE_MPEG;
|
||||||
cx->mpg_data_received = cx->vbi_data_inserted = 0;
|
cx->mpg_data_received = cx->vbi_data_inserted = 0;
|
||||||
cx->dualwatch_jiffies = jiffies;
|
cx->dualwatch_jiffies = jiffies;
|
||||||
cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
|
cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
|
||||||
cx->search_pack_header = 0;
|
cx->search_pack_header = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -710,21 +709,21 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
|
|||||||
s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
|
s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
|
||||||
|
|
||||||
/* Call out to the common CX2341x API setup for user controls */
|
/* Call out to the common CX2341x API setup for user controls */
|
||||||
priv.cx = cx;
|
cx->cxhdl.priv = s;
|
||||||
priv.s = s;
|
cx2341x_handler_setup(&cx->cxhdl);
|
||||||
cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When starting a capture and we're set for radio,
|
* When starting a capture and we're set for radio,
|
||||||
* ensure the video is muted, despite the user control.
|
* ensure the video is muted, despite the user control.
|
||||||
*/
|
*/
|
||||||
if (!cx->params.video_mute &&
|
if (!cx->cxhdl.video_mute &&
|
||||||
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
|
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
|
||||||
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
|
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
|
||||||
(cx->params.video_mute_yuv << 8) | 1);
|
(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atomic_read(&cx->tot_capturing) == 0) {
|
if (atomic_read(&cx->tot_capturing) == 0) {
|
||||||
|
cx2341x_handler_set_busy(&cx->cxhdl, 1);
|
||||||
clear_bit(CX18_F_I_EOS, &cx->i_flags);
|
clear_bit(CX18_F_I_EOS, &cx->i_flags);
|
||||||
cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
|
cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
|
||||||
}
|
}
|
||||||
@@ -826,6 +825,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
|
|||||||
if (atomic_read(&cx->tot_capturing) > 0)
|
if (atomic_read(&cx->tot_capturing) > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
cx2341x_handler_set_busy(&cx->cxhdl, 0);
|
||||||
cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
|
cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
|
||||||
wake_up(&s->waitq);
|
wake_up(&s->waitq);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user