aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@suse.cz>2005-01-04 10:28:18 +0100
committerJaroslav Kysela <perex@suse.cz>2005-01-04 10:28:18 +0100
commit1abef0c047ed200a5880f33a6ed0fcc8bae28bd9 (patch)
tree1c441901e52d64924397ded0161ff12432e35b51 /sound
parentbeed13f3cb5934f6558826e44f39d25dc9afa16f (diff)
downloadhistory-1abef0c047ed200a5880f33a6ed0fcc8bae28bd9.tar.gz
[ALSA] Clean up and fix stereo mutes
AC97 Codec Core Clean up the build of controls. The volume resolution detection is unified. Fixed minor bugs to handle stereo mutes. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/ac97/ac97_codec.c220
1 files changed, 86 insertions, 134 deletions
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index b0aa9ce794c5c4..c86d4c91c76184 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -656,16 +656,9 @@ AC97_SINGLE("PC Speaker Playback Switch", AC97_PC_BEEP, 15, 1, 1),
AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1)
};
-static const snd_kcontrol_new_t snd_ac97_controls_phone[2] = {
-AC97_SINGLE("Phone Playback Switch", AC97_PHONE, 15, 1, 1),
-AC97_SINGLE("Phone Playback Volume", AC97_PHONE, 0, 15, 1)
-};
+static const snd_kcontrol_new_t snd_ac97_controls_mic_boost =
+ AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0);
-static const snd_kcontrol_new_t snd_ac97_controls_mic[3] = {
-AC97_SINGLE("Mic Playback Switch", AC97_MIC, 15, 1, 1),
-AC97_SINGLE("Mic Playback Volume", AC97_MIC, 0, 15, 1),
-AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0)
-};
static const snd_kcontrol_new_t snd_ac97_control_capture_src = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1121,6 +1114,26 @@ static int snd_ac97_try_volume_mix(ac97_t * ac97, int reg)
return 1; /* success, useable */
}
+static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max, unsigned char *hi_max)
+{
+ unsigned short cbit[3] = { 0x20, 0x10, 0x01 };
+ unsigned char max[3] = { 63, 31, 15 };
+ int i;
+
+ *lo_max = *hi_max = 0;
+ for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {
+ unsigned short val;
+ snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
+ val = snd_ac97_read(ac97, reg);
+ if (! *lo_max && (val & cbit[i]))
+ *lo_max = max[i];
+ if (! *hi_max && (val & (cbit[i] << 8)))
+ *hi_max = max[i];
+ if (*lo_max && *hi_max)
+ break;
+ }
+}
+
int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit)
{
unsigned short mask, val, orig, res;
@@ -1134,21 +1147,6 @@ int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit)
return res == val;
}
-static void snd_ac97_change_volume_params1(ac97_t * ac97, int reg, unsigned char *max)
-{
- unsigned short val, val1;
-
- *max = 63;
- val = 0x8000 | 0x0020;
- snd_ac97_write(ac97, reg, val);
- val1 = snd_ac97_read(ac97, reg);
- if (val != val1) {
- *max = 31;
- }
- /* reset volume to zero */
- snd_ac97_write_cache(ac97, reg, 0x8000);
-}
-
/* check the volume resolution of center/lfe */
static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max)
{
@@ -1165,34 +1163,6 @@ static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, un
snd_ac97_write_cache(ac97, reg, 0x8080);
}
-/* check whether the volume resolution is 4 or 5 bits */
-static void snd_ac97_change_volume_params3(ac97_t * ac97, int reg, unsigned char *max)
-{
- unsigned short val, val1;
-
- *max = 31;
- val = 0x8000 | 0x0010;
- snd_ac97_write(ac97, reg, val);
- val1 = snd_ac97_read(ac97, reg);
- if (val != val1) {
- *max = 15;
- }
- /* reset volume to zero */
- snd_ac97_write_cache(ac97, reg, 0x8000);
-}
-
-/* check whether the volume is mono or stereo */
-static int snd_ac97_is_stereo_vol(ac97_t *ac97, int reg)
-{
- unsigned short val, val1, val2;
- val = snd_ac97_read(ac97, reg);
- val1 = val | 0x8000 | (0x01 << 8);
- snd_ac97_write(ac97, reg, val1);
- val2 = snd_ac97_read(ac97, reg);
- snd_ac97_write(ac97, reg, val); /* restore */
- return val1 == val2;
-}
-
static inline int printable(unsigned int x)
{
x &= 0xff;
@@ -1219,22 +1189,22 @@ snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97
static int snd_ac97_cmute_new(snd_card_t *card, char *name, int reg, ac97_t *ac97)
{
snd_kcontrol_t *kctl;
- int stereo = 0;
+ int err;
+ unsigned short val, val1, mute_mask;
if (! snd_ac97_valid_reg(ac97, reg))
return 0;
+ mute_mask = 0x8000;
+ val = snd_ac97_read(ac97, reg);
if (ac97->flags & AC97_STEREO_MUTES) {
/* check whether both mute bits work */
- unsigned short val, val1;
- val = snd_ac97_read(ac97, reg);
val1 = val | 0x8080;
snd_ac97_write(ac97, reg, val1);
if (val1 == snd_ac97_read(ac97, reg))
- stereo = 1;
- snd_ac97_write(ac97, reg, val);
+ mute_mask = 0x8080;
}
- if (stereo) {
+ if (mute_mask == 0x8080) {
snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1);
tmp.index = ac97->num;
kctl = snd_ctl_new1(&tmp, ac97);
@@ -1243,50 +1213,68 @@ static int snd_ac97_cmute_new(snd_card_t *card, char *name, int reg, ac97_t *ac9
tmp.index = ac97->num;
kctl = snd_ctl_new1(&tmp, ac97);
}
- return snd_ctl_add(card, kctl);
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
+ return err;
+ /* mute as default */
+ snd_ac97_write_cache(ac97, reg, val | mute_mask);
+ return 0;
}
/*
- * create volumes for normal stereo controls
+ * create a volume for normal stereo/mono controls
*/
-static int snd_ac97_cvol_new(snd_card_t *card, char *name, int reg, unsigned int max, ac97_t *ac97)
+static int snd_ac97_cvol_new(snd_card_t *card, char *name, int reg, unsigned int lo_max,
+ unsigned int hi_max, ac97_t *ac97)
{
int err;
- snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 8, 0, (unsigned int)max, 1);
- tmp.index = ac97->num;
+ snd_kcontrol_t *kctl;
if (! snd_ac97_valid_reg(ac97, reg))
return 0;
- if ((err = snd_ctl_add(card, snd_ctl_new1(&tmp, ac97))) < 0)
+ if (hi_max) {
+ /* invert */
+ snd_kcontrol_new_t tmp = AC97_DOUBLE(name, reg, 8, 0, lo_max, 1);
+ tmp.index = ac97->num;
+ kctl = snd_ctl_new1(&tmp, ac97);
+ } else {
+ /* invert */
+ snd_kcontrol_new_t tmp = AC97_SINGLE(name, reg, 0, lo_max, 1);
+ tmp.index = ac97->num;
+ kctl = snd_ctl_new1(&tmp, ac97);
+ }
+ err = snd_ctl_add(card, kctl);
+ if (err < 0)
return err;
snd_ac97_write_cache(ac97, reg,
- ((ac97->flags & AC97_STEREO_MUTES) ? 0x8080 : 0x8000) |
- (unsigned short)max | ((unsigned short)max << 8));
+ (snd_ac97_read(ac97, reg) & 0x8080) |
+ lo_max | (hi_max << 8));
return 0;
}
/*
- * create mute-switch and volumes for normal stereo controls
+ * create a mute-switch and a volume for normal stereo/mono controls
*/
-static int snd_ac97_cmix_new(snd_card_t *card, const char *pfx, int reg, int check_res, ac97_t *ac97)
+static int snd_ac97_cmix_new(snd_card_t *card, const char *pfx, int reg, ac97_t *ac97)
{
int err;
char name[44];
- unsigned char max;
+ unsigned char lo_max, hi_max;
if (! snd_ac97_valid_reg(ac97, reg))
return 0;
- sprintf(name, "%s Switch", pfx);
- if ((err = snd_ac97_cmute_new(card, name, reg, ac97)) < 0)
- return err;
- sprintf(name, "%s Volume", pfx);
- if (check_res)
- snd_ac97_change_volume_params1(ac97, reg, &max);
- else
- max = 31; /* 5bit */
- if ((err = snd_ac97_cvol_new(card, name, reg, max, ac97)) < 0)
- return err;
+ if (snd_ac97_try_bit(ac97, reg, 15)) {
+ sprintf(name, "%s Switch", pfx);
+ if ((err = snd_ac97_cmute_new(card, name, reg, ac97)) < 0)
+ return err;
+ }
+ check_volume_resolution(ac97, reg, &lo_max, &hi_max);
+ if (lo_max) {
+ sprintf(name, "%s Volume", pfx);
+ if ((err = snd_ac97_cvol_new(card, name, reg, lo_max, hi_max, ac97)) < 0)
+ return err;
+ }
return 0;
}
@@ -1304,7 +1292,7 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
/* build master controls */
/* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) {
- if ((err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, 1, ac97)) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, ac97)) < 0)
return err;
}
@@ -1336,32 +1324,20 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
/* build surround controls */
if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) {
- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_surround[0], ac97))) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Surround Playback", AC97_SURROUND_MASTER, ac97)) < 0)
return err;
- if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_surround[1], ac97))) < 0)
- return err;
- snd_ac97_change_volume_params2(ac97, AC97_SURROUND_MASTER, 0, &max);
- kctl->private_value &= ~(0xff << 16);
- kctl->private_value |= (int)max << 16;
- snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x8080 | max | (max << 8));
}
/* build headphone controls */
if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
- if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, 1, ac97)) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, ac97)) < 0)
return err;
}
/* build master mono controls */
if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) {
- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_master_mono[0], ac97))) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, ac97)) < 0)
return err;
- if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_master_mono[1], ac97))) < 0)
- return err;
- snd_ac97_change_volume_params1(ac97, AC97_MASTER_MONO, &max);
- kctl->private_value &= ~(0xff << 16);
- kctl->private_value |= (int)max << 16;
- snd_ac97_write_cache(ac97, AC97_MASTER_MONO, 0x8000 | max);
}
/* build master tone controls */
@@ -1389,56 +1365,39 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
/* build Phone controls */
if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) {
- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_phone[0], ac97))) < 0)
- return err;
- if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_phone[1], ac97))) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, ac97)) < 0)
return err;
- snd_ac97_change_volume_params3(ac97, AC97_PHONE, &max);
- kctl->private_value &= ~(0xff << 16);
- kctl->private_value |= (int)max << 16;
- snd_ac97_write_cache(ac97, AC97_PHONE, 0x8000 | max);
}
/* build MIC controls */
- snd_ac97_change_volume_params3(ac97, AC97_MIC, &max);
- if (snd_ac97_is_stereo_vol(ac97, AC97_MIC)) {
- /* build stereo mic */
- if ((err = snd_ac97_cmute_new(card, "Mic Playback Switch", AC97_MIC, ac97)) < 0)
- return err;
- if ((err = snd_ac97_cvol_new(card, "Mic Playback Volume", AC97_MIC, max, ac97)) < 0)
+ if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+ if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
return err;
- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic[2], ac97))) < 0)
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
return err;
- } else {
- /* build mono mic */
- for (idx = 0; idx < 3; idx++) {
- if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)
- return err;
- if (idx == 1) { // volume
- kctl->private_value &= ~(0xff << 16);
- kctl->private_value |= (int)max << 16;
- }
- }
- snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);
}
/* build Line controls */
- if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, 0, ac97)) < 0)
- return err;
+ if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) {
+ if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, ac97)) < 0)
+ return err;
+ }
/* build CD controls */
- if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, 0, ac97)) < 0)
- return err;
+ if (snd_ac97_try_volume_mix(ac97, AC97_CD)) {
+ if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, ac97)) < 0)
+ return err;
+ }
/* build Video controls */
if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) {
- if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, 0, ac97)) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, ac97)) < 0)
return err;
}
/* build Aux controls */
if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) {
- if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, 0, ac97)) < 0)
+ if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0)
return err;
}
@@ -1470,15 +1429,8 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
snd_ac97_write_cache(ac97, AC97_PCM, init_val);
} else {
- if ((err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97)) < 0)
+ if ((err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97)) < 0)
return err;
- /* FIXME: C-Media chips have no PCM volume!! */
- if (ac97->id == AC97_ID_CM9739)
- snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f);
- else {
- if ((err = snd_ac97_cvol_new(card, "PCM Playback Volume", AC97_PCM, 31, ac97)) < 0)
- return err;
- }
}
/* build Capture controls */