Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / pci / hdaudio / hdaudio_afg.c
blob1ec132c903b941feae4dae9885946c4628f3d302
1 /* $NetBSD: hdaudio_afg.c,v 1.17 2009/10/11 08:50:11 sborrill Exp $ */
3 /*
4 * Copyright (c) 2009 Precedence Technologies Ltd <support@precedence.co.uk>
5 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
6 * All rights reserved.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Precedence Technologies Ltd
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
33 * Widget parsing from FreeBSD hdac.c:
35 * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
36 * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
37 * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
62 #include <sys/cdefs.h>
63 __KERNEL_RCSID(0, "$NetBSD: hdaudio_afg.c,v 1.17 2009/10/11 08:50:11 sborrill Exp $");
65 #include <sys/types.h>
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
69 #include <sys/device.h>
70 #include <sys/conf.h>
71 #include <sys/bus.h>
72 #include <sys/kmem.h>
74 #include <sys/audioio.h>
75 #include <dev/audio_if.h>
76 #include <dev/auconv.h>
78 #include <dev/pci/hdaudio/hdaudiovar.h>
79 #include <dev/pci/hdaudio/hdaudioreg.h>
80 #include <dev/pci/hdaudio/hdaudio_mixer.h>
81 #include <dev/pci/hdaudio/hdaudioio.h>
83 #ifndef AUFMT_SURROUND_7_1
84 #define AUFMT_SURROUND_7_1 (AUFMT_DOLBY_5_1|AUFMT_SIDE_LEFT|AUFMT_SIDE_RIGHT)
85 #endif
87 /* #define HDAUDIO_AFG_DEBUG 1 */
89 #if defined(HDAUDIO_AFG_DEBUG)
90 static int hdaudio_afg_debug = HDAUDIO_AFG_DEBUG;
91 #else
92 static int hdaudio_afg_debug = 0;
93 #endif
95 #define hda_debug(sc, ...) \
96 if (hdaudio_afg_debug) hda_print(sc, __VA_ARGS__)
98 #define HDAUDIO_MIXER_CLASS_OUTPUTS 0
99 #define HDAUDIO_MIXER_CLASS_INPUTS 1
100 #define HDAUDIO_MIXER_CLASS_RECORD 2
101 #define HDAUDIO_MIXER_CLASS_LAST HDAUDIO_MIXER_CLASS_RECORD
103 #define HDAUDIO_GPIO_MASK 0
104 #define HDAUDIO_GPIO_DIR 1
105 #define HDAUDIO_GPIO_DATA 2
107 #define HDAUDIO_UNSOLTAG_EVENT_HP 0x00
109 #define HDAUDIO_HP_SENSE_PERIOD hz
111 static const char *hdaudio_afg_mixer_names[] = HDAUDIO_DEVICE_NAMES;
113 static const char *hdaudio_afg_port_connectivity[] = {
114 "Jack",
115 "Unconnected",
116 "Fixed Function",
117 "Jack & Fixed Function"
119 static const char *hdaudio_afg_default_device[] = {
120 "Line Out",
121 "Speaker",
122 "HP Out",
123 "CD",
124 "SPDIF Out",
125 "Digital Other Out",
126 "Modem Line Side",
127 "Modem Handset Side",
128 "Line In",
129 "AUX",
130 "Mic In",
131 "Telephony",
132 "SPDIF In",
133 "Digital Other In",
134 "Reserved",
135 "Other"
137 static const char *hdaudio_afg_color[] = {
138 "Unknown",
139 "Black",
140 "Grey",
141 "Blue",
142 "Green",
143 "Red",
144 "Orange",
145 "Yellow",
146 "Purple",
147 "Pink",
148 "ReservedA",
149 "ReservedB",
150 "ReservedC",
151 "ReservedD",
152 "White",
153 "Other"
156 #define HDAUDIO_MAXFORMATS 24
157 #define HDAUDIO_MAXCONNECTIONS 32
158 #define HDAUDIO_MAXPINS 16
159 #define HDAUDIO_PARSE_MAXDEPTH 10
161 #define HDAUDIO_AMP_VOL_DEFAULT (-1)
162 #define HDAUDIO_AMP_MUTE_DEFAULT (0xffffffff)
163 #define HDAUDIO_AMP_MUTE_NONE 0
164 #define HDAUDIO_AMP_MUTE_LEFT (1 << 0)
165 #define HDAUDIO_AMP_MUTE_RIGHT (1 << 1)
166 #define HDAUDIO_AMP_MUTE_ALL (HDAUDIO_AMP_MUTE_LEFT | HDAUDIO_AMP_MUTE_RIGHT)
167 #define HDAUDIO_AMP_LEFT_MUTED(x) ((x) & HDAUDIO_AMP_MUTE_LEFT)
168 #define HDAUDIO_AMP_RIGHT_MUTED(x) (((x) & HDAUDIO_AMP_MUTE_RIGHT) >> 1)
170 #define HDAUDIO_ADC_MONITOR 1
172 enum hdaudio_pindir {
173 HDAUDIO_PINDIR_NONE = 0,
174 HDAUDIO_PINDIR_OUT = 1,
175 HDAUDIO_PINDIR_IN = 2,
176 HDAUDIO_PINDIR_INOUT = 3,
179 #define hda_get_param(sc, cop) \
180 hdaudio_command((sc)->sc_codec, (sc)->sc_nid, \
181 CORB_GET_PARAMETER, COP_##cop)
182 #define hda_get_wparam(w, cop) \
183 hdaudio_command((w)->w_afg->sc_codec, (w)->w_nid, \
184 CORB_GET_PARAMETER, COP_##cop)
186 struct hdaudio_assoc {
187 bool as_enable;
188 bool as_activated;
189 u_char as_index;
190 enum hdaudio_pindir as_dir;
191 u_char as_pincnt;
192 u_char as_fakeredir;
193 bool as_digital;
194 int as_hpredir;
195 int as_pins[HDAUDIO_MAXPINS];
196 int as_dacs[HDAUDIO_MAXPINS];
199 struct hdaudio_widget {
200 struct hdaudio_afg_softc *w_afg;
201 char w_name[32];
202 int w_nid;
203 bool w_enable;
204 bool w_waspin;
205 int w_selconn;
206 int w_bindas;
207 int w_bindseqmask;
208 int w_pflags;
209 int w_audiodev;
210 uint32_t w_audiomask;
212 int w_nconns;
213 int w_conns[HDAUDIO_MAXCONNECTIONS];
214 bool w_connsenable[HDAUDIO_MAXCONNECTIONS];
216 int w_type;
217 struct {
218 uint32_t aw_cap;
219 uint32_t pcm_size_rate;
220 uint32_t stream_format;
221 uint32_t outamp_cap;
222 uint32_t inamp_cap;
223 uint32_t eapdbtl;
224 } w_p;
225 struct {
226 uint32_t config;
227 uint32_t cap;
228 uint32_t ctrl;
229 } w_pin;
232 struct hdaudio_control {
233 struct hdaudio_widget *ctl_widget, *ctl_childwidget;
234 bool ctl_enable;
235 int ctl_index;
236 enum hdaudio_pindir ctl_dir, ctl_ndir;
237 int ctl_mute, ctl_step, ctl_size, ctl_offset;
238 int ctl_left, ctl_right, ctl_forcemute;
239 uint32_t ctl_muted;
240 uint32_t ctl_audiomask, ctl_paudiomask;
243 #define HDAUDIO_CONTROL_GIVE(ctl) ((ctl)->ctl_step ? 1 : 0)
245 struct hdaudio_mixer {
246 struct hdaudio_control *mx_ctl;
247 mixer_devinfo_t mx_di;
250 struct hdaudio_audiodev {
251 struct hdaudio_afg_softc *ad_sc;
252 device_t ad_audiodev;
253 struct audio_encoding_set *ad_encodings;
254 int ad_nformats;
255 struct audio_format ad_formats[HDAUDIO_MAXFORMATS];
257 struct hdaudio_stream *ad_playback;
258 void (*ad_playbackintr)(void *);
259 void *ad_playbackintrarg;
260 int ad_playbacknid[HDAUDIO_MAXPINS];
261 struct hdaudio_assoc *ad_playbackassoc;
262 struct hdaudio_stream *ad_capture;
263 void (*ad_captureintr)(void *);
264 void *ad_captureintrarg;
265 int ad_capturenid[HDAUDIO_MAXPINS];
266 struct hdaudio_assoc *ad_captureassoc;
269 struct hdaudio_afg_softc {
270 device_t sc_dev;
271 struct hdaudio_softc *sc_host;
272 struct hdaudio_codec *sc_codec;
273 struct hdaudio_function_group *sc_fg;
274 int sc_nid;
275 uint16_t sc_vendor, sc_product;
277 prop_array_t sc_config;
279 int sc_startnode, sc_endnode;
280 int sc_nwidgets;
281 struct hdaudio_widget *sc_widgets;
282 int sc_nassocs;
283 struct hdaudio_assoc *sc_assocs;
284 int sc_nctls;
285 struct hdaudio_control *sc_ctls;
286 int sc_nmixers;
287 struct hdaudio_mixer *sc_mixers;
289 int sc_pchan, sc_rchan;
290 audio_params_t sc_pparam, sc_rparam;
292 struct callout sc_jack_callout;
293 bool sc_jack_polling;
295 struct {
296 uint32_t afg_cap;
297 uint32_t pcm_size_rate;
298 uint32_t stream_format;
299 uint32_t outamp_cap;
300 uint32_t inamp_cap;
301 uint32_t power_states;
302 uint32_t gpio_cnt;
303 } sc_p;
305 struct hdaudio_audiodev sc_audiodev;
308 static int hdaudio_afg_match(device_t, cfdata_t, void *);
309 static void hdaudio_afg_attach(device_t, device_t, void *);
310 static int hdaudio_afg_detach(device_t, int);
311 static void hdaudio_afg_childdet(device_t, device_t);
312 static bool hdaudio_afg_suspend(device_t, pmf_qual_t);
313 static bool hdaudio_afg_resume(device_t, pmf_qual_t);
315 CFATTACH_DECL2_NEW(
316 hdafg,
317 sizeof(struct hdaudio_afg_softc),
318 hdaudio_afg_match,
319 hdaudio_afg_attach,
320 hdaudio_afg_detach,
321 NULL,
322 NULL,
323 hdaudio_afg_childdet
326 static const struct audio_device hdaudio_afg_audio_device = {
327 "HD Audio",
328 "1.0",
329 "hdaudio"
332 static int hdaudio_afg_query_encoding(void *, struct audio_encoding *);
333 static int hdaudio_afg_set_params(void *, int, int,
334 audio_params_t *,
335 audio_params_t *,
336 stream_filter_list_t *,
337 stream_filter_list_t *);
338 static int hdaudio_afg_round_blocksize(void *, int, int,
339 const audio_params_t *);
340 static int hdaudio_afg_commit_settings(void *);
341 static int hdaudio_afg_halt_output(void *);
342 static int hdaudio_afg_halt_input(void *);
343 static int hdaudio_afg_set_port(void *, mixer_ctrl_t *);
344 static int hdaudio_afg_get_port(void *, mixer_ctrl_t *);
345 static int hdaudio_afg_query_devinfo(void *, mixer_devinfo_t *);
346 static void * hdaudio_afg_allocm(void *, int, size_t, struct malloc_type *, int);
347 static void hdaudio_afg_freem(void *, void *, struct malloc_type *);
348 static int hdaudio_afg_getdev(void *, struct audio_device *);
349 static size_t hdaudio_afg_round_buffersize(void *, int, size_t);
350 static paddr_t hdaudio_afg_mappage(void *, void *, off_t, int);
351 static int hdaudio_afg_get_props(void *);
352 static int hdaudio_afg_trigger_output(void *, void *, void *, int,
353 void (*)(void *), void *,
354 const audio_params_t *);
355 static int hdaudio_afg_trigger_input(void *, void *, void *, int,
356 void (*)(void *), void *,
357 const audio_params_t *);
358 static int hdaudio_afg_dev_ioctl(void *, u_long, void *, int, lwp_t *);
360 static const struct audio_hw_if hdaudio_afg_hw_if = {
361 .query_encoding = hdaudio_afg_query_encoding,
362 .set_params = hdaudio_afg_set_params,
363 .round_blocksize = hdaudio_afg_round_blocksize,
364 .commit_settings = hdaudio_afg_commit_settings,
365 .halt_output = hdaudio_afg_halt_output,
366 .halt_input = hdaudio_afg_halt_input,
367 .getdev = hdaudio_afg_getdev,
368 .set_port = hdaudio_afg_set_port,
369 .get_port = hdaudio_afg_get_port,
370 .query_devinfo = hdaudio_afg_query_devinfo,
371 .allocm = hdaudio_afg_allocm,
372 .freem = hdaudio_afg_freem,
373 .round_buffersize = hdaudio_afg_round_buffersize,
374 .mappage = hdaudio_afg_mappage,
375 .get_props = hdaudio_afg_get_props,
376 .trigger_output = hdaudio_afg_trigger_output,
377 .trigger_input = hdaudio_afg_trigger_input,
378 .dev_ioctl = hdaudio_afg_dev_ioctl
381 static int
382 hdaudio_afg_append_formats(struct hdaudio_audiodev *ad,
383 const struct audio_format *format)
385 if (ad->ad_nformats + 1 >= HDAUDIO_MAXFORMATS) {
386 hda_print1(ad->ad_sc, "[ENOMEM] ");
387 return ENOMEM;
389 ad->ad_formats[ad->ad_nformats++] = *format;
391 return 0;
394 static struct hdaudio_widget *
395 hdaudio_afg_widget_lookup(struct hdaudio_afg_softc *sc, int nid)
397 if (sc->sc_widgets == NULL || sc->sc_nwidgets == 0) {
398 hda_error(sc, "lookup failed; widgets %p nwidgets %d\n",
399 sc->sc_widgets, sc->sc_nwidgets);
400 return NULL;
402 if (nid < sc->sc_startnode || nid >= sc->sc_endnode) {
403 hda_debug(sc, "nid %02X out of range (%02X-%02X)\n",
404 nid, sc->sc_startnode, sc->sc_endnode);
405 return NULL;
407 return &sc->sc_widgets[nid - sc->sc_startnode];
410 static struct hdaudio_control *
411 hdaudio_afg_control_lookup(struct hdaudio_afg_softc *sc, int nid,
412 enum hdaudio_pindir dir, int index, int cnt)
414 struct hdaudio_control *ctl;
415 int i, found = 0;
417 if (sc->sc_ctls == NULL)
418 return NULL;
419 for (i = 0; i < sc->sc_nctls; i++) {
420 ctl = &sc->sc_ctls[i];
421 if (ctl->ctl_enable == false)
422 continue;
423 if (ctl->ctl_widget->w_nid != nid)
424 continue;
425 if (dir && ctl->ctl_ndir != dir)
426 continue;
427 if (index >= 0 && ctl->ctl_ndir == HDAUDIO_PINDIR_IN &&
428 ctl->ctl_dir == ctl->ctl_ndir && ctl->ctl_index != index)
429 continue;
430 found++;
431 if (found == cnt || cnt <= 0)
432 return ctl;
435 return NULL;
438 static void
439 hdaudio_afg_widget_connection_parse(struct hdaudio_widget *w)
441 struct hdaudio_afg_softc *sc = w->w_afg;
442 uint32_t res;
443 int i, j, maxconns, ents, entnum;
444 int cnid, addcnid, prevcnid;
446 w->w_nconns = 0;
448 res = hda_get_wparam(w, CONNECTION_LIST_LENGTH);
449 ents = COP_CONNECTION_LIST_LENGTH_LEN(res);
450 if (ents < 1)
451 return;
452 if (res & COP_CONNECTION_LIST_LENGTH_LONG_FORM)
453 entnum = 2;
454 else
455 entnum = 4;
456 maxconns = (sizeof(w->w_conns) / sizeof(w->w_conns[0])) - 1;
457 prevcnid = 0;
459 #define CONN_RMASK(e) (1 << ((32 / (e)) - 1))
460 #define CONN_NMASK(e) (CONN_RMASK(e) - 1)
461 #define CONN_RESVAL(r, e, n) ((r) >> ((32 / (e)) * (n)))
462 #define CONN_RANGE(r, e, n) (CONN_RESVAL(r, e, n) & CONN_RMASK(e))
463 #define CONN_CNID(r, e, n) (CONN_RESVAL(r, e, n) & CONN_NMASK(e))
465 for (i = 0; i < ents; i += entnum) {
466 res = hdaudio_command(sc->sc_codec, w->w_nid,
467 CORB_GET_CONNECTION_LIST_ENTRY, i);
468 for (j = 0; j < entnum; j++) {
469 cnid = CONN_CNID(res, entnum, j);
470 if (cnid == 0) {
471 if (w->w_nconns < ents) {
472 hda_error(sc, "WARNING: zero cnid\n");
473 } else {
474 goto getconns_out;
477 if (cnid < sc->sc_startnode || cnid >= sc->sc_endnode)
478 hda_debug(sc, "ghost nid=%02X\n", cnid);
479 if (CONN_RANGE(res, entnum, j) == 0)
480 addcnid = cnid;
481 else if (prevcnid == 0 || prevcnid >= cnid) {
482 hda_error(sc, "invalid child range\n");
483 addcnid = cnid;
484 } else
485 addcnid = prevcnid + 1;
486 while (addcnid <= cnid) {
487 if (w->w_nconns > maxconns) {
488 hda_error(sc,
489 "max connections reached\n");
490 goto getconns_out;
492 w->w_connsenable[w->w_nconns] = true;
493 w->w_conns[w->w_nconns++] = addcnid++;
494 hda_trace(sc, "add connection %02X->%02X\n",
495 w->w_nid, addcnid - 1);
497 prevcnid = cnid;
500 #undef CONN_RMASK
501 #undef CONN_NMASK
502 #undef CONN_RESVAL
503 #undef CONN_RANGE
504 #undef CONN_CNID
506 getconns_out:
507 return;
510 static void
511 hdaudio_afg_widget_pin_dump(struct hdaudio_afg_softc *sc)
513 struct hdaudio_widget *w;
514 int i, conn, color, defdev;
516 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
517 w = hdaudio_afg_widget_lookup(sc, i);
518 if (w == NULL || w->w_enable == false)
519 continue;
520 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
521 continue;
522 conn = COP_CFG_PORT_CONNECTIVITY(w->w_pin.config);
523 color = COP_CFG_COLOR(w->w_pin.config);
524 defdev = COP_CFG_DEFAULT_DEVICE(w->w_pin.config);
525 if (conn != 1) {
526 hda_print(sc, "io %02X: %s (%s, %s)\n",
527 w->w_nid,
528 hdaudio_afg_default_device[defdev],
529 hdaudio_afg_color[color],
530 hdaudio_afg_port_connectivity[conn]);
535 static uint32_t
536 hdaudio_afg_widget_getconfig(struct hdaudio_widget *w)
538 struct hdaudio_afg_softc *sc = w->w_afg;
539 uint32_t config = 0;
540 prop_object_iterator_t iter;
541 prop_dictionary_t dict;
542 prop_object_t obj;
543 int16_t nid;
545 if (sc->sc_config == NULL)
546 goto biosconfig;
548 iter = prop_array_iterator(sc->sc_config);
549 if (iter == NULL)
550 goto biosconfig;
551 prop_object_iterator_reset(iter);
552 while ((obj = prop_object_iterator_next(iter)) != NULL) {
553 if (prop_object_type(obj) != PROP_TYPE_DICTIONARY)
554 continue;
555 dict = (prop_dictionary_t)obj;
556 if (!prop_dictionary_get_int16(dict, "nid", &nid) ||
557 !prop_dictionary_get_uint32(dict, "config", &config))
558 continue;
559 if (nid == w->w_nid)
560 return config;
563 biosconfig:
564 return hdaudio_command(sc->sc_codec, w->w_nid,
565 CORB_GET_CONFIGURATION_DEFAULT, 0);
568 static void
569 hdaudio_afg_widget_pin_parse(struct hdaudio_widget *w)
571 struct hdaudio_afg_softc *sc = w->w_afg;
572 #if notyet
573 int conn, color, defdev;
574 #endif
576 w->w_pin.cap = hda_get_wparam(w, PIN_CAPABILITIES);
577 w->w_pin.config = hdaudio_afg_widget_getconfig(w);
578 w->w_pin.ctrl = hdaudio_command(sc->sc_codec, w->w_nid,
579 CORB_GET_PIN_WIDGET_CONTROL, 0);
581 /* treat line-out as speaker, unless connection type is RCA */
582 if (COP_CFG_DEFAULT_DEVICE(w->w_pin.config) == COP_DEVICE_LINE_OUT &&
583 COP_CFG_CONNECTION_TYPE(w->w_pin.config) != COP_CONN_TYPE_RCA) {
584 w->w_pin.config &= ~COP_DEVICE_MASK;
585 w->w_pin.config |= (COP_DEVICE_SPEAKER << COP_DEVICE_SHIFT);
588 if (w->w_pin.cap & COP_PINCAP_EAPD_CAPABLE) {
589 w->w_p.eapdbtl = hdaudio_command(sc->sc_codec, w->w_nid,
590 CORB_GET_EAPD_BTL_ENABLE, 0);
591 w->w_p.eapdbtl &= 0x7;
592 w->w_p.eapdbtl |= COP_EAPD_ENABLE_EAPD;
593 } else
594 w->w_p.eapdbtl = 0xffffffff;
596 #if 0
597 /* XXX VT1708 */
598 if (COP_CFG_DEFAULT_DEVICE(w->w_pin.config) == COP_DEVICE_SPEAKER &&
599 COP_CFG_DEFAULT_ASSOCIATION(w->w_pin.config) == 15) {
600 hda_trace(sc, "forcing speaker nid %02X to assoc=14\n",
601 w->w_nid);
602 /* set assoc=14 */
603 w->w_pin.config &= ~0xf0;
604 w->w_pin.config |= 0xe0;
606 if (COP_CFG_DEFAULT_DEVICE(w->w_pin.config) == COP_DEVICE_HP_OUT &&
607 COP_CFG_PORT_CONNECTIVITY(w->w_pin.config) == COP_PORT_NONE) {
608 hda_trace(sc, "forcing hp out nid %02X to assoc=14\n",
609 w->w_nid);
610 /* set connectivity to 'jack' */
611 w->w_pin.config &= ~(COP_PORT_BOTH << 30);
612 w->w_pin.config |= (COP_PORT_JACK << 30);
613 /* set seq=15 */
614 w->w_pin.config &= ~0xf;
615 w->w_pin.config |= 15;
616 /* set assoc=14 */
617 w->w_pin.config &= ~0xf0;
618 w->w_pin.config |= 0xe0;
620 #endif
622 #if notyet
623 conn = COP_CFG_PORT_CONNECTIVITY(w->w_pin.config);
624 color = COP_CFG_COLOR(w->w_pin.config);
625 defdev = COP_CFG_DEFAULT_DEVICE(w->w_pin.config);
627 /* TODO: set w->w_name */
628 #else
629 w->w_name[0] = '\0';
630 sprintf(w->w_name, "%02Xh", w->w_nid);
631 #endif
634 static uint32_t
635 hdaudio_afg_widget_getcaps(struct hdaudio_widget *w)
637 uint32_t wcap, config;
639 wcap = hda_get_wparam(w, AUDIO_WIDGET_CAPABILITIES);
640 config = hdaudio_afg_widget_getconfig(w);
642 w->w_waspin = false;
644 if (COP_CFG_DEFAULT_DEVICE(config) == COP_DEVICE_SPEAKER &&
645 (wcap & (COP_AWCAP_INAMP_PRESENT|COP_AWCAP_OUTAMP_PRESENT)) == 0) {
646 wcap &= ~COP_AWCAP_TYPE_MASK;
647 wcap |= (COP_AWCAP_TYPE_BEEP_GENERATOR << COP_AWCAP_TYPE_SHIFT);
648 w->w_waspin = true;
651 return wcap;
654 static void
655 hdaudio_afg_widget_parse(struct hdaudio_widget *w)
657 struct hdaudio_afg_softc *sc = w->w_afg;
659 w->w_p.aw_cap = hdaudio_afg_widget_getcaps(w);
660 w->w_type = COP_AWCAP_TYPE(w->w_p.aw_cap);
662 hdaudio_afg_widget_connection_parse(w);
664 if (w->w_p.aw_cap & COP_AWCAP_INAMP_PRESENT) {
665 if (w->w_p.aw_cap & COP_AWCAP_AMP_PARAM_OVERRIDE)
666 w->w_p.inamp_cap = hda_get_wparam(w,
667 AMPLIFIER_CAPABILITIES_INAMP);
668 else
669 w->w_p.inamp_cap = sc->sc_p.inamp_cap;
671 if (w->w_p.aw_cap & COP_AWCAP_OUTAMP_PRESENT) {
672 if (w->w_p.aw_cap & COP_AWCAP_AMP_PARAM_OVERRIDE)
673 w->w_p.outamp_cap = hda_get_wparam(w,
674 AMPLIFIER_CAPABILITIES_OUTAMP);
675 else
676 w->w_p.outamp_cap = sc->sc_p.outamp_cap;
679 w->w_p.stream_format = 0;
680 w->w_p.pcm_size_rate = 0;
681 switch (w->w_type) {
682 case COP_AWCAP_TYPE_AUDIO_OUTPUT:
683 case COP_AWCAP_TYPE_AUDIO_INPUT:
684 if (w->w_p.aw_cap & COP_AWCAP_FORMAT_OVERRIDE) {
685 w->w_p.stream_format = hda_get_wparam(w,
686 SUPPORTED_STREAM_FORMATS);
687 w->w_p.pcm_size_rate = hda_get_wparam(w,
688 SUPPORTED_PCM_SIZE_RATES);
689 } else {
690 w->w_p.stream_format = sc->sc_p.stream_format;
691 w->w_p.pcm_size_rate = sc->sc_p.pcm_size_rate;
693 break;
694 case COP_AWCAP_TYPE_PIN_COMPLEX:
695 hdaudio_afg_widget_pin_parse(w);
696 break;
700 static void
701 hdaudio_afg_assoc_dump(struct hdaudio_afg_softc *sc)
703 struct hdaudio_assoc *as = sc->sc_assocs;
704 struct hdaudio_widget *w;
705 uint32_t conn, color, defdev;
706 int maxassocs = sc->sc_nassocs;
707 int i, j;
709 for (i = 0; i < maxassocs; i++) {
710 int ndacs = 0;
712 if (as[i].as_enable == false)
713 continue;
715 for (j = 0; j < HDAUDIO_MAXPINS; j++) {
716 if (as[i].as_dacs[j] == 0)
717 continue;
718 ++ndacs;
719 hda_print(sc, "%s%d:%02X, %s ",
720 as[i].as_dir == HDAUDIO_PINDIR_IN ? "ADC" : "DAC",
721 i, as[i].as_dacs[j],
722 as[i].as_digital ? "Digital" : "Analog");
724 w = hdaudio_afg_widget_lookup(sc, as[i].as_pins[j]);
725 if (w == NULL) {
726 hda_print1(sc, "<none>\n");
727 continue;
729 conn = COP_CFG_PORT_CONNECTIVITY(w->w_pin.config);
730 color = COP_CFG_COLOR(w->w_pin.config);
731 defdev = COP_CFG_DEFAULT_DEVICE(w->w_pin.config);
732 if (conn != 1) {
733 hda_print1(sc, "%s: %s (%s, %02X)\n",
734 hdaudio_afg_default_device[defdev],
735 hdaudio_afg_port_connectivity[conn],
736 hdaudio_afg_color[color], w->w_nid);
737 } else {
738 hda_print1(sc, "<unknown>\n");
741 if (ndacs == 0)
742 hda_print1(sc, "<none>\n");
746 static void
747 hdaudio_afg_assoc_parse(struct hdaudio_afg_softc *sc)
749 struct hdaudio_assoc *as;
750 struct hdaudio_widget *w;
751 int i, j, cnt, maxassocs, type, assoc, seq, first, hpredir;
752 enum hdaudio_pindir dir;
754 hda_debug(sc, " count present associations\n");
755 /* Count present associations */
756 maxassocs = 0;
757 for (j = 1; j < HDAUDIO_MAXPINS; j++) {
758 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
759 w = hdaudio_afg_widget_lookup(sc, i);
760 if (w == NULL || w->w_enable == false)
761 continue;
762 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
763 continue;
764 if (COP_CFG_DEFAULT_ASSOCIATION(w->w_pin.config) != j)
765 continue;
766 maxassocs++;
767 if (j != 15) /* There could be many 1-pin assocs #15 */
768 break;
772 hda_debug(sc, " maxassocs %d\n", maxassocs);
773 sc->sc_nassocs = maxassocs;
775 if (maxassocs < 1)
776 return;
778 hda_debug(sc, " allocating memory\n");
779 as = kmem_zalloc(maxassocs * sizeof(*as), KM_SLEEP);
780 for (i = 0; i < maxassocs; i++) {
781 as[i].as_hpredir = -1;
782 /* as[i].as_chan = NULL; */
783 as[i].as_digital = true;
786 hda_debug(sc, " scan associations, skipping as=0\n");
787 /* Scan associations skipping as=0 */
788 cnt = 0;
789 for (j = 1; j < HDAUDIO_MAXPINS && cnt < maxassocs; j++) {
790 first = 16;
791 hpredir = 0;
792 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
793 w = hdaudio_afg_widget_lookup(sc, i);
794 if (w == NULL || w->w_enable == false)
795 continue;
796 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
797 continue;
798 assoc = COP_CFG_DEFAULT_ASSOCIATION(w->w_pin.config);
799 seq = COP_CFG_SEQUENCE(w->w_pin.config);
800 if (assoc != j)
801 continue;
802 KASSERT(cnt < maxassocs);
803 type = COP_CFG_DEFAULT_DEVICE(w->w_pin.config);
804 /* Get pin direction */
805 switch (type) {
806 case COP_DEVICE_LINE_OUT:
807 case COP_DEVICE_SPEAKER:
808 case COP_DEVICE_HP_OUT:
809 case COP_DEVICE_SPDIF_OUT:
810 case COP_DEVICE_DIGITAL_OTHER_OUT:
811 dir = HDAUDIO_PINDIR_OUT;
812 break;
813 default:
814 dir = HDAUDIO_PINDIR_IN;
815 break;
817 /* If this is a first pin, create new association */
818 if (as[cnt].as_pincnt == 0) {
819 as[cnt].as_enable = true;
820 as[cnt].as_activated = true;
821 as[cnt].as_index = j;
822 as[cnt].as_dir = dir;
824 if (seq < first)
825 first = seq;
826 /* Check association correctness */
827 if (as[cnt].as_pins[seq] != 0) {
828 hda_error(sc, "duplicate pin in association\n");
829 as[cnt].as_enable = false;
831 if (dir != as[cnt].as_dir) {
832 hda_error(sc,
833 "pin %02X has wrong direction for %02X\n",
834 w->w_nid, j);
835 as[cnt].as_enable = false;
837 if ((w->w_p.aw_cap & COP_AWCAP_DIGITAL) == 0)
838 as[cnt].as_digital = false;
839 /* Headphones with seq=15 may mean redirection */
840 if (type == COP_DEVICE_HP_OUT && seq == 15)
841 hpredir = 1;
842 as[cnt].as_pins[seq] = w->w_nid;
843 as[cnt].as_pincnt++;
844 if (j == 15)
845 cnt++;
847 if (j != 15 && cnt < maxassocs && as[cnt].as_pincnt > 0) {
848 if (hpredir && as[cnt].as_pincnt > 1)
849 as[cnt].as_hpredir = first;
850 cnt++;
854 hda_debug(sc, " all done\n");
855 sc->sc_assocs = as;
858 static void
859 hdaudio_afg_control_parse(struct hdaudio_afg_softc *sc)
861 struct hdaudio_control *ctl;
862 struct hdaudio_widget *w, *cw;
863 int i, j, cnt, maxctls, ocap, icap;
864 int mute, offset, step, size;
866 maxctls = 0;
867 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
868 w = hdaudio_afg_widget_lookup(sc, i);
869 if (w == NULL || w->w_enable == false)
870 continue;
871 if (w->w_p.outamp_cap)
872 maxctls++;
873 if (w->w_p.inamp_cap) {
874 switch (w->w_type) {
875 case COP_AWCAP_TYPE_AUDIO_SELECTOR:
876 case COP_AWCAP_TYPE_AUDIO_MIXER:
877 for (j = 0; j < w->w_nconns; j++) {
878 cw = hdaudio_afg_widget_lookup(sc,
879 w->w_conns[j]);
880 if (cw == NULL || cw->w_enable == false)
881 continue;
882 maxctls++;
884 break;
885 default:
886 maxctls++;
887 break;
892 sc->sc_nctls = maxctls;
893 if (maxctls < 1)
894 return;
896 ctl = kmem_zalloc(sc->sc_nctls * sizeof(*ctl), KM_SLEEP);
898 cnt = 0;
899 for (i = sc->sc_startnode; cnt < maxctls && i < sc->sc_endnode; i++) {
900 if (cnt >= maxctls) {
901 hda_error(sc, "ctl overflow\n");
902 break;
904 w = hdaudio_afg_widget_lookup(sc, i);
905 if (w == NULL || w->w_enable == false)
906 continue;
907 ocap = w->w_p.outamp_cap;
908 icap = w->w_p.inamp_cap;
909 if (ocap) {
910 hda_trace(sc, "add ctrl outamp %d:%02X:FF\n",
911 cnt, w->w_nid);
912 mute = COP_AMPCAP_MUTE_CAPABLE(ocap);
913 step = COP_AMPCAP_NUM_STEPS(ocap);
914 size = COP_AMPCAP_STEP_SIZE(ocap);
915 offset = COP_AMPCAP_OFFSET(ocap);
916 ctl[cnt].ctl_enable = true;
917 ctl[cnt].ctl_widget = w;
918 ctl[cnt].ctl_mute = mute;
919 ctl[cnt].ctl_step = step;
920 ctl[cnt].ctl_size = size;
921 ctl[cnt].ctl_offset = offset;
922 ctl[cnt].ctl_left = offset;
923 ctl[cnt].ctl_right = offset;
924 if (w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX ||
925 w->w_waspin == true)
926 ctl[cnt].ctl_ndir = HDAUDIO_PINDIR_IN;
927 else
928 ctl[cnt].ctl_ndir = HDAUDIO_PINDIR_OUT;
929 ctl[cnt++].ctl_dir = HDAUDIO_PINDIR_OUT;
931 if (icap) {
932 mute = COP_AMPCAP_MUTE_CAPABLE(icap);
933 step = COP_AMPCAP_NUM_STEPS(icap);
934 size = COP_AMPCAP_STEP_SIZE(icap);
935 offset = COP_AMPCAP_OFFSET(icap);
936 switch (w->w_type) {
937 case COP_AWCAP_TYPE_AUDIO_SELECTOR:
938 case COP_AWCAP_TYPE_AUDIO_MIXER:
939 for (j = 0; j < w->w_nconns; j++) {
940 if (cnt >= maxctls)
941 break;
942 cw = hdaudio_afg_widget_lookup(sc,
943 w->w_conns[j]);
944 if (cw == NULL || cw->w_enable == false)
945 continue;
946 hda_trace(sc, "add ctrl inamp selmix "
947 "%d:%02X:%02X\n", cnt, w->w_nid,
948 cw->w_nid);
949 ctl[cnt].ctl_enable = true;
950 ctl[cnt].ctl_widget = w;
951 ctl[cnt].ctl_childwidget = cw;
952 ctl[cnt].ctl_index = j;
953 ctl[cnt].ctl_mute = mute;
954 ctl[cnt].ctl_step = step;
955 ctl[cnt].ctl_size = size;
956 ctl[cnt].ctl_offset = offset;
957 ctl[cnt].ctl_left = offset;
958 ctl[cnt].ctl_right = offset;
959 ctl[cnt].ctl_ndir = HDAUDIO_PINDIR_IN;
960 ctl[cnt++].ctl_dir = HDAUDIO_PINDIR_IN;
962 break;
963 default:
964 if (cnt >= maxctls)
965 break;
966 hda_trace(sc, "add ctrl inamp "
967 "%d:%02X:FF\n", cnt, w->w_nid);
968 ctl[cnt].ctl_enable = true;
969 ctl[cnt].ctl_widget = w;
970 ctl[cnt].ctl_mute = mute;
971 ctl[cnt].ctl_step = step;
972 ctl[cnt].ctl_size = size;
973 ctl[cnt].ctl_offset = offset;
974 ctl[cnt].ctl_left = offset;
975 ctl[cnt].ctl_right = offset;
976 if (w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX)
977 ctl[cnt].ctl_ndir = HDAUDIO_PINDIR_OUT;
978 else
979 ctl[cnt].ctl_ndir = HDAUDIO_PINDIR_IN;
980 ctl[cnt++].ctl_dir = HDAUDIO_PINDIR_IN;
981 break;
986 sc->sc_ctls = ctl;
989 static void
990 hdaudio_afg_parse(struct hdaudio_afg_softc *sc)
992 struct hdaudio_widget *w;
993 uint32_t nodecnt;
994 int nid;
996 nodecnt = hda_get_param(sc, SUBORDINATE_NODE_COUNT);
997 sc->sc_startnode = COP_NODECNT_STARTNODE(nodecnt);
998 sc->sc_nwidgets = COP_NODECNT_NUMNODES(nodecnt);
999 sc->sc_endnode = sc->sc_startnode + sc->sc_nwidgets;
1000 hda_debug(sc, "afg start %02X end %02X nwidgets %d\n",
1001 sc->sc_startnode, sc->sc_endnode, sc->sc_nwidgets);
1003 hda_debug(sc, "powering up widgets\n");
1004 hdaudio_command(sc->sc_codec, sc->sc_nid,
1005 CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
1006 hda_delay(100);
1007 for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++)
1008 hdaudio_command(sc->sc_codec, nid,
1009 CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
1010 hda_delay(1000);
1012 sc->sc_p.afg_cap = hda_get_param(sc, AUDIO_FUNCTION_GROUP_CAPABILITIES);
1013 sc->sc_p.stream_format = hda_get_param(sc, SUPPORTED_STREAM_FORMATS);
1014 sc->sc_p.pcm_size_rate = hda_get_param(sc, SUPPORTED_PCM_SIZE_RATES);
1015 sc->sc_p.outamp_cap = hda_get_param(sc, AMPLIFIER_CAPABILITIES_OUTAMP);
1016 sc->sc_p.inamp_cap = hda_get_param(sc, AMPLIFIER_CAPABILITIES_INAMP);
1017 sc->sc_p.power_states = hda_get_param(sc, SUPPORTED_POWER_STATES);
1018 sc->sc_p.gpio_cnt = hda_get_param(sc, GPIO_COUNT);
1020 sc->sc_widgets = kmem_zalloc(sc->sc_nwidgets * sizeof(*w), KM_SLEEP);
1021 hda_debug(sc, "afg widgets %p-%p\n",
1022 sc->sc_widgets, sc->sc_widgets + sc->sc_nwidgets);
1024 for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++) {
1025 w = hdaudio_afg_widget_lookup(sc, nid);
1026 if (w == NULL)
1027 continue;
1028 w->w_afg = sc;
1029 w->w_nid = nid;
1030 w->w_enable = true;
1031 w->w_pflags = 0;
1032 w->w_audiodev = -1;
1033 w->w_selconn = -1;
1034 w->w_bindas = -1;
1035 w->w_p.eapdbtl = 0xffffffff;
1036 hdaudio_afg_widget_parse(w);
1040 static void
1041 hdaudio_afg_disable_nonaudio(struct hdaudio_afg_softc *sc)
1043 struct hdaudio_widget *w;
1044 int i;
1046 /* Disable power and volume widgets */
1047 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1048 w = hdaudio_afg_widget_lookup(sc, i);
1049 if (w == NULL || w->w_enable == false)
1050 continue;
1051 if (w->w_type == COP_AWCAP_TYPE_POWER_WIDGET ||
1052 w->w_type == COP_AWCAP_TYPE_VOLUME_KNOB) {
1053 hda_trace(w->w_afg, "disable %02X [nonaudio]\n",
1054 w->w_nid);
1055 w->w_enable = false;
1060 static void
1061 hdaudio_afg_disable_useless(struct hdaudio_afg_softc *sc)
1063 struct hdaudio_widget *w, *cw;
1064 struct hdaudio_control *ctl;
1065 int done, found, i, j, k;
1066 int conn, assoc;
1068 /* Disable useless pins */
1069 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1070 w = hdaudio_afg_widget_lookup(sc, i);
1071 if (w == NULL || w->w_enable == false)
1072 continue;
1073 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
1074 continue;
1075 conn = COP_CFG_PORT_CONNECTIVITY(w->w_pin.config);
1076 assoc = COP_CFG_DEFAULT_ASSOCIATION(w->w_pin.config);
1077 if (conn == COP_PORT_NONE) {
1078 hda_trace(w->w_afg, "disable %02X [no connectivity]\n",
1079 w->w_nid);
1080 w->w_enable = false;
1082 if (assoc == 0) {
1083 hda_trace(w->w_afg, "disable %02X [no association]\n",
1084 w->w_nid);
1085 w->w_enable = false;
1089 do {
1090 done = 1;
1091 /* Disable and mute controls for disabled widgets */
1092 i = 0;
1093 for (i = 0; i < sc->sc_nctls; i++) {
1094 ctl = &sc->sc_ctls[i];
1095 if (ctl->ctl_enable == false)
1096 continue;
1097 if (ctl->ctl_widget->w_enable == false ||
1098 (ctl->ctl_childwidget != NULL &&
1099 ctl->ctl_childwidget->w_enable == false)) {
1100 ctl->ctl_forcemute = 1;
1101 ctl->ctl_muted = HDAUDIO_AMP_MUTE_ALL;
1102 ctl->ctl_left = ctl->ctl_right = 0;
1103 ctl->ctl_enable = false;
1104 if (ctl->ctl_ndir == HDAUDIO_PINDIR_IN)
1105 ctl->ctl_widget->w_connsenable[
1106 ctl->ctl_index] = false;
1107 done = 0;
1108 hda_trace(ctl->ctl_widget->w_afg,
1109 "disable ctl %d:%02X:%02X [widget disabled]\n",
1110 i, ctl->ctl_widget->w_nid,
1111 ctl->ctl_childwidget ?
1112 ctl->ctl_childwidget->w_nid : 0xff);
1115 /* Disable useless widgets */
1116 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1117 w = hdaudio_afg_widget_lookup(sc, i);
1118 if (w == NULL || w->w_enable == false)
1119 continue;
1120 /* Disable inputs with disabled child widgets */
1121 for (j = 0; j < w->w_nconns; j++) {
1122 if (!w->w_connsenable[j])
1123 continue;
1124 cw = hdaudio_afg_widget_lookup(sc,
1125 w->w_conns[j]);
1126 if (cw == NULL || cw->w_enable == false) {
1127 w->w_connsenable[j] = false;
1128 hda_trace(w->w_afg,
1129 "disable conn %02X->%02X "
1130 "[disabled child]\n",
1131 w->w_nid, w->w_conns[j]);
1134 if (w->w_type != COP_AWCAP_TYPE_AUDIO_SELECTOR &&
1135 w->w_type != COP_AWCAP_TYPE_AUDIO_MIXER)
1136 continue;
1137 /* Disable mixers and selectors without inputs */
1138 found = 0;
1139 for (j = 0; j < w->w_nconns; j++)
1140 if (w->w_connsenable[j]) {
1141 found = 1;
1142 break;
1144 if (found == 0) {
1145 w->w_enable = false;
1146 done = 0;
1147 hda_trace(w->w_afg,
1148 "disable %02X [inputs disabled]\n",
1149 w->w_nid);
1151 /* Disable nodes without consumers */
1152 if (w->w_type != COP_AWCAP_TYPE_AUDIO_SELECTOR &&
1153 w->w_type != COP_AWCAP_TYPE_AUDIO_MIXER)
1154 continue;
1155 found = 0;
1156 for (k = sc->sc_startnode; k < sc->sc_endnode; k++) {
1157 cw = hdaudio_afg_widget_lookup(sc, k);
1158 if (cw == NULL || cw->w_enable == false)
1159 continue;
1160 for (j = 0; j < cw->w_nconns; j++) {
1161 if (cw->w_connsenable[j] &&
1162 cw->w_conns[j] == i) {
1163 found = 1;
1164 break;
1168 if (found == 0) {
1169 w->w_enable = false;
1170 done = 0;
1171 hda_trace(w->w_afg,
1172 "disable %02X [consumers disabled]\n",
1173 w->w_nid);
1176 } while (done == 0);
1179 static void
1180 hdaudio_afg_assoc_trace_undo(struct hdaudio_afg_softc *sc, int as, int seq)
1182 struct hdaudio_widget *w;
1183 int i;
1185 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1186 w = hdaudio_afg_widget_lookup(sc, i);
1187 if (w == NULL || w->w_enable == false)
1188 continue;
1189 if (w->w_bindas != as)
1190 continue;
1191 if (seq >= 0) {
1192 w->w_bindseqmask &= ~(1 << seq);
1193 if (w->w_bindseqmask == 0) {
1194 w->w_bindas = -1;
1195 w->w_selconn = -1;
1197 } else {
1198 w->w_bindas = -1;
1199 w->w_bindseqmask = 0;
1200 w->w_selconn = -1;
1205 static int
1206 hdaudio_afg_assoc_trace_dac(struct hdaudio_afg_softc *sc, int as, int seq,
1207 int nid, int dupseq, int minassoc, int only, int depth)
1209 struct hdaudio_widget *w;
1210 int i, im = -1;
1211 int m = 0, ret;
1213 if (depth >= HDAUDIO_PARSE_MAXDEPTH)
1214 return 0;
1215 w = hdaudio_afg_widget_lookup(sc, nid);
1216 if (w == NULL || w->w_enable == false)
1217 return 0;
1218 /* We use only unused widgets */
1219 if (w->w_bindas >= 0 && w->w_bindas != as) {
1220 if (!only)
1221 hda_trace(sc, "depth %d nid %02X busy by assoc %d\n",
1222 depth + 1, nid, w->w_bindas);
1223 return 0;
1225 if (dupseq < 0) {
1226 if (w->w_bindseqmask != 0) {
1227 if (!only)
1228 hda_trace(sc,
1229 "depth %d nid %02X busy by seqmask %x\n",
1230 depth + 1, nid, w->w_bindas);
1231 return 0;
1233 } else {
1234 /* If this is headphones, allow duplicate first pin */
1235 if (w->w_bindseqmask != 0 &&
1236 (w->w_bindseqmask & (1 << dupseq)) == 0)
1237 return 0;
1240 switch (w->w_type) {
1241 case COP_AWCAP_TYPE_AUDIO_INPUT:
1242 break;
1243 case COP_AWCAP_TYPE_AUDIO_OUTPUT:
1244 /* If we are tracing HP take only dac of first pin */
1245 if ((only == 0 || only == w->w_nid) &&
1246 (w->w_nid >= minassoc) && (dupseq < 0 || w->w_nid ==
1247 sc->sc_assocs[as].as_dacs[dupseq]))
1248 m = w->w_nid;
1249 break;
1250 case COP_AWCAP_TYPE_PIN_COMPLEX:
1251 if (depth > 0)
1252 break;
1253 /* FALLTHROUGH */
1254 default:
1255 for (i = 0; i < w->w_nconns; i++) {
1256 if (w->w_connsenable[i] == false)
1257 continue;
1258 if (w->w_selconn != -1 && w->w_selconn != i)
1259 continue;
1260 ret = hdaudio_afg_assoc_trace_dac(sc, as, seq,
1261 w->w_conns[i], dupseq, minassoc, only, depth + 1);
1262 if (ret) {
1263 if (m == 0 || ret < m) {
1264 m = ret;
1265 im = i;
1267 if (only || dupseq >= 0)
1268 break;
1271 if (m && only && ((w->w_nconns > 1 &&
1272 w->w_type != COP_AWCAP_TYPE_AUDIO_MIXER) ||
1273 w->w_type == COP_AWCAP_TYPE_AUDIO_SELECTOR))
1274 w->w_selconn = im;
1275 break;
1277 if (m && only) {
1278 w->w_bindas = as;
1279 w->w_bindseqmask |= (1 << seq);
1281 if (!only)
1282 hda_trace(sc, "depth %d nid %02X dupseq %d returned %02X\n",
1283 depth + 1, nid, dupseq, m);
1285 return m;
1288 static int
1289 hdaudio_afg_assoc_trace_out(struct hdaudio_afg_softc *sc, int as, int seq)
1291 struct hdaudio_assoc *assocs = sc->sc_assocs;
1292 int i, hpredir;
1293 int minassoc, res;
1295 /* Find next pin */
1296 for (i = seq; i < HDAUDIO_MAXPINS && assocs[as].as_pins[i] == 0; i++)
1298 /* Check if there is any left, if not then we have succeeded */
1299 if (i == HDAUDIO_MAXPINS)
1300 return 1;
1302 hpredir = (i == 15 && assocs[as].as_fakeredir == 0) ?
1303 assocs[as].as_hpredir : -1;
1304 minassoc = res = 0;
1305 do {
1306 /* Trace this pin taking min nid into account */
1307 res = hdaudio_afg_assoc_trace_dac(sc, as, i,
1308 assocs[as].as_pins[i], hpredir, minassoc, 0, 0);
1309 if (res == 0) {
1310 /* If we failed, return to previous and redo it */
1311 hda_trace(sc, " trace failed as=%d seq=%d pin=%02X "
1312 "hpredir=%d minassoc=%d\n",
1313 as, seq, assocs[as].as_pins[i], hpredir, minassoc);
1314 return 0;
1316 /* Trace again to mark the path */
1317 hdaudio_afg_assoc_trace_dac(sc, as, i,
1318 assocs[as].as_pins[i], hpredir, minassoc, res, 0);
1319 assocs[as].as_dacs[i] = res;
1320 /* We succeeded, so call next */
1321 if (hdaudio_afg_assoc_trace_out(sc, as, i + 1))
1322 return 1;
1323 /* If next failed, we should retry with next min */
1324 hdaudio_afg_assoc_trace_undo(sc, as, i);
1325 assocs[as].as_dacs[i] = 0;
1326 minassoc = res + 1;
1327 } while (1);
1330 static int
1331 hdaudio_afg_assoc_trace_adc(struct hdaudio_afg_softc *sc, int assoc, int seq,
1332 int nid, int only, int depth)
1334 struct hdaudio_widget *w, *wc;
1335 int i, j;
1336 int res = 0;
1338 if (depth > HDAUDIO_PARSE_MAXDEPTH)
1339 return 0;
1340 w = hdaudio_afg_widget_lookup(sc, nid);
1341 if (w == NULL || w->w_enable == false)
1342 return 0;
1343 /* Use only unused widgets */
1344 if (w->w_bindas >= 0 && w->w_bindas != assoc)
1345 return 0;
1347 switch (w->w_type) {
1348 case COP_AWCAP_TYPE_AUDIO_INPUT:
1349 if (only == w->w_nid)
1350 res = 1;
1351 break;
1352 case COP_AWCAP_TYPE_PIN_COMPLEX:
1353 if (depth > 0)
1354 break;
1355 /* FALLTHROUGH */
1356 default:
1357 /* Try to find reachable ADCs with specified nid */
1358 for (j = sc->sc_startnode; j < sc->sc_endnode; j++) {
1359 wc = hdaudio_afg_widget_lookup(sc, j);
1360 if (w == NULL || w->w_enable == false)
1361 continue;
1362 for (i = 0; i < wc->w_nconns; i++) {
1363 if (wc->w_connsenable[i] == false)
1364 continue;
1365 if (wc->w_conns[i] != nid)
1366 continue;
1367 if (hdaudio_afg_assoc_trace_adc(sc, assoc, seq,
1368 j, only, depth + 1) != 0) {
1369 res = 1;
1370 if (((wc->w_nconns > 1 &&
1371 wc->w_type != COP_AWCAP_TYPE_AUDIO_MIXER) ||
1372 wc->w_type != COP_AWCAP_TYPE_AUDIO_SELECTOR)
1373 && wc->w_selconn == -1)
1374 wc->w_selconn = i;
1378 break;
1380 if (res) {
1381 w->w_bindas = assoc;
1382 w->w_bindseqmask |= (1 << seq);
1384 return res;
1387 static int
1388 hdaudio_afg_assoc_trace_in(struct hdaudio_afg_softc *sc, int assoc)
1390 struct hdaudio_assoc *as = sc->sc_assocs;
1391 struct hdaudio_widget *w;
1392 int i, j, k;
1394 for (j = sc->sc_startnode; j < sc->sc_endnode; j++) {
1395 w = hdaudio_afg_widget_lookup(sc, j);
1396 if (w == NULL || w->w_enable == false)
1397 continue;
1398 if (w->w_type != COP_AWCAP_TYPE_AUDIO_INPUT)
1399 continue;
1400 if (w->w_bindas >= 0 && w->w_bindas != assoc)
1401 continue;
1403 /* Find next pin */
1404 for (i = 0; i < HDAUDIO_MAXPINS; i++) {
1405 if (as[assoc].as_pins[i] == 0)
1406 continue;
1407 /* Trace this pin taking goal into account */
1408 if (hdaudio_afg_assoc_trace_adc(sc, assoc, i,
1409 as[assoc].as_pins[i], j, 0) == 0) {
1410 hdaudio_afg_assoc_trace_undo(sc, assoc, -1);
1411 for (k = 0; k < HDAUDIO_MAXPINS; k++)
1412 as[assoc].as_dacs[k] = 0;
1413 break;
1415 as[assoc].as_dacs[i] = j;
1417 if (i == HDAUDIO_MAXPINS)
1418 return 1;
1420 return 0;
1423 static int
1424 hdaudio_afg_assoc_trace_to_out(struct hdaudio_afg_softc *sc, int nid, int depth)
1426 struct hdaudio_assoc *as = sc->sc_assocs;
1427 struct hdaudio_widget *w, *wc;
1428 int i, j;
1429 int res = 0;
1431 if (depth > HDAUDIO_PARSE_MAXDEPTH)
1432 return 0;
1433 w = hdaudio_afg_widget_lookup(sc, nid);
1434 if (w == NULL || w->w_enable == false)
1435 return 0;
1437 /* Use only unused widgets */
1438 if (depth > 0 && w->w_bindas != -1) {
1439 if (w->w_bindas < 0 ||
1440 as[w->w_bindas].as_dir == HDAUDIO_PINDIR_OUT) {
1441 return 1;
1442 } else {
1443 return 0;
1447 switch (w->w_type) {
1448 case COP_AWCAP_TYPE_AUDIO_INPUT:
1449 /* Do not traverse input (not yet supported) */
1450 break;
1451 case COP_AWCAP_TYPE_PIN_COMPLEX:
1452 if (depth > 0)
1453 break;
1454 /* FALLTHROUGH */
1455 default:
1456 /* Try to find reachable ADCs with specified nid */
1457 for (j = sc->sc_startnode; j < sc->sc_endnode; j++) {
1458 wc = hdaudio_afg_widget_lookup(sc, j);
1459 if (wc == NULL || wc->w_enable == false)
1460 continue;
1461 for (i = 0; i < wc->w_nconns; i++) {
1462 if (wc->w_connsenable[i] == false)
1463 continue;
1464 if (wc->w_conns[i] != nid)
1465 continue;
1466 if (hdaudio_afg_assoc_trace_to_out(sc,
1467 j, depth + 1) != 0) {
1468 res = 1;
1469 if (wc->w_type ==
1470 COP_AWCAP_TYPE_AUDIO_SELECTOR &&
1471 wc->w_selconn == -1)
1472 wc->w_selconn = i;
1476 break;
1478 if (res)
1479 w->w_bindas = -2;
1480 return res;
1483 static void
1484 hdaudio_afg_assoc_trace_misc(struct hdaudio_afg_softc *sc)
1486 struct hdaudio_assoc *as = sc->sc_assocs;
1487 struct hdaudio_widget *w;
1488 int j;
1490 /* Input monitor */
1492 * Find mixer associated with input, but supplying signal
1493 * for output associations. Hope it will be input monitor.
1495 for (j = sc->sc_startnode; j < sc->sc_endnode; j++) {
1496 w = hdaudio_afg_widget_lookup(sc, j);
1497 if (w == NULL || w->w_enable == false)
1498 continue;
1499 if (w->w_type != COP_AWCAP_TYPE_AUDIO_MIXER)
1500 continue;
1501 if (w->w_bindas < 0 ||
1502 as[w->w_bindas].as_dir != HDAUDIO_PINDIR_IN)
1503 continue;
1504 if (hdaudio_afg_assoc_trace_to_out(sc, w->w_nid, 0)) {
1505 w->w_pflags |= HDAUDIO_ADC_MONITOR;
1506 w->w_audiodev = HDAUDIO_MIXER_IMIX;
1510 /* Beeper */
1511 for (j = sc->sc_startnode; j < sc->sc_endnode; j++) {
1512 w = hdaudio_afg_widget_lookup(sc, j);
1513 if (w == NULL || w->w_enable == false)
1514 continue;
1515 if (w->w_type != COP_AWCAP_TYPE_BEEP_GENERATOR)
1516 continue;
1517 if (hdaudio_afg_assoc_trace_to_out(sc, w->w_nid, 0)) {
1518 hda_debug(sc, "beeper %02X traced to out\n", w->w_nid);
1520 w->w_bindas = -2;
1524 static void
1525 hdaudio_afg_build_tree(struct hdaudio_afg_softc *sc)
1527 struct hdaudio_assoc *as = sc->sc_assocs;
1528 int i, j, res;
1530 /* Trace all associations in order of their numbers */
1532 /* Trace DACs first */
1533 for (j = 0; j < sc->sc_nassocs; j++) {
1534 if (as[j].as_enable == false)
1535 continue;
1536 if (as[j].as_dir != HDAUDIO_PINDIR_OUT)
1537 continue;
1538 retry:
1539 res = hdaudio_afg_assoc_trace_out(sc, j, 0);
1540 if (res == 0 && as[j].as_hpredir >= 0 &&
1541 as[j].as_fakeredir == 0) {
1543 * If codec can't do analog HP redirection
1544 * try to make it using one more DAC
1546 as[j].as_fakeredir = 1;
1547 goto retry;
1549 if (!res) {
1550 hda_debug(sc, "disable assoc %d (%d) [trace failed]\n",
1551 j, as[j].as_index);
1552 for (i = 0; i < HDAUDIO_MAXPINS; i++) {
1553 if (as[j].as_pins[i] == 0)
1554 continue;
1555 hda_debug(sc, " assoc %d pin%d: %02X\n", j, i,
1556 as[j].as_pins[i]);
1558 for (i = 0; i < HDAUDIO_MAXPINS; i++) {
1559 if (as[j].as_dacs[i] == 0)
1560 continue;
1561 hda_debug(sc, " assoc %d dac%d: %02X\n", j, i,
1562 as[j].as_dacs[i]);
1565 as[j].as_enable = false;
1569 /* Trace ADCs */
1570 for (j = 0; j < sc->sc_nassocs; j++) {
1571 if (as[j].as_enable == false)
1572 continue;
1573 if (as[j].as_dir != HDAUDIO_PINDIR_IN)
1574 continue;
1575 res = hdaudio_afg_assoc_trace_in(sc, j);
1576 if (!res) {
1577 hda_error(sc, "disable assoc %d (%d) [trace failed]\n",
1578 j, as[j].as_index);
1579 for (i = 0; i < HDAUDIO_MAXPINS; i++) {
1580 if (as[j].as_pins[i] == 0)
1581 continue;
1582 hda_error(sc, " assoc %d pin%d: %02X\n", j, i,
1583 as[j].as_pins[i]);
1585 for (i = 0; i < HDAUDIO_MAXPINS; i++) {
1586 if (as[j].as_dacs[i] == 0)
1587 continue;
1588 hda_error(sc, " assoc %d adc%d: %02X\n", j, i,
1589 as[j].as_dacs[i]);
1592 as[j].as_enable = false;
1596 /* Trace mixer and beeper pseudo associations */
1597 hdaudio_afg_assoc_trace_misc(sc);
1600 static void
1601 hdaudio_afg_prepare_pin_controls(struct hdaudio_afg_softc *sc)
1603 struct hdaudio_assoc *as = sc->sc_assocs;
1604 struct hdaudio_widget *w;
1605 uint32_t pincap;
1606 int i;
1608 for (i = 0; i < sc->sc_nwidgets; i++) {
1609 w = &sc->sc_widgets[i];
1610 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
1611 continue;
1612 pincap = w->w_pin.cap;
1614 /* Disable everything */
1615 w->w_pin.ctrl &= ~(
1616 COP_PWC_VREF_ENABLE_MASK |
1617 COP_PWC_IN_ENABLE |
1618 COP_PWC_OUT_ENABLE |
1619 COP_PWC_HPHN_ENABLE);
1621 if (w->w_enable == false ||
1622 w->w_bindas < 0 || as[w->w_bindas].as_enable == false) {
1623 /* Pin is unused so leave it disabled */
1624 if ((pincap & (COP_PINCAP_OUTPUT_CAPABLE |
1625 COP_PINCAP_INPUT_CAPABLE)) ==
1626 (COP_PINCAP_OUTPUT_CAPABLE |
1627 COP_PINCAP_INPUT_CAPABLE)) {
1628 hda_trace(sc, "pin %02X off, "
1629 "in/out capable (bindas=%d "
1630 "enable=%d as_enable=%d)\n",
1631 w->w_nid, w->w_bindas, w->w_enable,
1632 w->w_bindas >= 0 ?
1633 as[w->w_bindas].as_enable : -1);
1634 w->w_pin.ctrl |= COP_PWC_OUT_ENABLE;
1636 continue;
1637 } else if (as[w->w_bindas].as_dir == HDAUDIO_PINDIR_IN) {
1638 /* Input pin, configure for input */
1639 if (pincap & COP_PINCAP_INPUT_CAPABLE)
1640 w->w_pin.ctrl |= COP_PWC_IN_ENABLE;
1642 if (COP_CFG_DEFAULT_DEVICE(w->w_pin.config) !=
1643 COP_DEVICE_MIC_IN)
1644 continue;
1645 if (COP_PINCAP_VREF_CONTROL(pincap) & COP_VREF_80)
1646 w->w_pin.ctrl |= COP_PWC_VREF_80;
1647 else if (COP_PINCAP_VREF_CONTROL(pincap) & COP_VREF_50)
1648 w->w_pin.ctrl |= COP_PWC_VREF_50;
1649 } else {
1650 /* Output pin, configure for output */
1651 if (pincap & COP_PINCAP_OUTPUT_CAPABLE)
1652 w->w_pin.ctrl |= COP_PWC_OUT_ENABLE;
1653 if ((pincap & COP_PINCAP_HEADPHONE_DRIVE_CAPABLE) &&
1654 (COP_CFG_DEFAULT_DEVICE(w->w_pin.config) ==
1655 COP_DEVICE_HP_OUT))
1656 w->w_pin.ctrl |= COP_PWC_HPHN_ENABLE;
1657 /* XXX VREF */
1662 static void
1663 hdaudio_afg_dump(struct hdaudio_afg_softc *sc)
1665 #if defined(HDAUDIO_AFG_DEBUG) && HDAUDIO_AFG_DEBUG > 1
1666 struct hdaudio_control *ctl;
1667 int i, type;
1669 for (i = 0; i < sc->sc_nctls; i++) {
1670 ctl = &sc->sc_ctls[i];
1671 type = (ctl->ctl_widget ? ctl->ctl_widget->w_type : -1);
1672 hda_print(sc, "%03X: nid %02X type %d %s (%s) index %d",
1673 i, (ctl->ctl_widget ? ctl->ctl_widget->w_nid : -1), type,
1674 (ctl->ctl_ndir == HDAUDIO_PINDIR_IN) ? "in " : "out",
1675 (ctl->ctl_dir == HDAUDIO_PINDIR_IN) ? "in " : "out",
1676 ctl->ctl_index);
1677 if (ctl->ctl_childwidget)
1678 hda_print1(sc, " cnid %02X",
1679 ctl->ctl_childwidget->w_nid);
1680 else
1681 hda_print1(sc, " ");
1682 hda_print1(sc, "\n");
1683 hda_print(sc, " mute: %d step: %3d size: %3d off: %3d%s\n",
1684 ctl->ctl_mute, ctl->ctl_step, ctl->ctl_size,
1685 ctl->ctl_offset,
1686 (ctl->ctl_enable == false) ? " [DISABLED]" : "");
1688 #endif
1691 static int
1692 hdaudio_afg_match(device_t parent, cfdata_t match, void *opaque)
1694 prop_dictionary_t args = opaque;
1695 uint8_t fgtype;
1696 bool rv;
1698 rv = prop_dictionary_get_uint8(args, "function-group-type", &fgtype);
1699 if (rv == false || fgtype != HDAUDIO_GROUP_TYPE_AFG)
1700 return 0;
1702 return 1;
1705 static void
1706 hdaudio_afg_disable_unassoc(struct hdaudio_afg_softc *sc)
1708 struct hdaudio_assoc *as = sc->sc_assocs;
1709 struct hdaudio_widget *w, *cw;
1710 struct hdaudio_control *ctl;
1711 int i, j, k;
1713 /* Disable unassociated widgets */
1714 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1715 w = hdaudio_afg_widget_lookup(sc, i);
1716 if (w == NULL || w->w_enable == false)
1717 continue;
1718 if (w->w_bindas == -1) {
1719 w->w_enable = 0;
1720 hda_trace(sc, "disable %02X [unassociated]\n",
1721 w->w_nid);
1725 /* Disable input connections on input pin and output on output */
1726 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1727 w = hdaudio_afg_widget_lookup(sc, i);
1728 if (w == NULL || w->w_enable == false)
1729 continue;
1730 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
1731 continue;
1732 if (w->w_bindas < 0)
1733 continue;
1734 if (as[w->w_bindas].as_dir == HDAUDIO_PINDIR_IN) {
1735 hda_trace(sc, "disable %02X input connections\n",
1736 w->w_nid);
1737 for (j = 0; j < w->w_nconns; j++)
1738 w->w_connsenable[j] = false;
1739 ctl = hdaudio_afg_control_lookup(sc, w->w_nid,
1740 HDAUDIO_PINDIR_IN, -1, 1);
1741 if (ctl && ctl->ctl_enable == true) {
1742 ctl->ctl_forcemute = 1;
1743 ctl->ctl_muted = HDAUDIO_AMP_MUTE_ALL;
1744 ctl->ctl_left = ctl->ctl_right = 0;
1745 ctl->ctl_enable = false;
1747 } else {
1748 ctl = hdaudio_afg_control_lookup(sc, w->w_nid,
1749 HDAUDIO_PINDIR_OUT, -1, 1);
1750 if (ctl && ctl->ctl_enable == true) {
1751 ctl->ctl_forcemute = 1;
1752 ctl->ctl_muted = HDAUDIO_AMP_MUTE_ALL;
1753 ctl->ctl_left = ctl->ctl_right = 0;
1754 ctl->ctl_enable = false;
1756 for (k = sc->sc_startnode; k < sc->sc_endnode; k++) {
1757 cw = hdaudio_afg_widget_lookup(sc, k);
1758 if (cw == NULL || cw->w_enable == false)
1759 continue;
1760 for (j = 0; j < cw->w_nconns; j++) {
1761 if (!cw->w_connsenable[j])
1762 continue;
1763 if (cw->w_conns[j] != i)
1764 continue;
1765 hda_trace(sc, "disable %02X -> %02X "
1766 "output connection\n",
1767 cw->w_nid, cw->w_conns[j]);
1768 cw->w_connsenable[j] = false;
1769 if (cw->w_type ==
1770 COP_AWCAP_TYPE_PIN_COMPLEX &&
1771 cw->w_nconns > 1)
1772 continue;
1773 ctl = hdaudio_afg_control_lookup(sc,
1774 k, HDAUDIO_PINDIR_IN, j, 1);
1775 if (ctl && ctl->ctl_enable == true) {
1776 ctl->ctl_forcemute = 1;
1777 ctl->ctl_muted =
1778 HDAUDIO_AMP_MUTE_ALL;
1779 ctl->ctl_left =
1780 ctl->ctl_right = 0;
1781 ctl->ctl_enable = false;
1789 static void
1790 hdaudio_afg_disable_unsel(struct hdaudio_afg_softc *sc)
1792 struct hdaudio_assoc *as = sc->sc_assocs;
1793 struct hdaudio_widget *w;
1794 int i, j;
1796 /* On playback path we can safely disable all unselected inputs */
1797 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1798 w = hdaudio_afg_widget_lookup(sc, i);
1799 if (w == NULL || w->w_enable == false)
1800 continue;
1801 if (w->w_nconns <= 1)
1802 continue;
1803 if (w->w_type == COP_AWCAP_TYPE_AUDIO_MIXER)
1804 continue;
1805 if (w->w_bindas < 0 ||
1806 as[w->w_bindas].as_dir == HDAUDIO_PINDIR_IN)
1807 continue;
1808 for (j = 0; j < w->w_nconns; j++) {
1809 if (w->w_connsenable[j] == false)
1810 continue;
1811 if (w->w_selconn < 0 || w->w_selconn == j)
1812 continue;
1813 hda_trace(sc, "disable %02X->%02X [unselected]\n",
1814 w->w_nid, w->w_conns[j]);
1815 w->w_connsenable[j] = false;
1820 static void
1821 hdaudio_afg_disable_crossassoc(struct hdaudio_afg_softc *sc)
1823 struct hdaudio_widget *w, *cw;
1824 struct hdaudio_control *ctl;
1825 int i, j;
1827 /* Disable cross associated and unwanted cross channel connections */
1829 /* ... using selectors */
1830 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
1831 w = hdaudio_afg_widget_lookup(sc, i);
1832 if (w == NULL || w->w_enable == false)
1833 continue;
1834 if (w->w_nconns <= 1)
1835 continue;
1836 if (w->w_type == COP_AWCAP_TYPE_AUDIO_MIXER)
1837 continue;
1838 if (w->w_bindas == -2)
1839 continue;
1840 for (j = 0; j < w->w_nconns; j++) {
1841 if (w->w_connsenable[j] == false)
1842 continue;
1843 cw = hdaudio_afg_widget_lookup(sc, w->w_conns[j]);
1844 if (cw == NULL || cw->w_enable == false)
1845 continue;
1846 if (cw->w_bindas == -2)
1847 continue;
1848 if (w->w_bindas == cw->w_bindas &&
1849 (w->w_bindseqmask & cw->w_bindseqmask) != 0)
1850 continue;
1851 hda_trace(sc, "disable %02X->%02X [crossassoc]\n",
1852 w->w_nid, w->w_conns[j]);
1853 w->w_connsenable[j] = false;
1856 /* ... using controls */
1857 for (i = 0; i < sc->sc_nctls; i++) {
1858 ctl = &sc->sc_ctls[i];
1859 if (ctl->ctl_enable == false || ctl->ctl_childwidget == NULL)
1860 continue;
1861 if (ctl->ctl_widget->w_bindas == -2 ||
1862 ctl->ctl_childwidget->w_bindas == -2)
1863 continue;
1864 if (ctl->ctl_widget->w_bindas !=
1865 ctl->ctl_childwidget->w_bindas ||
1866 (ctl->ctl_widget->w_bindseqmask &
1867 ctl->ctl_childwidget->w_bindseqmask) == 0) {
1868 ctl->ctl_forcemute = 1;
1869 ctl->ctl_muted = HDAUDIO_AMP_MUTE_ALL;
1870 ctl->ctl_left = ctl->ctl_right = 0;
1871 ctl->ctl_enable = false;
1872 if (ctl->ctl_ndir == HDAUDIO_PINDIR_IN) {
1873 hda_trace(sc, "disable ctl %d:%02X:%02X "
1874 "[crossassoc]\n",
1875 i, ctl->ctl_widget->w_nid,
1876 ctl->ctl_widget->w_conns[ctl->ctl_index]);
1877 ctl->ctl_widget->w_connsenable[
1878 ctl->ctl_index] = false;
1884 static struct hdaudio_control *
1885 hdaudio_afg_control_amp_get(struct hdaudio_afg_softc *sc, int nid,
1886 enum hdaudio_pindir dir, int index, int cnt)
1888 struct hdaudio_control *ctl;
1889 int i, found = 0;
1891 for (i = 0; i < sc->sc_nctls; i++) {
1892 ctl = &sc->sc_ctls[i];
1893 if (ctl->ctl_enable == false)
1894 continue;
1895 if (ctl->ctl_widget->w_nid != nid)
1896 continue;
1897 if (dir && ctl->ctl_ndir != dir)
1898 continue;
1899 if (index >= 0 && ctl->ctl_ndir == HDAUDIO_PINDIR_IN &&
1900 ctl->ctl_dir == ctl->ctl_ndir &&
1901 ctl->ctl_index != index)
1902 continue;
1903 ++found;
1904 if (found == cnt || cnt <= 0)
1905 return ctl;
1908 return NULL;
1911 static void
1912 hdaudio_afg_control_amp_set1(struct hdaudio_control *ctl, int lmute, int rmute,
1913 int left, int right, int dir)
1915 struct hdaudio_afg_softc *sc = ctl->ctl_widget->w_afg;
1916 int index = ctl->ctl_index;
1917 uint16_t v = 0;
1919 if (left != right || lmute != rmute) {
1920 v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
1921 (lmute << 7) | left;
1922 hdaudio_command(sc->sc_codec, ctl->ctl_widget->w_nid,
1923 CORB_SET_AMPLIFIER_GAIN_MUTE, v);
1924 v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
1925 (rmute << 7) | right;
1926 } else
1927 v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
1928 (lmute << 7) | left;
1929 hdaudio_command(sc->sc_codec, ctl->ctl_widget->w_nid,
1930 CORB_SET_AMPLIFIER_GAIN_MUTE, v);
1933 static void
1934 hdaudio_afg_control_amp_set(struct hdaudio_control *ctl, uint32_t mute,
1935 int left, int right)
1937 int lmute, rmute;
1939 /* Save new values if valid */
1940 if (mute != HDAUDIO_AMP_MUTE_DEFAULT)
1941 ctl->ctl_muted = mute;
1942 if (left != HDAUDIO_AMP_VOL_DEFAULT)
1943 ctl->ctl_left = left;
1944 if (right != HDAUDIO_AMP_VOL_DEFAULT)
1945 ctl->ctl_right = right;
1947 /* Prepare effective values */
1948 if (ctl->ctl_forcemute) {
1949 lmute = rmute = 1;
1950 left = right = 0;
1951 } else {
1952 lmute = HDAUDIO_AMP_LEFT_MUTED(ctl->ctl_muted);
1953 rmute = HDAUDIO_AMP_RIGHT_MUTED(ctl->ctl_muted);
1954 left = ctl->ctl_left;
1955 right = ctl->ctl_right;
1958 /* Apply effective values */
1959 if (ctl->ctl_dir & HDAUDIO_PINDIR_OUT)
1960 hdaudio_afg_control_amp_set1(ctl, lmute, rmute, left, right, 0);
1961 if (ctl->ctl_dir & HDAUDIO_PINDIR_IN)
1962 hdaudio_afg_control_amp_set1(ctl, lmute, rmute, left, right, 1);
1965 static void
1966 hdaudio_afg_control_commit(struct hdaudio_afg_softc *sc)
1968 struct hdaudio_control *ctl;
1969 int i, z;
1971 for (i = 0; i < sc->sc_nctls; i++) {
1972 ctl = &sc->sc_ctls[i];
1973 //if (ctl->ctl_enable == false || ctl->ctl_audiomask != 0)
1974 if (ctl->ctl_enable == false)
1975 continue;
1976 /* Init fixed controls to 0dB amplification */
1977 z = ctl->ctl_offset;
1978 if (z > ctl->ctl_step)
1979 z = ctl->ctl_step;
1980 hdaudio_afg_control_amp_set(ctl, HDAUDIO_AMP_MUTE_NONE, z, z);
1984 static void
1985 hdaudio_afg_widget_connection_select(struct hdaudio_widget *w, uint8_t index)
1987 struct hdaudio_afg_softc *sc = w->w_afg;
1989 if (w->w_nconns < 1 || index > (w->w_nconns - 1))
1990 return;
1992 hdaudio_command(sc->sc_codec, w->w_nid,
1993 CORB_SET_CONNECTION_SELECT_CONTROL, index);
1994 w->w_selconn = index;
1997 static void
1998 hdaudio_afg_assign_names(struct hdaudio_afg_softc *sc)
2000 struct hdaudio_assoc *as = sc->sc_assocs;
2001 struct hdaudio_widget *w;
2002 int i, j;
2003 int type = -1, use, used =0;
2004 static const int types[7][13] = {
2005 { HDAUDIO_MIXER_LINE, HDAUDIO_MIXER_LINE1, HDAUDIO_MIXER_LINE2,
2006 HDAUDIO_MIXER_LINE3, -1 },
2007 { HDAUDIO_MIXER_MONITOR, HDAUDIO_MIXER_MIC, -1 }, /* int mic */
2008 { HDAUDIO_MIXER_MIC, HDAUDIO_MIXER_MONITOR, -1 }, /* ext mic */
2009 { HDAUDIO_MIXER_CD, -1 },
2010 { HDAUDIO_MIXER_SPEAKER, -1 },
2011 { HDAUDIO_MIXER_DIGITAL1, HDAUDIO_MIXER_DIGITAL2,
2012 HDAUDIO_MIXER_DIGITAL3, -1 },
2013 { HDAUDIO_MIXER_LINE, HDAUDIO_MIXER_LINE1, HDAUDIO_MIXER_LINE2,
2014 HDAUDIO_MIXER_LINE3, HDAUDIO_MIXER_PHONEIN,
2015 HDAUDIO_MIXER_PHONEOUT, HDAUDIO_MIXER_VIDEO, HDAUDIO_MIXER_RADIO,
2016 HDAUDIO_MIXER_DIGITAL1, HDAUDIO_MIXER_DIGITAL2,
2017 HDAUDIO_MIXER_DIGITAL3, HDAUDIO_MIXER_MONITOR, -1 } /* others */
2020 /* Surely known names */
2021 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
2022 w = hdaudio_afg_widget_lookup(sc, i);
2023 if (w == NULL || w->w_enable == false)
2024 continue;
2025 if (w->w_bindas == -1)
2026 continue;
2027 use = -1;
2028 switch (w->w_type) {
2029 case COP_AWCAP_TYPE_PIN_COMPLEX:
2030 if (as[w->w_bindas].as_dir == HDAUDIO_PINDIR_OUT)
2031 break;
2032 type = -1;
2033 switch (COP_CFG_DEFAULT_DEVICE(w->w_pin.config)) {
2034 case COP_DEVICE_LINE_IN:
2035 type = 0;
2036 break;
2037 case COP_DEVICE_MIC_IN:
2038 if (COP_CFG_PORT_CONNECTIVITY(w->w_pin.config)
2039 == COP_PORT_JACK)
2040 break;
2041 type = 1;
2042 break;
2043 case COP_DEVICE_CD:
2044 type = 3;
2045 break;
2046 case COP_DEVICE_SPEAKER:
2047 type = 4;
2048 break;
2049 case COP_DEVICE_SPDIF_IN:
2050 case COP_DEVICE_DIGITAL_OTHER_IN:
2051 type = 5;
2052 break;
2054 if (type == -1)
2055 break;
2056 j = 0;
2057 while (types[type][j] >= 0 &&
2058 (used & (1 << types[type][j])) != 0) {
2059 j++;
2061 if (types[type][j] >= 0)
2062 use = types[type][j];
2063 break;
2064 case COP_AWCAP_TYPE_AUDIO_OUTPUT:
2065 use = HDAUDIO_MIXER_PCM;
2066 break;
2067 case COP_AWCAP_TYPE_BEEP_GENERATOR:
2068 use = HDAUDIO_MIXER_SPEAKER;
2069 break;
2070 default:
2071 break;
2073 if (use >= 0) {
2074 w->w_audiodev = use;
2075 used |= (1 << use);
2078 /* Semi-known names */
2079 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
2080 w = hdaudio_afg_widget_lookup(sc, i);
2081 if (w == NULL || w->w_enable == false)
2082 continue;
2083 if (w->w_audiodev >= 0)
2084 continue;
2085 if (w->w_bindas == -1)
2086 continue;
2087 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
2088 continue;
2089 if (as[w->w_bindas].as_dir == HDAUDIO_PINDIR_OUT)
2090 continue;
2091 type = -1;
2092 switch (COP_CFG_DEFAULT_DEVICE(w->w_pin.config)) {
2093 case COP_DEVICE_LINE_OUT:
2094 case COP_DEVICE_SPEAKER:
2095 case COP_DEVICE_HP_OUT:
2096 case COP_DEVICE_AUX:
2097 type = 0;
2098 break;
2099 case COP_DEVICE_MIC_IN:
2100 type = 2;
2101 break;
2102 case COP_DEVICE_SPDIF_OUT:
2103 case COP_DEVICE_DIGITAL_OTHER_OUT:
2104 type = 5;
2105 break;
2107 if (type == -1)
2108 break;
2109 j = 0;
2110 while (types[type][j] >= 0 &&
2111 (used & (1 << types[type][j])) != 0) {
2112 j++;
2114 if (types[type][j] >= 0) {
2115 w->w_audiodev = types[type][j];
2116 used |= (1 << types[type][j]);
2119 /* Others */
2120 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
2121 w = hdaudio_afg_widget_lookup(sc, i);
2122 if (w == NULL || w->w_enable == false)
2123 continue;
2124 if (w->w_audiodev >= 0)
2125 continue;
2126 if (w->w_bindas == -1)
2127 continue;
2128 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
2129 continue;
2130 if (as[w->w_bindas].as_dir == HDAUDIO_PINDIR_OUT)
2131 continue;
2132 j = 0;
2133 while (types[6][j] >= 0 &&
2134 (used & (1 << types[6][j])) != 0) {
2135 j++;
2137 if (types[6][j] >= 0) {
2138 w->w_audiodev = types[6][j];
2139 used |= (1 << types[6][j]);
2144 static int
2145 hdaudio_afg_control_source_amp(struct hdaudio_afg_softc *sc, int nid, int index,
2146 int audiodev, int ctlable, int depth, int need)
2148 struct hdaudio_widget *w, *wc;
2149 struct hdaudio_control *ctl;
2150 int i, j, conns = 0, rneed;
2152 if (depth >= HDAUDIO_PARSE_MAXDEPTH)
2153 return need;
2155 w = hdaudio_afg_widget_lookup(sc, nid);
2156 if (w == NULL || w->w_enable == false)
2157 return need;
2159 /* Count number of active inputs */
2160 if (depth > 0) {
2161 for (j = 0; j < w->w_nconns; j++) {
2162 if (w->w_connsenable[j])
2163 ++conns;
2168 * If this is not a first step, use input mixer. Pins have common
2169 * input ctl so care must be taken
2171 if (depth > 0 && ctlable && (conns == 1 ||
2172 w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)) {
2173 ctl = hdaudio_afg_control_amp_get(sc, w->w_nid,
2174 HDAUDIO_PINDIR_IN, index, 1);
2175 if (ctl) {
2176 if (HDAUDIO_CONTROL_GIVE(ctl) & need)
2177 ctl->ctl_audiomask |= (1 << audiodev);
2178 else
2179 ctl->ctl_paudiomask |= (1 << audiodev);
2180 need &= ~HDAUDIO_CONTROL_GIVE(ctl);
2184 /* If widget has own audiodev, don't traverse it. */
2185 if (w->w_audiodev >= 0 && depth > 0)
2186 return need;
2188 /* We must not traverse pins */
2189 if ((w->w_type == COP_AWCAP_TYPE_AUDIO_INPUT ||
2190 w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX) && depth > 0)
2191 return need;
2193 /* Record that this widget exports such signal */
2194 w->w_audiomask |= (1 << audiodev);
2197 * If signals mixed, we can't assign controls further. Ignore this
2198 * on depth zero. Caller must know why. Ignore this for static
2199 * selectors if this input is selected.
2201 if (conns > 1)
2202 ctlable = 0;
2204 if (ctlable) {
2205 ctl = hdaudio_afg_control_amp_get(sc, w->w_nid,
2206 HDAUDIO_PINDIR_OUT, -1, 1);
2207 if (ctl) {
2208 if (HDAUDIO_CONTROL_GIVE(ctl) & need)
2209 ctl->ctl_audiomask |= (1 << audiodev);
2210 else
2211 ctl->ctl_paudiomask |= (1 << audiodev);
2212 need &= ~HDAUDIO_CONTROL_GIVE(ctl);
2216 rneed = 0;
2217 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
2218 wc = hdaudio_afg_widget_lookup(sc, i);
2219 if (wc == NULL || wc->w_enable == false)
2220 continue;
2221 for (j = 0; j < wc->w_nconns; j++) {
2222 if (wc->w_connsenable[j] && wc->w_conns[j] == nid) {
2223 rneed |= hdaudio_afg_control_source_amp(sc,
2224 wc->w_nid, j, audiodev, ctlable, depth + 1,
2225 need);
2229 rneed &= need;
2231 return rneed;
2234 static void
2235 hdaudio_afg_control_dest_amp(struct hdaudio_afg_softc *sc, int nid,
2236 int audiodev, int depth, int need)
2238 struct hdaudio_assoc *as = sc->sc_assocs;
2239 struct hdaudio_widget *w, *wc;
2240 struct hdaudio_control *ctl;
2241 int i, j, consumers;
2243 if (depth > HDAUDIO_PARSE_MAXDEPTH)
2244 return;
2246 w = hdaudio_afg_widget_lookup(sc, nid);
2247 if (w == NULL || w->w_enable == false)
2248 return;
2250 if (depth > 0) {
2252 * If this node produces output for several consumers,
2253 * we can't touch it
2255 consumers = 0;
2256 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
2257 wc = hdaudio_afg_widget_lookup(sc, i);
2258 if (wc == NULL || wc->w_enable == false)
2259 continue;
2260 for (j = 0; j < wc->w_nconns; j++) {
2261 if (wc->w_connsenable[j] &&
2262 wc->w_conns[j] == nid)
2263 ++consumers;
2267 * The only exception is if real HP redirection is configured
2268 * and this is a duplication point.
2269 * XXX: Not completely correct.
2271 if ((consumers == 2 && (w->w_bindas < 0 ||
2272 as[w->w_bindas].as_hpredir < 0 ||
2273 as[w->w_bindas].as_fakeredir ||
2274 (w->w_bindseqmask & (1 << 15)) == 0)) ||
2275 consumers > 2)
2276 return;
2278 /* Else use its output mixer */
2279 ctl = hdaudio_afg_control_amp_get(sc, w->w_nid,
2280 HDAUDIO_PINDIR_OUT, -1, 1);
2281 if (ctl) {
2282 if (HDAUDIO_CONTROL_GIVE(ctl) & need)
2283 ctl->ctl_audiomask |= (1 << audiodev);
2284 else
2285 ctl->ctl_paudiomask |= (1 << audiodev);
2286 need &= ~HDAUDIO_CONTROL_GIVE(ctl);
2290 /* We must not traverse pin */
2291 if (w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX && depth > 0)
2292 return;
2294 for (i = 0; i < w->w_nconns; i++) {
2295 int tneed = need;
2296 if (w->w_connsenable[i] == false)
2297 continue;
2298 ctl = hdaudio_afg_control_amp_get(sc, w->w_nid,
2299 HDAUDIO_PINDIR_IN, i, 1);
2300 if (ctl) {
2301 if (HDAUDIO_CONTROL_GIVE(ctl) & tneed)
2302 ctl->ctl_audiomask |= (1 << audiodev);
2303 else
2304 ctl->ctl_paudiomask |= (1 << audiodev);
2305 tneed &= ~HDAUDIO_CONTROL_GIVE(ctl);
2307 hdaudio_afg_control_dest_amp(sc, w->w_conns[i], audiodev,
2308 depth + 1, tneed);
2312 static void
2313 hdaudio_afg_assign_mixers(struct hdaudio_afg_softc *sc)
2315 struct hdaudio_assoc *as = sc->sc_assocs;
2316 struct hdaudio_control *ctl;
2317 struct hdaudio_widget *w;
2318 int i;
2320 /* Assign mixers to the tree */
2321 for (i = sc->sc_startnode; i < sc->sc_endnode; i++) {
2322 w = hdaudio_afg_widget_lookup(sc, i);
2323 if (w == NULL || w->w_enable == FALSE)
2324 continue;
2325 if (w->w_type == COP_AWCAP_TYPE_AUDIO_OUTPUT ||
2326 w->w_type == COP_AWCAP_TYPE_BEEP_GENERATOR ||
2327 (w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX &&
2328 as[w->w_bindas].as_dir == HDAUDIO_PINDIR_IN)) {
2329 if (w->w_audiodev < 0)
2330 continue;
2331 hdaudio_afg_control_source_amp(sc, w->w_nid, -1,
2332 w->w_audiodev, 1, 0, 1);
2333 } else if (w->w_pflags & HDAUDIO_ADC_MONITOR) {
2334 if (w->w_audiodev < 0)
2335 continue;
2336 if (hdaudio_afg_control_source_amp(sc, w->w_nid, -1,
2337 w->w_audiodev, 1, 0, 1)) {
2338 /* If we are unable to control input monitor
2339 as source, try to control it as dest */
2340 hdaudio_afg_control_dest_amp(sc, w->w_nid,
2341 w->w_audiodev, 0, 1);
2343 } else if (w->w_type == COP_AWCAP_TYPE_AUDIO_INPUT) {
2344 hdaudio_afg_control_dest_amp(sc, w->w_nid,
2345 HDAUDIO_MIXER_RECLEV, 0, 1);
2346 } else if (w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX &&
2347 as[w->w_bindas].as_dir == HDAUDIO_PINDIR_OUT) {
2348 hdaudio_afg_control_dest_amp(sc, w->w_nid,
2349 HDAUDIO_MIXER_VOLUME, 0, 1);
2352 /* Treat unrequired as possible */
2353 i = 0;
2354 for (i = 0; i < sc->sc_nctls; i++) {
2355 ctl = &sc->sc_ctls[i];
2356 if (ctl->ctl_audiomask == 0)
2357 ctl->ctl_audiomask = ctl->ctl_paudiomask;
2361 static void
2362 hdaudio_afg_build_mixers(struct hdaudio_afg_softc *sc)
2364 struct hdaudio_mixer *mx;
2365 struct hdaudio_control *ctl, *masterctl = NULL;
2366 uint32_t audiomask = 0;
2367 int nmixers = 0;
2368 int i, j, index = 0;
2369 int ndac, nadc;
2370 int ctrlcnt[HDAUDIO_MIXER_NRDEVICES];
2372 memset(ctrlcnt, 0, sizeof(ctrlcnt));
2374 /* Count the number of required mixers */
2375 for (i = 0; i < sc->sc_nctls; i++) {
2376 ctl = &sc->sc_ctls[i];
2377 if (ctl->ctl_enable == false ||
2378 ctl->ctl_audiomask == 0)
2379 continue;
2380 audiomask |= ctl->ctl_audiomask;
2381 ++nmixers;
2382 if (ctl->ctl_mute)
2383 ++nmixers;
2386 /* XXXJDM TODO: softvol */
2387 /* Declare master volume if needed */
2388 if ((audiomask & (HDAUDIO_MASK(VOLUME) | HDAUDIO_MASK(PCM))) ==
2389 HDAUDIO_MASK(PCM)) {
2390 audiomask |= HDAUDIO_MASK(VOLUME);
2391 for (i = 0; i < sc->sc_nctls; i++) {
2392 if (sc->sc_ctls[i].ctl_audiomask == HDAUDIO_MASK(PCM)) {
2393 masterctl = &sc->sc_ctls[i];
2394 ++nmixers;
2395 if (masterctl->ctl_mute)
2396 ++nmixers;
2397 break;
2402 /* Make room for mixer classes */
2403 nmixers += (HDAUDIO_MIXER_CLASS_LAST + 1);
2405 /* count DACs and ADCs for selectors */
2406 ndac = nadc = 0;
2407 for (i = 0; i < sc->sc_nassocs; i++) {
2408 if (sc->sc_assocs[i].as_enable == false)
2409 continue;
2410 if (sc->sc_assocs[i].as_dir == HDAUDIO_PINDIR_OUT)
2411 ++ndac;
2412 else if (sc->sc_assocs[i].as_dir == HDAUDIO_PINDIR_IN)
2413 ++nadc;
2416 /* Make room for selectors */
2417 if (ndac > 0)
2418 ++nmixers;
2419 if (nadc > 0)
2420 ++nmixers;
2422 hda_trace(sc, " need %d mixers (3 classes%s)\n",
2423 nmixers, masterctl ? " + fake master" : "");
2425 /* Allocate memory for the mixers */
2426 mx = kmem_zalloc(nmixers * sizeof(*mx), KM_SLEEP);
2427 sc->sc_nmixers = nmixers;
2429 /* Build class mixers */
2430 for (i = 0; i <= HDAUDIO_MIXER_CLASS_LAST; i++) {
2431 mx[index].mx_ctl = NULL;
2432 mx[index].mx_di.index = index;
2433 mx[index].mx_di.type = AUDIO_MIXER_CLASS;
2434 mx[index].mx_di.mixer_class = i;
2435 mx[index].mx_di.next = mx[index].mx_di.prev = AUDIO_MIXER_LAST;
2436 switch (i) {
2437 case HDAUDIO_MIXER_CLASS_OUTPUTS:
2438 strcpy(mx[index].mx_di.label.name, AudioCoutputs);
2439 break;
2440 case HDAUDIO_MIXER_CLASS_INPUTS:
2441 strcpy(mx[index].mx_di.label.name, AudioCinputs);
2442 break;
2443 case HDAUDIO_MIXER_CLASS_RECORD:
2444 strcpy(mx[index].mx_di.label.name, AudioCrecord);
2445 break;
2447 ++index;
2450 /* Shadow master control */
2451 if (masterctl != NULL) {
2452 mx[index].mx_ctl = masterctl;
2453 mx[index].mx_di.index = index;
2454 mx[index].mx_di.type = AUDIO_MIXER_VALUE;
2455 mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
2456 mx[index].mx_di.un.v.num_channels = 2; /* XXX */
2457 mx[index].mx_di.mixer_class = HDAUDIO_MIXER_CLASS_OUTPUTS;
2458 mx[index].mx_di.un.v.delta = 256 / (masterctl->ctl_step + 1);
2459 strcpy(mx[index].mx_di.label.name, AudioNmaster);
2460 strcpy(mx[index].mx_di.un.v.units.name, AudioNvolume);
2461 hda_trace(sc, " adding outputs.%s\n",
2462 mx[index].mx_di.label.name);
2463 ++index;
2464 if (masterctl->ctl_mute) {
2465 mx[index] = mx[index - 1];
2466 mx[index].mx_di.index = index;
2467 mx[index].mx_di.type = AUDIO_MIXER_ENUM;
2468 mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
2469 strcpy(mx[index].mx_di.label.name, AudioNmaster "." AudioNmute);
2470 mx[index].mx_di.un.e.num_mem = 2;
2471 strcpy(mx[index].mx_di.un.e.member[0].label.name, AudioNoff);
2472 mx[index].mx_di.un.e.member[0].ord = 0;
2473 strcpy(mx[index].mx_di.un.e.member[1].label.name, AudioNon);
2474 mx[index].mx_di.un.e.member[1].ord = 1;
2475 ++index;
2479 /* Build volume mixers */
2480 for (i = 0; i < sc->sc_nctls; i++) {
2481 uint32_t audiodev;
2483 ctl = &sc->sc_ctls[i];
2484 if (ctl->ctl_enable == false ||
2485 ctl->ctl_audiomask == 0)
2486 continue;
2487 audiodev = ffs(ctl->ctl_audiomask) - 1;
2488 mx[index].mx_ctl = ctl;
2489 mx[index].mx_di.index = index;
2490 mx[index].mx_di.type = AUDIO_MIXER_VALUE;
2491 mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
2492 mx[index].mx_di.un.v.num_channels = 2; /* XXX */
2493 mx[index].mx_di.un.v.delta = 256 / (ctl->ctl_step + 1);
2494 if (ctrlcnt[audiodev] > 0)
2495 snprintf(mx[index].mx_di.label.name,
2496 sizeof(mx[index].mx_di.label.name),
2497 "%s%d",
2498 hdaudio_afg_mixer_names[audiodev],
2499 ctrlcnt[audiodev] + 1);
2500 else
2501 strcpy(mx[index].mx_di.label.name,
2502 hdaudio_afg_mixer_names[audiodev]);
2503 ctrlcnt[audiodev]++;
2505 switch (audiodev) {
2506 case HDAUDIO_MIXER_VOLUME:
2507 case HDAUDIO_MIXER_BASS:
2508 case HDAUDIO_MIXER_TREBLE:
2509 case HDAUDIO_MIXER_OGAIN:
2510 mx[index].mx_di.mixer_class =
2511 HDAUDIO_MIXER_CLASS_OUTPUTS;
2512 hda_trace(sc, " adding outputs.%s\n",
2513 mx[index].mx_di.label.name);
2514 break;
2515 case HDAUDIO_MIXER_MIC:
2516 case HDAUDIO_MIXER_MONITOR:
2517 mx[index].mx_di.mixer_class =
2518 HDAUDIO_MIXER_CLASS_RECORD;
2519 hda_trace(sc, " adding record.%s\n",
2520 mx[index].mx_di.label.name);
2521 break;
2522 default:
2523 mx[index].mx_di.mixer_class =
2524 HDAUDIO_MIXER_CLASS_INPUTS;
2525 hda_trace(sc, " adding inputs.%s\n",
2526 mx[index].mx_di.label.name);
2527 break;
2529 strcpy(mx[index].mx_di.un.v.units.name, AudioNvolume);
2531 ++index;
2533 if (ctl->ctl_mute) {
2534 mx[index] = mx[index - 1];
2535 mx[index].mx_di.index = index;
2536 mx[index].mx_di.type = AUDIO_MIXER_ENUM;
2537 mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
2538 snprintf(mx[index].mx_di.label.name,
2539 sizeof(mx[index].mx_di.label.name),
2540 "%s." AudioNmute,
2541 mx[index - 1].mx_di.label.name);
2542 mx[index].mx_di.un.e.num_mem = 2;
2543 strcpy(mx[index].mx_di.un.e.member[0].label.name, AudioNoff);
2544 mx[index].mx_di.un.e.member[0].ord = 0;
2545 strcpy(mx[index].mx_di.un.e.member[1].label.name, AudioNon);
2546 mx[index].mx_di.un.e.member[1].ord = 1;
2547 ++index;
2551 /* DAC selector */
2552 if (ndac > 0) {
2553 mx[index].mx_ctl = NULL;
2554 mx[index].mx_di.index = index;
2555 mx[index].mx_di.type = AUDIO_MIXER_SET;
2556 mx[index].mx_di.mixer_class = HDAUDIO_MIXER_CLASS_OUTPUTS;
2557 mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
2558 strcpy(mx[index].mx_di.label.name, "dacsel"); /* AudioNselect */
2559 mx[index].mx_di.un.s.num_mem = ndac;
2560 for (i = 0, j = 0; i < sc->sc_nassocs; i++) {
2561 if (sc->sc_assocs[i].as_enable == false)
2562 continue;
2563 if (sc->sc_assocs[i].as_dir != HDAUDIO_PINDIR_OUT)
2564 continue;
2565 mx[index].mx_di.un.s.member[j].mask = 1 << i;
2566 sprintf(mx[index].mx_di.un.s.member[j].label.name,
2567 "DAC%02X", i);
2568 ++j;
2570 ++index;
2573 /* ADC selector */
2574 if (nadc > 0) {
2575 mx[index].mx_ctl = NULL;
2576 mx[index].mx_di.index = index;
2577 mx[index].mx_di.type = AUDIO_MIXER_SET;
2578 mx[index].mx_di.mixer_class = HDAUDIO_MIXER_CLASS_RECORD;
2579 mx[index].mx_di.prev = mx[index].mx_di.next = AUDIO_MIXER_LAST;
2580 strcpy(mx[index].mx_di.label.name, AudioNsource);
2581 mx[index].mx_di.un.s.num_mem = nadc;
2582 for (i = 0, j = 0; i < sc->sc_nassocs; i++) {
2583 if (sc->sc_assocs[i].as_enable == false)
2584 continue;
2585 if (sc->sc_assocs[i].as_dir != HDAUDIO_PINDIR_IN)
2586 continue;
2587 mx[index].mx_di.un.s.member[j].mask = 1 << i;
2588 sprintf(mx[index].mx_di.un.s.member[j].label.name,
2589 "ADC%02X", i);
2590 ++j;
2592 ++index;
2595 sc->sc_mixers = mx;
2598 static void
2599 hdaudio_afg_commit(struct hdaudio_afg_softc *sc)
2601 struct hdaudio_widget *w;
2602 uint32_t gdata, gmask, gdir;
2603 int commitgpio, numgpio;
2604 int i;
2606 /* Commit controls */
2607 hdaudio_afg_control_commit(sc);
2609 /* Commit selectors, pins, and EAPD */
2610 for (i = 0; i < sc->sc_nwidgets; i++) {
2611 w = &sc->sc_widgets[i];
2612 if (w->w_selconn == -1)
2613 w->w_selconn = 0;
2614 if (w->w_nconns > 0)
2615 hdaudio_afg_widget_connection_select(w, w->w_selconn);
2616 if (w->w_type == COP_AWCAP_TYPE_PIN_COMPLEX)
2617 hdaudio_command(sc->sc_codec, w->w_nid,
2618 CORB_SET_PIN_WIDGET_CONTROL, w->w_pin.ctrl);
2619 if (w->w_p.eapdbtl != 0xffffffff)
2620 hdaudio_command(sc->sc_codec, w->w_nid,
2621 CORB_SET_EAPD_BTL_ENABLE, w->w_p.eapdbtl);
2624 gdata = gmask = gdir = commitgpio = 0;
2625 numgpio = COP_GPIO_COUNT_NUM_GPIO(sc->sc_p.gpio_cnt);
2627 hda_trace(sc, "found %d GPIOs\n", numgpio);
2628 #if notyet
2629 for (i = 0; i < numgpio && i < 8; i++) {
2630 if (commitgpio == 0)
2631 commitgpio = 1;
2632 gdata |= 1 << i;
2633 gmask |= 1 << i;
2634 gdir |= 1 << i;
2636 #endif
2638 if (commitgpio) {
2639 hda_trace(sc, "GPIO commit: data=%08X mask=%08X dir=%08X\n",
2640 gdata, gmask, gdir);
2641 hdaudio_command(sc->sc_codec, sc->sc_nid,
2642 CORB_SET_GPIO_ENABLE_MASK, gmask);
2643 hdaudio_command(sc->sc_codec, sc->sc_nid,
2644 CORB_SET_GPIO_DIRECTION, gdir);
2645 hdaudio_command(sc->sc_codec, sc->sc_nid,
2646 CORB_SET_GPIO_DATA, gdata);
2650 static void
2651 hdaudio_afg_stream_connect(struct hdaudio_afg_softc *sc, int mode)
2653 struct hdaudio_assoc *as = sc->sc_assocs;
2654 struct hdaudio_widget *w;
2655 uint16_t fmt, dfmt;
2656 int tag, chn, maxchan, c;
2657 int i, j;
2659 KASSERT(mode == AUMODE_PLAY || mode == AUMODE_RECORD);
2661 dfmt = COP_DIGITAL_CONVCTRL1_DIGEN; /* TODO: AC3 */
2663 if (mode == AUMODE_PLAY)
2664 fmt = hdaudio_stream_param(sc->sc_audiodev.ad_playback,
2665 &sc->sc_pparam);
2666 else
2667 fmt = hdaudio_stream_param(sc->sc_audiodev.ad_capture,
2668 &sc->sc_rparam);
2670 for (i = 0; i < sc->sc_nassocs; i++) {
2671 if (as[i].as_enable == false)
2672 continue;
2674 if (mode == AUMODE_PLAY && as[i].as_dir != HDAUDIO_PINDIR_OUT)
2675 continue;
2676 if (mode == AUMODE_RECORD && as[i].as_dir != HDAUDIO_PINDIR_IN)
2677 continue;
2679 fmt &= ~HDAUDIO_FMT_CHAN_MASK;
2680 if (as[i].as_dir == HDAUDIO_PINDIR_OUT &&
2681 sc->sc_audiodev.ad_playback != NULL) {
2682 tag = hdaudio_stream_tag(sc->sc_audiodev.ad_playback);
2683 fmt |= HDAUDIO_FMT_CHAN(sc->sc_pparam.channels);
2684 maxchan = sc->sc_pparam.channels;
2685 } else if (as[i].as_dir == HDAUDIO_PINDIR_IN &&
2686 sc->sc_audiodev.ad_capture != NULL) {
2687 tag = hdaudio_stream_tag(sc->sc_audiodev.ad_capture);
2688 fmt |= HDAUDIO_FMT_CHAN(sc->sc_rparam.channels);
2689 maxchan = sc->sc_rparam.channels;
2690 } else {
2691 tag = 0;
2692 if (as[i].as_dir == HDAUDIO_PINDIR_OUT) {
2693 fmt |= HDAUDIO_FMT_CHAN(sc->sc_pchan);
2694 maxchan = sc->sc_pchan;
2695 } else {
2696 fmt |= HDAUDIO_FMT_CHAN(sc->sc_rchan);
2697 maxchan = sc->sc_rchan;
2701 chn = 0;
2702 for (j = 0; j < HDAUDIO_MAXPINS; j++) {
2703 if (as[i].as_dacs[j] == 0)
2704 continue;
2705 w = hdaudio_afg_widget_lookup(sc, as[i].as_dacs[j]);
2706 if (w == NULL || w->w_enable == FALSE)
2707 continue;
2708 if (as[i].as_hpredir >= 0 && i == as[i].as_pincnt)
2709 chn = 0;
2710 if (chn >= maxchan)
2711 chn = 0; /* XXX */
2712 c = (tag << 4) | chn;
2714 if (as[i].as_activated == false)
2715 c = 0;
2717 hdaudio_command(sc->sc_codec, w->w_nid,
2718 CORB_SET_CONVERTER_FORMAT, fmt);
2719 if (w->w_p.aw_cap & COP_AWCAP_DIGITAL)
2720 hdaudio_command(sc->sc_codec, w->w_nid,
2721 CORB_SET_DIGITAL_CONVERTER_CONTROL_1, dfmt);
2722 hdaudio_command(sc->sc_codec, w->w_nid,
2723 CORB_SET_CONVERTER_STREAM_CHANNEL, c);
2724 chn += (w->w_p.aw_cap & COP_AWCAP_STEREO) ? 2 : 1;
2729 static int
2730 hdaudio_afg_stream_intr(struct hdaudio_stream *st)
2732 struct hdaudio_audiodev *ad = st->st_cookie;
2733 int handled = 0;
2734 uint8_t sts;
2736 sts = hda_read1(ad->ad_sc->sc_host, HDAUDIO_SD_STS(st->st_shift));
2737 hda_write1(ad->ad_sc->sc_host, HDAUDIO_SD_STS(st->st_shift),
2738 HDAUDIO_STS_DESE | HDAUDIO_STS_FIFOE | HDAUDIO_STS_BCIS);
2740 //if (sts & HDAUDIO_STS_BCIS) {
2741 if (st == ad->ad_playback && ad->ad_playbackintr) {
2742 ad->ad_playbackintr(ad->ad_playbackintrarg);
2743 handled = 1;
2744 } else if (st == ad->ad_capture && ad->ad_captureintr) {
2745 ad->ad_captureintr(ad->ad_captureintrarg);
2746 handled = 1;
2750 return handled;
2753 static int
2754 hdaudio_afg_assoc_count_channels(struct hdaudio_afg_softc *sc,
2755 struct hdaudio_assoc *as, enum hdaudio_pindir dir)
2757 struct hdaudio_widget *w;
2758 int *dacmap;
2759 int i, dacmapsz = sizeof(*dacmap) * sc->sc_endnode;
2760 int nchans = 0;
2762 if (as->as_enable == false || as->as_dir != dir)
2763 return 0;
2765 dacmap = kmem_zalloc(dacmapsz, KM_SLEEP);
2766 if (dacmap == NULL)
2767 return 0;
2769 for (i = 0; i < HDAUDIO_MAXPINS; i++)
2770 if (as->as_dacs[i])
2771 dacmap[as->as_dacs[i]] = 1;
2773 for (i = 1; i < sc->sc_endnode; i++) {
2774 if (!dacmap[i])
2775 continue;
2776 w = hdaudio_afg_widget_lookup(sc, i);
2777 if (w == NULL || w->w_enable == false)
2778 continue;
2779 nchans += (w->w_p.aw_cap & COP_AWCAP_STEREO) ? 2 : 1;
2782 kmem_free(dacmap, dacmapsz);
2784 return nchans;
2787 static bool
2788 hdaudio_afg_rate_supported(struct hdaudio_afg_softc *sc, u_int frequency)
2790 uint32_t caps = sc->sc_p.pcm_size_rate;
2792 #define ISFREQOK(shift) ((caps & (1 << (shift))) ? true : false)
2793 switch (frequency) {
2794 case 8000:
2795 return ISFREQOK(0);
2796 case 11025:
2797 return ISFREQOK(1);
2798 case 16000:
2799 return ISFREQOK(2);
2800 case 22050:
2801 return ISFREQOK(3);
2802 case 32000:
2803 return ISFREQOK(4);
2804 case 44100:
2805 return ISFREQOK(5);
2806 case 48000:
2807 return true; /* Must be supported by all codecs */
2808 case 88200:
2809 return ISFREQOK(7);
2810 case 96000:
2811 return ISFREQOK(8);
2812 case 176400:
2813 return ISFREQOK(9);
2814 case 192000:
2815 return ISFREQOK(10);
2816 case 384000:
2817 return ISFREQOK(11);
2818 default:
2819 return false;
2821 #undef ISFREQOK
2824 static bool
2825 hdaudio_afg_bits_supported(struct hdaudio_afg_softc *sc, u_int bits)
2827 uint32_t caps = sc->sc_p.pcm_size_rate;
2828 #define ISBITSOK(shift) ((caps & (1 << (shift))) ? true : false)
2829 switch (bits) {
2830 case 8:
2831 return ISBITSOK(16);
2832 case 16:
2833 return ISBITSOK(17);
2834 case 20:
2835 return ISBITSOK(18);
2836 case 24:
2837 return ISBITSOK(19);
2838 case 32:
2839 return ISBITSOK(20);
2840 default:
2841 return false;
2843 #undef ISBITSOK
2846 static bool
2847 hdaudio_afg_probe_encoding(struct hdaudio_afg_softc *sc,
2848 u_int minrate, u_int maxrate, u_int validbits, u_int precision, bool force)
2850 struct audio_format f;
2852 if (!force && hdaudio_afg_bits_supported(sc, validbits) == false)
2853 return false;
2855 memset(&f, 0, sizeof(f));
2856 f.driver_data = NULL;
2857 f.mode = 0;
2858 f.encoding = AUDIO_ENCODING_SLINEAR_LE;
2859 f.validbits = validbits;
2860 f.precision = precision;
2861 f.channels = 0;
2862 f.channel_mask = 0;
2863 f.frequency_type = 0;
2864 f.frequency[0] = minrate;
2865 f.frequency[1] = maxrate;
2867 #define HDAUDIO_INITFMT(ch, chmask) \
2868 do { \
2869 f.channels = (ch); \
2870 f.channel_mask = (chmask); \
2871 f.mode = 0; \
2872 if (sc->sc_pchan >= (ch)) \
2873 f.mode |= AUMODE_PLAY; \
2874 if (sc->sc_rchan >= (ch)) \
2875 f.mode |= AUMODE_RECORD; \
2876 if (f.mode != 0) \
2877 hdaudio_afg_append_formats(&sc->sc_audiodev, &f); \
2878 } while (0)
2880 /* Commented out, otherwise monaural samples play through left
2881 * channel only
2883 /* HDAUDIO_INITFMT(1, AUFMT_MONAURAL); */
2884 HDAUDIO_INITFMT(2, AUFMT_STEREO);
2885 HDAUDIO_INITFMT(4, AUFMT_SURROUND4);
2886 HDAUDIO_INITFMT(6, AUFMT_DOLBY_5_1);
2887 HDAUDIO_INITFMT(8, AUFMT_SURROUND_7_1);
2889 #undef HDAUDIO_INITFMT
2891 return true;
2895 static void
2896 hdaudio_afg_configure_encodings(struct hdaudio_afg_softc *sc)
2898 const u_int possible_rates[] = {
2899 8000, 11025, 16000, 22050, 32000, 44100,
2900 48000, 88200, 96000, 176500, 192000, /* 384000, */
2902 struct hdaudio_assoc *as = sc->sc_assocs;
2903 struct audio_format f;
2904 u_int minrate, maxrate;
2905 int nchan, i;
2907 sc->sc_pchan = sc->sc_rchan = 0;
2908 minrate = maxrate = 0;
2910 for (nchan = 0, i = 0; i < sc->sc_nassocs; i++) {
2911 nchan = hdaudio_afg_assoc_count_channels(sc, &as[i],
2912 HDAUDIO_PINDIR_OUT);
2913 if (nchan > sc->sc_pchan)
2914 sc->sc_pchan = nchan;
2916 for (nchan = 0, i = 0; i < sc->sc_nassocs; i++) {
2917 nchan = hdaudio_afg_assoc_count_channels(sc, &as[i],
2918 HDAUDIO_PINDIR_IN);
2919 if (nchan > sc->sc_rchan)
2920 sc->sc_rchan = nchan;
2922 hda_print(sc, "%dch/%dch", sc->sc_pchan, sc->sc_rchan);
2924 for (i = 0; __arraycount(possible_rates); i++)
2925 if (hdaudio_afg_rate_supported(sc, possible_rates[i])) {
2926 minrate = possible_rates[i];
2927 break;
2929 for (i = __arraycount(possible_rates) - 1; i >= 0; i--)
2930 if (hdaudio_afg_rate_supported(sc, possible_rates[i])) {
2931 maxrate = possible_rates[i];
2932 break;
2934 KASSERT(minrate > 0 && maxrate > 0); /* impossible */
2935 hda_print1(sc, " %uHz", minrate);
2936 if (minrate != maxrate)
2937 hda_print1(sc, "-%uHz", maxrate);
2939 if (hdaudio_afg_probe_encoding(sc, minrate, maxrate, 8, 16, false))
2940 hda_print1(sc, " 8/16");
2941 if (hdaudio_afg_probe_encoding(sc, minrate, maxrate, 16, 16, false))
2942 hda_print1(sc, " 16/16");
2943 if (hdaudio_afg_probe_encoding(sc, minrate, maxrate, 20, 32, false))
2944 hda_print1(sc, " 20/32");
2945 if (hdaudio_afg_probe_encoding(sc, minrate, maxrate, 24, 32, false))
2946 hda_print1(sc, " 24/32");
2947 if (hdaudio_afg_probe_encoding(sc, minrate, maxrate, 32, 32, false))
2948 hda_print1(sc, " 32/32");
2950 if (sc->sc_audiodev.ad_nformats == 0) {
2951 hdaudio_afg_probe_encoding(sc, minrate, maxrate, 16, 16, true);
2952 hda_print1(sc, " 16/16*");
2956 * XXX JDM 20090614
2957 * MI audio assumes that at least one playback and one capture format
2958 * is reported by the hw driver; until this bug is resolved just
2959 * report 2ch capabilities if the function group does not support
2960 * the direction.
2962 if (sc->sc_rchan == 0 || sc->sc_pchan == 0) {
2963 memset(&f, 0, sizeof(f));
2964 f.driver_data = NULL;
2965 f.mode = 0;
2966 f.encoding = AUDIO_ENCODING_SLINEAR_LE;
2967 f.validbits = 16;
2968 f.precision = 16;
2969 f.channels = 2;
2970 f.channel_mask = AUFMT_STEREO;
2971 f.frequency_type = 0;
2972 f.frequency[0] = f.frequency[1] = 48000;
2973 f.mode = AUMODE_PLAY|AUMODE_RECORD;
2974 hdaudio_afg_append_formats(&sc->sc_audiodev, &f);
2977 hda_print1(sc, "\n");
2980 static void
2981 hdaudio_afg_hp_switch_handler(void *opaque)
2983 struct hdaudio_afg_softc *sc = opaque;
2984 struct hdaudio_assoc *as = sc->sc_assocs;
2985 struct hdaudio_widget *w;
2986 uint32_t res = 0;
2987 int i, j;
2989 if (!device_is_active(sc->sc_dev))
2990 goto resched;
2992 for (i = 0; i < sc->sc_nassocs; i++)
2993 for (j = 0; j < HDAUDIO_MAXPINS; j++) {
2994 w = hdaudio_afg_widget_lookup(sc, as[i].as_pins[j]);
2995 if (w == NULL || w->w_enable == false)
2996 continue;
2997 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
2998 continue;
2999 if (COP_CFG_DEFAULT_DEVICE(w->w_pin.config) !=
3000 COP_DEVICE_HP_OUT)
3001 continue;
3002 res |= hdaudio_command(sc->sc_codec, as[i].as_pins[j],
3003 CORB_GET_PIN_SENSE, 0) &
3004 COP_GET_PIN_SENSE_PRESENSE_DETECT;
3007 for (i = 0; i < sc->sc_nassocs; i++)
3008 for (j = 0; j < HDAUDIO_MAXPINS; j++) {
3009 w = hdaudio_afg_widget_lookup(sc, as[i].as_pins[j]);
3010 if (w == NULL || w->w_enable == false)
3011 continue;
3012 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
3013 continue;
3014 switch (COP_CFG_DEFAULT_DEVICE(w->w_pin.config)) {
3015 case COP_DEVICE_HP_OUT:
3016 if (res & COP_GET_PIN_SENSE_PRESENSE_DETECT)
3017 w->w_pin.ctrl |= COP_PWC_OUT_ENABLE;
3018 else
3019 w->w_pin.ctrl &= ~COP_PWC_OUT_ENABLE;
3020 hdaudio_command(sc->sc_codec, w->w_nid,
3021 CORB_SET_PIN_WIDGET_CONTROL, w->w_pin.ctrl);
3022 break;
3023 case COP_DEVICE_LINE_OUT:
3024 case COP_DEVICE_SPEAKER:
3025 case COP_DEVICE_AUX:
3026 if (res & COP_GET_PIN_SENSE_PRESENSE_DETECT)
3027 w->w_pin.ctrl &= ~COP_PWC_OUT_ENABLE;
3028 else
3029 w->w_pin.ctrl |= COP_PWC_OUT_ENABLE;
3030 hdaudio_command(sc->sc_codec, w->w_nid,
3031 CORB_SET_PIN_WIDGET_CONTROL, w->w_pin.ctrl);
3032 break;
3033 default:
3034 break;
3038 resched:
3039 callout_schedule(&sc->sc_jack_callout, HDAUDIO_HP_SENSE_PERIOD);
3042 static void
3043 hdaudio_afg_hp_switch_init(struct hdaudio_afg_softc *sc)
3045 struct hdaudio_assoc *as = sc->sc_assocs;
3046 struct hdaudio_widget *w;
3047 bool enable = false;
3048 int i;
3050 for (i = 0; i < sc->sc_nassocs; i++) {
3051 if (as[i].as_hpredir < 0)
3052 continue;
3053 w = hdaudio_afg_widget_lookup(sc, as[i].as_pins[15]);
3054 if (w == NULL || w->w_enable == false)
3055 continue;
3056 if (w->w_type != COP_AWCAP_TYPE_PIN_COMPLEX)
3057 continue;
3058 if (!(w->w_pin.cap & COP_PINCAP_PRESENSE_DETECT_CAPABLE))
3059 continue;
3060 if (COP_CFG_MISC(w->w_pin.config) & 1) {
3061 hda_trace(sc, "no jack detection on pin %02X\n",
3062 as[i].as_pins[15]);
3063 continue;
3065 enable = true;
3067 if (w->w_p.aw_cap & COP_AWCAP_UNSOL_CAPABLE)
3068 hdaudio_command(sc->sc_codec, w->w_nid,
3069 CORB_SET_UNSOLICITED_RESPONSE,
3070 COP_SET_UNSOLICITED_RESPONSE_ENABLE |
3071 HDAUDIO_UNSOLTAG_EVENT_HP);
3073 hda_trace(sc, "jack detect supported on pin %02X [%s]\n",
3074 as[i].as_pins[15],
3075 (w->w_p.aw_cap & COP_AWCAP_UNSOL_CAPABLE) ?
3076 "unsol" : "poll");
3078 if (enable) {
3079 sc->sc_jack_polling = true;
3080 hdaudio_afg_hp_switch_handler(sc);
3081 } else
3082 hda_trace(sc, "jack detect not enabled\n");
3085 static void
3086 hdaudio_afg_attach(device_t parent, device_t self, void *opaque)
3088 struct hdaudio_afg_softc *sc = device_private(self);
3089 audio_params_t defparams;
3090 prop_dictionary_t args = opaque;
3091 uint64_t fgptr = 0;
3092 uint8_t nid = 0;
3093 int err;
3094 bool rv;
3096 sc->sc_dev = self;
3098 callout_init(&sc->sc_jack_callout, 0);
3099 callout_setfunc(&sc->sc_jack_callout,
3100 hdaudio_afg_hp_switch_handler, sc);
3102 if (!pmf_device_register(self, hdaudio_afg_suspend, hdaudio_afg_resume))
3103 aprint_error_dev(self, "couldn't establish power handler\n");
3105 sc->sc_config = prop_dictionary_get(args, "pin-config");
3106 if (sc->sc_config && prop_object_type(sc->sc_config) != PROP_TYPE_ARRAY)
3107 sc->sc_config = NULL;
3108 hda_print1(sc, " (%s configuration)\n", sc->sc_config ?
3109 "custom" : "firmware");
3111 rv = prop_dictionary_get_uint64(args, "function-group", &fgptr);
3112 if (rv == false || fgptr == 0) {
3113 hda_error(sc, "missing function-group property\n");
3114 return;
3116 rv = prop_dictionary_get_uint8(args, "node-id", &nid);
3117 if (rv == false || nid == 0) {
3118 hda_error(sc, "missing node-id property\n");
3119 return;
3121 prop_dictionary_get_uint16(args, "vendor-id", &sc->sc_vendor);
3122 prop_dictionary_get_uint16(args, "product-id", &sc->sc_product);
3124 sc->sc_nid = nid;
3125 sc->sc_fg = (struct hdaudio_function_group *)(vaddr_t)fgptr;
3126 sc->sc_codec = sc->sc_fg->fg_codec;
3127 KASSERT(sc->sc_codec != NULL);
3128 sc->sc_host = sc->sc_codec->co_host;
3129 KASSERT(sc->sc_host != NULL);
3131 hda_debug(sc, "parsing widgets\n");
3132 hdaudio_afg_parse(sc);
3133 hda_debug(sc, "parsing controls\n");
3134 hdaudio_afg_control_parse(sc);
3135 hda_debug(sc, "disabling non-audio devices\n");
3136 hdaudio_afg_disable_nonaudio(sc);
3137 hda_debug(sc, "disabling useless devices\n");
3138 hdaudio_afg_disable_useless(sc);
3139 hda_debug(sc, "parsing associations\n");
3140 hdaudio_afg_assoc_parse(sc);
3141 hda_debug(sc, "building tree\n");
3142 hdaudio_afg_build_tree(sc);
3143 hda_debug(sc, "disabling unassociated pins\n");
3144 hdaudio_afg_disable_unassoc(sc);
3145 hda_debug(sc, "disabling unselected pins\n");
3146 hdaudio_afg_disable_unsel(sc);
3147 hda_debug(sc, "disabling useless devices\n");
3148 hdaudio_afg_disable_useless(sc);
3149 hda_debug(sc, "disabling cross-associated pins\n");
3150 hdaudio_afg_disable_crossassoc(sc);
3151 hda_debug(sc, "disabling useless devices\n");
3152 hdaudio_afg_disable_useless(sc);
3154 hda_debug(sc, "assigning mixer names to sound sources\n");
3155 hdaudio_afg_assign_names(sc);
3156 hda_debug(sc, "assigning mixers to device tree\n");
3157 hdaudio_afg_assign_mixers(sc);
3159 hda_debug(sc, "preparing pin controls\n");
3160 hdaudio_afg_prepare_pin_controls(sc);
3161 hda_debug(sc, "commiting settings\n");
3162 hdaudio_afg_commit(sc);
3164 hda_debug(sc, "setup jack sensing\n");
3165 hdaudio_afg_hp_switch_init(sc);
3167 hda_debug(sc, "building mixer controls\n");
3168 hdaudio_afg_build_mixers(sc);
3170 hdaudio_afg_dump(sc);
3171 if (0) hdaudio_afg_widget_pin_dump(sc);
3172 hdaudio_afg_assoc_dump(sc);
3174 hda_debug(sc, "configuring encodings\n");
3175 sc->sc_audiodev.ad_sc = sc;
3176 hdaudio_afg_configure_encodings(sc);
3177 err = auconv_create_encodings(sc->sc_audiodev.ad_formats,
3178 sc->sc_audiodev.ad_nformats, &sc->sc_audiodev.ad_encodings);
3179 if (err) {
3180 hda_error(sc, "couldn't create encodings\n");
3181 return;
3184 hda_debug(sc, "reserving streams\n");
3185 sc->sc_audiodev.ad_capture = hdaudio_stream_establish(sc->sc_host,
3186 HDAUDIO_STREAM_ISS, hdaudio_afg_stream_intr, &sc->sc_audiodev);
3187 sc->sc_audiodev.ad_playback = hdaudio_stream_establish(sc->sc_host,
3188 HDAUDIO_STREAM_OSS, hdaudio_afg_stream_intr, &sc->sc_audiodev);
3190 hda_debug(sc, "connecting streams\n");
3191 defparams.channels = 2;
3192 defparams.sample_rate = 48000;
3193 defparams.precision = defparams.validbits = 16;
3194 defparams.encoding = AUDIO_ENCODING_SLINEAR_LE;
3195 sc->sc_pparam = sc->sc_rparam = defparams;
3196 hdaudio_afg_stream_connect(sc, AUMODE_PLAY);
3197 hdaudio_afg_stream_connect(sc, AUMODE_RECORD);
3199 hda_debug(sc, "attaching audio device\n");
3200 sc->sc_audiodev.ad_audiodev = audio_attach_mi(&hdaudio_afg_hw_if,
3201 &sc->sc_audiodev, self);
3204 static int
3205 hdaudio_afg_detach(device_t self, int flags)
3207 struct hdaudio_afg_softc *sc = device_private(self);
3208 struct hdaudio_widget *w = sc->sc_widgets;
3209 struct hdaudio_assoc *as = sc->sc_assocs;
3210 struct hdaudio_control *ctl = sc->sc_ctls;
3211 struct hdaudio_mixer *mx = sc->sc_mixers;
3213 callout_halt(&sc->sc_jack_callout, NULL);
3214 callout_destroy(&sc->sc_jack_callout);
3216 if (sc->sc_config)
3217 prop_object_release(sc->sc_config);
3218 if (sc->sc_audiodev.ad_audiodev)
3219 config_detach(sc->sc_audiodev.ad_audiodev, flags);
3220 if (sc->sc_audiodev.ad_encodings)
3221 auconv_delete_encodings(sc->sc_audiodev.ad_encodings);
3222 if (sc->sc_audiodev.ad_playback)
3223 hdaudio_stream_disestablish(sc->sc_audiodev.ad_playback);
3224 if (sc->sc_audiodev.ad_capture)
3225 hdaudio_stream_disestablish(sc->sc_audiodev.ad_capture);
3226 if (w)
3227 kmem_free(w, sc->sc_nwidgets * sizeof(*w));
3228 if (as)
3229 kmem_free(as, sc->sc_nassocs * sizeof(*as));
3230 if (ctl)
3231 kmem_free(ctl, sc->sc_nctls * sizeof(*ctl));
3232 if (mx)
3233 kmem_free(mx, sc->sc_nmixers * sizeof(*mx));
3235 pmf_device_deregister(self);
3237 return 0;
3240 static void
3241 hdaudio_afg_childdet(device_t self, device_t child)
3243 struct hdaudio_afg_softc *sc = device_private(self);
3245 if (child == sc->sc_audiodev.ad_audiodev)
3246 sc->sc_audiodev.ad_audiodev = NULL;
3249 static bool
3250 hdaudio_afg_suspend(device_t self, pmf_qual_t qual)
3252 struct hdaudio_afg_softc *sc = device_private(self);
3254 callout_halt(&sc->sc_jack_callout, NULL);
3256 return true;
3259 static bool
3260 hdaudio_afg_resume(device_t self, pmf_qual_t qual)
3262 struct hdaudio_afg_softc *sc = device_private(self);
3263 int nid;
3265 hdaudio_command(sc->sc_codec, sc->sc_nid,
3266 CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
3267 hda_delay(100);
3268 for (nid = sc->sc_startnode; nid < sc->sc_endnode; nid++)
3269 hdaudio_command(sc->sc_codec, nid,
3270 CORB_SET_POWER_STATE, COP_POWER_STATE_D0);
3271 hda_delay(1000);
3273 hdaudio_afg_commit(sc);
3274 hdaudio_afg_stream_connect(sc, AUMODE_PLAY);
3275 hdaudio_afg_stream_connect(sc, AUMODE_RECORD);
3277 if (sc->sc_jack_polling)
3278 hdaudio_afg_hp_switch_handler(sc);
3280 return true;
3283 static int
3284 hdaudio_afg_query_encoding(void *opaque, struct audio_encoding *ae)
3286 struct hdaudio_audiodev *ad = opaque;
3287 return auconv_query_encoding(ad->ad_encodings, ae);
3290 static int
3291 hdaudio_afg_set_params(void *opaque, int setmode, int usemode,
3292 audio_params_t *play, audio_params_t *rec,
3293 stream_filter_list_t *pfil, stream_filter_list_t *rfil)
3295 struct hdaudio_audiodev *ad = opaque;
3296 int index;
3298 if (play && (setmode & AUMODE_PLAY)) {
3299 index = auconv_set_converter(ad->ad_formats, ad->ad_nformats,
3300 AUMODE_PLAY, play, TRUE, pfil);
3301 if (index < 0)
3302 return EINVAL;
3303 ad->ad_sc->sc_pparam = *play;
3304 hdaudio_afg_stream_connect(ad->ad_sc, AUMODE_PLAY);
3306 if (rec && (setmode & AUMODE_RECORD)) {
3307 index = auconv_set_converter(ad->ad_formats, ad->ad_nformats,
3308 AUMODE_RECORD, rec, TRUE, rfil);
3309 if (index < 0)
3310 return EINVAL;
3311 ad->ad_sc->sc_rparam = *rec;
3312 hdaudio_afg_stream_connect(ad->ad_sc, AUMODE_RECORD);
3314 return 0;
3317 static int
3318 hdaudio_afg_round_blocksize(void *opaque, int blksize, int mode,
3319 const audio_params_t *param)
3321 struct hdaudio_audiodev *ad = opaque;
3322 struct hdaudio_stream *st;
3323 int bufsize;
3325 st = (mode == AUMODE_PLAY) ? ad->ad_playback : ad->ad_capture;
3326 if (st == NULL) {
3327 hda_trace(ad->ad_sc,
3328 "round_blocksize called for invalid stream\n");
3329 return 128;
3332 /* Multiple of 128 */
3333 blksize &= ~128;
3334 if (blksize <= 0)
3335 blksize = 128;
3337 bufsize = st->st_data.dma_size;
3338 if (bufsize > HDAUDIO_BDL_MAX * blksize) {
3339 blksize = bufsize / HDAUDIO_BDL_MAX;
3340 if (blksize & 128)
3341 blksize = (blksize + 128) & ~128;
3344 return blksize;
3347 static int
3348 hdaudio_afg_commit_settings(void *opaque)
3350 return 0;
3353 static int
3354 hdaudio_afg_halt_output(void *opaque)
3356 struct hdaudio_audiodev *ad = opaque;
3358 hdaudio_stream_stop(ad->ad_playback);
3360 return 0;
3363 static int
3364 hdaudio_afg_halt_input(void *opaque)
3366 struct hdaudio_audiodev *ad = opaque;
3368 hdaudio_stream_stop(ad->ad_capture);
3370 return 0;
3373 static int
3374 hdaudio_afg_getdev(void *opaque, struct audio_device *audiodev)
3376 *audiodev = hdaudio_afg_audio_device;
3377 return 0;
3380 static int
3381 hdaudio_afg_set_port(void *opaque, mixer_ctrl_t *mc)
3383 struct hdaudio_audiodev *ad = opaque;
3384 struct hdaudio_afg_softc *sc = ad->ad_sc;
3385 struct hdaudio_mixer *mx;
3386 struct hdaudio_control *ctl;
3387 int i, divisor;
3389 if (mc->dev < 0 || mc->dev >= sc->sc_nmixers)
3390 return EINVAL;
3391 mx = &sc->sc_mixers[mc->dev];
3392 ctl = mx->mx_ctl;
3393 if (ctl == NULL) {
3394 if (mx->mx_di.type != AUDIO_MIXER_SET)
3395 return ENXIO;
3396 if (mx->mx_di.mixer_class != HDAUDIO_MIXER_CLASS_OUTPUTS &&
3397 mx->mx_di.mixer_class != HDAUDIO_MIXER_CLASS_RECORD)
3398 return ENXIO;
3399 for (i = 0; i < sc->sc_nassocs; i++) {
3400 if (sc->sc_assocs[i].as_dir != HDAUDIO_PINDIR_OUT &&
3401 mx->mx_di.mixer_class ==
3402 HDAUDIO_MIXER_CLASS_OUTPUTS)
3403 continue;
3404 if (sc->sc_assocs[i].as_dir != HDAUDIO_PINDIR_IN &&
3405 mx->mx_di.mixer_class ==
3406 HDAUDIO_MIXER_CLASS_RECORD)
3407 continue;
3408 sc->sc_assocs[i].as_activated =
3409 (mc->un.mask & (1 << i)) ? true : false;
3411 hdaudio_afg_stream_connect(ad->ad_sc,
3412 mx->mx_di.mixer_class == HDAUDIO_MIXER_CLASS_OUTPUTS ?
3413 AUMODE_PLAY : AUMODE_RECORD);
3414 return 0;
3417 switch (mx->mx_di.type) {
3418 case AUDIO_MIXER_VALUE:
3419 if (ctl->ctl_step == 0)
3420 divisor = 128; /* ??? - just avoid div by 0 */
3421 else
3422 divisor = 255 / ctl->ctl_step;
3424 hdaudio_afg_control_amp_set(ctl, HDAUDIO_AMP_MUTE_NONE,
3425 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] / divisor,
3426 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] / divisor);
3427 break;
3428 case AUDIO_MIXER_ENUM:
3429 hdaudio_afg_control_amp_set(ctl,
3430 mc->un.ord ? HDAUDIO_AMP_MUTE_ALL : HDAUDIO_AMP_MUTE_NONE,
3431 ctl->ctl_left, ctl->ctl_right);
3432 break;
3433 default:
3434 return ENXIO;
3437 return 0;
3440 static int
3441 hdaudio_afg_get_port(void *opaque, mixer_ctrl_t *mc)
3443 struct hdaudio_audiodev *ad = opaque;
3444 struct hdaudio_afg_softc *sc = ad->ad_sc;
3445 struct hdaudio_mixer *mx;
3446 struct hdaudio_control *ctl;
3447 u_int mask = 0;
3448 int i, factor;
3450 if (mc->dev < 0 || mc->dev >= sc->sc_nmixers)
3451 return EINVAL;
3452 mx = &sc->sc_mixers[mc->dev];
3453 ctl = mx->mx_ctl;
3454 if (ctl == NULL) {
3455 if (mx->mx_di.type != AUDIO_MIXER_SET)
3456 return ENXIO;
3457 if (mx->mx_di.mixer_class != HDAUDIO_MIXER_CLASS_OUTPUTS &&
3458 mx->mx_di.mixer_class != HDAUDIO_MIXER_CLASS_RECORD)
3459 return ENXIO;
3460 for (i = 0; i < sc->sc_nassocs; i++) {
3461 if (sc->sc_assocs[i].as_enable == false)
3462 continue;
3463 if (sc->sc_assocs[i].as_activated == false)
3464 continue;
3465 if (sc->sc_assocs[i].as_dir == HDAUDIO_PINDIR_OUT &&
3466 mx->mx_di.mixer_class ==
3467 HDAUDIO_MIXER_CLASS_OUTPUTS)
3468 mask |= (1 << i);
3469 if (sc->sc_assocs[i].as_dir == HDAUDIO_PINDIR_IN &&
3470 mx->mx_di.mixer_class ==
3471 HDAUDIO_MIXER_CLASS_RECORD)
3472 mask |= (1 << i);
3474 mc->un.mask = mask;
3475 return 0;
3478 switch (mx->mx_di.type) {
3479 case AUDIO_MIXER_VALUE:
3480 if (ctl->ctl_step == 0)
3481 factor = 128; /* ??? - just avoid div by 0 */
3482 else
3483 factor = 255 / ctl->ctl_step;
3485 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ctl->ctl_left * factor;
3486 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ctl->ctl_right * factor;
3487 break;
3488 case AUDIO_MIXER_ENUM:
3489 mc->un.ord = (ctl->ctl_muted || ctl->ctl_forcemute) ? 1 : 0;
3490 break;
3491 default:
3492 return ENXIO;
3494 return 0;
3497 static int
3498 hdaudio_afg_query_devinfo(void *opaque, mixer_devinfo_t *di)
3500 struct hdaudio_audiodev *ad = opaque;
3501 struct hdaudio_afg_softc *sc = ad->ad_sc;
3503 if (di->index >= sc->sc_nmixers)
3504 return ENXIO;
3506 *di = sc->sc_mixers[di->index].mx_di;
3508 return 0;
3511 static void *
3512 hdaudio_afg_allocm(void *opaque, int direction, size_t size,
3513 struct malloc_type *type, int flags)
3515 struct hdaudio_audiodev *ad = opaque;
3516 struct hdaudio_stream *st;
3517 int err;
3519 st = (direction == AUMODE_PLAY) ? ad->ad_playback : ad->ad_capture;
3520 if (st == NULL)
3521 return NULL;
3523 if (st->st_data.dma_valid == true)
3524 hda_error(ad->ad_sc, "WARNING: allocm leak\n");
3526 st->st_data.dma_size = size;
3527 err = hdaudio_dma_alloc(st->st_host, &st->st_data,
3528 BUS_DMA_COHERENT | BUS_DMA_NOCACHE);
3529 if (err || st->st_data.dma_valid == false)
3530 return NULL;
3532 return DMA_KERNADDR(&st->st_data);
3535 static void
3536 hdaudio_afg_freem(void *opaque, void *addr, struct malloc_type *type)
3538 struct hdaudio_audiodev *ad = opaque;
3539 struct hdaudio_stream *st;
3541 if (addr == DMA_KERNADDR(&ad->ad_playback->st_data))
3542 st = ad->ad_playback;
3543 else if (addr == DMA_KERNADDR(&ad->ad_capture->st_data))
3544 st = ad->ad_capture;
3545 else
3546 return;
3548 hdaudio_dma_free(st->st_host, &st->st_data);
3551 static size_t
3552 hdaudio_afg_round_buffersize(void *opaque, int direction, size_t bufsize)
3554 /* Multiple of 128 */
3555 bufsize &= ~128;
3556 if (bufsize <= 0)
3557 bufsize = 128;
3558 return bufsize;
3561 static paddr_t
3562 hdaudio_afg_mappage(void *opaque, void *addr, off_t off, int prot)
3564 struct hdaudio_audiodev *ad = opaque;
3565 struct hdaudio_stream *st;
3567 if (addr == DMA_KERNADDR(&ad->ad_playback->st_data))
3568 st = ad->ad_playback;
3569 else if (addr == DMA_KERNADDR(&ad->ad_capture->st_data))
3570 st = ad->ad_capture;
3571 else
3572 return -1;
3574 if (st->st_data.dma_valid == false)
3575 return -1;
3577 return bus_dmamem_mmap(st->st_host->sc_dmat, st->st_data.dma_segs,
3578 st->st_data.dma_nsegs, off, prot, BUS_DMA_WAITOK);
3581 static int
3582 hdaudio_afg_get_props(void *opaque)
3584 struct hdaudio_audiodev *ad = opaque;
3585 int props = 0;
3587 if (ad->ad_playback)
3588 props |= AUDIO_PROP_PLAYBACK;
3589 if (ad->ad_capture)
3590 props |= AUDIO_PROP_CAPTURE;
3591 if (ad->ad_playback && ad->ad_capture) {
3592 props |= AUDIO_PROP_FULLDUPLEX;
3593 props |= AUDIO_PROP_INDEPENDENT;
3596 /* TODO: AUDIO_PROP_MMAP */
3598 return props;
3601 static int
3602 hdaudio_afg_trigger_output(void *opaque, void *start, void *end, int blksize,
3603 void (*intr)(void *), void *intrarg, const audio_params_t *param)
3605 struct hdaudio_audiodev *ad = opaque;
3606 bus_size_t dmasize;
3608 if (ad->ad_playback == NULL)
3609 return ENXIO;
3610 if (ad->ad_playback->st_data.dma_valid == false)
3611 return ENOMEM;
3613 ad->ad_playbackintr = intr;
3614 ad->ad_playbackintrarg = intrarg;
3616 dmasize = (char *)end - (char *)start;
3617 ad->ad_sc->sc_pparam = *param;
3618 hdaudio_afg_stream_connect(ad->ad_sc, AUMODE_PLAY);
3619 hdaudio_stream_start(ad->ad_playback, blksize, dmasize, param);
3621 return 0;
3624 static int
3625 hdaudio_afg_trigger_input(void *opaque, void *start, void *end, int blksize,
3626 void (*intr)(void *), void *intrarg, const audio_params_t *param)
3628 struct hdaudio_audiodev *ad = opaque;
3629 bus_size_t dmasize;
3631 if (ad->ad_capture == NULL)
3632 return ENXIO;
3633 if (ad->ad_capture->st_data.dma_valid == false)
3634 return ENOMEM;
3636 ad->ad_captureintr = intr;
3637 ad->ad_captureintrarg = intrarg;
3639 dmasize = (char *)end - (char *)start;
3640 ad->ad_sc->sc_rparam = *param;
3641 hdaudio_afg_stream_connect(ad->ad_sc, AUMODE_RECORD);
3642 hdaudio_stream_start(ad->ad_capture, blksize, dmasize, param);
3644 return 0;
3648 hdaudio_afg_widget_info(void *opaque, prop_dictionary_t request,
3649 prop_dictionary_t response)
3651 struct hdaudio_afg_softc *sc = opaque;
3652 struct hdaudio_widget *w;
3653 prop_array_t connlist;
3654 uint32_t config, wcap;
3655 uint16_t index;
3656 int nid;
3657 int i;
3659 if (prop_dictionary_get_uint16(request, "index", &index) == false)
3660 return EINVAL;
3662 nid = sc->sc_startnode + index;
3663 if (nid >= sc->sc_endnode)
3664 return EINVAL;
3666 w = hdaudio_afg_widget_lookup(sc, nid);
3667 if (w == NULL)
3668 return ENXIO;
3669 wcap = hda_get_wparam(w, PIN_CAPABILITIES);
3670 config = hdaudio_command(sc->sc_codec, w->w_nid,
3671 CORB_GET_CONFIGURATION_DEFAULT, 0);
3672 prop_dictionary_set_cstring_nocopy(response, "name", w->w_name);
3673 prop_dictionary_set_bool(response, "enable", w->w_enable);
3674 prop_dictionary_set_uint8(response, "nid", w->w_nid);
3675 prop_dictionary_set_uint8(response, "type", w->w_type);
3676 prop_dictionary_set_uint32(response, "config", config);
3677 prop_dictionary_set_uint32(response, "cap", wcap);
3678 if (w->w_nconns == 0)
3679 return 0;
3680 connlist = prop_array_create();
3681 for (i = 0; i < w->w_nconns; i++) {
3682 if (w->w_conns[i] == 0)
3683 continue;
3684 prop_array_add(connlist,
3685 prop_number_create_unsigned_integer(w->w_conns[i]));
3687 prop_dictionary_set(response, "connlist", connlist);
3688 prop_object_release(connlist);
3689 return 0;
3693 hdaudio_afg_codec_info(void *opaque, prop_dictionary_t request,
3694 prop_dictionary_t response)
3696 struct hdaudio_afg_softc *sc = opaque;
3697 prop_dictionary_set_uint16(response, "vendor-id",
3698 sc->sc_vendor);
3699 prop_dictionary_set_uint16(response, "product-id",
3700 sc->sc_product);
3701 return 0;
3704 static int
3705 hdaudio_afg_dev_ioctl(void *opaque, u_long cmd, void *addr, int flag, lwp_t *l)
3707 struct hdaudio_audiodev *ad = opaque;
3708 struct hdaudio_afg_softc *sc = ad->ad_sc;
3709 struct plistref *pref = addr;
3710 prop_dictionary_t request, response;
3711 int err;
3713 response = prop_dictionary_create();
3714 if (response == NULL)
3715 return ENOMEM;
3717 err = prop_dictionary_copyin_ioctl(pref, cmd, &request);
3718 if (err) {
3719 prop_object_release(response);
3720 return err;
3722 err = 0;
3723 switch (cmd) {
3724 case HDAUDIO_AFG_WIDGET_INFO:
3725 err = hdaudio_afg_widget_info(sc, request, response);
3726 break;
3727 case HDAUDIO_AFG_CODEC_INFO:
3728 err = hdaudio_afg_codec_info(sc, request, response);
3729 break;
3730 default:
3731 err = EINVAL;
3732 break;
3735 if (!err)
3736 err = prop_dictionary_copyout_ioctl(pref, cmd, response);
3738 if (response)
3739 prop_object_release(response);
3740 prop_object_release(request);
3741 return err;