diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a4e5e5952115..3d8bf39e6d98 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1053,6 +1053,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); | |||
1053 | /* FIXME: more better hash key? */ | 1053 | /* FIXME: more better hash key? */ |
1054 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) | 1054 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) |
1055 | #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) | 1055 | #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) |
1056 | #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) | ||
1057 | #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) | ||
1056 | #define INFO_AMP_CAPS (1<<0) | 1058 | #define INFO_AMP_CAPS (1<<0) |
1057 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) | 1059 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) |
1058 | 1060 | ||
@@ -1143,19 +1145,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
1143 | } | 1145 | } |
1144 | EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); | 1146 | EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); |
1145 | 1147 | ||
1146 | u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | 1148 | static unsigned int |
1149 | query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, | ||
1150 | unsigned int (*func)(struct hda_codec *, hda_nid_t)) | ||
1147 | { | 1151 | { |
1148 | struct hda_amp_info *info; | 1152 | struct hda_amp_info *info; |
1149 | 1153 | ||
1150 | info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); | 1154 | info = get_alloc_amp_hash(codec, key); |
1151 | if (!info) | 1155 | if (!info) |
1152 | return 0; | 1156 | return 0; |
1153 | if (!info->head.val) { | 1157 | if (!info->head.val) { |
1154 | info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1155 | info->head.val |= INFO_AMP_CAPS; | 1158 | info->head.val |= INFO_AMP_CAPS; |
1159 | info->amp_caps = func(codec, nid); | ||
1156 | } | 1160 | } |
1157 | return info->amp_caps; | 1161 | return info->amp_caps; |
1158 | } | 1162 | } |
1163 | |||
1164 | static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) | ||
1165 | { | ||
1166 | return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1167 | } | ||
1168 | |||
1169 | u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | ||
1170 | { | ||
1171 | return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), | ||
1172 | read_pin_cap); | ||
1173 | } | ||
1159 | EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); | 1174 | EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); |
1160 | 1175 | ||
1161 | /* | 1176 | /* |
@@ -2538,6 +2553,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
2538 | } | 2553 | } |
2539 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); | 2554 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); |
2540 | 2555 | ||
2556 | static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) | ||
2557 | { | ||
2558 | unsigned int val = 0; | ||
2559 | if (nid != codec->afg && | ||
2560 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) | ||
2561 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
2562 | if (!val || val == -1) | ||
2563 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2564 | if (!val || val == -1) | ||
2565 | return 0; | ||
2566 | return val; | ||
2567 | } | ||
2568 | |||
2569 | static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) | ||
2570 | { | ||
2571 | return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), | ||
2572 | get_pcm_param); | ||
2573 | } | ||
2574 | |||
2575 | static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) | ||
2576 | { | ||
2577 | unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||
2578 | if (!streams || streams == -1) | ||
2579 | streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
2580 | if (!streams || streams == -1) | ||
2581 | return 0; | ||
2582 | return streams; | ||
2583 | } | ||
2584 | |||
2585 | static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) | ||
2586 | { | ||
2587 | return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), | ||
2588 | get_stream_param); | ||
2589 | } | ||
2590 | |||
2541 | /** | 2591 | /** |
2542 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats | 2592 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats |
2543 | * @codec: the HDA codec | 2593 | * @codec: the HDA codec |
@@ -2556,15 +2606,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
2556 | { | 2606 | { |
2557 | unsigned int i, val, wcaps; | 2607 | unsigned int i, val, wcaps; |
2558 | 2608 | ||
2559 | val = 0; | ||
2560 | wcaps = get_wcaps(codec, nid); | 2609 | wcaps = get_wcaps(codec, nid); |
2561 | if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { | 2610 | val = query_pcm_param(codec, nid); |
2562 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
2563 | if (val == -1) | ||
2564 | return -EIO; | ||
2565 | } | ||
2566 | if (!val) | ||
2567 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2568 | 2611 | ||
2569 | if (ratesp) { | 2612 | if (ratesp) { |
2570 | u32 rates = 0; | 2613 | u32 rates = 0; |
@@ -2586,15 +2629,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
2586 | u64 formats = 0; | 2629 | u64 formats = 0; |
2587 | unsigned int streams, bps; | 2630 | unsigned int streams, bps; |
2588 | 2631 | ||
2589 | streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 2632 | streams = query_stream_param(codec, nid); |
2590 | if (streams == -1) | 2633 | if (!streams) |
2591 | return -EIO; | 2634 | return -EIO; |
2592 | if (!streams) { | ||
2593 | streams = snd_hda_param_read(codec, codec->afg, | ||
2594 | AC_PAR_STREAM); | ||
2595 | if (streams == -1) | ||
2596 | return -EIO; | ||
2597 | } | ||
2598 | 2635 | ||
2599 | bps = 0; | 2636 | bps = 0; |
2600 | if (streams & AC_SUPFMT_PCM) { | 2637 | if (streams & AC_SUPFMT_PCM) { |
@@ -2668,17 +2705,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
2668 | int i; | 2705 | int i; |
2669 | unsigned int val = 0, rate, stream; | 2706 | unsigned int val = 0, rate, stream; |
2670 | 2707 | ||
2671 | if (nid != codec->afg && | 2708 | val = query_pcm_param(codec, nid); |
2672 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { | 2709 | if (!val) |
2673 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | 2710 | return 0; |
2674 | if (val == -1) | ||
2675 | return 0; | ||
2676 | } | ||
2677 | if (!val) { | ||
2678 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2679 | if (val == -1) | ||
2680 | return 0; | ||
2681 | } | ||
2682 | 2711 | ||
2683 | rate = format & 0xff00; | 2712 | rate = format & 0xff00; |
2684 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) | 2713 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) |
@@ -2690,12 +2719,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
2690 | if (i >= AC_PAR_PCM_RATE_BITS) | 2719 | if (i >= AC_PAR_PCM_RATE_BITS) |
2691 | return 0; | 2720 | return 0; |
2692 | 2721 | ||
2693 | stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 2722 | stream = query_stream_param(codec, nid); |
2694 | if (stream == -1) | 2723 | if (!stream) |
2695 | return 0; | ||
2696 | if (!stream && nid != codec->afg) | ||
2697 | stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
2698 | if (!stream || stream == -1) | ||
2699 | return 0; | 2724 | return 0; |
2700 | 2725 | ||
2701 | if (stream & AC_SUPFMT_PCM) { | 2726 | if (stream & AC_SUPFMT_PCM) { |