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