blob: 7cc3a16882409255fb44760755bc1a5db29d4d7f [file] [log] [blame]
Takashi Iwai23d30f22012-05-07 17:17:32 +02001/*
2 * BIOS auto-parser helper functions for HD-audio
3 *
4 * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
5 *
6 * This driver is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/slab.h>
13#include <linux/export.h>
14#include <sound/core.h>
15#include "hda_codec.h"
16#include "hda_auto_parser.h"
17
18#define SFX "hda_codec: "
19
20int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
21 const struct hda_verb *list)
22{
23 const struct hda_verb **v;
24 snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
25 v = snd_array_new(&spec->verbs);
26 if (!v)
27 return -ENOMEM;
28 *v = list;
29 return 0;
30}
31EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
32
33void snd_hda_gen_apply_verbs(struct hda_codec *codec)
34{
35 struct hda_gen_spec *spec = codec->spec;
36 int i;
37 for (i = 0; i < spec->verbs.used; i++) {
38 struct hda_verb **v = snd_array_elem(&spec->verbs, i);
39 snd_hda_sequence_write(codec, *v);
40 }
41}
42EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
43
44void snd_hda_apply_pincfgs(struct hda_codec *codec,
45 const struct hda_pintbl *cfg)
46{
47 for (; cfg->nid; cfg++)
48 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
49}
50EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
51
52void snd_hda_apply_fixup(struct hda_codec *codec, int action)
53{
54 struct hda_gen_spec *spec = codec->spec;
55 int id = spec->fixup_id;
56#ifdef CONFIG_SND_DEBUG_VERBOSE
57 const char *modelname = spec->fixup_name;
58#endif
59 int depth = 0;
60
61 if (!spec->fixup_list)
62 return;
63
64 while (id >= 0) {
65 const struct hda_fixup *fix = spec->fixup_list + id;
66
67 switch (fix->type) {
68 case HDA_FIXUP_PINS:
69 if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
70 break;
71 snd_printdd(KERN_INFO SFX
72 "%s: Apply pincfg for %s\n",
73 codec->chip_name, modelname);
74 snd_hda_apply_pincfgs(codec, fix->v.pins);
75 break;
76 case HDA_FIXUP_VERBS:
77 if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
78 break;
79 snd_printdd(KERN_INFO SFX
80 "%s: Apply fix-verbs for %s\n",
81 codec->chip_name, modelname);
82 snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
83 break;
84 case HDA_FIXUP_FUNC:
85 if (!fix->v.func)
86 break;
87 snd_printdd(KERN_INFO SFX
88 "%s: Apply fix-func for %s\n",
89 codec->chip_name, modelname);
90 fix->v.func(codec, fix, action);
91 break;
92 default:
93 snd_printk(KERN_ERR SFX
94 "%s: Invalid fixup type %d\n",
95 codec->chip_name, fix->type);
96 break;
97 }
98 if (!fix->chained)
99 break;
100 if (++depth > 10)
101 break;
102 id = fix->chain_id;
103 }
104}
105EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
106
107void snd_hda_pick_fixup(struct hda_codec *codec,
108 const struct hda_model_fixup *models,
109 const struct snd_pci_quirk *quirk,
110 const struct hda_fixup *fixlist)
111{
112 struct hda_gen_spec *spec = codec->spec;
113 const struct snd_pci_quirk *q;
114 int id = -1;
115 const char *name = NULL;
116
117 /* when model=nofixup is given, don't pick up any fixups */
118 if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
119 spec->fixup_list = NULL;
120 spec->fixup_id = -1;
121 return;
122 }
123
124 if (codec->modelname && models) {
125 while (models->name) {
126 if (!strcmp(codec->modelname, models->name)) {
127 id = models->id;
128 name = models->name;
129 break;
130 }
131 models++;
132 }
133 }
134 if (id < 0) {
135 q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
136 if (q) {
137 id = q->value;
138#ifdef CONFIG_SND_DEBUG_VERBOSE
139 name = q->name;
140#endif
141 }
142 }
143 if (id < 0) {
144 for (q = quirk; q->subvendor; q++) {
145 unsigned int vendorid =
146 q->subdevice | (q->subvendor << 16);
147 if (vendorid == codec->subsystem_id) {
148 id = q->value;
149#ifdef CONFIG_SND_DEBUG_VERBOSE
150 name = q->name;
151#endif
152 break;
153 }
154 }
155 }
156
157 spec->fixup_id = id;
158 if (id >= 0) {
159 spec->fixup_list = fixlist;
160 spec->fixup_name = name;
161 }
162}
163EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);