diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-04-21 05:11:54 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-04-21 05:11:54 -0400 |
commit | b97bedcdedb4ae95b2128a4770dfc160e113b174 (patch) | |
tree | c604636b8991e0e53a20e0dbe666a57afe72ea45 /sound/pci/hda/hda_codec.c | |
parent | 858940773ad5f9dfe32ddb34fa1c90638c5a39df (diff) | |
parent | 586be3fcf97eec22fbc0ef6d67e823706aea7167 (diff) |
Merge branch 'topic/hda-cache' into topic/hda
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 114 |
1 files changed, 74 insertions, 40 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 66a7d3de9fa0..b649033a4c81 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -175,14 +175,23 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, | |||
175 | unsigned int verb, unsigned int parm) | 175 | unsigned int verb, unsigned int parm) |
176 | { | 176 | { |
177 | struct hda_bus *bus = codec->bus; | 177 | struct hda_bus *bus = codec->bus; |
178 | unsigned int res; | 178 | unsigned int cmd, res; |
179 | int repeated = 0; | ||
179 | 180 | ||
180 | res = make_codec_cmd(codec, nid, direct, verb, parm); | 181 | cmd = make_codec_cmd(codec, nid, direct, verb, parm); |
181 | snd_hda_power_up(codec); | 182 | snd_hda_power_up(codec); |
182 | mutex_lock(&bus->cmd_mutex); | 183 | mutex_lock(&bus->cmd_mutex); |
183 | if (!bus->ops.command(bus, res)) | 184 | again: |
185 | if (!bus->ops.command(bus, cmd)) { | ||
184 | res = bus->ops.get_response(bus); | 186 | res = bus->ops.get_response(bus); |
185 | else | 187 | if (res == -1 && bus->rirb_error) { |
188 | if (repeated++ < 1) { | ||
189 | snd_printd(KERN_WARNING "hda_codec: " | ||
190 | "Trying verb 0x%08x again\n", cmd); | ||
191 | goto again; | ||
192 | } | ||
193 | } | ||
194 | } else | ||
186 | res = (unsigned int)-1; | 195 | res = (unsigned int)-1; |
187 | mutex_unlock(&bus->cmd_mutex); | 196 | mutex_unlock(&bus->cmd_mutex); |
188 | snd_hda_power_down(codec); | 197 | snd_hda_power_down(codec); |
@@ -1056,6 +1065,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); | |||
1056 | /* FIXME: more better hash key? */ | 1065 | /* FIXME: more better hash key? */ |
1057 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) | 1066 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) |
1058 | #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) | 1067 | #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) |
1068 | #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) | ||
1069 | #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) | ||
1059 | #define INFO_AMP_CAPS (1<<0) | 1070 | #define INFO_AMP_CAPS (1<<0) |
1060 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) | 1071 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) |
1061 | 1072 | ||
@@ -1146,19 +1157,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
1146 | } | 1157 | } |
1147 | EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); | 1158 | EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); |
1148 | 1159 | ||
1149 | u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | 1160 | static unsigned int |
1161 | query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, | ||
1162 | unsigned int (*func)(struct hda_codec *, hda_nid_t)) | ||
1150 | { | 1163 | { |
1151 | struct hda_amp_info *info; | 1164 | struct hda_amp_info *info; |
1152 | 1165 | ||
1153 | info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); | 1166 | info = get_alloc_amp_hash(codec, key); |
1154 | if (!info) | 1167 | if (!info) |
1155 | return 0; | 1168 | return 0; |
1156 | if (!info->head.val) { | 1169 | if (!info->head.val) { |
1157 | info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1158 | info->head.val |= INFO_AMP_CAPS; | 1170 | info->head.val |= INFO_AMP_CAPS; |
1171 | info->amp_caps = func(codec, nid); | ||
1159 | } | 1172 | } |
1160 | return info->amp_caps; | 1173 | return info->amp_caps; |
1161 | } | 1174 | } |
1175 | |||
1176 | static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) | ||
1177 | { | ||
1178 | return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1179 | } | ||
1180 | |||
1181 | u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | ||
1182 | { | ||
1183 | return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), | ||
1184 | read_pin_cap); | ||
1185 | } | ||
1162 | EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); | 1186 | EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); |
1163 | 1187 | ||
1164 | /* | 1188 | /* |
@@ -2547,6 +2571,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
2547 | } | 2571 | } |
2548 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); | 2572 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); |
2549 | 2573 | ||
2574 | static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) | ||
2575 | { | ||
2576 | unsigned int val = 0; | ||
2577 | if (nid != codec->afg && | ||
2578 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) | ||
2579 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
2580 | if (!val || val == -1) | ||
2581 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2582 | if (!val || val == -1) | ||
2583 | return 0; | ||
2584 | return val; | ||
2585 | } | ||
2586 | |||
2587 | static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) | ||
2588 | { | ||
2589 | return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), | ||
2590 | get_pcm_param); | ||
2591 | } | ||
2592 | |||
2593 | static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) | ||
2594 | { | ||
2595 | unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||
2596 | if (!streams || streams == -1) | ||
2597 | streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
2598 | if (!streams || streams == -1) | ||
2599 | return 0; | ||
2600 | return streams; | ||
2601 | } | ||
2602 | |||
2603 | static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) | ||
2604 | { | ||
2605 | return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), | ||
2606 | get_stream_param); | ||
2607 | } | ||
2608 | |||
2550 | /** | 2609 | /** |
2551 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats | 2610 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats |
2552 | * @codec: the HDA codec | 2611 | * @codec: the HDA codec |
@@ -2565,15 +2624,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
2565 | { | 2624 | { |
2566 | unsigned int i, val, wcaps; | 2625 | unsigned int i, val, wcaps; |
2567 | 2626 | ||
2568 | val = 0; | ||
2569 | wcaps = get_wcaps(codec, nid); | 2627 | wcaps = get_wcaps(codec, nid); |
2570 | if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { | 2628 | val = query_pcm_param(codec, nid); |
2571 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
2572 | if (val == -1) | ||
2573 | return -EIO; | ||
2574 | } | ||
2575 | if (!val) | ||
2576 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2577 | 2629 | ||
2578 | if (ratesp) { | 2630 | if (ratesp) { |
2579 | u32 rates = 0; | 2631 | u32 rates = 0; |
@@ -2595,15 +2647,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
2595 | u64 formats = 0; | 2647 | u64 formats = 0; |
2596 | unsigned int streams, bps; | 2648 | unsigned int streams, bps; |
2597 | 2649 | ||
2598 | streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 2650 | streams = query_stream_param(codec, nid); |
2599 | if (streams == -1) | 2651 | if (!streams) |
2600 | return -EIO; | 2652 | return -EIO; |
2601 | if (!streams) { | ||
2602 | streams = snd_hda_param_read(codec, codec->afg, | ||
2603 | AC_PAR_STREAM); | ||
2604 | if (streams == -1) | ||
2605 | return -EIO; | ||
2606 | } | ||
2607 | 2653 | ||
2608 | bps = 0; | 2654 | bps = 0; |
2609 | if (streams & AC_SUPFMT_PCM) { | 2655 | if (streams & AC_SUPFMT_PCM) { |
@@ -2677,17 +2723,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
2677 | int i; | 2723 | int i; |
2678 | unsigned int val = 0, rate, stream; | 2724 | unsigned int val = 0, rate, stream; |
2679 | 2725 | ||
2680 | if (nid != codec->afg && | 2726 | val = query_pcm_param(codec, nid); |
2681 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { | 2727 | if (!val) |
2682 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | 2728 | return 0; |
2683 | if (val == -1) | ||
2684 | return 0; | ||
2685 | } | ||
2686 | if (!val) { | ||
2687 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2688 | if (val == -1) | ||
2689 | return 0; | ||
2690 | } | ||
2691 | 2729 | ||
2692 | rate = format & 0xff00; | 2730 | rate = format & 0xff00; |
2693 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) | 2731 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) |
@@ -2699,12 +2737,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
2699 | if (i >= AC_PAR_PCM_RATE_BITS) | 2737 | if (i >= AC_PAR_PCM_RATE_BITS) |
2700 | return 0; | 2738 | return 0; |
2701 | 2739 | ||
2702 | stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 2740 | stream = query_stream_param(codec, nid); |
2703 | if (stream == -1) | 2741 | if (!stream) |
2704 | return 0; | ||
2705 | if (!stream && nid != codec->afg) | ||
2706 | stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
2707 | if (!stream || stream == -1) | ||
2708 | return 0; | 2742 | return 0; |
2709 | 2743 | ||
2710 | if (stream & AC_SUPFMT_PCM) { | 2744 | if (stream & AC_SUPFMT_PCM) { |