diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-07-27 13:02:40 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2007-10-16 09:58:11 -0400 |
commit | 532d5381793f3c824f8ff68d7067fab8c76bb811 (patch) | |
tree | 41a27e08a905c28576167b711ccc2b06ea234a9f /sound/pci/hda/patch_analog.c | |
parent | 2807314d467e7dd929c42050031aabbd28e78f0b (diff) |
[ALSA] hda-codec - Add a generic bind-control helper
Added callbacks for a generic bind-control of mixer elements.
This can be used for creating a mixer element controlling multiple
widgets at the same time. Two macros, HDA_BIND_VOL() and HDA_BIND_SW(),
are introduced for creating bind-volume and bind-switch, respectively.
It taks the mixer element name and struct hda_bind_ctls pointer, which
contains the real control callbacks in ops field and long array for
private_value of each bound widget.
All widgets have to be the same type (i.e. the same amp capability).
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda/patch_analog.c')
-rw-r--r-- | sound/pci/hda/patch_analog.c | 177 |
1 files changed, 41 insertions, 136 deletions
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 488724f2e304..cc2e944cc59f 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -422,94 +422,36 @@ static struct hda_input_mux ad1986a_capture_source = { | |||
422 | }, | 422 | }, |
423 | }; | 423 | }; |
424 | 424 | ||
425 | /* | ||
426 | * PCM control | ||
427 | * | ||
428 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity | ||
429 | */ | ||
430 | |||
431 | #define ad1986a_pcm_amp_vol_info snd_hda_mixer_amp_volume_info | ||
432 | |||
433 | static int ad1986a_pcm_amp_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
434 | { | ||
435 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
436 | struct ad198x_spec *ad = codec->spec; | ||
437 | |||
438 | mutex_lock(&ad->amp_mutex); | ||
439 | snd_hda_mixer_amp_volume_get(kcontrol, ucontrol); | ||
440 | mutex_unlock(&ad->amp_mutex); | ||
441 | return 0; | ||
442 | } | ||
443 | 425 | ||
444 | static int ad1986a_pcm_amp_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 426 | static struct hda_bind_ctls ad1986a_bind_pcm_vol = { |
445 | { | 427 | .ops = &snd_hda_bind_vol, |
446 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 428 | .values = { |
447 | struct ad198x_spec *ad = codec->spec; | 429 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), |
448 | int i, change = 0; | 430 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), |
449 | 431 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), | |
450 | mutex_lock(&ad->amp_mutex); | 432 | 0 |
451 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | 433 | }, |
452 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | 434 | }; |
453 | change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | ||
454 | } | ||
455 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | ||
456 | mutex_unlock(&ad->amp_mutex); | ||
457 | return change; | ||
458 | } | ||
459 | |||
460 | #define ad1986a_pcm_amp_sw_info snd_hda_mixer_amp_switch_info | ||
461 | |||
462 | static int ad1986a_pcm_amp_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
463 | { | ||
464 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
465 | struct ad198x_spec *ad = codec->spec; | ||
466 | |||
467 | mutex_lock(&ad->amp_mutex); | ||
468 | snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); | ||
469 | mutex_unlock(&ad->amp_mutex); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int ad1986a_pcm_amp_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
474 | { | ||
475 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
476 | struct ad198x_spec *ad = codec->spec; | ||
477 | int i, change = 0; | ||
478 | 435 | ||
479 | mutex_lock(&ad->amp_mutex); | 436 | static struct hda_bind_ctls ad1986a_bind_pcm_sw = { |
480 | for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) { | 437 | .ops = &snd_hda_bind_sw, |
481 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT); | 438 | .values = { |
482 | change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); | 439 | HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), |
483 | } | 440 | HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), |
484 | kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT); | 441 | HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), |
485 | mutex_unlock(&ad->amp_mutex); | 442 | 0 |
486 | return change; | 443 | }, |
487 | } | 444 | }; |
488 | 445 | ||
489 | /* | 446 | /* |
490 | * mixers | 447 | * mixers |
491 | */ | 448 | */ |
492 | static struct snd_kcontrol_new ad1986a_mixers[] = { | 449 | static struct snd_kcontrol_new ad1986a_mixers[] = { |
493 | { | 450 | /* |
494 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 451 | * bind volumes/mutes of 3 DACs as a single PCM control for simplicity |
495 | .name = "PCM Playback Volume", | 452 | */ |
496 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 453 | HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), |
497 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 454 | HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), |
498 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | ||
499 | .info = ad1986a_pcm_amp_vol_info, | ||
500 | .get = ad1986a_pcm_amp_vol_get, | ||
501 | .put = ad1986a_pcm_amp_vol_put, | ||
502 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
503 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
504 | }, | ||
505 | { | ||
506 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
507 | .name = "PCM Playback Switch", | ||
508 | .info = ad1986a_pcm_amp_sw_info, | ||
509 | .get = ad1986a_pcm_amp_sw_get, | ||
510 | .put = ad1986a_pcm_amp_sw_put, | ||
511 | .private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT) | ||
512 | }, | ||
513 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | 455 | HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), |
514 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 456 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
515 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), | 457 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), |
@@ -596,41 +538,23 @@ static struct snd_kcontrol_new ad1986a_laptop_mixers[] = { | |||
596 | /* laptop-eapd model - 2ch only */ | 538 | /* laptop-eapd model - 2ch only */ |
597 | 539 | ||
598 | /* master controls both pins 0x1a and 0x1b */ | 540 | /* master controls both pins 0x1a and 0x1b */ |
599 | static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol, | 541 | static struct hda_bind_ctls ad1986a_laptop_master_vol = { |
600 | struct snd_ctl_elem_value *ucontrol) | 542 | .ops = &snd_hda_bind_vol, |
601 | { | 543 | .values = { |
602 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 544 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), |
603 | long *valp = ucontrol->value.integer.value; | 545 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), |
604 | int change; | 546 | 0, |
605 | 547 | }, | |
606 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | 548 | }; |
607 | 0x7f, valp[0] & 0x7f); | ||
608 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | ||
609 | 0x7f, valp[1] & 0x7f); | ||
610 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | ||
611 | 0x7f, valp[0] & 0x7f); | ||
612 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | ||
613 | 0x7f, valp[1] & 0x7f); | ||
614 | return change; | ||
615 | } | ||
616 | |||
617 | static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol, | ||
618 | struct snd_ctl_elem_value *ucontrol) | ||
619 | { | ||
620 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
621 | long *valp = ucontrol->value.integer.value; | ||
622 | int change; | ||
623 | 549 | ||
624 | change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, | 550 | static struct hda_bind_ctls ad1986a_laptop_master_sw = { |
625 | 0x80, valp[0] ? 0 : 0x80); | 551 | .ops = &snd_hda_bind_sw, |
626 | change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, | 552 | .values = { |
627 | 0x80, valp[1] ? 0 : 0x80); | 553 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), |
628 | snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | 554 | HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), |
629 | 0x80, valp[0] ? 0 : 0x80); | 555 | 0, |
630 | snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | 556 | }, |
631 | 0x80, valp[1] ? 0 : 0x80); | 557 | }; |
632 | return change; | ||
633 | } | ||
634 | 558 | ||
635 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | 559 | static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { |
636 | .num_items = 3, | 560 | .num_items = 3, |
@@ -642,23 +566,8 @@ static struct hda_input_mux ad1986a_laptop_eapd_capture_source = { | |||
642 | }; | 566 | }; |
643 | 567 | ||
644 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | 568 | static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { |
645 | { | 569 | HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), |
646 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 570 | HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), |
647 | .name = "Master Playback Volume", | ||
648 | .info = snd_hda_mixer_amp_volume_info, | ||
649 | .get = snd_hda_mixer_amp_volume_get, | ||
650 | .put = ad1986a_laptop_master_vol_put, | ||
651 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
652 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
653 | }, | ||
654 | { | ||
655 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
656 | .name = "Master Playback Switch", | ||
657 | .info = snd_hda_mixer_amp_switch_info, | ||
658 | .get = snd_hda_mixer_amp_switch_get, | ||
659 | .put = ad1986a_laptop_master_sw_put, | ||
660 | .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), | ||
661 | }, | ||
662 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 571 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
663 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), | 572 | HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), |
664 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), | 573 | HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT), |
@@ -856,7 +765,6 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
856 | if (spec == NULL) | 765 | if (spec == NULL) |
857 | return -ENOMEM; | 766 | return -ENOMEM; |
858 | 767 | ||
859 | mutex_init(&spec->amp_mutex); | ||
860 | codec->spec = spec; | 768 | codec->spec = spec; |
861 | 769 | ||
862 | spec->multiout.max_channels = 6; | 770 | spec->multiout.max_channels = 6; |
@@ -1064,7 +972,6 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1064 | if (spec == NULL) | 972 | if (spec == NULL) |
1065 | return -ENOMEM; | 973 | return -ENOMEM; |
1066 | 974 | ||
1067 | mutex_init(&spec->amp_mutex); | ||
1068 | codec->spec = spec; | 975 | codec->spec = spec; |
1069 | 976 | ||
1070 | spec->multiout.max_channels = 2; | 977 | spec->multiout.max_channels = 2; |
@@ -1466,7 +1373,6 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1466 | if (spec == NULL) | 1373 | if (spec == NULL) |
1467 | return -ENOMEM; | 1374 | return -ENOMEM; |
1468 | 1375 | ||
1469 | mutex_init(&spec->amp_mutex); | ||
1470 | codec->spec = spec; | 1376 | codec->spec = spec; |
1471 | 1377 | ||
1472 | spec->multiout.max_channels = 2; | 1378 | spec->multiout.max_channels = 2; |
@@ -2672,7 +2578,6 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2672 | if (spec == NULL) | 2578 | if (spec == NULL) |
2673 | return -ENOMEM; | 2579 | return -ENOMEM; |
2674 | 2580 | ||
2675 | mutex_init(&spec->amp_mutex); | ||
2676 | codec->spec = spec; | 2581 | codec->spec = spec; |
2677 | 2582 | ||
2678 | if (is_rev2(codec)) | 2583 | if (is_rev2(codec)) |