aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_analog.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r--sound/pci/hda/patch_analog.c132
1 files changed, 98 insertions, 34 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 686c77491dea..26247cfe749d 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -27,7 +27,6 @@
27#include <sound/core.h> 27#include <sound/core.h>
28#include "hda_codec.h" 28#include "hda_codec.h"
29#include "hda_local.h" 29#include "hda_local.h"
30#include "hda_patch.h"
31 30
32struct ad198x_spec { 31struct ad198x_spec {
33 struct snd_kcontrol_new *mixers[5]; 32 struct snd_kcontrol_new *mixers[5];
@@ -67,8 +66,7 @@ struct ad198x_spec {
67 66
68 /* dynamic controls, init_verbs and input_mux */ 67 /* dynamic controls, init_verbs and input_mux */
69 struct auto_pin_cfg autocfg; 68 struct auto_pin_cfg autocfg;
70 unsigned int num_kctl_alloc, num_kctl_used; 69 struct snd_array kctls;
71 struct snd_kcontrol_new *kctl_alloc;
72 struct hda_input_mux private_imux; 70 struct hda_input_mux private_imux;
73 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; 71 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
74 72
@@ -154,6 +152,8 @@ static const char *ad_slave_sws[] = {
154 NULL 152 NULL
155}; 153};
156 154
155static void ad198x_free_kctls(struct hda_codec *codec);
156
157static int ad198x_build_controls(struct hda_codec *codec) 157static int ad198x_build_controls(struct hda_codec *codec)
158{ 158{
159 struct ad198x_spec *spec = codec->spec; 159 struct ad198x_spec *spec = codec->spec;
@@ -202,6 +202,7 @@ static int ad198x_build_controls(struct hda_codec *codec)
202 return err; 202 return err;
203 } 203 }
204 204
205 ad198x_free_kctls(codec); /* no longer needed */
205 return 0; 206 return 0;
206} 207}
207 208
@@ -375,16 +376,27 @@ static int ad198x_build_pcms(struct hda_codec *codec)
375 return 0; 376 return 0;
376} 377}
377 378
378static void ad198x_free(struct hda_codec *codec) 379static void ad198x_free_kctls(struct hda_codec *codec)
379{ 380{
380 struct ad198x_spec *spec = codec->spec; 381 struct ad198x_spec *spec = codec->spec;
381 unsigned int i;
382 382
383 if (spec->kctl_alloc) { 383 if (spec->kctls.list) {
384 for (i = 0; i < spec->num_kctl_used; i++) 384 struct snd_kcontrol_new *kctl = spec->kctls.list;
385 kfree(spec->kctl_alloc[i].name); 385 int i;
386 kfree(spec->kctl_alloc); 386 for (i = 0; i < spec->kctls.used; i++)
387 kfree(kctl[i].name);
387 } 388 }
389 snd_array_free(&spec->kctls);
390}
391
392static void ad198x_free(struct hda_codec *codec)
393{
394 struct ad198x_spec *spec = codec->spec;
395
396 if (!spec)
397 return;
398
399 ad198x_free_kctls(codec);
388 kfree(codec->spec); 400 kfree(codec->spec);
389} 401}
390 402
@@ -629,6 +641,36 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
629 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), 641 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
630 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), 642 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
631 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), 643 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
644 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
645 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
646 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
647 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
648 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
649 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
650 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
651 {
652 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
653 .name = "Capture Source",
654 .info = ad198x_mux_enum_info,
655 .get = ad198x_mux_enum_get,
656 .put = ad198x_mux_enum_put,
657 },
658 {
659 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
660 .name = "External Amplifier",
661 .info = ad198x_eapd_info,
662 .get = ad198x_eapd_get,
663 .put = ad198x_eapd_put,
664 .private_value = 0x1b | (1 << 8), /* port-D, inversed */
665 },
666 { } /* end */
667};
668
669static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
670 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
671 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
672 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
673 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
632 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), 674 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
633 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), 675 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
634 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), 676 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
@@ -917,6 +959,7 @@ enum {
917 AD1986A_LAPTOP_EAPD, 959 AD1986A_LAPTOP_EAPD,
918 AD1986A_LAPTOP_AUTOMUTE, 960 AD1986A_LAPTOP_AUTOMUTE,
919 AD1986A_ULTRA, 961 AD1986A_ULTRA,
962 AD1986A_SAMSUNG,
920 AD1986A_MODELS 963 AD1986A_MODELS
921}; 964};
922 965
@@ -927,6 +970,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = {
927 [AD1986A_LAPTOP_EAPD] = "laptop-eapd", 970 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
928 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", 971 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
929 [AD1986A_ULTRA] = "ultra", 972 [AD1986A_ULTRA] = "ultra",
973 [AD1986A_SAMSUNG] = "samsung",
930}; 974};
931 975
932static struct snd_pci_quirk ad1986a_cfg_tbl[] = { 976static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
@@ -949,9 +993,9 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
949 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), 993 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
950 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), 994 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
951 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), 995 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
952 SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), 996 SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
953 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), 997 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
954 SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), 998 SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
955 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), 999 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
956 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), 1000 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
957 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), 1001 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
@@ -1033,6 +1077,17 @@ static int patch_ad1986a(struct hda_codec *codec)
1033 break; 1077 break;
1034 case AD1986A_LAPTOP_EAPD: 1078 case AD1986A_LAPTOP_EAPD:
1035 spec->mixers[0] = ad1986a_laptop_eapd_mixers; 1079 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1080 spec->num_init_verbs = 2;
1081 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1082 spec->multiout.max_channels = 2;
1083 spec->multiout.num_dacs = 1;
1084 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1085 if (!is_jack_available(codec, 0x25))
1086 spec->multiout.dig_out_nid = 0;
1087 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1088 break;
1089 case AD1986A_SAMSUNG:
1090 spec->mixers[0] = ad1986a_samsung_mixers;
1036 spec->num_init_verbs = 3; 1091 spec->num_init_verbs = 3;
1037 spec->init_verbs[1] = ad1986a_eapd_init_verbs; 1092 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1038 spec->init_verbs[2] = ad1986a_automic_verbs; 1093 spec->init_verbs[2] = ad1986a_automic_verbs;
@@ -2452,9 +2507,6 @@ static struct hda_amp_list ad1988_loopbacks[] = {
2452 * Automatic parse of I/O pins from the BIOS configuration 2507 * Automatic parse of I/O pins from the BIOS configuration
2453 */ 2508 */
2454 2509
2455#define NUM_CONTROL_ALLOC 32
2456#define NUM_VERB_ALLOC 32
2457
2458enum { 2510enum {
2459 AD_CTL_WIDGET_VOL, 2511 AD_CTL_WIDGET_VOL,
2460 AD_CTL_WIDGET_MUTE, 2512 AD_CTL_WIDGET_MUTE,
@@ -2472,27 +2524,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name,
2472{ 2524{
2473 struct snd_kcontrol_new *knew; 2525 struct snd_kcontrol_new *knew;
2474 2526
2475 if (spec->num_kctl_used >= spec->num_kctl_alloc) { 2527 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2476 int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; 2528 knew = snd_array_new(&spec->kctls);
2477 2529 if (!knew)
2478 knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ 2530 return -ENOMEM;
2479 if (! knew)
2480 return -ENOMEM;
2481 if (spec->kctl_alloc) {
2482 memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
2483 kfree(spec->kctl_alloc);
2484 }
2485 spec->kctl_alloc = knew;
2486 spec->num_kctl_alloc = num;
2487 }
2488
2489 knew = &spec->kctl_alloc[spec->num_kctl_used];
2490 *knew = ad1988_control_templates[type]; 2531 *knew = ad1988_control_templates[type];
2491 knew->name = kstrdup(name, GFP_KERNEL); 2532 knew->name = kstrdup(name, GFP_KERNEL);
2492 if (! knew->name) 2533 if (! knew->name)
2493 return -ENOMEM; 2534 return -ENOMEM;
2494 knew->private_value = val; 2535 knew->private_value = val;
2495 spec->num_kctl_used++;
2496 return 0; 2536 return 0;
2497} 2537}
2498 2538
@@ -2846,8 +2886,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec)
2846 if (spec->autocfg.dig_in_pin) 2886 if (spec->autocfg.dig_in_pin)
2847 spec->dig_in_nid = AD1988_SPDIF_IN; 2887 spec->dig_in_nid = AD1988_SPDIF_IN;
2848 2888
2849 if (spec->kctl_alloc) 2889 if (spec->kctls.list)
2850 spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 2890 spec->mixers[spec->num_mixers++] = spec->kctls.list;
2851 2891
2852 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; 2892 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
2853 2893
@@ -3861,6 +3901,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = {
3861static struct snd_pci_quirk ad1884a_cfg_tbl[] = { 3901static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
3862 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), 3902 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
3863 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), 3903 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
3904 SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
3864 SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), 3905 SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
3865 SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), 3906 SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
3866 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), 3907 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
@@ -4267,7 +4308,7 @@ static int patch_ad1882(struct hda_codec *codec)
4267/* 4308/*
4268 * patch entries 4309 * patch entries
4269 */ 4310 */
4270struct hda_codec_preset snd_hda_preset_analog[] = { 4311static struct hda_codec_preset snd_hda_preset_analog[] = {
4271 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, 4312 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
4272 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, 4313 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
4273 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, 4314 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
@@ -4285,3 +4326,26 @@ struct hda_codec_preset snd_hda_preset_analog[] = {
4285 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, 4326 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
4286 {} /* terminator */ 4327 {} /* terminator */
4287}; 4328};
4329
4330MODULE_ALIAS("snd-hda-codec-id:11d4*");
4331
4332MODULE_LICENSE("GPL");
4333MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4334
4335static struct hda_codec_preset_list analog_list = {
4336 .preset = snd_hda_preset_analog,
4337 .owner = THIS_MODULE,
4338};
4339
4340static int __init patch_analog_init(void)
4341{
4342 return snd_hda_add_codec_preset(&analog_list);
4343}
4344
4345static void __exit patch_analog_exit(void)
4346{
4347 snd_hda_delete_codec_preset(&analog_list);
4348}
4349
4350module_init(patch_analog_init)
4351module_exit(patch_analog_exit)