diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-04-07 09:55:15 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-04-07 09:55:15 -0400 |
commit | a12d3e1e1cb67bab2411966b345151c316633847 (patch) | |
tree | be1a29ccb9ebb22fa659012a63d13b0e6f8008bb /sound/pci/hda | |
parent | 8e28e3b29fdbb2b94bb279700114b5963fe1d4e8 (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.c | 69 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 |
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 | } |
308 | EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); | 308 | EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); |
309 | 309 | ||
310 | static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | ||
311 | hda_nid_t *conn_list, int max_conns); | ||
312 | static bool add_conn_list(struct snd_array *array, hda_nid_t nid); | ||
313 | static 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 | */ |
322 | int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | 328 | int 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 | } | ||
363 | EXPORT_SYMBOL_HDA(snd_hda_get_connections); | ||
364 | |||
365 | static 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 | } |
420 | EXPORT_SYMBOL_HDA(snd_hda_get_connections); | ||
421 | 463 | ||
464 | static 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 | |||
473 | static 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 */ |