aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-07-04 10:23:26 -0400
committerTakashi Iwai <tiwai@suse.de>2011-07-12 01:44:46 -0400
commitb2f934a0dffd4153e9447ee9e0090e357a3d8b3b (patch)
tree88237adf2e9523f3f955b7f79c9a47061dc044c6 /sound
parent19110595c89b2d606883b7cb99260c7e47fd2143 (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.c99
-rw-r--r--sound/pci/hda/hda_codec.h2
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
311static int _hda_get_connections(struct hda_codec *codec, hda_nid_t nid, 311static 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);
313static bool add_conn_list(struct snd_array *array, hda_nid_t nid); 313
314/* look up the cached results */
315static 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}
367EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); 369EXPORT_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 */
519int 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}
542EXPORT_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);
906int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, 906int 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);
908int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
909 const hda_nid_t *list);
908int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, 910int 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);
910int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, 912int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,