diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 147 |
1 files changed, 100 insertions, 47 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index bc3ed249b0f..5b54ac07fcb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -344,7 +344,7 @@ static void process_unsol_events(struct work_struct *work) | |||
344 | /* | 344 | /* |
345 | * initialize unsolicited queue | 345 | * initialize unsolicited queue |
346 | */ | 346 | */ |
347 | static int __devinit init_unsol_queue(struct hda_bus *bus) | 347 | static int init_unsol_queue(struct hda_bus *bus) |
348 | { | 348 | { |
349 | struct hda_bus_unsolicited *unsol; | 349 | struct hda_bus_unsolicited *unsol; |
350 | 350 | ||
@@ -454,7 +454,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, | |||
454 | /* | 454 | /* |
455 | * find a matching codec preset | 455 | * find a matching codec preset |
456 | */ | 456 | */ |
457 | static const struct hda_codec_preset __devinit * | 457 | static const struct hda_codec_preset * |
458 | find_codec_preset(struct hda_codec *codec) | 458 | find_codec_preset(struct hda_codec *codec) |
459 | { | 459 | { |
460 | const struct hda_codec_preset **tbl, *preset; | 460 | const struct hda_codec_preset **tbl, *preset; |
@@ -624,6 +624,13 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
624 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 624 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
625 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 625 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
626 | snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); | 626 | snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); |
627 | if (codec->bus->modelname) { | ||
628 | codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); | ||
629 | if (!codec->modelname) { | ||
630 | snd_hda_codec_free(codec); | ||
631 | return -ENODEV; | ||
632 | } | ||
633 | } | ||
627 | 634 | ||
628 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 635 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
629 | INIT_DELAYED_WORK(&codec->power_work, hda_power_work); | 636 | INIT_DELAYED_WORK(&codec->power_work, hda_power_work); |
@@ -672,6 +679,30 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
672 | if (bus->modelname) | 679 | if (bus->modelname) |
673 | codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); | 680 | codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); |
674 | 681 | ||
682 | err = snd_hda_codec_configure(codec); | ||
683 | if (err < 0) { | ||
684 | snd_hda_codec_free(codec); | ||
685 | return err; | ||
686 | } | ||
687 | snd_hda_codec_proc_new(codec); | ||
688 | |||
689 | #ifdef CONFIG_SND_HDA_HWDEP | ||
690 | snd_hda_create_hwdep(codec); | ||
691 | #endif | ||
692 | |||
693 | sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, | ||
694 | codec->subsystem_id, codec->revision_id); | ||
695 | snd_component_add(codec->bus->card, component); | ||
696 | |||
697 | if (codecp) | ||
698 | *codecp = codec; | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | int snd_hda_codec_configure(struct hda_codec *codec) | ||
703 | { | ||
704 | int err; | ||
705 | |||
675 | codec->preset = find_codec_preset(codec); | 706 | codec->preset = find_codec_preset(codec); |
676 | if (!codec->name) { | 707 | if (!codec->name) { |
677 | err = get_codec_name(codec); | 708 | err = get_codec_name(codec); |
@@ -698,25 +729,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
698 | printk(KERN_ERR "hda-codec: No codec parser is available\n"); | 729 | printk(KERN_ERR "hda-codec: No codec parser is available\n"); |
699 | 730 | ||
700 | patched: | 731 | patched: |
701 | if (err < 0) { | 732 | if (!err && codec->patch_ops.unsol_event) |
702 | snd_hda_codec_free(codec); | 733 | err = init_unsol_queue(codec->bus); |
703 | return err; | 734 | return err; |
704 | } | ||
705 | |||
706 | if (codec->patch_ops.unsol_event) | ||
707 | init_unsol_queue(bus); | ||
708 | |||
709 | snd_hda_codec_proc_new(codec); | ||
710 | #ifdef CONFIG_SND_HDA_HWDEP | ||
711 | snd_hda_create_hwdep(codec); | ||
712 | #endif | ||
713 | |||
714 | sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); | ||
715 | snd_component_add(codec->bus->card, component); | ||
716 | |||
717 | if (codecp) | ||
718 | *codecp = codec; | ||
719 | return 0; | ||
720 | } | 735 | } |
721 | 736 | ||
722 | /** | 737 | /** |
@@ -1118,6 +1133,31 @@ void snd_hda_ctls_clear(struct hda_codec *codec) | |||
1118 | snd_array_free(&codec->mixers); | 1133 | snd_array_free(&codec->mixers); |
1119 | } | 1134 | } |
1120 | 1135 | ||
1136 | void snd_hda_codec_reset(struct hda_codec *codec) | ||
1137 | { | ||
1138 | int i; | ||
1139 | |||
1140 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1141 | cancel_delayed_work(&codec->power_work); | ||
1142 | flush_scheduled_work(); | ||
1143 | #endif | ||
1144 | snd_hda_ctls_clear(codec); | ||
1145 | /* relase PCMs */ | ||
1146 | for (i = 0; i < codec->num_pcms; i++) { | ||
1147 | if (codec->pcm_info[i].pcm) | ||
1148 | snd_device_free(codec->bus->card, | ||
1149 | codec->pcm_info[i].pcm); | ||
1150 | } | ||
1151 | if (codec->patch_ops.free) | ||
1152 | codec->patch_ops.free(codec); | ||
1153 | codec->spec = NULL; | ||
1154 | free_hda_cache(&codec->amp_cache); | ||
1155 | free_hda_cache(&codec->cmd_cache); | ||
1156 | codec->num_pcms = 0; | ||
1157 | codec->pcm_info = NULL; | ||
1158 | codec->preset = NULL; | ||
1159 | } | ||
1160 | |||
1121 | /* create a virtual master control and add slaves */ | 1161 | /* create a virtual master control and add slaves */ |
1122 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | 1162 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, |
1123 | unsigned int *tlv, const char **slaves) | 1163 | unsigned int *tlv, const char **slaves) |
@@ -1939,23 +1979,30 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) | |||
1939 | struct hda_codec *codec; | 1979 | struct hda_codec *codec; |
1940 | 1980 | ||
1941 | list_for_each_entry(codec, &bus->codec_list, list) { | 1981 | list_for_each_entry(codec, &bus->codec_list, list) { |
1942 | int err = 0; | 1982 | int err = snd_hda_codec_build_controls(codec); |
1943 | /* fake as if already powered-on */ | ||
1944 | hda_keep_power_on(codec); | ||
1945 | /* then fire up */ | ||
1946 | hda_set_power_state(codec, | ||
1947 | codec->afg ? codec->afg : codec->mfg, | ||
1948 | AC_PWRST_D0); | ||
1949 | /* continue to initialize... */ | ||
1950 | if (codec->patch_ops.init) | ||
1951 | err = codec->patch_ops.init(codec); | ||
1952 | if (!err && codec->patch_ops.build_controls) | ||
1953 | err = codec->patch_ops.build_controls(codec); | ||
1954 | snd_hda_power_down(codec); | ||
1955 | if (err < 0) | 1983 | if (err < 0) |
1956 | return err; | 1984 | return err; |
1957 | } | 1985 | } |
1986 | return 0; | ||
1987 | } | ||
1958 | 1988 | ||
1989 | int snd_hda_codec_build_controls(struct hda_codec *codec) | ||
1990 | { | ||
1991 | int err = 0; | ||
1992 | /* fake as if already powered-on */ | ||
1993 | hda_keep_power_on(codec); | ||
1994 | /* then fire up */ | ||
1995 | hda_set_power_state(codec, | ||
1996 | codec->afg ? codec->afg : codec->mfg, | ||
1997 | AC_PWRST_D0); | ||
1998 | /* continue to initialize... */ | ||
1999 | if (codec->patch_ops.init) | ||
2000 | err = codec->patch_ops.init(codec); | ||
2001 | if (!err && codec->patch_ops.build_controls) | ||
2002 | err = codec->patch_ops.build_controls(codec); | ||
2003 | snd_hda_power_down(codec); | ||
2004 | if (err < 0) | ||
2005 | return err; | ||
1959 | return 0; | 2006 | return 0; |
1960 | } | 2007 | } |
1961 | 2008 | ||
@@ -2256,8 +2303,8 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, | |||
2256 | return 0; | 2303 | return 0; |
2257 | } | 2304 | } |
2258 | 2305 | ||
2259 | static int __devinit set_pcm_default_values(struct hda_codec *codec, | 2306 | static int set_pcm_default_values(struct hda_codec *codec, |
2260 | struct hda_pcm_stream *info) | 2307 | struct hda_pcm_stream *info) |
2261 | { | 2308 | { |
2262 | /* query support PCM information from the given NID */ | 2309 | /* query support PCM information from the given NID */ |
2263 | if (info->nid && (!info->rates || !info->formats)) { | 2310 | if (info->nid && (!info->rates || !info->formats)) { |
@@ -2331,7 +2378,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) | |||
2331 | * | 2378 | * |
2332 | * This function returns 0 if successfull, or a negative error code. | 2379 | * This function returns 0 if successfull, or a negative error code. |
2333 | */ | 2380 | */ |
2334 | int __devinit snd_hda_build_pcms(struct hda_bus *bus) | 2381 | int snd_hda_build_pcms(struct hda_bus *bus) |
2335 | { | 2382 | { |
2336 | static const char *dev_name[HDA_PCM_NTYPES] = { | 2383 | static const char *dev_name[HDA_PCM_NTYPES] = { |
2337 | "Audio", "SPDIF", "HDMI", "Modem" | 2384 | "Audio", "SPDIF", "HDMI", "Modem" |
@@ -2352,14 +2399,17 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) | |||
2352 | list_for_each_entry(codec, &bus->codec_list, list) { | 2399 | list_for_each_entry(codec, &bus->codec_list, list) { |
2353 | unsigned int pcm; | 2400 | unsigned int pcm; |
2354 | int err; | 2401 | int err; |
2355 | if (!codec->patch_ops.build_pcms) | 2402 | if (!codec->num_pcms) { |
2356 | continue; | 2403 | if (!codec->patch_ops.build_pcms) |
2357 | err = codec->patch_ops.build_pcms(codec); | 2404 | continue; |
2358 | if (err < 0) | 2405 | err = codec->patch_ops.build_pcms(codec); |
2359 | return err; | 2406 | if (err < 0) |
2407 | return err; | ||
2408 | } | ||
2360 | for (pcm = 0; pcm < codec->num_pcms; pcm++) { | 2409 | for (pcm = 0; pcm < codec->num_pcms; pcm++) { |
2361 | struct hda_pcm *cpcm = &codec->pcm_info[pcm]; | 2410 | struct hda_pcm *cpcm = &codec->pcm_info[pcm]; |
2362 | int type = cpcm->pcm_type; | 2411 | int type = cpcm->pcm_type; |
2412 | int dev; | ||
2363 | switch (type) { | 2413 | switch (type) { |
2364 | case HDA_PCM_TYPE_AUDIO: | 2414 | case HDA_PCM_TYPE_AUDIO: |
2365 | if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { | 2415 | if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { |
@@ -2367,7 +2417,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) | |||
2367 | "Too many audio devices\n"); | 2417 | "Too many audio devices\n"); |
2368 | continue; | 2418 | continue; |
2369 | } | 2419 | } |
2370 | cpcm->device = audio_idx[num_devs[type]]; | 2420 | dev = audio_idx[num_devs[type]]; |
2371 | break; | 2421 | break; |
2372 | case HDA_PCM_TYPE_SPDIF: | 2422 | case HDA_PCM_TYPE_SPDIF: |
2373 | case HDA_PCM_TYPE_HDMI: | 2423 | case HDA_PCM_TYPE_HDMI: |
@@ -2378,7 +2428,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) | |||
2378 | dev_name[type]); | 2428 | dev_name[type]); |
2379 | continue; | 2429 | continue; |
2380 | } | 2430 | } |
2381 | cpcm->device = dev_idx[type]; | 2431 | dev = dev_idx[type]; |
2382 | break; | 2432 | break; |
2383 | default: | 2433 | default: |
2384 | snd_printk(KERN_WARNING | 2434 | snd_printk(KERN_WARNING |
@@ -2386,9 +2436,12 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) | |||
2386 | continue; | 2436 | continue; |
2387 | } | 2437 | } |
2388 | num_devs[type]++; | 2438 | num_devs[type]++; |
2389 | err = snd_hda_attach_pcm(codec, cpcm); | 2439 | if (!cpcm->pcm) { |
2390 | if (err < 0) | 2440 | cpcm->device = dev; |
2391 | return err; | 2441 | err = snd_hda_attach_pcm(codec, cpcm); |
2442 | if (err < 0) | ||
2443 | return err; | ||
2444 | } | ||
2392 | } | 2445 | } |
2393 | } | 2446 | } |
2394 | return 0; | 2447 | return 0; |