aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/hda/hda_codec.c89
-rw-r--r--sound/pci/hda/hda_codec.h24
2 files changed, 68 insertions, 45 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index fc934baaae65..46f8ab1df874 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -494,6 +494,10 @@ static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
494} 494}
495 495
496 496
497static void init_hda_cache(struct hda_cache_rec *cache,
498 unsigned int record_size);
499static inline void free_hda_cache(struct hda_cache_rec *cache);
500
497/* 501/*
498 * codec destructor 502 * codec destructor
499 */ 503 */
@@ -505,13 +509,11 @@ static void snd_hda_codec_free(struct hda_codec *codec)
505 codec->bus->caddr_tbl[codec->addr] = NULL; 509 codec->bus->caddr_tbl[codec->addr] = NULL;
506 if (codec->patch_ops.free) 510 if (codec->patch_ops.free)
507 codec->patch_ops.free(codec); 511 codec->patch_ops.free(codec);
508 kfree(codec->amp_info); 512 free_hda_cache(&codec->amp_cache);
509 kfree(codec->wcaps); 513 kfree(codec->wcaps);
510 kfree(codec); 514 kfree(codec);
511} 515}
512 516
513static void init_amp_hash(struct hda_codec *codec);
514
515/** 517/**
516 * snd_hda_codec_new - create a HDA codec 518 * snd_hda_codec_new - create a HDA codec
517 * @bus: the bus to assign 519 * @bus: the bus to assign
@@ -545,7 +547,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
545 codec->bus = bus; 547 codec->bus = bus;
546 codec->addr = codec_addr; 548 codec->addr = codec_addr;
547 mutex_init(&codec->spdif_mutex); 549 mutex_init(&codec->spdif_mutex);
548 init_amp_hash(codec); 550 init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
549 551
550 list_add_tail(&codec->list, &bus->codec_list); 552 list_add_tail(&codec->list, &bus->codec_list);
551 bus->caddr_tbl[codec_addr] = codec; 553 bus->caddr_tbl[codec_addr] = codec;
@@ -664,59 +666,72 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
664#define INFO_AMP_VOL(ch) (1 << (1 + (ch))) 666#define INFO_AMP_VOL(ch) (1 << (1 + (ch)))
665 667
666/* initialize the hash table */ 668/* initialize the hash table */
667static void __devinit init_amp_hash(struct hda_codec *codec) 669static void __devinit init_hda_cache(struct hda_cache_rec *cache,
670 unsigned int record_size)
671{
672 memset(cache, 0, sizeof(*cache));
673 memset(cache->hash, 0xff, sizeof(cache->hash));
674 cache->record_size = record_size;
675}
676
677static inline void free_hda_cache(struct hda_cache_rec *cache)
668{ 678{
669 memset(codec->amp_hash, 0xff, sizeof(codec->amp_hash)); 679 kfree(cache->buffer);
670 codec->num_amp_entries = 0;
671 codec->amp_info_size = 0;
672 codec->amp_info = NULL;
673} 680}
674 681
675/* query the hash. allocate an entry if not found. */ 682/* query the hash. allocate an entry if not found. */
676static struct hda_amp_info *get_alloc_amp_hash(struct hda_codec *codec, u32 key) 683static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache,
684 u32 key)
677{ 685{
678 u16 idx = key % (u16)ARRAY_SIZE(codec->amp_hash); 686 u16 idx = key % (u16)ARRAY_SIZE(cache->hash);
679 u16 cur = codec->amp_hash[idx]; 687 u16 cur = cache->hash[idx];
680 struct hda_amp_info *info; 688 struct hda_cache_head *info;
681 689
682 while (cur != 0xffff) { 690 while (cur != 0xffff) {
683 info = &codec->amp_info[cur]; 691 info = (struct hda_cache_head *)(cache->buffer +
692 cur * cache->record_size);
684 if (info->key == key) 693 if (info->key == key)
685 return info; 694 return info;
686 cur = info->next; 695 cur = info->next;
687 } 696 }
688 697
689 /* add a new hash entry */ 698 /* add a new hash entry */
690 if (codec->num_amp_entries >= codec->amp_info_size) { 699 if (cache->num_entries >= cache->size) {
691 /* reallocate the array */ 700 /* reallocate the array */
692 int new_size = codec->amp_info_size + 64; 701 unsigned int new_size = cache->size + 64;
693 struct hda_amp_info *new_info; 702 void *new_buffer;
694 new_info = kcalloc(new_size, sizeof(struct hda_amp_info), 703 new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL);
695 GFP_KERNEL); 704 if (!new_buffer) {
696 if (!new_info) {
697 snd_printk(KERN_ERR "hda_codec: " 705 snd_printk(KERN_ERR "hda_codec: "
698 "can't malloc amp_info\n"); 706 "can't malloc amp_info\n");
699 return NULL; 707 return NULL;
700 } 708 }
701 if (codec->amp_info) { 709 if (cache->buffer) {
702 memcpy(new_info, codec->amp_info, 710 memcpy(new_buffer, cache->buffer,
703 codec->amp_info_size * 711 cache->size * cache->record_size);
704 sizeof(struct hda_amp_info)); 712 kfree(cache->buffer);
705 kfree(codec->amp_info);
706 } 713 }
707 codec->amp_info_size = new_size; 714 cache->size = new_size;
708 codec->amp_info = new_info; 715 cache->buffer = new_buffer;
709 } 716 }
710 cur = codec->num_amp_entries++; 717 cur = cache->num_entries++;
711 info = &codec->amp_info[cur]; 718 info = (struct hda_cache_head *)(cache->buffer +
719 cur * cache->record_size);
712 info->key = key; 720 info->key = key;
713 info->status = 0; /* not initialized yet */ 721 info->val = 0;
714 info->next = codec->amp_hash[idx]; 722 info->next = cache->hash[idx];
715 codec->amp_hash[idx] = cur; 723 cache->hash[idx] = cur;
716 724
717 return info; 725 return info;
718} 726}
719 727
728/* query and allocate an amp hash entry */
729static inline struct hda_amp_info *
730get_alloc_amp_hash(struct hda_codec *codec, u32 key)
731{
732 return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
733}
734
720/* 735/*
721 * query AMP capabilities for the given widget and direction 736 * query AMP capabilities for the given widget and direction
722 */ 737 */
@@ -727,7 +742,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
727 info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); 742 info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0));
728 if (!info) 743 if (!info)
729 return 0; 744 return 0;
730 if (!(info->status & INFO_AMP_CAPS)) { 745 if (!(info->head.val & INFO_AMP_CAPS)) {
731 if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) 746 if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
732 nid = codec->afg; 747 nid = codec->afg;
733 info->amp_caps = snd_hda_param_read(codec, nid, 748 info->amp_caps = snd_hda_param_read(codec, nid,
@@ -735,7 +750,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
735 AC_PAR_AMP_OUT_CAP : 750 AC_PAR_AMP_OUT_CAP :
736 AC_PAR_AMP_IN_CAP); 751 AC_PAR_AMP_IN_CAP);
737 if (info->amp_caps) 752 if (info->amp_caps)
738 info->status |= INFO_AMP_CAPS; 753 info->head.val |= INFO_AMP_CAPS;
739 } 754 }
740 return info->amp_caps; 755 return info->amp_caps;
741} 756}
@@ -749,7 +764,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
749 if (!info) 764 if (!info)
750 return -EINVAL; 765 return -EINVAL;
751 info->amp_caps = caps; 766 info->amp_caps = caps;
752 info->status |= INFO_AMP_CAPS; 767 info->head.val |= INFO_AMP_CAPS;
753 return 0; 768 return 0;
754} 769}
755 770
@@ -763,7 +778,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec,
763{ 778{
764 u32 val, parm; 779 u32 val, parm;
765 780
766 if (info->status & INFO_AMP_VOL(ch)) 781 if (info->head.val & INFO_AMP_VOL(ch))
767 return info->vol[ch]; 782 return info->vol[ch];
768 783
769 parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; 784 parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
@@ -772,7 +787,7 @@ static unsigned int get_vol_mute(struct hda_codec *codec,
772 val = snd_hda_codec_read(codec, nid, 0, 787 val = snd_hda_codec_read(codec, nid, 0,
773 AC_VERB_GET_AMP_GAIN_MUTE, parm); 788 AC_VERB_GET_AMP_GAIN_MUTE, parm);
774 info->vol[ch] = val & 0xff; 789 info->vol[ch] = val & 0xff;
775 info->status |= INFO_AMP_VOL(ch); 790 info->head.val |= INFO_AMP_VOL(ch);
776 return info->vol[ch]; 791 return info->vol[ch];
777} 792}
778 793
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 1370e346bf34..1a69743160ce 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -480,12 +480,24 @@ struct hda_codec_ops {
480}; 480};
481 481
482/* record for amp information cache */ 482/* record for amp information cache */
483struct hda_amp_info { 483struct hda_cache_head {
484 u32 key; /* hash key */ 484 u32 key; /* hash key */
485 u16 val; /* assigned value */
486 u16 next; /* next link; -1 = terminal */
487};
488
489struct hda_amp_info {
490 struct hda_cache_head head;
485 u32 amp_caps; /* amp capabilities */ 491 u32 amp_caps; /* amp capabilities */
486 u16 vol[2]; /* current volume & mute */ 492 u16 vol[2]; /* current volume & mute */
487 u16 status; /* update flag */ 493};
488 u16 next; /* next link */ 494
495struct hda_cache_rec {
496 u16 hash[64]; /* hash table for index */
497 unsigned int num_entries; /* number of assigned entries */
498 unsigned int size; /* allocated size */
499 unsigned int record_size; /* record size (including header) */
500 void *buffer; /* hash table entries */
489}; 501};
490 502
491/* PCM callbacks */ 503/* PCM callbacks */
@@ -557,11 +569,7 @@ struct hda_codec {
557 hda_nid_t start_nid; 569 hda_nid_t start_nid;
558 u32 *wcaps; 570 u32 *wcaps;
559 571
560 /* hash for amp access */ 572 struct hda_cache_rec amp_cache; /* cache for amp access */
561 u16 amp_hash[32];
562 int num_amp_entries;
563 int amp_info_size;
564 struct hda_amp_info *amp_info;
565 573
566 struct mutex spdif_mutex; 574 struct mutex spdif_mutex;
567 unsigned int spdif_status; /* IEC958 status bits */ 575 unsigned int spdif_status; /* IEC958 status bits */