ALSA: hda - Add a new quirk match based on default pin configuration
authorDavid Henningsson <david.henningsson@canonical.com>
Mon, 26 May 2014 08:22:41 +0000 (16:22 +0800)
committerTakashi Iwai <tiwai@suse.de>
Mon, 26 May 2014 09:03:53 +0000 (11:03 +0200)
Normally, we match on pci ssid only. This works but needs new code
for every machine. To catch more machines in the same quirk, let's add
a new type of quirk, where we match on
 1) PCI Subvendor ID (i e, not device, just vendor)
 2) Codec ID
 3) Pin configuration default

If all these three match, we could be reasonably certain that the
quirk should apply to the machine even though it might not be the
exact same device.

Signed-off-by: David Henningsson <david.henningsson@canonical.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_local.h

index 36961ab3b81dcd14c5fb5812ce857c45b667f366..a14275326234c23e4ceca1d592a90b41377ee1b1 100644 (file)
@@ -839,6 +839,43 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
 }
 EXPORT_SYMBOL_GPL(snd_hda_apply_fixup);
 
+static bool pin_config_match(struct hda_codec *codec,
+                            const struct hda_pintbl *pins)
+{
+       for (; pins->nid; pins++) {
+               u32 def_conf = snd_hda_codec_get_pincfg(codec, pins->nid);
+               if (pins->val != def_conf)
+                       return false;
+       }
+       return true;
+}
+
+void snd_hda_pick_pin_fixup(struct hda_codec *codec,
+                           const struct snd_hda_pin_quirk *pin_quirk,
+                           const struct hda_fixup *fixlist)
+{
+       const struct snd_hda_pin_quirk *pq;
+
+       if (codec->fixup_forced)
+               return;
+
+       for (pq = pin_quirk; pq->subvendor; pq++) {
+               if (codec->bus->pci->subsystem_vendor != pq->subvendor)
+                       continue;
+               if (codec->vendor_id != pq->codec)
+                       continue;
+               if (pin_config_match(codec, pq->pins)) {
+                       codec->fixup_id = pq->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+                       codec->fixup_name = pq->name;
+#endif
+                       codec->fixup_list = fixlist;
+                       return;
+               }
+       }
+}
+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,
index e51d155292155b522df246ee612e156a3d8a0a88..ebd1fa6f015cb432f568bcf8ce1c9a37c5f23324 100644 (file)
@@ -407,6 +407,16 @@ struct hda_fixup {
        } v;
 };
 
+struct snd_hda_pin_quirk {
+       unsigned int codec;             /* Codec vendor/device ID */
+       unsigned short subvendor;       /* PCI subvendor ID */
+       const struct hda_pintbl *pins;  /* list of matching pins */
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       const char *name;
+#endif
+       int value;                      /* quirk value */
+};
+
 /* fixup types */
 enum {
        HDA_FIXUP_INVALID,
@@ -434,6 +444,10 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                        const struct hda_model_fixup *models,
                        const struct snd_pci_quirk *quirk,
                        const struct hda_fixup *fixlist);
+void snd_hda_pick_pin_fixup(struct hda_codec *codec,
+                           const struct snd_hda_pin_quirk *pin_quirk,
+                           const struct hda_fixup *fixlist);
+
 
 /*
  * unsolicited event handler