aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-04-21 05:11:54 -0400
committerTakashi Iwai <tiwai@suse.de>2009-04-21 05:11:54 -0400
commitb97bedcdedb4ae95b2128a4770dfc160e113b174 (patch)
treec604636b8991e0e53a20e0dbe666a57afe72ea45 /sound/pci/hda/hda_codec.c
parent858940773ad5f9dfe32ddb34fa1c90638c5a39df (diff)
parent586be3fcf97eec22fbc0ef6d67e823706aea7167 (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.c114
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}
1147EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); 1158EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
1148 1159
1149u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) 1160static unsigned int
1161query_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
1176static 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
1181u32 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}
1162EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); 1186EXPORT_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}
2548EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); 2572EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
2549 2573
2574static 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
2587static 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
2593static 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
2603static 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) {