summaryrefslogtreecommitdiff
path: root/sound/pci/hda/hda_auto_parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_auto_parser.c')
-rw-r--r--sound/pci/hda/hda_auto_parser.c61
1 files changed, 50 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 7c6b1fe8dfcc..8e74be038b0f 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -956,6 +956,28 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup);
+/* check whether the given quirk entry matches with vendor/device pair */
+static bool hda_quirk_match(u16 vendor, u16 device, const struct hda_quirk *q)
+{
+ if (q->subvendor != vendor)
+ return false;
+ return !q->subdevice ||
+ (device & q->subdevice_mask) == q->subdevice;
+}
+
+/* look through the quirk list and return the matching entry */
+static const struct hda_quirk *
+hda_quirk_lookup_id(u16 vendor, u16 device, const struct hda_quirk *list)
+{
+ const struct hda_quirk *q;
+
+ for (q = list; q->subvendor || q->subdevice; q++) {
+ if (hda_quirk_match(vendor, device, q))
+ return q;
+ }
+ return NULL;
+}
+
/**
* snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string
* @codec: the HDA codec
@@ -975,14 +997,16 @@ EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup);
*/
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
- const struct snd_pci_quirk *quirk,
+ const struct hda_quirk *quirk,
const struct hda_fixup *fixlist)
{
- const struct snd_pci_quirk *q;
+ const struct hda_quirk *q;
int id = HDA_FIXUP_ID_NOT_SET;
const char *name = NULL;
const char *type = NULL;
unsigned int vendor, device;
+ u16 pci_vendor, pci_device;
+ u16 codec_vendor, codec_device;
if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
return;
@@ -1013,27 +1037,42 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
if (!quirk)
return;
+ if (codec->bus->pci) {
+ pci_vendor = codec->bus->pci->subsystem_vendor;
+ pci_device = codec->bus->pci->subsystem_device;
+ }
+
+ codec_vendor = codec->core.subsystem_id >> 16;
+ codec_device = codec->core.subsystem_id & 0xffff;
+
/* match with the SSID alias given by the model string "XXXX:YYYY" */
if (codec->modelname &&
sscanf(codec->modelname, "%04x:%04x", &vendor, &device) == 2) {
- q = snd_pci_quirk_lookup_id(vendor, device, quirk);
+ q = hda_quirk_lookup_id(vendor, device, quirk);
if (q) {
type = "alias SSID";
goto found_device;
}
}
- /* match with the PCI SSID */
- q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (q) {
- type = "PCI SSID";
- goto found_device;
+ /* match primarily with the PCI SSID */
+ for (q = quirk; q->subvendor || q->subdevice; q++) {
+ /* if the entry is specific to codec SSID, check with it */
+ if (!codec->bus->pci || q->match_codec_ssid) {
+ if (hda_quirk_match(codec_vendor, codec_device, q)) {
+ type = "codec SSID";
+ goto found_device;
+ }
+ } else {
+ if (hda_quirk_match(pci_vendor, pci_device, q)) {
+ type = "PCI SSID";
+ goto found_device;
+ }
+ }
}
/* match with the codec SSID */
- q = snd_pci_quirk_lookup_id(codec->core.subsystem_id >> 16,
- codec->core.subsystem_id & 0xffff,
- quirk);
+ q = hda_quirk_lookup_id(codec_vendor, codec_device, quirk);
if (q) {
type = "codec SSID";
goto found_device;