From: "John W. Linville" <linville@tuxdriver.com>
To: linux-kernel@vger.kernel.org
Cc: jgarzik@pobox.com, alan@redhat.com
Subject: [patch 2.6.10-rc2] oss: AC97 quirk facility
Date: Wed, 17 Nov 2004 16:30:16 -0500 [thread overview]
Message-ID: <20041117163016.A5351@tuxdriver.com> (raw)
Add a quirk facility for AC97 in OSS, and add a quirk list for the
i810_audio driver.
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
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...
include/linux/ac97_codec.h | 21 +++++++
sound/oss/ac97_codec.c | 91 +++++++++++++++++++++++++++++++
sound/oss/i810_audio.c | 132 +++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 240 insertions(+), 4 deletions(-)
--- oss_ac97_quirk-2.6/include/linux/ac97_codec.h.orig
+++ oss_ac97_quirk-2.6/include/linux/ac97_codec.h
@@ -315,4 +315,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_ */
--- oss_ac97_quirk-2.6/sound/oss/ac97_codec.c.orig
+++ oss_ac97_quirk-2.6/sound/oss/ac97_codec.c
@@ -52,6 +52,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>
@@ -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},
@@ -1453,5 +1457,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");
--- oss_ac97_quirk-2.6/sound/oss/i810_audio.c.orig
+++ oss_ac97_quirk-2.6/sound/oss/i810_audio.c
@@ -111,6 +111,7 @@ static int ftsodell;
static int strict_clocking;
static unsigned int clocking;
static int spdif_locked;
+static int ac97_quirk = AC97_TUNE_DEFAULT;
//#define DEBUG
//#define DEBUG2
@@ -481,6 +482,124 @@ struct i810_card {
#define CIV_TO_LVI(card, port, off) \
I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI)
+static struct ac97_quirk ac97_quirks[] __devinitdata = {
+ {
+ .vendor = 0x0e11,
+ .device = 0x00b8,
+ .name = "Compaq Evo D510C",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x00d8,
+ .name = "Dell Precision 530", /* AD1885 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x0126,
+ .name = "Dell Optiplex GX260", /* AD1981A */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x012d,
+ .name = "Dell Precision 450", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ { /* FIXME: which codec? */
+ .vendor = 0x103c,
+ .device = 0x00c3,
+ .name = "Hewlett-Packard onboard",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x12f1,
+ .name = "HP xw8200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x3008,
+ .name = "HP xw4200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x10f1,
+ .device = 0x2665,
+ .name = "Fujitsu-Siemens Celsius", /* AD1981? */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x10f1,
+ .device = 0x2885,
+ .name = "AMD64 Mobo", /* ALC650 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x110a,
+ .device = 0x0056,
+ .name = "Fujitsu-Siemens Scenic", /* AD1981? */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x11d4,
+ .device = 0x5375,
+ .name = "ADI AD1985 (discrete)",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1462,
+ .device = 0x5470,
+ .name = "MSI P4 ATX 645 Ultra",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1734,
+ .device = 0x0088,
+ .name = "Fujitsu-Siemens D1522", /* AD1981 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x8086,
+ .device = 0x4856,
+ .name = "Intel D845WN (82801BA)",
+ .type = AC97_TUNE_SWAP_HP
+ },
+ {
+ .vendor = 0x8086,
+ .device = 0x4d44,
+ .name = "Intel D850EMV2", /* AD1885 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x8086,
+ .device = 0x4d56,
+ .name = "Intel ICH/AD1885",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x1028,
+ .device = 0x012d,
+ .name = "Dell Precision 450", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x3008,
+ .name = "HP xw4200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .vendor = 0x103c,
+ .device = 0x12f1,
+ .name = "HP xw8200", /* AD1981B*/
+ .type = AC97_TUNE_HP_ONLY
+ },
+ { } /* terminator */
+};
+
static struct i810_card *devs = NULL;
static int i810_open_mixdev(struct inode *inode, struct file *file);
@@ -3043,6 +3162,9 @@ static int __devinit i810_ac97_init(stru
card->ac97_codec[num_ac97] = codec;
}
+ /* tune up the primary codec */
+ ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk);
+
/* pick the minimum of channels supported by ICHx or codec(s) */
card->channels = (card->channels > total_channels)?total_channels:card->channels;
@@ -3463,10 +3585,12 @@ static int i810_pm_resume(struct pci_dev
MODULE_AUTHOR("");
MODULE_DESCRIPTION("Intel 810 audio support");
MODULE_LICENSE("GPL");
-MODULE_PARM(ftsodell, "i");
-MODULE_PARM(clocking, "i");
-MODULE_PARM(strict_clocking, "i");
-MODULE_PARM(spdif_locked, "i");
+module_param(ftsodell, int, 000);
+module_param(clocking, int, 000);
+module_param(strict_clocking, int, 000);
+module_param(spdif_locked, int, 000);
+module_param(ac97_quirk, int, 000);
+MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
#define I810_MODULE_NAME "intel810_audio"
next reply other threads:[~2004-11-17 21:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-17 21:30 John W. Linville [this message]
2004-11-17 22:56 ` [patch 2.6.10-rc2] oss: AC97 quirk facility Andrew Morton
2004-11-18 1:25 ` John W. Linville
2004-11-18 18:27 ` Jeff Garzik
2004-11-18 18:36 ` Jan Engelhardt
2004-11-18 18:38 ` Jeff Garzik
2004-11-18 18:41 ` Jan Engelhardt
2004-11-18 18:45 ` Jeff Garzik
2004-11-19 1:23 ` Lee Revell
2004-11-18 18:41 ` Alan Cox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20041117163016.A5351@tuxdriver.com \
--to=linville@tuxdriver.com \
--cc=alan@redhat.com \
--cc=jgarzik@pobox.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.