From 24dc2f33e9336e9e01da8321352fb93173454e88 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 24 Nov 2008 22:16:46 +0100 Subject: msp3400: convert to v4l2_subdev. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/msp3400-driver.c | 406 ++++++++++++++++------------- 1 file changed, 225 insertions(+), 181 deletions(-) (limited to 'linux/drivers/media/video/msp3400-driver.c') diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index c6c0a584c..def15e381 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -51,18 +51,18 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) #include #else #include #endif +#include +#include +#include +#include +#include +#include #include "compat.h" #include "msp3400-driver.h" @@ -270,7 +270,7 @@ static char *scart_names[] = { void msp_set_scart(struct i2c_client *client, int in, int out) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = to_state(i2c_get_clientdata(client)); state->in_scart = in; @@ -294,7 +294,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) void msp_set_audio(struct i2c_client *client) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = to_state(i2c_get_clientdata(client)); int bal = 0, bass, treble, loudness; int val = 0; int reallymuted = state->muted | state->scan_in_progress; @@ -341,7 +341,7 @@ void msp_set_audio(struct i2c_client *client) static void msp_wake_thread(struct i2c_client *client) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = to_state(i2c_get_clientdata(client)); if (NULL == state->kthread) return; @@ -395,9 +395,9 @@ static int msp_mode_v4l1_to_v4l2(int mode) } #endif -static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = to_state(sd); switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: @@ -438,9 +438,10 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) return 0; } -static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: @@ -486,40 +487,16 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) return 0; } -static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) +#ifdef CONFIG_VIDEO_ALLOW_V4L1 +static int msp_ioctl(struct v4l2_subdev *sd, int cmd, void *arg) { - struct msp_state *state = i2c_get_clientdata(client); - - if (msp_debug >= 2) - v4l_i2c_print_ioctl(client, cmd); + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); switch (cmd) { - case AUDC_SET_RADIO: - if (state->radio) - return 0; - state->radio = 1; - v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); - state->watch_stereo = 0; - switch (state->opmode) { - case OPMODE_MANUAL: - /* set msp3400 to FM radio mode */ - msp3400c_set_mode(client, MSP_MODE_FM_RADIO); - msp3400c_set_carrier(client, MSP_CARRIER(10.7), - MSP_CARRIER(10.7)); - msp_set_audio(client); - break; - case OPMODE_AUTODETECT: - case OPMODE_AUTOSELECT: - /* the thread will do for us */ - msp_wake_thread(client); - break; - } - break; - /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ -#ifdef CONFIG_VIDEO_ALLOW_V4L1 case VIDIOCGAUDIO: { struct video_audio *va = arg; @@ -593,105 +570,137 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp_wake_thread(client); break; } -#endif - case VIDIOC_S_FREQUENCY: - { - /* new channel -- kick audio carrier scan */ - msp_wake_thread(client); - break; + default: + return -ENOIOCTLCMD; } + return 0; +} +#endif - /* --- v4l2 ioctls --- */ - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - int update = state->radio || state->v4l2_std != *id; +/* --- v4l2 ioctls --- */ +static int msp_s_radio(struct v4l2_subdev *sd) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - state->v4l2_std = *id; - state->radio = 0; - if (update) - msp_wake_thread(client); + if (state->radio) return 0; + state->radio = 1; + v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); + state->watch_stereo = 0; + switch (state->opmode) { + case OPMODE_MANUAL: + /* set msp3400 to FM radio mode */ + msp3400c_set_mode(client, MSP_MODE_FM_RADIO); + msp3400c_set_carrier(client, MSP_CARRIER(10.7), + MSP_CARRIER(10.7)); + msp_set_audio(client); + break; + case OPMODE_AUTODETECT: + case OPMODE_AUTOSELECT: + /* the thread will do for us */ + msp_wake_thread(client); + break; } + return 0; +} - case VIDIOC_INT_G_AUDIO_ROUTING: - { - struct v4l2_routing *rt = arg; +static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); - *rt = state->routing; - break; - } + /* new channel -- kick audio carrier scan */ + msp_wake_thread(client); + return 0; +} - case VIDIOC_INT_S_AUDIO_ROUTING: - { - struct v4l2_routing *rt = arg; - int tuner = (rt->input >> 3) & 1; - int sc_in = rt->input & 0x7; - int sc1_out = rt->output & 0xf; - int sc2_out = (rt->output >> 4) & 0xf; - u16 val, reg; - int i; - int extern_input = 1; - - if (state->routing.input == rt->input && - state->routing.output == rt->output) - break; - state->routing = *rt; - /* check if the tuner input is used */ - for (i = 0; i < 5; i++) { - if (((rt->input >> (4 + i * 4)) & 0xf) == 0) - extern_input = 0; - } - state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - msp_set_scart(client, sc_in, 0); - msp_set_scart(client, sc1_out, 1); - msp_set_scart(client, sc2_out, 2); - msp_set_audmode(client); - reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; - val = msp_read_dem(client, reg); - msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); - /* wake thread when a new input is chosen */ +static int msp_s_std(struct v4l2_subdev *sd, v4l2_std_id id) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int update = state->radio || state->v4l2_std != id; + + state->v4l2_std = id; + state->radio = 0; + if (update) msp_wake_thread(client); - break; + return 0; +} + +static int msp_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int tuner = (rt->input >> 3) & 1; + int sc_in = rt->input & 0x7; + int sc1_out = rt->output & 0xf; + int sc2_out = (rt->output >> 4) & 0xf; + u16 val, reg; + int i; + int extern_input = 1; + + if (state->routing.input == rt->input && + state->routing.output == rt->output) + return 0; + state->routing = *rt; + /* check if the tuner input is used */ + for (i = 0; i < 5; i++) { + if (((rt->input >> (4 + i * 4)) & 0xf) == 0) + extern_input = 0; } + state->mode = extern_input ? MSP_MODE_EXTERN : MSP_MODE_AM_DETECT; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; + msp_set_scart(client, sc_in, 0); + msp_set_scart(client, sc1_out, 1); + msp_set_scart(client, sc2_out, 2); + msp_set_audmode(client); + reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; + val = msp_read_dem(client, reg); + msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); + /* wake thread when a new input is chosen */ + msp_wake_thread(client); + return 0; +} - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *vt = arg; +static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (state->radio) - break; - if (state->opmode == OPMODE_AUTOSELECT) - msp_detect_stereo(client); - vt->audmode = state->audmode; - vt->rxsubchans = state->rxsubchans; - vt->capability |= V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - break; - } + if (state->radio) + return 0; + if (state->opmode == OPMODE_AUTOSELECT) + msp_detect_stereo(client); + vt->audmode = state->audmode; + vt->rxsubchans = state->rxsubchans; + vt->capability |= V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + return 0; +} - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; +static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (state->radio) /* TODO: add mono/stereo support for radio */ - break; - if (state->audmode == vt->audmode) - break; - state->audmode = vt->audmode; - /* only set audmode */ - msp_set_audmode(client); - break; - } + if (state->radio) /* TODO: add mono/stereo support for radio */ + return 0; + if (state->audmode == vt->audmode) + return 0; + state->audmode = vt->audmode; + /* only set audmode */ + msp_set_audmode(client); + return 0; +} - case VIDIOC_INT_I2S_CLOCK_FREQ: - { - u32 *a = (u32 *)arg; +static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a); + v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); - switch (*a) { + switch (freq) { case 1024000: state->i2s_mode = 0; break; @@ -700,24 +709,24 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; default: return -EINVAL; - } - break; } + return 0; +} - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; +static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +{ + struct msp_state *state = to_state(sd); - switch (qc->id) { + switch (qc->id) { case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_MUTE: return v4l2_ctrl_query_fill_std(qc); default: break; - } - if (!state->has_sound_processing) - return -EINVAL; - switch (qc->id) { + } + if (!state->has_sound_processing) + return -EINVAL; + switch (qc->id) { case V4L2_CID_AUDIO_LOUDNESS: case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: @@ -725,32 +734,38 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return v4l2_ctrl_query_fill_std(qc); default: return -EINVAL; - } } + return 0; +} - case VIDIOC_G_CTRL: - return msp_get_ctrl(client, arg); - - case VIDIOC_S_CTRL: - return msp_set_ctrl(client, arg); +static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - case VIDIOC_LOG_STATUS: - { - const char *p; + return v4l2_chip_ident_i2c_client(client, chip, state->ident, + (state->rev1 << 16) | state->rev2); +} - if (state->opmode == OPMODE_AUTOSELECT) - msp_detect_stereo(client); - v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", - client->name, state->rev1, state->rev2); - v4l_info(client, "Audio: volume %d%s\n", - state->volume, state->muted ? " (muted)" : ""); - if (state->has_sound_processing) { - v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", - state->balance, state->bass, - state->treble, - state->loudness ? "on" : "off"); - } - switch (state->mode) { +static int msp_log_status(struct v4l2_subdev *sd) +{ + struct msp_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + const char *p; + + if (state->opmode == OPMODE_AUTOSELECT) + msp_detect_stereo(client); + v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", + client->name, state->rev1, state->rev2); + v4l_info(client, "Audio: volume %d%s\n", + state->volume, state->muted ? " (muted)" : ""); + if (state->has_sound_processing) { + v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", + state->balance, state->bass, + state->treble, + state->loudness ? "on" : "off"); + } + switch (state->mode) { case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; case MSP_MODE_FM_RADIO: p = "FM Radio"; break; case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; @@ -761,36 +776,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case MSP_MODE_BTSC: p = "BTSC"; break; case MSP_MODE_EXTERN: p = "External input"; break; default: p = "unknown"; break; - } - if (state->mode == MSP_MODE_EXTERN) { - v4l_info(client, "Mode: %s\n", p); - } else if (state->opmode == OPMODE_MANUAL) { - v4l_info(client, "Mode: %s (%s%s)\n", p, + } + if (state->mode == MSP_MODE_EXTERN) { + v4l_info(client, "Mode: %s\n", p); + } else if (state->opmode == OPMODE_MANUAL) { + v4l_info(client, "Mode: %s (%s%s)\n", p, (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - } else { - if (state->opmode == OPMODE_AUTODETECT) - v4l_info(client, "Mode: %s\n", p); - v4l_info(client, "Standard: %s (%s%s)\n", + } else { + if (state->opmode == OPMODE_AUTODETECT) + v4l_info(client, "Mode: %s\n", p); + v4l_info(client, "Standard: %s (%s%s)\n", msp_standard_std_name(state->std), (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - } - v4l_info(client, "Audmode: 0x%04x\n", state->audmode); - v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", - state->routing.input, state->routing.output); - v4l_info(client, "ACB: 0x%04x\n", state->acb); - break; - } - - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, - (state->rev1 << 16) | state->rev2); - - default: - /* unknown */ - return -EINVAL; } + v4l_info(client, "Audmode: 0x%04x\n", state->audmode); + v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", + state->routing.input, state->routing.output); + v4l_info(client, "ACB: 0x%04x\n", state->acb); return 0; } @@ -808,11 +812,49 @@ static int msp_resume(struct i2c_client *client) return 0; } +static int msp_command(struct i2c_client *client, unsigned cmd, void *arg) +{ + return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops msp_core_ops = { + .log_status = msp_log_status, + .g_chip_ident = msp_g_chip_ident, + .g_ctrl = msp_g_ctrl, + .s_ctrl = msp_s_ctrl, + .queryctrl = msp_queryctrl, +#ifdef CONFIG_VIDEO_ALLOW_V4L1 + .ioctl = msp_ioctl, +#endif +}; + +static const struct v4l2_subdev_tuner_ops msp_tuner_ops = { + .s_frequency = msp_s_frequency, + .g_tuner = msp_g_tuner, + .s_tuner = msp_s_tuner, + .s_radio = msp_s_radio, + .s_std = msp_s_std, +}; + +static const struct v4l2_subdev_audio_ops msp_audio_ops = { + .s_routing = msp_s_routing, + .s_i2s_clock_freq = msp_s_i2s_clock_freq, +}; + +static const struct v4l2_subdev_ops msp_ops = { + .core = &msp_core_ops, + .tuner = &msp_tuner_ops, + .audio = &msp_audio_ops, +}; + /* ----------------------------------------------------------------------- */ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct msp_state *state; + struct v4l2_subdev *sd; int (*thread_func)(void *data) = NULL; int msp_hard; int msp_family; @@ -836,7 +878,8 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) if (!state) return -ENOMEM; - i2c_set_clientdata(client, state); + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &msp_ops); state->v4l2_std = V4L2_STD_NTSC; state->audmode = V4L2_TUNER_MODE_STEREO; @@ -990,8 +1033,9 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) static int msp_remove(struct i2c_client *client) { - struct msp_state *state = i2c_get_clientdata(client); + struct msp_state *state = to_state(i2c_get_clientdata(client)); + v4l2_device_unregister_subdev(&state->sd); /* shutdown control thread */ if (state->kthread) { state->restart = 1; -- cgit v1.2.3 From 3fa4127b747284ddb0986e285315094ffb1362c5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 18 Dec 2008 16:27:28 +0100 Subject: v4l2-subdev: ioctl ops should use unsigned for cmd arg. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/msp3400-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/msp3400-driver.c') diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index def15e381..9d2c98b82 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -488,7 +488,7 @@ static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } #ifdef CONFIG_VIDEO_ALLOW_V4L1 -static int msp_ioctl(struct v4l2_subdev *sd, int cmd, void *arg) +static int msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); -- cgit v1.2.3 From 3e6b888d8b2f7a4ebef1b4c33acb0d253488ea4a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Dec 2008 11:04:34 +0100 Subject: v4l2-ioctl: change to long return type to match unlocked_ioctl. From: Hans Verkuil Since internal to v4l2 the ioctl prototype is the same regardless of it being called through .ioctl or .unlocked_ioctl, we need to convert it all to the long return type of unlocked_ioctl. Thanks to Jean-Francois Moine for posting an initial patch for this and thus bringing it to our attention. Priority: normal Signed-off-by: Hans Verkuil CC: Jean-Francois Moine --- linux/drivers/media/video/msp3400-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/msp3400-driver.c') diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index 9d2c98b82..d59f7a537 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -488,7 +488,7 @@ static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } #ifdef CONFIG_VIDEO_ALLOW_V4L1 -static int msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +static long msp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); -- cgit v1.2.3 From 1b466c7ec5d6b66905c47c49fd3cbc59569e7b4e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 30 Dec 2008 11:14:19 +0100 Subject: v4l2: debugging API changed to match against driver name instead of ID. From: Hans Verkuil Since the i2c driver ID will be removed in the near future we have to modify the v4l2 debugging API to use the driver name instead of driver ID. Note that this API is not used in applications other than v4l2-dbg.cpp as it is for debugging and testing only. Should anyone use the old VIDIOC_G_CHIP_IDENT, then this will be logged with a warning that it is deprecated and will be removed in 2.6.30. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/msp3400-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux/drivers/media/video/msp3400-driver.c') diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index d59f7a537..053f168bf 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -738,7 +738,7 @@ static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) return 0; } -static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_chip_ident *chip) +static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); -- cgit v1.2.3