diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c index 0993fd605f24..e32db6491b31 100644 --- a/sys/dev/sound/pcm/ac97.c +++ b/sys/dev/sound/pcm/ac97.c @@ -54,6 +54,7 @@ struct ac97_info { device_t dev; void *devinfo; u_int32_t id; + u_int32_t subvendor; unsigned count, caps, se, extcaps, extid, extstat, noext:1; u_int32_t flags; struct ac97mixtable_entry mix[32]; @@ -152,7 +153,7 @@ static struct ac97_codecid ac97codecid[] = { { 0x414c4740, 0x0f, 0, "ALC202", 0 }, { 0x414c4720, 0x0f, 0, "ALC650", 0 }, { 0x414c4752, 0x0f, 0, "ALC250", 0 }, - { 0x414c4760, 0x0f, 0, "ALC655", 0 }, + { 0x414c4760, 0x0f, 0, "ALC655", alc655_patch }, { 0x414c4770, 0x0f, 0, "ALC203", 0 }, { 0x414c4780, 0x0f, 0, "ALC658", 0 }, { 0x414c4790, 0x0f, 0, "ALC850", 0 }, @@ -405,6 +406,12 @@ ac97_getcaps(struct ac97_info *codec) return codec->caps; } +u_int32_t +ac97_getsubvendor(struct ac97_info *codec) +{ + return codec->subvendor; +} + static int ac97_setrecsrc(struct ac97_info *codec, int channel) { @@ -627,6 +634,9 @@ ac97_initmixer(struct ac97_info *codec) } codec->id = id; + codec->subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16; + codec->subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) & + 0x0000ffff; codec->noext = 0; codec_patch = NULL; @@ -913,7 +923,6 @@ ac97mix_init(struct snd_mixer *m) { struct ac97_info *codec = mix_getdevinfo(m); struct snddev_info *d; - u_int32_t subvendor; u_int32_t i, mask; if (codec == NULL) @@ -924,20 +933,18 @@ ac97mix_init(struct snd_mixer *m) switch (codec->id) { case 0x41445374: /* AD1981B */ - subvendor = (u_int32_t)pci_get_subdevice(codec->dev) << 16; - subvendor |= (u_int32_t)pci_get_subvendor(codec->dev) & - 0x0000ffff; - /* IBM Thinkcentre */ - if (subvendor == 0x02d91014) { - /* Enable headphone jack sensing */ - ac97_wrcd(codec, 0x72, ac97_rdcd(codec, 0x72) | - 0x0800); + if (codec->subvendor == 0x02d91014) { + /* + * IBM Thinkcentre: + * Tie "ogain" and "phone" to "vol" since its + * master volume is basically useless and can't + * control anything. + */ mask = 0; if (codec->mix[SOUND_MIXER_OGAIN].enable) mask |= SOUND_MASK_OGAIN; if (codec->mix[SOUND_MIXER_PHONEOUT].enable) mask |= SOUND_MASK_PHONEOUT; - /* Tie ogain/phone to master volume */ if (codec->mix[SOUND_MIXER_VOLUME].enable) mix_setparentchild(m, SOUND_MIXER_VOLUME, mask); diff --git a/sys/dev/sound/pcm/ac97.h b/sys/dev/sound/pcm/ac97.h index f73dc76f4470..3112cc0d474e 100644 --- a/sys/dev/sound/pcm/ac97.h +++ b/sys/dev/sound/pcm/ac97.h @@ -101,6 +101,7 @@ int ac97_setextmode(struct ac97_info *codec, u_int16_t mode); u_int16_t ac97_getextmode(struct ac97_info *codec); u_int16_t ac97_getextcaps(struct ac97_info *codec); u_int16_t ac97_getcaps(struct ac97_info *codec); +u_int32_t ac97_getsubvendor(struct ac97_info *codec); u_int16_t ac97_rdcd(struct ac97_info *codec, int reg); void ac97_wrcd(struct ac97_info *codec, int reg, u_int16_t val); diff --git a/sys/dev/sound/pcm/ac97_patch.c b/sys/dev/sound/pcm/ac97_patch.c index 1be08522971c..1db0a989fd90 100644 --- a/sys/dev/sound/pcm/ac97_patch.c +++ b/sys/dev/sound/pcm/ac97_patch.c @@ -49,19 +49,49 @@ void ad198x_patch(struct ac97_info* codec) void ad1981b_patch(struct ac97_info* codec) { -#if 0 - ac97_wrcd(codec, AC97_AD_JACK_SPDIF, - ac97_rdcd(codec, AC97_AD_JACK_SPDIF) | 0x0800); -#endif + /* + * Enable headphone jack sensing. + */ + switch (ac97_getsubvendor(codec)) { + case 0x02d91014: /* IBM Thinkcentre */ + ac97_wrcd(codec, AC97_AD_JACK_SPDIF, + ac97_rdcd(codec, AC97_AD_JACK_SPDIF) | 0x0800); + break; + default: + break; + } } void cmi9739_patch(struct ac97_info* codec) { /* - * Few laptops (notably ASUS W1000N) need extra register - * initialization to power up the internal speakers. + * Few laptops need extra register initialization + * to power up the internal speakers. */ - ac97_wrcd(codec, AC97_REG_POWER, 0x000f); - ac97_wrcd(codec, AC97_MIXEXT_CLFE, 0x0000); - ac97_wrcd(codec, 0x64, 0x7110); + switch (ac97_getsubvendor(codec)) { + case 0x18431043: /* ASUS W1000N */ + ac97_wrcd(codec, AC97_REG_POWER, 0x000f); + ac97_wrcd(codec, AC97_MIXEXT_CLFE, 0x0000); + ac97_wrcd(codec, 0x64, 0x7110); + break; + default: + break; + } +} + +void alc655_patch(struct ac97_info* codec) +{ + /* + * MSI (Micro-Star International) specific EAPD quirk. + */ + switch (ac97_getsubvendor(codec)) { + case 0x00611462: /* MSI S250 */ + case 0x01311462: /* MSI S270 */ + case 0x01611462: /* LG K1 Express */ + case 0x03511462: /* MSI L725 */ + ac97_wrcd(codec, 0x7a, ac97_rdcd(codec, 0x7a) & 0xfffd); + break; + default: + break; + } } diff --git a/sys/dev/sound/pcm/ac97_patch.h b/sys/dev/sound/pcm/ac97_patch.h index 7a329753a639..c8df443e3627 100644 --- a/sys/dev/sound/pcm/ac97_patch.h +++ b/sys/dev/sound/pcm/ac97_patch.h @@ -32,3 +32,4 @@ void ad1886_patch(struct ac97_info*); void ad198x_patch(struct ac97_info*); void ad1981b_patch(struct ac97_info*); void cmi9739_patch(struct ac97_info*); +void alc655_patch(struct ac97_info*);