X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Foss%2Fac97_codec.c;h=20a09424a48a4bda97fea247f83444c50d9c3383;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=c883411dacaf8f05c5ee52cff7becdeef5e60c70;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index c883411da..20a09424a 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,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}, @@ -173,6 +177,7 @@ static const struct { {0x83847608, "SigmaTel STAC9708", &sigmatel_9708_ops}, {0x83847609, "SigmaTel STAC9721/23", &sigmatel_9721_ops}, {0x83847644, "SigmaTel STAC9744/45", &sigmatel_9744_ops}, + {0x83847652, "SigmaTel STAC9752/53", &default_ops}, {0x83847656, "SigmaTel STAC9756/57", &sigmatel_9744_ops}, {0x83847666, "SigmaTel STAC9750T", &sigmatel_9744_ops}, {0x83847684, "SigmaTel STAC9783/84?", &null_ops}, @@ -1453,5 +1458,92 @@ void ac97_unregister_driver(struct ac97_driver *driver) } 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");