aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-04-07 09:55:15 -0400
committerTakashi Iwai <tiwai@suse.de>2011-04-07 09:55:15 -0400
commita12d3e1e1cb67bab2411966b345151c316633847 (patch)
treebe1a29ccb9ebb22fa659012a63d13b0e6f8008bb /sound/pci/hda
parent8e28e3b29fdbb2b94bb279700114b5963fe1d4e8 (diff)
ALSA: hda - Remember connection lists
The connection lists are static and we can reuse the previous results instead of querying via verb at each time. This will reduce the I/O in the runtime especially for some codec auto-parsers. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c69
-rw-r--r--sound/pci/hda/hda_codec.h2
2 files changed, 69 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 2c79e96d0324..11ead159abd9 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -307,6 +307,12 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
307} 307}
308EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); 308EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
309 309
310static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
311 hda_nid_t *conn_list, int max_conns);
312static bool add_conn_list(struct snd_array *array, hda_nid_t nid);
313static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
314 hda_nid_t *src, int len);
315
310/** 316/**
311 * snd_hda_get_connections - get connection list 317 * snd_hda_get_connections - get connection list
312 * @codec: the HDA codec 318 * @codec: the HDA codec
@@ -320,7 +326,44 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
320 * Returns the number of connections, or a negative error code. 326 * Returns the number of connections, or a negative error code.
321 */ 327 */
322int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, 328int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
323 hda_nid_t *conn_list, int max_conns) 329 hda_nid_t *conn_list, int max_conns)
330{
331 struct snd_array *array = &codec->conn_lists;
332 int i, j, len, old_used;
333 hda_nid_t list[HDA_MAX_CONNECTIONS];
334
335 /* look up the cached results */
336 for (i = 0; i < array->used; ) {
337 hda_nid_t *p = snd_array_elem(array, i);
338 len = p[1];
339 if (nid == *p)
340 return copy_conn_list(nid, conn_list, max_conns,
341 p + 2, len);
342 i += len + 2;
343 }
344
345 len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
346 if (len < 0)
347 return len;
348
349 /* add to the cache */
350 old_used = array->used;
351 if (!add_conn_list(array, nid) || !add_conn_list(array, len))
352 goto error_add;
353 for (i = 0; i < len; i++)
354 if (!add_conn_list(array, list[i]))
355 goto error_add;
356
357 return copy_conn_list(nid, conn_list, max_conns, list, len);
358
359 error_add:
360 array->used = old_used;
361 return -ENOMEM;
362}
363EXPORT_SYMBOL_HDA(snd_hda_get_connections);
364
365static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
366 hda_nid_t *conn_list, int max_conns)
324{ 367{
325 unsigned int parm; 368 unsigned int parm;
326 int i, conn_len, conns; 369 int i, conn_len, conns;
@@ -417,8 +460,28 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
417 } 460 }
418 return conns; 461 return conns;
419} 462}
420EXPORT_SYMBOL_HDA(snd_hda_get_connections);
421 463
464static bool add_conn_list(struct snd_array *array, hda_nid_t nid)
465{
466 hda_nid_t *p = snd_array_new(array);
467 if (!p)
468 return false;
469 *p = nid;
470 return true;
471}
472
473static int copy_conn_list(hda_nid_t nid, hda_nid_t *dst, int max_dst,
474 hda_nid_t *src, int len)
475{
476 if (len > max_dst) {
477 snd_printk(KERN_ERR "hda_codec: "
478 "Too many connections %d for NID 0x%x\n",
479 len, nid);
480 return -EINVAL;
481 }
482 memcpy(dst, src, len * sizeof(hda_nid_t));
483 return len;
484}
422 485
423/** 486/**
424 * snd_hda_queue_unsol_event - add an unsolicited event to queue 487 * snd_hda_queue_unsol_event - add an unsolicited event to queue
@@ -1017,6 +1080,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
1017 list_del(&codec->list); 1080 list_del(&codec->list);
1018 snd_array_free(&codec->mixers); 1081 snd_array_free(&codec->mixers);
1019 snd_array_free(&codec->nids); 1082 snd_array_free(&codec->nids);
1083 snd_array_free(&codec->conn_lists);
1020 codec->bus->caddr_tbl[codec->addr] = NULL; 1084 codec->bus->caddr_tbl[codec->addr] = NULL;
1021 if (codec->patch_ops.free) 1085 if (codec->patch_ops.free)
1022 codec->patch_ops.free(codec); 1086 codec->patch_ops.free(codec);
@@ -1077,6 +1141,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
1077 snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); 1141 snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
1078 snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); 1142 snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
1079 snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); 1143 snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
1144 snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
1080 if (codec->bus->modelname) { 1145 if (codec->bus->modelname) {
1081 codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); 1146 codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
1082 if (!codec->modelname) { 1147 if (!codec->modelname) {
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index e46d5420a9f2..7d57a66c1b31 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -825,6 +825,8 @@ struct hda_codec {
825 struct hda_cache_rec amp_cache; /* cache for amp access */ 825 struct hda_cache_rec amp_cache; /* cache for amp access */
826 struct hda_cache_rec cmd_cache; /* cache for other commands */ 826 struct hda_cache_rec cmd_cache; /* cache for other commands */
827 827
828 struct snd_array conn_lists; /* connection-list array */
829
828 struct mutex spdif_mutex; 830 struct mutex spdif_mutex;
829 struct mutex control_mutex; 831 struct mutex control_mutex;
830 unsigned int spdif_status; /* IEC958 status bits */ 832 unsigned int spdif_status; /* IEC958 status bits */