- AC97 quirk / patch cleanups. Most quirks doesn't work in general sense

and should only be applied on certain specific card / vendor, hence the
  addition of ac97_getsubvendor().
- Fix low volume issue on several MSI laptops through ALC655 quirk.

Reported/Tested by:	Christian Mueller
                   	<raptor-freebsd-multimedia@xpls.de>
MFC after:		1 week
This commit is contained in:
Ariff Abdullah 2007-04-19 13:54:22 +00:00
parent b03cfe2396
commit fd7390d640
4 changed files with 59 additions and 20 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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*);