From 5af0c8f6a09534ebc6c56b4e5d79d0d521364750 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 9 Jan 2006 18:21:37 -0200 Subject: V4L/DVB (3326): Fix stereo and standard reporting of msp3400 (esp. for radio) - Add VIDIOC_LOG_STATUS to the radio device ioctl list. - Reduce the confusion between modes and standards - Fix stereo reporting for radio. - Don't set i2c configuration if the chip doesn't support it. - Fix reporting of current standard for radio. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bttv-driver.c | 1 + drivers/media/video/msp3400-driver.c | 62 ++++++++++++++++++++++++------- drivers/media/video/msp3400-kthreads.c | 68 ++++++++++++++++++---------------- drivers/media/video/msp3400.h | 28 +++++++------- 4 files changed, 100 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index f3de852517191d..0e697034678806 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -3220,6 +3220,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, case VIDIOCSFREQ: case VIDIOCGAUDIO: case VIDIOCSAUDIO: + case VIDIOC_LOG_STATUS: return bttv_common_ioctls(btv,cmd,arg); default: diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 04a05d7dd470b8..aa8c556b6ba1f2 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -345,7 +345,7 @@ int msp_modus(struct i2c_client *client) return 0x0003; } - if (state->std & V4L2_STD_PAL) { + if (state->v4l2_std & V4L2_STD_PAL) { v4l_dbg(1, client, "video mode selected to PAL\n"); #if 1 @@ -356,11 +356,11 @@ int msp_modus(struct i2c_client *client) return 0x1003; #endif } - if (state->std & V4L2_STD_NTSC) { + if (state->v4l2_std & V4L2_STD_NTSC) { v4l_dbg(1, client, "video mode selected to NTSC\n"); return 0x2003; } - if (state->std & V4L2_STD_SECAM) { + if (state->v4l2_std & V4L2_STD_SECAM) { v4l_dbg(1, client, "video mode selected to SECAM\n"); return 0x0003; } @@ -663,6 +663,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; case AUDC_SET_RADIO: + if (state->radio) + return 0; state->radio = 1; v4l_dbg(1, client, "switching to radio mode\n"); state->watch_stereo = 0; @@ -701,6 +703,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) va->bass = state->bass; va->treble = state->treble; + if (state->radio) + break; if (state->opmode == OPMODE_AUTOSELECT) msp_any_detect_stereo(client); va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans); @@ -738,8 +742,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) std = V4L2_STD_SECAM; else std = V4L2_STD_NTSC; - if (std != state->std) { - state->std = std; + if (std != state->v4l2_std) { + state->v4l2_std = std; update = 1; } if (update) @@ -768,9 +772,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_S_STD: { v4l2_std_id *id = arg; - int update = state->radio || state->std != *id; + int update = state->radio || state->v4l2_std != *id; - state->std = *id; + state->v4l2_std = *id; state->radio = 0; if (update) msp_wake_thread(client); @@ -879,6 +883,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_tuner *vt = arg; + if (state->radio) + break; if (state->opmode == OPMODE_AUTOSELECT) msp_any_detect_stereo(client); vt->audmode = state->audmode; @@ -892,6 +898,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; + if (state->radio) + break; /* only set audmode */ if (vt->audmode != -1 && vt->audmode != 0) msp_any_set_audmode(client, vt->audmode); @@ -981,22 +989,46 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return msp_set_ctrl(client, arg); case VIDIOC_LOG_STATUS: + { + const char *p; + if (state->opmode == OPMODE_AUTOSELECT) msp_any_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", + 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", + v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", state->balance, state->bass, state->treble, state->loudness ? "on" : "off"); } - v4l_info(client, "Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), - (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", - (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); - v4l_info(client, "ACB: 0x%04x\n", state->acb); + 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 + FM-stereo"; break; + case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; + case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; + case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; + case MSP_MODE_AM_NICAM: p = "NICAM/AM (L)"; break; + case MSP_MODE_BTSC: p = "BTSC"; break; + case MSP_MODE_EXTERN: p = "External input"; break; + default: p = "unknown"; break; + } + 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 { + 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, "ACB: 0x%04x\n", state->acb); break; + } default: /* nothing */ @@ -1061,7 +1093,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) i2c_set_clientdata(client, state); memset(state, 0, sizeof(*state)); - state->std = V4L2_STD_NTSC; + state->v4l2_std = V4L2_STD_NTSC; state->volume = 58880; /* 0db gain */ state->balance = 32768; /* 0db gain */ state->bass = 32768; @@ -1109,6 +1141,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5; /* Has scart2 a volume control? Not in pre-D revisions. */ state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart23_in_scart2_out; + /* Has a configurable i2s out? */ + state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7; /* Has subwoofer output: not in pre-D revs and not in stripped down products */ state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5; /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 14a425a6ff8590..2b59b6847535af 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -37,7 +37,7 @@ static struct { int retval; int main, second; char *name; -} msp_modelist[] = { +} msp_stdlist[] = { { 0x0000, 0, 0, "could not detect sound standard" }, { 0x0001, 0, 0, "autodetect start" }, { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, @@ -144,13 +144,13 @@ static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { /* ------------------------------------------------------------------------ */ -const char *msp_standard_mode_name(int mode) +const char *msp_standard_std_name(int std) { int i; - for (i = 0; msp_modelist[i].name != NULL; i++) - if (msp_modelist[i].retval == mode) - return msp_modelist[i].name; + for (i = 0; msp_stdlist[i].name != NULL; i++) + if (msp_stdlist[i].retval == std) + return msp_stdlist[i].name; return "unknown"; } @@ -498,7 +498,7 @@ int msp3400c_thread(void *data) cd = msp3400c_carrier_detect_main; count = ARRAY_SIZE(msp3400c_carrier_detect_main); - if (amsound && (state->std & V4L2_STD_SECAM)) { + if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) { /* autodetect doesn't work well with AM ... */ max1 = 3; count = 0; @@ -535,7 +535,7 @@ int msp3400c_thread(void *data) break; } - if (amsound && (state->std & V4L2_STD_SECAM)) { + if (amsound && (state->v4l2_std & V4L2_STD_SECAM)) { /* autodetect doesn't work well with AM ... */ cd = NULL; count = 0; @@ -591,7 +591,7 @@ int msp3400c_thread(void *data) state->nicam_on = 0; msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); state->watch_stereo = 1; - } else if (max2 == 0 && (state->std & V4L2_STD_SECAM)) { + } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { /* L NICAM or AM-mono */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_setmode(client, MSP_MODE_AM_NICAM); @@ -676,22 +676,22 @@ int msp3410d_thread(void *data) goto restart; /* start autodetect */ - std = 1; - if (state->std & V4L2_STD_NTSC) - std = 0x20; + if (state->radio) + std = 0x40; else - msp_write_dem(client, 0x20, std); + std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; state->watch_stereo = 0; if (debug) - v4l_dbg(1, client, "setting mode: %s (0x%04x)\n", - msp_standard_mode_name(std), std); + v4l_dbg(1, client, "setting standard: %s (0x%04x)\n", + msp_standard_std_name(std), std); if (std != 1) { /* programmed some specific mode */ val = std; } else { /* triggered autodetect */ + msp_write_dem(client, 0x20, std); for (;;) { if (msp_sleep(state, 100)) goto restart; @@ -703,19 +703,21 @@ int msp3410d_thread(void *data) v4l_dbg(1, client, "detection still in progress\n"); } } - for (i = 0; msp_modelist[i].name != NULL; i++) - if (msp_modelist[i].retval == val) + for (i = 0; msp_stdlist[i].name != NULL; i++) + if (msp_stdlist[i].retval == val) break; - v4l_dbg(1, client, "current mode: %s (0x%04x)\n", - msp_standard_mode_name(val), val); - state->main = msp_modelist[i].main; - state->second = msp_modelist[i].second; - - if (amsound && (state->std & V4L2_STD_SECAM) && (val != 0x0009)) { + v4l_dbg(1, client, "current standard: %s (0x%04x)\n", + msp_standard_std_name(val), val); + state->main = msp_stdlist[i].main; + state->second = msp_stdlist[i].second; + state->std = val; + + if (amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && + (val != 0x0009)) { /* autodetection has failed, let backup */ v4l_dbg(1, client, "autodetection failed," - " switching to backup mode: %s (0x%04x)\n", - msp_modelist[8].name ? msp_modelist[8].name : "unknown",val); + " switching to backup standard: %s (0x%04x)\n", + msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); val = 0x0009; msp_write_dem(client, 0x20, val); } @@ -762,7 +764,7 @@ int msp3410d_thread(void *data) state->watch_stereo = 0; /* not needed in theory if we have radio, but short programming enables carrier mute */ - msp3400c_setmode(client,MSP_MODE_FM_RADIO); + msp3400c_setmode(client, MSP_MODE_FM_RADIO); msp3400c_setcarrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); /* scart routing */ @@ -775,7 +777,7 @@ int msp3410d_thread(void *data) case 0x0003: case 0x0004: case 0x0005: - state->mode = MSP_MODE_FM_TERRA; + state->mode = MSP_MODE_FM_TERRA; state->rxsubchans = V4L2_TUNER_SUB_MONO; state->audmode = V4L2_TUNER_MODE_MONO; state->nicam_on = 0; @@ -786,7 +788,8 @@ int msp3410d_thread(void *data) /* unmute, restore misc registers */ msp_set_audio(client); msp_write_dsp(client, 0x13, state->acb); - msp_write_dem(client, 0x40, state->i2s_mode); + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); /* monitor tv audio mode */ while (state->watch_stereo) { @@ -857,14 +860,15 @@ static int msp34xxg_reset(struct i2c_client *client) if (msp_write_dsp(client, 0x13, 0x0f20)) return -1; - msp_write_dem(client, 0x40, state->i2s_mode); + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); /* step-by-step initialisation, as described in the manual */ modus = msp_modus(client); if (state->radio) std = 0x40; else - std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1; + std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; modus &= ~0x03; /* STATUS_CHANGE = 0 */ modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ if (msp_write_dem(client, 0x30, modus)) @@ -933,9 +937,9 @@ int msp34xxg_thread(void *data) } unmute: - state->mode = std; - v4l_dbg(1, client, "current mode: %s (0x%04x)\n", - msp_standard_mode_name(std), std); + state->std = std; + v4l_dbg(1, client, "current standard: %s (0x%04x)\n", + msp_standard_std_name(std), std); /* unmute: dispatch sound to scart output, set scart volume */ msp_set_audio(client); diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index fb44eef5d513d8..8a05cf500a8cf8 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -57,22 +57,24 @@ extern int stereo_threshold; struct msp_state { int rev1, rev2; - int has_nicam; - int has_radio; - int has_headphones; - int has_ntsc_jp_d_k3; - int has_scart4; - int has_scart23_in_scart2_out; - int has_scart2_out_volume; - int has_subwoofer; - int has_sound_processing; - int has_virtual_dolby_surround; - int has_dolby_pro_logic; + u8 has_nicam; + u8 has_radio; + u8 has_headphones; + u8 has_ntsc_jp_d_k3; + u8 has_scart4; + u8 has_scart23_in_scart2_out; + u8 has_scart2_out_volume; + u8 has_i2s_conf; + u8 has_subwoofer; + u8 has_sound_processing; + u8 has_virtual_dolby_surround; + u8 has_dolby_pro_logic; int radio; int opmode; + int std; int mode; - v4l2_std_id std; + v4l2_std_id v4l2_std; int nicam_on; int acb; int in_scart; @@ -109,7 +111,7 @@ int msp_modus(struct i2c_client *client); int msp_sleep(struct msp_state *state, int timeout); /* msp3400-kthreads.c */ -const char *msp_standard_mode_name(int mode); +const char *msp_standard_std_name(int std); void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2); void msp3400c_setmode(struct i2c_client *client, int type); void msp3400c_setstereo(struct i2c_client *client, int mode); -- cgit 1.2.3-korg