aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-11-21 10:33:22 -0500
committerJaroslav Kysela <perex@suse.cz>2006-01-03 06:29:27 -0500
commit54d174031576a2855c49611d83d4946bde81b504 (patch)
tree6bdcefaccb78bddfa1a3ea7b429e1178b479999d
parent1b98ea4791892399d8c23c93e117567eeff38887 (diff)
[ALSA] hda-codec - Fix connection list parsing
Modules: HDA Codec driver,HDA generic driver - Fix connection list parsing (with ranged flag). - Increase the max number of connections - Introduce widget capabilities cache - Power up/down widgets at init, suspend and resume Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_codec.c155
-rw-r--r--sound/pci/hda/hda_codec.h13
-rw-r--r--sound/pci/hda/hda_local.h14
-rw-r--r--sound/pci/hda/patch_realtek.c3
-rw-r--r--sound/pci/hda/patch_sigmatel.c25
5 files changed, 140 insertions, 70 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 7f4e19951bae..402ce00c6a13 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -155,8 +155,9 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
155 hda_nid_t *conn_list, int max_conns) 155 hda_nid_t *conn_list, int max_conns)
156{ 156{
157 unsigned int parm; 157 unsigned int parm;
158 int i, j, conn_len, num_tupples, conns; 158 int i, conn_len, conns;
159 unsigned int shift, num_elems, mask; 159 unsigned int shift, num_elems, mask;
160 hda_nid_t prev_nid;
160 161
161 snd_assert(conn_list && max_conns > 0, return -EINVAL); 162 snd_assert(conn_list && max_conns > 0, return -EINVAL);
162 163
@@ -171,7 +172,6 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
171 num_elems = 4; 172 num_elems = 4;
172 } 173 }
173 conn_len = parm & AC_CLIST_LENGTH; 174 conn_len = parm & AC_CLIST_LENGTH;
174 num_tupples = num_elems / 2;
175 mask = (1 << (shift-1)) - 1; 175 mask = (1 << (shift-1)) - 1;
176 176
177 if (! conn_len) 177 if (! conn_len)
@@ -186,40 +186,38 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
186 186
187 /* multi connection */ 187 /* multi connection */
188 conns = 0; 188 conns = 0;
189 for (i = 0; i < conn_len; i += num_elems) { 189 prev_nid = 0;
190 parm = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, i); 190 for (i = 0; i < conn_len; i++) {
191 for (j = 0; j < num_tupples; j++) { 191 int range_val;
192 int range_val; 192 hda_nid_t val, n;
193 hda_nid_t val1, val2, n; 193
194 range_val = parm & (1 << (shift-1)); /* ranges */ 194 if (i % num_elems == 0)
195 val1 = parm & mask; 195 parm = snd_hda_codec_read(codec, nid, 0,
196 parm >>= shift; 196 AC_VERB_GET_CONNECT_LIST, i);
197 val2 = parm & mask; 197 range_val = !! (parm & (1 << (shift-1))); /* ranges */
198 parm >>= shift; 198 val = parm & mask;
199 if (range_val) { 199 parm >>= shift;
200 /* ranges between val1 and val2 */ 200 if (range_val) {
201 if (val1 > val2) { 201 /* ranges between the previous and this one */
202 snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", val1, val2); 202 if (! prev_nid || prev_nid >= val) {
203 continue; 203 snd_printk(KERN_WARNING "hda_codec: invalid dep_range_val %x:%x\n", prev_nid, val);
204 } 204 continue;
205 for (n = val1; n <= val2; n++) { 205 }
206 if (conns >= max_conns) 206 for (n = prev_nid + 1; n <= val; n++) {
207 return -EINVAL; 207 if (conns >= max_conns) {
208 conn_list[conns++] = n; 208 snd_printk(KERN_ERR "Too many connections\n");
209 }
210 } else {
211 if (! val1)
212 break;
213 if (conns >= max_conns)
214 return -EINVAL;
215 conn_list[conns++] = val1;
216 if (! val2)
217 break;
218 if (conns >= max_conns)
219 return -EINVAL; 209 return -EINVAL;
220 conn_list[conns++] = val2; 210 }
211 conn_list[conns++] = n;
221 } 212 }
213 } else {
214 if (conns >= max_conns) {
215 snd_printk(KERN_ERR "Too many connections\n");
216 return -EINVAL;
217 }
218 conn_list[conns++] = val;
222 } 219 }
220 prev_nid = val;
223 } 221 }
224 return conns; 222 return conns;
225} 223}
@@ -456,6 +454,27 @@ static void setup_fg_nodes(struct hda_codec *codec)
456} 454}
457 455
458/* 456/*
457 * read widget caps for each widget and store in cache
458 */
459static int read_widget_caps(struct hda_codec *codec, hda_nid_t fg_node)
460{
461 int i;
462 hda_nid_t nid;
463
464 codec->num_nodes = snd_hda_get_sub_nodes(codec, fg_node,
465 &codec->start_nid);
466 codec->wcaps = kmalloc(codec->num_nodes * 4, GFP_KERNEL);
467 if (! codec->wcaps)
468 return -ENOMEM;
469 nid = codec->start_nid;
470 for (i = 0; i < codec->num_nodes; i++, nid++)
471 codec->wcaps[i] = snd_hda_param_read(codec, nid,
472 AC_PAR_AUDIO_WIDGET_CAP);
473 return 0;
474}
475
476
477/*
459 * codec destructor 478 * codec destructor
460 */ 479 */
461static void snd_hda_codec_free(struct hda_codec *codec) 480static void snd_hda_codec_free(struct hda_codec *codec)
@@ -467,6 +486,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
467 if (codec->patch_ops.free) 486 if (codec->patch_ops.free)
468 codec->patch_ops.free(codec); 487 codec->patch_ops.free(codec);
469 kfree(codec->amp_info); 488 kfree(codec->amp_info);
489 kfree(codec->wcaps);
470 kfree(codec); 490 kfree(codec);
471} 491}
472 492
@@ -520,6 +540,12 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
520 return -ENODEV; 540 return -ENODEV;
521 } 541 }
522 542
543 if (read_widget_caps(codec, codec->afg ? codec->afg : codec->mfg) < 0) {
544 snd_printk(KERN_ERR "hda_codec: cannot malloc\n");
545 snd_hda_codec_free(codec);
546 return -ENOMEM;
547 }
548
523 if (! codec->subsystem_id) { 549 if (! codec->subsystem_id) {
524 hda_nid_t nid = codec->afg ? codec->afg : codec->mfg; 550 hda_nid_t nid = codec->afg ? codec->afg : codec->mfg;
525 codec->subsystem_id = snd_hda_codec_read(codec, nid, 0, 551 codec->subsystem_id = snd_hda_codec_read(codec, nid, 0,
@@ -647,7 +673,7 @@ static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
647 if (! info) 673 if (! info)
648 return 0; 674 return 0;
649 if (! (info->status & INFO_AMP_CAPS)) { 675 if (! (info->status & INFO_AMP_CAPS)) {
650 if (!(snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_AMP_OVRD)) 676 if (! (get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
651 nid = codec->afg; 677 nid = codec->afg;
652 info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ? 678 info->amp_caps = snd_hda_param_read(codec, nid, direction == HDA_OUTPUT ?
653 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); 679 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
@@ -1195,6 +1221,31 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
1195} 1221}
1196 1222
1197 1223
1224/*
1225 * set power state of the codec
1226 */
1227static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
1228 unsigned int power_state)
1229{
1230 hda_nid_t nid, nid_start;
1231 int nodes;
1232
1233 snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
1234 power_state);
1235
1236 nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start);
1237 for (nid = nid_start; nid < nodes + nid_start; nid++) {
1238 if (get_wcaps(codec, nid) & AC_WCAP_POWER)
1239 snd_hda_codec_write(codec, nid, 0,
1240 AC_VERB_SET_POWER_STATE,
1241 power_state);
1242 }
1243
1244 if (power_state == AC_PWRST_D0)
1245 msleep(10);
1246}
1247
1248
1198/** 1249/**
1199 * snd_hda_build_controls - build mixer controls 1250 * snd_hda_build_controls - build mixer controls
1200 * @bus: the BUS 1251 * @bus: the BUS
@@ -1222,6 +1273,9 @@ int snd_hda_build_controls(struct hda_bus *bus)
1222 list_for_each(p, &bus->codec_list) { 1273 list_for_each(p, &bus->codec_list) {
1223 struct hda_codec *codec = list_entry(p, struct hda_codec, list); 1274 struct hda_codec *codec = list_entry(p, struct hda_codec, list);
1224 int err; 1275 int err;
1276 hda_set_power_state(codec,
1277 codec->afg ? codec->afg : codec->mfg,
1278 AC_PWRST_D0);
1225 if (! codec->patch_ops.init) 1279 if (! codec->patch_ops.init)
1226 continue; 1280 continue;
1227 err = codec->patch_ops.init(codec); 1281 err = codec->patch_ops.init(codec);
@@ -1340,7 +1394,7 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
1340 1394
1341 val = 0; 1395 val = 0;
1342 if (nid != codec->afg && 1396 if (nid != codec->afg &&
1343 snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) { 1397 (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
1344 val = snd_hda_param_read(codec, nid, AC_PAR_PCM); 1398 val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
1345 if (val == -1) 1399 if (val == -1)
1346 return -EIO; 1400 return -EIO;
@@ -1362,7 +1416,7 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
1362 unsigned int bps; 1416 unsigned int bps;
1363 unsigned int wcaps; 1417 unsigned int wcaps;
1364 1418
1365 wcaps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); 1419 wcaps = get_wcaps(codec, nid);
1366 streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); 1420 streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
1367 if (streams == -1) 1421 if (streams == -1)
1368 return -EIO; 1422 return -EIO;
@@ -1432,7 +1486,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
1432 unsigned int val = 0, rate, stream; 1486 unsigned int val = 0, rate, stream;
1433 1487
1434 if (nid != codec->afg && 1488 if (nid != codec->afg &&
1435 snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) & AC_WCAP_FORMAT_OVRD) { 1489 (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) {
1436 val = snd_hda_param_read(codec, nid, AC_PAR_PCM); 1490 val = snd_hda_param_read(codec, nid, AC_PAR_PCM);
1437 if (val == -1) 1491 if (val == -1)
1438 return 0; 1492 return 0;
@@ -1658,9 +1712,21 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew)
1658 int err; 1712 int err;
1659 1713
1660 for (; knew->name; knew++) { 1714 for (; knew->name; knew++) {
1661 err = snd_ctl_add(codec->bus->card, snd_ctl_new1(knew, codec)); 1715 struct snd_kcontrol *kctl;
1662 if (err < 0) 1716 kctl = snd_ctl_new1(knew, codec);
1663 return err; 1717 if (! kctl)
1718 return -ENOMEM;
1719 err = snd_ctl_add(codec->bus->card, kctl);
1720 if (err < 0) {
1721 if (! codec->addr)
1722 return err;
1723 kctl = snd_ctl_new1(knew, codec);
1724 if (! kctl)
1725 return -ENOMEM;
1726 kctl->id.device = codec->addr;
1727 if ((err = snd_ctl_add(codec->bus->card, kctl)) < 0)
1728 return err;
1729 }
1664 } 1730 }
1665 return 0; 1731 return 0;
1666} 1732}
@@ -1874,8 +1940,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
1874 1940
1875 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); 1941 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
1876 for (nid = nid_start; nid < nodes + nid_start; nid++) { 1942 for (nid = nid_start; nid < nodes + nid_start; nid++) {
1877 unsigned int wid_caps = snd_hda_param_read(codec, nid, 1943 unsigned int wid_caps = get_wcaps(codec, nid);
1878 AC_PAR_AUDIO_WIDGET_CAP);
1879 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; 1944 unsigned int wid_type = (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
1880 unsigned int def_conf; 1945 unsigned int def_conf;
1881 short assoc, loc; 1946 short assoc, loc;
@@ -1993,6 +2058,9 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
1993 struct hda_codec *codec = list_entry(p, struct hda_codec, list); 2058 struct hda_codec *codec = list_entry(p, struct hda_codec, list);
1994 if (codec->patch_ops.suspend) 2059 if (codec->patch_ops.suspend)
1995 codec->patch_ops.suspend(codec, state); 2060 codec->patch_ops.suspend(codec, state);
2061 hda_set_power_state(codec,
2062 codec->afg ? codec->afg : codec->mfg,
2063 AC_PWRST_D3);
1996 } 2064 }
1997 return 0; 2065 return 0;
1998} 2066}
@@ -2010,6 +2078,9 @@ int snd_hda_resume(struct hda_bus *bus)
2010 2078
2011 list_for_each(p, &bus->codec_list) { 2079 list_for_each(p, &bus->codec_list) {
2012 struct hda_codec *codec = list_entry(p, struct hda_codec, list); 2080 struct hda_codec *codec = list_entry(p, struct hda_codec, list);
2081 hda_set_power_state(codec,
2082 codec->afg ? codec->afg : codec->mfg,
2083 AC_PWRST_D0);
2013 if (codec->patch_ops.resume) 2084 if (codec->patch_ops.resume)
2014 codec->patch_ops.resume(codec); 2085 codec->patch_ops.resume(codec);
2015 } 2086 }
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 0b5c36788898..63e26c7a2b7a 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -214,6 +214,12 @@ enum {
214#define AC_PWRST_D2SUP (1<<2) 214#define AC_PWRST_D2SUP (1<<2)
215#define AC_PWRST_D3SUP (1<<3) 215#define AC_PWRST_D3SUP (1<<3)
216 216
217/* Power state values */
218#define AC_PWRST_D0 0x00
219#define AC_PWRST_D1 0x01
220#define AC_PWRST_D2 0x02
221#define AC_PWRST_D3 0x03
222
217/* Processing capabilies */ 223/* Processing capabilies */
218#define AC_PCAP_BENIGN (1<<0) 224#define AC_PCAP_BENIGN (1<<0)
219#define AC_PCAP_NUM_COEF (0xff<<8) 225#define AC_PCAP_NUM_COEF (0xff<<8)
@@ -376,7 +382,7 @@ enum {
376}; 382};
377 383
378/* max. connections to a widget */ 384/* max. connections to a widget */
379#define HDA_MAX_CONNECTIONS 16 385#define HDA_MAX_CONNECTIONS 32
380 386
381/* max. codec address */ 387/* max. codec address */
382#define HDA_MAX_CODEC_ADDRESS 0x0f 388#define HDA_MAX_CODEC_ADDRESS 0x0f
@@ -542,6 +548,11 @@ struct hda_codec {
542 /* codec specific info */ 548 /* codec specific info */
543 void *spec; 549 void *spec;
544 550
551 /* widget capabilities cache */
552 unsigned int num_nodes;
553 hda_nid_t start_nid;
554 u32 *wcaps;
555
545 /* hash for amp access */ 556 /* hash for amp access */
546 u16 amp_hash[32]; 557 u16 amp_hash[32];
547 int num_amp_entries; 558 int num_amp_entries;
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 502290424c67..ded32359b654 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -87,7 +87,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid);
87/* 87/*
88 * input MUX helper 88 * input MUX helper
89 */ 89 */
90#define HDA_MAX_NUM_INPUTS 8 90#define HDA_MAX_NUM_INPUTS 16
91struct hda_input_mux_item { 91struct hda_input_mux_item {
92 const char *label; 92 const char *label;
93 unsigned int index; 93 unsigned int index;
@@ -243,4 +243,16 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
243#define PIN_HP 0xc0 243#define PIN_HP 0xc0
244#define PIN_HP_AMP 0x80 244#define PIN_HP_AMP 0x80
245 245
246/*
247 * get widget capabilities
248 */
249static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid)
250{
251 if (nid < codec->start_nid ||
252 nid >= codec->start_nid + codec->num_nodes)
253 return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP);
254 return codec->wcaps[nid - codec->start_nid];
255}
256
257
246#endif /* __SOUND_HDA_LOCAL_H */ 258#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 62e6993056e6..77c5f95ea55b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2091,8 +2091,7 @@ static int patch_alc880(struct hda_codec *codec)
2091 2091
2092 if (! spec->adc_nids && spec->input_mux) { 2092 if (! spec->adc_nids && spec->input_mux) {
2093 /* check whether NID 0x07 is valid */ 2093 /* check whether NID 0x07 is valid */
2094 unsigned int wcap = snd_hda_param_read(codec, alc880_adc_nids[0], 2094 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
2095 AC_PAR_AUDIO_WIDGET_CAP);
2096 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ 2095 wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */
2097 if (wcap != AC_WID_AUD_IN) { 2096 if (wcap != AC_WID_AUD_IN) {
2098 spec->adc_nids = alc880_adc_nids_alt; 2097 spec->adc_nids = alc880_adc_nids_alt;
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index d8d68f5b6131..c8c539cb4a8f 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -624,7 +624,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin
624 if (! pin) 624 if (! pin)
625 return 0; 625 return 0;
626 626
627 wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP); 627 wid_caps = get_wcaps(codec, pin);
628 if (wid_caps & AC_WCAP_UNSOL_CAP) 628 if (wid_caps & AC_WCAP_UNSOL_CAP)
629 /* Enable unsolicited responses on the HP widget */ 629 /* Enable unsolicited responses on the HP widget */
630 snd_hda_codec_write(codec, pin, 0, 630 snd_hda_codec_write(codec, pin, 0,
@@ -786,33 +786,10 @@ static int stac9200_parse_auto_config(struct hda_codec *codec)
786 return 1; 786 return 1;
787} 787}
788 788
789static int stac92xx_init_pstate(struct hda_codec *codec)
790{
791 hda_nid_t nid, nid_start;
792 int nodes;
793
794 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_POWER_STATE, 0x00);
795
796 nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
797 for (nid = nid_start; nid < nodes + nid_start; nid++) {
798 unsigned int wid_caps = snd_hda_param_read(codec, nid,
799 AC_PAR_AUDIO_WIDGET_CAP);
800 if (wid_caps & AC_WCAP_POWER)
801 snd_hda_codec_write(codec, nid, 0,
802 AC_VERB_SET_POWER_STATE, 0x00);
803 }
804
805 mdelay(100);
806
807 return 0;
808}
809
810static int stac92xx_init(struct hda_codec *codec) 789static int stac92xx_init(struct hda_codec *codec)
811{ 790{
812 struct sigmatel_spec *spec = codec->spec; 791 struct sigmatel_spec *spec = codec->spec;
813 792
814 stac92xx_init_pstate(codec);
815
816 snd_hda_sequence_write(codec, spec->init); 793 snd_hda_sequence_write(codec, spec->init);
817 794
818 stac92xx_auto_init_multi_out(codec); 795 stac92xx_auto_init_multi_out(codec);