aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_codec.c74
1 files changed, 34 insertions, 40 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e6efaed4b464..cb3a76139341 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -566,9 +566,10 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre
566 * amp access functions 566 * amp access functions
567 */ 567 */
568 568
569#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + (idx) * 32 + (dir) * 64) 569/* FIXME: more better hash key? */
570#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24))
570#define INFO_AMP_CAPS (1<<0) 571#define INFO_AMP_CAPS (1<<0)
571#define INFO_AMP_VOL (1<<1) 572#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
572 573
573/* initialize the hash table */ 574/* initialize the hash table */
574static void init_amp_hash(struct hda_codec *codec) 575static void init_amp_hash(struct hda_codec *codec)
@@ -627,28 +628,29 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
627 628
628/* 629/*
629 * read the current volume to info 630 * read the current volume to info
630 * if the cache exists, read from the cache. 631 * if the cache exists, read the cache value.
631 */ 632 */
632static void get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, 633static unsigned int get_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
633 hda_nid_t nid, int ch, int direction, int index) 634 hda_nid_t nid, int ch, int direction, int index)
634{ 635{
635 u32 val, parm; 636 u32 val, parm;
636 637
637 if (info->status & (INFO_AMP_VOL << ch)) 638 if (info->status & INFO_AMP_VOL(ch))
638 return; 639 return info->vol[ch];
639 640
640 parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; 641 parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
641 parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; 642 parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
642 parm |= index; 643 parm |= index;
643 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); 644 val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm);
644 info->vol[ch] = val & 0xff; 645 info->vol[ch] = val & 0xff;
645 info->status |= INFO_AMP_VOL << ch; 646 info->status |= INFO_AMP_VOL(ch);
647 return info->vol[ch];
646} 648}
647 649
648/* 650/*
649 * write the current volume in info to the h/w 651 * write the current volume in info to the h/w and update the cache
650 */ 652 */
651static void put_vol_mute(struct hda_codec *codec, 653static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
652 hda_nid_t nid, int ch, int direction, int index, int val) 654 hda_nid_t nid, int ch, int direction, int index, int val)
653{ 655{
654 u32 parm; 656 u32 parm;
@@ -658,30 +660,34 @@ static void put_vol_mute(struct hda_codec *codec,
658 parm |= index << AC_AMP_SET_INDEX_SHIFT; 660 parm |= index << AC_AMP_SET_INDEX_SHIFT;
659 parm |= val; 661 parm |= val;
660 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); 662 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
663 info->vol[ch] = val;
661} 664}
662 665
663/* 666/*
664 * read/write AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. 667 * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
665 */ 668 */
666static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) 669static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
667{ 670{
668 struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); 671 struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
669 if (! info) 672 if (! info)
670 return 0; 673 return 0;
671 get_vol_mute(codec, info, nid, ch, direction, index); 674 return get_vol_mute(codec, info, nid, ch, direction, index);
672 return info->vol[ch];
673} 675}
674 676
675static int snd_hda_codec_amp_write(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int val) 677/*
678 * update the AMP value, mask = bit mask to set, val = the value
679 */
680static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val)
676{ 681{
677 struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); 682 struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
683
678 if (! info) 684 if (! info)
679 return 0; 685 return 0;
680 get_vol_mute(codec, info, nid, ch, direction, idx); 686 val &= mask;
687 val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
681 if (info->vol[ch] == val && ! codec->in_resume) 688 if (info->vol[ch] == val && ! codec->in_resume)
682 return 0; 689 return 0;
683 put_vol_mute(codec, nid, ch, direction, idx, val); 690 put_vol_mute(codec, info, nid, ch, direction, idx, val);
684 info->vol[ch] = val;
685 return 1; 691 return 1;
686} 692}
687 693
@@ -740,21 +746,15 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
740 int chs = get_amp_channels(kcontrol); 746 int chs = get_amp_channels(kcontrol);
741 int dir = get_amp_direction(kcontrol); 747 int dir = get_amp_direction(kcontrol);
742 int idx = get_amp_index(kcontrol); 748 int idx = get_amp_index(kcontrol);
743 int val;
744 long *valp = ucontrol->value.integer.value; 749 long *valp = ucontrol->value.integer.value;
745 int change = 0; 750 int change = 0;
746 751
747 if (chs & 1) { 752 if (chs & 1)
748 val = *valp & 0x7f; 753 change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
749 val |= snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x80; 754 0x7f, *valp);
750 change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); 755 if (chs & 2)
751 valp++; 756 change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
752 } 757 0x7f, valp[1]);
753 if (chs & 2) {
754 val = *valp & 0x7f;
755 val |= snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x80;
756 change |= snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
757 }
758 return change; 758 return change;
759} 759}
760 760
@@ -793,21 +793,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
793 int chs = get_amp_channels(kcontrol); 793 int chs = get_amp_channels(kcontrol);
794 int dir = get_amp_direction(kcontrol); 794 int dir = get_amp_direction(kcontrol);
795 int idx = get_amp_index(kcontrol); 795 int idx = get_amp_index(kcontrol);
796 int val;
797 long *valp = ucontrol->value.integer.value; 796 long *valp = ucontrol->value.integer.value;
798 int change = 0; 797 int change = 0;
799 798
800 if (chs & 1) { 799 if (chs & 1)
801 val = snd_hda_codec_amp_read(codec, nid, 0, dir, idx) & 0x7f; 800 change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
802 val |= *valp ? 0 : 0x80; 801 0x80, *valp ? 0 : 0x80);
803 change = snd_hda_codec_amp_write(codec, nid, 0, dir, idx, val); 802 if (chs & 2)
804 valp++; 803 change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
805 } 804 0x80, valp[1] ? 0 : 0x80);
806 if (chs & 2) {
807 val = snd_hda_codec_amp_read(codec, nid, 1, dir, idx) & 0x7f;
808 val |= *valp ? 0 : 0x80;
809 change = snd_hda_codec_amp_write(codec, nid, 1, dir, idx, val);
810 }
811 return change; 805 return change;
812} 806}
813 807