Commit a03705c2 authored by Jaroslav Kysela's avatar Jaroslav Kysela

[ALSA] Allow strings for ac97_quirk options

AC97 Codec Core,Intel8x0 driver,VIA82xx driver
Since there are many ac97_quirk values, the number is no longer good to
remember what it really means.  Now ac97_quirk option becomes as a string
option, and more undstandable.  For example, you can pass like
'ac97_quirk=hp_only'.  The old number is still kept and parsed for backward
compatibility.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 870fd554
...@@ -566,7 +566,7 @@ struct ac97_quirk { ...@@ -566,7 +566,7 @@ struct ac97_quirk {
int type; /* quirk type above */ int type; /* quirk type above */
}; };
int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, int override); int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *override);
int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned int rate); int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned int rate);
int snd_ac97_pcm_assign(ac97_bus_t *ac97, int snd_ac97_pcm_assign(ac97_bus_t *ac97,
......
...@@ -2299,6 +2299,7 @@ void snd_ac97_resume(ac97_t *ac97) ...@@ -2299,6 +2299,7 @@ void snd_ac97_resume(ac97_t *ac97)
/* /*
* Hardware tuning
*/ */
static void set_ctl_name(char *dst, const char *src, const char *suffix) static void set_ctl_name(char *dst, const char *src, const char *suffix)
{ {
...@@ -2308,6 +2309,7 @@ static void set_ctl_name(char *dst, const char *src, const char *suffix) ...@@ -2308,6 +2309,7 @@ static void set_ctl_name(char *dst, const char *src, const char *suffix)
strcpy(dst, src); strcpy(dst, src);
} }
/* remove the control with the given name and optional suffix */
int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix) int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix)
{ {
snd_ctl_elem_id_t id; snd_ctl_elem_id_t id;
...@@ -2326,6 +2328,7 @@ static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name, const char *suff ...@@ -2326,6 +2328,7 @@ static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name, const char *suff
return snd_ctl_find_id(ac97->bus->card, &sid); return snd_ctl_find_id(ac97->bus->card, &sid);
} }
/* rename the control with the given name and optional suffix */
int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix) int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix)
{ {
snd_kcontrol_t *kctl = ctl_find(ac97, src, suffix); snd_kcontrol_t *kctl = ctl_find(ac97, src, suffix);
...@@ -2343,6 +2346,7 @@ void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst) ...@@ -2343,6 +2346,7 @@ void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst)
snd_ac97_rename_ctl(ac97, src, dst, "Volume"); snd_ac97_rename_ctl(ac97, src, dst, "Volume");
} }
/* swap controls */
int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix) int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix)
{ {
snd_kcontrol_t *kctl1, *kctl2; snd_kcontrol_t *kctl1, *kctl2;
...@@ -2356,20 +2360,29 @@ int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char * ...@@ -2356,20 +2360,29 @@ int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *
return -ENOENT; return -ENOENT;
} }
static int swap_headphone(ac97_t *ac97, int remove_master) /* ac97 tune: use Headphone control as master */
static int tune_hp_only(ac97_t *ac97)
{ {
if (ctl_find(ac97, "Headphone Playback Switch", NULL) == NULL) if (ctl_find(ac97, "Headphone Playback Switch", NULL) == NULL)
return -ENOENT; return -ENOENT;
if (remove_master) { snd_ac97_remove_ctl(ac97, "Master Playback", "Switch");
snd_ac97_remove_ctl(ac97, "Master Playback", "Switch"); snd_ac97_remove_ctl(ac97, "Master Playback", "Volume");
snd_ac97_remove_ctl(ac97, "Master Playback", "Volume"); snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
} else return 0;
snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Line-Out Playback"); }
/* ac97 tune: swap Headphone and Master controls */
static int tune_swap_hp(ac97_t *ac97)
{
if (ctl_find(ac97, "Headphone Playback Switch", NULL) == NULL)
return -ENOENT;
snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Line-Out Playback");
snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback"); snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
return 0; return 0;
} }
static int swap_surround(ac97_t *ac97) /* ac97 tune: swap Surround and Master controls */
static int tune_swap_surround(ac97_t *ac97)
{ {
if (snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Switch") || if (snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Switch") ||
snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Volume")) snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Volume"))
...@@ -2377,6 +2390,7 @@ static int swap_surround(ac97_t *ac97) ...@@ -2377,6 +2390,7 @@ static int swap_surround(ac97_t *ac97)
return 0; return 0;
} }
/* ac97 tune: set up mic sharing for AD codecs */
static int tune_ad_sharing(ac97_t *ac97) static int tune_ad_sharing(ac97_t *ac97)
{ {
unsigned short scfg; unsigned short scfg;
...@@ -2393,6 +2407,7 @@ static int tune_ad_sharing(ac97_t *ac97) ...@@ -2393,6 +2407,7 @@ static int tune_ad_sharing(ac97_t *ac97)
static const snd_kcontrol_new_t snd_ac97_alc_jack_detect = static const snd_kcontrol_new_t snd_ac97_alc_jack_detect =
AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0); AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0);
/* ac97 tune: set up ALC jack-select */
static int tune_alc_jack(ac97_t *ac97) static int tune_alc_jack(ac97_t *ac97)
{ {
if ((ac97->id & 0xffffff00) != 0x414c4700) { if ((ac97->id & 0xffffff00) != 0x414c4700) {
...@@ -2404,6 +2419,7 @@ static int tune_alc_jack(ac97_t *ac97) ...@@ -2404,6 +2419,7 @@ static int tune_alc_jack(ac97_t *ac97)
return snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_alc_jack_detect, ac97)); return snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_alc_jack_detect, ac97));
} }
/* ac97 tune: inversed EAPD bit */
static int tune_inv_eapd(ac97_t *ac97) static int tune_inv_eapd(ac97_t *ac97)
{ {
snd_kcontrol_t *kctl = ctl_find(ac97, "External Amplifier", NULL); snd_kcontrol_t *kctl = ctl_find(ac97, "External Amplifier", NULL);
...@@ -2432,6 +2448,7 @@ static int master_mute_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc ...@@ -2432,6 +2448,7 @@ static int master_mute_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *uc
return err; return err;
} }
/* ac97 tune: EAPD controls mute LED bound with the master mute */
static int tune_mute_led(ac97_t *ac97) static int tune_mute_led(ac97_t *ac97)
{ {
snd_kcontrol_t *msw = ctl_find(ac97, "Master Playback Switch", NULL); snd_kcontrol_t *msw = ctl_find(ac97, "Master Playback Switch", NULL);
...@@ -2443,26 +2460,48 @@ static int tune_mute_led(ac97_t *ac97) ...@@ -2443,26 +2460,48 @@ static int tune_mute_led(ac97_t *ac97)
return 0; return 0;
} }
static int apply_quirk(ac97_t *ac97, int quirk) struct quirk_table {
const char *name;
int (*func)(ac97_t *);
};
static struct quirk_table applicable_quirks[] = {
{ "none", NULL },
{ "hp_only", tune_hp_only },
{ "swap_hp", tune_swap_hp },
{ "swap_surround", tune_swap_surround },
{ "ad_sharing", tune_ad_sharing },
{ "alc_jack", tune_alc_jack },
{ "inv_eapd", tune_inv_eapd },
{ "mute_led", tune_mute_led },
};
/* apply the quirk with the given type */
static int apply_quirk(ac97_t *ac97, int type)
{ {
switch (quirk) { if (type <= 0)
case AC97_TUNE_NONE:
return 0; return 0;
case AC97_TUNE_HP_ONLY: else if (type >= ARRAY_SIZE(applicable_quirks))
return swap_headphone(ac97, 1); return -EINVAL;
case AC97_TUNE_SWAP_HP: if (applicable_quirks[type].func)
return swap_headphone(ac97, 0); return applicable_quirks[type].func(ac97);
case AC97_TUNE_SWAP_SURROUND: return 0;
return swap_surround(ac97); }
case AC97_TUNE_AD_SHARING:
return tune_ad_sharing(ac97); /* apply the quirk with the given name */
case AC97_TUNE_ALC_JACK: static int apply_quirk_str(ac97_t *ac97, const char *typestr)
return tune_alc_jack(ac97); {
case AC97_TUNE_INV_EAPD: int i;
return tune_inv_eapd(ac97); struct quirk_table *q;
case AC97_TUNE_MUTE_LED:
return tune_mute_led(ac97); for (i = 0; i < ARRAY_SIZE(applicable_quirks); i++) {
q = &applicable_quirks[i];
if (q->name && ! strcmp(typestr, q->name))
return apply_quirk(ac97, i);
} }
/* for compatibility, accept the numbers, too */
if (*typestr >= '0' && *typestr <= '9')
return apply_quirk(ac97, (int)simple_strtol(typestr, NULL, 10));
return -EINVAL; return -EINVAL;
} }
...@@ -2470,7 +2509,7 @@ static int apply_quirk(ac97_t *ac97, int quirk) ...@@ -2470,7 +2509,7 @@ static int apply_quirk(ac97_t *ac97, int quirk)
* snd_ac97_tune_hardware - tune up the hardware * snd_ac97_tune_hardware - tune up the hardware
* @ac97: the ac97 instance * @ac97: the ac97 instance
* @quirk: quirk list * @quirk: quirk list
* @override: explicit quirk value (overrides the list if not AC97_TUNE_DEFAULT) * @override: explicit quirk value (overrides the list if non-NULL)
* *
* Do some workaround for each pci device, such as renaming of the * Do some workaround for each pci device, such as renaming of the
* headphone (true line-out) control as "Master". * headphone (true line-out) control as "Master".
...@@ -2479,16 +2518,17 @@ static int apply_quirk(ac97_t *ac97, int quirk) ...@@ -2479,16 +2518,17 @@ static int apply_quirk(ac97_t *ac97, int quirk)
* Returns zero if successful, or a negative error code on failure. * Returns zero if successful, or a negative error code on failure.
*/ */
int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, int override) int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *override)
{ {
int result; int result;
snd_assert(quirk, return -EINVAL); snd_assert(quirk, return -EINVAL);
if (override != AC97_TUNE_DEFAULT) { /* quirk overriden? */
result = apply_quirk(ac97, override); if (override && strcmp(override, "-1") && strcmp(override, "default")) {
result = apply_quirk_str(ac97, override);
if (result < 0) if (result < 0)
snd_printk(KERN_ERR "applying quirk type %d failed (%d)\n", override, result); snd_printk(KERN_ERR "applying quirk type %s failed (%d)\n", override, result);
return result; return result;
} }
......
...@@ -66,7 +66,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ ...@@ -66,7 +66,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
static int ac97_quirk[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = AC97_TUNE_DEFAULT}; static char *ac97_quirk[SNDRV_CARDS];
static int buggy_irq[SNDRV_CARDS]; static int buggy_irq[SNDRV_CARDS];
static int xbox[SNDRV_CARDS]; static int xbox[SNDRV_CARDS];
...@@ -82,7 +82,7 @@ module_param_array(enable, bool, NULL, 0444); ...@@ -82,7 +82,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard."); MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard.");
module_param_array(ac97_clock, int, NULL, 0444); module_param_array(ac97_clock, int, NULL, 0444);
MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
module_param_array(ac97_quirk, int, NULL, 0444); module_param_array(ac97_quirk, charp, NULL, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
module_param_array(buggy_irq, bool, NULL, 0444); module_param_array(buggy_irq, bool, NULL, 0444);
MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");
...@@ -1902,7 +1902,7 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { ...@@ -1902,7 +1902,7 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
{ } /* terminator */ { } /* terminator */
}; };
static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac97_quirk) static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, const char *quirk_override)
{ {
ac97_bus_t *pbus; ac97_bus_t *pbus;
ac97_template_t ac97; ac97_template_t ac97;
...@@ -1998,7 +1998,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac ...@@ -1998,7 +1998,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac
} }
} }
/* tune up the primary codec */ /* tune up the primary codec */
snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks, ac97_quirk); snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks, quirk_override);
/* enable separate SDINs for ICH4 */ /* enable separate SDINs for ICH4 */
if (chip->device_type == DEVICE_INTEL_ICH4) if (chip->device_type == DEVICE_INTEL_ICH4)
pbus->isdin = 1; pbus->isdin = 1;
......
...@@ -81,7 +81,7 @@ static long mpu_port[SNDRV_CARDS]; ...@@ -81,7 +81,7 @@ static long mpu_port[SNDRV_CARDS];
static int joystick[SNDRV_CARDS]; static int joystick[SNDRV_CARDS];
#endif #endif
static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
static int ac97_quirk[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = AC97_TUNE_DEFAULT}; static char *ac97_quirk[SNDRV_CARDS];
static int dxs_support[SNDRV_CARDS]; static int dxs_support[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444); module_param_array(index, int, NULL, 0444);
...@@ -98,7 +98,7 @@ MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)"); ...@@ -98,7 +98,7 @@ MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)");
#endif #endif
module_param_array(ac97_clock, int, NULL, 0444); module_param_array(ac97_clock, int, NULL, 0444);
MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz).");
module_param_array(ac97_quirk, int, NULL, 0444); module_param_array(ac97_quirk, charp, NULL, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
module_param_array(dxs_support, int, NULL, 0444); module_param_array(dxs_support, int, NULL, 0444);
MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)");
...@@ -1602,7 +1602,7 @@ static struct ac97_quirk ac97_quirks[] = { ...@@ -1602,7 +1602,7 @@ static struct ac97_quirk ac97_quirks[] = {
{ } /* terminator */ { } /* terminator */
}; };
static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, int ac97_quirk) static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, const char *quirk_override)
{ {
ac97_template_t ac97; ac97_template_t ac97;
int err; int err;
...@@ -1625,7 +1625,7 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, int ac97_quirk) ...@@ -1625,7 +1625,7 @@ static int __devinit snd_via82xx_mixer_new(via82xx_t *chip, int ac97_quirk)
if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0)
return err; return err;
snd_ac97_tune_hardware(chip->ac97, ac97_quirks, ac97_quirk); snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override);
if (chip->chip_type != TYPE_VIA686) { if (chip->chip_type != TYPE_VIA686) {
/* use slot 10/11 */ /* use slot 10/11 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment