oss: AC97 quirk facility
PATCH 1/1 oss: AC97 quirk facility
Add a quirk facility for AC97 in OSS, and add a quirk list for the i810_audio driver.
Signed-off-by John W. Linville <[email protected]>
---
This allows automatically "correct" behaviour for sound hardware w/ known oddities. For example, many cards have the headphone and line-out outputs swapped or headphone outputs only.
The code is stolen shamelessly from ALSA, FWIW...
drivers/sound/ac97_codec.c | 91 +++++++++++++++++++++++++++++++++ drivers/sound/i810_audio.c | 124 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/ac97_codec.h | 21 +++++++ 3 files changed, 236 insertions(+)
drivers/sound/ac97_codec.c renamed from drivers/sound/ac97_codec.c.orig +91 -0
@@ -56,6 +56,7 @@#include <linux/errno.h> #include <linux/bitops.h> #include <linux/delay.h> +#include <linux/pci.h> #include <linux/ac97_codec.h> #include <asm/uaccess.h>
@@ -134,6 +135,9 @@ static const struct { {0x41445348, "Analog Devices AD1881A", &null_ops}, {0x41445360, "Analog Devices AD1885", &default_ops}, {0x41445361, "Analog Devices AD1886", &ad1886_ops}, + {0x41445370, "Analog Devices AD1981", &null_ops}, + {0x41445372, "Analog Devices AD1981A", &null_ops}, + {0x41445374, "Analog Devices AD1981B", &null_ops}, {0x41445460, "Analog Devices AD1885", &default_ops}, {0x41445461, "Analog Devices AD1886", &ad1886_ops}, {0x414B4D00, "Asahi Kasei AK4540", &null_ops},
@@ -1482,5 +1486,92 @@ void ac97_unregister_driver(struct ac97_ }EXPORT_SYMBOL_GPL (ac97_unregister_driver); + +static int swap_headphone (int remove_master) +{ +struct list_head *l; +struct ac97_codec *c; +if (remove_master) { +down (&codec_sem); +list_for_each (l, &codecs) + { + c = list_entry(l, struct ac97_codec, list); +if (supported_mixer (c,SOUND_MIXER_PHONEOUT )) + c->supported_mixers &= ~SOUND_MASK_PHONEOUT ; + } +up (&codec_sem); + }else + ac97_hw[SOUND_MIXER_PHONEOUT ].offset =AC97_MASTER_VOL_STEREO ; + +/* Scale values already match */ + ac97_hw[SOUND_MIXER_VOLUME ].offset =AC97_MASTER_VOL_MONO ; +return 0 ; +} + +static int apply_quirk (int quirk) +{ +switch (quirk) { +case AC97_TUNE_NONE : +return 0 ; +case AC97_TUNE_HP_ONLY : +return swap_headphone (1 ); +case AC97_TUNE_SWAP_HP : +return swap_headphone (0 ); +case AC97_TUNE_SWAP_SURROUND : +return -ENOSYS ;/* not yet implemented */ +case AC97_TUNE_AD_SHARING : +return -ENOSYS ;/* not yet implemented */ +case AC97_TUNE_ALC_JACK : +return -ENOSYS ;/* not yet implemented */ + } +return -EINVAL ; +} + +/** +* ac97_tune_hardware - tune up the hardware +* @pdev: pci_dev pointer +* @quirk: quirk list +* @override: explicit quirk value (overrides if not AC97_TUNE_DEFAULT) +* +* Do some workaround for each pci device, such as renaming of the +* headphone (true line-out) control as "Master". +* The quirk-list must be terminated with a zero-filled entry. +* +* Returns zero if successful, or a negative error code on failure. +*/ + +int ac97_tune_hardware (struct pci_dev *pdev,struct ac97_quirk *quirk,int override) +{ +int result; + +if (!quirk) +return -EINVAL ; + +if (override !=AC97_TUNE_DEFAULT ) { + result =apply_quirk (override); +if (result <0 ) +printk (KERN_ERR "applying quirk type %d failed (%d)\n" , override, result); +return result; + } + +for (; quirk->vendor; quirk++) { +if (quirk->vendor != pdev->subsystem_vendor) +continue ; +if ((! quirk->mask && quirk->device == pdev->subsystem_device) || + quirk->device == (quirk->mask & pdev->subsystem_device)) { +#ifdef DEBUG +printk ("ac97 quirk for %s (%04x:%04x)\n" , quirk->name, ac97->subsystem_vendor, pdev->subsystem_device); +#endif + result =apply_quirk (quirk->type); +if (result <0 ) +printk (KERN_ERR "applying quirk type %d for %s failed (%d)\n" , quirk->type, quirk->name, result); +return result; + } + } +return 0 ; +} + +EXPORT_SYMBOL_GPL (ac97_tune_hardware); +MODULE_LICENSE ("GPL" );
drivers/sound/i810_audio.c renamed from drivers/sound/i810_audio.c.orig +124 -0
148 lines not on this page · raw message
include/linux/ac97_codec.h renamed from include/linux/ac97_codec.h.orig +21 -0
@@ -316,4 +316,25 @@ struct ac97_driver {extern int ac97_register_driver (struct ac97_driver *driver);extern void ac97_unregister_driver (struct ac97_driver *driver); +/* quirk types */ +enum { +AC97_TUNE_DEFAULT =-1 ,/* use default from quirk list (not valid in list) */ +AC97_TUNE_NONE =0 ,/* nothing extra to do */ +AC97_TUNE_HP_ONLY ,/* headphone (true line-out) control as master only */ +AC97_TUNE_SWAP_HP ,/* swap headphone and master controls */ +AC97_TUNE_SWAP_SURROUND ,/* swap master and surround controls */ +AC97_TUNE_AD_SHARING ,/* for AD1985, turn on OMS bit and use headphone */ +AC97_TUNE_ALC_JACK ,/* for Realtek, enable JACK detection */ +}; + +struct ac97_quirk { +unsigned short vendor;/* PCI vendor id */ +unsigned short device;/* PCI device id */ +unsigned short mask;/* device id bit mask, 0 = accept all */ +const char *name;/* name shown as info */ +int type;/* quirk type above */ +}; + +extern int ac97_tune_hardware (struct pci_dev *pdev,struct ac97_quirk *quirk,int override); +#endif /* _AC97_CODEC_H_ */