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

Last change on this file was 0d59ea7e, checked in by Jiri Svoboda <jiri@…>, 3 years ago

Multiple HD Audio converters cannot pull from a single stream

We select one arbitrary output converter for out PCM output, similar to what
we do for input.

We filter the 'other' VirtualBox output converters based on rates/formats
being zero.

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