source: mainline/uspace/drv/audio/hdaudio/codec.c@ cecba66e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cecba66e was 0e4c5f0, checked in by Jiri Svoboda <jiri@…>, 10 years ago

hdaudio capture support. wavplay fixes to recording code.

  • Property mode set to 100644
File size: 16.2 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup hdaudio
30 * @{
31 */
32/** @file High Definition Audio codec
33 */
34
35#include <async.h>
36#include <bitops.h>
37#include <ddf/log.h>
38#include <errno.h>
39#include <stdlib.h>
40
41#include "codec.h"
42#include "hdactl.h"
43#include "spec/codec.h"
44#include "spec/fmt.h"
45#include "stream.h"
46
47static int hda_ccmd(hda_codec_t *codec, int node, uint32_t vid, uint32_t payload,
48 uint32_t *resp)
49{
50 uint32_t verb;
51 uint32_t myresp;
52
53 if (resp == NULL)
54 resp = &myresp;
55
56 if ((vid & 0x700) != 0) {
57 verb = (codec->address << 28) |
58 ((node & 0x1ff) << 20) |
59 ((vid & 0xfff) << 8) |
60 (payload & 0xff);
61 } else {
62 verb = (codec->address << 28) |
63 ((node & 0x1ff) << 20) |
64 ((vid & 0xf) << 16) |
65 (payload & 0xffff);
66 }
67 int rc = hda_cmd(codec->hda, verb, resp);
68/*
69 if (resp != NULL) {
70 ddf_msg(LVL_NOTE, "verb 0x%" PRIx32 " -> 0x%" PRIx32, verb,
71 *resp);
72 } else {
73 ddf_msg(LVL_NOTE, "verb 0x%" PRIx32, verb);
74 }
75*/
76 return rc;
77}
78
79static int hda_get_parameter(hda_codec_t *codec, int node, hda_param_id_t param,
80 uint32_t *resp)
81{
82 return hda_ccmd(codec, node, hda_param_get, param, resp);
83}
84
85static int hda_get_subnc(hda_codec_t *codec, int node, int *startnode,
86 int *nodecount)
87{
88 int rc;
89 uint32_t resp;
90
91 rc = hda_get_parameter(codec, node, hda_sub_nc, &resp);
92 if (rc != EOK)
93 return rc;
94
95 *startnode = BIT_RANGE_EXTRACT(uint32_t, subnc_startnode_h,
96 subnc_startnode_l, resp);
97 *nodecount = BIT_RANGE_EXTRACT(uint32_t, subnc_nodecount_h,
98 subnc_nodecount_l, resp);
99
100 return EOK;
101}
102
103/** Get Function Group Type */
104static int hda_get_fgrp_type(hda_codec_t *codec, int node, bool *unsol,
105 hda_fgrp_type_t *type)
106{
107 int rc;
108 uint32_t resp;
109
110 rc = hda_get_parameter(codec, node, hda_fgrp_type, &resp);
111 if (rc != EOK)
112 return rc;
113
114 *unsol = (resp & BIT_V(uint32_t, fgrpt_unsol)) != 0;
115 *type = BIT_RANGE_EXTRACT(uint32_t, fgrpt_type_h, fgrpt_type_l, resp);
116
117 return EOK;
118}
119
120static int hda_get_clist_len(hda_codec_t *codec, int node, bool *longform,
121 int *items)
122{
123 int rc;
124 uint32_t resp;
125
126 rc = hda_get_parameter(codec, node, hda_clist_len, &resp);
127 if (rc != EOK)
128 return rc;
129
130// ddf_msg(LVL_NOTE, "hda_get_clist_len: resp=0x%x", resp);
131 *longform = resp & BIT_V(uint32_t, cll_longform);
132 *items = resp & BIT_RANGE_EXTRACT(uint32_t, cll_len_h, cll_len_l, resp);
133 return EOK;
134}
135
136static int hda_get_clist_entry(hda_codec_t *codec, int node, int n, uint32_t *resp)
137{
138 return hda_ccmd(codec, node, hda_clist_entry_get, n, resp);
139}
140
141static int hda_get_eapd_btl_enable(hda_codec_t *codec, int node, uint32_t *resp)
142{
143 return hda_ccmd(codec, node, hda_eapd_btl_enable_get, 0, resp);
144}
145
146static int hda_set_eapd_btl_enable(hda_codec_t *codec, int node, uint8_t payload)
147{
148 return hda_ccmd(codec, node, hda_eapd_btl_enable_set, payload, NULL);
149}
150
151/** Get Suppported PCM Size, Rates */
152static int hda_get_supp_rates(hda_codec_t *codec, int node, uint32_t *rates)
153{
154 return hda_get_parameter(codec, node, hda_supp_rates, rates);
155}
156
157/** Get Suppported Stream Formats */
158static int hda_get_supp_formats(hda_codec_t *codec, int node, uint32_t *fmts)
159{
160 return hda_get_parameter(codec, node, hda_supp_formats, fmts);
161}
162
163static int hda_set_converter_fmt(hda_codec_t *codec, int node, uint16_t fmt)
164{
165 return hda_ccmd(codec, node, hda_converter_fmt_set, fmt, NULL);
166}
167
168static int hda_set_converter_ctl(hda_codec_t *codec, int node, uint8_t stream,
169 uint8_t channel)
170{
171 uint32_t ctl;
172
173 ctl = (stream << cctl_stream_l) | (channel << cctl_channel_l);
174 return hda_ccmd(codec, node, hda_converter_ctl_set, ctl, NULL);
175}
176
177static int hda_set_pin_ctl(hda_codec_t *codec, int node, uint8_t pctl)
178{
179 return hda_ccmd(codec, node, hda_pin_ctl_set, pctl, NULL);
180}
181
182static int hda_get_pin_ctl(hda_codec_t *codec, int node, uint8_t *pctl)
183{
184 int rc;
185 uint32_t resp;
186
187 rc = hda_ccmd(codec, node, hda_pin_ctl_get, 0, &resp);
188 if (rc != EOK)
189 return rc;
190
191 *pctl = resp;
192 return EOK;
193}
194
195/** Get Audio Widget Capabilities */
196static int hda_get_aw_caps(hda_codec_t *codec, int node,
197 hda_awidget_type_t *type, uint32_t *caps)
198{
199 int rc;
200 uint32_t resp;
201
202 rc = hda_get_parameter(codec, node, hda_aw_caps, &resp);
203 if (rc != EOK)
204 return rc;
205
206 *type = BIT_RANGE_EXTRACT(uint32_t, awc_type_h, awc_type_l, resp);
207 *caps = resp;
208
209 return EOK;
210}
211
212/** Get Pin Capabilities */
213static int hda_get_pin_caps(hda_codec_t *codec, int node, uint32_t *caps)
214{
215 return hda_get_parameter(codec, node, hda_pin_caps, caps);
216}
217
218/** Get Power State */
219static int hda_get_power_state(hda_codec_t *codec, int node, uint32_t *pstate)
220{
221 return hda_ccmd(codec, node, hda_power_state_get, 0, pstate);
222}
223
224/** Get Configuration Default */
225static int hda_get_cfg_def(hda_codec_t *codec, int node, uint32_t *cfgdef)
226{
227 return hda_ccmd(codec, node, hda_cfg_def_get, 0, cfgdef);
228}
229
230static int hda_get_conn_sel(hda_codec_t *codec, int node, uint32_t *conn)
231{
232 return hda_ccmd(codec, node, hda_conn_sel_get, 0, conn);
233}
234
235/** Get Amplifier Gain / Mute */
236static int hda_get_amp_gain_mute(hda_codec_t *codec, int node, uint16_t payload,
237 uint32_t *resp)
238{
239// ddf_msg(LVL_NOTE, "hda_get_amp_gain_mute(codec, %d, %x)",
240// node, payload);
241 int rc = hda_ccmd(codec, node, hda_amp_gain_mute_get, payload, resp);
242// ddf_msg(LVL_NOTE, "hda_get_amp_gain_mute(codec, %d, %x, resp=%x)",
243// node, payload, *resp);
244 return rc;
245}
246
247/** Get GP I/O Count */
248static int hda_get_gpio_cnt(hda_codec_t *codec, int node, uint32_t *resp)
249{
250 return hda_get_parameter(codec, node, hda_gpio_cnt, resp);
251}
252
253static int hda_set_amp_gain_mute(hda_codec_t *codec, int node, uint16_t payload)
254{
255// ddf_msg(LVL_NOTE, "hda_set_amp_gain_mute(codec, %d, %x)",
256// node, payload);
257 return hda_ccmd(codec, node, hda_amp_gain_mute_set, payload, NULL);
258}
259
260static int hda_set_out_amp_max(hda_codec_t *codec, uint8_t aw)
261{
262 uint32_t ampcaps;
263 uint32_t gmleft, gmright;
264 uint32_t offset;
265 int rc;
266
267 rc = hda_get_parameter(codec, aw,
268 hda_out_amp_caps, &ampcaps);
269 if (rc != EOK)
270 goto error;
271
272 offset = ampcaps & 0x7f;
273 ddf_msg(LVL_NOTE, "out amp caps 0x%x (offset=0x%x)",
274 ampcaps, offset);
275
276 rc = hda_set_amp_gain_mute(codec, aw, 0xb000 + offset);
277 if (rc != EOK)
278 goto error;
279
280 rc = hda_get_amp_gain_mute(codec, aw, 0x8000, &gmleft);
281 if (rc != EOK)
282 goto error;
283
284 rc = hda_get_amp_gain_mute(codec, aw, 0xa000, &gmright);
285 if (rc != EOK)
286 goto error;
287
288 ddf_msg(LVL_NOTE, "gain/mute: L:0x%x R:0x%x", gmleft, gmright);
289
290 return EOK;
291error:
292 return rc;
293}
294
295static int hda_set_in_amp_max(hda_codec_t *codec, uint8_t aw)
296{
297 uint32_t ampcaps;
298 uint32_t gmleft, gmright;
299 uint32_t offset;
300 int i;
301 int rc;
302
303 rc = hda_get_parameter(codec, aw,
304 hda_out_amp_caps, &ampcaps);
305 if (rc != EOK)
306 goto error;
307
308 offset = ampcaps & 0x7f;
309 ddf_msg(LVL_NOTE, "in amp caps 0x%x (offset=0x%x)", ampcaps, offset);
310
311 for (i = 0; i < 15; i++) {
312 rc = hda_set_amp_gain_mute(codec, aw, 0x7000 + (i << 8) + offset);
313 if (rc != EOK)
314 goto error;
315
316 rc = hda_get_amp_gain_mute(codec, aw, 0x0000 + i, &gmleft);
317 if (rc != EOK)
318 goto error;
319
320 rc = hda_get_amp_gain_mute(codec, aw, 0x2000 + i, &gmright);
321 if (rc != EOK)
322 goto error;
323
324 ddf_msg(LVL_NOTE, "in:%d gain/mute: L:0x%x R:0x%x",
325 i, gmleft, gmright);
326 }
327
328 return EOK;
329error:
330 return rc;
331}
332
333static int hda_clist_dump(hda_codec_t *codec, uint8_t aw)
334{
335 int rc;
336 bool longform;
337 int len;
338 uint32_t resp;
339 uint32_t mask;
340 uint32_t cidx;
341 int shift;
342 int epresp;
343 int i, j;
344
345 ddf_msg(LVL_NOTE, "Connections for widget %d:", aw);
346
347 rc = hda_get_clist_len(codec, aw, &longform, &len);
348 if (rc != EOK) {
349 ddf_msg(LVL_ERROR, "Failed getting connection list length.");
350 return rc;
351 }
352
353 if (len > 1) {
354 rc = hda_get_conn_sel(codec, aw, &cidx);
355 if (rc != EOK) {
356 ddf_msg(LVL_ERROR, "Failed getting connection select");
357 return rc;
358 }
359 } else {
360 cidx = 0;
361 }
362
363// ddf_msg(LVL_NOTE, "longform:%d len:%d", longform, len);
364
365 if (longform) {
366 epresp = 2;
367 mask = 0xffff;
368 shift = 16;
369 } else {
370 epresp = 4;
371 mask = 0xff;
372 shift = 8;
373 }
374
375 i = 0;
376 while (i < len) {
377 rc = hda_get_clist_entry(codec, aw, i, &resp);
378 if (rc != EOK) {
379 ddf_msg(LVL_ERROR, "Failed getting connection list entry.");
380 return rc;
381 }
382
383 for (j = 0; j < epresp && i < len; j++) {
384 ddf_msg(LVL_NOTE, "<- %d%s", resp & mask,
385 (int)cidx == i ? " *** current *** " : "");
386 resp = resp >> shift;
387 ++i;
388 }
389
390 }
391
392 return rc;
393}
394
395static int hda_pin_init(hda_codec_t *codec, uint8_t aw)
396{
397 int rc;
398 uint32_t cfgdef;
399 uint32_t pcaps;
400 uint32_t eapd;
401 uint8_t pctl;
402
403 rc = hda_get_cfg_def(codec, aw, &cfgdef);
404 if (rc != EOK)
405 goto error;
406 ddf_msg(LVL_NOTE, "aw %d: PIN cdfgef=0x%x",
407 aw, cfgdef);
408
409 rc = hda_get_pin_caps(codec, aw, &pcaps);
410 if (rc != EOK)
411 goto error;
412 ddf_msg(LVL_NOTE, "aw %d : PIN caps=0x%x",
413 aw, pcaps);
414
415 if ((pcaps & BIT_V(uint32_t, pwc_eapd)) != 0) {
416 rc = hda_get_eapd_btl_enable(codec, aw, &eapd);
417 if (rc != EOK)
418 goto error;
419
420 ddf_msg(LVL_NOTE, "PIN %d had EAPD value=0x%x", aw, eapd);
421
422 rc = hda_set_eapd_btl_enable(codec, aw, eapd | 2);
423 if (rc != EOK)
424 goto error;
425
426 rc = hda_get_eapd_btl_enable(codec, aw, &eapd);
427 if (rc != EOK)
428 goto error;
429
430 ddf_msg(LVL_NOTE, "PIN %d now has EAPD value=0x%x", aw, eapd);
431 }
432
433 pctl = 0;
434 if ((pcaps & BIT_V(uint32_t, pwc_output)) != 0) {
435 ddf_msg(LVL_NOTE, "PIN %d will enable output", aw);
436 pctl = pctl | BIT_V(uint8_t, pctl_out_enable);
437 }
438
439 if ((pcaps & BIT_V(uint32_t, pwc_input)) != 0) {
440 ddf_msg(LVL_NOTE, "PIN %d will enable input", aw);
441 pctl = pctl | BIT_V(uint8_t, pctl_in_enable);
442 }
443
444 if ((pcaps & BIT_V(uint32_t, pwc_hpd)) != 0) {
445 ddf_msg(LVL_NOTE, "PIN %d will enable headphone drive", aw);
446 pctl = pctl | BIT_V(uint8_t, pctl_hpd_enable);
447 }
448
449/* if ((pcaps & BIT_V(uint32_t, pwc_input)) != 0) {
450 ddf_msg(LVL_NOTE, "PIN %d will enable input");
451 pctl = pctl | BIT_V(uint8_t, pctl_input_enable);
452 }
453*/
454 ddf_msg(LVL_NOTE, "Setting PIN %d ctl to 0x%x", aw, pctl);
455 rc = hda_set_pin_ctl(codec, aw, pctl);
456 if (rc != EOK)
457 goto error;
458
459 pctl = 0;
460 rc = hda_get_pin_ctl(codec, aw, &pctl);
461 if (rc != EOK)
462 goto error;
463
464 ddf_msg(LVL_NOTE, "PIN %d ctl reads as 0x%x", aw, pctl);
465
466 return EOK;
467error:
468 return rc;
469}
470
471/** Init power-control in wiget capable of doing so. */
472static int hda_power_ctl_init(hda_codec_t *codec, uint8_t aw)
473{
474 int rc;
475 uint32_t pwrstate;
476
477 ddf_msg(LVL_NOTE, "aw %d is power control-capable", aw);
478
479 rc = hda_get_power_state(codec, aw, &pwrstate);
480 if (rc != EOK)
481 goto error;
482 ddf_msg(LVL_NOTE, "aw %d: power state = 0x%x", aw, pwrstate);
483
484 return EOK;
485error:
486 return rc;
487}
488
489hda_codec_t *hda_codec_init(hda_t *hda, uint8_t address)
490{
491 hda_codec_t *codec;
492 int rc;
493 int sfg, nfg;
494 int saw, naw;
495 int fg, aw;
496 bool unsol;
497 hda_fgrp_type_t grptype;
498 hda_awidget_type_t awtype;
499 uint32_t awcaps;
500 uint32_t rates;
501 uint32_t formats;
502 uint32_t gpio;
503
504 codec = calloc(1, sizeof(hda_codec_t));
505 if (codec == NULL)
506 return NULL;
507
508 codec->hda = hda;
509 codec->address = address;
510 codec->in_aw = -1;
511
512 rc = hda_get_subnc(codec, 0, &sfg, &nfg);
513 if (rc != EOK)
514 goto error;
515
516 ddf_msg(LVL_NOTE, "hda_get_subnc -> %d", rc);
517 ddf_msg(LVL_NOTE, "sfg=%d nfg=%d", sfg, nfg);
518
519 for (fg = sfg; fg < sfg + nfg; fg++) {
520 ddf_msg(LVL_NOTE, "Enumerate FG %d", fg);
521
522 rc = hda_get_fgrp_type(codec, fg, &unsol, &grptype);
523 if (rc != EOK)
524 goto error;
525
526 ddf_msg(LVL_NOTE, "hda_get_fgrp_type -> %d", rc);
527 ddf_msg(LVL_NOTE, "unsol: %d, grptype: %d", unsol, grptype);
528
529 rc = hda_get_gpio_cnt(codec, fg, &gpio);
530 if (rc != EOK)
531 goto error;
532
533 ddf_msg(LVL_NOTE, "GPIO: wake=%d unsol=%d gpis=%d gpos=%d gpios=%d",
534 (gpio & BIT_V(uint32_t, 31)) != 0,
535 (gpio & BIT_V(uint32_t, 30)) != 0,
536 BIT_RANGE_EXTRACT(uint32_t, 23, 16, gpio),
537 BIT_RANGE_EXTRACT(uint32_t, 15, 8, gpio),
538 BIT_RANGE_EXTRACT(uint32_t, 7, 0, gpio));
539
540 rc = hda_power_ctl_init(codec, fg);
541 if (rc != EOK)
542 goto error;
543
544 rc = hda_get_subnc(codec, fg, &saw, &naw);
545 if (rc != EOK)
546 goto error;
547
548 ddf_msg(LVL_NOTE, "hda_get_subnc -> %d", rc);
549 ddf_msg(LVL_NOTE, "saw=%d baw=%d", saw, naw);
550
551 for (aw = saw; aw < saw + naw; aw++) {
552 rc = hda_get_aw_caps(codec, aw, &awtype, &awcaps);
553 if (rc != EOK)
554 goto error;
555 ddf_msg(LVL_NOTE, "aw %d: type=0x%x caps=0x%x",
556 aw, awtype, awcaps);
557
558 if ((awcaps & BIT_V(uint32_t, awc_power_cntrl)) != 0) {
559 rc = hda_power_ctl_init(codec, aw);
560 if (rc != EOK)
561 goto error;
562 }
563
564 switch (awtype) {
565 case awt_audio_input:
566 case awt_audio_mixer:
567 case awt_audio_selector:
568 case awt_pin_complex:
569 case awt_power_widget:
570 rc = hda_clist_dump(codec, aw);
571 if (rc != EOK)
572 goto error;
573 break;
574 default:
575 break;
576 }
577
578 if (awtype == awt_pin_complex) {
579 rc = hda_pin_init(codec, aw);
580 if (rc != EOK)
581 goto error;
582 } else if (awtype == awt_audio_output) {
583 codec->out_aw_list[codec->out_aw_num++] = aw;
584
585 rc = hda_get_supp_rates(codec, aw, &rates);
586 if (rc != EOK)
587 goto error;
588
589 rc = hda_get_supp_formats(codec, aw, &formats);
590 if (rc != EOK)
591 goto error;
592
593 ddf_msg(LVL_NOTE, "Output widget %d: rates=0x%x formats=0x%x",
594 aw, rates, formats);
595 } else if (awtype == awt_audio_input) {
596 if (codec->in_aw < 0) {
597 ddf_msg(LVL_NOTE, "Selected input "
598 "widget %d\n", aw);
599 codec->in_aw = aw;
600 } else {
601 ddf_msg(LVL_NOTE, "Ignoring input "
602 "widget %d\n", aw);
603 }
604
605 rc = hda_get_supp_rates(codec, aw, &rates);
606 if (rc != EOK)
607 goto error;
608
609 rc = hda_get_supp_formats(codec, aw, &formats);
610 if (rc != EOK)
611 goto error;
612
613 ddf_msg(LVL_NOTE, "Input widget %d: rates=0x%x formats=0x%x",
614 aw, rates, formats);
615 }
616
617 if ((awcaps & BIT_V(uint32_t, awc_out_amp_present)) != 0)
618 hda_set_out_amp_max(codec, aw);
619
620 if ((awcaps & BIT_V(uint32_t, awc_in_amp_present)) != 0)
621 hda_set_in_amp_max(codec, aw);
622 }
623 }
624
625 hda_ctl_dump_info(hda->ctl);
626
627 ddf_msg(LVL_NOTE, "Codec OK");
628 return codec;
629error:
630 free(codec);
631 return NULL;
632}
633
634void hda_codec_fini(hda_codec_t *codec)
635{
636 ddf_msg(LVL_NOTE, "hda_codec_fini()");
637 free(codec);
638}
639
640int hda_out_converter_setup(hda_codec_t *codec, hda_stream_t *stream)
641{
642 int rc;
643 int out_aw;
644 int i;
645
646 for (i = 0; i < codec->out_aw_num; i++) {
647 out_aw = codec->out_aw_list[i];
648
649 /* Configure converter */
650
651 ddf_msg(LVL_NOTE, "Configure output converter format");
652 rc = hda_set_converter_fmt(codec, out_aw, stream->fmt);
653 if (rc != EOK)
654 goto error;
655
656 ddf_msg(LVL_NOTE, "Configure output converter stream, channel");
657 rc = hda_set_converter_ctl(codec, out_aw, stream->sid, 0);
658 if (rc != EOK)
659 goto error;
660 }
661
662 return EOK;
663error:
664 return rc;
665}
666
667int hda_in_converter_setup(hda_codec_t *codec, hda_stream_t *stream)
668{
669 int rc;
670
671 /* Configure converter */
672
673 ddf_msg(LVL_NOTE, "Configure input converter format");
674 rc = hda_set_converter_fmt(codec, codec->in_aw, stream->fmt);
675 if (rc != EOK)
676 goto error;
677
678 ddf_msg(LVL_NOTE, "Configure input converter stream, channel");
679 rc = hda_set_converter_ctl(codec, codec->in_aw, stream->sid, 0);
680 if (rc != EOK)
681 goto error;
682
683 return EOK;
684error:
685 return rc;
686}
687
688/** @}
689 */
Note: See TracBrowser for help on using the repository browser.