]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * HD-audio codec driver binding | |
3 | * Copyright (c) Takashi Iwai <tiwai@suse.de> | |
4 | */ | |
5 | ||
6 | #include <linux/init.h> | |
7 | #include <linux/slab.h> | |
8 | #include <linux/mutex.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/export.h> | |
11 | #include <linux/pm.h> | |
12 | #include <linux/pm_runtime.h> | |
13 | #include <sound/core.h> | |
14 | #include "hda_codec.h" | |
15 | #include "hda_local.h" | |
16 | ||
17 | /* | |
18 | * find a matching codec id | |
19 | */ | |
20 | static int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv) | |
21 | { | |
22 | struct hda_codec *codec = container_of(dev, struct hda_codec, core); | |
23 | struct hda_codec_driver *driver = | |
24 | container_of(drv, struct hda_codec_driver, core); | |
25 | const struct hda_device_id *list; | |
26 | /* check probe_id instead of vendor_id if set */ | |
27 | u32 id = codec->probe_id ? codec->probe_id : codec->core.vendor_id; | |
28 | u32 rev_id = codec->core.revision_id; | |
29 | ||
30 | for (list = driver->id; list->vendor_id; list++) { | |
31 | if (list->vendor_id == id && | |
32 | (!list->rev_id || list->rev_id == rev_id)) { | |
33 | codec->preset = list; | |
34 | return 1; | |
35 | } | |
36 | } | |
37 | return 0; | |
38 | } | |
39 | ||
40 | /* process an unsolicited event */ | |
41 | static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev) | |
42 | { | |
43 | struct hda_codec *codec = container_of(dev, struct hda_codec, core); | |
44 | ||
45 | if (codec->patch_ops.unsol_event) | |
46 | codec->patch_ops.unsol_event(codec, ev); | |
47 | } | |
48 | ||
49 | /** | |
50 | * snd_hda_codec_set_name - set the codec name | |
51 | * @codec: the HDA codec | |
52 | * @name: name string to set | |
53 | */ | |
54 | int snd_hda_codec_set_name(struct hda_codec *codec, const char *name) | |
55 | { | |
56 | int err; | |
57 | ||
58 | if (!name) | |
59 | return 0; | |
60 | err = snd_hdac_device_set_chip_name(&codec->core, name); | |
61 | if (err < 0) | |
62 | return err; | |
63 | ||
64 | /* update the mixer name */ | |
65 | if (!*codec->card->mixername || | |
66 | codec->bus->mixer_assigned >= codec->core.addr) { | |
67 | snprintf(codec->card->mixername, | |
68 | sizeof(codec->card->mixername), "%s %s", | |
69 | codec->core.vendor_name, codec->core.chip_name); | |
70 | codec->bus->mixer_assigned = codec->core.addr; | |
71 | } | |
72 | ||
73 | return 0; | |
74 | } | |
75 | EXPORT_SYMBOL_GPL(snd_hda_codec_set_name); | |
76 | ||
77 | static int hda_codec_driver_probe(struct device *dev) | |
78 | { | |
79 | struct hda_codec *codec = dev_to_hda_codec(dev); | |
80 | struct module *owner = dev->driver->owner; | |
81 | hda_codec_patch_t patch; | |
82 | int err; | |
83 | ||
84 | if (WARN_ON(!codec->preset)) | |
85 | return -EINVAL; | |
86 | ||
87 | err = snd_hda_codec_set_name(codec, codec->preset->name); | |
88 | if (err < 0) | |
89 | goto error; | |
90 | err = snd_hdac_regmap_init(&codec->core); | |
91 | if (err < 0) | |
92 | goto error; | |
93 | ||
94 | if (!try_module_get(owner)) { | |
95 | err = -EINVAL; | |
96 | goto error; | |
97 | } | |
98 | ||
99 | patch = (hda_codec_patch_t)codec->preset->driver_data; | |
100 | if (patch) { | |
101 | err = patch(codec); | |
102 | if (err < 0) | |
103 | goto error_module; | |
104 | } | |
105 | ||
106 | err = snd_hda_codec_build_pcms(codec); | |
107 | if (err < 0) | |
108 | goto error_module; | |
109 | err = snd_hda_codec_build_controls(codec); | |
110 | if (err < 0) | |
111 | goto error_module; | |
112 | if (codec->card->registered) { | |
113 | err = snd_card_register(codec->card); | |
114 | if (err < 0) | |
115 | goto error_module; | |
116 | snd_hda_codec_register(codec); | |
117 | } | |
118 | ||
119 | codec->core.lazy_cache = true; | |
120 | return 0; | |
121 | ||
122 | error_module: | |
123 | module_put(owner); | |
124 | ||
125 | error: | |
126 | snd_hda_codec_cleanup_for_unbind(codec); | |
127 | return err; | |
128 | } | |
129 | ||
130 | static int hda_codec_driver_remove(struct device *dev) | |
131 | { | |
132 | struct hda_codec *codec = dev_to_hda_codec(dev); | |
133 | ||
134 | if (codec->patch_ops.free) | |
135 | codec->patch_ops.free(codec); | |
136 | snd_hda_codec_cleanup_for_unbind(codec); | |
137 | module_put(dev->driver->owner); | |
138 | return 0; | |
139 | } | |
140 | ||
141 | static void hda_codec_driver_shutdown(struct device *dev) | |
142 | { | |
143 | struct hda_codec *codec = dev_to_hda_codec(dev); | |
144 | ||
145 | if (!pm_runtime_suspended(dev) && codec->patch_ops.reboot_notify) | |
146 | codec->patch_ops.reboot_notify(codec); | |
147 | } | |
148 | ||
149 | int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, | |
150 | struct module *owner) | |
151 | { | |
152 | drv->core.driver.name = name; | |
153 | drv->core.driver.owner = owner; | |
154 | drv->core.driver.bus = &snd_hda_bus_type; | |
155 | drv->core.driver.probe = hda_codec_driver_probe; | |
156 | drv->core.driver.remove = hda_codec_driver_remove; | |
157 | drv->core.driver.shutdown = hda_codec_driver_shutdown; | |
158 | drv->core.driver.pm = &hda_codec_driver_pm; | |
159 | drv->core.type = HDA_DEV_LEGACY; | |
160 | drv->core.match = hda_codec_match; | |
161 | drv->core.unsol_event = hda_codec_unsol_event; | |
162 | return driver_register(&drv->core.driver); | |
163 | } | |
164 | EXPORT_SYMBOL_GPL(__hda_codec_driver_register); | |
165 | ||
166 | void hda_codec_driver_unregister(struct hda_codec_driver *drv) | |
167 | { | |
168 | driver_unregister(&drv->core.driver); | |
169 | } | |
170 | EXPORT_SYMBOL_GPL(hda_codec_driver_unregister); | |
171 | ||
172 | static inline bool codec_probed(struct hda_codec *codec) | |
173 | { | |
174 | return device_attach(hda_codec_dev(codec)) > 0 && codec->preset; | |
175 | } | |
176 | ||
177 | /* try to auto-load codec module */ | |
178 | static void request_codec_module(struct hda_codec *codec) | |
179 | { | |
180 | #ifdef MODULE | |
181 | char modalias[32]; | |
182 | const char *mod = NULL; | |
183 | ||
184 | switch (codec->probe_id) { | |
185 | case HDA_CODEC_ID_GENERIC_HDMI: | |
186 | #if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) | |
187 | mod = "snd-hda-codec-hdmi"; | |
188 | #endif | |
189 | break; | |
190 | case HDA_CODEC_ID_GENERIC: | |
191 | #if IS_MODULE(CONFIG_SND_HDA_GENERIC) | |
192 | mod = "snd-hda-codec-generic"; | |
193 | #endif | |
194 | break; | |
195 | default: | |
196 | snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); | |
197 | mod = modalias; | |
198 | break; | |
199 | } | |
200 | ||
201 | if (mod) | |
202 | request_module(mod); | |
203 | #endif /* MODULE */ | |
204 | } | |
205 | ||
206 | /* try to auto-load and bind the codec module */ | |
207 | static void codec_bind_module(struct hda_codec *codec) | |
208 | { | |
209 | #ifdef MODULE | |
210 | request_codec_module(codec); | |
211 | if (codec_probed(codec)) | |
212 | return; | |
213 | #endif | |
214 | } | |
215 | ||
216 | #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) | |
217 | /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ | |
218 | static bool is_likely_hdmi_codec(struct hda_codec *codec) | |
219 | { | |
220 | hda_nid_t nid; | |
221 | ||
222 | for_each_hda_codec_node(nid, codec) { | |
223 | unsigned int wcaps = get_wcaps(codec, nid); | |
224 | switch (get_wcaps_type(wcaps)) { | |
225 | case AC_WID_AUD_IN: | |
226 | return false; /* HDMI parser supports only HDMI out */ | |
227 | case AC_WID_AUD_OUT: | |
228 | if (!(wcaps & AC_WCAP_DIGITAL)) | |
229 | return false; | |
230 | break; | |
231 | } | |
232 | } | |
233 | return true; | |
234 | } | |
235 | #else | |
236 | /* no HDMI codec parser support */ | |
237 | #define is_likely_hdmi_codec(codec) false | |
238 | #endif /* CONFIG_SND_HDA_CODEC_HDMI */ | |
239 | ||
240 | static int codec_bind_generic(struct hda_codec *codec) | |
241 | { | |
242 | if (codec->probe_id) | |
243 | return -ENODEV; | |
244 | ||
245 | if (is_likely_hdmi_codec(codec)) { | |
246 | codec->probe_id = HDA_CODEC_ID_GENERIC_HDMI; | |
247 | request_codec_module(codec); | |
248 | if (codec_probed(codec)) | |
249 | return 0; | |
250 | } | |
251 | ||
252 | codec->probe_id = HDA_CODEC_ID_GENERIC; | |
253 | request_codec_module(codec); | |
254 | if (codec_probed(codec)) | |
255 | return 0; | |
256 | return -ENODEV; | |
257 | } | |
258 | ||
259 | #if IS_ENABLED(CONFIG_SND_HDA_GENERIC) | |
260 | #define is_generic_config(codec) \ | |
261 | (codec->modelname && !strcmp(codec->modelname, "generic")) | |
262 | #else | |
263 | #define is_generic_config(codec) 0 | |
264 | #endif | |
265 | ||
266 | /** | |
267 | * snd_hda_codec_configure - (Re-)configure the HD-audio codec | |
268 | * @codec: the HDA codec | |
269 | * | |
270 | * Start parsing of the given codec tree and (re-)initialize the whole | |
271 | * patch instance. | |
272 | * | |
273 | * Returns 0 if successful or a negative error code. | |
274 | */ | |
275 | int snd_hda_codec_configure(struct hda_codec *codec) | |
276 | { | |
277 | int err; | |
278 | ||
279 | if (is_generic_config(codec)) | |
280 | codec->probe_id = HDA_CODEC_ID_GENERIC; | |
281 | else | |
282 | codec->probe_id = 0; | |
283 | ||
284 | err = snd_hdac_device_register(&codec->core); | |
285 | if (err < 0) | |
286 | return err; | |
287 | ||
288 | if (!codec->preset) | |
289 | codec_bind_module(codec); | |
290 | if (!codec->preset) { | |
291 | err = codec_bind_generic(codec); | |
292 | if (err < 0) { | |
293 | codec_err(codec, "Unable to bind the codec\n"); | |
294 | goto error; | |
295 | } | |
296 | } | |
297 | ||
298 | return 0; | |
299 | ||
300 | error: | |
301 | snd_hdac_device_unregister(&codec->core); | |
302 | return err; | |
303 | } | |
304 | EXPORT_SYMBOL_GPL(snd_hda_codec_configure); |