diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-07-04 10:23:26 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-07-12 01:44:46 -0400 |
commit | b2f934a0dffd4153e9447ee9e0090e357a3d8b3b (patch) | |
tree | 88237adf2e9523f3f955b7f79c9a47061dc044c6 /sound | |
parent | 19110595c89b2d606883b7cb99260c7e47fd2143 (diff) |
ALSA: hda - Add snd_hda_override_conn_list() helper function
Add a function to add/modify the connection-list cache entry.
It'll be useful to fix a buggy hardware result.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 99 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 2 |
2 files changed, 71 insertions, 30 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 7f8502388a82..d0deab1ed510 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -310,10 +310,23 @@ EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); | |||
310 | 310 | ||
311 | static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | 311 | static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, |
312 | hda_nid_t *conn_list, int max_conns); | 312 | hda_nid_t *conn_list, int max_conns); |
313 | static bool add_conn_list(struct snd_array *array, hda_nid_t nid); | 313 | |
314 | /* look up the cached results */ | ||
315 | static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid) | ||
316 | { | ||
317 | int i, len; | ||
318 | for (i = 0; i < array->used; ) { | ||
319 | hda_nid_t *p = snd_array_elem(array, i); | ||
320 | if (nid == *p) | ||
321 | return p; | ||
322 | len = p[1]; | ||
323 | i += len + 2; | ||
324 | } | ||
325 | return NULL; | ||
326 | } | ||
314 | 327 | ||
315 | /** | 328 | /** |
316 | * snd_hda_get_connections - get connection list | 329 | * snd_hda_get_conn_list - get connection list |
317 | * @codec: the HDA codec | 330 | * @codec: the HDA codec |
318 | * @nid: NID to parse | 331 | * @nid: NID to parse |
319 | * @listp: the pointer to store NID list | 332 | * @listp: the pointer to store NID list |
@@ -327,42 +340,31 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, | |||
327 | const hda_nid_t **listp) | 340 | const hda_nid_t **listp) |
328 | { | 341 | { |
329 | struct snd_array *array = &codec->conn_lists; | 342 | struct snd_array *array = &codec->conn_lists; |
330 | int i, len, old_used; | 343 | int len, err; |
331 | hda_nid_t list[HDA_MAX_CONNECTIONS]; | 344 | hda_nid_t list[HDA_MAX_CONNECTIONS]; |
332 | hda_nid_t *p; | 345 | hda_nid_t *p; |
346 | bool added = false; | ||
333 | 347 | ||
334 | /* look up the cached results */ | 348 | again: |
335 | for (i = 0; i < array->used; ) { | 349 | /* if the connection-list is already cached, read it */ |
336 | p = snd_array_elem(array, i); | 350 | p = lookup_conn_list(array, nid); |
337 | len = p[1]; | 351 | if (p) { |
338 | if (nid == *p) { | 352 | if (listp) |
339 | if (listp) | 353 | *listp = p + 2; |
340 | *listp = p + 2; | 354 | return p[1]; |
341 | return len; | ||
342 | } | ||
343 | i += len + 2; | ||
344 | } | 355 | } |
356 | if (snd_BUG_ON(added)) | ||
357 | return -EINVAL; | ||
345 | 358 | ||
359 | /* read the connection and add to the cache */ | ||
346 | len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); | 360 | len = _hda_get_connections(codec, nid, list, HDA_MAX_CONNECTIONS); |
347 | if (len < 0) | 361 | if (len < 0) |
348 | return len; | 362 | return len; |
349 | 363 | err = snd_hda_override_conn_list(codec, nid, len, list); | |
350 | /* add to the cache */ | 364 | if (err < 0) |
351 | old_used = array->used; | 365 | return err; |
352 | if (!add_conn_list(array, nid) || !add_conn_list(array, len)) | 366 | added = true; |
353 | goto error_add; | 367 | goto again; |
354 | for (i = 0; i < len; i++) | ||
355 | if (!add_conn_list(array, list[i])) | ||
356 | goto error_add; | ||
357 | |||
358 | p = snd_array_elem(array, old_used); | ||
359 | if (listp) | ||
360 | *listp = p + 2; | ||
361 | return len; | ||
362 | |||
363 | error_add: | ||
364 | array->used = old_used; | ||
365 | return -ENOMEM; | ||
366 | } | 368 | } |
367 | EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); | 369 | EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); |
368 | 370 | ||
@@ -503,6 +505,43 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid) | |||
503 | } | 505 | } |
504 | 506 | ||
505 | /** | 507 | /** |
508 | * snd_hda_override_conn_list - add/modify the connection-list to cache | ||
509 | * @codec: the HDA codec | ||
510 | * @nid: NID to parse | ||
511 | * @len: number of connection list entries | ||
512 | * @list: the list of connection entries | ||
513 | * | ||
514 | * Add or modify the given connection-list to the cache. If the corresponding | ||
515 | * cache already exists, invalidate it and append a new one. | ||
516 | * | ||
517 | * Returns zero or a negative error code. | ||
518 | */ | ||
519 | int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, | ||
520 | const hda_nid_t *list) | ||
521 | { | ||
522 | struct snd_array *array = &codec->conn_lists; | ||
523 | hda_nid_t *p; | ||
524 | int i, old_used; | ||
525 | |||
526 | p = lookup_conn_list(array, nid); | ||
527 | if (p) | ||
528 | *p = -1; /* invalidate the old entry */ | ||
529 | |||
530 | old_used = array->used; | ||
531 | if (!add_conn_list(array, nid) || !add_conn_list(array, len)) | ||
532 | goto error_add; | ||
533 | for (i = 0; i < len; i++) | ||
534 | if (!add_conn_list(array, list[i])) | ||
535 | goto error_add; | ||
536 | return 0; | ||
537 | |||
538 | error_add: | ||
539 | array->used = old_used; | ||
540 | return -ENOMEM; | ||
541 | } | ||
542 | EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); | ||
543 | |||
544 | /** | ||
506 | * snd_hda_get_conn_index - get the connection index of the given NID | 545 | * snd_hda_get_conn_index - get the connection index of the given NID |
507 | * @codec: the HDA codec | 546 | * @codec: the HDA codec |
508 | * @mux: NID containing the list | 547 | * @mux: NID containing the list |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 10d500d2ba33..e6bc16f66bce 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -905,6 +905,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, | |||
905 | hda_nid_t *conn_list, int max_conns); | 905 | hda_nid_t *conn_list, int max_conns); |
906 | int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, | 906 | int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, |
907 | const hda_nid_t **listp); | 907 | const hda_nid_t **listp); |
908 | int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, | ||
909 | const hda_nid_t *list); | ||
908 | int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, | 910 | int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, |
909 | hda_nid_t nid, int recursive); | 911 | hda_nid_t nid, int recursive); |
910 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | 912 | int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, |