hdac.c revision 223118
1162922Sariff/*-
2162922Sariff * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
3162922Sariff * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
4182999Smav * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
5162922Sariff * All rights reserved.
6162922Sariff *
7162922Sariff * Redistribution and use in source and binary forms, with or without
8162922Sariff * modification, are permitted provided that the following conditions
9162922Sariff * are met:
10162922Sariff * 1. Redistributions of source code must retain the above copyright
11162922Sariff *    notice, this list of conditions and the following disclaimer.
12162922Sariff * 2. Redistributions in binary form must reproduce the above copyright
13162922Sariff *    notice, this list of conditions and the following disclaimer in the
14162922Sariff *    documentation and/or other materials provided with the distribution.
15162922Sariff *
16162922Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17162922Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18162922Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19162922Sariff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20162922Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21162922Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22162922Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23162922Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24162922Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25162922Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26162922Sariff * SUCH DAMAGE.
27162922Sariff */
28162922Sariff
29162922Sariff/*
30162922Sariff * Intel High Definition Audio (Controller) driver for FreeBSD. Be advised
31162922Sariff * that this driver still in its early stage, and possible of rewrite are
32162922Sariff * pretty much guaranteed. There are supposedly several distinct parent/child
33162922Sariff * busses to make this "perfect", but as for now and for the sake of
34162922Sariff * simplicity, everything is gobble up within single source.
35162922Sariff *
36162922Sariff * List of subsys:
37162922Sariff *     1) HDA Controller support
38162922Sariff *     2) HDA Codecs support, which may include
39162922Sariff *        - HDA
40162922Sariff *        - Modem
41162922Sariff *     3) Widget parser - the real magic of why this driver works on so
42162922Sariff *        many hardwares with minimal vendor specific quirk. The original
43162922Sariff *        parser was written using Ruby and can be found at
44162922Sariff *        http://people.freebsd.org/~ariff/HDA/parser.rb . This crude
45162922Sariff *        ruby parser take the verbose dmesg dump as its input. Refer to
46162922Sariff *        http://www.microsoft.com/whdc/device/audio/default.mspx for various
47164614Sariff *        interesting documents, especially UAA (Universal Audio Architecture).
48162922Sariff *     4) Possible vendor specific support.
49162922Sariff *        (snd_hda_intel, snd_hda_ati, etc..)
50162922Sariff *
51162922Sariff * Thanks to Ahmad Ubaidah Omar @ Defenxis Sdn. Bhd. for the
52162922Sariff * Compaq V3000 with Conexant HDA.
53162922Sariff *
54162922Sariff *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55162922Sariff *    *                                                                 *
56162922Sariff *    *        This driver is a collaborative effort made by:           *
57162922Sariff *    *                                                                 *
58162922Sariff *    *          Stephane E. Potvin <sepotvin@videotron.ca>             *
59162922Sariff *    *               Andrea Bittau <a.bittau@cs.ucl.ac.uk>             *
60162922Sariff *    *               Wesley Morgan <morganw@chemikals.org>             *
61162922Sariff *    *              Daniel Eischen <deischen@FreeBSD.org>              *
62162922Sariff *    *             Maxime Guillaud <bsd-ports@mguillaud.net>           *
63162922Sariff *    *              Ariff Abdullah <ariff@FreeBSD.org>                 *
64182999Smav *    *             Alexander Motin <mav@FreeBSD.org>                   *
65162922Sariff *    *                                                                 *
66162922Sariff *    *   ....and various people from freebsd-multimedia@FreeBSD.org    *
67162922Sariff *    *                                                                 *
68162922Sariff *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
69162922Sariff */
70162922Sariff
71193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
72193640Sariff#include "opt_snd.h"
73193640Sariff#endif
74193640Sariff
75162922Sariff#include <dev/sound/pcm/sound.h>
76162922Sariff#include <dev/pci/pcireg.h>
77162922Sariff#include <dev/pci/pcivar.h>
78162922Sariff
79171141Sariff#include <sys/ctype.h>
80171141Sariff#include <sys/taskqueue.h>
81171141Sariff
82162922Sariff#include <dev/sound/pci/hda/hdac_private.h>
83162922Sariff#include <dev/sound/pci/hda/hdac_reg.h>
84162922Sariff#include <dev/sound/pci/hda/hda_reg.h>
85162922Sariff#include <dev/sound/pci/hda/hdac.h>
86162922Sariff
87162922Sariff#include "mixer_if.h"
88162922Sariff
89204351Smav#define HDA_DRV_TEST_REV	"20100226_0142"
90162922Sariff
91162922SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 223118 2011-06-15 19:53:08Z joel $");
92162922Sariff
93169277Sariff#define HDA_BOOTVERBOSE(stmt)	do {			\
94169277Sariff	if (bootverbose != 0 || snd_verbose > 3) {	\
95169277Sariff		stmt					\
96169277Sariff	}						\
97193640Sariff} while (0)
98162922Sariff
99183097Smav#define HDA_BOOTHVERBOSE(stmt)	do {			\
100183097Smav	if (snd_verbose > 3) {				\
101183097Smav		stmt					\
102183097Smav	}						\
103193640Sariff} while (0)
104183097Smav
105162965Sariff#if 1
106162922Sariff#undef HDAC_INTR_EXTRA
107162922Sariff#define HDAC_INTR_EXTRA		1
108162922Sariff#endif
109162922Sariff
110162965Sariff#define hdac_lock(sc)		snd_mtxlock((sc)->lock)
111162965Sariff#define hdac_unlock(sc)		snd_mtxunlock((sc)->lock)
112163057Sariff#define hdac_lockassert(sc)	snd_mtxassert((sc)->lock)
113163057Sariff#define hdac_lockowned(sc)	mtx_owned((sc)->lock)
114162922Sariff
115162965Sariff#define HDA_FLAG_MATCH(fl, v)	(((fl) & (v)) == (v))
116163257Sariff#define HDA_DEV_MATCH(fl, v)	((fl) == (v) || \
117163257Sariff				(fl) == 0xffffffff || \
118163257Sariff				(((fl) & 0xffff0000) == 0xffff0000 && \
119163257Sariff				((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \
120163257Sariff				(((fl) & 0x0000ffff) == 0x0000ffff && \
121163257Sariff				((fl) & 0xffff0000) == ((v) & 0xffff0000)))
122162965Sariff#define HDA_MATCH_ALL		0xffffffff
123162965Sariff#define HDAC_INVALID		0xffffffff
124162965Sariff
125169277Sariff/* Default controller / jack sense poll: 250ms */
126169277Sariff#define HDAC_POLL_INTERVAL	max(hz >> 2, 1)
127169277Sariff
128171141Sariff/*
129171141Sariff * Make room for possible 4096 playback/record channels, in 100 years to come.
130171141Sariff */
131171141Sariff#define HDAC_TRIGGER_NONE	0x00000000
132171141Sariff#define HDAC_TRIGGER_PLAY	0x00000fff
133171141Sariff#define HDAC_TRIGGER_REC	0x00fff000
134171141Sariff#define HDAC_TRIGGER_UNSOL	0x80000000
135171141Sariff
136162922Sariff#define HDA_MODEL_CONSTRUCT(vendor, model)	\
137162922Sariff		(((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff))
138162922Sariff
139162922Sariff/* Controller models */
140162922Sariff
141162922Sariff/* Intel */
142162922Sariff#define INTEL_VENDORID		0x8086
143211910Sjfv#define HDA_INTEL_CPT		HDA_MODEL_CONSTRUCT(INTEL, 0x1c20)
144218149Sjfv#define HDA_INTEL_PATSBURG	HDA_MODEL_CONSTRUCT(INTEL, 0x1d20)
145221789Sjfv#define HDA_INTEL_PPT1		HDA_MODEL_CONSTRUCT(INTEL, 0x1e20)
146162922Sariff#define HDA_INTEL_82801F	HDA_MODEL_CONSTRUCT(INTEL, 0x2668)
147171330Sariff#define HDA_INTEL_63XXESB	HDA_MODEL_CONSTRUCT(INTEL, 0x269a)
148162922Sariff#define HDA_INTEL_82801G	HDA_MODEL_CONSTRUCT(INTEL, 0x27d8)
149163136Sariff#define HDA_INTEL_82801H	HDA_MODEL_CONSTRUCT(INTEL, 0x284b)
150171330Sariff#define HDA_INTEL_82801I	HDA_MODEL_CONSTRUCT(INTEL, 0x293e)
151197017Smav#define HDA_INTEL_82801JI	HDA_MODEL_CONSTRUCT(INTEL, 0x3a3e)
152197017Smav#define HDA_INTEL_82801JD	HDA_MODEL_CONSTRUCT(INTEL, 0x3a6e)
153187020Smav#define HDA_INTEL_PCH		HDA_MODEL_CONSTRUCT(INTEL, 0x3b56)
154218149Sjfv#define HDA_INTEL_PCH2		HDA_MODEL_CONSTRUCT(INTEL, 0x3b57)
155184207Smav#define HDA_INTEL_SCH		HDA_MODEL_CONSTRUCT(INTEL, 0x811b)
156162922Sariff#define HDA_INTEL_ALL		HDA_MODEL_CONSTRUCT(INTEL, 0xffff)
157162922Sariff
158162922Sariff/* Nvidia */
159162922Sariff#define NVIDIA_VENDORID		0x10de
160162922Sariff#define HDA_NVIDIA_MCP51	HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c)
161162922Sariff#define HDA_NVIDIA_MCP55	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371)
162173817Sariff#define HDA_NVIDIA_MCP61_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4)
163173817Sariff#define HDA_NVIDIA_MCP61_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0)
164173817Sariff#define HDA_NVIDIA_MCP65_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a)
165173817Sariff#define HDA_NVIDIA_MCP65_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b)
166173817Sariff#define HDA_NVIDIA_MCP67_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x055c)
167173817Sariff#define HDA_NVIDIA_MCP67_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x055d)
168186511Smav#define HDA_NVIDIA_MCP78_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0774)
169186511Smav#define HDA_NVIDIA_MCP78_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0775)
170186511Smav#define HDA_NVIDIA_MCP78_3	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0776)
171186511Smav#define HDA_NVIDIA_MCP78_4	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0777)
172186511Smav#define HDA_NVIDIA_MCP73_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x07fc)
173186511Smav#define HDA_NVIDIA_MCP73_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x07fd)
174186511Smav#define HDA_NVIDIA_MCP79_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac0)
175186511Smav#define HDA_NVIDIA_MCP79_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac1)
176186511Smav#define HDA_NVIDIA_MCP79_3	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac2)
177186511Smav#define HDA_NVIDIA_MCP79_4	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0ac3)
178197018Smav#define HDA_NVIDIA_MCP89_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d94)
179197018Smav#define HDA_NVIDIA_MCP89_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d95)
180197018Smav#define HDA_NVIDIA_MCP89_3	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d96)
181197018Smav#define HDA_NVIDIA_MCP89_4	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0d97)
182162922Sariff#define HDA_NVIDIA_ALL		HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff)
183162922Sariff
184162922Sariff/* ATI */
185162922Sariff#define ATI_VENDORID		0x1002
186162922Sariff#define HDA_ATI_SB450		HDA_MODEL_CONSTRUCT(ATI, 0x437b)
187163136Sariff#define HDA_ATI_SB600		HDA_MODEL_CONSTRUCT(ATI, 0x4383)
188187020Smav#define HDA_ATI_RS600		HDA_MODEL_CONSTRUCT(ATI, 0x793b)
189187020Smav#define HDA_ATI_RS690		HDA_MODEL_CONSTRUCT(ATI, 0x7919)
190187020Smav#define HDA_ATI_RS780		HDA_MODEL_CONSTRUCT(ATI, 0x960f)
191187020Smav#define HDA_ATI_R600		HDA_MODEL_CONSTRUCT(ATI, 0xaa00)
192187020Smav#define HDA_ATI_RV630		HDA_MODEL_CONSTRUCT(ATI, 0xaa08)
193187020Smav#define HDA_ATI_RV610		HDA_MODEL_CONSTRUCT(ATI, 0xaa10)
194187020Smav#define HDA_ATI_RV670		HDA_MODEL_CONSTRUCT(ATI, 0xaa18)
195187020Smav#define HDA_ATI_RV635		HDA_MODEL_CONSTRUCT(ATI, 0xaa20)
196187020Smav#define HDA_ATI_RV620		HDA_MODEL_CONSTRUCT(ATI, 0xaa28)
197187020Smav#define HDA_ATI_RV770		HDA_MODEL_CONSTRUCT(ATI, 0xaa30)
198187020Smav#define HDA_ATI_RV730		HDA_MODEL_CONSTRUCT(ATI, 0xaa38)
199187020Smav#define HDA_ATI_RV710		HDA_MODEL_CONSTRUCT(ATI, 0xaa40)
200187020Smav#define HDA_ATI_RV740		HDA_MODEL_CONSTRUCT(ATI, 0xaa48)
201162922Sariff#define HDA_ATI_ALL		HDA_MODEL_CONSTRUCT(ATI, 0xffff)
202162922Sariff
203216766Syongari/* RDC */
204216766Syongari#define RDC_VENDORID		0x17f3
205216766Syongari#define HDA_RDC_M3010		HDA_MODEL_CONSTRUCT(RDC, 0x3010)
206216766Syongari
207163136Sariff/* VIA */
208163136Sariff#define VIA_VENDORID		0x1106
209163136Sariff#define HDA_VIA_VT82XX		HDA_MODEL_CONSTRUCT(VIA, 0x3288)
210163136Sariff#define HDA_VIA_ALL		HDA_MODEL_CONSTRUCT(VIA, 0xffff)
211163136Sariff
212163136Sariff/* SiS */
213163136Sariff#define SIS_VENDORID		0x1039
214163136Sariff#define HDA_SIS_966		HDA_MODEL_CONSTRUCT(SIS, 0x7502)
215163136Sariff#define HDA_SIS_ALL		HDA_MODEL_CONSTRUCT(SIS, 0xffff)
216163136Sariff
217186301Smav/* ULI */
218186301Smav#define ULI_VENDORID		0x10b9
219186301Smav#define HDA_ULI_M5461		HDA_MODEL_CONSTRUCT(ULI, 0x5461)
220186301Smav#define HDA_ULI_ALL		HDA_MODEL_CONSTRUCT(ULI, 0xffff)
221186301Smav
222162922Sariff/* OEM/subvendors */
223162922Sariff
224165466Sariff/* Intel */
225165466Sariff#define INTEL_D101GGC_SUBVENDOR	HDA_MODEL_CONSTRUCT(INTEL, 0xd600)
226165466Sariff
227162922Sariff/* HP/Compaq */
228162922Sariff#define HP_VENDORID		0x103c
229162922Sariff#define HP_V3000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b5)
230162922Sariff#define HP_NX7400_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a2)
231162922Sariff#define HP_NX6310_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30aa)
232165281Sariff#define HP_NX6325_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b0)
233166294Sariff#define HP_XW4300_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3013)
234169277Sariff#define HP_3010_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3010)
235169277Sariff#define HP_DV5000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a5)
236174579Sariff#define HP_DC7700S_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x2801)
237172811Sariff#define HP_DC7700_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x2802)
238162922Sariff#define HP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0xffff)
239165281Sariff/* What is wrong with XN 2563 anyway? (Got the picture ?) */
240165281Sariff#define HP_NX6325_SUBVENDORX	0x103c30b0
241162922Sariff
242162922Sariff/* Dell */
243162922Sariff#define DELL_VENDORID		0x1028
244180532Sdelphij#define DELL_D630_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01f9)
245162922Sariff#define DELL_D820_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01cc)
246184483Smav#define DELL_V1400_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x0227)
247178155Sariff#define DELL_V1500_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x0228)
248162922Sariff#define DELL_I1300_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01c9)
249169277Sariff#define DELL_XPSM1210_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01d7)
250169277Sariff#define DELL_OPLX745_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01da)
251162922Sariff#define DELL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0xffff)
252162922Sariff
253162922Sariff/* Clevo */
254162922Sariff#define CLEVO_VENDORID		0x1558
255162922Sariff#define CLEVO_D900T_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0x0900)
256162922Sariff#define CLEVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0xffff)
257162922Sariff
258162922Sariff/* Acer */
259162922Sariff#define ACER_VENDORID		0x1025
260165992Sariff#define ACER_A5050_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x010f)
261173817Sariff#define ACER_A4520_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0127)
262174182Sariff#define ACER_A4710_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x012f)
263182854Sjoel#define ACER_A4715_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0133)
264169277Sariff#define ACER_3681WXM_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0110)
265182999Smav#define ACER_T6292_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x011b)
266189879Smav#define ACER_T5320_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x011f)
267162922Sariff#define ACER_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0xffff)
268162922Sariff
269162965Sariff/* Asus */
270162965Sariff#define ASUS_VENDORID		0x1043
271178155Sariff#define ASUS_A8X_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1153)
272163276Sariff#define ASUS_U5F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
273178155Sariff#define ASUS_W6F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
274165281Sariff#define ASUS_A7M_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1323)
275178155Sariff#define ASUS_F3JC_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1338)
276178155Sariff#define ASUS_G2K_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1339)
277167623Sariff#define ASUS_A7T_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x13c2)
278169277Sariff#define ASUS_W2J_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1971)
279178155Sariff#define ASUS_M5200_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
280190630Smav#define ASUS_P5PL2_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x817f)
281178155Sariff#define ASUS_P1AH2_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
282178155Sariff#define ASUS_M2NPVMX_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
283170518Sariff#define ASUS_M2V_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81e7)
284178155Sariff#define ASUS_P5BWD_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81ec)
285169277Sariff#define ASUS_M2N_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x8234)
286171141Sariff#define ASUS_A8NVMCSM_SUBVENDOR	HDA_MODEL_CONSTRUCT(NVIDIA, 0xcb84)
287162965Sariff#define ASUS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
288162922Sariff
289163257Sariff/* IBM / Lenovo */
290163257Sariff#define IBM_VENDORID		0x1014
291163257Sariff#define IBM_M52_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0x02f6)
292163257Sariff#define IBM_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0xffff)
293162965Sariff
294164614Sariff/* Lenovo */
295164657Sariff#define LENOVO_VENDORID		0x17aa
296164657Sariff#define LENOVO_3KN100_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x2066)
297182854Sjoel#define LENOVO_3KN200_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x384e)
298172811Sariff#define LENOVO_TCA55_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x1015)
299164657Sariff#define LENOVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0xffff)
300163257Sariff
301164657Sariff/* Samsung */
302164657Sariff#define SAMSUNG_VENDORID	0x144d
303164657Sariff#define SAMSUNG_Q1_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027)
304164657Sariff#define SAMSUNG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff)
305164614Sariff
306164750Sariff/* Medion ? */
307164750Sariff#define MEDION_VENDORID			0x161f
308164750Sariff#define MEDION_MD95257_SUBVENDOR	HDA_MODEL_CONSTRUCT(MEDION, 0x203d)
309164750Sariff#define MEDION_ALL_SUBVENDOR		HDA_MODEL_CONSTRUCT(MEDION, 0xffff)
310164750Sariff
311173817Sariff/* Apple Computer Inc. */
312173817Sariff#define APPLE_VENDORID		0x106b
313173817Sariff#define APPLE_MB3_SUBVENDOR	HDA_MODEL_CONSTRUCT(APPLE, 0x00a1)
314173817Sariff
315182999Smav/* Sony */
316182999Smav#define SONY_VENDORID		0x104d
317182999Smav#define SONY_S5_SUBVENDOR	HDA_MODEL_CONSTRUCT(SONY, 0x81cc)
318182999Smav#define SONY_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SONY, 0xffff)
319182999Smav
320164828Sariff/*
321164828Sariff * Apple Intel MacXXXX seems using Sigmatel codec/vendor id
322164828Sariff * instead of their own, which is beyond my comprehension
323164828Sariff * (see HDA_CODEC_STAC9221 below).
324164828Sariff */
325164828Sariff#define APPLE_INTEL_MAC		0x76808384
326199846Smav#define APPLE_MACBOOKPRO55	0xcb7910de
327164828Sariff
328165281Sariff/* LG Electronics */
329165281Sariff#define LG_VENDORID		0x1854
330165281Sariff#define LG_LW20_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0x0018)
331165281Sariff#define LG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0xffff)
332165281Sariff
333165351Sariff/* Fujitsu Siemens */
334165351Sariff#define FS_VENDORID		0x1734
335165351Sariff#define FS_PA1510_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10b8)
336172811Sariff#define FS_SI1848_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10cd)
337165351Sariff#define FS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0xffff)
338165351Sariff
339172811Sariff/* Fujitsu Limited */
340172811Sariff#define FL_VENDORID		0x10cf
341172811Sariff#define FL_S7020D_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x1326)
342182854Sjoel#define FL_U1010_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x142d)
343172811Sariff#define FL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0xffff)
344172811Sariff
345165770Sariff/* Toshiba */
346165770Sariff#define TOSHIBA_VENDORID	0x1179
347165770Sariff#define TOSHIBA_U200_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001)
348173817Sariff#define TOSHIBA_A135_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xff01)
349165770Sariff#define TOSHIBA_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff)
350165770Sariff
351165992Sariff/* Micro-Star International (MSI) */
352165992Sariff#define MSI_VENDORID		0x1462
353165992Sariff#define MSI_MS1034_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x0349)
354172811Sariff#define MSI_MS034A_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x034a)
355165992Sariff#define MSI_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0xffff)
356165992Sariff
357172811Sariff/* Giga-Byte Technology */
358172811Sariff#define GB_VENDORID		0x1458
359172811Sariff#define GB_G33S2H_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xa022)
360172811Sariff#define GP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xffff)
361172811Sariff
362169277Sariff/* Uniwill ? */
363169277Sariff#define UNIWILL_VENDORID	0x1584
364169277Sariff#define UNIWILL_9075_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075)
365170944Sariff#define UNIWILL_9080_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9080)
366169277Sariff
367169277Sariff
368162922Sariff/* Misc constants.. */
369182999Smav#define HDA_AMP_VOL_DEFAULT	(-1)
370162922Sariff#define HDA_AMP_MUTE_DEFAULT	(0xffffffff)
371162922Sariff#define HDA_AMP_MUTE_NONE	(0)
372162922Sariff#define HDA_AMP_MUTE_LEFT	(1 << 0)
373162922Sariff#define HDA_AMP_MUTE_RIGHT	(1 << 1)
374162922Sariff#define HDA_AMP_MUTE_ALL	(HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT)
375162922Sariff
376162922Sariff#define HDA_AMP_LEFT_MUTED(v)	((v) & (HDA_AMP_MUTE_LEFT))
377162922Sariff#define HDA_AMP_RIGHT_MUTED(v)	(((v) & HDA_AMP_MUTE_RIGHT) >> 1)
378162922Sariff
379182999Smav#define HDA_ADC_MONITOR		(1 << 0)
380162922Sariff
381182999Smav#define HDA_CTL_OUT		1
382182999Smav#define HDA_CTL_IN		2
383169277Sariff
384169277Sariff#define HDA_GPIO_MAX		8
385169277Sariff/* 0 - 7 = GPIO , 8 = Flush */
386163057Sariff#define HDA_QUIRK_GPIO0		(1 << 0)
387163057Sariff#define HDA_QUIRK_GPIO1		(1 << 1)
388163057Sariff#define HDA_QUIRK_GPIO2		(1 << 2)
389169277Sariff#define HDA_QUIRK_GPIO3		(1 << 3)
390169277Sariff#define HDA_QUIRK_GPIO4		(1 << 4)
391169277Sariff#define HDA_QUIRK_GPIO5		(1 << 5)
392169277Sariff#define HDA_QUIRK_GPIO6		(1 << 6)
393169277Sariff#define HDA_QUIRK_GPIO7		(1 << 7)
394169277Sariff#define HDA_QUIRK_GPIOFLUSH	(1 << 8)
395162922Sariff
396169277Sariff/* 9 - 25 = anything else */
397169277Sariff#define HDA_QUIRK_SOFTPCMVOL	(1 << 9)
398169277Sariff#define HDA_QUIRK_FIXEDRATE	(1 << 10)
399169277Sariff#define HDA_QUIRK_FORCESTEREO	(1 << 11)
400169277Sariff#define HDA_QUIRK_EAPDINV	(1 << 12)
401169277Sariff#define HDA_QUIRK_DMAPOS	(1 << 13)
402182999Smav#define HDA_QUIRK_SENSEINV	(1 << 14)
403169277Sariff
404169277Sariff/* 26 - 31 = vrefs */
405169277Sariff#define HDA_QUIRK_IVREF50	(1 << 26)
406169277Sariff#define HDA_QUIRK_IVREF80	(1 << 27)
407169277Sariff#define HDA_QUIRK_IVREF100	(1 << 28)
408169277Sariff#define HDA_QUIRK_OVREF50	(1 << 29)
409169277Sariff#define HDA_QUIRK_OVREF80	(1 << 30)
410169277Sariff#define HDA_QUIRK_OVREF100	(1 << 31)
411169277Sariff
412169277Sariff#define HDA_QUIRK_IVREF		(HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 | \
413169277Sariff							HDA_QUIRK_IVREF100)
414169277Sariff#define HDA_QUIRK_OVREF		(HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 | \
415169277Sariff							HDA_QUIRK_OVREF100)
416169277Sariff#define HDA_QUIRK_VREF		(HDA_QUIRK_IVREF | HDA_QUIRK_OVREF)
417169277Sariff
418171141Sariff#if __FreeBSD_version < 600000
419171141Sariff#define taskqueue_drain(...)
420171141Sariff#endif
421171141Sariff
422163057Sariffstatic const struct {
423163057Sariff	char *key;
424163057Sariff	uint32_t value;
425163057Sariff} hdac_quirks_tab[] = {
426163057Sariff	{ "gpio0", HDA_QUIRK_GPIO0 },
427163057Sariff	{ "gpio1", HDA_QUIRK_GPIO1 },
428163057Sariff	{ "gpio2", HDA_QUIRK_GPIO2 },
429169277Sariff	{ "gpio3", HDA_QUIRK_GPIO3 },
430169277Sariff	{ "gpio4", HDA_QUIRK_GPIO4 },
431169277Sariff	{ "gpio5", HDA_QUIRK_GPIO5 },
432169277Sariff	{ "gpio6", HDA_QUIRK_GPIO6 },
433169277Sariff	{ "gpio7", HDA_QUIRK_GPIO7 },
434165039Sariff	{ "gpioflush", HDA_QUIRK_GPIOFLUSH },
435163057Sariff	{ "softpcmvol", HDA_QUIRK_SOFTPCMVOL },
436163057Sariff	{ "fixedrate", HDA_QUIRK_FIXEDRATE },
437163136Sariff	{ "forcestereo", HDA_QUIRK_FORCESTEREO },
438163276Sariff	{ "eapdinv", HDA_QUIRK_EAPDINV },
439169277Sariff	{ "dmapos", HDA_QUIRK_DMAPOS },
440182999Smav	{ "senseinv", HDA_QUIRK_SENSEINV },
441169277Sariff	{ "ivref50", HDA_QUIRK_IVREF50 },
442169277Sariff	{ "ivref80", HDA_QUIRK_IVREF80 },
443169277Sariff	{ "ivref100", HDA_QUIRK_IVREF100 },
444169277Sariff	{ "ovref50", HDA_QUIRK_OVREF50 },
445169277Sariff	{ "ovref80", HDA_QUIRK_OVREF80 },
446169277Sariff	{ "ovref100", HDA_QUIRK_OVREF100 },
447169277Sariff	{ "ivref", HDA_QUIRK_IVREF },
448169277Sariff	{ "ovref", HDA_QUIRK_OVREF },
449165069Sariff	{ "vref", HDA_QUIRK_VREF },
450163057Sariff};
451163057Sariff#define HDAC_QUIRKS_TAB_LEN	\
452163057Sariff		(sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0]))
453163057Sariff
454162922Sariff#define HDA_BDL_MIN	2
455162922Sariff#define HDA_BDL_MAX	256
456162922Sariff#define HDA_BDL_DEFAULT	HDA_BDL_MIN
457162922Sariff
458169277Sariff#define HDA_BLK_MIN	HDAC_DMA_ALIGNMENT
459167648Sariff#define HDA_BLK_ALIGN	(~(HDA_BLK_MIN - 1))
460167648Sariff
461162922Sariff#define HDA_BUFSZ_MIN		4096
462162922Sariff#define HDA_BUFSZ_MAX		65536
463162922Sariff#define HDA_BUFSZ_DEFAULT	16384
464162922Sariff
465162922Sariff#define HDA_PARSE_MAXDEPTH	10
466162922Sariff
467169277Sariff#define HDAC_UNSOLTAG_EVENT_HP		0x00
468162922Sariff
469165239SariffMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
470162922Sariff
471182999Smavconst char *HDA_COLORS[16] = {"Unknown", "Black", "Grey", "Blue", "Green", "Red",
472182999Smav    "Orange", "Yellow", "Purple", "Pink", "Res.A", "Res.B", "Res.C", "Res.D",
473182999Smav    "White", "Other"};
474162922Sariff
475182999Smavconst char *HDA_DEVS[16] = {"Line-out", "Speaker", "Headphones", "CD",
476182999Smav    "SPDIF-out", "Digital-out", "Modem-line", "Modem-handset", "Line-in",
477182999Smav    "AUX", "Mic", "Telephony", "SPDIF-in", "Digital-in", "Res.E", "Other"};
478182999Smav
479182999Smavconst char *HDA_CONNS[4] = {"Jack", "None", "Fixed", "Both"};
480182999Smav
481162922Sariff/* Default */
482162922Sariffstatic uint32_t hdac_fmt[] = {
483193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
484162922Sariff	0
485162922Sariff};
486162922Sariff
487162922Sariffstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0};
488162922Sariff
489189086Smav#define HDAC_NO_MSI	1
490194861Smav#define HDAC_NO_64BIT	2
491189086Smav
492162922Sariffstatic const struct {
493162922Sariff	uint32_t	model;
494162922Sariff	char		*desc;
495189086Smav	char		flags;
496162922Sariff} hdac_devices[] = {
497211910Sjfv	{ HDA_INTEL_CPT,     "Intel Cougar Point",	0 },
498218149Sjfv	{ HDA_INTEL_PATSBURG,"Intel Patsburg",  0 },
499221794Sjfv	{ HDA_INTEL_PPT1,    "Intel Panther Point",	0 },
500189086Smav	{ HDA_INTEL_82801F,  "Intel 82801F",	0 },
501189086Smav	{ HDA_INTEL_63XXESB, "Intel 631x/632xESB",	0 },
502189086Smav	{ HDA_INTEL_82801G,  "Intel 82801G",	0 },
503189086Smav	{ HDA_INTEL_82801H,  "Intel 82801H",	0 },
504189086Smav	{ HDA_INTEL_82801I,  "Intel 82801I",	0 },
505197017Smav	{ HDA_INTEL_82801JI, "Intel 82801JI",	0 },
506197017Smav	{ HDA_INTEL_82801JD, "Intel 82801JD",	0 },
507218149Sjfv	{ HDA_INTEL_PCH,     "Intel 5 Series/3400 Series",	0 },
508218149Sjfv	{ HDA_INTEL_PCH2,    "Intel 5 Series/3400 Series",	0 },
509189086Smav	{ HDA_INTEL_SCH,     "Intel SCH",	0 },
510189086Smav	{ HDA_NVIDIA_MCP51,  "NVidia MCP51",	HDAC_NO_MSI },
511195690Smav	{ HDA_NVIDIA_MCP55,  "NVidia MCP55",	HDAC_NO_MSI },
512189086Smav	{ HDA_NVIDIA_MCP61_1, "NVidia MCP61",	0 },
513189086Smav	{ HDA_NVIDIA_MCP61_2, "NVidia MCP61",	0 },
514189086Smav	{ HDA_NVIDIA_MCP65_1, "NVidia MCP65",	0 },
515189086Smav	{ HDA_NVIDIA_MCP65_2, "NVidia MCP65",	0 },
516189086Smav	{ HDA_NVIDIA_MCP67_1, "NVidia MCP67",	0 },
517189086Smav	{ HDA_NVIDIA_MCP67_2, "NVidia MCP67",	0 },
518189086Smav	{ HDA_NVIDIA_MCP73_1, "NVidia MCP73",	0 },
519189086Smav	{ HDA_NVIDIA_MCP73_2, "NVidia MCP73",	0 },
520194861Smav	{ HDA_NVIDIA_MCP78_1, "NVidia MCP78",	HDAC_NO_64BIT },
521194861Smav	{ HDA_NVIDIA_MCP78_2, "NVidia MCP78",	HDAC_NO_64BIT },
522194861Smav	{ HDA_NVIDIA_MCP78_3, "NVidia MCP78",	HDAC_NO_64BIT },
523194861Smav	{ HDA_NVIDIA_MCP78_4, "NVidia MCP78",	HDAC_NO_64BIT },
524189086Smav	{ HDA_NVIDIA_MCP79_1, "NVidia MCP79",	0 },
525189086Smav	{ HDA_NVIDIA_MCP79_2, "NVidia MCP79",	0 },
526189086Smav	{ HDA_NVIDIA_MCP79_3, "NVidia MCP79",	0 },
527189086Smav	{ HDA_NVIDIA_MCP79_4, "NVidia MCP79",	0 },
528197018Smav	{ HDA_NVIDIA_MCP89_1, "NVidia MCP89",	0 },
529197018Smav	{ HDA_NVIDIA_MCP89_2, "NVidia MCP89",	0 },
530197018Smav	{ HDA_NVIDIA_MCP89_3, "NVidia MCP89",	0 },
531197018Smav	{ HDA_NVIDIA_MCP89_4, "NVidia MCP89",	0 },
532189086Smav	{ HDA_ATI_SB450,     "ATI SB450",	0 },
533189086Smav	{ HDA_ATI_SB600,     "ATI SB600",	0 },
534189086Smav	{ HDA_ATI_RS600,     "ATI RS600",	0 },
535189086Smav	{ HDA_ATI_RS690,     "ATI RS690",	0 },
536189086Smav	{ HDA_ATI_RS780,     "ATI RS780",	0 },
537189086Smav	{ HDA_ATI_R600,      "ATI R600",	0 },
538189086Smav	{ HDA_ATI_RV610,     "ATI RV610",	0 },
539189086Smav	{ HDA_ATI_RV620,     "ATI RV620",	0 },
540189086Smav	{ HDA_ATI_RV630,     "ATI RV630",	0 },
541189086Smav	{ HDA_ATI_RV635,     "ATI RV635",	0 },
542189086Smav	{ HDA_ATI_RV710,     "ATI RV710",	0 },
543189086Smav	{ HDA_ATI_RV730,     "ATI RV730",	0 },
544189086Smav	{ HDA_ATI_RV740,     "ATI RV740",	0 },
545189086Smav	{ HDA_ATI_RV770,     "ATI RV770",	0 },
546216766Syongari	{ HDA_RDC_M3010,     "RDC M3010",	0 },
547189086Smav	{ HDA_VIA_VT82XX,    "VIA VT8251/8237A",0 },
548189086Smav	{ HDA_SIS_966,       "SiS 966",		0 },
549189086Smav	{ HDA_ULI_M5461,     "ULI M5461",	0 },
550162922Sariff	/* Unknown */
551162922Sariff	{ HDA_INTEL_ALL,  "Intel (Unknown)"  },
552162922Sariff	{ HDA_NVIDIA_ALL, "NVidia (Unknown)" },
553162922Sariff	{ HDA_ATI_ALL,    "ATI (Unknown)"    },
554163136Sariff	{ HDA_VIA_ALL,    "VIA (Unknown)"    },
555163136Sariff	{ HDA_SIS_ALL,    "SiS (Unknown)"    },
556186301Smav	{ HDA_ULI_ALL,    "ULI (Unknown)"    },
557162922Sariff};
558162922Sariff#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0]))
559162922Sariff
560162922Sariffstatic const struct {
561169277Sariff	uint16_t vendor;
562169277Sariff	uint8_t reg;
563169277Sariff	uint8_t mask;
564169277Sariff	uint8_t enable;
565169277Sariff} hdac_pcie_snoop[] = {
566169277Sariff	{  INTEL_VENDORID, 0x00, 0x00, 0x00 },
567169277Sariff	{    ATI_VENDORID, 0x42, 0xf8, 0x02 },
568169277Sariff	{ NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f },
569169277Sariff};
570169277Sariff#define HDAC_PCIESNOOP_LEN	\
571169277Sariff			(sizeof(hdac_pcie_snoop) / sizeof(hdac_pcie_snoop[0]))
572169277Sariff
573169277Sariffstatic const struct {
574162922Sariff	uint32_t	rate;
575162922Sariff	int		valid;
576162922Sariff	uint16_t	base;
577162922Sariff	uint16_t	mul;
578162922Sariff	uint16_t	div;
579162922Sariff} hda_rate_tab[] = {
580162922Sariff	{   8000, 1, 0x0000, 0x0000, 0x0500 },	/* (48000 * 1) / 6 */
581162922Sariff	{   9600, 0, 0x0000, 0x0000, 0x0400 },	/* (48000 * 1) / 5 */
582162922Sariff	{  12000, 0, 0x0000, 0x0000, 0x0300 },	/* (48000 * 1) / 4 */
583162922Sariff	{  16000, 1, 0x0000, 0x0000, 0x0200 },	/* (48000 * 1) / 3 */
584162922Sariff	{  18000, 0, 0x0000, 0x1000, 0x0700 },	/* (48000 * 3) / 8 */
585162922Sariff	{  19200, 0, 0x0000, 0x0800, 0x0400 },	/* (48000 * 2) / 5 */
586162922Sariff	{  24000, 0, 0x0000, 0x0000, 0x0100 },	/* (48000 * 1) / 2 */
587162922Sariff	{  28800, 0, 0x0000, 0x1000, 0x0400 },	/* (48000 * 3) / 5 */
588162922Sariff	{  32000, 1, 0x0000, 0x0800, 0x0200 },	/* (48000 * 2) / 3 */
589162922Sariff	{  36000, 0, 0x0000, 0x1000, 0x0300 },	/* (48000 * 3) / 4 */
590162922Sariff	{  38400, 0, 0x0000, 0x1800, 0x0400 },	/* (48000 * 4) / 5 */
591162922Sariff	{  48000, 1, 0x0000, 0x0000, 0x0000 },	/* (48000 * 1) / 1 */
592162922Sariff	{  64000, 0, 0x0000, 0x1800, 0x0200 },	/* (48000 * 4) / 3 */
593162922Sariff	{  72000, 0, 0x0000, 0x1000, 0x0100 },	/* (48000 * 3) / 2 */
594162922Sariff	{  96000, 1, 0x0000, 0x0800, 0x0000 },	/* (48000 * 2) / 1 */
595162922Sariff	{ 144000, 0, 0x0000, 0x1000, 0x0000 },	/* (48000 * 3) / 1 */
596162922Sariff	{ 192000, 1, 0x0000, 0x1800, 0x0000 },	/* (48000 * 4) / 1 */
597162922Sariff	{   8820, 0, 0x4000, 0x0000, 0x0400 },	/* (44100 * 1) / 5 */
598162922Sariff	{  11025, 1, 0x4000, 0x0000, 0x0300 },	/* (44100 * 1) / 4 */
599162922Sariff	{  12600, 0, 0x4000, 0x0800, 0x0600 },	/* (44100 * 2) / 7 */
600162922Sariff	{  14700, 0, 0x4000, 0x0000, 0x0200 },	/* (44100 * 1) / 3 */
601162922Sariff	{  17640, 0, 0x4000, 0x0800, 0x0400 },	/* (44100 * 2) / 5 */
602162922Sariff	{  18900, 0, 0x4000, 0x1000, 0x0600 },	/* (44100 * 3) / 7 */
603162922Sariff	{  22050, 1, 0x4000, 0x0000, 0x0100 },	/* (44100 * 1) / 2 */
604162922Sariff	{  25200, 0, 0x4000, 0x1800, 0x0600 },	/* (44100 * 4) / 7 */
605162922Sariff	{  26460, 0, 0x4000, 0x1000, 0x0400 },	/* (44100 * 3) / 5 */
606162922Sariff	{  29400, 0, 0x4000, 0x0800, 0x0200 },	/* (44100 * 2) / 3 */
607162922Sariff	{  33075, 0, 0x4000, 0x1000, 0x0300 },	/* (44100 * 3) / 4 */
608162922Sariff	{  35280, 0, 0x4000, 0x1800, 0x0400 },	/* (44100 * 4) / 5 */
609162922Sariff	{  44100, 1, 0x4000, 0x0000, 0x0000 },	/* (44100 * 1) / 1 */
610162922Sariff	{  58800, 0, 0x4000, 0x1800, 0x0200 },	/* (44100 * 4) / 3 */
611162922Sariff	{  66150, 0, 0x4000, 0x1000, 0x0100 },	/* (44100 * 3) / 2 */
612162922Sariff	{  88200, 1, 0x4000, 0x0800, 0x0000 },	/* (44100 * 2) / 1 */
613162922Sariff	{ 132300, 0, 0x4000, 0x1000, 0x0000 },	/* (44100 * 3) / 1 */
614162922Sariff	{ 176400, 1, 0x4000, 0x1800, 0x0000 },	/* (44100 * 4) / 1 */
615162922Sariff};
616162922Sariff#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
617162922Sariff
618162922Sariff/* All codecs you can eat... */
619162922Sariff#define HDA_CODEC_CONSTRUCT(vendor, id) \
620162922Sariff		(((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff))
621162922Sariff
622199846Smav/* Cirrus Logic */
623199846Smav#define CIRRUSLOGIC_VENDORID	0x1013
624199846Smav#define HDA_CODEC_CS4206	HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0x4206)
625199846Smav#define HDA_CODEC_CS4207	HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0x4207)
626200375Smav#define HDA_CODEC_CSXXXX	HDA_CODEC_CONSTRUCT(CIRRUSLOGIC, 0xffff)
627199846Smav
628162922Sariff/* Realtek */
629162922Sariff#define REALTEK_VENDORID	0x10ec
630162922Sariff#define HDA_CODEC_ALC260	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
631169277Sariff#define HDA_CODEC_ALC262	HDA_CODEC_CONSTRUCT(REALTEK, 0x0262)
632183024Smav#define HDA_CODEC_ALC267	HDA_CODEC_CONSTRUCT(REALTEK, 0x0267)
633171330Sariff#define HDA_CODEC_ALC268	HDA_CODEC_CONSTRUCT(REALTEK, 0x0268)
634183024Smav#define HDA_CODEC_ALC269	HDA_CODEC_CONSTRUCT(REALTEK, 0x0269)
635205413Smav#define HDA_CODEC_ALC270	HDA_CODEC_CONSTRUCT(REALTEK, 0x0270)
636183024Smav#define HDA_CODEC_ALC272	HDA_CODEC_CONSTRUCT(REALTEK, 0x0272)
637205413Smav#define HDA_CODEC_ALC273	HDA_CODEC_CONSTRUCT(REALTEK, 0x0273)
638205413Smav#define HDA_CODEC_ALC275	HDA_CODEC_CONSTRUCT(REALTEK, 0x0275)
639170518Sariff#define HDA_CODEC_ALC660	HDA_CODEC_CONSTRUCT(REALTEK, 0x0660)
640183024Smav#define HDA_CODEC_ALC662	HDA_CODEC_CONSTRUCT(REALTEK, 0x0662)
641183025Smav#define HDA_CODEC_ALC663	HDA_CODEC_CONSTRUCT(REALTEK, 0x0663)
642205413Smav#define HDA_CODEC_ALC665	HDA_CODEC_CONSTRUCT(REALTEK, 0x0665)
643162922Sariff#define HDA_CODEC_ALC861	HDA_CODEC_CONSTRUCT(REALTEK, 0x0861)
644169277Sariff#define HDA_CODEC_ALC861VD	HDA_CODEC_CONSTRUCT(REALTEK, 0x0862)
645162922Sariff#define HDA_CODEC_ALC880	HDA_CODEC_CONSTRUCT(REALTEK, 0x0880)
646163057Sariff#define HDA_CODEC_ALC882	HDA_CODEC_CONSTRUCT(REALTEK, 0x0882)
647163057Sariff#define HDA_CODEC_ALC883	HDA_CODEC_CONSTRUCT(REALTEK, 0x0883)
648169277Sariff#define HDA_CODEC_ALC885	HDA_CODEC_CONSTRUCT(REALTEK, 0x0885)
649197640Smav#define HDA_CODEC_ALC887	HDA_CODEC_CONSTRUCT(REALTEK, 0x0887)
650165305Sariff#define HDA_CODEC_ALC888	HDA_CODEC_CONSTRUCT(REALTEK, 0x0888)
651182999Smav#define HDA_CODEC_ALC889	HDA_CODEC_CONSTRUCT(REALTEK, 0x0889)
652205413Smav#define HDA_CODEC_ALC892	HDA_CODEC_CONSTRUCT(REALTEK, 0x0892)
653162922Sariff#define HDA_CODEC_ALCXXXX	HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
654162922Sariff
655169277Sariff/* Analog Devices */
656169277Sariff#define ANALOGDEVICES_VENDORID	0x11d4
657186403Smav#define HDA_CODEC_AD1884A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x184a)
658186403Smav#define HDA_CODEC_AD1882	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1882)
659186403Smav#define HDA_CODEC_AD1883	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1883)
660186403Smav#define HDA_CODEC_AD1884	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1884)
661186403Smav#define HDA_CODEC_AD1984A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x194a)
662186403Smav#define HDA_CODEC_AD1984B	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x194b)
663169277Sariff#define HDA_CODEC_AD1981HD	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981)
664169277Sariff#define HDA_CODEC_AD1983	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983)
665174025Sariff#define HDA_CODEC_AD1984	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1984)
666169277Sariff#define HDA_CODEC_AD1986A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986)
667186403Smav#define HDA_CODEC_AD1987	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1987)
668169277Sariff#define HDA_CODEC_AD1988	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988)
669170518Sariff#define HDA_CODEC_AD1988B	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x198b)
670186403Smav#define HDA_CODEC_AD1882A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x882a)
671186403Smav#define HDA_CODEC_AD1989B	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x989b)
672169277Sariff#define HDA_CODEC_ADXXXX	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff)
673162922Sariff
674162922Sariff/* CMedia */
675162922Sariff#define CMEDIA_VENDORID		0x434d
676162922Sariff#define HDA_CODEC_CMI9880	HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980)
677162922Sariff#define HDA_CODEC_CMIXXXX	HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff)
678162922Sariff
679162922Sariff/* Sigmatel */
680162922Sariff#define SIGMATEL_VENDORID	0x8384
681182999Smav#define HDA_CODEC_STAC9230X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7612)
682182999Smav#define HDA_CODEC_STAC9230D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7613)
683182999Smav#define HDA_CODEC_STAC9229X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7614)
684182999Smav#define HDA_CODEC_STAC9229D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7615)
685182999Smav#define HDA_CODEC_STAC9228X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7616)
686182999Smav#define HDA_CODEC_STAC9228D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7617)
687182999Smav#define HDA_CODEC_STAC9227X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
688182999Smav#define HDA_CODEC_STAC9227D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7619)
689183894Smav#define HDA_CODEC_STAC9274	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7620)
690183894Smav#define HDA_CODEC_STAC9274D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7621)
691183894Smav#define HDA_CODEC_STAC9273X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7622)
692183894Smav#define HDA_CODEC_STAC9273D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7623)
693183894Smav#define HDA_CODEC_STAC9272X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7624)
694183894Smav#define HDA_CODEC_STAC9272D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7625)
695183894Smav#define HDA_CODEC_STAC9271X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7626)
696182999Smav#define HDA_CODEC_STAC9271D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
697183894Smav#define HDA_CODEC_STAC9274X5NH	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7628)
698183894Smav#define HDA_CODEC_STAC9274D5NH	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7629)
699183894Smav#define HDA_CODEC_STAC9250	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7634)
700183894Smav#define HDA_CODEC_STAC9251	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7636)
701183894Smav#define HDA_CODEC_IDT92HD700X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7638)
702183894Smav#define HDA_CODEC_IDT92HD700D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7639)
703183894Smav#define HDA_CODEC_IDT92HD206X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7645)
704183894Smav#define HDA_CODEC_IDT92HD206D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7646)
705200375Smav#define HDA_CODEC_CXD9872RDK	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7661)
706182999Smav#define HDA_CODEC_STAC9872AK	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7662)
707200375Smav#define HDA_CODEC_CXD9872AKD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7664)
708162922Sariff#define HDA_CODEC_STAC9221	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
709182999Smav#define HDA_CODEC_STAC922XD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
710183894Smav#define HDA_CODEC_STAC9221_A2	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7682)
711162922Sariff#define HDA_CODEC_STAC9221D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
712162922Sariff#define HDA_CODEC_STAC9220	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
713183894Smav#define HDA_CODEC_STAC9200D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7691)
714183894Smav#define HDA_CODEC_IDT92HD005	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7698)
715183894Smav#define HDA_CODEC_IDT92HD005D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7699)
716183894Smav#define HDA_CODEC_STAC9205X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0)
717183894Smav#define HDA_CODEC_STAC9205D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a1)
718183894Smav#define HDA_CODEC_STAC9204X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a2)
719183894Smav#define HDA_CODEC_STAC9204D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a3)
720183894Smav#define HDA_CODEC_STAC9220_A2	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7880)
721183894Smav#define HDA_CODEC_STAC9220_A1	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7882)
722162922Sariff#define HDA_CODEC_STACXXXX	HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
723162922Sariff
724183894Smav/* IDT */
725183894Smav#define IDT_VENDORID		0x111d
726183894Smav#define HDA_CODEC_IDT92HD75BX	HDA_CODEC_CONSTRUCT(IDT, 0x7603)
727183894Smav#define HDA_CODEC_IDT92HD83C1X	HDA_CODEC_CONSTRUCT(IDT, 0x7604)
728183894Smav#define HDA_CODEC_IDT92HD81B1X	HDA_CODEC_CONSTRUCT(IDT, 0x7605)
729183894Smav#define HDA_CODEC_IDT92HD75B3	HDA_CODEC_CONSTRUCT(IDT, 0x7608)
730183894Smav#define HDA_CODEC_IDT92HD73D1	HDA_CODEC_CONSTRUCT(IDT, 0x7674)
731183894Smav#define HDA_CODEC_IDT92HD73C1	HDA_CODEC_CONSTRUCT(IDT, 0x7675)
732183894Smav#define HDA_CODEC_IDT92HD73E1	HDA_CODEC_CONSTRUCT(IDT, 0x7676)
733183894Smav#define HDA_CODEC_IDT92HD71B8	HDA_CODEC_CONSTRUCT(IDT, 0x76b0)
734183894Smav#define HDA_CODEC_IDT92HD71B7	HDA_CODEC_CONSTRUCT(IDT, 0x76b2)
735183894Smav#define HDA_CODEC_IDT92HD71B5	HDA_CODEC_CONSTRUCT(IDT, 0x76b6)
736183894Smav#define HDA_CODEC_IDT92HD83C1C	HDA_CODEC_CONSTRUCT(IDT, 0x76d4)
737183894Smav#define HDA_CODEC_IDT92HD81B1C	HDA_CODEC_CONSTRUCT(IDT, 0x76d5)
738183894Smav#define HDA_CODEC_IDTXXXX	HDA_CODEC_CONSTRUCT(IDT, 0xffff)
739183894Smav
740182999Smav/* Silicon Image */
741182999Smav#define SII_VENDORID	0x1095
742187020Smav#define HDA_CODEC_SII1390	HDA_CODEC_CONSTRUCT(SII, 0x1390)
743186146Smav#define HDA_CODEC_SII1392	HDA_CODEC_CONSTRUCT(SII, 0x1392)
744182999Smav#define HDA_CODEC_SIIXXXX	HDA_CODEC_CONSTRUCT(SII, 0xffff)
745182999Smav
746182999Smav/* Lucent/Agere */
747182999Smav#define AGERE_VENDORID	0x11c1
748182999Smav#define HDA_CODEC_AGEREXXXX	HDA_CODEC_CONSTRUCT(AGERE, 0xffff)
749182999Smav
750186430Smav/* Conexant */
751162922Sariff#define CONEXANT_VENDORID	0x14f1
752186430Smav#define HDA_CODEC_CX20549	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045)
753186430Smav#define HDA_CODEC_CX20551	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047)
754186430Smav#define HDA_CODEC_CX20561	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5051)
755200375Smav#define HDA_CODEC_CX20582	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5066)
756205413Smav#define HDA_CODEC_CX20583	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5067)
757223058Smav#define HDA_CODEC_CX20584	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5068)
758208934Smav#define HDA_CODEC_CX20585	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5069)
759223058Smav#define HDA_CODEC_CX20590	HDA_CODEC_CONSTRUCT(CONEXANT, 0x506e)
760223058Smav#define HDA_CODEC_CX20631	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5097)
761223058Smav#define HDA_CODEC_CX20632	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5098)
762223058Smav#define HDA_CODEC_CX20641	HDA_CODEC_CONSTRUCT(CONEXANT, 0x50a1)
763223058Smav#define HDA_CODEC_CX20642	HDA_CODEC_CONSTRUCT(CONEXANT, 0x50a2)
764223058Smav#define HDA_CODEC_CX20651	HDA_CODEC_CONSTRUCT(CONEXANT, 0x50ab)
765223058Smav#define HDA_CODEC_CX20652	HDA_CODEC_CONSTRUCT(CONEXANT, 0x50ac)
766223058Smav#define HDA_CODEC_CX20664	HDA_CODEC_CONSTRUCT(CONEXANT, 0x50b8)
767223058Smav#define HDA_CODEC_CX20665	HDA_CODEC_CONSTRUCT(CONEXANT, 0x50b9)
768162922Sariff#define HDA_CODEC_CXXXXX	HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff)
769162922Sariff
770169277Sariff/* VIA */
771169277Sariff#define HDA_CODEC_VT1708_8	HDA_CODEC_CONSTRUCT(VIA, 0x1708)
772169277Sariff#define HDA_CODEC_VT1708_9	HDA_CODEC_CONSTRUCT(VIA, 0x1709)
773169277Sariff#define HDA_CODEC_VT1708_A	HDA_CODEC_CONSTRUCT(VIA, 0x170a)
774169277Sariff#define HDA_CODEC_VT1708_B	HDA_CODEC_CONSTRUCT(VIA, 0x170b)
775169277Sariff#define HDA_CODEC_VT1709_0	HDA_CODEC_CONSTRUCT(VIA, 0xe710)
776169277Sariff#define HDA_CODEC_VT1709_1	HDA_CODEC_CONSTRUCT(VIA, 0xe711)
777169277Sariff#define HDA_CODEC_VT1709_2	HDA_CODEC_CONSTRUCT(VIA, 0xe712)
778169277Sariff#define HDA_CODEC_VT1709_3	HDA_CODEC_CONSTRUCT(VIA, 0xe713)
779169277Sariff#define HDA_CODEC_VT1709_4	HDA_CODEC_CONSTRUCT(VIA, 0xe714)
780169277Sariff#define HDA_CODEC_VT1709_5	HDA_CODEC_CONSTRUCT(VIA, 0xe715)
781169277Sariff#define HDA_CODEC_VT1709_6	HDA_CODEC_CONSTRUCT(VIA, 0xe716)
782169277Sariff#define HDA_CODEC_VT1709_7	HDA_CODEC_CONSTRUCT(VIA, 0xe717)
783186145Smav#define HDA_CODEC_VT1708B_0	HDA_CODEC_CONSTRUCT(VIA, 0xe720)
784186145Smav#define HDA_CODEC_VT1708B_1	HDA_CODEC_CONSTRUCT(VIA, 0xe721)
785186145Smav#define HDA_CODEC_VT1708B_2	HDA_CODEC_CONSTRUCT(VIA, 0xe722)
786186145Smav#define HDA_CODEC_VT1708B_3	HDA_CODEC_CONSTRUCT(VIA, 0xe723)
787186145Smav#define HDA_CODEC_VT1708B_4	HDA_CODEC_CONSTRUCT(VIA, 0xe724)
788186145Smav#define HDA_CODEC_VT1708B_5	HDA_CODEC_CONSTRUCT(VIA, 0xe725)
789186145Smav#define HDA_CODEC_VT1708B_6	HDA_CODEC_CONSTRUCT(VIA, 0xe726)
790186145Smav#define HDA_CODEC_VT1708B_7	HDA_CODEC_CONSTRUCT(VIA, 0xe727)
791187020Smav#define HDA_CODEC_VT1708S_0	HDA_CODEC_CONSTRUCT(VIA, 0x0397)
792187020Smav#define HDA_CODEC_VT1708S_1	HDA_CODEC_CONSTRUCT(VIA, 0x1397)
793187020Smav#define HDA_CODEC_VT1708S_2	HDA_CODEC_CONSTRUCT(VIA, 0x2397)
794187020Smav#define HDA_CODEC_VT1708S_3	HDA_CODEC_CONSTRUCT(VIA, 0x3397)
795187020Smav#define HDA_CODEC_VT1708S_4	HDA_CODEC_CONSTRUCT(VIA, 0x4397)
796187020Smav#define HDA_CODEC_VT1708S_5	HDA_CODEC_CONSTRUCT(VIA, 0x5397)
797187020Smav#define HDA_CODEC_VT1708S_6	HDA_CODEC_CONSTRUCT(VIA, 0x6397)
798187020Smav#define HDA_CODEC_VT1708S_7	HDA_CODEC_CONSTRUCT(VIA, 0x7397)
799187020Smav#define HDA_CODEC_VT1702_0	HDA_CODEC_CONSTRUCT(VIA, 0x0398)
800187020Smav#define HDA_CODEC_VT1702_1	HDA_CODEC_CONSTRUCT(VIA, 0x1398)
801187020Smav#define HDA_CODEC_VT1702_2	HDA_CODEC_CONSTRUCT(VIA, 0x2398)
802187020Smav#define HDA_CODEC_VT1702_3	HDA_CODEC_CONSTRUCT(VIA, 0x3398)
803187020Smav#define HDA_CODEC_VT1702_4	HDA_CODEC_CONSTRUCT(VIA, 0x4398)
804187020Smav#define HDA_CODEC_VT1702_5	HDA_CODEC_CONSTRUCT(VIA, 0x5398)
805187020Smav#define HDA_CODEC_VT1702_6	HDA_CODEC_CONSTRUCT(VIA, 0x6398)
806187020Smav#define HDA_CODEC_VT1702_7	HDA_CODEC_CONSTRUCT(VIA, 0x7398)
807199258Smav#define HDA_CODEC_VT1716S_0	HDA_CODEC_CONSTRUCT(VIA, 0x0433)
808199258Smav#define HDA_CODEC_VT1716S_1	HDA_CODEC_CONSTRUCT(VIA, 0xa721)
809199258Smav#define HDA_CODEC_VT1718S_0	HDA_CODEC_CONSTRUCT(VIA, 0x0428)
810199258Smav#define HDA_CODEC_VT1718S_1	HDA_CODEC_CONSTRUCT(VIA, 0x4428)
811199258Smav#define HDA_CODEC_VT1812	HDA_CODEC_CONSTRUCT(VIA, 0x0448)
812199258Smav#define HDA_CODEC_VT1818S	HDA_CODEC_CONSTRUCT(VIA, 0x0440)
813199258Smav#define HDA_CODEC_VT1828S	HDA_CODEC_CONSTRUCT(VIA, 0x4441)
814199258Smav#define HDA_CODEC_VT2002P_0	HDA_CODEC_CONSTRUCT(VIA, 0x0438)
815199258Smav#define HDA_CODEC_VT2002P_1	HDA_CODEC_CONSTRUCT(VIA, 0x4438)
816199258Smav#define HDA_CODEC_VT2020	HDA_CODEC_CONSTRUCT(VIA, 0x0441)
817169277Sariff#define HDA_CODEC_VTXXXX	HDA_CODEC_CONSTRUCT(VIA, 0xffff)
818162922Sariff
819182999Smav/* ATI */
820186146Smav#define HDA_CODEC_ATIRS600_1	HDA_CODEC_CONSTRUCT(ATI, 0x793c)
821186146Smav#define HDA_CODEC_ATIRS600_2	HDA_CODEC_CONSTRUCT(ATI, 0x7919)
822186146Smav#define HDA_CODEC_ATIRS690	HDA_CODEC_CONSTRUCT(ATI, 0x791a)
823186146Smav#define HDA_CODEC_ATIR6XX	HDA_CODEC_CONSTRUCT(ATI, 0xaa01)
824182999Smav#define HDA_CODEC_ATIXXXX	HDA_CODEC_CONSTRUCT(ATI, 0xffff)
825169277Sariff
826182999Smav/* NVIDIA */
827187020Smav#define HDA_CODEC_NVIDIAMCP78	HDA_CODEC_CONSTRUCT(NVIDIA, 0x0002)
828187445Smav#define HDA_CODEC_NVIDIAMCP78_2	HDA_CODEC_CONSTRUCT(NVIDIA, 0x0006)
829187020Smav#define HDA_CODEC_NVIDIAMCP7A	HDA_CODEC_CONSTRUCT(NVIDIA, 0x0007)
830208934Smav#define HDA_CODEC_NVIDIAGT220	HDA_CODEC_CONSTRUCT(NVIDIA, 0x000a)
831208934Smav#define HDA_CODEC_NVIDIAGT21X	HDA_CODEC_CONSTRUCT(NVIDIA, 0x000b)
832208934Smav#define HDA_CODEC_NVIDIAMCP89	HDA_CODEC_CONSTRUCT(NVIDIA, 0x000c)
833208934Smav#define HDA_CODEC_NVIDIAGT240	HDA_CODEC_CONSTRUCT(NVIDIA, 0x000d)
834187020Smav#define HDA_CODEC_NVIDIAMCP67	HDA_CODEC_CONSTRUCT(NVIDIA, 0x0067)
835187445Smav#define HDA_CODEC_NVIDIAMCP73	HDA_CODEC_CONSTRUCT(NVIDIA, 0x8001)
836182999Smav#define HDA_CODEC_NVIDIAXXXX	HDA_CODEC_CONSTRUCT(NVIDIA, 0xffff)
837182999Smav
838183894Smav/* INTEL */
839222298Smav#define HDA_CODEC_INTELIP	HDA_CODEC_CONSTRUCT(INTEL, 0x0054)
840222298Smav#define HDA_CODEC_INTELBL	HDA_CODEC_CONSTRUCT(INTEL, 0x2801)
841222298Smav#define HDA_CODEC_INTELCA	HDA_CODEC_CONSTRUCT(INTEL, 0x2802)
842222298Smav#define HDA_CODEC_INTELEL	HDA_CODEC_CONSTRUCT(INTEL, 0x2803)
843222298Smav#define HDA_CODEC_INTELIP2	HDA_CODEC_CONSTRUCT(INTEL, 0x2804)
844222298Smav#define HDA_CODEC_INTELCPT	HDA_CODEC_CONSTRUCT(INTEL, 0x2805)
845222298Smav#define HDA_CODEC_INTELCL	HDA_CODEC_CONSTRUCT(INTEL, 0x29fb)
846183894Smav#define HDA_CODEC_INTELXXXX	HDA_CODEC_CONSTRUCT(INTEL, 0xffff)
847183894Smav
848162922Sariff/* Codecs */
849162922Sariffstatic const struct {
850162922Sariff	uint32_t id;
851162922Sariff	char *name;
852162922Sariff} hdac_codecs[] = {
853199846Smav	{ HDA_CODEC_CS4206,    "Cirrus Logic CS4206" },
854199846Smav	{ HDA_CODEC_CS4207,    "Cirrus Logic CS4207" },
855162922Sariff	{ HDA_CODEC_ALC260,    "Realtek ALC260" },
856169277Sariff	{ HDA_CODEC_ALC262,    "Realtek ALC262" },
857183024Smav	{ HDA_CODEC_ALC267,    "Realtek ALC267" },
858171330Sariff	{ HDA_CODEC_ALC268,    "Realtek ALC268" },
859183024Smav	{ HDA_CODEC_ALC269,    "Realtek ALC269" },
860205413Smav	{ HDA_CODEC_ALC270,    "Realtek ALC270" },
861183024Smav	{ HDA_CODEC_ALC272,    "Realtek ALC272" },
862205413Smav	{ HDA_CODEC_ALC273,    "Realtek ALC273" },
863205413Smav	{ HDA_CODEC_ALC275,    "Realtek ALC275" },
864170518Sariff	{ HDA_CODEC_ALC660,    "Realtek ALC660" },
865183024Smav	{ HDA_CODEC_ALC662,    "Realtek ALC662" },
866183024Smav	{ HDA_CODEC_ALC663,    "Realtek ALC663" },
867205413Smav	{ HDA_CODEC_ALC665,    "Realtek ALC665" },
868162922Sariff	{ HDA_CODEC_ALC861,    "Realtek ALC861" },
869169277Sariff	{ HDA_CODEC_ALC861VD,  "Realtek ALC861-VD" },
870162922Sariff	{ HDA_CODEC_ALC880,    "Realtek ALC880" },
871162922Sariff	{ HDA_CODEC_ALC882,    "Realtek ALC882" },
872163057Sariff	{ HDA_CODEC_ALC883,    "Realtek ALC883" },
873169277Sariff	{ HDA_CODEC_ALC885,    "Realtek ALC885" },
874197640Smav	{ HDA_CODEC_ALC887,    "Realtek ALC887" },
875165305Sariff	{ HDA_CODEC_ALC888,    "Realtek ALC888" },
876182999Smav	{ HDA_CODEC_ALC889,    "Realtek ALC889" },
877205413Smav	{ HDA_CODEC_ALC892,    "Realtek ALC892" },
878186403Smav	{ HDA_CODEC_AD1882,    "Analog Devices AD1882" },
879186403Smav	{ HDA_CODEC_AD1882A,   "Analog Devices AD1882A" },
880186403Smav	{ HDA_CODEC_AD1883,    "Analog Devices AD1883" },
881186403Smav	{ HDA_CODEC_AD1884,    "Analog Devices AD1884" },
882186403Smav	{ HDA_CODEC_AD1884A,   "Analog Devices AD1884A" },
883169277Sariff	{ HDA_CODEC_AD1981HD,  "Analog Devices AD1981HD" },
884169277Sariff	{ HDA_CODEC_AD1983,    "Analog Devices AD1983" },
885174025Sariff	{ HDA_CODEC_AD1984,    "Analog Devices AD1984" },
886186403Smav	{ HDA_CODEC_AD1984A,   "Analog Devices AD1984A" },
887186403Smav	{ HDA_CODEC_AD1984B,   "Analog Devices AD1984B" },
888169277Sariff	{ HDA_CODEC_AD1986A,   "Analog Devices AD1986A" },
889186403Smav	{ HDA_CODEC_AD1987,    "Analog Devices AD1987" },
890186403Smav	{ HDA_CODEC_AD1988,    "Analog Devices AD1988A" },
891170518Sariff	{ HDA_CODEC_AD1988B,   "Analog Devices AD1988B" },
892186403Smav	{ HDA_CODEC_AD1989B,   "Analog Devices AD1989B" },
893162922Sariff	{ HDA_CODEC_CMI9880,   "CMedia CMI9880" },
894200375Smav	{ HDA_CODEC_CXD9872RDK, "Sigmatel CXD9872RD/K" },
895200375Smav	{ HDA_CODEC_CXD9872AKD, "Sigmatel CXD9872AKD" },
896183894Smav	{ HDA_CODEC_STAC9200D, "Sigmatel STAC9200D" },
897183894Smav	{ HDA_CODEC_STAC9204X, "Sigmatel STAC9204X" },
898183894Smav	{ HDA_CODEC_STAC9204D, "Sigmatel STAC9204D" },
899183894Smav	{ HDA_CODEC_STAC9205X, "Sigmatel STAC9205X" },
900183894Smav	{ HDA_CODEC_STAC9205D, "Sigmatel STAC9205D" },
901183894Smav	{ HDA_CODEC_STAC9220,  "Sigmatel STAC9220" },
902183894Smav	{ HDA_CODEC_STAC9220_A1, "Sigmatel STAC9220_A1" },
903183894Smav	{ HDA_CODEC_STAC9220_A2, "Sigmatel STAC9220_A2" },
904162922Sariff	{ HDA_CODEC_STAC9221,  "Sigmatel STAC9221" },
905183894Smav	{ HDA_CODEC_STAC9221_A2, "Sigmatel STAC9221_A2" },
906162922Sariff	{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
907162922Sariff	{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
908183894Smav	{ HDA_CODEC_STAC9227X, "Sigmatel STAC9227X" },
909183894Smav	{ HDA_CODEC_STAC9227D, "Sigmatel STAC9227D" },
910183894Smav	{ HDA_CODEC_STAC9228X, "Sigmatel STAC9228X" },
911183894Smav	{ HDA_CODEC_STAC9228D, "Sigmatel STAC9228D" },
912183894Smav	{ HDA_CODEC_STAC9229X, "Sigmatel STAC9229X" },
913183894Smav	{ HDA_CODEC_STAC9229D, "Sigmatel STAC9229D" },
914182999Smav	{ HDA_CODEC_STAC9230X, "Sigmatel STAC9230X" },
915182999Smav	{ HDA_CODEC_STAC9230D, "Sigmatel STAC9230D" },
916183894Smav	{ HDA_CODEC_STAC9250,  "Sigmatel STAC9250" },
917183894Smav	{ HDA_CODEC_STAC9251,  "Sigmatel STAC9251" },
918183894Smav	{ HDA_CODEC_STAC9271X, "Sigmatel STAC9271X" },
919166796Sariff	{ HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" },
920183894Smav	{ HDA_CODEC_STAC9272X, "Sigmatel STAC9272X" },
921183894Smav	{ HDA_CODEC_STAC9272D, "Sigmatel STAC9272D" },
922183894Smav	{ HDA_CODEC_STAC9273X, "Sigmatel STAC9273X" },
923183894Smav	{ HDA_CODEC_STAC9273D, "Sigmatel STAC9273D" },
924183894Smav	{ HDA_CODEC_STAC9274,  "Sigmatel STAC9274" },
925183894Smav	{ HDA_CODEC_STAC9274D, "Sigmatel STAC9274D" },
926183894Smav	{ HDA_CODEC_STAC9274X5NH, "Sigmatel STAC9274X5NH" },
927183894Smav	{ HDA_CODEC_STAC9274D5NH, "Sigmatel STAC9274D5NH" },
928183894Smav	{ HDA_CODEC_STAC9872AK, "Sigmatel STAC9872AK" },
929183894Smav	{ HDA_CODEC_IDT92HD005, "IDT 92HD005" },
930183894Smav	{ HDA_CODEC_IDT92HD005D, "IDT 92HD005D" },
931183894Smav	{ HDA_CODEC_IDT92HD206X, "IDT 92HD206X" },
932183894Smav	{ HDA_CODEC_IDT92HD206D, "IDT 92HD206D" },
933183894Smav	{ HDA_CODEC_IDT92HD700X, "IDT 92HD700X" },
934183894Smav	{ HDA_CODEC_IDT92HD700D, "IDT 92HD700D" },
935183894Smav	{ HDA_CODEC_IDT92HD71B5, "IDT 92HD71B5" },
936183894Smav	{ HDA_CODEC_IDT92HD71B7, "IDT 92HD71B7" },
937183894Smav	{ HDA_CODEC_IDT92HD71B8, "IDT 92HD71B8" },
938183894Smav	{ HDA_CODEC_IDT92HD73C1, "IDT 92HD73C1" },
939183894Smav	{ HDA_CODEC_IDT92HD73D1, "IDT 92HD73D1" },
940183894Smav	{ HDA_CODEC_IDT92HD73E1, "IDT 92HD73E1" },
941183894Smav	{ HDA_CODEC_IDT92HD75B3, "IDT 92HD75B3" },
942183894Smav	{ HDA_CODEC_IDT92HD75BX, "IDT 92HD75BX" },
943183894Smav	{ HDA_CODEC_IDT92HD81B1C, "IDT 92HD81B1C" },
944183894Smav	{ HDA_CODEC_IDT92HD81B1X, "IDT 92HD81B1X" },
945183894Smav	{ HDA_CODEC_IDT92HD83C1C, "IDT 92HD83C1C" },
946183894Smav	{ HDA_CODEC_IDT92HD83C1X, "IDT 92HD83C1X" },
947186430Smav	{ HDA_CODEC_CX20549,   "Conexant CX20549 (Venice)" },
948186430Smav	{ HDA_CODEC_CX20551,   "Conexant CX20551 (Waikiki)" },
949186430Smav	{ HDA_CODEC_CX20561,   "Conexant CX20561 (Hermosa)" },
950200375Smav	{ HDA_CODEC_CX20582,   "Conexant CX20582 (Pebble)" },
951205413Smav	{ HDA_CODEC_CX20583,   "Conexant CX20583 (Pebble HSF)" },
952223058Smav	{ HDA_CODEC_CX20584,   "Conexant CX20584" },
953208934Smav	{ HDA_CODEC_CX20585,   "Conexant CX20585" },
954223058Smav	{ HDA_CODEC_CX20590,   "Conexant CX20590" },
955223058Smav	{ HDA_CODEC_CX20631,   "Conexant CX20631" },
956223058Smav	{ HDA_CODEC_CX20632,   "Conexant CX20632" },
957223058Smav	{ HDA_CODEC_CX20641,   "Conexant CX20641" },
958223058Smav	{ HDA_CODEC_CX20642,   "Conexant CX20642" },
959223058Smav	{ HDA_CODEC_CX20651,   "Conexant CX20651" },
960223058Smav	{ HDA_CODEC_CX20652,   "Conexant CX20652" },
961223058Smav	{ HDA_CODEC_CX20664,   "Conexant CX20664" },
962223058Smav	{ HDA_CODEC_CX20665,   "Conexant CX20665" },
963169277Sariff	{ HDA_CODEC_VT1708_8,  "VIA VT1708_8" },
964169277Sariff	{ HDA_CODEC_VT1708_9,  "VIA VT1708_9" },
965169277Sariff	{ HDA_CODEC_VT1708_A,  "VIA VT1708_A" },
966169277Sariff	{ HDA_CODEC_VT1708_B,  "VIA VT1708_B" },
967169277Sariff	{ HDA_CODEC_VT1709_0,  "VIA VT1709_0" },
968169277Sariff	{ HDA_CODEC_VT1709_1,  "VIA VT1709_1" },
969169277Sariff	{ HDA_CODEC_VT1709_2,  "VIA VT1709_2" },
970169277Sariff	{ HDA_CODEC_VT1709_3,  "VIA VT1709_3" },
971169277Sariff	{ HDA_CODEC_VT1709_4,  "VIA VT1709_4" },
972169277Sariff	{ HDA_CODEC_VT1709_5,  "VIA VT1709_5" },
973169277Sariff	{ HDA_CODEC_VT1709_6,  "VIA VT1709_6" },
974169277Sariff	{ HDA_CODEC_VT1709_7,  "VIA VT1709_7" },
975186145Smav	{ HDA_CODEC_VT1708B_0, "VIA VT1708B_0" },
976186145Smav	{ HDA_CODEC_VT1708B_1, "VIA VT1708B_1" },
977186145Smav	{ HDA_CODEC_VT1708B_2, "VIA VT1708B_2" },
978186145Smav	{ HDA_CODEC_VT1708B_3, "VIA VT1708B_3" },
979186145Smav	{ HDA_CODEC_VT1708B_4, "VIA VT1708B_4" },
980186145Smav	{ HDA_CODEC_VT1708B_5, "VIA VT1708B_5" },
981186145Smav	{ HDA_CODEC_VT1708B_6, "VIA VT1708B_6" },
982186145Smav	{ HDA_CODEC_VT1708B_7, "VIA VT1708B_7" },
983187020Smav	{ HDA_CODEC_VT1708S_0, "VIA VT1708S_0" },
984187020Smav	{ HDA_CODEC_VT1708S_1, "VIA VT1708S_1" },
985187020Smav	{ HDA_CODEC_VT1708S_2, "VIA VT1708S_2" },
986187020Smav	{ HDA_CODEC_VT1708S_3, "VIA VT1708S_3" },
987187020Smav	{ HDA_CODEC_VT1708S_4, "VIA VT1708S_4" },
988187020Smav	{ HDA_CODEC_VT1708S_5, "VIA VT1708S_5" },
989187020Smav	{ HDA_CODEC_VT1708S_6, "VIA VT1708S_6" },
990187020Smav	{ HDA_CODEC_VT1708S_7, "VIA VT1708S_7" },
991187020Smav	{ HDA_CODEC_VT1702_0, "VIA VT1702_0" },
992187020Smav	{ HDA_CODEC_VT1702_1, "VIA VT1702_1" },
993187020Smav	{ HDA_CODEC_VT1702_2, "VIA VT1702_2" },
994187020Smav	{ HDA_CODEC_VT1702_3, "VIA VT1702_3" },
995187020Smav	{ HDA_CODEC_VT1702_4, "VIA VT1702_4" },
996187020Smav	{ HDA_CODEC_VT1702_5, "VIA VT1702_5" },
997187020Smav	{ HDA_CODEC_VT1702_6, "VIA VT1702_6" },
998187020Smav	{ HDA_CODEC_VT1702_7, "VIA VT1702_7" },
999199258Smav	{ HDA_CODEC_VT1716S_0, "VIA VT1716S_0" },
1000199258Smav	{ HDA_CODEC_VT1716S_1, "VIA VT1716S_1" },
1001199258Smav	{ HDA_CODEC_VT1718S_0, "VIA VT1718S_0" },
1002199258Smav	{ HDA_CODEC_VT1718S_1, "VIA VT1718S_1" },
1003199258Smav	{ HDA_CODEC_VT1812, "VIA VT1812" },
1004199258Smav	{ HDA_CODEC_VT1818S, "VIA VT1818S" },
1005199258Smav	{ HDA_CODEC_VT1828S, "VIA VT1828S" },
1006199258Smav	{ HDA_CODEC_VT2002P_0, "VIA VT2002P_0" },
1007199258Smav	{ HDA_CODEC_VT2002P_1, "VIA VT2002P_1" },
1008199258Smav	{ HDA_CODEC_VT2020, "VIA VT2020" },
1009186146Smav	{ HDA_CODEC_ATIRS600_1,"ATI RS600 HDMI" },
1010186146Smav	{ HDA_CODEC_ATIRS600_2,"ATI RS600 HDMI" },
1011186146Smav	{ HDA_CODEC_ATIRS690,  "ATI RS690/780 HDMI" },
1012186146Smav	{ HDA_CODEC_ATIR6XX,   "ATI R6xx HDMI" },
1013187020Smav	{ HDA_CODEC_NVIDIAMCP67, "NVidia MCP67 HDMI" },
1014187445Smav	{ HDA_CODEC_NVIDIAMCP73, "NVidia MCP73 HDMI" },
1015187020Smav	{ HDA_CODEC_NVIDIAMCP78, "NVidia MCP78 HDMI" },
1016187445Smav	{ HDA_CODEC_NVIDIAMCP78_2, "NVidia MCP78 HDMI" },
1017187020Smav	{ HDA_CODEC_NVIDIAMCP7A, "NVidia MCP7A HDMI" },
1018208934Smav	{ HDA_CODEC_NVIDIAGT220, "NVidia GT220 HDMI" },
1019208934Smav	{ HDA_CODEC_NVIDIAGT21X, "NVidia GT21x HDMI" },
1020208934Smav	{ HDA_CODEC_NVIDIAMCP89, "NVidia MCP89 HDMI" },
1021208934Smav	{ HDA_CODEC_NVIDIAGT240, "NVidia GT240 HDMI" },
1022222298Smav	{ HDA_CODEC_INTELIP,   "Intel Ibex Peak HDMI" },
1023222298Smav	{ HDA_CODEC_INTELBL,   "Intel Bearlake HDMI" },
1024222298Smav	{ HDA_CODEC_INTELCA,   "Intel Cantiga HDMI" },
1025222298Smav	{ HDA_CODEC_INTELEL,   "Intel Eaglelake HDMI" },
1026222298Smav	{ HDA_CODEC_INTELIP2,  "Intel Ibex Peak HDMI" },
1027222298Smav	{ HDA_CODEC_INTELCPT,  "Intel Cougar Point HDMI" },
1028222298Smav	{ HDA_CODEC_INTELCL,   "Intel Crestline HDMI" },
1029187020Smav	{ HDA_CODEC_SII1390,   "Silicon Image SiI1390 HDMI" },
1030186146Smav	{ HDA_CODEC_SII1392,   "Silicon Image SiI1392 HDMI" },
1031162922Sariff	/* Unknown codec */
1032162922Sariff	{ HDA_CODEC_ALCXXXX,   "Realtek (Unknown)" },
1033169277Sariff	{ HDA_CODEC_ADXXXX,    "Analog Devices (Unknown)" },
1034200375Smav	{ HDA_CODEC_CSXXXX,    "Cirrus Logic (Unknown)" },
1035162922Sariff	{ HDA_CODEC_CMIXXXX,   "CMedia (Unknown)" },
1036162922Sariff	{ HDA_CODEC_STACXXXX,  "Sigmatel (Unknown)" },
1037182999Smav	{ HDA_CODEC_SIIXXXX,   "Silicon Image (Unknown)" },
1038182999Smav	{ HDA_CODEC_AGEREXXXX, "Lucent/Agere Systems (Unknown)" },
1039162922Sariff	{ HDA_CODEC_CXXXXX,    "Conexant (Unknown)" },
1040169277Sariff	{ HDA_CODEC_VTXXXX,    "VIA (Unknown)" },
1041182999Smav	{ HDA_CODEC_ATIXXXX,   "ATI (Unknown)" },
1042182999Smav	{ HDA_CODEC_NVIDIAXXXX,"NVidia (Unknown)" },
1043183894Smav	{ HDA_CODEC_INTELXXXX, "Intel (Unknown)" },
1044183894Smav	{ HDA_CODEC_IDTXXXX,   "IDT (Unknown)" },
1045162922Sariff};
1046162922Sariff#define HDAC_CODECS_LEN	(sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
1047162922Sariff
1048162922Sariff
1049162922Sariff/****************************************************************************
1050162922Sariff * Function prototypes
1051162922Sariff ****************************************************************************/
1052162922Sariffstatic void	hdac_intr_handler(void *);
1053182999Smavstatic int	hdac_reset(struct hdac_softc *, int);
1054162922Sariffstatic int	hdac_get_capabilities(struct hdac_softc *);
1055162922Sariffstatic void	hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
1056162922Sariffstatic int	hdac_dma_alloc(struct hdac_softc *,
1057162922Sariff					struct hdac_dma *, bus_size_t);
1058169277Sariffstatic void	hdac_dma_free(struct hdac_softc *, struct hdac_dma *);
1059162922Sariffstatic int	hdac_mem_alloc(struct hdac_softc *);
1060162922Sariffstatic void	hdac_mem_free(struct hdac_softc *);
1061162922Sariffstatic int	hdac_irq_alloc(struct hdac_softc *);
1062162922Sariffstatic void	hdac_irq_free(struct hdac_softc *);
1063162922Sariffstatic void	hdac_corb_init(struct hdac_softc *);
1064162922Sariffstatic void	hdac_rirb_init(struct hdac_softc *);
1065162922Sariffstatic void	hdac_corb_start(struct hdac_softc *);
1066162922Sariffstatic void	hdac_rirb_start(struct hdac_softc *);
1067182999Smavstatic void	hdac_scan_codecs(struct hdac_softc *);
1068182999Smavstatic void	hdac_probe_codec(struct hdac_codec *);
1069182999Smavstatic void	hdac_probe_function(struct hdac_codec *, nid_t);
1070182999Smavstatic int	hdac_pcmchannel_setup(struct hdac_chan *);
1071162922Sariff
1072162922Sariffstatic void	hdac_attach2(void *);
1073162922Sariff
1074162922Sariffstatic uint32_t	hdac_command_sendone_internal(struct hdac_softc *,
1075162922Sariff							uint32_t, int);
1076162922Sariffstatic void	hdac_command_send_internal(struct hdac_softc *,
1077162922Sariff					struct hdac_command_list *, int);
1078162922Sariff
1079162922Sariffstatic int	hdac_probe(device_t);
1080162922Sariffstatic int	hdac_attach(device_t);
1081162922Sariffstatic int	hdac_detach(device_t);
1082182999Smavstatic int	hdac_suspend(device_t);
1083182999Smavstatic int	hdac_resume(device_t);
1084162922Sariffstatic void	hdac_widget_connection_select(struct hdac_widget *, uint8_t);
1085162922Sariffstatic void	hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
1086162922Sariff						uint32_t, int, int);
1087162922Sariffstatic struct	hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
1088182999Smav							nid_t, int, int, int);
1089162922Sariffstatic void	hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
1090162922Sariff				nid_t, nid_t, int, int, int, int, int, int);
1091162922Sariffstatic struct	hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
1092162922Sariff
1093164614Sariffstatic int	hdac_rirb_flush(struct hdac_softc *sc);
1094164614Sariffstatic int	hdac_unsolq_flush(struct hdac_softc *sc);
1095164614Sariff
1096182999Smavstatic void	hdac_dump_pin_config(struct hdac_widget *w, uint32_t conf);
1097182999Smav
1098162922Sariff#define hdac_command(a1, a2, a3)	\
1099162922Sariff		hdac_command_sendone_internal(a1, a2, a3)
1100162922Sariff
1101182999Smav#define hdac_codec_id(c)							\
1102182999Smav		((uint32_t)((c == NULL) ? 0x00000000 :	\
1103182999Smav		((((uint32_t)(c)->vendor_id & 0x0000ffff) << 16) |	\
1104182999Smav		((uint32_t)(c)->device_id & 0x0000ffff))))
1105162922Sariff
1106162922Sariffstatic char *
1107182999Smavhdac_codec_name(struct hdac_codec *codec)
1108162922Sariff{
1109162922Sariff	uint32_t id;
1110162922Sariff	int i;
1111162922Sariff
1112182999Smav	id = hdac_codec_id(codec);
1113162922Sariff
1114162922Sariff	for (i = 0; i < HDAC_CODECS_LEN; i++) {
1115163257Sariff		if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
1116162922Sariff			return (hdac_codecs[i].name);
1117162922Sariff	}
1118162922Sariff
1119162922Sariff	return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec");
1120162922Sariff}
1121162922Sariff
1122162922Sariffstatic char *
1123162922Sariffhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
1124162922Sariff{
1125162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
1126162922Sariff	int i, first = 1;
1127162922Sariff
1128162922Sariff	bzero(buf, len);
1129162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
1130162922Sariff		if (mask & (1 << i)) {
1131162922Sariff			if (first == 0)
1132162922Sariff				strlcat(buf, ", ", len);
1133162922Sariff			strlcat(buf, ossname[i], len);
1134162922Sariff			first = 0;
1135162922Sariff		}
1136162922Sariff	}
1137182999Smav	return (buf);
1138162922Sariff}
1139162922Sariff
1140162922Sariffstatic struct hdac_audio_ctl *
1141162922Sariffhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
1142162922Sariff{
1143162922Sariff	if (devinfo == NULL ||
1144162922Sariff	    devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO ||
1145162922Sariff	    index == NULL || devinfo->function.audio.ctl == NULL ||
1146162922Sariff	    devinfo->function.audio.ctlcnt < 1 ||
1147162922Sariff	    *index < 0 || *index >= devinfo->function.audio.ctlcnt)
1148162922Sariff		return (NULL);
1149162922Sariff	return (&devinfo->function.audio.ctl[(*index)++]);
1150162922Sariff}
1151162922Sariff
1152162922Sariffstatic struct hdac_audio_ctl *
1153182999Smavhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid, int dir,
1154162922Sariff						int index, int cnt)
1155162922Sariff{
1156182999Smav	struct hdac_audio_ctl *ctl;
1157182999Smav	int i, found = 0;
1158162922Sariff
1159162922Sariff	if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
1160162922Sariff		return (NULL);
1161162922Sariff
1162162922Sariff	i = 0;
1163162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
1164182999Smav		if (ctl->enable == 0)
1165162922Sariff			continue;
1166182999Smav		if (ctl->widget->nid != nid)
1167162922Sariff			continue;
1168182999Smav		if (dir && ctl->ndir != dir)
1169182999Smav			continue;
1170182999Smav		if (index >= 0 && ctl->ndir == HDA_CTL_IN &&
1171182999Smav		    ctl->dir == ctl->ndir && ctl->index != index)
1172182999Smav			continue;
1173162922Sariff		found++;
1174182999Smav		if (found == cnt || cnt <= 0)
1175162922Sariff			return (ctl);
1176162922Sariff	}
1177162922Sariff
1178182999Smav	return (NULL);
1179162922Sariff}
1180162922Sariff
1181182999Smav/*
1182182999Smav * Jack detection (Speaker/HP redirection) event handler.
1183182999Smav */
1184162922Sariffstatic void
1185162922Sariffhdac_hp_switch_handler(struct hdac_devinfo *devinfo)
1186162922Sariff{
1187182999Smav	struct hdac_audio_as *as;
1188162922Sariff	struct hdac_softc *sc;
1189162922Sariff	struct hdac_widget *w;
1190162922Sariff	struct hdac_audio_ctl *ctl;
1191182999Smav	uint32_t val, res;
1192182999Smav	int i, j;
1193162922Sariff	nid_t cad;
1194162922Sariff
1195162922Sariff	if (devinfo == NULL || devinfo->codec == NULL ||
1196162922Sariff	    devinfo->codec->sc == NULL)
1197162922Sariff		return;
1198162922Sariff
1199162922Sariff	sc = devinfo->codec->sc;
1200162922Sariff	cad = devinfo->codec->cad;
1201182999Smav	as = devinfo->function.audio.as;
1202182999Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
1203182999Smav		if (as[i].hpredir < 0)
1204182999Smav			continue;
1205182999Smav
1206182999Smav		w = hdac_widget_get(devinfo, as[i].pins[15]);
1207182999Smav		if (w == NULL || w->enable == 0 || w->type !=
1208182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1209182999Smav			continue;
1210162922Sariff
1211171141Sariff		res = hdac_command(sc,
1212182999Smav		    HDA_CMD_GET_PIN_SENSE(cad, as[i].pins[15]), cad);
1213171141Sariff
1214182999Smav		HDA_BOOTVERBOSE(
1215182999Smav			device_printf(sc->dev,
1216182999Smav			    "Pin sense: nid=%d res=0x%08x\n",
1217182999Smav			    as[i].pins[15], res);
1218182999Smav		);
1219171141Sariff
1220182999Smav		res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res);
1221182999Smav		if (devinfo->function.audio.quirks & HDA_QUIRK_SENSEINV)
1222182999Smav			res ^= 1;
1223162922Sariff
1224182999Smav		/* (Un)Mute headphone pin. */
1225162922Sariff		ctl = hdac_audio_ctl_amp_get(devinfo,
1226182999Smav		    as[i].pins[15], HDA_CTL_IN, -1, 1);
1227182999Smav		if (ctl != NULL && ctl->mute) {
1228182999Smav			/* If pin has muter - use it. */
1229182999Smav			val = (res != 0) ? 0 : 1;
1230182999Smav			if (val != ctl->forcemute) {
1231182999Smav				ctl->forcemute = val;
1232162922Sariff				hdac_audio_ctl_amp_set(ctl,
1233182999Smav				    HDA_AMP_MUTE_DEFAULT,
1234182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
1235162922Sariff			}
1236182999Smav		} else {
1237182999Smav			/* If there is no muter - disable pin output. */
1238182999Smav			w = hdac_widget_get(devinfo, as[i].pins[15]);
1239163057Sariff			if (w != NULL && w->type ==
1240163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
1241182999Smav				if (res != 0)
1242169277Sariff					val = w->wclass.pin.ctrl |
1243162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1244162922Sariff				else
1245169277Sariff					val = w->wclass.pin.ctrl &
1246162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1247169277Sariff				if (val != w->wclass.pin.ctrl) {
1248169277Sariff					w->wclass.pin.ctrl = val;
1249169277Sariff					hdac_command(sc,
1250169277Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
1251169277Sariff					    w->nid, w->wclass.pin.ctrl), cad);
1252169277Sariff				}
1253162922Sariff			}
1254182999Smav		}
1255182999Smav		/* (Un)Mute other pins. */
1256182999Smav		for (j = 0; j < 15; j++) {
1257182999Smav			if (as[i].pins[j] <= 0)
1258182999Smav				continue;
1259182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
1260182999Smav			    as[i].pins[j], HDA_CTL_IN, -1, 1);
1261182999Smav			if (ctl != NULL && ctl->mute) {
1262182999Smav				/* If pin has muter - use it. */
1263182999Smav				val = (res != 0) ? 1 : 0;
1264182999Smav				if (val == ctl->forcemute)
1265169277Sariff					continue;
1266182999Smav				ctl->forcemute = val;
1267182999Smav				hdac_audio_ctl_amp_set(ctl,
1268182999Smav				    HDA_AMP_MUTE_DEFAULT,
1269182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
1270182999Smav				continue;
1271162922Sariff			}
1272182999Smav			/* If there is no muter - disable pin output. */
1273182999Smav			w = hdac_widget_get(devinfo, as[i].pins[j]);
1274163057Sariff			if (w != NULL && w->type ==
1275163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
1276182999Smav				if (res != 0)
1277182999Smav					val = w->wclass.pin.ctrl &
1278182999Smav					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1279182999Smav				else
1280182999Smav					val = w->wclass.pin.ctrl |
1281182999Smav					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1282169277Sariff				if (val != w->wclass.pin.ctrl) {
1283169277Sariff					w->wclass.pin.ctrl = val;
1284169277Sariff					hdac_command(sc,
1285169277Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
1286169277Sariff					    w->nid, w->wclass.pin.ctrl), cad);
1287169277Sariff				}
1288162922Sariff			}
1289162922Sariff		}
1290182999Smav	}
1291182999Smav}
1292182999Smav
1293182999Smav/*
1294182999Smav * Callback for poll based jack detection.
1295182999Smav */
1296182999Smavstatic void
1297182999Smavhdac_jack_poll_callback(void *arg)
1298182999Smav{
1299182999Smav	struct hdac_devinfo *devinfo = arg;
1300182999Smav	struct hdac_softc *sc;
1301182999Smav
1302182999Smav	if (devinfo == NULL || devinfo->codec == NULL ||
1303182999Smav	    devinfo->codec->sc == NULL)
1304182999Smav		return;
1305182999Smav	sc = devinfo->codec->sc;
1306182999Smav	hdac_lock(sc);
1307182999Smav	if (sc->poll_ival == 0) {
1308182999Smav		hdac_unlock(sc);
1309182999Smav		return;
1310182999Smav	}
1311182999Smav	hdac_hp_switch_handler(devinfo);
1312182999Smav	callout_reset(&sc->poll_jack, sc->poll_ival,
1313182999Smav	    hdac_jack_poll_callback, devinfo);
1314182999Smav	hdac_unlock(sc);
1315182999Smav}
1316182999Smav
1317182999Smav/*
1318182999Smav * Jack detection initializer.
1319182999Smav */
1320182999Smavstatic void
1321182999Smavhdac_hp_switch_init(struct hdac_devinfo *devinfo)
1322182999Smav{
1323182999Smav        struct hdac_softc *sc = devinfo->codec->sc;
1324182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
1325182999Smav        struct hdac_widget *w;
1326182999Smav        uint32_t id;
1327182999Smav        int i, enable = 0, poll = 0;
1328182999Smav        nid_t cad;
1329182999Smav
1330182999Smav	id = hdac_codec_id(devinfo->codec);
1331182999Smav	cad = devinfo->codec->cad;
1332182999Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
1333182999Smav		if (as[i].hpredir < 0)
1334182999Smav			continue;
1335182999Smav
1336182999Smav		w = hdac_widget_get(devinfo, as[i].pins[15]);
1337182999Smav		if (w == NULL || w->enable == 0 || w->type !=
1338182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1339182999Smav			continue;
1340182999Smav		if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
1341182999Smav		    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
1342182999Smav			device_printf(sc->dev,
1343182999Smav			    "No jack detection support at pin %d\n",
1344182999Smav			    as[i].pins[15]);
1345182999Smav			continue;
1346182999Smav		}
1347182999Smav		enable = 1;
1348182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
1349169277Sariff			hdac_command(sc,
1350182999Smav			    HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid,
1351182999Smav			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
1352182999Smav			    HDAC_UNSOLTAG_EVENT_HP), cad);
1353182999Smav		} else
1354182999Smav			poll = 1;
1355182999Smav		HDA_BOOTVERBOSE(
1356169277Sariff			device_printf(sc->dev,
1357182999Smav			    "Enabling headphone/speaker "
1358182999Smav			    "audio routing switching:\n");
1359182999Smav			device_printf(sc->dev, "\tas=%d sense nid=%d [%s]\n",
1360182999Smav			    i, w->nid, (poll != 0) ? "POLL" : "UNSOL");
1361182999Smav		);
1362182999Smav	}
1363182999Smav	if (enable) {
1364182999Smav		hdac_hp_switch_handler(devinfo);
1365182999Smav		if (poll) {
1366182999Smav			callout_reset(&sc->poll_jack, 1,
1367182999Smav			    hdac_jack_poll_callback, devinfo);
1368169277Sariff		}
1369162922Sariff	}
1370162922Sariff}
1371162922Sariff
1372182999Smav/*
1373182999Smav * Unsolicited messages handler.
1374182999Smav */
1375162922Sariffstatic void
1376162922Sariffhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
1377162922Sariff{
1378162922Sariff	struct hdac_softc *sc;
1379162922Sariff	struct hdac_devinfo *devinfo = NULL;
1380182999Smav	int i;
1381162922Sariff
1382162922Sariff	if (codec == NULL || codec->sc == NULL)
1383162922Sariff		return;
1384162922Sariff
1385162922Sariff	sc = codec->sc;
1386162922Sariff
1387163057Sariff	HDA_BOOTVERBOSE(
1388182999Smav		device_printf(sc->dev, "Unsol Tag: 0x%08x\n", tag);
1389162922Sariff	);
1390162922Sariff
1391182999Smav	for (i = 0; i < codec->num_fgs; i++) {
1392182999Smav		if (codec->fgs[i].node_type ==
1393182999Smav		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
1394182999Smav			devinfo = &codec->fgs[i];
1395162965Sariff			break;
1396182999Smav		}
1397162922Sariff	}
1398162965Sariff
1399162922Sariff	if (devinfo == NULL)
1400162922Sariff		return;
1401162922Sariff
1402162922Sariff	switch (tag) {
1403162922Sariff	case HDAC_UNSOLTAG_EVENT_HP:
1404162922Sariff		hdac_hp_switch_handler(devinfo);
1405162922Sariff		break;
1406162922Sariff	default:
1407182999Smav		device_printf(sc->dev, "Unknown unsol tag: 0x%08x!\n", tag);
1408162922Sariff		break;
1409162922Sariff	}
1410162922Sariff}
1411162922Sariff
1412164614Sariffstatic int
1413162922Sariffhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
1414162922Sariff{
1415162922Sariff	/* XXX to be removed */
1416162922Sariff#ifdef HDAC_INTR_EXTRA
1417162922Sariff	uint32_t res;
1418162922Sariff#endif
1419162922Sariff
1420171330Sariff	if (!(ch->flags & HDAC_CHN_RUNNING))
1421164614Sariff		return (0);
1422162922Sariff
1423162922Sariff	/* XXX to be removed */
1424162922Sariff#ifdef HDAC_INTR_EXTRA
1425162922Sariff	res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS);
1426162922Sariff#endif
1427162922Sariff
1428162922Sariff	/* XXX to be removed */
1429162922Sariff#ifdef HDAC_INTR_EXTRA
1430163057Sariff	HDA_BOOTVERBOSE(
1431163057Sariff		if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE))
1432182999Smav			device_printf(ch->pdevinfo->dev,
1433163057Sariff			    "PCMDIR_%s intr triggered beyond stream boundary:"
1434163057Sariff			    "%08x\n",
1435163057Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
1436163057Sariff	);
1437162922Sariff#endif
1438162922Sariff
1439162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS,
1440163057Sariff	    HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS );
1441162922Sariff
1442162922Sariff	/* XXX to be removed */
1443162922Sariff#ifdef HDAC_INTR_EXTRA
1444162922Sariff	if (res & HDAC_SDSTS_BCIS) {
1445162922Sariff#endif
1446164614Sariff		return (1);
1447162922Sariff	/* XXX to be removed */
1448162922Sariff#ifdef HDAC_INTR_EXTRA
1449162922Sariff	}
1450162922Sariff#endif
1451164614Sariff
1452164614Sariff	return (0);
1453162922Sariff}
1454162922Sariff
1455162922Sariff/****************************************************************************
1456162922Sariff * void hdac_intr_handler(void *)
1457162922Sariff *
1458162922Sariff * Interrupt handler. Processes interrupts received from the hdac.
1459162922Sariff ****************************************************************************/
1460162922Sariffstatic void
1461162922Sariffhdac_intr_handler(void *context)
1462162922Sariff{
1463162922Sariff	struct hdac_softc *sc;
1464162922Sariff	uint32_t intsts;
1465162922Sariff	uint8_t rirbsts;
1466164614Sariff	struct hdac_rirb *rirb_base;
1467171141Sariff	uint32_t trigger;
1468182999Smav	int i;
1469162922Sariff
1470162922Sariff	sc = (struct hdac_softc *)context;
1471162922Sariff
1472162922Sariff	hdac_lock(sc);
1473164614Sariff	if (sc->polling != 0) {
1474164614Sariff		hdac_unlock(sc);
1475164614Sariff		return;
1476164614Sariff	}
1477171141Sariff
1478162922Sariff	/* Do we have anything to do? */
1479162922Sariff	intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
1480163057Sariff	if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) {
1481162922Sariff		hdac_unlock(sc);
1482162922Sariff		return;
1483162922Sariff	}
1484162922Sariff
1485171141Sariff	trigger = 0;
1486171141Sariff
1487162922Sariff	/* Was this a controller interrupt? */
1488163057Sariff	if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) {
1489162922Sariff		rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
1490162922Sariff		rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1491162922Sariff		/* Get as many responses that we can */
1492163057Sariff		while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) {
1493164614Sariff			HDAC_WRITE_1(&sc->mem,
1494164614Sariff			    HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
1495171141Sariff			if (hdac_rirb_flush(sc) != 0)
1496171141Sariff				trigger |= HDAC_TRIGGER_UNSOL;
1497162922Sariff			rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1498162922Sariff		}
1499162922Sariff		/* XXX to be removed */
1500162922Sariff		/* Clear interrupt and exit */
1501162922Sariff#ifdef HDAC_INTR_EXTRA
1502162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS);
1503162922Sariff#endif
1504162922Sariff	}
1505164614Sariff
1506163057Sariff	if (intsts & HDAC_INTSTS_SIS_MASK) {
1507182999Smav		for (i = 0; i < sc->num_chans; i++) {
1508182999Smav			if ((intsts & (1 << (sc->chans[i].off >> 5))) &&
1509182999Smav			    hdac_stream_intr(sc, &sc->chans[i]) != 0)
1510182999Smav				trigger |= (1 << i);
1511182999Smav		}
1512162922Sariff		/* XXX to be removed */
1513162922Sariff#ifdef HDAC_INTR_EXTRA
1514164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts &
1515164614Sariff		    HDAC_INTSTS_SIS_MASK);
1516162922Sariff#endif
1517162922Sariff	}
1518162922Sariff
1519164614Sariff	hdac_unlock(sc);
1520162922Sariff
1521182999Smav	for (i = 0; i < sc->num_chans; i++) {
1522182999Smav		if (trigger & (1 << i))
1523182999Smav			chn_intr(sc->chans[i].c);
1524182999Smav	}
1525171141Sariff	if (trigger & HDAC_TRIGGER_UNSOL)
1526171141Sariff		taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
1527162922Sariff}
1528162922Sariff
1529162922Sariff/****************************************************************************
1530182999Smav * int hdac_reset(hdac_softc *, int)
1531162922Sariff *
1532162922Sariff * Reset the hdac to a quiescent and known state.
1533162922Sariff ****************************************************************************/
1534162922Sariffstatic int
1535182999Smavhdac_reset(struct hdac_softc *sc, int wakeup)
1536162922Sariff{
1537162922Sariff	uint32_t gctl;
1538162922Sariff	int count, i;
1539162922Sariff
1540162922Sariff	/*
1541162922Sariff	 * Stop all Streams DMA engine
1542162922Sariff	 */
1543162922Sariff	for (i = 0; i < sc->num_iss; i++)
1544162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
1545162922Sariff	for (i = 0; i < sc->num_oss; i++)
1546162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
1547162922Sariff	for (i = 0; i < sc->num_bss; i++)
1548162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
1549162922Sariff
1550162922Sariff	/*
1551169277Sariff	 * Stop Control DMA engines.
1552162922Sariff	 */
1553162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
1554162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
1555162922Sariff
1556162922Sariff	/*
1557169277Sariff	 * Reset DMA position buffer.
1558169277Sariff	 */
1559169277Sariff	HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0);
1560169277Sariff	HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0);
1561169277Sariff
1562169277Sariff	/*
1563162922Sariff	 * Reset the controller. The reset must remain asserted for
1564162922Sariff	 * a minimum of 100us.
1565162922Sariff	 */
1566162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1567162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
1568162922Sariff	count = 10000;
1569162922Sariff	do {
1570162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1571162922Sariff		if (!(gctl & HDAC_GCTL_CRST))
1572162922Sariff			break;
1573162922Sariff		DELAY(10);
1574162922Sariff	} while	(--count);
1575162922Sariff	if (gctl & HDAC_GCTL_CRST) {
1576162922Sariff		device_printf(sc->dev, "Unable to put hdac in reset\n");
1577162922Sariff		return (ENXIO);
1578162922Sariff	}
1579182999Smav
1580182999Smav	/* If wakeup is not requested - leave the controller in reset state. */
1581182999Smav	if (!wakeup)
1582182999Smav		return (0);
1583182999Smav
1584162922Sariff	DELAY(100);
1585162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1586162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
1587162922Sariff	count = 10000;
1588162922Sariff	do {
1589162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1590163057Sariff		if (gctl & HDAC_GCTL_CRST)
1591162922Sariff			break;
1592162922Sariff		DELAY(10);
1593162922Sariff	} while (--count);
1594162922Sariff	if (!(gctl & HDAC_GCTL_CRST)) {
1595162922Sariff		device_printf(sc->dev, "Device stuck in reset\n");
1596162922Sariff		return (ENXIO);
1597162922Sariff	}
1598162922Sariff
1599162922Sariff	/*
1600162922Sariff	 * Wait for codecs to finish their own reset sequence. The delay here
1601162922Sariff	 * should be of 250us but for some reasons, on it's not enough on my
1602162922Sariff	 * computer. Let's use twice as much as necessary to make sure that
1603162922Sariff	 * it's reset properly.
1604162922Sariff	 */
1605162922Sariff	DELAY(1000);
1606162922Sariff
1607162922Sariff	return (0);
1608162922Sariff}
1609162922Sariff
1610162922Sariff
1611162922Sariff/****************************************************************************
1612162922Sariff * int hdac_get_capabilities(struct hdac_softc *);
1613162922Sariff *
1614162922Sariff * Retreive the general capabilities of the hdac;
1615162922Sariff *	Number of Input Streams
1616162922Sariff *	Number of Output Streams
1617162922Sariff *	Number of bidirectional Streams
1618162922Sariff *	64bit ready
1619162922Sariff *	CORB and RIRB sizes
1620162922Sariff ****************************************************************************/
1621162922Sariffstatic int
1622162922Sariffhdac_get_capabilities(struct hdac_softc *sc)
1623162922Sariff{
1624162922Sariff	uint16_t gcap;
1625162922Sariff	uint8_t corbsize, rirbsize;
1626162922Sariff
1627162922Sariff	gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
1628162922Sariff	sc->num_iss = HDAC_GCAP_ISS(gcap);
1629162922Sariff	sc->num_oss = HDAC_GCAP_OSS(gcap);
1630162922Sariff	sc->num_bss = HDAC_GCAP_BSS(gcap);
1631196762Smav	sc->num_sdo = HDAC_GCAP_NSDO(gcap);
1632163057Sariff	sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK);
1633162922Sariff
1634162922Sariff	corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
1635162922Sariff	if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
1636162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_256)
1637162922Sariff		sc->corb_size = 256;
1638162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
1639162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_16)
1640162922Sariff		sc->corb_size = 16;
1641162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
1642162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_2)
1643162922Sariff		sc->corb_size = 2;
1644162922Sariff	else {
1645162922Sariff		device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
1646162922Sariff		    __func__, corbsize);
1647162922Sariff		return (ENXIO);
1648162922Sariff	}
1649162922Sariff
1650162922Sariff	rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
1651162922Sariff	if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
1652162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_256)
1653162922Sariff		sc->rirb_size = 256;
1654162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
1655162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_16)
1656162922Sariff		sc->rirb_size = 16;
1657162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
1658162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_2)
1659162922Sariff		sc->rirb_size = 2;
1660162922Sariff	else {
1661162922Sariff		device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
1662162922Sariff		    __func__, rirbsize);
1663162922Sariff		return (ENXIO);
1664162922Sariff	}
1665162922Sariff
1666196762Smav	HDA_BOOTVERBOSE(
1667196762Smav		device_printf(sc->dev, "Caps: OSS %d, ISS %d, BSS %d, "
1668196762Smav		    "NSDO %d%s, CORB %d, RIRB %d\n",
1669196762Smav		    sc->num_oss, sc->num_iss, sc->num_bss, 1 << sc->num_sdo,
1670196762Smav		    sc->support_64bit ? ", 64bit" : "",
1671196762Smav		    sc->corb_size, sc->rirb_size);
1672182999Smav	);
1673182999Smav
1674162922Sariff	return (0);
1675162922Sariff}
1676162922Sariff
1677162922Sariff
1678162922Sariff/****************************************************************************
1679162922Sariff * void hdac_dma_cb
1680162922Sariff *
1681162922Sariff * This function is called by bus_dmamap_load when the mapping has been
1682162922Sariff * established. We just record the physical address of the mapping into
1683162922Sariff * the struct hdac_dma passed in.
1684162922Sariff ****************************************************************************/
1685162922Sariffstatic void
1686162922Sariffhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
1687162922Sariff{
1688162922Sariff	struct hdac_dma *dma;
1689162922Sariff
1690162922Sariff	if (error == 0) {
1691162922Sariff		dma = (struct hdac_dma *)callback_arg;
1692162922Sariff		dma->dma_paddr = segs[0].ds_addr;
1693162922Sariff	}
1694162922Sariff}
1695162922Sariff
1696162922Sariff
1697162922Sariff/****************************************************************************
1698162922Sariff * int hdac_dma_alloc
1699162922Sariff *
1700162922Sariff * This function allocate and setup a dma region (struct hdac_dma).
1701162922Sariff * It must be freed by a corresponding hdac_dma_free.
1702162922Sariff ****************************************************************************/
1703162922Sariffstatic int
1704162922Sariffhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
1705162922Sariff{
1706169277Sariff	bus_size_t roundsz;
1707162922Sariff	int result;
1708162922Sariff
1709169277Sariff	roundsz = roundup2(size, HDAC_DMA_ALIGNMENT);
1710162922Sariff	bzero(dma, sizeof(*dma));
1711162922Sariff
1712162922Sariff	/*
1713162922Sariff	 * Create a DMA tag
1714162922Sariff	 */
1715194861Smav	result = bus_dma_tag_create(
1716194861Smav	    bus_get_dma_tag(sc->dev),		/* parent */
1717162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
1718162922Sariff	    0,					/* boundary */
1719194861Smav	    (sc->support_64bit) ? BUS_SPACE_MAXADDR :
1720194861Smav		BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1721162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
1722162922Sariff	    NULL,				/* filtfunc */
1723162922Sariff	    NULL,				/* fistfuncarg */
1724169277Sariff	    roundsz, 				/* maxsize */
1725162922Sariff	    1,					/* nsegments */
1726169277Sariff	    roundsz, 				/* maxsegsz */
1727162922Sariff	    0,					/* flags */
1728162922Sariff	    NULL,				/* lockfunc */
1729162922Sariff	    NULL,				/* lockfuncarg */
1730162922Sariff	    &dma->dma_tag);			/* dmat */
1731162922Sariff	if (result != 0) {
1732162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
1733162922Sariff		    __func__, result);
1734167773Sariff		goto hdac_dma_alloc_fail;
1735162922Sariff	}
1736162922Sariff
1737162922Sariff	/*
1738162922Sariff	 * Allocate DMA memory
1739162922Sariff	 */
1740162965Sariff	result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
1741169277Sariff	    BUS_DMA_NOWAIT | BUS_DMA_ZERO |
1742171330Sariff	    ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0),
1743171330Sariff	    &dma->dma_map);
1744162922Sariff	if (result != 0) {
1745162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n",
1746162922Sariff		    __func__, result);
1747167773Sariff		goto hdac_dma_alloc_fail;
1748162922Sariff	}
1749162922Sariff
1750169277Sariff	dma->dma_size = roundsz;
1751169277Sariff
1752162922Sariff	/*
1753162922Sariff	 * Map the memory
1754162922Sariff	 */
1755162922Sariff	result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
1756169277Sariff	    (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0);
1757162922Sariff	if (result != 0 || dma->dma_paddr == 0) {
1758167773Sariff		if (result == 0)
1759167773Sariff			result = ENOMEM;
1760162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n",
1761162922Sariff		    __func__, result);
1762167773Sariff		goto hdac_dma_alloc_fail;
1763162922Sariff	}
1764162922Sariff
1765183097Smav	HDA_BOOTHVERBOSE(
1766169277Sariff		device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n",
1767169277Sariff		    __func__, (uintmax_t)size, (uintmax_t)roundsz);
1768169277Sariff	);
1769169277Sariff
1770162922Sariff	return (0);
1771169277Sariff
1772167773Sariffhdac_dma_alloc_fail:
1773169277Sariff	hdac_dma_free(sc, dma);
1774167773Sariff
1775162922Sariff	return (result);
1776162922Sariff}
1777162922Sariff
1778162922Sariff
1779162922Sariff/****************************************************************************
1780169277Sariff * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *)
1781162922Sariff *
1782162922Sariff * Free a struct dhac_dma that has been previously allocated via the
1783162922Sariff * hdac_dma_alloc function.
1784162922Sariff ****************************************************************************/
1785162922Sariffstatic void
1786169277Sariffhdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma)
1787162922Sariff{
1788167773Sariff	if (dma->dma_map != NULL) {
1789169277Sariff#if 0
1790162922Sariff		/* Flush caches */
1791162922Sariff		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
1792162922Sariff		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1793169277Sariff#endif
1794162922Sariff		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1795167773Sariff	}
1796167773Sariff	if (dma->dma_vaddr != NULL) {
1797162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1798167773Sariff		dma->dma_vaddr = NULL;
1799167773Sariff	}
1800167773Sariff	dma->dma_map = NULL;
1801167773Sariff	if (dma->dma_tag != NULL) {
1802162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1803167773Sariff		dma->dma_tag = NULL;
1804162922Sariff	}
1805167773Sariff	dma->dma_size = 0;
1806162922Sariff}
1807162922Sariff
1808162922Sariff/****************************************************************************
1809162922Sariff * int hdac_mem_alloc(struct hdac_softc *)
1810162922Sariff *
1811162922Sariff * Allocate all the bus resources necessary to speak with the physical
1812162922Sariff * controller.
1813162922Sariff ****************************************************************************/
1814162922Sariffstatic int
1815162922Sariffhdac_mem_alloc(struct hdac_softc *sc)
1816162922Sariff{
1817162922Sariff	struct hdac_mem *mem;
1818162922Sariff
1819162922Sariff	mem = &sc->mem;
1820162922Sariff	mem->mem_rid = PCIR_BAR(0);
1821162922Sariff	mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1822162922Sariff	    &mem->mem_rid, RF_ACTIVE);
1823162922Sariff	if (mem->mem_res == NULL) {
1824162922Sariff		device_printf(sc->dev,
1825162922Sariff		    "%s: Unable to allocate memory resource\n", __func__);
1826162922Sariff		return (ENOMEM);
1827162922Sariff	}
1828162922Sariff	mem->mem_tag = rman_get_bustag(mem->mem_res);
1829162922Sariff	mem->mem_handle = rman_get_bushandle(mem->mem_res);
1830162922Sariff
1831162922Sariff	return (0);
1832162922Sariff}
1833162922Sariff
1834162922Sariff/****************************************************************************
1835162922Sariff * void hdac_mem_free(struct hdac_softc *)
1836162922Sariff *
1837162922Sariff * Free up resources previously allocated by hdac_mem_alloc.
1838162922Sariff ****************************************************************************/
1839162922Sariffstatic void
1840162922Sariffhdac_mem_free(struct hdac_softc *sc)
1841162922Sariff{
1842162922Sariff	struct hdac_mem *mem;
1843162922Sariff
1844162922Sariff	mem = &sc->mem;
1845162922Sariff	if (mem->mem_res != NULL)
1846162922Sariff		bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
1847162922Sariff		    mem->mem_res);
1848164614Sariff	mem->mem_res = NULL;
1849162922Sariff}
1850162922Sariff
1851162922Sariff/****************************************************************************
1852162922Sariff * int hdac_irq_alloc(struct hdac_softc *)
1853162922Sariff *
1854162922Sariff * Allocate and setup the resources necessary for interrupt handling.
1855162922Sariff ****************************************************************************/
1856162922Sariffstatic int
1857162922Sariffhdac_irq_alloc(struct hdac_softc *sc)
1858162922Sariff{
1859162922Sariff	struct hdac_irq *irq;
1860162922Sariff	int result;
1861162922Sariff
1862162922Sariff	irq = &sc->irq;
1863162922Sariff	irq->irq_rid = 0x0;
1864171330Sariff
1865171330Sariff	if ((sc->flags & HDAC_F_MSI) &&
1866171330Sariff	    (result = pci_msi_count(sc->dev)) == 1 &&
1867171330Sariff	    pci_alloc_msi(sc->dev, &result) == 0)
1868171330Sariff		irq->irq_rid = 0x1;
1869171330Sariff	else
1870171330Sariff		sc->flags &= ~HDAC_F_MSI;
1871171330Sariff
1872162922Sariff	irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1873162922Sariff	    &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
1874162922Sariff	if (irq->irq_res == NULL) {
1875162922Sariff		device_printf(sc->dev, "%s: Unable to allocate irq\n",
1876162922Sariff		    __func__);
1877167773Sariff		goto hdac_irq_alloc_fail;
1878162922Sariff	}
1879182999Smav	result = bus_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE | INTR_TYPE_AV,
1880182999Smav	    NULL, hdac_intr_handler, sc, &irq->irq_handle);
1881162922Sariff	if (result != 0) {
1882162922Sariff		device_printf(sc->dev,
1883162922Sariff		    "%s: Unable to setup interrupt handler (%x)\n",
1884162922Sariff		    __func__, result);
1885167773Sariff		goto hdac_irq_alloc_fail;
1886162922Sariff	}
1887162922Sariff
1888162922Sariff	return (0);
1889162922Sariff
1890167773Sariffhdac_irq_alloc_fail:
1891164614Sariff	hdac_irq_free(sc);
1892164614Sariff
1893162922Sariff	return (ENXIO);
1894162922Sariff}
1895162922Sariff
1896162922Sariff/****************************************************************************
1897162922Sariff * void hdac_irq_free(struct hdac_softc *)
1898162922Sariff *
1899162922Sariff * Free up resources previously allocated by hdac_irq_alloc.
1900162922Sariff ****************************************************************************/
1901162922Sariffstatic void
1902162922Sariffhdac_irq_free(struct hdac_softc *sc)
1903162922Sariff{
1904162922Sariff	struct hdac_irq *irq;
1905162922Sariff
1906162922Sariff	irq = &sc->irq;
1907164614Sariff	if (irq->irq_res != NULL && irq->irq_handle != NULL)
1908162922Sariff		bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
1909162922Sariff	if (irq->irq_res != NULL)
1910162922Sariff		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1911162922Sariff		    irq->irq_res);
1912188656Smav	if (irq->irq_rid == 0x1)
1913171330Sariff		pci_release_msi(sc->dev);
1914164614Sariff	irq->irq_handle = NULL;
1915164614Sariff	irq->irq_res = NULL;
1916171330Sariff	irq->irq_rid = 0x0;
1917162922Sariff}
1918162922Sariff
1919162922Sariff/****************************************************************************
1920162922Sariff * void hdac_corb_init(struct hdac_softc *)
1921162922Sariff *
1922162922Sariff * Initialize the corb registers for operations but do not start it up yet.
1923162922Sariff * The CORB engine must not be running when this function is called.
1924162922Sariff ****************************************************************************/
1925162922Sariffstatic void
1926162922Sariffhdac_corb_init(struct hdac_softc *sc)
1927162922Sariff{
1928162922Sariff	uint8_t corbsize;
1929162922Sariff	uint64_t corbpaddr;
1930162922Sariff
1931162922Sariff	/* Setup the CORB size. */
1932162922Sariff	switch (sc->corb_size) {
1933162922Sariff	case 256:
1934162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
1935162922Sariff		break;
1936162922Sariff	case 16:
1937162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
1938162922Sariff		break;
1939162922Sariff	case 2:
1940162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
1941162922Sariff		break;
1942162922Sariff	default:
1943162922Sariff		panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
1944162922Sariff	}
1945162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
1946162922Sariff
1947162922Sariff	/* Setup the CORB Address in the hdac */
1948162922Sariff	corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
1949162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
1950162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
1951162922Sariff
1952162922Sariff	/* Set the WP and RP */
1953162922Sariff	sc->corb_wp = 0;
1954162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
1955162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
1956162922Sariff	/*
1957162922Sariff	 * The HDA specification indicates that the CORBRPRST bit will always
1958162922Sariff	 * read as zero. Unfortunately, it seems that at least the 82801G
1959162922Sariff	 * doesn't reset the bit to zero, which stalls the corb engine.
1960162922Sariff	 * manually reset the bit to zero before continuing.
1961162922Sariff	 */
1962162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
1963162922Sariff
1964162922Sariff	/* Enable CORB error reporting */
1965162922Sariff#if 0
1966162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
1967162922Sariff#endif
1968162922Sariff}
1969162922Sariff
1970162922Sariff/****************************************************************************
1971162922Sariff * void hdac_rirb_init(struct hdac_softc *)
1972162922Sariff *
1973162922Sariff * Initialize the rirb registers for operations but do not start it up yet.
1974162922Sariff * The RIRB engine must not be running when this function is called.
1975162922Sariff ****************************************************************************/
1976162922Sariffstatic void
1977162922Sariffhdac_rirb_init(struct hdac_softc *sc)
1978162922Sariff{
1979162922Sariff	uint8_t rirbsize;
1980162922Sariff	uint64_t rirbpaddr;
1981162922Sariff
1982162922Sariff	/* Setup the RIRB size. */
1983162922Sariff	switch (sc->rirb_size) {
1984162922Sariff	case 256:
1985162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
1986162922Sariff		break;
1987162922Sariff	case 16:
1988162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
1989162922Sariff		break;
1990162922Sariff	case 2:
1991162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
1992162922Sariff		break;
1993162922Sariff	default:
1994162922Sariff		panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
1995162922Sariff	}
1996162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
1997162922Sariff
1998162922Sariff	/* Setup the RIRB Address in the hdac */
1999162922Sariff	rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
2000162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
2001162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
2002162922Sariff
2003162922Sariff	/* Setup the WP and RP */
2004162922Sariff	sc->rirb_rp = 0;
2005162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
2006162922Sariff
2007182999Smav	/* Setup the interrupt threshold */
2008182999Smav	HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
2009162922Sariff
2010182999Smav	/* Enable Overrun and response received reporting */
2011162922Sariff#if 0
2012182999Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
2013182999Smav	    HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
2014162922Sariff#else
2015182999Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
2016162922Sariff#endif
2017162922Sariff
2018169277Sariff#if 0
2019162922Sariff	/*
2020162922Sariff	 * Make sure that the Host CPU cache doesn't contain any dirty
2021162922Sariff	 * cache lines that falls in the rirb. If I understood correctly, it
2022162922Sariff	 * should be sufficient to do this only once as the rirb is purely
2023162922Sariff	 * read-only from now on.
2024162922Sariff	 */
2025162922Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2026162922Sariff	    BUS_DMASYNC_PREREAD);
2027169277Sariff#endif
2028162922Sariff}
2029162922Sariff
2030162922Sariff/****************************************************************************
2031162922Sariff * void hdac_corb_start(hdac_softc *)
2032162922Sariff *
2033162922Sariff * Startup the corb DMA engine
2034162922Sariff ****************************************************************************/
2035162922Sariffstatic void
2036162922Sariffhdac_corb_start(struct hdac_softc *sc)
2037162922Sariff{
2038162922Sariff	uint32_t corbctl;
2039162922Sariff
2040162922Sariff	corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
2041162922Sariff	corbctl |= HDAC_CORBCTL_CORBRUN;
2042162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
2043162922Sariff}
2044162922Sariff
2045162922Sariff/****************************************************************************
2046162922Sariff * void hdac_rirb_start(hdac_softc *)
2047162922Sariff *
2048162922Sariff * Startup the rirb DMA engine
2049162922Sariff ****************************************************************************/
2050162922Sariffstatic void
2051162922Sariffhdac_rirb_start(struct hdac_softc *sc)
2052162922Sariff{
2053162922Sariff	uint32_t rirbctl;
2054162922Sariff
2055162922Sariff	rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
2056162922Sariff	rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
2057162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
2058162922Sariff}
2059162922Sariff
2060162922Sariff
2061162922Sariff/****************************************************************************
2062172811Sariff * void hdac_scan_codecs(struct hdac_softc *, int)
2063162922Sariff *
2064172811Sariff * Scan the bus for available codecs, starting with num.
2065162922Sariff ****************************************************************************/
2066162922Sariffstatic void
2067182999Smavhdac_scan_codecs(struct hdac_softc *sc)
2068162922Sariff{
2069162922Sariff	struct hdac_codec *codec;
2070162922Sariff	int i;
2071162922Sariff	uint16_t statests;
2072162922Sariff
2073162922Sariff	statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
2074182999Smav	for (i = 0; i < HDAC_CODEC_MAX; i++) {
2075162922Sariff		if (HDAC_STATESTS_SDIWAKE(statests, i)) {
2076162922Sariff			/* We have found a codec. */
2077162922Sariff			codec = (struct hdac_codec *)malloc(sizeof(*codec),
2078162922Sariff			    M_HDAC, M_ZERO | M_NOWAIT);
2079162922Sariff			if (codec == NULL) {
2080162922Sariff				device_printf(sc->dev,
2081162922Sariff				    "Unable to allocate memory for codec\n");
2082162922Sariff				continue;
2083162922Sariff			}
2084164614Sariff			codec->commands = NULL;
2085164614Sariff			codec->responses_received = 0;
2086162922Sariff			codec->verbs_sent = 0;
2087162922Sariff			codec->sc = sc;
2088162922Sariff			codec->cad = i;
2089162922Sariff			sc->codecs[i] = codec;
2090182999Smav			hdac_probe_codec(codec);
2091162922Sariff		}
2092162922Sariff	}
2093162922Sariff	/* All codecs have been probed, now try to attach drivers to them */
2094163057Sariff	/* bus_generic_attach(sc->dev); */
2095162922Sariff}
2096162922Sariff
2097162922Sariff/****************************************************************************
2098162922Sariff * void hdac_probe_codec(struct hdac_softc *, int)
2099162922Sariff *
2100162922Sariff * Probe a the given codec_id for available function groups.
2101162922Sariff ****************************************************************************/
2102182999Smavstatic void
2103162922Sariffhdac_probe_codec(struct hdac_codec *codec)
2104162922Sariff{
2105162922Sariff	struct hdac_softc *sc = codec->sc;
2106162922Sariff	uint32_t vendorid, revisionid, subnode;
2107162922Sariff	int startnode;
2108162922Sariff	int endnode;
2109162922Sariff	int i;
2110162922Sariff	nid_t cad = codec->cad;
2111162922Sariff
2112163057Sariff	HDA_BOOTVERBOSE(
2113184089Smav		device_printf(sc->dev, "Probing codec #%d...\n", cad);
2114162922Sariff	);
2115162922Sariff	vendorid = hdac_command(sc,
2116162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
2117162922Sariff	    cad);
2118162922Sariff	revisionid = hdac_command(sc,
2119162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
2120162922Sariff	    cad);
2121182999Smav	codec->vendor_id = HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
2122182999Smav	codec->device_id = HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
2123182999Smav	codec->revision_id = HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
2124182999Smav	codec->stepping_id = HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
2125182999Smav
2126182999Smav	if (vendorid == HDAC_INVALID && revisionid == HDAC_INVALID) {
2127182999Smav		device_printf(sc->dev, "Codec #%d is not responding!"
2128182999Smav		    " Probing aborted.\n", cad);
2129182999Smav		return;
2130182999Smav	}
2131182999Smav
2132184089Smav	device_printf(sc->dev, "HDA Codec #%d: %s\n",
2133182999Smav	    cad, hdac_codec_name(codec));
2134182999Smav	HDA_BOOTVERBOSE(
2135184089Smav		device_printf(sc->dev, " HDA Codec ID: 0x%08x\n",
2136182999Smav		    hdac_codec_id(codec));
2137182999Smav		device_printf(sc->dev, "       Vendor: 0x%04x\n",
2138182999Smav		    codec->vendor_id);
2139182999Smav		device_printf(sc->dev, "       Device: 0x%04x\n",
2140182999Smav		    codec->device_id);
2141182999Smav		device_printf(sc->dev, "     Revision: 0x%02x\n",
2142182999Smav		    codec->revision_id);
2143182999Smav		device_printf(sc->dev, "     Stepping: 0x%02x\n",
2144182999Smav		    codec->stepping_id);
2145182999Smav		device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
2146182999Smav		    sc->pci_subvendor);
2147182999Smav	);
2148162922Sariff	subnode = hdac_command(sc,
2149162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
2150162922Sariff	    cad);
2151162922Sariff	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
2152162922Sariff	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
2153162922Sariff
2154183097Smav	HDA_BOOTHVERBOSE(
2155182999Smav		device_printf(sc->dev, "\tstartnode=%d endnode=%d\n",
2156163057Sariff		    startnode, endnode);
2157162922Sariff	);
2158182999Smav
2159182999Smav	codec->fgs = (struct hdac_devinfo *)malloc(sizeof(struct hdac_devinfo) *
2160182999Smav	    (endnode - startnode), M_HDAC, M_NOWAIT | M_ZERO);
2161182999Smav	if (codec->fgs == NULL) {
2162183024Smav		device_printf(sc->dev, "%s: Unable to allocate function groups\n",
2163182999Smav		    __func__);
2164182999Smav		return;
2165162922Sariff	}
2166162922Sariff
2167182999Smav	for (i = startnode; i < endnode; i++)
2168182999Smav		hdac_probe_function(codec, i);
2169182999Smav	return;
2170162922Sariff}
2171162922Sariff
2172182999Smav/*
2173182999Smav * Probe codec function and add it to the list.
2174182999Smav */
2175182999Smavstatic void
2176162922Sariffhdac_probe_function(struct hdac_codec *codec, nid_t nid)
2177162922Sariff{
2178162922Sariff	struct hdac_softc *sc = codec->sc;
2179182999Smav	struct hdac_devinfo *devinfo = &codec->fgs[codec->num_fgs];
2180162922Sariff	uint32_t fctgrptype;
2181182999Smav	uint32_t res;
2182162922Sariff	nid_t cad = codec->cad;
2183162922Sariff
2184162965Sariff	fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
2185162965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
2186162922Sariff
2187162922Sariff	devinfo->nid = nid;
2188162965Sariff	devinfo->node_type = fctgrptype;
2189162922Sariff	devinfo->codec = codec;
2190162922Sariff
2191182999Smav	res = hdac_command(sc,
2192182999Smav	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
2193162922Sariff
2194182999Smav	devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
2195182999Smav	devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
2196182999Smav	devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
2197162922Sariff
2198182999Smav	HDA_BOOTVERBOSE(
2199182999Smav		device_printf(sc->dev,
2200182999Smav		    "\tFound %s FG nid=%d startnode=%d endnode=%d total=%d\n",
2201182999Smav		    (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
2202182999Smav		    (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
2203182999Smav		    "unknown", nid, devinfo->startnode, devinfo->endnode,
2204182999Smav		    devinfo->nodecnt);
2205182999Smav	);
2206182999Smav
2207182999Smav	if (devinfo->nodecnt > 0)
2208182999Smav		devinfo->widget = (struct hdac_widget *)malloc(
2209182999Smav		    sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
2210182999Smav		    M_NOWAIT | M_ZERO);
2211182999Smav	else
2212182999Smav		devinfo->widget = NULL;
2213182999Smav
2214182999Smav	if (devinfo->widget == NULL) {
2215182999Smav		device_printf(sc->dev, "unable to allocate widgets!\n");
2216182999Smav		devinfo->endnode = devinfo->startnode;
2217182999Smav		devinfo->nodecnt = 0;
2218182999Smav		return;
2219182999Smav	}
2220182999Smav
2221182999Smav	codec->num_fgs++;
2222162922Sariff}
2223162922Sariff
2224162922Sariffstatic void
2225162922Sariffhdac_widget_connection_parse(struct hdac_widget *w)
2226162922Sariff{
2227162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2228162922Sariff	uint32_t res;
2229169277Sariff	int i, j, max, ents, entnum;
2230162922Sariff	nid_t cad = w->devinfo->codec->cad;
2231162922Sariff	nid_t nid = w->nid;
2232169277Sariff	nid_t cnid, addcnid, prevcnid;
2233162922Sariff
2234169277Sariff	w->nconns = 0;
2235169277Sariff
2236162922Sariff	res = hdac_command(sc,
2237162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad);
2238162922Sariff
2239169277Sariff	ents = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res);
2240162922Sariff
2241169277Sariff	if (ents < 1)
2242162922Sariff		return;
2243162922Sariff
2244162922Sariff	entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4;
2245162922Sariff	max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1;
2246169277Sariff	prevcnid = 0;
2247162922Sariff
2248169277Sariff#define CONN_RMASK(e)		(1 << ((32 / (e)) - 1))
2249169277Sariff#define CONN_NMASK(e)		(CONN_RMASK(e) - 1)
2250169277Sariff#define CONN_RESVAL(r, e, n)	((r) >> ((32 / (e)) * (n)))
2251169277Sariff#define CONN_RANGE(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_RMASK(e))
2252169277Sariff#define CONN_CNID(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_NMASK(e))
2253169277Sariff
2254169277Sariff	for (i = 0; i < ents; i += entnum) {
2255162922Sariff		res = hdac_command(sc,
2256162922Sariff		    HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad);
2257162922Sariff		for (j = 0; j < entnum; j++) {
2258169277Sariff			cnid = CONN_CNID(res, entnum, j);
2259169277Sariff			if (cnid == 0) {
2260169277Sariff				if (w->nconns < ents)
2261169277Sariff					device_printf(sc->dev,
2262169277Sariff					    "%s: nid=%d WARNING: zero cnid "
2263169277Sariff					    "entnum=%d j=%d index=%d "
2264169277Sariff					    "entries=%d found=%d res=0x%08x\n",
2265169277Sariff					    __func__, nid, entnum, j, i,
2266169277Sariff					    ents, w->nconns, res);
2267169277Sariff				else
2268169277Sariff					goto getconns_out;
2269169277Sariff			}
2270169277Sariff			if (cnid < w->devinfo->startnode ||
2271169277Sariff			    cnid >= w->devinfo->endnode) {
2272169277Sariff				HDA_BOOTVERBOSE(
2273169277Sariff					device_printf(sc->dev,
2274182999Smav					    "GHOST: nid=%d j=%d "
2275169277Sariff					    "entnum=%d index=%d res=0x%08x\n",
2276182999Smav					    nid, j, entnum, i, res);
2277169277Sariff				);
2278169277Sariff			}
2279169277Sariff			if (CONN_RANGE(res, entnum, j) == 0)
2280169277Sariff				addcnid = cnid;
2281169277Sariff			else if (prevcnid == 0 || prevcnid >= cnid) {
2282162922Sariff				device_printf(sc->dev,
2283169277Sariff				    "%s: WARNING: Invalid child range "
2284169277Sariff				    "nid=%d index=%d j=%d entnum=%d "
2285169277Sariff				    "prevcnid=%d cnid=%d res=0x%08x\n",
2286169277Sariff				    __func__, nid, i, j, entnum, prevcnid,
2287169277Sariff				    cnid, res);
2288169277Sariff				addcnid = cnid;
2289169277Sariff			} else
2290169277Sariff				addcnid = prevcnid + 1;
2291169277Sariff			while (addcnid <= cnid) {
2292169277Sariff				if (w->nconns > max) {
2293169277Sariff					device_printf(sc->dev,
2294182999Smav					    "Adding %d (nid=%d): "
2295169277Sariff					    "Max connection reached! max=%d\n",
2296182999Smav					    addcnid, nid, max + 1);
2297169277Sariff					goto getconns_out;
2298169277Sariff				}
2299182999Smav				w->connsenable[w->nconns] = 1;
2300169277Sariff				w->conns[w->nconns++] = addcnid++;
2301162922Sariff			}
2302169277Sariff			prevcnid = cnid;
2303162922Sariff		}
2304162922Sariff	}
2305162922Sariff
2306169277Sariffgetconns_out:
2307169277Sariff	return;
2308162922Sariff}
2309162922Sariff
2310162922Sariffstatic uint32_t
2311182999Smavhdac_widget_pin_patch(uint32_t config, const char *str)
2312182999Smav{
2313182999Smav	char buf[256];
2314182999Smav	char *key, *value, *rest, *bad;
2315182999Smav	int ival, i;
2316182999Smav
2317182999Smav	strlcpy(buf, str, sizeof(buf));
2318182999Smav	rest = buf;
2319182999Smav	while ((key = strsep(&rest, "=")) != NULL) {
2320182999Smav		value = strsep(&rest, " \t");
2321182999Smav		if (value == NULL)
2322182999Smav			break;
2323182999Smav		ival = strtol(value, &bad, 10);
2324182999Smav		if (strcmp(key, "seq") == 0) {
2325182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK;
2326182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) &
2327182999Smav			    HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK);
2328182999Smav		} else if (strcmp(key, "as") == 0) {
2329182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK;
2330182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) &
2331182999Smav			    HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK);
2332182999Smav		} else if (strcmp(key, "misc") == 0) {
2333182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_MISC_MASK;
2334182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) &
2335182999Smav			    HDA_CONFIG_DEFAULTCONF_MISC_MASK);
2336182999Smav		} else if (strcmp(key, "color") == 0) {
2337182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_COLOR_MASK;
2338182999Smav			if (bad[0] == 0) {
2339182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) &
2340182999Smav				    HDA_CONFIG_DEFAULTCONF_COLOR_MASK);
2341182999Smav			};
2342182999Smav			for (i = 0; i < 16; i++) {
2343182999Smav				if (strcasecmp(HDA_COLORS[i], value) == 0) {
2344182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT);
2345182999Smav					break;
2346182999Smav				}
2347182999Smav			}
2348182999Smav		} else if (strcmp(key, "ctype") == 0) {
2349182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK;
2350182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) &
2351182999Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK);
2352182999Smav		} else if (strcmp(key, "device") == 0) {
2353182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2354182999Smav			if (bad[0] == 0) {
2355182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) &
2356182999Smav				    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK);
2357182999Smav				continue;
2358182999Smav			};
2359182999Smav			for (i = 0; i < 16; i++) {
2360182999Smav				if (strcasecmp(HDA_DEVS[i], value) == 0) {
2361182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT);
2362182999Smav					break;
2363182999Smav				}
2364182999Smav			}
2365182999Smav		} else if (strcmp(key, "loc") == 0) {
2366182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_LOCATION_MASK;
2367182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) &
2368182999Smav			    HDA_CONFIG_DEFAULTCONF_LOCATION_MASK);
2369182999Smav		} else if (strcmp(key, "conn") == 0) {
2370182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2371182999Smav			if (bad[0] == 0) {
2372182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) &
2373182999Smav				    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2374182999Smav				continue;
2375182999Smav			};
2376182999Smav			for (i = 0; i < 4; i++) {
2377182999Smav				if (strcasecmp(HDA_CONNS[i], value) == 0) {
2378182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT);
2379182999Smav					break;
2380182999Smav				}
2381182999Smav			}
2382182999Smav		}
2383182999Smav	}
2384182999Smav	return (config);
2385182999Smav}
2386182999Smav
2387182999Smavstatic uint32_t
2388162922Sariffhdac_widget_pin_getconfig(struct hdac_widget *w)
2389162922Sariff{
2390162922Sariff	struct hdac_softc *sc;
2391166965Sariff	uint32_t config, orig, id;
2392162922Sariff	nid_t cad, nid;
2393182999Smav	char buf[32];
2394182999Smav	const char *res = NULL, *patch = NULL;
2395162922Sariff
2396162922Sariff	sc = w->devinfo->codec->sc;
2397162922Sariff	cad = w->devinfo->codec->cad;
2398162922Sariff	nid = w->nid;
2399182999Smav	id = hdac_codec_id(w->devinfo->codec);
2400162922Sariff
2401162922Sariff	config = hdac_command(sc,
2402162922Sariff	    HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
2403162922Sariff	    cad);
2404166965Sariff	orig = config;
2405166965Sariff
2406182999Smav	HDA_BOOTVERBOSE(
2407182999Smav		hdac_dump_pin_config(w, orig);
2408182999Smav	);
2409182999Smav
2410182999Smav	/* XXX: Old patches require complete review.
2411182999Smav	 * Now they may create more problem then solve due to
2412182999Smav	 * incorrect associations.
2413162965Sariff	 */
2414165281Sariff	if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) {
2415165281Sariff		switch (nid) {
2416165281Sariff		case 26:
2417165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2418165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2419165281Sariff			break;
2420165281Sariff		case 27:
2421165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2422165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
2423165281Sariff			break;
2424167610Sariff		default:
2425167610Sariff			break;
2426165281Sariff		}
2427165281Sariff	} else if (id == HDA_CODEC_ALC880 &&
2428162965Sariff	    (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR ||
2429162965Sariff	    sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) {
2430162922Sariff		/*
2431162965Sariff		 * Super broken BIOS
2432162922Sariff		 */
2433162922Sariff		switch (nid) {
2434162922Sariff		case 24:	/* MIC1 */
2435162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2436162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2437162922Sariff			break;
2438162922Sariff		case 25:	/* XXX MIC2 */
2439162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2440162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2441162922Sariff			break;
2442162922Sariff		case 26:	/* LINE1 */
2443162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2444162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2445162922Sariff			break;
2446162922Sariff		case 27:	/* XXX LINE2 */
2447162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2448162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2449162922Sariff			break;
2450162922Sariff		case 28:	/* CD */
2451162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2452162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
2453162922Sariff			break;
2454162922Sariff		}
2455166965Sariff	} else if (id == HDA_CODEC_ALC883 &&
2456172811Sariff	    (sc->pci_subvendor == MSI_MS034A_SUBVENDOR ||
2457172811Sariff	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor))) {
2458166965Sariff		switch (nid) {
2459166965Sariff		case 25:
2460166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2461166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2462166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2463166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2464166965Sariff			break;
2465169277Sariff		case 28:
2466169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2467169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2468169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2469169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2470169277Sariff			break;
2471166965Sariff		}
2472186430Smav	} else if (id == HDA_CODEC_CX20549 && sc->pci_subvendor ==
2473166965Sariff	    HP_V3000_SUBVENDOR) {
2474166965Sariff		switch (nid) {
2475166965Sariff		case 18:
2476166965Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2477166965Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2478166965Sariff			break;
2479166965Sariff		case 20:
2480166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2481166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2482166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2483166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2484166965Sariff			break;
2485167454Sariff		case 21:
2486167454Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2487167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2488167454Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2489167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2490167454Sariff			break;
2491166965Sariff		}
2492186430Smav	} else if (id == HDA_CODEC_CX20551 && sc->pci_subvendor ==
2493169277Sariff	    HP_DV5000_SUBVENDOR) {
2494169277Sariff		switch (nid) {
2495169277Sariff		case 20:
2496169277Sariff		case 21:
2497169277Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2498169277Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2499169277Sariff			break;
2500169277Sariff		}
2501169277Sariff	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2502169277Sariff	    ASUS_W6F_SUBVENDOR) {
2503169277Sariff		switch (nid) {
2504169277Sariff		case 11:
2505169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2506169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2507169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
2508169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2509169277Sariff			break;
2510178324Sariff		case 12:
2511178324Sariff		case 14:
2512178324Sariff		case 16:
2513178324Sariff		case 31:
2514178324Sariff		case 32:
2515178324Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2516178324Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2517178324Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2518178324Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2519178324Sariff			break;
2520169277Sariff		case 15:
2521169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2522169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2523169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2524169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2525169277Sariff			break;
2526169277Sariff		}
2527169277Sariff	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2528169277Sariff	    UNIWILL_9075_SUBVENDOR) {
2529169277Sariff		switch (nid) {
2530169277Sariff		case 15:
2531169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2532169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2533169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2534169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2535169277Sariff			break;
2536169277Sariff		}
2537182999Smav	}
2538182999Smav
2539182999Smav	/* New patches */
2540182999Smav	if (id == HDA_CODEC_AD1986A &&
2541171141Sariff	    (sc->pci_subvendor == ASUS_M2NPVMX_SUBVENDOR ||
2542190630Smav	    sc->pci_subvendor == ASUS_A8NVMCSM_SUBVENDOR ||
2543190630Smav	    sc->pci_subvendor == ASUS_P5PL2_SUBVENDOR)) {
2544169277Sariff		switch (nid) {
2545190630Smav		case 26: /* Headphones with redirection */
2546190630Smav			patch = "as=1 seq=15";
2547190630Smav			break;
2548190630Smav		case 28: /* 5.1 out => 2.0 out + 1 input */
2549182999Smav			patch = "device=Line-in as=8 seq=1";
2550169277Sariff			break;
2551190630Smav		case 29: /* Can't use this as input, as the only available mic
2552190630Smav			  * preamplifier is busy by front panel mic (nid 31).
2553190630Smav			  * If you want to use this rear connector as mic input,
2554190630Smav			  * you have to disable the front panel one. */
2555190630Smav			patch = "as=0";
2556169277Sariff			break;
2557182999Smav		case 31: /* Lot of inputs configured with as=15 and unusable */
2558182999Smav			patch = "as=8 seq=3";
2559169277Sariff			break;
2560182999Smav		case 32:
2561182999Smav			patch = "as=8 seq=4";
2562182999Smav			break;
2563182999Smav		case 34:
2564182999Smav			patch = "as=8 seq=5";
2565182999Smav			break;
2566182999Smav		case 36:
2567182999Smav			patch = "as=8 seq=6";
2568182999Smav			break;
2569169277Sariff		}
2570182999Smav	} else if (id == HDA_CODEC_ALC260 &&
2571182999Smav	    HDA_DEV_MATCH(SONY_S5_SUBVENDOR, sc->pci_subvendor)) {
2572182999Smav		switch (nid) {
2573182999Smav		case 16:
2574182999Smav			patch = "seq=15 device=Headphones";
2575182999Smav			break;
2576182999Smav		}
2577189879Smav	} else if (id == HDA_CODEC_ALC268) {
2578189879Smav	    if (sc->pci_subvendor == ACER_T5320_SUBVENDOR) {
2579174578Sariff		switch (nid) {
2580189879Smav		case 20: /* Headphones Jack */
2581189879Smav			patch = "as=1 seq=15";
2582174578Sariff			break;
2583174578Sariff		}
2584189879Smav	    }
2585162922Sariff	}
2586162922Sariff
2587182999Smav	if (patch != NULL)
2588182999Smav		config = hdac_widget_pin_patch(config, patch);
2589182999Smav
2590182999Smav	snprintf(buf, sizeof(buf), "cad%u.nid%u.config", cad, nid);
2591182999Smav	if (resource_string_value(device_get_name(sc->dev),
2592182999Smav	    device_get_unit(sc->dev), buf, &res) == 0) {
2593182999Smav		if (strncmp(res, "0x", 2) == 0) {
2594182999Smav			config = strtol(res + 2, NULL, 16);
2595182999Smav		} else {
2596182999Smav			config = hdac_widget_pin_patch(config, res);
2597182999Smav		}
2598182999Smav	}
2599182999Smav
2600166965Sariff	HDA_BOOTVERBOSE(
2601166965Sariff		if (config != orig)
2602166965Sariff			device_printf(sc->dev,
2603182999Smav			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
2604166965Sariff			    nid, orig, config);
2605166965Sariff	);
2606166965Sariff
2607162922Sariff	return (config);
2608162922Sariff}
2609162922Sariff
2610166965Sariffstatic uint32_t
2611166965Sariffhdac_widget_pin_getcaps(struct hdac_widget *w)
2612166965Sariff{
2613166965Sariff	struct hdac_softc *sc;
2614166965Sariff	uint32_t caps, orig, id;
2615166965Sariff	nid_t cad, nid;
2616166965Sariff
2617166965Sariff	sc = w->devinfo->codec->sc;
2618166965Sariff	cad = w->devinfo->codec->cad;
2619166965Sariff	nid = w->nid;
2620182999Smav	id = hdac_codec_id(w->devinfo->codec);
2621166965Sariff
2622166965Sariff	caps = hdac_command(sc,
2623166965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
2624166965Sariff	orig = caps;
2625166965Sariff
2626166965Sariff	HDA_BOOTVERBOSE(
2627166965Sariff		if (caps != orig)
2628166965Sariff			device_printf(sc->dev,
2629182999Smav			    "Patching pin caps nid=%u 0x%08x -> 0x%08x\n",
2630166965Sariff			    nid, orig, caps);
2631166965Sariff	);
2632166965Sariff
2633166965Sariff	return (caps);
2634166965Sariff}
2635166965Sariff
2636162922Sariffstatic void
2637162922Sariffhdac_widget_pin_parse(struct hdac_widget *w)
2638162922Sariff{
2639162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2640162922Sariff	uint32_t config, pincap;
2641186912Smav	const char *devstr;
2642162922Sariff	nid_t cad = w->devinfo->codec->cad;
2643162922Sariff	nid_t nid = w->nid;
2644186912Smav	int conn, color;
2645162922Sariff
2646162922Sariff	config = hdac_widget_pin_getconfig(w);
2647162922Sariff	w->wclass.pin.config = config;
2648162922Sariff
2649166965Sariff	pincap = hdac_widget_pin_getcaps(w);
2650162922Sariff	w->wclass.pin.cap = pincap;
2651162922Sariff
2652162922Sariff	w->wclass.pin.ctrl = hdac_command(sc,
2653182999Smav	    HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad);
2654162922Sariff
2655162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
2656162922Sariff		w->param.eapdbtl = hdac_command(sc,
2657162922Sariff		    HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
2658162922Sariff		w->param.eapdbtl &= 0x7;
2659162922Sariff		w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
2660162922Sariff	} else
2661162965Sariff		w->param.eapdbtl = HDAC_INVALID;
2662162922Sariff
2663182999Smav	devstr = HDA_DEVS[(config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >>
2664182999Smav	    HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT];
2665162922Sariff
2666186912Smav	conn = (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >>
2667186912Smav	    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT;
2668186912Smav	color = (config & HDA_CONFIG_DEFAULTCONF_COLOR_MASK) >>
2669186912Smav	    HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT;
2670162922Sariff
2671162922Sariff	strlcat(w->name, ": ", sizeof(w->name));
2672162922Sariff	strlcat(w->name, devstr, sizeof(w->name));
2673162922Sariff	strlcat(w->name, " (", sizeof(w->name));
2674186912Smav	if (conn == 0 && color != 0 && color != 15) {
2675186912Smav		strlcat(w->name, HDA_COLORS[color], sizeof(w->name));
2676186912Smav		strlcat(w->name, " ", sizeof(w->name));
2677186912Smav	}
2678186912Smav	strlcat(w->name, HDA_CONNS[conn], sizeof(w->name));
2679162922Sariff	strlcat(w->name, ")", sizeof(w->name));
2680162922Sariff}
2681162922Sariff
2682182999Smavstatic uint32_t
2683182999Smavhdac_widget_getcaps(struct hdac_widget *w, int *waspin)
2684182999Smav{
2685182999Smav	struct hdac_softc *sc;
2686182999Smav	uint32_t caps, orig, id;
2687182999Smav	nid_t cad, nid, beeper = -1;
2688182999Smav
2689182999Smav	sc = w->devinfo->codec->sc;
2690182999Smav	cad = w->devinfo->codec->cad;
2691182999Smav	nid = w->nid;
2692182999Smav	id = hdac_codec_id(w->devinfo->codec);
2693182999Smav
2694182999Smav	caps = hdac_command(sc,
2695182999Smav	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
2696182999Smav	    cad);
2697182999Smav	orig = caps;
2698182999Smav
2699182999Smav	/* On some codecs beeper is an input pin, but it is not recordable
2700182999Smav	   alone. Also most of BIOSes does not declare beeper pin.
2701182999Smav	   Change beeper pin node type to beeper to help parser. */
2702182999Smav	*waspin = 0;
2703182999Smav	switch (id) {
2704187721Smav	case HDA_CODEC_AD1882:
2705187721Smav	case HDA_CODEC_AD1883:
2706187721Smav	case HDA_CODEC_AD1984:
2707187721Smav	case HDA_CODEC_AD1984A:
2708187721Smav	case HDA_CODEC_AD1984B:
2709187721Smav	case HDA_CODEC_AD1987:
2710182999Smav	case HDA_CODEC_AD1988:
2711182999Smav	case HDA_CODEC_AD1988B:
2712187721Smav	case HDA_CODEC_AD1989B:
2713182999Smav		beeper = 26;
2714182999Smav		break;
2715182999Smav	case HDA_CODEC_ALC260:
2716182999Smav		beeper = 23;
2717182999Smav		break;
2718182999Smav	case HDA_CODEC_ALC262:
2719182999Smav	case HDA_CODEC_ALC268:
2720182999Smav	case HDA_CODEC_ALC880:
2721182999Smav	case HDA_CODEC_ALC882:
2722182999Smav	case HDA_CODEC_ALC883:
2723182999Smav	case HDA_CODEC_ALC885:
2724182999Smav	case HDA_CODEC_ALC888:
2725182999Smav	case HDA_CODEC_ALC889:
2726182999Smav		beeper = 29;
2727182999Smav		break;
2728182999Smav	}
2729182999Smav	if (nid == beeper) {
2730182999Smav		caps &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
2731182999Smav		caps |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
2732182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
2733182999Smav		*waspin = 1;
2734182999Smav	}
2735182999Smav
2736182999Smav	HDA_BOOTVERBOSE(
2737182999Smav		if (caps != orig) {
2738182999Smav			device_printf(sc->dev,
2739182999Smav			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
2740182999Smav			    nid, orig, caps);
2741182999Smav		}
2742182999Smav	);
2743182999Smav
2744182999Smav	return (caps);
2745182999Smav}
2746182999Smav
2747162922Sariffstatic void
2748162922Sariffhdac_widget_parse(struct hdac_widget *w)
2749162922Sariff{
2750162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2751162922Sariff	uint32_t wcap, cap;
2752162922Sariff	char *typestr;
2753162922Sariff	nid_t cad = w->devinfo->codec->cad;
2754162922Sariff	nid_t nid = w->nid;
2755162922Sariff
2756182999Smav	wcap = hdac_widget_getcaps(w, &w->waspin);
2757182999Smav
2758162922Sariff	w->param.widget_cap = wcap;
2759162922Sariff	w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
2760162922Sariff
2761162922Sariff	switch (w->type) {
2762162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
2763162922Sariff		typestr = "audio output";
2764162922Sariff		break;
2765162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
2766162922Sariff		typestr = "audio input";
2767162922Sariff		break;
2768162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
2769162922Sariff		typestr = "audio mixer";
2770162922Sariff		break;
2771162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
2772162922Sariff		typestr = "audio selector";
2773162922Sariff		break;
2774162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
2775162922Sariff		typestr = "pin";
2776162922Sariff		break;
2777162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET:
2778162922Sariff		typestr = "power widget";
2779162922Sariff		break;
2780162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET:
2781162922Sariff		typestr = "volume widget";
2782162922Sariff		break;
2783162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
2784162922Sariff		typestr = "beep widget";
2785162922Sariff		break;
2786162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET:
2787162922Sariff		typestr = "vendor widget";
2788162922Sariff		break;
2789162922Sariff	default:
2790162922Sariff		typestr = "unknown type";
2791162922Sariff		break;
2792162922Sariff	}
2793162922Sariff
2794162922Sariff	strlcpy(w->name, typestr, sizeof(w->name));
2795162922Sariff
2796162922Sariff	hdac_widget_connection_parse(w);
2797162922Sariff
2798162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
2799162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2800162922Sariff			w->param.outamp_cap =
2801162922Sariff			    hdac_command(sc,
2802162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2803162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP), cad);
2804162922Sariff		else
2805162922Sariff			w->param.outamp_cap =
2806162922Sariff			    w->devinfo->function.audio.outamp_cap;
2807162922Sariff	} else
2808162922Sariff		w->param.outamp_cap = 0;
2809162922Sariff
2810162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) {
2811162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2812162922Sariff			w->param.inamp_cap =
2813162922Sariff			    hdac_command(sc,
2814162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2815162922Sariff			    HDA_PARAM_INPUT_AMP_CAP), cad);
2816162922Sariff		else
2817162922Sariff			w->param.inamp_cap =
2818162922Sariff			    w->devinfo->function.audio.inamp_cap;
2819162922Sariff	} else
2820162922Sariff		w->param.inamp_cap = 0;
2821162922Sariff
2822162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
2823162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
2824162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) {
2825162922Sariff			cap = hdac_command(sc,
2826162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2827162922Sariff			    HDA_PARAM_SUPP_STREAM_FORMATS), cad);
2828162922Sariff			w->param.supp_stream_formats = (cap != 0) ? cap :
2829162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2830162922Sariff			cap = hdac_command(sc,
2831162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2832162922Sariff			    HDA_PARAM_SUPP_PCM_SIZE_RATE), cad);
2833162922Sariff			w->param.supp_pcm_size_rate = (cap != 0) ? cap :
2834162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2835162922Sariff		} else {
2836162922Sariff			w->param.supp_stream_formats =
2837162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2838162922Sariff			w->param.supp_pcm_size_rate =
2839162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2840162922Sariff		}
2841162922Sariff	} else {
2842162922Sariff		w->param.supp_stream_formats = 0;
2843162922Sariff		w->param.supp_pcm_size_rate = 0;
2844162922Sariff	}
2845162922Sariff
2846162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
2847162922Sariff		hdac_widget_pin_parse(w);
2848162922Sariff}
2849162922Sariff
2850162922Sariffstatic struct hdac_widget *
2851162922Sariffhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid)
2852162922Sariff{
2853162922Sariff	if (devinfo == NULL || devinfo->widget == NULL ||
2854162922Sariff		    nid < devinfo->startnode || nid >= devinfo->endnode)
2855162922Sariff		return (NULL);
2856162922Sariff	return (&devinfo->widget[nid - devinfo->startnode]);
2857162922Sariff}
2858162922Sariff
2859164614Sariffstatic __inline int
2860164614Sariffhda_poll_channel(struct hdac_chan *ch)
2861164614Sariff{
2862164614Sariff	uint32_t sz, delta;
2863164614Sariff	volatile uint32_t ptr;
2864164614Sariff
2865171330Sariff	if (!(ch->flags & HDAC_CHN_RUNNING))
2866164614Sariff		return (0);
2867164614Sariff
2868164614Sariff	sz = ch->blksz * ch->blkcnt;
2869169277Sariff	if (ch->dmapos != NULL)
2870169277Sariff		ptr = *(ch->dmapos);
2871169277Sariff	else
2872169277Sariff		ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem,
2873169277Sariff		    ch->off + HDAC_SDLPIB);
2874164614Sariff	ch->ptr = ptr;
2875164614Sariff	ptr %= sz;
2876164614Sariff	ptr &= ~(ch->blksz - 1);
2877164614Sariff	delta = (sz + ptr - ch->prevptr) % sz;
2878164614Sariff
2879164614Sariff	if (delta < ch->blksz)
2880164614Sariff		return (0);
2881164614Sariff
2882164614Sariff	ch->prevptr = ptr;
2883164614Sariff
2884164614Sariff	return (1);
2885164614Sariff}
2886164614Sariff
2887162922Sariffstatic void
2888164614Sariffhda_poll_callback(void *arg)
2889164614Sariff{
2890164614Sariff	struct hdac_softc *sc = arg;
2891171141Sariff	uint32_t trigger;
2892182999Smav	int i, active = 0;
2893164614Sariff
2894164614Sariff	if (sc == NULL)
2895164614Sariff		return;
2896164614Sariff
2897164614Sariff	hdac_lock(sc);
2898182999Smav	if (sc->polling == 0) {
2899164614Sariff		hdac_unlock(sc);
2900164614Sariff		return;
2901164614Sariff	}
2902164614Sariff
2903171141Sariff	trigger = 0;
2904182999Smav	for (i = 0; i < sc->num_chans; i++) {
2905182999Smav		if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
2906182999Smav		    continue;
2907182999Smav		active = 1;
2908182999Smav		if (hda_poll_channel(&sc->chans[i]))
2909182999Smav		    trigger |= (1 << i);
2910182999Smav	}
2911164614Sariff
2912164614Sariff	/* XXX */
2913182999Smav	if (active)
2914182999Smav		callout_reset(&sc->poll_hda, sc->poll_ticks,
2915182999Smav		    hda_poll_callback, sc);
2916164614Sariff
2917164614Sariff	hdac_unlock(sc);
2918164614Sariff
2919182999Smav	for (i = 0; i < sc->num_chans; i++) {
2920182999Smav		if (trigger & (1 << i))
2921182999Smav			chn_intr(sc->chans[i].c);
2922182999Smav	}
2923164614Sariff}
2924164614Sariff
2925164614Sariffstatic int
2926164614Sariffhdac_rirb_flush(struct hdac_softc *sc)
2927164614Sariff{
2928164614Sariff	struct hdac_rirb *rirb_base, *rirb;
2929164614Sariff	struct hdac_codec *codec;
2930164614Sariff	struct hdac_command_list *commands;
2931164614Sariff	nid_t cad;
2932164614Sariff	uint32_t resp;
2933164614Sariff	uint8_t rirbwp;
2934171141Sariff	int ret;
2935164614Sariff
2936164614Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2937164614Sariff	rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
2938169277Sariff#if 0
2939164614Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2940164614Sariff	    BUS_DMASYNC_POSTREAD);
2941169277Sariff#endif
2942164614Sariff
2943171141Sariff	ret = 0;
2944171141Sariff
2945164614Sariff	while (sc->rirb_rp != rirbwp) {
2946164614Sariff		sc->rirb_rp++;
2947164614Sariff		sc->rirb_rp %= sc->rirb_size;
2948164614Sariff		rirb = &rirb_base[sc->rirb_rp];
2949164614Sariff		cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
2950164614Sariff		if (cad < 0 || cad >= HDAC_CODEC_MAX ||
2951164614Sariff		    sc->codecs[cad] == NULL)
2952164614Sariff			continue;
2953164614Sariff		resp = rirb->response;
2954164614Sariff		codec = sc->codecs[cad];
2955164614Sariff		commands = codec->commands;
2956164614Sariff		if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
2957164614Sariff			sc->unsolq[sc->unsolq_wp++] = (cad << 16) |
2958164614Sariff			    ((resp >> 26) & 0xffff);
2959164614Sariff			sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
2960164614Sariff		} else if (commands != NULL && commands->num_commands > 0 &&
2961164614Sariff		    codec->responses_received < commands->num_commands)
2962164614Sariff			commands->responses[codec->responses_received++] =
2963164614Sariff			    resp;
2964164614Sariff		ret++;
2965164614Sariff	}
2966164614Sariff
2967164614Sariff	return (ret);
2968164614Sariff}
2969164614Sariff
2970164614Sariffstatic int
2971164614Sariffhdac_unsolq_flush(struct hdac_softc *sc)
2972164614Sariff{
2973164614Sariff	nid_t cad;
2974164614Sariff	uint32_t tag;
2975164614Sariff	int ret = 0;
2976164614Sariff
2977164614Sariff	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
2978164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
2979164614Sariff		while (sc->unsolq_rp != sc->unsolq_wp) {
2980164614Sariff			cad = sc->unsolq[sc->unsolq_rp] >> 16;
2981164614Sariff			tag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
2982164614Sariff			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
2983164614Sariff			hdac_unsolicited_handler(sc->codecs[cad], tag);
2984164614Sariff			ret++;
2985164614Sariff		}
2986164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_READY;
2987164614Sariff	}
2988164614Sariff
2989164614Sariff	return (ret);
2990164614Sariff}
2991164614Sariff
2992164614Sariffstatic void
2993164614Sariffhdac_poll_callback(void *arg)
2994164614Sariff{
2995164614Sariff	struct hdac_softc *sc = arg;
2996164614Sariff	if (sc == NULL)
2997164614Sariff		return;
2998166796Sariff
2999164614Sariff	hdac_lock(sc);
3000169277Sariff	if (sc->polling == 0 || sc->poll_ival == 0) {
3001164614Sariff		hdac_unlock(sc);
3002164614Sariff		return;
3003164614Sariff	}
3004171141Sariff	if (hdac_rirb_flush(sc) != 0)
3005171141Sariff		hdac_unsolq_flush(sc);
3006169277Sariff	callout_reset(&sc->poll_hdac, sc->poll_ival, hdac_poll_callback, sc);
3007164614Sariff	hdac_unlock(sc);
3008164614Sariff}
3009164614Sariff
3010164614Sariffstatic void
3011182999Smavhdac_poll_reinit(struct hdac_softc *sc)
3012182999Smav{
3013182999Smav	int i, pollticks, min = 1000000;
3014182999Smav	struct hdac_chan *ch;
3015182999Smav
3016182999Smav	for (i = 0; i < sc->num_chans; i++) {
3017182999Smav		if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
3018182999Smav			continue;
3019182999Smav		ch = &sc->chans[i];
3020182999Smav		pollticks = ((uint64_t)hz * ch->blksz) /
3021193640Sariff		    ((uint64_t)sndbuf_getalign(ch->b) * sndbuf_getspd(ch->b));
3022182999Smav		pollticks >>= 1;
3023182999Smav		if (pollticks > hz)
3024182999Smav			pollticks = hz;
3025182999Smav		if (pollticks < 1) {
3026182999Smav			HDA_BOOTVERBOSE(
3027182999Smav				device_printf(sc->dev,
3028182999Smav				    "%s: pollticks=%d < 1 !\n",
3029182999Smav				    __func__, pollticks);
3030182999Smav			);
3031182999Smav			pollticks = 1;
3032182999Smav		}
3033182999Smav		if (min > pollticks)
3034182999Smav			min = pollticks;
3035182999Smav	}
3036182999Smav	HDA_BOOTVERBOSE(
3037182999Smav		device_printf(sc->dev,
3038182999Smav		    "%s: pollticks %d -> %d\n",
3039182999Smav		    __func__, sc->poll_ticks, min);
3040182999Smav	);
3041182999Smav	sc->poll_ticks = min;
3042182999Smav	if (min == 1000000)
3043182999Smav		callout_stop(&sc->poll_hda);
3044182999Smav	else
3045182999Smav		callout_reset(&sc->poll_hda, 1, hda_poll_callback, sc);
3046182999Smav}
3047182999Smav
3048182999Smavstatic void
3049162922Sariffhdac_stream_stop(struct hdac_chan *ch)
3050162922Sariff{
3051162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3052162922Sariff	uint32_t ctl;
3053162922Sariff
3054162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
3055162922Sariff	ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
3056162922Sariff	    HDAC_SDCTL_RUN);
3057162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
3058162922Sariff
3059171330Sariff	ch->flags &= ~HDAC_CHN_RUNNING;
3060164614Sariff
3061182999Smav	if (sc->polling != 0)
3062182999Smav		hdac_poll_reinit(sc);
3063164614Sariff
3064182999Smav	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
3065182999Smav	ctl &= ~(1 << (ch->off >> 5));
3066182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
3067162922Sariff}
3068162922Sariff
3069162922Sariffstatic void
3070162922Sariffhdac_stream_start(struct hdac_chan *ch)
3071162922Sariff{
3072162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3073162922Sariff	uint32_t ctl;
3074162922Sariff
3075182999Smav	ch->flags |= HDAC_CHN_RUNNING;
3076162922Sariff
3077182999Smav	if (sc->polling != 0)
3078182999Smav		hdac_poll_reinit(sc);
3079182999Smav
3080182999Smav	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
3081182999Smav	ctl |= 1 << (ch->off >> 5);
3082182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
3083182999Smav
3084182999Smav	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
3085182999Smav	ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
3086182999Smav	    HDAC_SDCTL_RUN;
3087162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
3088162922Sariff}
3089162922Sariff
3090162922Sariffstatic void
3091162922Sariffhdac_stream_reset(struct hdac_chan *ch)
3092162922Sariff{
3093162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3094162922Sariff	int timeout = 1000;
3095162922Sariff	int to = timeout;
3096162922Sariff	uint32_t ctl;
3097162922Sariff
3098162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
3099162922Sariff	ctl |= HDAC_SDCTL_SRST;
3100162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
3101162922Sariff	do {
3102162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
3103162922Sariff		if (ctl & HDAC_SDCTL_SRST)
3104162922Sariff			break;
3105162922Sariff		DELAY(10);
3106162922Sariff	} while (--to);
3107162922Sariff	if (!(ctl & HDAC_SDCTL_SRST)) {
3108162922Sariff		device_printf(sc->dev, "timeout in reset\n");
3109162922Sariff	}
3110162922Sariff	ctl &= ~HDAC_SDCTL_SRST;
3111162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
3112162922Sariff	to = timeout;
3113162922Sariff	do {
3114162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
3115162922Sariff		if (!(ctl & HDAC_SDCTL_SRST))
3116162922Sariff			break;
3117162922Sariff		DELAY(10);
3118162922Sariff	} while (--to);
3119163057Sariff	if (ctl & HDAC_SDCTL_SRST)
3120162922Sariff		device_printf(sc->dev, "can't reset!\n");
3121162922Sariff}
3122162922Sariff
3123162922Sariffstatic void
3124162922Sariffhdac_stream_setid(struct hdac_chan *ch)
3125162922Sariff{
3126162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3127162922Sariff	uint32_t ctl;
3128162922Sariff
3129162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2);
3130162922Sariff	ctl &= ~HDAC_SDCTL2_STRM_MASK;
3131162922Sariff	ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT;
3132162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl);
3133162922Sariff}
3134162922Sariff
3135162922Sariffstatic void
3136162922Sariffhdac_bdl_setup(struct hdac_chan *ch)
3137162922Sariff{
3138162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3139164614Sariff	struct hdac_bdle *bdle;
3140162922Sariff	uint64_t addr;
3141164614Sariff	uint32_t blksz, blkcnt;
3142162922Sariff	int i;
3143162922Sariff
3144162922Sariff	addr = (uint64_t)sndbuf_getbufaddr(ch->b);
3145164614Sariff	bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr;
3146162922Sariff
3147182999Smav	blksz = ch->blksz;
3148182999Smav	blkcnt = ch->blkcnt;
3149164614Sariff
3150164614Sariff	for (i = 0; i < blkcnt; i++, bdle++) {
3151162922Sariff		bdle->addrl = (uint32_t)addr;
3152162922Sariff		bdle->addrh = (uint32_t)(addr >> 32);
3153164614Sariff		bdle->len = blksz;
3154182999Smav		bdle->ioc = 1;
3155164614Sariff		addr += blksz;
3156162922Sariff	}
3157162922Sariff
3158164614Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt);
3159164614Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1);
3160162922Sariff	addr = ch->bdl_dma.dma_paddr;
3161162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr);
3162162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
3163169277Sariff	if (ch->dmapos != NULL &&
3164169277Sariff	    !(HDAC_READ_4(&sc->mem, HDAC_DPIBLBASE) & 0x00000001)) {
3165169277Sariff		addr = sc->pos_dma.dma_paddr;
3166169277Sariff		HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE,
3167169277Sariff		    ((uint32_t)addr & HDAC_DPLBASE_DPLBASE_MASK) | 0x00000001);
3168169277Sariff		HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, (uint32_t)(addr >> 32));
3169169277Sariff	}
3170162922Sariff}
3171162922Sariff
3172162922Sariffstatic int
3173162922Sariffhdac_bdl_alloc(struct hdac_chan *ch)
3174162922Sariff{
3175162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3176162922Sariff	int rc;
3177162922Sariff
3178162922Sariff	rc = hdac_dma_alloc(sc, &ch->bdl_dma,
3179162922Sariff	    sizeof(struct hdac_bdle) * HDA_BDL_MAX);
3180162922Sariff	if (rc) {
3181162922Sariff		device_printf(sc->dev, "can't alloc bdl\n");
3182162922Sariff		return (rc);
3183162922Sariff	}
3184162922Sariff
3185162922Sariff	return (0);
3186162922Sariff}
3187162922Sariff
3188162922Sariffstatic void
3189162922Sariffhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid,
3190162922Sariff					int index, int lmute, int rmute,
3191162922Sariff					int left, int right, int dir)
3192162922Sariff{
3193162922Sariff	uint16_t v = 0;
3194162922Sariff
3195162922Sariff	if (sc == NULL)
3196162922Sariff		return;
3197162922Sariff
3198162922Sariff	if (left != right || lmute != rmute) {
3199162922Sariff		v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
3200162922Sariff		    (lmute << 7) | left;
3201162922Sariff		hdac_command(sc,
3202164614Sariff		    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
3203162922Sariff		v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
3204162922Sariff		    (rmute << 7) | right;
3205162922Sariff	} else
3206162922Sariff		v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
3207162922Sariff		    (lmute << 7) | left;
3208162922Sariff
3209162922Sariff	hdac_command(sc,
3210162922Sariff	    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
3211162922Sariff}
3212162922Sariff
3213162922Sariffstatic void
3214162922Sariffhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
3215162922Sariff						int left, int right)
3216162922Sariff{
3217162922Sariff	struct hdac_softc *sc;
3218162922Sariff	nid_t nid, cad;
3219162922Sariff	int lmute, rmute;
3220162922Sariff
3221162922Sariff	sc = ctl->widget->devinfo->codec->sc;
3222162922Sariff	cad = ctl->widget->devinfo->codec->cad;
3223162922Sariff	nid = ctl->widget->nid;
3224162922Sariff
3225182999Smav	/* Save new values if valid. */
3226182999Smav	if (mute != HDA_AMP_MUTE_DEFAULT)
3227182999Smav		ctl->muted = mute;
3228182999Smav	if (left != HDA_AMP_VOL_DEFAULT)
3229182999Smav		ctl->left = left;
3230182999Smav	if (right != HDA_AMP_VOL_DEFAULT)
3231182999Smav		ctl->right = right;
3232182999Smav	/* Prepare effective values */
3233182999Smav	if (ctl->forcemute) {
3234182999Smav		lmute = 1;
3235182999Smav		rmute = 1;
3236182999Smav		left = 0;
3237182999Smav		right = 0;
3238182999Smav	} else {
3239162922Sariff		lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
3240162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
3241182999Smav		left = ctl->left;
3242182999Smav		right = ctl->right;
3243162922Sariff	}
3244182999Smav	/* Apply effective values */
3245162922Sariff	if (ctl->dir & HDA_CTL_OUT)
3246162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
3247162922Sariff		    lmute, rmute, left, right, 0);
3248162922Sariff	if (ctl->dir & HDA_CTL_IN)
3249182999Smav    		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
3250162922Sariff		    lmute, rmute, left, right, 1);
3251162922Sariff}
3252162922Sariff
3253162922Sariffstatic void
3254162922Sariffhdac_widget_connection_select(struct hdac_widget *w, uint8_t index)
3255162922Sariff{
3256162922Sariff	if (w == NULL || w->nconns < 1 || index > (w->nconns - 1))
3257162922Sariff		return;
3258162922Sariff	hdac_command(w->devinfo->codec->sc,
3259162922Sariff	    HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad,
3260162922Sariff	    w->nid, index), w->devinfo->codec->cad);
3261162922Sariff	w->selconn = index;
3262162922Sariff}
3263162922Sariff
3264162922Sariff
3265162922Sariff/****************************************************************************
3266162922Sariff * uint32_t hdac_command_sendone_internal
3267162922Sariff *
3268162922Sariff * Wrapper function that sends only one command to a given codec
3269162922Sariff ****************************************************************************/
3270162922Sariffstatic uint32_t
3271162922Sariffhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad)
3272162922Sariff{
3273162922Sariff	struct hdac_command_list cl;
3274162965Sariff	uint32_t response = HDAC_INVALID;
3275162922Sariff
3276163057Sariff	if (!hdac_lockowned(sc))
3277162922Sariff		device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n");
3278162922Sariff	cl.num_commands = 1;
3279162922Sariff	cl.verbs = &verb;
3280162922Sariff	cl.responses = &response;
3281162922Sariff
3282162922Sariff	hdac_command_send_internal(sc, &cl, cad);
3283162922Sariff
3284162922Sariff	return (response);
3285162922Sariff}
3286162922Sariff
3287162922Sariff/****************************************************************************
3288162922Sariff * hdac_command_send_internal
3289162922Sariff *
3290162922Sariff * Send a command list to the codec via the corb. We queue as much verbs as
3291162922Sariff * we can and msleep on the codec. When the interrupt get the responses
3292162922Sariff * back from the rirb, it will wake us up so we can queue the remaining verbs
3293162922Sariff * if any.
3294162922Sariff ****************************************************************************/
3295162922Sariffstatic void
3296162922Sariffhdac_command_send_internal(struct hdac_softc *sc,
3297162922Sariff			struct hdac_command_list *commands, nid_t cad)
3298162922Sariff{
3299162922Sariff	struct hdac_codec *codec;
3300162922Sariff	int corbrp;
3301162922Sariff	uint32_t *corb;
3302162922Sariff	int timeout;
3303162922Sariff	int retry = 10;
3304164614Sariff	struct hdac_rirb *rirb_base;
3305162922Sariff
3306164614Sariff	if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL ||
3307164614Sariff	    commands->num_commands < 1)
3308162922Sariff		return;
3309162922Sariff
3310162922Sariff	codec = sc->codecs[cad];
3311162922Sariff	codec->commands = commands;
3312162922Sariff	codec->responses_received = 0;
3313162922Sariff	codec->verbs_sent = 0;
3314162922Sariff	corb = (uint32_t *)sc->corb_dma.dma_vaddr;
3315162922Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
3316162922Sariff
3317162922Sariff	do {
3318162922Sariff		if (codec->verbs_sent != commands->num_commands) {
3319162922Sariff			/* Queue as many verbs as possible */
3320162922Sariff			corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP);
3321169277Sariff#if 0
3322162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
3323162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
3324169277Sariff#endif
3325162922Sariff			while (codec->verbs_sent != commands->num_commands &&
3326162922Sariff			    ((sc->corb_wp + 1) % sc->corb_size) != corbrp) {
3327162922Sariff				sc->corb_wp++;
3328162922Sariff				sc->corb_wp %= sc->corb_size;
3329162922Sariff				corb[sc->corb_wp] =
3330162922Sariff				    commands->verbs[codec->verbs_sent++];
3331162922Sariff			}
3332162922Sariff
3333162922Sariff			/* Send the verbs to the codecs */
3334169277Sariff#if 0
3335162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
3336162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
3337169277Sariff#endif
3338162922Sariff			HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
3339162922Sariff		}
3340162922Sariff
3341162922Sariff		timeout = 1000;
3342164614Sariff		while (hdac_rirb_flush(sc) == 0 && --timeout)
3343162922Sariff			DELAY(10);
3344162922Sariff	} while ((codec->verbs_sent != commands->num_commands ||
3345164614Sariff	    codec->responses_received != commands->num_commands) && --retry);
3346162922Sariff
3347162922Sariff	if (retry == 0)
3348162922Sariff		device_printf(sc->dev,
3349164614Sariff		    "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n",
3350164614Sariff		    __func__, commands->num_commands, codec->verbs_sent,
3351164614Sariff		    codec->responses_received);
3352162922Sariff
3353164614Sariff	codec->commands = NULL;
3354164614Sariff	codec->responses_received = 0;
3355162922Sariff	codec->verbs_sent = 0;
3356162922Sariff
3357164614Sariff	hdac_unsolq_flush(sc);
3358162922Sariff}
3359162922Sariff
3360162922Sariff
3361162922Sariff/****************************************************************************
3362162922Sariff * Device Methods
3363162922Sariff ****************************************************************************/
3364162922Sariff
3365162922Sariff/****************************************************************************
3366162922Sariff * int hdac_probe(device_t)
3367162922Sariff *
3368162922Sariff * Probe for the presence of an hdac. If none is found, check for a generic
3369162922Sariff * match using the subclass of the device.
3370162922Sariff ****************************************************************************/
3371162922Sariffstatic int
3372162922Sariffhdac_probe(device_t dev)
3373162922Sariff{
3374162922Sariff	int i, result;
3375163257Sariff	uint32_t model;
3376163257Sariff	uint16_t class, subclass;
3377162922Sariff	char desc[64];
3378162922Sariff
3379162922Sariff	model = (uint32_t)pci_get_device(dev) << 16;
3380162922Sariff	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
3381162922Sariff	class = pci_get_class(dev);
3382162922Sariff	subclass = pci_get_subclass(dev);
3383162922Sariff
3384162922Sariff	bzero(desc, sizeof(desc));
3385162922Sariff	result = ENXIO;
3386162922Sariff	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
3387162922Sariff		if (hdac_devices[i].model == model) {
3388162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3389162922Sariff		    	result = BUS_PROBE_DEFAULT;
3390162922Sariff			break;
3391162922Sariff		}
3392163257Sariff		if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
3393162922Sariff		    class == PCIC_MULTIMEDIA &&
3394162922Sariff		    subclass == PCIS_MULTIMEDIA_HDA) {
3395162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3396162922Sariff		    	result = BUS_PROBE_GENERIC;
3397162922Sariff			break;
3398162922Sariff		}
3399162922Sariff	}
3400162922Sariff	if (result == ENXIO && class == PCIC_MULTIMEDIA &&
3401162922Sariff	    subclass == PCIS_MULTIMEDIA_HDA) {
3402162922Sariff		strlcpy(desc, "Generic", sizeof(desc));
3403162922Sariff	    	result = BUS_PROBE_GENERIC;
3404162922Sariff	}
3405162922Sariff	if (result != ENXIO) {
3406162922Sariff		strlcat(desc, " High Definition Audio Controller",
3407162922Sariff		    sizeof(desc));
3408162922Sariff		device_set_desc_copy(dev, desc);
3409162922Sariff	}
3410162922Sariff
3411162922Sariff	return (result);
3412162922Sariff}
3413162922Sariff
3414162922Sariffstatic void *
3415162922Sariffhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
3416162922Sariff					struct pcm_channel *c, int dir)
3417162922Sariff{
3418182999Smav	struct hdac_pcm_devinfo *pdevinfo = data;
3419182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3420162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3421162922Sariff	struct hdac_chan *ch;
3422182999Smav	int i, ord = 0, chid;
3423162922Sariff
3424162922Sariff	hdac_lock(sc);
3425182999Smav
3426182999Smav	chid = (dir == PCMDIR_PLAY)?pdevinfo->play:pdevinfo->rec;
3427182999Smav	ch = &sc->chans[chid];
3428182999Smav	for (i = 0; i < sc->num_chans && i < chid; i++) {
3429182999Smav		if (ch->dir == sc->chans[i].dir)
3430182999Smav			ord++;
3431182999Smav	}
3432162922Sariff	if (dir == PCMDIR_PLAY) {
3433182999Smav		ch->off = (sc->num_iss + ord) << 5;
3434162922Sariff	} else {
3435182999Smav		ch->off = ord << 5;
3436162922Sariff	}
3437182999Smav
3438162922Sariff	if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
3439162922Sariff		ch->caps.minspeed = ch->caps.maxspeed = 48000;
3440162922Sariff		ch->pcmrates[0] = 48000;
3441162922Sariff		ch->pcmrates[1] = 0;
3442162922Sariff	}
3443169277Sariff	if (sc->pos_dma.dma_vaddr != NULL)
3444169277Sariff		ch->dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr +
3445169277Sariff		    (sc->streamcnt * 8));
3446169277Sariff	else
3447169277Sariff		ch->dmapos = NULL;
3448169277Sariff	ch->sid = ++sc->streamcnt;
3449169277Sariff	ch->dir = dir;
3450162922Sariff	ch->b = b;
3451162922Sariff	ch->c = c;
3452182999Smav	ch->blksz = pdevinfo->chan_size / pdevinfo->chan_blkcnt;
3453182999Smav	ch->blkcnt = pdevinfo->chan_blkcnt;
3454162922Sariff	hdac_unlock(sc);
3455162922Sariff
3456162922Sariff	if (hdac_bdl_alloc(ch) != 0) {
3457162922Sariff		ch->blkcnt = 0;
3458162922Sariff		return (NULL);
3459162922Sariff	}
3460162922Sariff
3461169277Sariff	if (sndbuf_alloc(ch->b, sc->chan_dmat,
3462171330Sariff	    (sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0,
3463182999Smav	    pdevinfo->chan_size) != 0)
3464162922Sariff		return (NULL);
3465162922Sariff
3466162922Sariff	return (ch);
3467162922Sariff}
3468162922Sariff
3469162922Sariffstatic int
3470162922Sariffhdac_channel_setformat(kobj_t obj, void *data, uint32_t format)
3471162922Sariff{
3472162922Sariff	struct hdac_chan *ch = data;
3473162922Sariff	int i;
3474162922Sariff
3475162922Sariff	for (i = 0; ch->caps.fmtlist[i] != 0; i++) {
3476162922Sariff		if (format == ch->caps.fmtlist[i]) {
3477162922Sariff			ch->fmt = format;
3478162922Sariff			return (0);
3479162922Sariff		}
3480162922Sariff	}
3481162922Sariff
3482162922Sariff	return (EINVAL);
3483162922Sariff}
3484162922Sariff
3485193640Sariffstatic uint32_t
3486162922Sariffhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed)
3487162922Sariff{
3488162922Sariff	struct hdac_chan *ch = data;
3489164614Sariff	uint32_t spd = 0, threshold;
3490162922Sariff	int i;
3491162922Sariff
3492162922Sariff	for (i = 0; ch->pcmrates[i] != 0; i++) {
3493162922Sariff		spd = ch->pcmrates[i];
3494164614Sariff		threshold = spd + ((ch->pcmrates[i + 1] != 0) ?
3495164614Sariff		    ((ch->pcmrates[i + 1] - spd) >> 1) : 0);
3496164614Sariff		if (speed < threshold)
3497162922Sariff			break;
3498162922Sariff	}
3499162922Sariff
3500164614Sariff	if (spd == 0)	/* impossible */
3501162922Sariff		ch->spd = 48000;
3502162922Sariff	else
3503162922Sariff		ch->spd = spd;
3504162922Sariff
3505162922Sariff	return (ch->spd);
3506162922Sariff}
3507162922Sariff
3508162922Sariffstatic void
3509162922Sariffhdac_stream_setup(struct hdac_chan *ch)
3510162922Sariff{
3511162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3512182999Smav	struct hdac_audio_as *as = &ch->devinfo->function.audio.as[ch->as];
3513173817Sariff	struct hdac_widget *w;
3514182999Smav	int i, chn, totalchn, c;
3515162922Sariff	nid_t cad = ch->devinfo->codec->cad;
3516182999Smav	uint16_t fmt, dfmt;
3517202127Smav	uint16_t chmap[2][5] = {{ 0x0010, 0x0001, 0x0201, 0x0231, 0x0231 }, /* 5.1 */
3518202127Smav				{ 0x0010, 0x0001, 0x2001, 0x2031, 0x2431 }};/* 7.1 */
3519202127Smav	int map = -1;
3520162922Sariff
3521202127Smav	totalchn = AFMT_CHANNEL(ch->fmt);
3522183097Smav	HDA_BOOTHVERBOSE(
3523182999Smav		device_printf(ch->pdevinfo->dev,
3524182999Smav		    "PCMDIR_%s: Stream setup fmt=%08x speed=%d\n",
3525182999Smav		    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3526182999Smav		    ch->fmt, ch->spd);
3527182999Smav	);
3528162922Sariff	fmt = 0;
3529162922Sariff	if (ch->fmt & AFMT_S16_LE)
3530162922Sariff		fmt |= ch->bit16 << 4;
3531162922Sariff	else if (ch->fmt & AFMT_S32_LE)
3532162922Sariff		fmt |= ch->bit32 << 4;
3533162922Sariff	else
3534162922Sariff		fmt |= 1 << 4;
3535162922Sariff	for (i = 0; i < HDA_RATE_TAB_LEN; i++) {
3536162922Sariff		if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) {
3537162922Sariff			fmt |= hda_rate_tab[i].base;
3538162922Sariff			fmt |= hda_rate_tab[i].mul;
3539162922Sariff			fmt |= hda_rate_tab[i].div;
3540162922Sariff			break;
3541162922Sariff		}
3542162922Sariff	}
3543202127Smav	fmt |= (totalchn - 1);
3544162922Sariff
3545202127Smav	/* Set channel mapping for known speaker setups. */
3546202127Smav	if (as->pinset == 0x0007 || as->pinset == 0x0013) /* Standard 5.1 */
3547202127Smav		map = 0;
3548202127Smav	else if (as->pinset == 0x0017) /* Standard 7.1 */
3549202127Smav		map = 1;
3550162922Sariff
3551162922Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
3552182999Smav
3553182999Smav	dfmt = HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN;
3554182999Smav	if (ch->fmt & AFMT_AC3)
3555182999Smav		dfmt |= HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO;
3556162922Sariff
3557173817Sariff	chn = 0;
3558162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
3559173817Sariff		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3560173817Sariff		if (w == NULL)
3561173817Sariff			continue;
3562182999Smav
3563202127Smav		/* If HP redirection is enabled, but failed to use same
3564202127Smav		   DAC, make last DAC to duplicate first one. */
3565204351Smav		if (as->fakeredir && i == (as->pincnt - 1)) {
3566202127Smav			c = (ch->sid << 4);
3567202127Smav		} else {
3568202127Smav			if (map >= 0) /* Map known speaker setups. */
3569202127Smav				chn = (((chmap[map][totalchn / 2] >> i * 4) &
3570202127Smav				    0xf) - 1) * 2;
3571202127Smav			if (chn < 0 || chn >= totalchn) {
3572202127Smav				c = 0;
3573202127Smav			} else {
3574202127Smav				c = (ch->sid << 4) | chn;
3575202127Smav			}
3576202127Smav		}
3577183097Smav		HDA_BOOTHVERBOSE(
3578182999Smav			device_printf(ch->pdevinfo->dev,
3579182999Smav			    "PCMDIR_%s: Stream setup nid=%d: "
3580202127Smav			    "fmt=0x%04x, dfmt=0x%04x, chan=0x%04x\n",
3581162922Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3582202127Smav			    ch->io[i], fmt, dfmt, c);
3583162922Sariff		);
3584162922Sariff		hdac_command(sc,
3585162922Sariff		    HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
3586182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
3587174025Sariff			hdac_command(sc,
3588182999Smav			    HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], dfmt),
3589174025Sariff			    cad);
3590182999Smav		}
3591182999Smav		hdac_command(sc,
3592182999Smav		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], c), cad);
3593197611Smav#if 0
3594197611Smav		hdac_command(sc,
3595197611Smav		    HDA_CMD_SET_CONV_CHAN_COUNT(cad, ch->io[i], 1), cad);
3596197611Smav		hdac_command(sc,
3597197611Smav		    HDA_CMD_SET_HDMI_CHAN_SLOT(cad, ch->io[i], 0x00), cad);
3598197611Smav		hdac_command(sc,
3599197611Smav		    HDA_CMD_SET_HDMI_CHAN_SLOT(cad, ch->io[i], 0x11), cad);
3600197611Smav#endif
3601202127Smav		chn += HDA_PARAM_AUDIO_WIDGET_CAP_CC(w->param.widget_cap) + 1;
3602162922Sariff	}
3603162922Sariff}
3604162922Sariff
3605202156Smav/*
3606202156Smav * Greatest Common Divisor.
3607202156Smav */
3608202156Smavstatic unsigned
3609202156Smavgcd(unsigned a, unsigned b)
3610202156Smav{
3611202156Smav	u_int c;
3612202156Smav
3613202156Smav	while (b != 0) {
3614202156Smav		c = a;
3615202156Smav		a = b;
3616202156Smav		b = (c % b);
3617202156Smav	}
3618202156Smav	return (a);
3619202156Smav}
3620202156Smav
3621202156Smav/*
3622202156Smav * Least Common Multiple.
3623202156Smav */
3624202156Smavstatic unsigned
3625202156Smavlcm(unsigned a, unsigned b)
3626202156Smav{
3627202156Smav
3628202156Smav	return ((a * b) / gcd(a, b));
3629202156Smav}
3630202156Smav
3631162922Sariffstatic int
3632167648Sariffhdac_channel_setfragments(kobj_t obj, void *data,
3633167648Sariff					uint32_t blksz, uint32_t blkcnt)
3634162922Sariff{
3635162922Sariff	struct hdac_chan *ch = data;
3636164614Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3637162922Sariff
3638202156Smav	blksz -= blksz % lcm(HDAC_DMA_ALIGNMENT, sndbuf_getalign(ch->b));
3639162922Sariff
3640167648Sariff	if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN))
3641167648Sariff		blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN;
3642167648Sariff	if (blksz < HDA_BLK_MIN)
3643167648Sariff		blksz = HDA_BLK_MIN;
3644167648Sariff	if (blkcnt > HDA_BDL_MAX)
3645167648Sariff		blkcnt = HDA_BDL_MAX;
3646167648Sariff	if (blkcnt < HDA_BDL_MIN)
3647167648Sariff		blkcnt = HDA_BDL_MIN;
3648164614Sariff
3649167648Sariff	while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) {
3650167648Sariff		if ((blkcnt >> 1) >= HDA_BDL_MIN)
3651167648Sariff			blkcnt >>= 1;
3652167648Sariff		else if ((blksz >> 1) >= HDA_BLK_MIN)
3653167648Sariff			blksz >>= 1;
3654167648Sariff		else
3655167648Sariff			break;
3656167648Sariff	}
3657167648Sariff
3658164614Sariff	if ((sndbuf_getblksz(ch->b) != blksz ||
3659167648Sariff	    sndbuf_getblkcnt(ch->b) != blkcnt) &&
3660167648Sariff	    sndbuf_resize(ch->b, blkcnt, blksz) != 0)
3661164614Sariff		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
3662167648Sariff		    __func__, blksz, blkcnt);
3663164614Sariff
3664164614Sariff	ch->blksz = sndbuf_getblksz(ch->b);
3665167648Sariff	ch->blkcnt = sndbuf_getblkcnt(ch->b);
3666164614Sariff
3667193640Sariff	return (0);
3668167648Sariff}
3669167648Sariff
3670193640Sariffstatic uint32_t
3671167648Sariffhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
3672167648Sariff{
3673167648Sariff	struct hdac_chan *ch = data;
3674167648Sariff
3675182999Smav	hdac_channel_setfragments(obj, data, blksz, ch->pdevinfo->chan_blkcnt);
3676167648Sariff
3677162922Sariff	return (ch->blksz);
3678162922Sariff}
3679162922Sariff
3680162922Sariffstatic void
3681162922Sariffhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
3682162922Sariff{
3683162922Sariff	struct hdac_devinfo *devinfo = ch->devinfo;
3684182999Smav	struct hdac_widget *w;
3685162922Sariff	nid_t cad = devinfo->codec->cad;
3686162922Sariff	int i;
3687162922Sariff
3688162922Sariff	hdac_stream_stop(ch);
3689162922Sariff
3690162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
3691182999Smav		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3692182999Smav		if (w == NULL)
3693182999Smav			continue;
3694182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
3695182999Smav			hdac_command(sc,
3696182999Smav			    HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], 0),
3697182999Smav			    cad);
3698182999Smav		}
3699162922Sariff		hdac_command(sc,
3700162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
3701162922Sariff		    0), cad);
3702162922Sariff	}
3703162922Sariff}
3704162922Sariff
3705162922Sariffstatic void
3706162922Sariffhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch)
3707162922Sariff{
3708162922Sariff	ch->ptr = 0;
3709162922Sariff	ch->prevptr = 0;
3710162922Sariff	hdac_stream_stop(ch);
3711162922Sariff	hdac_stream_reset(ch);
3712162922Sariff	hdac_bdl_setup(ch);
3713162922Sariff	hdac_stream_setid(ch);
3714162922Sariff	hdac_stream_setup(ch);
3715162922Sariff	hdac_stream_start(ch);
3716162922Sariff}
3717162922Sariff
3718162922Sariffstatic int
3719162922Sariffhdac_channel_trigger(kobj_t obj, void *data, int go)
3720162922Sariff{
3721162922Sariff	struct hdac_chan *ch = data;
3722162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3723162922Sariff
3724170521Sariff	if (!PCMTRIG_COMMON(go))
3725170521Sariff		return (0);
3726170521Sariff
3727162922Sariff	hdac_lock(sc);
3728162922Sariff	switch (go) {
3729162922Sariff	case PCMTRIG_START:
3730162922Sariff		hdac_channel_start(sc, ch);
3731162922Sariff		break;
3732162922Sariff	case PCMTRIG_STOP:
3733162922Sariff	case PCMTRIG_ABORT:
3734162922Sariff		hdac_channel_stop(sc, ch);
3735162922Sariff		break;
3736167610Sariff	default:
3737167610Sariff		break;
3738162922Sariff	}
3739162922Sariff	hdac_unlock(sc);
3740162922Sariff
3741162922Sariff	return (0);
3742162922Sariff}
3743162922Sariff
3744193640Sariffstatic uint32_t
3745162922Sariffhdac_channel_getptr(kobj_t obj, void *data)
3746162922Sariff{
3747162922Sariff	struct hdac_chan *ch = data;
3748162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3749162922Sariff	uint32_t ptr;
3750162922Sariff
3751162922Sariff	hdac_lock(sc);
3752164614Sariff	if (sc->polling != 0)
3753164614Sariff		ptr = ch->ptr;
3754169277Sariff	else if (ch->dmapos != NULL)
3755169277Sariff		ptr = *(ch->dmapos);
3756164614Sariff	else
3757164614Sariff		ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB);
3758162922Sariff	hdac_unlock(sc);
3759162922Sariff
3760164614Sariff	/*
3761164614Sariff	 * Round to available space and force 128 bytes aligment.
3762164614Sariff	 */
3763164614Sariff	ptr %= ch->blksz * ch->blkcnt;
3764167648Sariff	ptr &= HDA_BLK_ALIGN;
3765162922Sariff
3766162922Sariff	return (ptr);
3767162922Sariff}
3768162922Sariff
3769162922Sariffstatic struct pcmchan_caps *
3770162922Sariffhdac_channel_getcaps(kobj_t obj, void *data)
3771162922Sariff{
3772162922Sariff	return (&((struct hdac_chan *)data)->caps);
3773162922Sariff}
3774162922Sariff
3775162922Sariffstatic kobj_method_t hdac_channel_methods[] = {
3776162922Sariff	KOBJMETHOD(channel_init,		hdac_channel_init),
3777162922Sariff	KOBJMETHOD(channel_setformat,		hdac_channel_setformat),
3778162922Sariff	KOBJMETHOD(channel_setspeed,		hdac_channel_setspeed),
3779162922Sariff	KOBJMETHOD(channel_setblocksize,	hdac_channel_setblocksize),
3780167648Sariff	KOBJMETHOD(channel_setfragments,	hdac_channel_setfragments),
3781162922Sariff	KOBJMETHOD(channel_trigger,		hdac_channel_trigger),
3782162922Sariff	KOBJMETHOD(channel_getptr,		hdac_channel_getptr),
3783162922Sariff	KOBJMETHOD(channel_getcaps,		hdac_channel_getcaps),
3784193640Sariff	KOBJMETHOD_END
3785162922Sariff};
3786162922SariffCHANNEL_DECLARE(hdac_channel);
3787162922Sariff
3788162922Sariffstatic int
3789162922Sariffhdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
3790162922Sariff{
3791182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3792182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3793162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3794162922Sariff	struct hdac_widget *w, *cw;
3795162922Sariff	struct hdac_audio_ctl *ctl;
3796162922Sariff	uint32_t mask, recmask, id;
3797162922Sariff	int i, j, softpcmvol;
3798162922Sariff
3799162922Sariff	hdac_lock(sc);
3800162922Sariff
3801182999Smav	/* Make sure that in case of soft volume it won't stay muted. */
3802182999Smav	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
3803182999Smav		pdevinfo->left[i] = 100;
3804182999Smav		pdevinfo->right[i] = 100;
3805182999Smav	}
3806182999Smav
3807162922Sariff	mask = 0;
3808162922Sariff	recmask = 0;
3809182999Smav	id = hdac_codec_id(devinfo->codec);
3810162922Sariff
3811182999Smav	/* Declate EAPD as ogain control. */
3812182999Smav	if (pdevinfo->play >= 0) {
3813182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3814182999Smav			w = hdac_widget_get(devinfo, i);
3815182999Smav			if (w == NULL || w->enable == 0)
3816182999Smav				continue;
3817182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3818182999Smav			    w->param.eapdbtl == HDAC_INVALID ||
3819182999Smav			    w->bindas != sc->chans[pdevinfo->play].as)
3820182999Smav				continue;
3821182999Smav			mask |= SOUND_MASK_OGAIN;
3822162922Sariff			break;
3823162922Sariff		}
3824162922Sariff	}
3825162922Sariff
3826182999Smav	/* Declare volume controls assigned to this association. */
3827162922Sariff	i = 0;
3828162922Sariff	ctl = NULL;
3829162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3830182999Smav		if (ctl->enable == 0)
3831162922Sariff			continue;
3832182999Smav		if ((pdevinfo->play >= 0 &&
3833182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
3834182999Smav		    (pdevinfo->rec >= 0 &&
3835182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
3836182999Smav		    (ctl->widget->bindas == -2 && pdevinfo->index == 0))
3837182999Smav			mask |= ctl->ossmask;
3838162922Sariff	}
3839162922Sariff
3840182999Smav	/* Declare record sources available to this association. */
3841182999Smav	if (pdevinfo->rec >= 0) {
3842182999Smav		struct hdac_chan *ch = &sc->chans[pdevinfo->rec];
3843182999Smav		for (i = 0; ch->io[i] != -1; i++) {
3844182999Smav			w = hdac_widget_get(devinfo, ch->io[i]);
3845182999Smav			if (w == NULL || w->enable == 0)
3846182999Smav				continue;
3847182999Smav			for (j = 0; j < w->nconns; j++) {
3848182999Smav				if (w->connsenable[j] == 0)
3849162922Sariff					continue;
3850182999Smav				cw = hdac_widget_get(devinfo, w->conns[j]);
3851182999Smav				if (cw == NULL || cw->enable == 0)
3852165992Sariff					continue;
3853182999Smav				if (cw->bindas != sc->chans[pdevinfo->rec].as &&
3854182999Smav				    cw->bindas != -2)
3855165992Sariff					continue;
3856182999Smav				recmask |= cw->ossmask;
3857165992Sariff			}
3858182999Smav		}
3859182999Smav	}
3860182999Smav
3861185230Smav	/* Declare soft PCM volume if needed. */
3862193640Sariff	if (pdevinfo->play >= 0) {
3863182999Smav		ctl = NULL;
3864182999Smav		if ((mask & SOUND_MASK_PCM) == 0 ||
3865182999Smav		    (devinfo->function.audio.quirks & HDA_QUIRK_SOFTPCMVOL)) {
3866182999Smav			softpcmvol = 1;
3867182999Smav			mask |= SOUND_MASK_PCM;
3868162922Sariff		} else {
3869182999Smav			softpcmvol = 0;
3870182999Smav			i = 0;
3871182999Smav			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3872182999Smav				if (ctl->enable == 0)
3873162922Sariff					continue;
3874182999Smav				if (ctl->widget->bindas != sc->chans[pdevinfo->play].as &&
3875182999Smav				    (ctl->widget->bindas != -2 || pdevinfo->index != 0))
3876162922Sariff					continue;
3877182999Smav				if (!(ctl->ossmask & SOUND_MASK_PCM))
3878182999Smav					continue;
3879182999Smav				if (ctl->step > 0)
3880182999Smav					break;
3881162922Sariff			}
3882162922Sariff		}
3883182999Smav
3884182999Smav		if (softpcmvol == 1 || ctl == NULL) {
3885182999Smav			pcm_setflags(pdevinfo->dev, pcm_getflags(pdevinfo->dev) | SD_F_SOFTPCMVOL);
3886182999Smav			HDA_BOOTVERBOSE(
3887182999Smav				device_printf(pdevinfo->dev,
3888182999Smav				    "%s Soft PCM volume\n",
3889182999Smav				    (softpcmvol == 1) ? "Forcing" : "Enabling");
3890182999Smav			);
3891182999Smav		}
3892185230Smav	}
3893182999Smav
3894185230Smav	/* Declare master volume if needed. */
3895185230Smav	if (pdevinfo->play >= 0) {
3896185230Smav		if ((mask & (SOUND_MASK_VOLUME | SOUND_MASK_PCM)) ==
3897185230Smav		    SOUND_MASK_PCM) {
3898182999Smav			mask |= SOUND_MASK_VOLUME;
3899182999Smav			mix_setparentchild(m, SOUND_MIXER_VOLUME,
3900182999Smav			    SOUND_MASK_PCM);
3901182999Smav			mix_setrealdev(m, SOUND_MIXER_VOLUME,
3902182999Smav			    SOUND_MIXER_NONE);
3903182999Smav			HDA_BOOTVERBOSE(
3904182999Smav				device_printf(pdevinfo->dev,
3905182999Smav				    "Forcing master volume with PCM\n");
3906182999Smav			);
3907182999Smav		}
3908162922Sariff	}
3909162922Sariff
3910169277Sariff	recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3911169277Sariff	mask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3912162922Sariff
3913162922Sariff	mix_setrecdevs(m, recmask);
3914162922Sariff	mix_setdevs(m, mask);
3915162922Sariff
3916162922Sariff	hdac_unlock(sc);
3917162922Sariff
3918162922Sariff	return (0);
3919162922Sariff}
3920162922Sariff
3921162922Sariffstatic int
3922162922Sariffhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
3923162922Sariff					unsigned left, unsigned right)
3924162922Sariff{
3925182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3926182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3927162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3928162922Sariff	struct hdac_widget *w;
3929162922Sariff	struct hdac_audio_ctl *ctl;
3930182999Smav	uint32_t mute;
3931182999Smav	int lvol, rvol;
3932182999Smav	int i, j;
3933162922Sariff
3934162922Sariff	hdac_lock(sc);
3935182999Smav	/* Save new values. */
3936182999Smav	pdevinfo->left[dev] = left;
3937182999Smav	pdevinfo->right[dev] = right;
3938182999Smav
3939182999Smav	/* 'ogain' is the special case implemented with EAPD. */
3940162922Sariff	if (dev == SOUND_MIXER_OGAIN) {
3941163257Sariff		uint32_t orig;
3942182999Smav		w = NULL;
3943182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3944182999Smav			w = hdac_widget_get(devinfo, i);
3945182999Smav			if (w == NULL || w->enable == 0)
3946182999Smav				continue;
3947182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3948182999Smav			    w->param.eapdbtl == HDAC_INVALID)
3949182999Smav				continue;
3950182999Smav			break;
3951162922Sariff		}
3952182999Smav		if (i >= devinfo->endnode) {
3953162922Sariff			hdac_unlock(sc);
3954162922Sariff			return (-1);
3955162922Sariff		}
3956163257Sariff		orig = w->param.eapdbtl;
3957163432Sariff		if (left == 0)
3958162922Sariff			w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3959162922Sariff		else
3960162922Sariff			w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3961163257Sariff		if (orig != w->param.eapdbtl) {
3962163432Sariff			uint32_t val;
3963163432Sariff
3964163432Sariff			val = w->param.eapdbtl;
3965163432Sariff			if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV)
3966163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3967163257Sariff			hdac_command(sc,
3968163257Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad,
3969163432Sariff			    w->nid, val), devinfo->codec->cad);
3970163257Sariff		}
3971162922Sariff		hdac_unlock(sc);
3972162922Sariff		return (left | (left << 8));
3973162922Sariff	}
3974162922Sariff
3975182999Smav	/* Recalculate all controls related to this OSS device. */
3976162922Sariff	i = 0;
3977162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3978182999Smav		if (ctl->enable == 0 ||
3979162922Sariff		    !(ctl->ossmask & (1 << dev)))
3980162922Sariff			continue;
3981182999Smav		if (!((pdevinfo->play >= 0 &&
3982182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
3983182999Smav		    (pdevinfo->rec >= 0 &&
3984182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
3985182999Smav		    ctl->widget->bindas == -2))
3986182999Smav			continue;
3987182999Smav
3988182999Smav		lvol = 100;
3989182999Smav		rvol = 100;
3990182999Smav		for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
3991182999Smav			if (ctl->ossmask & (1 << j)) {
3992182999Smav				lvol = lvol * pdevinfo->left[j] / 100;
3993182999Smav				rvol = rvol * pdevinfo->right[j] / 100;
3994162922Sariff			}
3995162922Sariff		}
3996202789Smav		mute = (lvol == 0) ? HDA_AMP_MUTE_LEFT : 0;
3997202789Smav		mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT : 0;
3998182999Smav		lvol = (lvol * ctl->step + 50) / 100;
3999182999Smav		rvol = (rvol * ctl->step + 50) / 100;
4000162922Sariff		hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
4001162922Sariff	}
4002162922Sariff	hdac_unlock(sc);
4003162922Sariff
4004162922Sariff	return (left | (right << 8));
4005162922Sariff}
4006162922Sariff
4007182999Smav/*
4008182999Smav * Commutate specified record source.
4009182999Smav */
4010182999Smavstatic uint32_t
4011182999Smavhdac_audio_ctl_recsel_comm(struct hdac_pcm_devinfo *pdevinfo, uint32_t src, nid_t nid, int depth)
4012162922Sariff{
4013182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
4014162922Sariff	struct hdac_widget *w, *cw;
4015182999Smav	struct hdac_audio_ctl *ctl;
4016182999Smav	char buf[64];
4017182999Smav	int i, muted;
4018182999Smav	uint32_t res = 0;
4019162922Sariff
4020182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
4021182999Smav		return (0);
4022182999Smav
4023182999Smav	w = hdac_widget_get(devinfo, nid);
4024182999Smav	if (w == NULL || w->enable == 0)
4025182999Smav		return (0);
4026182999Smav
4027182999Smav	for (i = 0; i < w->nconns; i++) {
4028182999Smav		if (w->connsenable[i] == 0)
4029182999Smav			continue;
4030182999Smav		cw = hdac_widget_get(devinfo, w->conns[i]);
4031182999Smav		if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
4032182999Smav			continue;
4033182999Smav		/* Call recursively to trace signal to it's source if needed. */
4034182999Smav		if ((src & cw->ossmask) != 0) {
4035182999Smav			if (cw->ossdev < 0) {
4036182999Smav				res |= hdac_audio_ctl_recsel_comm(pdevinfo, src,
4037182999Smav				    w->conns[i], depth + 1);
4038182999Smav			} else {
4039182999Smav				res |= cw->ossmask;
4040182999Smav			}
4041182999Smav		}
4042182999Smav		/* We have two special cases: mixers and others (selectors). */
4043182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
4044182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
4045182999Smav			    w->nid, HDA_CTL_IN, i, 1);
4046182999Smav			if (ctl == NULL)
4047182999Smav				continue;
4048182999Smav			/* If we have input control on this node mute them
4049182999Smav			 * according to requested sources. */
4050182999Smav			muted = (src & cw->ossmask) ? 0 : 1;
4051182999Smav	    		if (muted != ctl->forcemute) {
4052182999Smav				ctl->forcemute = muted;
4053182999Smav				hdac_audio_ctl_amp_set(ctl,
4054182999Smav				    HDA_AMP_MUTE_DEFAULT,
4055182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
4056182999Smav			}
4057183097Smav			HDA_BOOTHVERBOSE(
4058182999Smav				device_printf(pdevinfo->dev,
4059182999Smav				    "Recsel (%s): nid %d source %d %s\n",
4060182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(
4061182999Smav				    src, buf, sizeof(buf)),
4062182999Smav				    nid, i, muted?"mute":"unmute");
4063182999Smav			);
4064182999Smav		} else {
4065182999Smav			if (w->nconns == 1)
4066182999Smav				break;
4067182999Smav			if ((src & cw->ossmask) == 0)
4068182999Smav				continue;
4069182999Smav			/* If we found requested source - select it and exit. */
4070182999Smav			hdac_widget_connection_select(w, i);
4071183097Smav			HDA_BOOTHVERBOSE(
4072182999Smav				device_printf(pdevinfo->dev,
4073182999Smav				    "Recsel (%s): nid %d source %d select\n",
4074182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(
4075182999Smav			    	    src, buf, sizeof(buf)),
4076182999Smav				    nid, i);
4077182999Smav			);
4078162922Sariff			break;
4079162922Sariff		}
4080162922Sariff	}
4081182999Smav	return (res);
4082182999Smav}
4083162922Sariff
4084182999Smavstatic uint32_t
4085182999Smavhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
4086182999Smav{
4087182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
4088182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
4089182999Smav	struct hdac_widget *w;
4090182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
4091182999Smav	struct hdac_chan *ch;
4092182999Smav	int i;
4093182999Smav	uint32_t ret = 0xffffffff;
4094182999Smav
4095162922Sariff	hdac_lock(sc);
4096162922Sariff
4097182999Smav	/* Commutate requested recsrc for each ADC. */
4098182999Smav	ch = &sc->chans[pdevinfo->rec];
4099182999Smav	for (i = 0; ch->io[i] != -1; i++) {
4100182999Smav		w = hdac_widget_get(devinfo, ch->io[i]);
4101162965Sariff		if (w == NULL || w->enable == 0)
4102162922Sariff			continue;
4103182999Smav		ret &= hdac_audio_ctl_recsel_comm(pdevinfo, src, ch->io[i], 0);
4104162922Sariff	}
4105162922Sariff
4106162922Sariff	hdac_unlock(sc);
4107162922Sariff
4108182999Smav	return ((ret == 0xffffffff)? 0 : ret);
4109162922Sariff}
4110162922Sariff
4111162922Sariffstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
4112162922Sariff	KOBJMETHOD(mixer_init,		hdac_audio_ctl_ossmixer_init),
4113162922Sariff	KOBJMETHOD(mixer_set,		hdac_audio_ctl_ossmixer_set),
4114162922Sariff	KOBJMETHOD(mixer_setrecsrc,	hdac_audio_ctl_ossmixer_setrecsrc),
4115193640Sariff	KOBJMETHOD_END
4116162922Sariff};
4117162922SariffMIXER_DECLARE(hdac_audio_ctl_ossmixer);
4118162922Sariff
4119171141Sariffstatic void
4120171141Sariffhdac_unsolq_task(void *context, int pending)
4121171141Sariff{
4122171141Sariff	struct hdac_softc *sc;
4123171141Sariff
4124171141Sariff	sc = (struct hdac_softc *)context;
4125171141Sariff
4126171141Sariff	hdac_lock(sc);
4127171141Sariff	hdac_unsolq_flush(sc);
4128171141Sariff	hdac_unlock(sc);
4129171141Sariff}
4130171141Sariff
4131162922Sariff/****************************************************************************
4132162922Sariff * int hdac_attach(device_t)
4133162922Sariff *
4134162922Sariff * Attach the device into the kernel. Interrupts usually won't be enabled
4135162922Sariff * when this function is called. Setup everything that doesn't require
4136162922Sariff * interrupts and defer probing of codecs until interrupts are enabled.
4137162922Sariff ****************************************************************************/
4138162922Sariffstatic int
4139162922Sariffhdac_attach(device_t dev)
4140162922Sariff{
4141162922Sariff	struct hdac_softc *sc;
4142162922Sariff	int result;
4143189086Smav	int i, devid = -1;
4144189086Smav	uint32_t model;
4145189086Smav	uint16_t class, subclass;
4146169277Sariff	uint16_t vendor;
4147169277Sariff	uint8_t v;
4148162922Sariff
4149223118Sjoel	HDA_BOOTVERBOSE(
4150223118Sjoel		device_printf(dev, "HDA Driver Revision: %s\n",
4151223118Sjoel		    HDA_DRV_TEST_REV);
4152223118Sjoel	);
4153182999Smav
4154189086Smav	model = (uint32_t)pci_get_device(dev) << 16;
4155189086Smav	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
4156189086Smav	class = pci_get_class(dev);
4157189086Smav	subclass = pci_get_subclass(dev);
4158189086Smav
4159189086Smav	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
4160189086Smav		if (hdac_devices[i].model == model) {
4161189086Smav			devid = i;
4162189086Smav			break;
4163189086Smav		}
4164189086Smav		if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
4165189086Smav		    class == PCIC_MULTIMEDIA &&
4166189086Smav		    subclass == PCIS_MULTIMEDIA_HDA) {
4167189086Smav			devid = i;
4168189086Smav			break;
4169189086Smav		}
4170189086Smav	}
4171189086Smav
4172182999Smav	sc = device_get_softc(dev);
4173163057Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
4174162922Sariff	sc->dev = dev;
4175163257Sariff	sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
4176163257Sariff	sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff;
4177169277Sariff	vendor = pci_get_vendor(dev);
4178162922Sariff
4179165281Sariff	if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) {
4180165281Sariff		/* Screw nx6325 - subdevice/subvendor swapped */
4181165281Sariff		sc->pci_subvendor = HP_NX6325_SUBVENDOR;
4182165281Sariff	}
4183165281Sariff
4184164614Sariff	callout_init(&sc->poll_hda, CALLOUT_MPSAFE);
4185164614Sariff	callout_init(&sc->poll_hdac, CALLOUT_MPSAFE);
4186169277Sariff	callout_init(&sc->poll_jack, CALLOUT_MPSAFE);
4187164614Sariff
4188171141Sariff	TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc);
4189171141Sariff
4190182999Smav	sc->poll_ticks = 1000000;
4191169277Sariff	sc->poll_ival = HDAC_POLL_INTERVAL;
4192169277Sariff	if (resource_int_value(device_get_name(dev),
4193169277Sariff	    device_get_unit(dev), "polling", &i) == 0 && i != 0)
4194164614Sariff		sc->polling = 1;
4195164614Sariff	else
4196164614Sariff		sc->polling = 0;
4197164614Sariff
4198162922Sariff	sc->hdabus = NULL;
4199162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++)
4200162922Sariff		sc->codecs[i] = NULL;
4201162922Sariff
4202162922Sariff	pci_enable_busmaster(dev);
4203162922Sariff
4204169277Sariff	if (vendor == INTEL_VENDORID) {
4205169277Sariff		/* TCSEL -> TC0 */
4206169277Sariff		v = pci_read_config(dev, 0x44, 1);
4207169277Sariff		pci_write_config(dev, 0x44, v & 0xf8, 1);
4208183097Smav		HDA_BOOTHVERBOSE(
4209169277Sariff			device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v,
4210169277Sariff			    pci_read_config(dev, 0x44, 1));
4211169277Sariff		);
4212169277Sariff	}
4213169277Sariff
4214189127Smav	if (devid >= 0 && (hdac_devices[devid].flags & HDAC_NO_MSI))
4215188656Smav		sc->flags &= ~HDAC_F_MSI;
4216188656Smav	else
4217171330Sariff		sc->flags |= HDAC_F_MSI;
4218189086Smav	if (resource_int_value(device_get_name(dev),
4219189086Smav	    device_get_unit(dev), "msi", &i) == 0) {
4220189086Smav		if (i == 0)
4221189086Smav			sc->flags &= ~HDAC_F_MSI;
4222189086Smav		else
4223189086Smav			sc->flags |= HDAC_F_MSI;
4224189086Smav	}
4225171330Sariff
4226169277Sariff#if defined(__i386__) || defined(__amd64__)
4227171330Sariff	sc->flags |= HDAC_F_DMA_NOCACHE;
4228169277Sariff
4229169277Sariff	if (resource_int_value(device_get_name(dev),
4230169277Sariff	    device_get_unit(dev), "snoop", &i) == 0 && i != 0) {
4231169277Sariff#else
4232171330Sariff	sc->flags &= ~HDAC_F_DMA_NOCACHE;
4233169277Sariff#endif
4234169277Sariff		/*
4235169277Sariff		 * Try to enable PCIe snoop to avoid messing around with
4236169277Sariff		 * uncacheable DMA attribute. Since PCIe snoop register
4237169277Sariff		 * config is pretty much vendor specific, there are no
4238169277Sariff		 * general solutions on how to enable it, forcing us (even
4239169277Sariff		 * Microsoft) to enable uncacheable or write combined DMA
4240169277Sariff		 * by default.
4241169277Sariff		 *
4242169277Sariff		 * http://msdn2.microsoft.com/en-us/library/ms790324.aspx
4243169277Sariff		 */
4244169277Sariff		for (i = 0; i < HDAC_PCIESNOOP_LEN; i++) {
4245169277Sariff			if (hdac_pcie_snoop[i].vendor != vendor)
4246169277Sariff				continue;
4247171330Sariff			sc->flags &= ~HDAC_F_DMA_NOCACHE;
4248169277Sariff			if (hdac_pcie_snoop[i].reg == 0x00)
4249169277Sariff				break;
4250169277Sariff			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
4251169277Sariff			if ((v & hdac_pcie_snoop[i].enable) ==
4252169277Sariff			    hdac_pcie_snoop[i].enable)
4253169277Sariff				break;
4254169277Sariff			v &= hdac_pcie_snoop[i].mask;
4255169277Sariff			v |= hdac_pcie_snoop[i].enable;
4256169277Sariff			pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1);
4257169277Sariff			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
4258169277Sariff			if ((v & hdac_pcie_snoop[i].enable) !=
4259169277Sariff			    hdac_pcie_snoop[i].enable) {
4260169277Sariff				HDA_BOOTVERBOSE(
4261169277Sariff					device_printf(dev,
4262169277Sariff					    "WARNING: Failed to enable PCIe "
4263169277Sariff					    "snoop!\n");
4264169277Sariff				);
4265169277Sariff#if defined(__i386__) || defined(__amd64__)
4266171330Sariff				sc->flags |= HDAC_F_DMA_NOCACHE;
4267169277Sariff#endif
4268169277Sariff			}
4269169277Sariff			break;
4270169277Sariff		}
4271169277Sariff#if defined(__i386__) || defined(__amd64__)
4272169277Sariff	}
4273169277Sariff#endif
4274169277Sariff
4275183097Smav	HDA_BOOTHVERBOSE(
4276169277Sariff		device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n",
4277171330Sariff		    (sc->flags & HDAC_F_DMA_NOCACHE) ?
4278171330Sariff		    "Uncacheable" : "PCIe snoop", vendor);
4279169277Sariff	);
4280169277Sariff
4281162922Sariff	/* Allocate resources */
4282162922Sariff	result = hdac_mem_alloc(sc);
4283162922Sariff	if (result != 0)
4284163057Sariff		goto hdac_attach_fail;
4285162922Sariff	result = hdac_irq_alloc(sc);
4286162922Sariff	if (result != 0)
4287163057Sariff		goto hdac_attach_fail;
4288162922Sariff
4289162922Sariff	/* Get Capabilities */
4290162922Sariff	result = hdac_get_capabilities(sc);
4291162922Sariff	if (result != 0)
4292163057Sariff		goto hdac_attach_fail;
4293162922Sariff
4294194861Smav	if (devid >= 0 && (hdac_devices[devid].flags & HDAC_NO_64BIT))
4295194861Smav		sc->support_64bit = 0;
4296194861Smav
4297162922Sariff	/* Allocate CORB and RIRB dma memory */
4298162922Sariff	result = hdac_dma_alloc(sc, &sc->corb_dma,
4299162922Sariff	    sc->corb_size * sizeof(uint32_t));
4300162922Sariff	if (result != 0)
4301163057Sariff		goto hdac_attach_fail;
4302162922Sariff	result = hdac_dma_alloc(sc, &sc->rirb_dma,
4303162922Sariff	    sc->rirb_size * sizeof(struct hdac_rirb));
4304162922Sariff	if (result != 0)
4305163057Sariff		goto hdac_attach_fail;
4306162922Sariff
4307194861Smav	result = bus_dma_tag_create(
4308194861Smav	    bus_get_dma_tag(sc->dev),		/* parent */
4309194861Smav	    HDAC_DMA_ALIGNMENT,			/* alignment */
4310194861Smav	    0,					/* boundary */
4311194861Smav	    (sc->support_64bit) ? BUS_SPACE_MAXADDR :
4312194861Smav		BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
4313194861Smav	    BUS_SPACE_MAXADDR,			/* highaddr */
4314194861Smav	    NULL,				/* filtfunc */
4315194861Smav	    NULL,				/* fistfuncarg */
4316194861Smav	    HDA_BUFSZ_MAX, 			/* maxsize */
4317194861Smav	    1,					/* nsegments */
4318194861Smav	    HDA_BUFSZ_MAX, 			/* maxsegsz */
4319194861Smav	    0,					/* flags */
4320194861Smav	    NULL,				/* lockfunc */
4321194861Smav	    NULL,				/* lockfuncarg */
4322194861Smav	    &sc->chan_dmat);			/* dmat */
4323194861Smav	if (result != 0) {
4324194861Smav		device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n",
4325194861Smav		     __func__, result);
4326194861Smav		goto hdac_attach_fail;
4327194861Smav	}
4328194861Smav
4329162922Sariff	/* Quiesce everything */
4330183097Smav	HDA_BOOTHVERBOSE(
4331182999Smav		device_printf(dev, "Reset controller...\n");
4332182999Smav	);
4333182999Smav	hdac_reset(sc, 1);
4334162922Sariff
4335162922Sariff	/* Initialize the CORB and RIRB */
4336162922Sariff	hdac_corb_init(sc);
4337162922Sariff	hdac_rirb_init(sc);
4338162922Sariff
4339162922Sariff	/* Defer remaining of initialization until interrupts are enabled */
4340162922Sariff	sc->intrhook.ich_func = hdac_attach2;
4341162922Sariff	sc->intrhook.ich_arg = (void *)sc;
4342162922Sariff	if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
4343162922Sariff		sc->intrhook.ich_func = NULL;
4344162922Sariff		hdac_attach2((void *)sc);
4345162922Sariff	}
4346162922Sariff
4347163057Sariff	return (0);
4348162922Sariff
4349163057Sariffhdac_attach_fail:
4350162922Sariff	hdac_irq_free(sc);
4351169277Sariff	hdac_dma_free(sc, &sc->rirb_dma);
4352169277Sariff	hdac_dma_free(sc, &sc->corb_dma);
4353162922Sariff	hdac_mem_free(sc);
4354162922Sariff	snd_mtxfree(sc->lock);
4355162922Sariff
4356163057Sariff	return (ENXIO);
4357162922Sariff}
4358162922Sariff
4359162922Sariffstatic void
4360162922Sariffhdac_audio_parse(struct hdac_devinfo *devinfo)
4361162922Sariff{
4362182999Smav	struct hdac_codec *codec = devinfo->codec;
4363182999Smav	struct hdac_softc *sc = codec->sc;
4364162922Sariff	struct hdac_widget *w;
4365162922Sariff	uint32_t res;
4366162922Sariff	int i;
4367162922Sariff	nid_t cad, nid;
4368162922Sariff
4369162922Sariff	cad = devinfo->codec->cad;
4370162922Sariff	nid = devinfo->nid;
4371162922Sariff
4372162922Sariff	res = hdac_command(sc,
4373169277Sariff	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad);
4374169277Sariff	devinfo->function.audio.gpio = res;
4375169277Sariff
4376163057Sariff	HDA_BOOTVERBOSE(
4377183097Smav		device_printf(sc->dev, "GPIO: 0x%08x "
4378183097Smav		    "NumGPIO=%d NumGPO=%d "
4379169277Sariff		    "NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
4380183097Smav		    devinfo->function.audio.gpio,
4381169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
4382169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
4383169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
4384169277Sariff		    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
4385169277Sariff		    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
4386162922Sariff	);
4387162922Sariff
4388162922Sariff	res = hdac_command(sc,
4389162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS),
4390162922Sariff	    cad);
4391162922Sariff	devinfo->function.audio.supp_stream_formats = res;
4392162922Sariff
4393162922Sariff	res = hdac_command(sc,
4394162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE),
4395162922Sariff	    cad);
4396162922Sariff	devinfo->function.audio.supp_pcm_size_rate = res;
4397162922Sariff
4398162922Sariff	res = hdac_command(sc,
4399162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP),
4400162922Sariff	    cad);
4401162922Sariff	devinfo->function.audio.outamp_cap = res;
4402162922Sariff
4403162922Sariff	res = hdac_command(sc,
4404162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP),
4405162922Sariff	    cad);
4406162922Sariff	devinfo->function.audio.inamp_cap = res;
4407162922Sariff
4408162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4409162922Sariff		w = hdac_widget_get(devinfo, i);
4410162922Sariff		if (w == NULL)
4411162922Sariff			device_printf(sc->dev, "Ghost widget! nid=%d!\n", i);
4412162922Sariff		else {
4413162922Sariff			w->devinfo = devinfo;
4414162922Sariff			w->nid = i;
4415162922Sariff			w->enable = 1;
4416162922Sariff			w->selconn = -1;
4417162922Sariff			w->pflags = 0;
4418182999Smav			w->ossdev = -1;
4419182999Smav			w->bindas = -1;
4420162965Sariff			w->param.eapdbtl = HDAC_INVALID;
4421162922Sariff			hdac_widget_parse(w);
4422162922Sariff		}
4423162922Sariff	}
4424162922Sariff}
4425162922Sariff
4426162922Sariffstatic void
4427162922Sariffhdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
4428162922Sariff{
4429162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4430162922Sariff	struct hdac_audio_ctl *ctls;
4431162922Sariff	struct hdac_widget *w, *cw;
4432162922Sariff	int i, j, cnt, max, ocap, icap;
4433163057Sariff	int mute, offset, step, size;
4434162922Sariff
4435162922Sariff	/* XXX This is redundant */
4436162922Sariff	max = 0;
4437162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4438162922Sariff		w = hdac_widget_get(devinfo, i);
4439162922Sariff		if (w == NULL || w->enable == 0)
4440162922Sariff			continue;
4441162922Sariff		if (w->param.outamp_cap != 0)
4442162922Sariff			max++;
4443162922Sariff		if (w->param.inamp_cap != 0) {
4444162922Sariff			switch (w->type) {
4445162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4446162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4447162922Sariff				for (j = 0; j < w->nconns; j++) {
4448162922Sariff					cw = hdac_widget_get(devinfo,
4449162922Sariff					    w->conns[j]);
4450162922Sariff					if (cw == NULL || cw->enable == 0)
4451162922Sariff						continue;
4452162922Sariff					max++;
4453162922Sariff				}
4454162922Sariff				break;
4455162922Sariff			default:
4456162922Sariff				max++;
4457162922Sariff				break;
4458162922Sariff			}
4459162922Sariff		}
4460162922Sariff	}
4461162922Sariff
4462162922Sariff	devinfo->function.audio.ctlcnt = max;
4463162922Sariff
4464162922Sariff	if (max < 1)
4465162922Sariff		return;
4466162922Sariff
4467162922Sariff	ctls = (struct hdac_audio_ctl *)malloc(
4468162922Sariff	    sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT);
4469162922Sariff
4470162922Sariff	if (ctls == NULL) {
4471162922Sariff		/* Blekh! */
4472162922Sariff		device_printf(sc->dev, "unable to allocate ctls!\n");
4473162922Sariff		devinfo->function.audio.ctlcnt = 0;
4474162922Sariff		return;
4475162922Sariff	}
4476162922Sariff
4477162922Sariff	cnt = 0;
4478162922Sariff	for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) {
4479162922Sariff		if (cnt >= max) {
4480162922Sariff			device_printf(sc->dev, "%s: Ctl overflow!\n",
4481162922Sariff			    __func__);
4482162922Sariff			break;
4483162922Sariff		}
4484162922Sariff		w = hdac_widget_get(devinfo, i);
4485162922Sariff		if (w == NULL || w->enable == 0)
4486162922Sariff			continue;
4487162922Sariff		ocap = w->param.outamp_cap;
4488162922Sariff		icap = w->param.inamp_cap;
4489162922Sariff		if (ocap != 0) {
4490163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap);
4491163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap);
4492163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap);
4493163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap);
4494163057Sariff			/*if (offset > step) {
4495163057Sariff				HDA_BOOTVERBOSE(
4496163057Sariff					device_printf(sc->dev,
4497182999Smav					    "BUGGY outamp: nid=%d "
4498163057Sariff					    "[offset=%d > step=%d]\n",
4499163057Sariff					    w->nid, offset, step);
4500163057Sariff				);
4501163057Sariff				offset = step;
4502163057Sariff			}*/
4503162922Sariff			ctls[cnt].enable = 1;
4504162922Sariff			ctls[cnt].widget = w;
4505163057Sariff			ctls[cnt].mute = mute;
4506163057Sariff			ctls[cnt].step = step;
4507163057Sariff			ctls[cnt].size = size;
4508163057Sariff			ctls[cnt].offset = offset;
4509163057Sariff			ctls[cnt].left = offset;
4510163057Sariff			ctls[cnt].right = offset;
4511182999Smav			if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
4512182999Smav			    w->waspin)
4513182999Smav				ctls[cnt].ndir = HDA_CTL_IN;
4514182999Smav			else
4515182999Smav				ctls[cnt].ndir = HDA_CTL_OUT;
4516162922Sariff			ctls[cnt++].dir = HDA_CTL_OUT;
4517162922Sariff		}
4518162922Sariff
4519162922Sariff		if (icap != 0) {
4520163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap);
4521163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap);
4522163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap);
4523163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap);
4524163057Sariff			/*if (offset > step) {
4525163057Sariff				HDA_BOOTVERBOSE(
4526163057Sariff					device_printf(sc->dev,
4527182999Smav					    "BUGGY inamp: nid=%d "
4528163057Sariff					    "[offset=%d > step=%d]\n",
4529163057Sariff					    w->nid, offset, step);
4530163057Sariff				);
4531163057Sariff				offset = step;
4532163057Sariff			}*/
4533162922Sariff			switch (w->type) {
4534162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4535162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4536162922Sariff				for (j = 0; j < w->nconns; j++) {
4537162922Sariff					if (cnt >= max) {
4538162922Sariff						device_printf(sc->dev,
4539162922Sariff						    "%s: Ctl overflow!\n",
4540162922Sariff						    __func__);
4541162922Sariff						break;
4542162922Sariff					}
4543162922Sariff					cw = hdac_widget_get(devinfo,
4544162922Sariff					    w->conns[j]);
4545162922Sariff					if (cw == NULL || cw->enable == 0)
4546162922Sariff						continue;
4547162922Sariff					ctls[cnt].enable = 1;
4548162922Sariff					ctls[cnt].widget = w;
4549162922Sariff					ctls[cnt].childwidget = cw;
4550162922Sariff					ctls[cnt].index = j;
4551163057Sariff					ctls[cnt].mute = mute;
4552163057Sariff					ctls[cnt].step = step;
4553163057Sariff					ctls[cnt].size = size;
4554163057Sariff					ctls[cnt].offset = offset;
4555163057Sariff					ctls[cnt].left = offset;
4556163057Sariff					ctls[cnt].right = offset;
4557182999Smav	    				ctls[cnt].ndir = HDA_CTL_IN;
4558162922Sariff					ctls[cnt++].dir = HDA_CTL_IN;
4559162922Sariff				}
4560162922Sariff				break;
4561162922Sariff			default:
4562162922Sariff				if (cnt >= max) {
4563162922Sariff					device_printf(sc->dev,
4564162922Sariff					    "%s: Ctl overflow!\n",
4565162922Sariff					    __func__);
4566162922Sariff					break;
4567162922Sariff				}
4568162922Sariff				ctls[cnt].enable = 1;
4569162922Sariff				ctls[cnt].widget = w;
4570163057Sariff				ctls[cnt].mute = mute;
4571163057Sariff				ctls[cnt].step = step;
4572163057Sariff				ctls[cnt].size = size;
4573163057Sariff				ctls[cnt].offset = offset;
4574163057Sariff				ctls[cnt].left = offset;
4575163057Sariff				ctls[cnt].right = offset;
4576182999Smav				if (w->type ==
4577182999Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4578182999Smav					ctls[cnt].ndir = HDA_CTL_OUT;
4579182999Smav				else
4580182999Smav					ctls[cnt].ndir = HDA_CTL_IN;
4581162922Sariff				ctls[cnt++].dir = HDA_CTL_IN;
4582162922Sariff				break;
4583162922Sariff			}
4584162922Sariff		}
4585162922Sariff	}
4586162922Sariff
4587162922Sariff	devinfo->function.audio.ctl = ctls;
4588162922Sariff}
4589162922Sariff
4590182999Smavstatic void
4591182999Smavhdac_audio_as_parse(struct hdac_devinfo *devinfo)
4592182999Smav{
4593182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
4594182999Smav	struct hdac_audio_as *as;
4595182999Smav	struct hdac_widget *w;
4596182999Smav	int i, j, cnt, max, type, dir, assoc, seq, first, hpredir;
4597182999Smav
4598184991Smav	/* Count present associations */
4599182999Smav	max = 0;
4600184991Smav	for (j = 1; j < 16; j++) {
4601182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4602182999Smav			w = hdac_widget_get(devinfo, i);
4603182999Smav			if (w == NULL || w->enable == 0)
4604182999Smav				continue;
4605182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4606182999Smav				continue;
4607182999Smav			if (HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config)
4608182999Smav			    != j)
4609182999Smav				continue;
4610182999Smav			max++;
4611182999Smav			if (j != 15)  /* There could be many 1-pin assocs #15 */
4612182999Smav				break;
4613182999Smav		}
4614182999Smav	}
4615182999Smav
4616182999Smav	devinfo->function.audio.ascnt = max;
4617182999Smav
4618182999Smav	if (max < 1)
4619182999Smav		return;
4620182999Smav
4621182999Smav	as = (struct hdac_audio_as *)malloc(
4622182999Smav	    sizeof(*as) * max, M_HDAC, M_ZERO | M_NOWAIT);
4623182999Smav
4624182999Smav	if (as == NULL) {
4625182999Smav		/* Blekh! */
4626182999Smav		device_printf(sc->dev, "unable to allocate assocs!\n");
4627182999Smav		devinfo->function.audio.ascnt = 0;
4628182999Smav		return;
4629182999Smav	}
4630182999Smav
4631182999Smav	for (i = 0; i < max; i++) {
4632182999Smav		as[i].hpredir = -1;
4633182999Smav		as[i].chan = -1;
4634197611Smav		as[i].digital = 0;
4635182999Smav	}
4636182999Smav
4637182999Smav	/* Scan associations skipping as=0. */
4638182999Smav	cnt = 0;
4639182999Smav	for (j = 1; j < 16; j++) {
4640182999Smav		first = 16;
4641182999Smav		hpredir = 0;
4642182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4643182999Smav			w = hdac_widget_get(devinfo, i);
4644182999Smav			if (w == NULL || w->enable == 0)
4645182999Smav				continue;
4646182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4647182999Smav				continue;
4648182999Smav			assoc = HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config);
4649182999Smav			seq = HDA_CONFIG_DEFAULTCONF_SEQUENCE(w->wclass.pin.config);
4650182999Smav			if (assoc != j) {
4651182999Smav				continue;
4652182999Smav			}
4653182999Smav			KASSERT(cnt < max,
4654182999Smav			    ("%s: Associations owerflow (%d of %d)",
4655182999Smav			    __func__, cnt, max));
4656182999Smav			type = w->wclass.pin.config &
4657182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4658182999Smav			/* Get pin direction. */
4659182999Smav			if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT ||
4660182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
4661182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
4662182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT ||
4663182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT)
4664182999Smav				dir = HDA_CTL_OUT;
4665182999Smav			else
4666182999Smav				dir = HDA_CTL_IN;
4667182999Smav			/* If this is a first pin - create new association. */
4668182999Smav			if (as[cnt].pincnt == 0) {
4669182999Smav				as[cnt].enable = 1;
4670182999Smav				as[cnt].index = j;
4671182999Smav				as[cnt].dir = dir;
4672182999Smav			}
4673182999Smav			if (seq < first)
4674182999Smav				first = seq;
4675182999Smav			/* Check association correctness. */
4676182999Smav			if (as[cnt].pins[seq] != 0) {
4677182999Smav				device_printf(sc->dev, "%s: Duplicate pin %d (%d) "
4678182999Smav				    "in association %d! Disabling association.\n",
4679182999Smav				    __func__, seq, w->nid, j);
4680182999Smav				as[cnt].enable = 0;
4681182999Smav			}
4682182999Smav			if (dir != as[cnt].dir) {
4683182999Smav				device_printf(sc->dev, "%s: Pin %d has wrong "
4684182999Smav				    "direction for association %d! Disabling "
4685182999Smav				    "association.\n",
4686182999Smav				    __func__, w->nid, j);
4687182999Smav				as[cnt].enable = 0;
4688182999Smav			}
4689197611Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
4690197611Smav				if (HDA_PARAM_PIN_CAP_DP(w->wclass.pin.cap))
4691197611Smav					as[cnt].digital = 3;
4692197611Smav				else if (HDA_PARAM_PIN_CAP_HDMI(w->wclass.pin.cap))
4693197611Smav					as[cnt].digital = 2;
4694197611Smav				else
4695197611Smav					as[cnt].digital = 1;
4696197611Smav			}
4697182999Smav			/* Headphones with seq=15 may mean redirection. */
4698182999Smav			if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT &&
4699182999Smav			    seq == 15)
4700182999Smav				hpredir = 1;
4701182999Smav			as[cnt].pins[seq] = w->nid;
4702182999Smav			as[cnt].pincnt++;
4703182999Smav			/* Association 15 is a multiple unassociated pins. */
4704182999Smav			if (j == 15)
4705182999Smav				cnt++;
4706182999Smav		}
4707182999Smav		if (j != 15 && as[cnt].pincnt > 0) {
4708182999Smav			if (hpredir && as[cnt].pincnt > 1)
4709182999Smav				as[cnt].hpredir = first;
4710182999Smav			cnt++;
4711182999Smav		}
4712182999Smav	}
4713182999Smav	HDA_BOOTVERBOSE(
4714182999Smav		device_printf(sc->dev,
4715183097Smav		    "%d associations found:\n", max);
4716182999Smav		for (i = 0; i < max; i++) {
4717182999Smav			device_printf(sc->dev,
4718182999Smav			    "Association %d (%d) %s%s:\n",
4719182999Smav			    i, as[i].index, (as[i].dir == HDA_CTL_IN)?"in":"out",
4720182999Smav			    as[i].enable?"":" (disabled)");
4721182999Smav			for (j = 0; j < 16; j++) {
4722182999Smav				if (as[i].pins[j] == 0)
4723182999Smav					continue;
4724182999Smav				device_printf(sc->dev,
4725183097Smav				    " Pin nid=%d seq=%d\n",
4726182999Smav				    as[i].pins[j], j);
4727182999Smav			}
4728182999Smav		}
4729182999Smav	);
4730182999Smav
4731182999Smav	devinfo->function.audio.as = as;
4732182999Smav}
4733182999Smav
4734162965Sariffstatic const struct {
4735162965Sariff	uint32_t model;
4736162965Sariff	uint32_t id;
4737162965Sariff	uint32_t set, unset;
4738162965Sariff} hdac_quirks[] = {
4739163057Sariff	/*
4740163057Sariff	 * XXX Force stereo quirk. Monoural recording / playback
4741163057Sariff	 *     on few codecs (especially ALC880) seems broken or
4742163057Sariff	 *     perhaps unsupported.
4743163057Sariff	 */
4744163057Sariff	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
4745169277Sariff	    HDA_QUIRK_FORCESTEREO | HDA_QUIRK_IVREF, 0 },
4746162965Sariff	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
4747165039Sariff	    HDA_QUIRK_GPIO0, 0 },
4748178155Sariff	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
4749178155Sariff	    HDA_QUIRK_GPIO0, 0 },
4750162965Sariff	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
4751165039Sariff	    HDA_QUIRK_GPIO0, 0 },
4752165281Sariff	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
4753165281Sariff	    HDA_QUIRK_GPIO0, 0 },
4754167623Sariff	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
4755167623Sariff	    HDA_QUIRK_GPIO0, 0 },
4756169277Sariff	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
4757169277Sariff	    HDA_QUIRK_GPIO0, 0 },
4758163276Sariff	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
4759163276Sariff	    HDA_QUIRK_EAPDINV, 0 },
4760178155Sariff	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
4761163432Sariff	    HDA_QUIRK_EAPDINV, 0 },
4762169277Sariff	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
4763169277Sariff	    HDA_QUIRK_OVREF, 0 },
4764169277Sariff	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
4765169277Sariff	    HDA_QUIRK_OVREF, 0 },
4766169277Sariff	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
4767169277Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },*/
4768165281Sariff	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
4769165281Sariff	    HDA_QUIRK_GPIO1, 0 },
4770164657Sariff	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
4771182999Smav	    HDA_QUIRK_EAPDINV | HDA_QUIRK_SENSEINV, 0 },
4772164657Sariff	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
4773164657Sariff	    HDA_QUIRK_EAPDINV, 0 },
4774173817Sariff	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
4775173817Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0},
4776165039Sariff	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
4777165039Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 },
4778199846Smav	{ APPLE_MACBOOKPRO55, HDA_CODEC_CS4206,
4779199846Smav	    HDA_QUIRK_GPIO1 | HDA_QUIRK_GPIO3, 0 },
4780183894Smav	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
4781180532Sdelphij	    HDA_QUIRK_GPIO0, 0 },
4782184483Smav	{ DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X,
4783184483Smav	    HDA_QUIRK_GPIO2, 0 },
4784183894Smav	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
4785178155Sariff	    HDA_QUIRK_GPIO0, 0 },
4786169277Sariff	{ HDA_MATCH_ALL, HDA_CODEC_AD1988,
4787169277Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4788170518Sariff	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
4789170518Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4790186430Smav	{ HDA_MATCH_ALL, HDA_CODEC_CX20549,
4791182999Smav	    0, HDA_QUIRK_FORCESTEREO }
4792162965Sariff};
4793162965Sariff#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
4794162965Sariff
4795162922Sariffstatic void
4796162922Sariffhdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
4797162922Sariff{
4798162922Sariff	struct hdac_widget *w;
4799162965Sariff	uint32_t id, subvendor;
4800162922Sariff	int i;
4801162922Sariff
4802182999Smav	id = hdac_codec_id(devinfo->codec);
4803163057Sariff	subvendor = devinfo->codec->sc->pci_subvendor;
4804163057Sariff
4805162922Sariff	/*
4806163057Sariff	 * Quirks
4807162922Sariff	 */
4808163057Sariff	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
4809163257Sariff		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) &&
4810163257Sariff		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
4811163057Sariff			continue;
4812163057Sariff		if (hdac_quirks[i].set != 0)
4813163057Sariff			devinfo->function.audio.quirks |=
4814163057Sariff			    hdac_quirks[i].set;
4815163057Sariff		if (hdac_quirks[i].unset != 0)
4816163057Sariff			devinfo->function.audio.quirks &=
4817163057Sariff			    ~(hdac_quirks[i].unset);
4818163057Sariff	}
4819163057Sariff
4820162922Sariff	switch (id) {
4821187196Smav	case HDA_CODEC_AD1983:
4822187196Smav		/*
4823187202Smav		 * This codec has several possible usages, but none
4824187202Smav		 * fit the parser best. Help parser to choose better.
4825187196Smav		 */
4826187196Smav		/* Disable direct unmixed playback to get pcm volume. */
4827187196Smav		w = hdac_widget_get(devinfo, 5);
4828187196Smav		if (w != NULL)
4829187196Smav			w->connsenable[0] = 0;
4830187196Smav		w = hdac_widget_get(devinfo, 6);
4831187196Smav		if (w != NULL)
4832187196Smav			w->connsenable[0] = 0;
4833187196Smav		w = hdac_widget_get(devinfo, 11);
4834187196Smav		if (w != NULL)
4835187196Smav			w->connsenable[0] = 0;
4836187196Smav		/* Disable mic and line selectors. */
4837187196Smav		w = hdac_widget_get(devinfo, 12);
4838187196Smav		if (w != NULL)
4839187196Smav			w->connsenable[1] = 0;
4840187196Smav		w = hdac_widget_get(devinfo, 13);
4841187196Smav		if (w != NULL)
4842187196Smav			w->connsenable[1] = 0;
4843187196Smav		/* Disable recording from mono playback mix. */
4844187196Smav		w = hdac_widget_get(devinfo, 20);
4845187196Smav		if (w != NULL)
4846187196Smav			w->connsenable[3] = 0;
4847187196Smav		break;
4848162922Sariff	case HDA_CODEC_AD1986A:
4849186503Smav		/*
4850186503Smav		 * This codec has overcomplicated input mixing.
4851186503Smav		 * Make some cleaning there.
4852186503Smav		 */
4853186503Smav		/* Disable input mono mixer. Not needed and not supported. */
4854186503Smav		w = hdac_widget_get(devinfo, 43);
4855186503Smav		if (w != NULL)
4856186503Smav			w->enable = 0;
4857186503Smav		/* Disable any with any input mixing mesh. Use separately. */
4858186503Smav		w = hdac_widget_get(devinfo, 39);
4859186503Smav		if (w != NULL)
4860186503Smav			w->enable = 0;
4861186503Smav		w = hdac_widget_get(devinfo, 40);
4862186503Smav		if (w != NULL)
4863186503Smav			w->enable = 0;
4864186503Smav		w = hdac_widget_get(devinfo, 41);
4865186503Smav		if (w != NULL)
4866186503Smav			w->enable = 0;
4867186503Smav		w = hdac_widget_get(devinfo, 42);
4868186503Smav		if (w != NULL)
4869186503Smav			w->enable = 0;
4870186503Smav		/* Disable duplicate mixer node connector. */
4871186503Smav		w = hdac_widget_get(devinfo, 15);
4872186503Smav		if (w != NULL)
4873186503Smav			w->connsenable[3] = 0;
4874190630Smav		/* There is only one mic preamplifier, use it effectively. */
4875190630Smav		w = hdac_widget_get(devinfo, 31);
4876190630Smav		if (w != NULL) {
4877190630Smav			if ((w->wclass.pin.config &
4878190630Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
4879190630Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
4880190630Smav				w = hdac_widget_get(devinfo, 16);
4881190630Smav				if (w != NULL)
4882190630Smav				    w->connsenable[2] = 0;
4883190630Smav			} else {
4884190630Smav				w = hdac_widget_get(devinfo, 15);
4885190630Smav				if (w != NULL)
4886190630Smav				    w->connsenable[0] = 0;
4887190630Smav			}
4888190630Smav		}
4889190630Smav		w = hdac_widget_get(devinfo, 32);
4890190630Smav		if (w != NULL) {
4891190630Smav			if ((w->wclass.pin.config &
4892190630Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
4893190630Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
4894190630Smav				w = hdac_widget_get(devinfo, 16);
4895190630Smav				if (w != NULL)
4896190630Smav				    w->connsenable[0] = 0;
4897190630Smav			} else {
4898190630Smav				w = hdac_widget_get(devinfo, 15);
4899190630Smav				if (w != NULL)
4900190630Smav				    w->connsenable[1] = 0;
4901190630Smav			}
4902190630Smav		}
4903186503Smav
4904182999Smav		if (subvendor == ASUS_A8X_SUBVENDOR) {
4905178155Sariff			/*
4906178155Sariff			 * This is just plain ridiculous.. There
4907178155Sariff			 * are several A8 series that share the same
4908178155Sariff			 * pci id but works differently (EAPD).
4909178155Sariff			 */
4910178155Sariff			w = hdac_widget_get(devinfo, 26);
4911178155Sariff			if (w != NULL && w->type ==
4912178155Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4913178155Sariff			    (w->wclass.pin.config &
4914178155Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
4915178155Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
4916178155Sariff				devinfo->function.audio.quirks &=
4917178155Sariff				    ~HDA_QUIRK_EAPDINV;
4918169277Sariff		}
4919162922Sariff		break;
4920184230Smav	case HDA_CODEC_AD1981HD:
4921184230Smav		/*
4922184230Smav		 * This codec has very unusual design with several
4923184254Smav		 * points inappropriate for the present parser.
4924184230Smav		 */
4925184230Smav		/* Disable recording from mono playback mix. */
4926184230Smav		w = hdac_widget_get(devinfo, 21);
4927184230Smav		if (w != NULL)
4928184230Smav			w->connsenable[3] = 0;
4929184230Smav		/* Disable rear to front mic mixer, use separately. */
4930184230Smav		w = hdac_widget_get(devinfo, 31);
4931184230Smav		if (w != NULL)
4932184230Smav			w->enable = 0;
4933202789Smav		/* Disable direct playback, use mixer. */
4934202789Smav		w = hdac_widget_get(devinfo, 5);
4935184230Smav		if (w != NULL)
4936202789Smav			w->connsenable[0] = 0;
4937202789Smav		w = hdac_widget_get(devinfo, 6);
4938202789Smav		if (w != NULL)
4939202789Smav			w->connsenable[0] = 0;
4940202789Smav		w = hdac_widget_get(devinfo, 9);
4941202789Smav		if (w != NULL)
4942202789Smav			w->connsenable[0] = 0;
4943202789Smav		w = hdac_widget_get(devinfo, 24);
4944202789Smav		if (w != NULL)
4945202789Smav			w->connsenable[0] = 0;
4946184230Smav		break;
4947223058Smav	case HDA_CODEC_CX20582:
4948223058Smav	case HDA_CODEC_CX20583:
4949223058Smav	case HDA_CODEC_CX20584:
4950223058Smav	case HDA_CODEC_CX20585:
4951223058Smav	case HDA_CODEC_CX20590:
4952223058Smav		/*
4953223058Smav		 * These codecs have extra connectivity on record side
4954223058Smav		 * too reach for the present parser.
4955223058Smav		 */
4956223058Smav		w = hdac_widget_get(devinfo, 20);
4957223058Smav		if (w != NULL)
4958223058Smav			w->connsenable[1] = 0;
4959223058Smav		w = hdac_widget_get(devinfo, 21);
4960223058Smav		if (w != NULL)
4961223058Smav			w->connsenable[1] = 0;
4962223058Smav		w = hdac_widget_get(devinfo, 22);
4963223058Smav		if (w != NULL)
4964223058Smav			w->connsenable[0] = 0;
4965223058Smav		break;
4966182999Smav	}
4967182999Smav}
4968182999Smav
4969182999Smav/*
4970182999Smav * Trace path from DAC to pin.
4971182999Smav */
4972182999Smavstatic nid_t
4973182999Smavhdac_audio_trace_dac(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
4974182999Smav    int dupseq, int min, int only, int depth)
4975182999Smav{
4976182999Smav	struct hdac_widget *w;
4977182999Smav	int i, im = -1;
4978182999Smav	nid_t m = 0, ret;
4979182999Smav
4980182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
4981182999Smav		return (0);
4982182999Smav	w = hdac_widget_get(devinfo, nid);
4983182999Smav	if (w == NULL || w->enable == 0)
4984182999Smav		return (0);
4985183097Smav	HDA_BOOTHVERBOSE(
4986182999Smav		if (!only) {
4987182999Smav			device_printf(devinfo->codec->sc->dev,
4988182999Smav			    " %*stracing via nid %d\n",
4989182999Smav				depth + 1, "", w->nid);
4990169277Sariff		}
4991182999Smav	);
4992182999Smav	/* Use only unused widgets */
4993182999Smav	if (w->bindas >= 0 && w->bindas != as) {
4994183097Smav		HDA_BOOTHVERBOSE(
4995182999Smav			if (!only) {
4996182999Smav				device_printf(devinfo->codec->sc->dev,
4997182999Smav				    " %*snid %d busy by association %d\n",
4998182999Smav					depth + 1, "", w->nid, w->bindas);
4999182999Smav			}
5000182999Smav		);
5001182999Smav		return (0);
5002182999Smav	}
5003182999Smav	if (dupseq < 0) {
5004182999Smav		if (w->bindseqmask != 0) {
5005183097Smav			HDA_BOOTHVERBOSE(
5006182999Smav				if (!only) {
5007182999Smav					device_printf(devinfo->codec->sc->dev,
5008182999Smav					    " %*snid %d busy by seqmask %x\n",
5009182999Smav						depth + 1, "", w->nid, w->bindseqmask);
5010182999Smav				}
5011182999Smav			);
5012182999Smav			return (0);
5013169277Sariff		}
5014182999Smav	} else {
5015182999Smav		/* If this is headphones - allow duplicate first pin. */
5016182999Smav		if (w->bindseqmask != 0 &&
5017182999Smav		    (w->bindseqmask & (1 << dupseq)) == 0) {
5018183097Smav			HDA_BOOTHVERBOSE(
5019182999Smav				device_printf(devinfo->codec->sc->dev,
5020182999Smav				    " %*snid %d busy by seqmask %x\n",
5021182999Smav					depth + 1, "", w->nid, w->bindseqmask);
5022182999Smav			);
5023182999Smav			return (0);
5024169277Sariff		}
5025182999Smav	}
5026182999Smav
5027182999Smav	switch (w->type) {
5028182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
5029182999Smav		/* Do not traverse input. AD1988 has digital monitor
5030182999Smav		for which we are not ready. */
5031169277Sariff		break;
5032182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
5033182999Smav		/* If we are tracing HP take only dac of first pin. */
5034182999Smav		if ((only == 0 || only == w->nid) &&
5035182999Smav		    (w->nid >= min) && (dupseq < 0 || w->nid ==
5036182999Smav		    devinfo->function.audio.as[as].dacs[dupseq]))
5037182999Smav			m = w->nid;
5038178155Sariff		break;
5039182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
5040182999Smav		if (depth > 0)
5041169277Sariff			break;
5042182999Smav		/* Fall */
5043182999Smav	default:
5044182999Smav		/* Find reachable DACs with smallest nid respecting constraints. */
5045182999Smav		for (i = 0; i < w->nconns; i++) {
5046182999Smav			if (w->connsenable[i] == 0)
5047162922Sariff				continue;
5048182999Smav			if (w->selconn != -1 && w->selconn != i)
5049162922Sariff				continue;
5050182999Smav			if ((ret = hdac_audio_trace_dac(devinfo, as, seq,
5051182999Smav			    w->conns[i], dupseq, min, only, depth + 1)) != 0) {
5052182999Smav				if (m == 0 || ret < m) {
5053182999Smav					m = ret;
5054182999Smav					im = i;
5055182999Smav				}
5056182999Smav				if (only || dupseq >= 0)
5057182999Smav					break;
5058182999Smav			}
5059162922Sariff		}
5060182999Smav		if (m && only && ((w->nconns > 1 &&
5061182999Smav		    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
5062182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
5063182999Smav			w->selconn = im;
5064162922Sariff		break;
5065182999Smav	}
5066182999Smav	if (m && only) {
5067182999Smav		w->bindas = as;
5068182999Smav		w->bindseqmask |= (1 << seq);
5069182999Smav	}
5070183097Smav	HDA_BOOTHVERBOSE(
5071182999Smav		if (!only) {
5072182999Smav			device_printf(devinfo->codec->sc->dev,
5073182999Smav			    " %*snid %d returned %d\n",
5074182999Smav				depth + 1, "", w->nid, m);
5075182999Smav		}
5076182999Smav	);
5077182999Smav	return (m);
5078182999Smav}
5079162922Sariff
5080182999Smav/*
5081182999Smav * Trace path from widget to ADC.
5082182999Smav */
5083182999Smavstatic nid_t
5084182999Smavhdac_audio_trace_adc(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
5085182999Smav    int only, int depth)
5086182999Smav{
5087182999Smav	struct hdac_widget *w, *wc;
5088182999Smav	int i, j;
5089182999Smav	nid_t res = 0;
5090182999Smav
5091182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
5092182999Smav		return (0);
5093182999Smav	w = hdac_widget_get(devinfo, nid);
5094182999Smav	if (w == NULL || w->enable == 0)
5095182999Smav		return (0);
5096183097Smav	HDA_BOOTHVERBOSE(
5097182999Smav		device_printf(devinfo->codec->sc->dev,
5098182999Smav		    " %*stracing via nid %d\n",
5099182999Smav			depth + 1, "", w->nid);
5100182999Smav	);
5101182999Smav	/* Use only unused widgets */
5102182999Smav	if (w->bindas >= 0 && w->bindas != as) {
5103183097Smav		HDA_BOOTHVERBOSE(
5104182999Smav			device_printf(devinfo->codec->sc->dev,
5105182999Smav			    " %*snid %d busy by association %d\n",
5106182999Smav				depth + 1, "", w->nid, w->bindas);
5107182999Smav		);
5108182999Smav		return (0);
5109182999Smav	}
5110182999Smav
5111182999Smav	switch (w->type) {
5112182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
5113182999Smav		/* If we are tracing HP take only dac of first pin. */
5114182999Smav		if (only == w->nid)
5115182999Smav			res = 1;
5116162922Sariff		break;
5117182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
5118182999Smav		if (depth > 0)
5119182999Smav			break;
5120182999Smav		/* Fall */
5121182999Smav	default:
5122182999Smav		/* Try to find reachable ADCs with specified nid. */
5123182999Smav		for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5124182999Smav			wc = hdac_widget_get(devinfo, j);
5125182999Smav			if (wc == NULL || wc->enable == 0)
5126182999Smav				continue;
5127182999Smav			for (i = 0; i < wc->nconns; i++) {
5128182999Smav				if (wc->connsenable[i] == 0)
5129182999Smav					continue;
5130182999Smav				if (wc->conns[i] != nid)
5131182999Smav					continue;
5132182999Smav				if (hdac_audio_trace_adc(devinfo, as, seq,
5133182999Smav				    j, only, depth + 1) != 0) {
5134182999Smav					res = 1;
5135182999Smav					if (((wc->nconns > 1 &&
5136182999Smav					    wc->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
5137182999Smav					    wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) &&
5138182999Smav					    wc->selconn == -1)
5139182999Smav						wc->selconn = i;
5140182999Smav				}
5141182999Smav			}
5142169277Sariff		}
5143169277Sariff		break;
5144162922Sariff	}
5145182999Smav	if (res) {
5146182999Smav		w->bindas = as;
5147182999Smav		w->bindseqmask |= (1 << seq);
5148182999Smav	}
5149183097Smav	HDA_BOOTHVERBOSE(
5150182999Smav		device_printf(devinfo->codec->sc->dev,
5151182999Smav		    " %*snid %d returned %d\n",
5152182999Smav			depth + 1, "", w->nid, res);
5153182999Smav	);
5154182999Smav	return (res);
5155162922Sariff}
5156162922Sariff
5157182999Smav/*
5158182999Smav * Erase trace path of the specified association.
5159182999Smav */
5160182999Smavstatic void
5161182999Smavhdac_audio_undo_trace(struct hdac_devinfo *devinfo, int as, int seq)
5162182999Smav{
5163182999Smav	struct hdac_widget *w;
5164182999Smav	int i;
5165182999Smav
5166182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5167182999Smav		w = hdac_widget_get(devinfo, i);
5168182999Smav		if (w == NULL || w->enable == 0)
5169182999Smav			continue;
5170182999Smav		if (w->bindas == as) {
5171182999Smav			if (seq >= 0) {
5172182999Smav				w->bindseqmask &= ~(1 << seq);
5173182999Smav				if (w->bindseqmask == 0) {
5174182999Smav					w->bindas = -1;
5175182999Smav					w->selconn = -1;
5176182999Smav				}
5177182999Smav			} else {
5178182999Smav				w->bindas = -1;
5179182999Smav				w->bindseqmask = 0;
5180182999Smav				w->selconn = -1;
5181182999Smav			}
5182182999Smav		}
5183182999Smav	}
5184182999Smav}
5185182999Smav
5186182999Smav/*
5187182999Smav * Trace association path from DAC to output
5188182999Smav */
5189162922Sariffstatic int
5190182999Smavhdac_audio_trace_as_out(struct hdac_devinfo *devinfo, int as, int seq)
5191162922Sariff{
5192182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
5193182999Smav	int i, hpredir;
5194182999Smav	nid_t min, res;
5195162922Sariff
5196182999Smav	/* Find next pin */
5197185176Smav	for (i = seq; i < 16 && ases[as].pins[i] == 0; i++)
5198182999Smav		;
5199188510Smav	/* Check if there is no any left. If so - we succeeded. */
5200182999Smav	if (i == 16)
5201182999Smav		return (1);
5202182999Smav
5203182999Smav	hpredir = (i == 15 && ases[as].fakeredir == 0)?ases[as].hpredir:-1;
5204182999Smav	min = 0;
5205182999Smav	res = 0;
5206182999Smav	do {
5207183097Smav		HDA_BOOTHVERBOSE(
5208182999Smav			device_printf(devinfo->codec->sc->dev,
5209182999Smav			    " Tracing pin %d with min nid %d",
5210182999Smav			    ases[as].pins[i], min);
5211182999Smav			if (hpredir >= 0)
5212183097Smav				printf(" and hpredir %d", hpredir);
5213183097Smav			printf("\n");
5214182999Smav		);
5215182999Smav		/* Trace this pin taking min nid into account. */
5216182999Smav		res = hdac_audio_trace_dac(devinfo, as, i,
5217182999Smav		    ases[as].pins[i], hpredir, min, 0, 0);
5218182999Smav		if (res == 0) {
5219182999Smav			/* If we failed - return to previous and redo it. */
5220182999Smav			HDA_BOOTVERBOSE(
5221182999Smav				device_printf(devinfo->codec->sc->dev,
5222182999Smav				    " Unable to trace pin %d seq %d with min "
5223183097Smav				    "nid %d",
5224183097Smav				    ases[as].pins[i], i, min);
5225183097Smav				if (hpredir >= 0)
5226183097Smav					printf(" and hpredir %d", hpredir);
5227183097Smav				printf("\n");
5228182999Smav			);
5229182999Smav			return (0);
5230162922Sariff		}
5231182999Smav		HDA_BOOTVERBOSE(
5232182999Smav			device_printf(devinfo->codec->sc->dev,
5233183097Smav			    " Pin %d traced to DAC %d",
5234183097Smav			    ases[as].pins[i], res);
5235183097Smav			if (hpredir >= 0)
5236183097Smav				printf(" and hpredir %d", hpredir);
5237183097Smav			if (ases[as].fakeredir)
5238183097Smav				printf(" with fake redirection");
5239183097Smav			printf("\n");
5240182999Smav		);
5241182999Smav		/* Trace again to mark the path */
5242182999Smav		hdac_audio_trace_dac(devinfo, as, i,
5243182999Smav		    ases[as].pins[i], hpredir, min, res, 0);
5244182999Smav		ases[as].dacs[i] = res;
5245188510Smav		/* We succeeded, so call next. */
5246182999Smav		if (hdac_audio_trace_as_out(devinfo, as, i + 1))
5247182999Smav			return (1);
5248182999Smav		/* If next failed, we should retry with next min */
5249182999Smav		hdac_audio_undo_trace(devinfo, as, i);
5250182999Smav		ases[as].dacs[i] = 0;
5251182999Smav		min = res + 1;
5252182999Smav	} while (1);
5253162922Sariff}
5254162922Sariff
5255182999Smav/*
5256182999Smav * Trace association path from input to ADC
5257182999Smav */
5258162922Sariffstatic int
5259182999Smavhdac_audio_trace_as_in(struct hdac_devinfo *devinfo, int as)
5260162922Sariff{
5261182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
5262162922Sariff	struct hdac_widget *w;
5263182999Smav	int i, j, k;
5264162922Sariff
5265182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5266182999Smav		w = hdac_widget_get(devinfo, j);
5267182999Smav		if (w == NULL || w->enable == 0)
5268182999Smav			continue;
5269182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
5270182999Smav			continue;
5271182999Smav		if (w->bindas >= 0 && w->bindas != as)
5272182999Smav			continue;
5273182999Smav
5274182999Smav		/* Find next pin */
5275182999Smav		for (i = 0; i < 16; i++) {
5276182999Smav			if (ases[as].pins[i] == 0)
5277182999Smav				continue;
5278182999Smav
5279183097Smav			HDA_BOOTHVERBOSE(
5280182999Smav				device_printf(devinfo->codec->sc->dev,
5281182999Smav				    " Tracing pin %d to ADC %d\n",
5282182999Smav				    ases[as].pins[i], j);
5283182999Smav			);
5284182999Smav			/* Trace this pin taking goal into account. */
5285182999Smav			if (hdac_audio_trace_adc(devinfo, as, i,
5286182999Smav			    ases[as].pins[i], j, 0) == 0) {
5287182999Smav				/* If we failed - return to previous and redo it. */
5288182999Smav				HDA_BOOTVERBOSE(
5289182999Smav					device_printf(devinfo->codec->sc->dev,
5290183097Smav					    " Unable to trace pin %d to ADC %d, undo traces\n",
5291182999Smav					    ases[as].pins[i], j);
5292182999Smav				);
5293182999Smav				hdac_audio_undo_trace(devinfo, as, -1);
5294182999Smav				for (k = 0; k < 16; k++)
5295182999Smav					ases[as].dacs[k] = 0;
5296182999Smav				break;
5297162922Sariff			}
5298182999Smav			HDA_BOOTVERBOSE(
5299182999Smav				device_printf(devinfo->codec->sc->dev,
5300183097Smav				    " Pin %d traced to ADC %d\n",
5301183097Smav				    ases[as].pins[i], j);
5302182999Smav			);
5303182999Smav			ases[as].dacs[i] = j;
5304162922Sariff		}
5305182999Smav		if (i == 16)
5306182999Smav			return (1);
5307162922Sariff	}
5308182999Smav	return (0);
5309162922Sariff}
5310162922Sariff
5311182999Smav/*
5312182999Smav * Trace input monitor path from mixer to output association.
5313182999Smav */
5314183097Smavstatic int
5315182999Smavhdac_audio_trace_to_out(struct hdac_devinfo *devinfo, nid_t nid, int depth)
5316162922Sariff{
5317182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
5318182999Smav	struct hdac_widget *w, *wc;
5319182999Smav	int i, j;
5320182999Smav	nid_t res = 0;
5321162922Sariff
5322162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
5323162922Sariff		return (0);
5324162922Sariff	w = hdac_widget_get(devinfo, nid);
5325162922Sariff	if (w == NULL || w->enable == 0)
5326162922Sariff		return (0);
5327183097Smav	HDA_BOOTHVERBOSE(
5328182999Smav		device_printf(devinfo->codec->sc->dev,
5329182999Smav		    " %*stracing via nid %d\n",
5330182999Smav			depth + 1, "", w->nid);
5331182999Smav	);
5332182999Smav	/* Use only unused widgets */
5333182999Smav	if (depth > 0 && w->bindas != -1) {
5334182999Smav		if (w->bindas < 0 || ases[w->bindas].dir == HDA_CTL_OUT) {
5335183097Smav			HDA_BOOTHVERBOSE(
5336182999Smav				device_printf(devinfo->codec->sc->dev,
5337182999Smav				    " %*snid %d found output association %d\n",
5338182999Smav					depth + 1, "", w->nid, w->bindas);
5339182999Smav			);
5340202789Smav			if (w->bindas >= 0)
5341202789Smav				w->pflags |= HDA_ADC_MONITOR;
5342182999Smav			return (1);
5343182999Smav		} else {
5344183097Smav			HDA_BOOTHVERBOSE(
5345182999Smav				device_printf(devinfo->codec->sc->dev,
5346182999Smav				    " %*snid %d busy by input association %d\n",
5347182999Smav					depth + 1, "", w->nid, w->bindas);
5348182999Smav			);
5349182999Smav			return (0);
5350182999Smav		}
5351182999Smav	}
5352182999Smav
5353162922Sariff	switch (w->type) {
5354162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
5355182999Smav		/* Do not traverse input. AD1988 has digital monitor
5356182999Smav		for which we are not ready. */
5357162922Sariff		break;
5358162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
5359182999Smav		if (depth > 0)
5360182999Smav			break;
5361182999Smav		/* Fall */
5362182999Smav	default:
5363182999Smav		/* Try to find reachable ADCs with specified nid. */
5364182999Smav		for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5365182999Smav			wc = hdac_widget_get(devinfo, j);
5366182999Smav			if (wc == NULL || wc->enable == 0)
5367182999Smav				continue;
5368182999Smav			for (i = 0; i < wc->nconns; i++) {
5369182999Smav				if (wc->connsenable[i] == 0)
5370182999Smav					continue;
5371182999Smav				if (wc->conns[i] != nid)
5372182999Smav					continue;
5373182999Smav				if (hdac_audio_trace_to_out(devinfo,
5374182999Smav				    j, depth + 1) != 0) {
5375182999Smav					res = 1;
5376182999Smav					if (wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5377182999Smav					    wc->selconn == -1)
5378182999Smav						wc->selconn = i;
5379182999Smav				}
5380182999Smav			}
5381162922Sariff		}
5382162922Sariff		break;
5383182999Smav	}
5384202789Smav	if (res && w->bindas == -1)
5385182999Smav		w->bindas = -2;
5386182999Smav
5387183097Smav	HDA_BOOTHVERBOSE(
5388182999Smav		device_printf(devinfo->codec->sc->dev,
5389182999Smav		    " %*snid %d returned %d\n",
5390182999Smav			depth + 1, "", w->nid, res);
5391182999Smav	);
5392182999Smav	return (res);
5393182999Smav}
5394182999Smav
5395182999Smav/*
5396182999Smav * Trace extra associations (beeper, monitor)
5397182999Smav */
5398182999Smavstatic void
5399182999Smavhdac_audio_trace_as_extra(struct hdac_devinfo *devinfo)
5400182999Smav{
5401182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5402182999Smav	struct hdac_widget *w;
5403182999Smav	int j;
5404182999Smav
5405182999Smav	/* Input monitor */
5406182999Smav	/* Find mixer associated with input, but supplying signal
5407182999Smav	   for output associations. Hope it will be input monitor. */
5408182999Smav	HDA_BOOTVERBOSE(
5409182999Smav		device_printf(devinfo->codec->sc->dev,
5410182999Smav		    "Tracing input monitor\n");
5411182999Smav	);
5412182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5413182999Smav		w = hdac_widget_get(devinfo, j);
5414182999Smav		if (w == NULL || w->enable == 0)
5415182999Smav			continue;
5416182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5417182999Smav			continue;
5418182999Smav		if (w->bindas < 0 || as[w->bindas].dir != HDA_CTL_IN)
5419182999Smav			continue;
5420182999Smav		HDA_BOOTVERBOSE(
5421182999Smav			device_printf(devinfo->codec->sc->dev,
5422182999Smav			    " Tracing nid %d to out\n",
5423182999Smav			    j);
5424182999Smav		);
5425182999Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
5426182999Smav			HDA_BOOTVERBOSE(
5427182999Smav				device_printf(devinfo->codec->sc->dev,
5428182999Smav				    " nid %d is input monitor\n",
5429182999Smav					w->nid);
5430182999Smav			);
5431182999Smav			w->ossdev = SOUND_MIXER_IMIX;
5432162922Sariff		}
5433162922Sariff	}
5434182999Smav
5435202789Smav	/* Other inputs monitor */
5436202789Smav	/* Find input pins supplying signal for output associations.
5437202789Smav	   Hope it will be input monitoring. */
5438202789Smav	HDA_BOOTVERBOSE(
5439202789Smav		device_printf(devinfo->codec->sc->dev,
5440202789Smav		    "Tracing other input monitors\n");
5441202789Smav	);
5442202789Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5443202789Smav		w = hdac_widget_get(devinfo, j);
5444202789Smav		if (w == NULL || w->enable == 0)
5445202789Smav			continue;
5446202789Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5447202789Smav			continue;
5448202789Smav		if (w->bindas < 0 || as[w->bindas].dir != HDA_CTL_IN)
5449202789Smav			continue;
5450202789Smav		HDA_BOOTVERBOSE(
5451202789Smav			device_printf(devinfo->codec->sc->dev,
5452202789Smav			    " Tracing nid %d to out\n",
5453202789Smav			    j);
5454202789Smav		);
5455202789Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
5456202789Smav			HDA_BOOTVERBOSE(
5457202789Smav				device_printf(devinfo->codec->sc->dev,
5458202789Smav				    " nid %d is input monitor\n",
5459202789Smav					w->nid);
5460202789Smav			);
5461202789Smav		}
5462202789Smav	}
5463202789Smav
5464182999Smav	/* Beeper */
5465182999Smav	HDA_BOOTVERBOSE(
5466182999Smav		device_printf(devinfo->codec->sc->dev,
5467182999Smav		    "Tracing beeper\n");
5468182999Smav	);
5469182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5470182999Smav		w = hdac_widget_get(devinfo, j);
5471182999Smav		if (w == NULL || w->enable == 0)
5472182999Smav			continue;
5473182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET)
5474182999Smav			continue;
5475183097Smav		HDA_BOOTHVERBOSE(
5476182999Smav			device_printf(devinfo->codec->sc->dev,
5477182999Smav			    " Tracing nid %d to out\n",
5478182999Smav			    j);
5479182999Smav		);
5480183097Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
5481183097Smav			HDA_BOOTVERBOSE(
5482183097Smav				device_printf(devinfo->codec->sc->dev,
5483183097Smav				    " nid %d traced to out\n",
5484183097Smav				    j);
5485183097Smav			);
5486183097Smav		}
5487182999Smav		w->bindas = -2;
5488182999Smav	}
5489162922Sariff}
5490162922Sariff
5491182999Smav/*
5492182999Smav * Bind assotiations to PCM channels
5493182999Smav */
5494182999Smavstatic void
5495182999Smavhdac_audio_bind_as(struct hdac_devinfo *devinfo)
5496162922Sariff{
5497182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
5498182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5499182999Smav	int j, cnt = 0, free;
5500162922Sariff
5501182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5502182999Smav		if (as[j].enable)
5503182999Smav			cnt++;
5504182999Smav	}
5505182999Smav	if (sc->num_chans == 0) {
5506182999Smav		sc->chans = (struct hdac_chan *)malloc(
5507182999Smav		    sizeof(struct hdac_chan) * cnt,
5508182999Smav		    M_HDAC, M_ZERO | M_NOWAIT);
5509182999Smav		if (sc->chans == NULL) {
5510190519Smav			device_printf(sc->dev,
5511182999Smav			    "Channels memory allocation failed!\n");
5512182999Smav			return;
5513182999Smav		}
5514182999Smav	} else {
5515182999Smav		sc->chans = (struct hdac_chan *)realloc(sc->chans,
5516183810Smav		    sizeof(struct hdac_chan) * (sc->num_chans + cnt),
5517182999Smav		    M_HDAC, M_ZERO | M_NOWAIT);
5518182999Smav		if (sc->chans == NULL) {
5519182999Smav			sc->num_chans = 0;
5520190519Smav			device_printf(sc->dev,
5521182999Smav			    "Channels memory allocation failed!\n");
5522182999Smav			return;
5523182999Smav		}
5524190519Smav		/* Fixup relative pointers after realloc */
5525190519Smav		for (j = 0; j < sc->num_chans; j++)
5526190519Smav			sc->chans[j].caps.fmtlist = sc->chans[j].fmtlist;
5527182999Smav	}
5528182999Smav	free = sc->num_chans;
5529182999Smav	sc->num_chans += cnt;
5530162922Sariff
5531182999Smav	for (j = free; j < free + cnt; j++) {
5532190519Smav		sc->chans[j].devinfo = devinfo;
5533190519Smav		sc->chans[j].as = -1;
5534182999Smav	}
5535162922Sariff
5536182999Smav	/* Assign associations in order of their numbers, */
5537182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5538182999Smav		if (as[j].enable == 0)
5539182999Smav			continue;
5540182999Smav
5541182999Smav		as[j].chan = free;
5542190519Smav		sc->chans[free].as = j;
5543190519Smav		sc->chans[free].dir =
5544185225Smav		    (as[j].dir == HDA_CTL_IN) ? PCMDIR_REC : PCMDIR_PLAY;
5545190519Smav		hdac_pcmchannel_setup(&sc->chans[free]);
5546182999Smav		free++;
5547182999Smav	}
5548182999Smav}
5549162922Sariff
5550182999Smavstatic void
5551182999Smavhdac_audio_disable_nonaudio(struct hdac_devinfo *devinfo)
5552182999Smav{
5553182999Smav	struct hdac_widget *w;
5554182999Smav	int i;
5555182999Smav
5556182999Smav	/* Disable power and volume widgets. */
5557182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5558182999Smav		w = hdac_widget_get(devinfo, i);
5559182999Smav		if (w == NULL || w->enable == 0)
5560182999Smav			continue;
5561182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET ||
5562182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET) {
5563182999Smav			w->enable = 0;
5564183097Smav			HDA_BOOTHVERBOSE(
5565182999Smav				device_printf(devinfo->codec->sc->dev,
5566182999Smav				    " Disabling nid %d due to it's"
5567182999Smav				    " non-audio type.\n",
5568182999Smav				    w->nid);
5569182999Smav			);
5570162922Sariff		}
5571182999Smav	}
5572182999Smav}
5573182999Smav
5574182999Smavstatic void
5575182999Smavhdac_audio_disable_useless(struct hdac_devinfo *devinfo)
5576182999Smav{
5577182999Smav	struct hdac_widget *w, *cw;
5578182999Smav	struct hdac_audio_ctl *ctl;
5579182999Smav	int done, found, i, j, k;
5580182999Smav
5581182999Smav	/* Disable useless pins. */
5582182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5583182999Smav		w = hdac_widget_get(devinfo, i);
5584182999Smav		if (w == NULL || w->enable == 0)
5585182999Smav			continue;
5586184991Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
5587184991Smav			if ((w->wclass.pin.config &
5588184991Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
5589184991Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) {
5590184991Smav				w->enable = 0;
5591184991Smav				HDA_BOOTHVERBOSE(
5592184991Smav					device_printf(devinfo->codec->sc->dev,
5593184991Smav					    " Disabling pin nid %d due"
5594184991Smav					    " to None connectivity.\n",
5595184991Smav					    w->nid);
5596184991Smav				);
5597184991Smav			} else if ((w->wclass.pin.config &
5598184991Smav			    HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) == 0) {
5599184991Smav				w->enable = 0;
5600184991Smav				HDA_BOOTHVERBOSE(
5601184991Smav					device_printf(devinfo->codec->sc->dev,
5602184991Smav					    " Disabling unassociated"
5603184991Smav					    " pin nid %d.\n",
5604184991Smav					    w->nid);
5605184991Smav				);
5606184991Smav			}
5607182999Smav		}
5608182999Smav	}
5609182999Smav	do {
5610182999Smav		done = 1;
5611182999Smav		/* Disable and mute controls for disabled widgets. */
5612162922Sariff		i = 0;
5613162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5614182999Smav			if (ctl->enable == 0)
5615162922Sariff				continue;
5616182999Smav			if (ctl->widget->enable == 0 ||
5617182999Smav			    (ctl->childwidget != NULL &&
5618182999Smav			    ctl->childwidget->enable == 0)) {
5619182999Smav				ctl->forcemute = 1;
5620182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5621182999Smav				ctl->left = 0;
5622182999Smav				ctl->right = 0;
5623182999Smav				ctl->enable = 0;
5624182999Smav				if (ctl->ndir == HDA_CTL_IN)
5625182999Smav					ctl->widget->connsenable[ctl->index] = 0;
5626182999Smav				done = 0;
5627183097Smav				HDA_BOOTHVERBOSE(
5628182999Smav					device_printf(devinfo->codec->sc->dev,
5629182999Smav					    " Disabling ctl %d nid %d cnid %d due"
5630182999Smav					    " to disabled widget.\n", i,
5631182999Smav					    ctl->widget->nid,
5632182999Smav					    (ctl->childwidget != NULL)?
5633182999Smav					    ctl->childwidget->nid:-1);
5634182999Smav				);
5635182999Smav			}
5636182999Smav		}
5637182999Smav		/* Disable useless widgets. */
5638182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5639182999Smav			w = hdac_widget_get(devinfo, i);
5640182999Smav			if (w == NULL || w->enable == 0)
5641182999Smav				continue;
5642182999Smav			/* Disable inputs with disabled child widgets. */
5643182999Smav			for (j = 0; j < w->nconns; j++) {
5644182999Smav				if (w->connsenable[j]) {
5645182999Smav					cw = hdac_widget_get(devinfo, w->conns[j]);
5646182999Smav					if (cw == NULL || cw->enable == 0) {
5647182999Smav						w->connsenable[j] = 0;
5648183097Smav						HDA_BOOTHVERBOSE(
5649182999Smav							device_printf(devinfo->codec->sc->dev,
5650182999Smav							    " Disabling nid %d connection %d due"
5651182999Smav							    " to disabled child widget.\n",
5652182999Smav							    i, j);
5653182999Smav						);
5654163057Sariff					}
5655163057Sariff				}
5656162922Sariff			}
5657182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5658182999Smav			    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5659162922Sariff				continue;
5660182999Smav			/* Disable mixers and selectors without inputs. */
5661182999Smav			found = 0;
5662182999Smav			for (j = 0; j < w->nconns; j++) {
5663182999Smav				if (w->connsenable[j]) {
5664182999Smav					found = 1;
5665162922Sariff					break;
5666162922Sariff				}
5667182999Smav			}
5668182999Smav			if (found == 0) {
5669182999Smav				w->enable = 0;
5670182999Smav				done = 0;
5671183097Smav				HDA_BOOTHVERBOSE(
5672182999Smav					device_printf(devinfo->codec->sc->dev,
5673182999Smav					    " Disabling nid %d due to all it's"
5674182999Smav					    " inputs disabled.\n", w->nid);
5675182999Smav				);
5676182999Smav			}
5677182999Smav			/* Disable nodes without consumers. */
5678182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5679182999Smav			    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5680182999Smav				continue;
5681182999Smav			found = 0;
5682182999Smav			for (k = devinfo->startnode; k < devinfo->endnode; k++) {
5683182999Smav				cw = hdac_widget_get(devinfo, k);
5684182999Smav				if (cw == NULL || cw->enable == 0)
5685182999Smav					continue;
5686182999Smav				for (j = 0; j < cw->nconns; j++) {
5687182999Smav					if (cw->connsenable[j] && cw->conns[j] == i) {
5688182999Smav						found = 1;
5689182999Smav						break;
5690182999Smav					}
5691162922Sariff				}
5692162922Sariff			}
5693182999Smav			if (found == 0) {
5694182999Smav				w->enable = 0;
5695182999Smav				done = 0;
5696183097Smav				HDA_BOOTHVERBOSE(
5697182999Smav					device_printf(devinfo->codec->sc->dev,
5698182999Smav					    " Disabling nid %d due to all it's"
5699182999Smav					    " consumers disabled.\n", w->nid);
5700182999Smav				);
5701182999Smav			}
5702162922Sariff		}
5703182999Smav	} while (done == 0);
5704182999Smav
5705182999Smav}
5706182999Smav
5707182999Smavstatic void
5708182999Smavhdac_audio_disable_unas(struct hdac_devinfo *devinfo)
5709182999Smav{
5710182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5711182999Smav	struct hdac_widget *w, *cw;
5712182999Smav	struct hdac_audio_ctl *ctl;
5713182999Smav	int i, j, k;
5714182999Smav
5715182999Smav	/* Disable unassosiated widgets. */
5716182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5717182999Smav		w = hdac_widget_get(devinfo, i);
5718182999Smav		if (w == NULL || w->enable == 0)
5719182999Smav			continue;
5720182999Smav		if (w->bindas == -1) {
5721182999Smav			w->enable = 0;
5722183097Smav			HDA_BOOTHVERBOSE(
5723182999Smav				device_printf(devinfo->codec->sc->dev,
5724182999Smav				    " Disabling unassociated nid %d.\n",
5725182999Smav				    w->nid);
5726182999Smav			);
5727182999Smav		}
5728182999Smav	}
5729182999Smav	/* Disable input connections on input pin and
5730182999Smav	 * output on output. */
5731182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5732182999Smav		w = hdac_widget_get(devinfo, i);
5733182999Smav		if (w == NULL || w->enable == 0)
5734182999Smav			continue;
5735182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5736182999Smav			continue;
5737182999Smav		if (w->bindas < 0)
5738182999Smav			continue;
5739182999Smav		if (as[w->bindas].dir == HDA_CTL_IN) {
5740182999Smav			for (j = 0; j < w->nconns; j++) {
5741182999Smav				if (w->connsenable[j] == 0)
5742182999Smav					continue;
5743182999Smav				w->connsenable[j] = 0;
5744183097Smav				HDA_BOOTHVERBOSE(
5745182999Smav					device_printf(devinfo->codec->sc->dev,
5746182999Smav					    " Disabling connection to input pin "
5747182999Smav					    "nid %d conn %d.\n",
5748182999Smav					    i, j);
5749182999Smav				);
5750162922Sariff			}
5751182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5752182999Smav			    HDA_CTL_IN, -1, 1);
5753182999Smav			if (ctl && ctl->enable) {
5754182999Smav				ctl->forcemute = 1;
5755182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5756182999Smav				ctl->left = 0;
5757182999Smav				ctl->right = 0;
5758182999Smav				ctl->enable = 0;
5759182999Smav			}
5760182999Smav		} else {
5761182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5762182999Smav			    HDA_CTL_OUT, -1, 1);
5763182999Smav			if (ctl && ctl->enable) {
5764182999Smav				ctl->forcemute = 1;
5765182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5766182999Smav				ctl->left = 0;
5767182999Smav				ctl->right = 0;
5768182999Smav				ctl->enable = 0;
5769182999Smav			}
5770182999Smav			for (k = devinfo->startnode; k < devinfo->endnode; k++) {
5771182999Smav				cw = hdac_widget_get(devinfo, k);
5772182999Smav				if (cw == NULL || cw->enable == 0)
5773182999Smav					continue;
5774182999Smav				for (j = 0; j < cw->nconns; j++) {
5775182999Smav					if (cw->connsenable[j] && cw->conns[j] == i) {
5776182999Smav						cw->connsenable[j] = 0;
5777183097Smav						HDA_BOOTHVERBOSE(
5778182999Smav							device_printf(devinfo->codec->sc->dev,
5779182999Smav							    " Disabling connection from output pin "
5780182999Smav							    "nid %d conn %d cnid %d.\n",
5781182999Smav							    k, j, i);
5782182999Smav						);
5783182999Smav						if (cw->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5784182999Smav						    cw->nconns > 1)
5785182999Smav							continue;
5786182999Smav						ctl = hdac_audio_ctl_amp_get(devinfo, k,
5787182999Smav		    				    HDA_CTL_IN, j, 1);
5788182999Smav						if (ctl && ctl->enable) {
5789182999Smav							ctl->forcemute = 1;
5790182999Smav							ctl->muted = HDA_AMP_MUTE_ALL;
5791182999Smav							ctl->left = 0;
5792182999Smav							ctl->right = 0;
5793182999Smav							ctl->enable = 0;
5794182999Smav						}
5795182999Smav					}
5796182999Smav				}
5797182999Smav			}
5798162922Sariff		}
5799162922Sariff	}
5800162922Sariff}
5801162922Sariff
5802182999Smavstatic void
5803182999Smavhdac_audio_disable_notselected(struct hdac_devinfo *devinfo)
5804162922Sariff{
5805182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5806182999Smav	struct hdac_widget *w;
5807182999Smav	int i, j;
5808182999Smav
5809182999Smav	/* On playback path we can safely disable all unseleted inputs. */
5810182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5811182999Smav		w = hdac_widget_get(devinfo, i);
5812182999Smav		if (w == NULL || w->enable == 0)
5813182999Smav			continue;
5814182999Smav		if (w->nconns <= 1)
5815182999Smav			continue;
5816182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5817182999Smav			continue;
5818182999Smav		if (w->bindas < 0 || as[w->bindas].dir == HDA_CTL_IN)
5819182999Smav			continue;
5820182999Smav		for (j = 0; j < w->nconns; j++) {
5821182999Smav			if (w->connsenable[j] == 0)
5822182999Smav				continue;
5823182999Smav			if (w->selconn < 0 || w->selconn == j)
5824182999Smav				continue;
5825182999Smav			w->connsenable[j] = 0;
5826183097Smav			HDA_BOOTHVERBOSE(
5827182999Smav				device_printf(devinfo->codec->sc->dev,
5828182999Smav				    " Disabling unselected connection "
5829182999Smav				    "nid %d conn %d.\n",
5830182999Smav				    i, j);
5831182999Smav			);
5832182999Smav		}
5833182999Smav	}
5834182999Smav}
5835182999Smav
5836182999Smavstatic void
5837182999Smavhdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
5838182999Smav{
5839202789Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
5840162922Sariff	struct hdac_widget *w, *cw;
5841162922Sariff	struct hdac_audio_ctl *ctl;
5842182999Smav	int i, j;
5843162922Sariff
5844187052Smav	/* Disable crossassociatement and unwanted crosschannel connections. */
5845182999Smav	/* ... using selectors */
5846182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5847182999Smav		w = hdac_widget_get(devinfo, i);
5848182999Smav		if (w == NULL || w->enable == 0)
5849182999Smav			continue;
5850182999Smav		if (w->nconns <= 1)
5851182999Smav			continue;
5852182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5853182999Smav			continue;
5854182999Smav		if (w->bindas == -2)
5855182999Smav			continue;
5856182999Smav		for (j = 0; j < w->nconns; j++) {
5857182999Smav			if (w->connsenable[j] == 0)
5858182999Smav				continue;
5859182999Smav			cw = hdac_widget_get(devinfo, w->conns[j]);
5860182999Smav			if (cw == NULL || w->enable == 0)
5861182999Smav				continue;
5862202789Smav			if (cw->bindas == -2 ||
5863202789Smav			    ((w->pflags & HDA_ADC_MONITOR) &&
5864202789Smav			     cw->bindas >= 0 &&
5865202789Smav			     ases[cw->bindas].dir == HDA_CTL_IN))
5866182999Smav				continue;
5867187052Smav			if (w->bindas == cw->bindas &&
5868187052Smav			    (w->bindseqmask & cw->bindseqmask) != 0)
5869187052Smav				continue;
5870182999Smav			w->connsenable[j] = 0;
5871183097Smav			HDA_BOOTHVERBOSE(
5872182999Smav				device_printf(devinfo->codec->sc->dev,
5873182999Smav				    " Disabling crossassociatement connection "
5874182999Smav				    "nid %d conn %d cnid %d.\n",
5875182999Smav				    i, j, cw->nid);
5876182999Smav			);
5877182999Smav		}
5878182999Smav	}
5879182999Smav	/* ... using controls */
5880182999Smav	i = 0;
5881182999Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5882182999Smav		if (ctl->enable == 0 || ctl->childwidget == NULL)
5883182999Smav			continue;
5884202789Smav		if (ctl->widget->bindas == -2)
5885182999Smav			continue;
5886202789Smav		if (ctl->childwidget->bindas == -2 ||
5887202789Smav		    ((ctl->widget->pflags & HDA_ADC_MONITOR) &&
5888202789Smav		     ctl->childwidget->bindas >= 0 &&
5889202789Smav		     ases[ctl->childwidget->bindas].dir == HDA_CTL_IN))
5890202789Smav			continue;
5891187052Smav		if (ctl->widget->bindas != ctl->childwidget->bindas ||
5892187052Smav		    (ctl->widget->bindseqmask & ctl->childwidget->bindseqmask) == 0) {
5893182999Smav			ctl->forcemute = 1;
5894182999Smav			ctl->muted = HDA_AMP_MUTE_ALL;
5895182999Smav			ctl->left = 0;
5896182999Smav			ctl->right = 0;
5897182999Smav			ctl->enable = 0;
5898182999Smav			if (ctl->ndir == HDA_CTL_IN)
5899182999Smav				ctl->widget->connsenable[ctl->index] = 0;
5900183097Smav			HDA_BOOTHVERBOSE(
5901182999Smav				device_printf(devinfo->codec->sc->dev,
5902182999Smav				    " Disabling crossassociatement connection "
5903182999Smav				    "ctl %d nid %d cnid %d.\n", i,
5904182999Smav				    ctl->widget->nid,
5905182999Smav				    ctl->childwidget->nid);
5906182999Smav			);
5907182999Smav		}
5908182999Smav	}
5909182999Smav
5910182999Smav}
5911182999Smav
5912182999Smav#define HDA_CTL_GIVE(ctl)	((ctl)->step?1:0)
5913182999Smav
5914182999Smav/*
5915182999Smav * Find controls to control amplification for source.
5916182999Smav */
5917182999Smavstatic int
5918182999Smavhdac_audio_ctl_source_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
5919182999Smav    int ossdev, int ctlable, int depth, int need)
5920182999Smav{
5921182999Smav	struct hdac_widget *w, *wc;
5922182999Smav	struct hdac_audio_ctl *ctl;
5923182999Smav	int i, j, conns = 0, rneed;
5924182999Smav
5925162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
5926182999Smav		return (need);
5927162922Sariff
5928162922Sariff	w = hdac_widget_get(devinfo, nid);
5929162922Sariff	if (w == NULL || w->enable == 0)
5930182999Smav		return (need);
5931182999Smav
5932182999Smav	/* Count number of active inputs. */
5933182999Smav	if (depth > 0) {
5934182999Smav		for (j = 0; j < w->nconns; j++) {
5935182999Smav			if (w->connsenable[j])
5936182999Smav				conns++;
5937162922Sariff		}
5938162922Sariff	}
5939182999Smav
5940182999Smav	/* If this is not a first step - use input mixer.
5941182999Smav	   Pins have common input ctl so care must be taken. */
5942182999Smav	if (depth > 0 && ctlable && (conns == 1 ||
5943182999Smav	    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)) {
5944182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_IN,
5945182999Smav		    index, 1);
5946182999Smav		if (ctl) {
5947182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5948182999Smav				ctl->ossmask |= (1 << ossdev);
5949182999Smav			else
5950182999Smav				ctl->possmask |= (1 << ossdev);
5951182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5952182999Smav		}
5953182999Smav	}
5954182999Smav
5955182999Smav	/* If widget has own ossdev - not traverse it.
5956182999Smav	   It will be traversed on it's own. */
5957182999Smav	if (w->ossdev >= 0 && depth > 0)
5958182999Smav		return (need);
5959182999Smav
5960182999Smav	/* We must not traverse pin */
5961182999Smav	if ((w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
5962182999Smav	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
5963182999Smav	    depth > 0)
5964182999Smav		return (need);
5965182999Smav
5966182999Smav	/* record that this widget exports such signal, */
5967182999Smav	w->ossmask |= (1 << ossdev);
5968182999Smav
5969182999Smav	/* If signals mixed, we can't assign controls farther.
5970182999Smav	 * Ignore this on depth zero. Caller must knows why.
5971182999Smav	 * Ignore this for static selectors if this input selected.
5972182999Smav	 */
5973182999Smav	if (conns > 1)
5974182999Smav		ctlable = 0;
5975182999Smav
5976182999Smav	if (ctlable) {
5977182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_OUT, -1, 1);
5978182999Smav		if (ctl) {
5979182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5980182999Smav				ctl->ossmask |= (1 << ossdev);
5981182999Smav			else
5982182999Smav				ctl->possmask |= (1 << ossdev);
5983182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5984182999Smav		}
5985182999Smav	}
5986182999Smav
5987182999Smav	rneed = 0;
5988182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5989182999Smav		wc = hdac_widget_get(devinfo, i);
5990182999Smav		if (wc == NULL || wc->enable == 0)
5991162922Sariff			continue;
5992182999Smav		for (j = 0; j < wc->nconns; j++) {
5993182999Smav			if (wc->connsenable[j] && wc->conns[j] == nid) {
5994182999Smav				rneed |= hdac_audio_ctl_source_amp(devinfo,
5995182999Smav				    wc->nid, j, ossdev, ctlable, depth + 1, need);
5996182999Smav			}
5997162922Sariff		}
5998162922Sariff	}
5999182999Smav	rneed &= need;
6000182999Smav
6001182999Smav	return (rneed);
6002162922Sariff}
6003162922Sariff
6004182999Smav/*
6005182999Smav * Find controls to control amplification for destination.
6006182999Smav */
6007182999Smavstatic void
6008202789Smavhdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
6009182999Smav    int ossdev, int depth, int need)
6010162922Sariff{
6011182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6012182999Smav	struct hdac_widget *w, *wc;
6013182999Smav	struct hdac_audio_ctl *ctl;
6014182999Smav	int i, j, consumers;
6015182999Smav
6016162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
6017182999Smav		return;
6018162922Sariff
6019162922Sariff	w = hdac_widget_get(devinfo, nid);
6020162922Sariff	if (w == NULL || w->enable == 0)
6021182999Smav		return;
6022182999Smav
6023182999Smav	if (depth > 0) {
6024182999Smav		/* If this node produce output for several consumers,
6025182999Smav		   we can't touch it. */
6026182999Smav		consumers = 0;
6027182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6028182999Smav			wc = hdac_widget_get(devinfo, i);
6029182999Smav			if (wc == NULL || wc->enable == 0)
6030182999Smav				continue;
6031182999Smav			for (j = 0; j < wc->nconns; j++) {
6032182999Smav				if (wc->connsenable[j] && wc->conns[j] == nid)
6033182999Smav					consumers++;
6034182999Smav			}
6035182999Smav		}
6036182999Smav		/* The only exception is if real HP redirection is configured
6037182999Smav		   and this is a duplication point.
6038182999Smav		   XXX: Actually exception is not completely correct.
6039182999Smav		   XXX: Duplication point check is not perfect. */
6040182999Smav		if ((consumers == 2 && (w->bindas < 0 ||
6041182999Smav		    as[w->bindas].hpredir < 0 || as[w->bindas].fakeredir ||
6042182999Smav		    (w->bindseqmask & (1 << 15)) == 0)) ||
6043182999Smav		    consumers > 2)
6044182999Smav			return;
6045182999Smav
6046182999Smav		/* Else use it's output mixer. */
6047182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
6048182999Smav		    HDA_CTL_OUT, -1, 1);
6049182999Smav		if (ctl) {
6050182999Smav			if (HDA_CTL_GIVE(ctl) & need)
6051182999Smav				ctl->ossmask |= (1 << ossdev);
6052182999Smav			else
6053182999Smav				ctl->possmask |= (1 << ossdev);
6054182999Smav			need &= ~HDA_CTL_GIVE(ctl);
6055182999Smav		}
6056182999Smav	}
6057182999Smav
6058182999Smav	/* We must not traverse pin */
6059182999Smav	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
6060182999Smav	    depth > 0)
6061182999Smav		return;
6062182999Smav
6063162922Sariff	for (i = 0; i < w->nconns; i++) {
6064182999Smav		int tneed = need;
6065182999Smav		if (w->connsenable[i] == 0)
6066162922Sariff			continue;
6067202789Smav		if (index >= 0 && i != index)
6068202789Smav			continue;
6069182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
6070182999Smav		    HDA_CTL_IN, i, 1);
6071182999Smav		if (ctl) {
6072182999Smav			if (HDA_CTL_GIVE(ctl) & tneed)
6073182999Smav				ctl->ossmask |= (1 << ossdev);
6074182999Smav			else
6075182999Smav				ctl->possmask |= (1 << ossdev);
6076182999Smav			tneed &= ~HDA_CTL_GIVE(ctl);
6077162922Sariff		}
6078202789Smav		hdac_audio_ctl_dest_amp(devinfo, w->conns[i], -1, ossdev,
6079182999Smav		    depth + 1, tneed);
6080162922Sariff	}
6081162922Sariff}
6082162922Sariff
6083182999Smav/*
6084182999Smav * Assign OSS names to sound sources
6085182999Smav */
6086182999Smavstatic void
6087182999Smavhdac_audio_assign_names(struct hdac_devinfo *devinfo)
6088162922Sariff{
6089182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6090182999Smav	struct hdac_widget *w;
6091182999Smav	int i, j;
6092182999Smav	int type = -1, use, used = 0;
6093182999Smav	static const int types[7][13] = {
6094182999Smav	    { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
6095182999Smav	      SOUND_MIXER_LINE3, -1 },	/* line */
6096182999Smav	    { SOUND_MIXER_MONITOR, SOUND_MIXER_MIC, -1 }, /* int mic */
6097182999Smav	    { SOUND_MIXER_MIC, SOUND_MIXER_MONITOR, -1 }, /* ext mic */
6098182999Smav	    { SOUND_MIXER_CD, -1 },	/* cd */
6099182999Smav	    { SOUND_MIXER_SPEAKER, -1 },	/* speaker */
6100182999Smav	    { SOUND_MIXER_DIGITAL1, SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3,
6101182999Smav	      -1 },	/* digital */
6102182999Smav	    { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
6103182999Smav	      SOUND_MIXER_LINE3, SOUND_MIXER_PHONEIN, SOUND_MIXER_PHONEOUT,
6104182999Smav	      SOUND_MIXER_VIDEO, SOUND_MIXER_RADIO, SOUND_MIXER_DIGITAL1,
6105182999Smav	      SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3, SOUND_MIXER_MONITOR,
6106182999Smav	      -1 }	/* others */
6107182999Smav	};
6108162922Sariff
6109182999Smav	/* Surely known names */
6110162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6111162922Sariff		w = hdac_widget_get(devinfo, i);
6112162922Sariff		if (w == NULL || w->enable == 0)
6113162922Sariff			continue;
6114182999Smav		if (w->bindas == -1)
6115182999Smav			continue;
6116182999Smav		use = -1;
6117182999Smav		switch (w->type) {
6118182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
6119182999Smav			if (as[w->bindas].dir == HDA_CTL_OUT)
6120182999Smav				break;
6121182999Smav			type = -1;
6122182999Smav			switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
6123182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
6124182999Smav				type = 0;
6125182999Smav				break;
6126182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
6127182999Smav				if ((w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK)
6128182999Smav				    == HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
6129182999Smav					break;
6130182999Smav				type = 1;
6131182999Smav				break;
6132182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
6133182999Smav				type = 3;
6134182999Smav				break;
6135182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
6136182999Smav				type = 4;
6137182999Smav				break;
6138182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
6139182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
6140182999Smav				type = 5;
6141182999Smav				break;
6142182999Smav			}
6143182999Smav			if (type == -1)
6144182999Smav				break;
6145182999Smav			j = 0;
6146182999Smav			while (types[type][j] >= 0 &&
6147182999Smav			    (used & (1 << types[type][j])) != 0) {
6148182999Smav				j++;
6149182999Smav			}
6150182999Smav			if (types[type][j] >= 0)
6151182999Smav				use = types[type][j];
6152182999Smav			break;
6153182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
6154182999Smav			use = SOUND_MIXER_PCM;
6155182999Smav			break;
6156182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
6157182999Smav			use = SOUND_MIXER_SPEAKER;
6158182999Smav			break;
6159182999Smav		default:
6160182999Smav			break;
6161182999Smav		}
6162182999Smav		if (use >= 0) {
6163182999Smav			w->ossdev = use;
6164182999Smav			used |= (1 << use);
6165182999Smav		}
6166182999Smav	}
6167182999Smav	/* Semi-known names */
6168182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6169182999Smav		w = hdac_widget_get(devinfo, i);
6170182999Smav		if (w == NULL || w->enable == 0)
6171182999Smav			continue;
6172182999Smav		if (w->ossdev >= 0)
6173182999Smav			continue;
6174182999Smav		if (w->bindas == -1)
6175182999Smav			continue;
6176162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6177162922Sariff			continue;
6178182999Smav		if (as[w->bindas].dir == HDA_CTL_OUT)
6179162922Sariff			continue;
6180182999Smav		type = -1;
6181182999Smav		switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
6182182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
6183182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
6184182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
6185182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
6186182999Smav			type = 0;
6187182999Smav			break;
6188182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
6189182999Smav			type = 2;
6190182999Smav			break;
6191182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
6192182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
6193182999Smav			type = 5;
6194182999Smav			break;
6195182999Smav		}
6196182999Smav		if (type == -1)
6197182999Smav			break;
6198182999Smav		j = 0;
6199182999Smav		while (types[type][j] >= 0 &&
6200182999Smav		    (used & (1 << types[type][j])) != 0) {
6201182999Smav			j++;
6202182999Smav		}
6203182999Smav		if (types[type][j] >= 0) {
6204182999Smav			w->ossdev = types[type][j];
6205182999Smav			used |= (1 << types[type][j]);
6206182999Smav		}
6207182999Smav	}
6208182999Smav	/* Others */
6209182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6210182999Smav		w = hdac_widget_get(devinfo, i);
6211182999Smav		if (w == NULL || w->enable == 0)
6212162922Sariff			continue;
6213182999Smav		if (w->ossdev >= 0)
6214182999Smav			continue;
6215182999Smav		if (w->bindas == -1)
6216182999Smav			continue;
6217182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6218182999Smav			continue;
6219182999Smav		if (as[w->bindas].dir == HDA_CTL_OUT)
6220182999Smav			continue;
6221182999Smav		j = 0;
6222182999Smav		while (types[6][j] >= 0 &&
6223182999Smav		    (used & (1 << types[6][j])) != 0) {
6224182999Smav			j++;
6225162922Sariff		}
6226182999Smav		if (types[6][j] >= 0) {
6227182999Smav			w->ossdev = types[6][j];
6228182999Smav			used |= (1 << types[6][j]);
6229182999Smav		}
6230162922Sariff	}
6231162922Sariff}
6232162922Sariff
6233162922Sariffstatic void
6234162922Sariffhdac_audio_build_tree(struct hdac_devinfo *devinfo)
6235162922Sariff{
6236182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6237182999Smav	int j, res;
6238162922Sariff
6239182999Smav	/* Trace all associations in order of their numbers, */
6240182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
6241182999Smav		if (as[j].enable == 0)
6242182999Smav			continue;
6243163057Sariff		HDA_BOOTVERBOSE(
6244162922Sariff			device_printf(devinfo->codec->sc->dev,
6245182999Smav			    "Tracing association %d (%d)\n", j, as[j].index);
6246162922Sariff		);
6247182999Smav		if (as[j].dir == HDA_CTL_OUT) {
6248182999Smavretry:
6249182999Smav			res = hdac_audio_trace_as_out(devinfo, j, 0);
6250182999Smav			if (res == 0 && as[j].hpredir >= 0 &&
6251182999Smav			    as[j].fakeredir == 0) {
6252182999Smav				/* If codec can't do analog HP redirection
6253182999Smav				   try to make it using one more DAC. */
6254182999Smav				as[j].fakeredir = 1;
6255182999Smav				goto retry;
6256182999Smav			}
6257182999Smav		} else {
6258182999Smav			res = hdac_audio_trace_as_in(devinfo, j);
6259182999Smav		}
6260182999Smav		if (res) {
6261182999Smav			HDA_BOOTVERBOSE(
6262182999Smav				device_printf(devinfo->codec->sc->dev,
6263188510Smav				    "Association %d (%d) trace succeeded\n",
6264182999Smav				    j, as[j].index);
6265182999Smav			);
6266182999Smav		} else {
6267182999Smav			HDA_BOOTVERBOSE(
6268182999Smav				device_printf(devinfo->codec->sc->dev,
6269182999Smav				    "Association %d (%d) trace failed\n",
6270182999Smav				    j, as[j].index);
6271182999Smav			);
6272182999Smav			as[j].enable = 0;
6273182999Smav		}
6274162922Sariff	}
6275162922Sariff
6276182999Smav	/* Trace mixer and beeper pseudo associations. */
6277182999Smav	hdac_audio_trace_as_extra(devinfo);
6278182999Smav}
6279162922Sariff
6280182999Smavstatic void
6281182999Smavhdac_audio_assign_mixers(struct hdac_devinfo *devinfo)
6282182999Smav{
6283182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6284182999Smav	struct hdac_audio_ctl *ctl;
6285202789Smav	struct hdac_widget *w, *cw;
6286202789Smav	int i, j;
6287162922Sariff
6288182999Smav	/* Assign mixers to the tree. */
6289162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6290162922Sariff		w = hdac_widget_get(devinfo, i);
6291162922Sariff		if (w == NULL || w->enable == 0)
6292162922Sariff			continue;
6293182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
6294182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET ||
6295182999Smav		    (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
6296182999Smav		    as[w->bindas].dir == HDA_CTL_IN)) {
6297182999Smav			if (w->ossdev < 0)
6298182999Smav				continue;
6299182999Smav			hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
6300182999Smav			    w->ossdev, 1, 0, 1);
6301182999Smav		} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
6302202789Smav			hdac_audio_ctl_dest_amp(devinfo, w->nid, -1,
6303182999Smav			    SOUND_MIXER_RECLEV, 0, 1);
6304182999Smav		} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
6305182999Smav		    as[w->bindas].dir == HDA_CTL_OUT) {
6306202789Smav			hdac_audio_ctl_dest_amp(devinfo, w->nid, -1,
6307182999Smav			    SOUND_MIXER_VOLUME, 0, 1);
6308162922Sariff		}
6309202796Smav		if (w->ossdev == SOUND_MIXER_IMIX) {
6310202796Smav			if (hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
6311202796Smav			    w->ossdev, 1, 0, 1)) {
6312202796Smav				/* If we are unable to control input monitor
6313202796Smav				   as source - try to control it as destination. */
6314202796Smav				hdac_audio_ctl_dest_amp(devinfo, w->nid, -1,
6315202796Smav				    w->ossdev, 0, 1);
6316202796Smav			}
6317202796Smav		}
6318202789Smav		if (w->pflags & HDA_ADC_MONITOR) {
6319202789Smav			for (j = 0; j < w->nconns; j++) {
6320202789Smav				if (!w->connsenable[j])
6321202789Smav				    continue;
6322202789Smav				cw = hdac_widget_get(devinfo, w->conns[j]);
6323202789Smav				if (cw == NULL || cw->enable == 0)
6324202789Smav				    continue;
6325202789Smav				if (cw->bindas == -1)
6326202789Smav				    continue;
6327202789Smav				if (cw->bindas >= 0 &&
6328202789Smav				    as[cw->bindas].dir != HDA_CTL_IN)
6329202789Smav					continue;
6330202789Smav				hdac_audio_ctl_dest_amp(devinfo,
6331202796Smav				    w->nid, j, SOUND_MIXER_IGAIN, 0, 1);
6332202789Smav			}
6333202789Smav		}
6334162922Sariff	}
6335182999Smav	/* Treat unrequired as possible. */
6336182999Smav	i = 0;
6337182999Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6338182999Smav		if (ctl->ossmask == 0)
6339182999Smav			ctl->ossmask = ctl->possmask;
6340182999Smav	}
6341182999Smav}
6342162922Sariff
6343182999Smavstatic void
6344182999Smavhdac_audio_prepare_pin_ctrl(struct hdac_devinfo *devinfo)
6345182999Smav{
6346182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6347182999Smav	struct hdac_widget *w;
6348182999Smav	uint32_t pincap;
6349182999Smav	int i;
6350182999Smav
6351182999Smav	for (i = 0; i < devinfo->nodecnt; i++) {
6352182999Smav		w = &devinfo->widget[i];
6353182999Smav		if (w == NULL)
6354162922Sariff			continue;
6355182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6356162922Sariff			continue;
6357182999Smav
6358182999Smav		pincap = w->wclass.pin.cap;
6359182999Smav
6360182999Smav		/* Disable everything. */
6361182999Smav		w->wclass.pin.ctrl &= ~(
6362182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
6363182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
6364182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
6365182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
6366182999Smav
6367182999Smav		if (w->enable == 0 ||
6368182999Smav		    w->bindas < 0 || as[w->bindas].enable == 0) {
6369182999Smav			/* Pin is unused so left it disabled. */
6370182999Smav			continue;
6371182999Smav		} else if (as[w->bindas].dir == HDA_CTL_IN) {
6372182999Smav			/* Input pin, configure for input. */
6373182999Smav			if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
6374182999Smav				w->wclass.pin.ctrl |=
6375182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
6376182999Smav
6377182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) &&
6378182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
6379182999Smav				w->wclass.pin.ctrl |=
6380182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
6381182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
6382182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) &&
6383182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
6384182999Smav				w->wclass.pin.ctrl |=
6385182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
6386182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
6387182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) &&
6388182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
6389182999Smav				w->wclass.pin.ctrl |=
6390182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
6391182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
6392182999Smav		} else {
6393182999Smav			/* Output pin, configure for output. */
6394182999Smav			if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
6395182999Smav				w->wclass.pin.ctrl |=
6396182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
6397182999Smav
6398182999Smav			if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap) &&
6399182999Smav			    (w->wclass.pin.config &
6400182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
6401182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
6402182999Smav				w->wclass.pin.ctrl |=
6403182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
6404182999Smav
6405182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) &&
6406182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
6407182999Smav				w->wclass.pin.ctrl |=
6408182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
6409182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
6410182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) &&
6411182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
6412182999Smav				w->wclass.pin.ctrl |=
6413182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
6414182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
6415182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) &&
6416182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
6417182999Smav				w->wclass.pin.ctrl |=
6418182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
6419182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
6420182999Smav		}
6421162922Sariff	}
6422162922Sariff}
6423162922Sariff
6424162922Sariffstatic void
6425187154Smavhdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
6426187154Smav{
6427187154Smav	struct hdac_audio_ctl *ctl;
6428187154Smav	int i, z;
6429187154Smav
6430187154Smav	i = 0;
6431187154Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6432187154Smav		if (ctl->enable == 0 || ctl->ossmask != 0) {
6433187154Smav			/* Mute disabled and mixer controllable controls.
6434187154Smav			 * Last will be initialized by mixer_init().
6435187154Smav			 * This expected to reduce click on startup. */
6436187154Smav			hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_ALL, 0, 0);
6437187154Smav			continue;
6438187154Smav		}
6439187154Smav		/* Init fixed controls to 0dB amplification. */
6440187154Smav		z = ctl->offset;
6441187154Smav		if (z > ctl->step)
6442187154Smav			z = ctl->step;
6443187154Smav		hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_NONE, z, z);
6444187154Smav	}
6445187154Smav}
6446187154Smav
6447187154Smavstatic void
6448182999Smavhdac_audio_commit(struct hdac_devinfo *devinfo)
6449162922Sariff{
6450162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6451162922Sariff	struct hdac_widget *w;
6452164750Sariff	nid_t cad;
6453182999Smav	uint32_t gdata, gmask, gdir;
6454182999Smav	int commitgpio, numgpio;
6455164750Sariff	int i;
6456162922Sariff
6457162922Sariff	cad = devinfo->codec->cad;
6458162922Sariff
6459182999Smav	if (sc->pci_subvendor == APPLE_INTEL_MAC)
6460182999Smav		hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
6461182999Smav		    0x7e7, 0), cad);
6462169277Sariff
6463187154Smav	/* Commit controls. */
6464187154Smav	hdac_audio_ctl_commit(devinfo);
6465187154Smav
6466187154Smav	/* Commit selectors, pins and EAPD. */
6467187154Smav	for (i = 0; i < devinfo->nodecnt; i++) {
6468187154Smav		w = &devinfo->widget[i];
6469187154Smav		if (w == NULL)
6470187154Smav			continue;
6471187154Smav		if (w->selconn == -1)
6472187154Smav			w->selconn = 0;
6473187154Smav		if (w->nconns > 0)
6474187154Smav			hdac_widget_connection_select(w, w->selconn);
6475187154Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
6476187154Smav			hdac_command(sc,
6477187154Smav			    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
6478187154Smav			    w->wclass.pin.ctrl), cad);
6479187154Smav		}
6480187154Smav		if (w->param.eapdbtl != HDAC_INVALID) {
6481187154Smav		    	uint32_t val;
6482187154Smav
6483187154Smav			val = w->param.eapdbtl;
6484187154Smav			if (devinfo->function.audio.quirks &
6485187154Smav			    HDA_QUIRK_EAPDINV)
6486187154Smav				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
6487187154Smav			hdac_command(sc,
6488187154Smav			    HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid,
6489187154Smav			    val), cad);
6490187154Smav		}
6491187154Smav	}
6492187154Smav
6493187154Smav	/* Commit GPIOs. */
6494182999Smav	gdata = 0;
6495182999Smav	gmask = 0;
6496182999Smav	gdir = 0;
6497182999Smav	commitgpio = 0;
6498182999Smav	numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO(
6499182999Smav	    devinfo->function.audio.gpio);
6500166796Sariff
6501182999Smav	if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
6502182999Smav		commitgpio = (numgpio > 0) ? 1 : 0;
6503182999Smav	else {
6504182999Smav		for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) {
6505182999Smav			if (!(devinfo->function.audio.quirks &
6506182999Smav			    (1 << i)))
6507182999Smav				continue;
6508182999Smav			if (commitgpio == 0) {
6509182999Smav				commitgpio = 1;
6510182999Smav				HDA_BOOTVERBOSE(
6511182999Smav					gdata = hdac_command(sc,
6512182999Smav					    HDA_CMD_GET_GPIO_DATA(cad,
6513182999Smav					    devinfo->nid), cad);
6514182999Smav					gmask = hdac_command(sc,
6515182999Smav					    HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
6516182999Smav					    devinfo->nid), cad);
6517182999Smav					gdir = hdac_command(sc,
6518182999Smav					    HDA_CMD_GET_GPIO_DIRECTION(cad,
6519182999Smav					    devinfo->nid), cad);
6520182999Smav					device_printf(sc->dev,
6521182999Smav					    "GPIO init: data=0x%08x "
6522182999Smav					    "mask=0x%08x dir=0x%08x\n",
6523182999Smav					    gdata, gmask, gdir);
6524182999Smav					gdata = 0;
6525182999Smav					gmask = 0;
6526182999Smav					gdir = 0;
6527182999Smav				);
6528165039Sariff			}
6529182999Smav			gdata |= 1 << i;
6530182999Smav			gmask |= 1 << i;
6531182999Smav			gdir |= 1 << i;
6532165039Sariff		}
6533182999Smav	}
6534165039Sariff
6535182999Smav	if (commitgpio != 0) {
6536182999Smav		HDA_BOOTVERBOSE(
6537182999Smav			device_printf(sc->dev,
6538182999Smav			    "GPIO commit: data=0x%08x mask=0x%08x "
6539182999Smav			    "dir=0x%08x\n",
6540182999Smav			    gdata, gmask, gdir);
6541182999Smav		);
6542182999Smav		hdac_command(sc,
6543182999Smav		    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
6544182999Smav		    gmask), cad);
6545182999Smav		hdac_command(sc,
6546182999Smav		    HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
6547182999Smav		    gdir), cad);
6548182999Smav		hdac_command(sc,
6549182999Smav		    HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
6550182999Smav		    gdata), cad);
6551162922Sariff	}
6552162922Sariff}
6553162922Sariff
6554162922Sariffstatic void
6555182999Smavhdac_powerup(struct hdac_devinfo *devinfo)
6556182999Smav{
6557182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
6558182999Smav	nid_t cad = devinfo->codec->cad;
6559182999Smav	int i;
6560182999Smav
6561182999Smav	hdac_command(sc,
6562182999Smav	    HDA_CMD_SET_POWER_STATE(cad,
6563182999Smav	    devinfo->nid, HDA_CMD_POWER_STATE_D0),
6564182999Smav	    cad);
6565182999Smav	DELAY(100);
6566182999Smav
6567182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6568182999Smav		hdac_command(sc,
6569182999Smav		    HDA_CMD_SET_POWER_STATE(cad,
6570182999Smav		    i, HDA_CMD_POWER_STATE_D0),
6571182999Smav		    cad);
6572182999Smav	}
6573182999Smav	DELAY(1000);
6574182999Smav}
6575182999Smav
6576162922Sariffstatic int
6577182999Smavhdac_pcmchannel_setup(struct hdac_chan *ch)
6578162922Sariff{
6579182999Smav	struct hdac_devinfo *devinfo = ch->devinfo;
6580182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6581162922Sariff	struct hdac_widget *w;
6582182999Smav	uint32_t cap, fmtcap, pcmcap;
6583202127Smav	int i, j, ret, channels, onlystereo;
6584202127Smav	uint16_t pinset;
6585162922Sariff
6586162922Sariff	ch->caps = hdac_caps;
6587162922Sariff	ch->caps.fmtlist = ch->fmtlist;
6588162922Sariff	ch->bit16 = 1;
6589162922Sariff	ch->bit32 = 0;
6590162922Sariff	ch->pcmrates[0] = 48000;
6591162922Sariff	ch->pcmrates[1] = 0;
6592162922Sariff
6593162922Sariff	ret = 0;
6594202127Smav	channels = 0;
6595202127Smav	onlystereo = 1;
6596202127Smav	pinset = 0;
6597162922Sariff	fmtcap = devinfo->function.audio.supp_stream_formats;
6598162922Sariff	pcmcap = devinfo->function.audio.supp_pcm_size_rate;
6599162922Sariff
6600202127Smav	for (i = 0; i < 16; i++) {
6601182999Smav		/* Check as is correct */
6602182999Smav		if (ch->as < 0)
6603182999Smav			break;
6604182999Smav		/* Cound only present DACs */
6605182999Smav		if (as[ch->as].dacs[i] <= 0)
6606162922Sariff			continue;
6607182999Smav		/* Ignore duplicates */
6608182999Smav		for (j = 0; j < ret; j++) {
6609182999Smav			if (ch->io[j] == as[ch->as].dacs[i])
6610182999Smav				break;
6611182999Smav		}
6612182999Smav		if (j < ret)
6613162922Sariff			continue;
6614182999Smav
6615182999Smav		w = hdac_widget_get(devinfo, as[ch->as].dacs[i]);
6616182999Smav		if (w == NULL || w->enable == 0)
6617182999Smav			continue;
6618162922Sariff		cap = w->param.supp_stream_formats;
6619182999Smav		if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap) &&
6620182999Smav		    !HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
6621162922Sariff			continue;
6622202127Smav		/* Many CODECs does not declare AC3 support on SPDIF.
6623182999Smav		   I don't beleave that they doesn't support it! */
6624182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6625182999Smav			cap |= HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK;
6626164614Sariff		if (ret == 0) {
6627182999Smav			fmtcap = cap;
6628164614Sariff			pcmcap = w->param.supp_pcm_size_rate;
6629164614Sariff		} else {
6630182999Smav			fmtcap &= cap;
6631164614Sariff			pcmcap &= w->param.supp_pcm_size_rate;
6632164614Sariff		}
6633182999Smav		ch->io[ret++] = as[ch->as].dacs[i];
6634202127Smav		/* Do not count redirection pin/dac channels. */
6635202127Smav		if (i == 15 && as[ch->as].hpredir >= 0)
6636202127Smav			continue;
6637202127Smav		channels += HDA_PARAM_AUDIO_WIDGET_CAP_CC(w->param.widget_cap) + 1;
6638202127Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_CC(w->param.widget_cap) != 1)
6639202127Smav			onlystereo = 0;
6640202127Smav		pinset |= (1 << i);
6641162922Sariff	}
6642162922Sariff	ch->io[ret] = -1;
6643162922Sariff
6644202127Smav	if (as[ch->as].fakeredir)
6645202127Smav		ret--;
6646202127Smav	/* Standard speaks only about stereo pins and playback, ... */
6647202127Smav	if ((!onlystereo) || as[ch->as].dir != HDA_CTL_OUT)
6648202127Smav		pinset = 0;
6649202127Smav	/* ..., but there it gives us info about speakers layout. */
6650202127Smav	as[ch->as].pinset = pinset;
6651202127Smav
6652162922Sariff	ch->supp_stream_formats = fmtcap;
6653162922Sariff	ch->supp_pcm_size_rate = pcmcap;
6654162922Sariff
6655162922Sariff	/*
6656162922Sariff	 *  8bit = 0
6657162922Sariff	 * 16bit = 1
6658162922Sariff	 * 20bit = 2
6659162922Sariff	 * 24bit = 3
6660162922Sariff	 * 32bit = 4
6661162922Sariff	 */
6662162922Sariff	if (ret > 0) {
6663162922Sariff		i = 0;
6664182999Smav		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(fmtcap)) {
6665182999Smav			if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(pcmcap))
6666182999Smav				ch->bit16 = 1;
6667182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(pcmcap))
6668182999Smav				ch->bit16 = 0;
6669182999Smav			if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(pcmcap))
6670182999Smav				ch->bit32 = 4;
6671182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(pcmcap))
6672182999Smav				ch->bit32 = 3;
6673182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(pcmcap))
6674182999Smav				ch->bit32 = 2;
6675202127Smav			if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO)) {
6676202127Smav				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 1, 0);
6677202127Smav				if (ch->bit32)
6678202127Smav					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 1, 0);
6679182999Smav			}
6680202127Smav			if (channels >= 2) {
6681202127Smav				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 2, 0);
6682202127Smav				if (ch->bit32)
6683202127Smav					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 2, 0);
6684202127Smav			}
6685202127Smav			if (channels == 4 || /* Any 4-channel */
6686202127Smav			    pinset == 0x0007 || /* 5.1 */
6687202127Smav			    pinset == 0x0013 || /* 5.1 */
6688202127Smav			    pinset == 0x0017) {  /* 7.1 */
6689202127Smav				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 4, 0);
6690202127Smav				if (ch->bit32)
6691202127Smav					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 4, 0);
6692202127Smav			}
6693202127Smav			if (channels == 6 || /* Any 6-channel */
6694202127Smav			    pinset == 0x0017) {  /* 7.1 */
6695202127Smav				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 6, 1);
6696202127Smav				if (ch->bit32)
6697202127Smav					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 6, 1);
6698202127Smav			}
6699202127Smav			if (channels == 8) { /* Any 8-channel */
6700202127Smav				ch->fmtlist[i++] = SND_FORMAT(AFMT_S16_LE, 8, 1);
6701202127Smav				if (ch->bit32)
6702202127Smav					ch->fmtlist[i++] = SND_FORMAT(AFMT_S32_LE, 8, 1);
6703202127Smav			}
6704162922Sariff		}
6705182999Smav		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(fmtcap)) {
6706193640Sariff			ch->fmtlist[i++] = SND_FORMAT(AFMT_AC3, 2, 0);
6707182999Smav		}
6708162922Sariff		ch->fmtlist[i] = 0;
6709162922Sariff		i = 0;
6710182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(pcmcap))
6711162922Sariff			ch->pcmrates[i++] = 8000;
6712182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(pcmcap))
6713162922Sariff			ch->pcmrates[i++] = 11025;
6714182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(pcmcap))
6715162922Sariff			ch->pcmrates[i++] = 16000;
6716182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(pcmcap))
6717162922Sariff			ch->pcmrates[i++] = 22050;
6718182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(pcmcap))
6719162922Sariff			ch->pcmrates[i++] = 32000;
6720182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(pcmcap))
6721162922Sariff			ch->pcmrates[i++] = 44100;
6722182999Smav		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(pcmcap)) */
6723162922Sariff		ch->pcmrates[i++] = 48000;
6724182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(pcmcap))
6725162922Sariff			ch->pcmrates[i++] = 88200;
6726182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(pcmcap))
6727162922Sariff			ch->pcmrates[i++] = 96000;
6728182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(pcmcap))
6729162922Sariff			ch->pcmrates[i++] = 176400;
6730182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(pcmcap))
6731162922Sariff			ch->pcmrates[i++] = 192000;
6732182999Smav		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(pcmcap)) */
6733162922Sariff		ch->pcmrates[i] = 0;
6734162922Sariff		if (i > 0) {
6735162922Sariff			ch->caps.minspeed = ch->pcmrates[0];
6736162922Sariff			ch->caps.maxspeed = ch->pcmrates[i - 1];
6737162922Sariff		}
6738162922Sariff	}
6739162922Sariff
6740162922Sariff	return (ret);
6741162922Sariff}
6742162922Sariff
6743162922Sariffstatic void
6744185225Smavhdac_create_pcms(struct hdac_devinfo *devinfo)
6745185225Smav{
6746185225Smav	struct hdac_softc *sc = devinfo->codec->sc;
6747185225Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6748185225Smav	int i, j, apdev = 0, ardev = 0, dpdev = 0, drdev = 0;
6749185225Smav
6750185225Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
6751185225Smav		if (as[i].enable == 0)
6752185225Smav			continue;
6753185225Smav		if (as[i].dir == HDA_CTL_IN) {
6754185225Smav			if (as[i].digital)
6755185225Smav				drdev++;
6756185225Smav			else
6757185225Smav				ardev++;
6758185225Smav		} else {
6759185225Smav			if (as[i].digital)
6760185225Smav				dpdev++;
6761185225Smav			else
6762185225Smav				apdev++;
6763185225Smav		}
6764185225Smav	}
6765185225Smav	devinfo->function.audio.num_devs =
6766185225Smav	    max(ardev, apdev) + max(drdev, dpdev);
6767185225Smav	devinfo->function.audio.devs =
6768185225Smav	    (struct hdac_pcm_devinfo *)malloc(
6769185225Smav	    devinfo->function.audio.num_devs * sizeof(struct hdac_pcm_devinfo),
6770185225Smav	    M_HDAC, M_ZERO | M_NOWAIT);
6771185225Smav	if (devinfo->function.audio.devs == NULL) {
6772185225Smav		device_printf(sc->dev,
6773185225Smav		    "Unable to allocate memory for devices\n");
6774185225Smav		return;
6775185225Smav	}
6776185225Smav	for (i = 0; i < devinfo->function.audio.num_devs; i++) {
6777185225Smav		devinfo->function.audio.devs[i].index = i;
6778185225Smav		devinfo->function.audio.devs[i].devinfo = devinfo;
6779185225Smav		devinfo->function.audio.devs[i].play = -1;
6780185225Smav		devinfo->function.audio.devs[i].rec = -1;
6781197611Smav		devinfo->function.audio.devs[i].digital = 255;
6782185225Smav	}
6783185225Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
6784185225Smav		if (as[i].enable == 0)
6785185225Smav			continue;
6786185225Smav		for (j = 0; j < devinfo->function.audio.num_devs; j++) {
6787197611Smav			if (devinfo->function.audio.devs[j].digital != 255 &&
6788197640Smav			    (!devinfo->function.audio.devs[j].digital) !=
6789197611Smav			    (!as[i].digital))
6790185225Smav				continue;
6791185225Smav			if (as[i].dir == HDA_CTL_IN) {
6792185225Smav				if (devinfo->function.audio.devs[j].rec >= 0)
6793185225Smav					continue;
6794185225Smav				devinfo->function.audio.devs[j].rec
6795185225Smav				    = as[i].chan;
6796185225Smav			} else {
6797185225Smav				if (devinfo->function.audio.devs[j].play >= 0)
6798185225Smav					continue;
6799185225Smav				devinfo->function.audio.devs[j].play
6800185225Smav				    = as[i].chan;
6801185225Smav			}
6802185225Smav			sc->chans[as[i].chan].pdevinfo =
6803185225Smav			    &devinfo->function.audio.devs[j];
6804185225Smav			devinfo->function.audio.devs[j].digital =
6805185225Smav			    as[i].digital;
6806185225Smav			break;
6807185225Smav		}
6808185225Smav	}
6809185225Smav	for (i = 0; i < devinfo->function.audio.num_devs; i++) {
6810185225Smav		struct hdac_pcm_devinfo *pdevinfo =
6811185225Smav		    &devinfo->function.audio.devs[i];
6812185225Smav		pdevinfo->dev =
6813185225Smav		    device_add_child(sc->dev, "pcm", -1);
6814185225Smav		device_set_ivars(pdevinfo->dev,
6815185225Smav		     (void *)pdevinfo);
6816185225Smav	}
6817185225Smav}
6818185225Smav
6819185225Smavstatic void
6820182999Smavhdac_dump_ctls(struct hdac_pcm_devinfo *pdevinfo, const char *banner, uint32_t flag)
6821162922Sariff{
6822182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6823162922Sariff	struct hdac_audio_ctl *ctl;
6824162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6825182999Smav	char buf[64];
6826182999Smav	int i, j, printed;
6827162922Sariff
6828162922Sariff	if (flag == 0) {
6829182999Smav		flag = ~(SOUND_MASK_VOLUME | SOUND_MASK_PCM |
6830162922Sariff		    SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
6831202796Smav		    SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IGAIN |
6832202796Smav		    SOUND_MASK_OGAIN | SOUND_MASK_IMIX | SOUND_MASK_MONITOR);
6833162922Sariff	}
6834162922Sariff
6835182999Smav	for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
6836182999Smav		if ((flag & (1 << j)) == 0)
6837162922Sariff			continue;
6838182999Smav		i = 0;
6839182999Smav		printed = 0;
6840182999Smav		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6841182999Smav			if (ctl->enable == 0 ||
6842182999Smav			    ctl->widget->enable == 0)
6843182999Smav				continue;
6844182999Smav			if (!((pdevinfo->play >= 0 &&
6845182999Smav			    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
6846182999Smav			    (pdevinfo->rec >= 0 &&
6847182999Smav			    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
6848182999Smav			    (ctl->widget->bindas == -2 && pdevinfo->index == 0)))
6849182999Smav				continue;
6850182999Smav			if ((ctl->ossmask & (1 << j)) == 0)
6851182999Smav				continue;
6852182999Smav
6853182999Smav	    		if (printed == 0) {
6854182999Smav				device_printf(pdevinfo->dev, "\n");
6855182999Smav				if (banner != NULL) {
6856182999Smav					device_printf(pdevinfo->dev, "%s", banner);
6857182999Smav				} else {
6858182999Smav					device_printf(pdevinfo->dev, "Unknown Ctl");
6859182999Smav				}
6860182999Smav				printf(" (OSS: %s)\n",
6861182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(1 << j,
6862182999Smav				    buf, sizeof(buf)));
6863182999Smav				device_printf(pdevinfo->dev, "   |\n");
6864182999Smav				printed = 1;
6865162922Sariff			}
6866182999Smav			device_printf(pdevinfo->dev, "   +- ctl %2d (nid %3d %s", i,
6867182999Smav				ctl->widget->nid,
6868182999Smav				(ctl->ndir == HDA_CTL_IN)?"in ":"out");
6869182999Smav			if (ctl->ndir == HDA_CTL_IN && ctl->ndir == ctl->dir)
6870182999Smav				printf(" %2d): ", ctl->index);
6871182999Smav			else
6872182999Smav				printf("):    ");
6873182999Smav			if (ctl->step > 0) {
6874182999Smav				printf("%+d/%+ddB (%d steps)%s\n",
6875182999Smav			    	    (0 - ctl->offset) * (ctl->size + 1) / 4,
6876182999Smav				    (ctl->step - ctl->offset) * (ctl->size + 1) / 4,
6877182999Smav				    ctl->step + 1,
6878182999Smav				    ctl->mute?" + mute":"");
6879182999Smav			} else
6880182999Smav				printf("%s\n", ctl->mute?"mute":"");
6881162922Sariff		}
6882162922Sariff	}
6883162922Sariff}
6884162922Sariff
6885162922Sariffstatic void
6886182999Smavhdac_dump_audio_formats(device_t dev, uint32_t fcap, uint32_t pcmcap)
6887162922Sariff{
6888162922Sariff	uint32_t cap;
6889162922Sariff
6890162922Sariff	cap = fcap;
6891162922Sariff	if (cap != 0) {
6892182999Smav		device_printf(dev, "     Stream cap: 0x%08x\n", cap);
6893183097Smav		device_printf(dev, "                ");
6894162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
6895162922Sariff			printf(" AC3");
6896162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
6897162922Sariff			printf(" FLOAT32");
6898162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
6899162922Sariff			printf(" PCM");
6900162922Sariff		printf("\n");
6901162922Sariff	}
6902162922Sariff	cap = pcmcap;
6903162922Sariff	if (cap != 0) {
6904182999Smav		device_printf(dev, "        PCM cap: 0x%08x\n", cap);
6905183097Smav		device_printf(dev, "                ");
6906162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
6907162922Sariff			printf(" 8");
6908162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
6909162922Sariff			printf(" 16");
6910162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
6911162922Sariff			printf(" 20");
6912162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
6913162922Sariff			printf(" 24");
6914162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
6915162922Sariff			printf(" 32");
6916183097Smav		printf(" bits,");
6917162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
6918162922Sariff			printf(" 8");
6919162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
6920162922Sariff			printf(" 11");
6921162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
6922162922Sariff			printf(" 16");
6923162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
6924162922Sariff			printf(" 22");
6925162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
6926162922Sariff			printf(" 32");
6927162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
6928162922Sariff			printf(" 44");
6929162922Sariff		printf(" 48");
6930162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
6931162922Sariff			printf(" 88");
6932162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
6933162922Sariff			printf(" 96");
6934162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
6935162922Sariff			printf(" 176");
6936162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
6937162922Sariff			printf(" 192");
6938183097Smav		printf(" KHz\n");
6939162922Sariff	}
6940162922Sariff}
6941162922Sariff
6942162922Sariffstatic void
6943162922Sariffhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
6944162922Sariff{
6945183097Smav	uint32_t pincap;
6946162922Sariff
6947162922Sariff	pincap = w->wclass.pin.cap;
6948162922Sariff
6949162922Sariff	device_printf(sc->dev, "        Pin cap: 0x%08x\n", pincap);
6950162922Sariff	device_printf(sc->dev, "                ");
6951162922Sariff	if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap))
6952162922Sariff		printf(" ISC");
6953162922Sariff	if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap))
6954162922Sariff		printf(" TRQD");
6955162922Sariff	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap))
6956162922Sariff		printf(" PDC");
6957162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
6958162922Sariff		printf(" HP");
6959162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
6960162922Sariff		printf(" OUT");
6961162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
6962162922Sariff		printf(" IN");
6963162922Sariff	if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap))
6964162922Sariff		printf(" BAL");
6965197611Smav	if (HDA_PARAM_PIN_CAP_HDMI(pincap))
6966197611Smav		printf(" HDMI");
6967165069Sariff	if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) {
6968165069Sariff		printf(" VREF[");
6969165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
6970165069Sariff			printf(" 50");
6971165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
6972165069Sariff			printf(" 80");
6973165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
6974165069Sariff			printf(" 100");
6975165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap))
6976165069Sariff			printf(" GROUND");
6977165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap))
6978165069Sariff			printf(" HIZ");
6979165069Sariff		printf(" ]");
6980165069Sariff	}
6981162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap))
6982162922Sariff		printf(" EAPD");
6983197611Smav	if (HDA_PARAM_PIN_CAP_DP(pincap))
6984197611Smav		printf(" DP");
6985197611Smav	if (HDA_PARAM_PIN_CAP_HBR(pincap))
6986197611Smav		printf(" HBR");
6987162922Sariff	printf("\n");
6988162922Sariff	device_printf(sc->dev, "     Pin config: 0x%08x\n",
6989162922Sariff	    w->wclass.pin.config);
6990162922Sariff	device_printf(sc->dev, "    Pin control: 0x%08x", w->wclass.pin.ctrl);
6991162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE)
6992162922Sariff		printf(" HP");
6993162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE)
6994162922Sariff		printf(" IN");
6995162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
6996162922Sariff		printf(" OUT");
6997182999Smav	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK)
6998182999Smav		printf(" VREFs");
6999162922Sariff	printf("\n");
7000162922Sariff}
7001162922Sariff
7002162922Sariffstatic void
7003182999Smavhdac_dump_pin_config(struct hdac_widget *w, uint32_t conf)
7004182999Smav{
7005182999Smav	struct hdac_softc *sc = w->devinfo->codec->sc;
7006182999Smav
7007183097Smav	device_printf(sc->dev, " nid %d 0x%08x as %2d seq %2d %13s %5s "
7008182999Smav	    "jack %2d loc %2d color %7s misc %d%s\n",
7009182999Smav	    w->nid, conf,
7010182999Smav	    HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf),
7011182999Smav	    HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf),
7012182999Smav	    HDA_DEVS[HDA_CONFIG_DEFAULTCONF_DEVICE(conf)],
7013182999Smav	    HDA_CONNS[HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf)],
7014182999Smav	    HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf),
7015182999Smav	    HDA_CONFIG_DEFAULTCONF_LOCATION(conf),
7016182999Smav	    HDA_COLORS[HDA_CONFIG_DEFAULTCONF_COLOR(conf)],
7017182999Smav	    HDA_CONFIG_DEFAULTCONF_MISC(conf),
7018182999Smav	    (w->enable == 0)?" [DISABLED]":"");
7019182999Smav}
7020182999Smav
7021182999Smavstatic void
7022182999Smavhdac_dump_pin_configs(struct hdac_devinfo *devinfo)
7023182999Smav{
7024182999Smav	struct hdac_widget *w;
7025182999Smav	int i;
7026182999Smav
7027182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
7028182999Smav		w = hdac_widget_get(devinfo, i);
7029182999Smav		if (w == NULL)
7030182999Smav			continue;
7031182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
7032182999Smav			continue;
7033182999Smav		hdac_dump_pin_config(w, w->wclass.pin.config);
7034182999Smav	}
7035182999Smav}
7036182999Smav
7037182999Smavstatic void
7038162922Sariffhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
7039162922Sariff{
7040163057Sariff	device_printf(sc->dev, "     %s amp: 0x%08x\n", banner, cap);
7041162922Sariff	device_printf(sc->dev, "                 "
7042162922Sariff	    "mute=%d step=%d size=%d offset=%d\n",
7043162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap),
7044162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap),
7045162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap),
7046162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap));
7047162922Sariff}
7048162922Sariff
7049162922Sariffstatic void
7050162922Sariffhdac_dump_nodes(struct hdac_devinfo *devinfo)
7051162922Sariff{
7052162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
7053182999Smav	static char *ossname[] = SOUND_DEVICE_NAMES;
7054162922Sariff	struct hdac_widget *w, *cw;
7055182999Smav	char buf[64];
7056162922Sariff	int i, j;
7057162922Sariff
7058162922Sariff	device_printf(sc->dev, "\n");
7059162922Sariff	device_printf(sc->dev, "Default Parameter\n");
7060162922Sariff	device_printf(sc->dev, "-----------------\n");
7061182999Smav	hdac_dump_audio_formats(sc->dev,
7062162922Sariff	    devinfo->function.audio.supp_stream_formats,
7063162922Sariff	    devinfo->function.audio.supp_pcm_size_rate);
7064162922Sariff	device_printf(sc->dev, "         IN amp: 0x%08x\n",
7065162922Sariff	    devinfo->function.audio.inamp_cap);
7066162922Sariff	device_printf(sc->dev, "        OUT amp: 0x%08x\n",
7067162922Sariff	    devinfo->function.audio.outamp_cap);
7068162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
7069162922Sariff		w = hdac_widget_get(devinfo, i);
7070162922Sariff		if (w == NULL) {
7071162922Sariff			device_printf(sc->dev, "Ghost widget nid=%d\n", i);
7072162922Sariff			continue;
7073162922Sariff		}
7074162922Sariff		device_printf(sc->dev, "\n");
7075183097Smav		device_printf(sc->dev, "            nid: %d%s\n", w->nid,
7076162922Sariff		    (w->enable == 0) ? " [DISABLED]" : "");
7077183097Smav		device_printf(sc->dev, "           Name: %s\n", w->name);
7078183097Smav		device_printf(sc->dev, "     Widget cap: 0x%08x\n",
7079162922Sariff		    w->param.widget_cap);
7080183097Smav		if (w->param.widget_cap & 0x0ee1) {
7081183097Smav			device_printf(sc->dev, "                ");
7082183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(w->param.widget_cap))
7083183097Smav			    printf(" LRSWAP");
7084183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(w->param.widget_cap))
7085183097Smav			    printf(" PWR");
7086183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
7087183097Smav			    printf(" DIGITAL");
7088183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap))
7089183097Smav			    printf(" UNSOL");
7090183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(w->param.widget_cap))
7091183097Smav			    printf(" PROC");
7092183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(w->param.widget_cap))
7093183097Smav			    printf(" STRIPE");
7094197611Smav			j = HDA_PARAM_AUDIO_WIDGET_CAP_CC(w->param.widget_cap);
7095197611Smav			if (j == 1)
7096183097Smav			    printf(" STEREO");
7097197611Smav			else if (j > 1)
7098197611Smav			    printf(" %dCH", j + 1);
7099183097Smav			printf("\n");
7100183097Smav		}
7101183097Smav		if (w->bindas != -1) {
7102183097Smav			device_printf(sc->dev, "    Association: %d (0x%08x)\n",
7103183097Smav			    w->bindas, w->bindseqmask);
7104183097Smav		}
7105183097Smav		if (w->ossmask != 0 || w->ossdev >= 0) {
7106183097Smav			device_printf(sc->dev, "            OSS: %s",
7107183097Smav			    hdac_audio_ctl_ossmixer_mask2allname(w->ossmask, buf, sizeof(buf)));
7108183097Smav			if (w->ossdev >= 0)
7109183097Smav			    printf(" (%s)", ossname[w->ossdev]);
7110183097Smav			printf("\n");
7111183097Smav		}
7112162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
7113162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
7114182999Smav			hdac_dump_audio_formats(sc->dev,
7115162922Sariff			    w->param.supp_stream_formats,
7116162922Sariff			    w->param.supp_pcm_size_rate);
7117162922Sariff		} else if (w->type ==
7118162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
7119162922Sariff			hdac_dump_pin(sc, w);
7120162965Sariff		if (w->param.eapdbtl != HDAC_INVALID)
7121162922Sariff			device_printf(sc->dev, "           EAPD: 0x%08x\n",
7122162922Sariff			    w->param.eapdbtl);
7123163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) &&
7124163057Sariff		    w->param.outamp_cap != 0)
7125162922Sariff			hdac_dump_amp(sc, w->param.outamp_cap, "Output");
7126163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) &&
7127163057Sariff		    w->param.inamp_cap != 0)
7128162922Sariff			hdac_dump_amp(sc, w->param.inamp_cap, " Input");
7129183097Smav		if (w->nconns > 0) {
7130183097Smav			device_printf(sc->dev, "    connections: %d\n", w->nconns);
7131182999Smav			device_printf(sc->dev, "          |\n");
7132183097Smav		}
7133162922Sariff		for (j = 0; j < w->nconns; j++) {
7134162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
7135182999Smav			device_printf(sc->dev, "          + %s<- nid=%d [%s]",
7136182999Smav			    (w->connsenable[j] == 0)?"[DISABLED] ":"",
7137162922Sariff			    w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
7138162922Sariff			if (cw == NULL)
7139162922Sariff				printf(" [UNKNOWN]");
7140162922Sariff			else if (cw->enable == 0)
7141162922Sariff				printf(" [DISABLED]");
7142162922Sariff			if (w->nconns > 1 && w->selconn == j && w->type !=
7143162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
7144162922Sariff				printf(" (selected)");
7145162922Sariff			printf("\n");
7146162922Sariff		}
7147162922Sariff	}
7148162922Sariff
7149162922Sariff}
7150162922Sariff
7151182999Smavstatic void
7152182999Smavhdac_dump_dst_nid(struct hdac_pcm_devinfo *pdevinfo, nid_t nid, int depth)
7153163057Sariff{
7154182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
7155163057Sariff	struct hdac_widget *w, *cw;
7156182999Smav	char buf[64];
7157182999Smav	int i, printed = 0;
7158163057Sariff
7159163057Sariff	if (depth > HDA_PARSE_MAXDEPTH)
7160182999Smav		return;
7161163057Sariff
7162163057Sariff	w = hdac_widget_get(devinfo, nid);
7163182999Smav	if (w == NULL || w->enable == 0)
7164182999Smav		return;
7165163057Sariff
7166182999Smav	if (depth == 0)
7167182999Smav		device_printf(pdevinfo->dev, "%*s", 4, "");
7168182999Smav	else
7169182999Smav		device_printf(pdevinfo->dev, "%*s  + <- ", 4 + (depth - 1) * 7, "");
7170182999Smav	printf("nid=%d [%s]", w->nid, w->name);
7171163057Sariff
7172182999Smav	if (depth > 0) {
7173182999Smav		if (w->ossmask == 0) {
7174182999Smav			printf("\n");
7175182999Smav			return;
7176163057Sariff		}
7177182999Smav		printf(" [src: %s]",
7178182999Smav		    hdac_audio_ctl_ossmixer_mask2allname(
7179182999Smav			w->ossmask, buf, sizeof(buf)));
7180182999Smav		if (w->ossdev >= 0) {
7181182999Smav			printf("\n");
7182182999Smav			return;
7183182999Smav		}
7184163057Sariff	}
7185182999Smav	printf("\n");
7186182999Smav
7187182999Smav	for (i = 0; i < w->nconns; i++) {
7188182999Smav		if (w->connsenable[i] == 0)
7189182999Smav			continue;
7190182999Smav		cw = hdac_widget_get(devinfo, w->conns[i]);
7191182999Smav		if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
7192182999Smav			continue;
7193182999Smav		if (printed == 0) {
7194182999Smav			device_printf(pdevinfo->dev, "%*s  |\n", 4 + (depth) * 7, "");
7195182999Smav			printed = 1;
7196182999Smav		}
7197182999Smav		hdac_dump_dst_nid(pdevinfo, w->conns[i], depth + 1);
7198182999Smav	}
7199163057Sariff
7200163057Sariff}
7201163057Sariff
7202162922Sariffstatic void
7203182999Smavhdac_dump_dac(struct hdac_pcm_devinfo *pdevinfo)
7204162922Sariff{
7205182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
7206182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
7207202736Smav	struct hdac_audio_as *as;
7208163057Sariff	struct hdac_widget *w;
7209163057Sariff	int i, printed = 0;
7210163057Sariff
7211182999Smav	if (pdevinfo->play < 0)
7212182999Smav		return;
7213182999Smav
7214202736Smav	as = &devinfo->function.audio.as[sc->chans[pdevinfo->play].as];
7215202736Smav	for (i = 0; i < 16; i++) {
7216202736Smav		if (as->pins[i] <= 0)
7217202736Smav			continue;
7218202736Smav		w = hdac_widget_get(devinfo, as->pins[i]);
7219163057Sariff		if (w == NULL || w->enable == 0)
7220163057Sariff			continue;
7221163057Sariff		if (printed == 0) {
7222163057Sariff			printed = 1;
7223182999Smav			device_printf(pdevinfo->dev, "\n");
7224182999Smav			device_printf(pdevinfo->dev, "Playback:\n");
7225163057Sariff		}
7226182999Smav		device_printf(pdevinfo->dev, "\n");
7227202736Smav		hdac_dump_dst_nid(pdevinfo, as->pins[i], 0);
7228163057Sariff	}
7229162922Sariff}
7230162922Sariff
7231162922Sariffstatic void
7232182999Smavhdac_dump_adc(struct hdac_pcm_devinfo *pdevinfo)
7233162922Sariff{
7234182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
7235162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
7236182999Smav	struct hdac_widget *w;
7237182999Smav	int i;
7238162922Sariff	int printed = 0;
7239162922Sariff
7240182999Smav	if (pdevinfo->rec < 0)
7241182999Smav		return;
7242182999Smav
7243162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
7244162922Sariff		w = hdac_widget_get(devinfo, i);
7245162922Sariff		if (w == NULL || w->enable == 0)
7246162922Sariff			continue;
7247182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
7248162922Sariff			continue;
7249182999Smav		if (w->bindas != sc->chans[pdevinfo->rec].as)
7250182999Smav			continue;
7251162922Sariff		if (printed == 0) {
7252162922Sariff			printed = 1;
7253182999Smav			device_printf(pdevinfo->dev, "\n");
7254182999Smav			device_printf(pdevinfo->dev, "Record:\n");
7255162922Sariff		}
7256182999Smav		device_printf(pdevinfo->dev, "\n");
7257182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
7258182999Smav	}
7259182999Smav}
7260182999Smav
7261182999Smavstatic void
7262182999Smavhdac_dump_mix(struct hdac_pcm_devinfo *pdevinfo)
7263182999Smav{
7264182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
7265182999Smav	struct hdac_widget *w;
7266182999Smav	int i;
7267182999Smav	int printed = 0;
7268182999Smav
7269182999Smav	if (pdevinfo->index != 0)
7270182999Smav		return;
7271182999Smav
7272182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
7273182999Smav		w = hdac_widget_get(devinfo, i);
7274182999Smav		if (w == NULL || w->enable == 0)
7275182999Smav			continue;
7276202789Smav		if (w->ossdev != SOUND_MIXER_IMIX)
7277182999Smav			continue;
7278182999Smav		if (printed == 0) {
7279182999Smav			printed = 1;
7280182999Smav			device_printf(pdevinfo->dev, "\n");
7281182999Smav			device_printf(pdevinfo->dev, "Input Mix:\n");
7282162922Sariff		}
7283182999Smav		device_printf(pdevinfo->dev, "\n");
7284182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
7285162922Sariff	}
7286162922Sariff}
7287162922Sariff
7288162922Sariffstatic void
7289182999Smavhdac_dump_pcmchannels(struct hdac_pcm_devinfo *pdevinfo)
7290162922Sariff{
7291182999Smav	struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
7292162922Sariff	nid_t *nids;
7293182999Smav	int i;
7294162922Sariff
7295182999Smav	if (pdevinfo->play >= 0) {
7296182999Smav		i = pdevinfo->play;
7297182999Smav		device_printf(pdevinfo->dev, "\n");
7298182999Smav		device_printf(pdevinfo->dev, "Playback:\n");
7299182999Smav		device_printf(pdevinfo->dev, "\n");
7300182999Smav		hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
7301182999Smav		    sc->chans[i].supp_pcm_size_rate);
7302182999Smav		device_printf(pdevinfo->dev, "            DAC:");
7303182999Smav		for (nids = sc->chans[i].io; *nids != -1; nids++)
7304162922Sariff			printf(" %d", *nids);
7305162922Sariff		printf("\n");
7306162922Sariff	}
7307182999Smav	if (pdevinfo->rec >= 0) {
7308182999Smav		i = pdevinfo->rec;
7309182999Smav		device_printf(pdevinfo->dev, "\n");
7310182999Smav		device_printf(pdevinfo->dev, "Record:\n");
7311182999Smav		device_printf(pdevinfo->dev, "\n");
7312182999Smav		hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
7313182999Smav		    sc->chans[i].supp_pcm_size_rate);
7314182999Smav		device_printf(pdevinfo->dev, "            ADC:");
7315182999Smav		for (nids = sc->chans[i].io; *nids != -1; nids++)
7316162922Sariff			printf(" %d", *nids);
7317162922Sariff		printf("\n");
7318162922Sariff	}
7319162922Sariff}
7320162922Sariff
7321162922Sariffstatic void
7322163057Sariffhdac_release_resources(struct hdac_softc *sc)
7323163057Sariff{
7324182999Smav        int i, j;
7325163057Sariff
7326163057Sariff	if (sc == NULL)
7327163057Sariff		return;
7328163057Sariff
7329163057Sariff	hdac_lock(sc);
7330169277Sariff	sc->polling = 0;
7331169277Sariff	sc->poll_ival = 0;
7332170721Sariff	callout_stop(&sc->poll_hda);
7333169277Sariff	callout_stop(&sc->poll_hdac);
7334169277Sariff	callout_stop(&sc->poll_jack);
7335182999Smav	hdac_reset(sc, 0);
7336163057Sariff	hdac_unlock(sc);
7337171141Sariff	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
7338170721Sariff	callout_drain(&sc->poll_hda);
7339169277Sariff	callout_drain(&sc->poll_hdac);
7340169277Sariff	callout_drain(&sc->poll_jack);
7341163057Sariff
7342169277Sariff	hdac_irq_free(sc);
7343169277Sariff
7344182999Smav	for (i = 0; i < HDAC_CODEC_MAX; i++) {
7345182999Smav		if (sc->codecs[i] == NULL)
7346163057Sariff			continue;
7347182999Smav		for (j = 0; j < sc->codecs[i]->num_fgs; j++) {
7348182999Smav			free(sc->codecs[i]->fgs[j].widget, M_HDAC);
7349182999Smav			if (sc->codecs[i]->fgs[j].node_type ==
7350182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
7351182999Smav				free(sc->codecs[i]->fgs[j].function.audio.ctl,
7352182999Smav				    M_HDAC);
7353182999Smav				free(sc->codecs[i]->fgs[j].function.audio.as,
7354182999Smav				    M_HDAC);
7355182999Smav				free(sc->codecs[i]->fgs[j].function.audio.devs,
7356182999Smav				    M_HDAC);
7357182999Smav			}
7358182999Smav		}
7359182999Smav		free(sc->codecs[i]->fgs, M_HDAC);
7360182999Smav		free(sc->codecs[i], M_HDAC);
7361163057Sariff		sc->codecs[i] = NULL;
7362163057Sariff	}
7363163057Sariff
7364169277Sariff	hdac_dma_free(sc, &sc->pos_dma);
7365169277Sariff	hdac_dma_free(sc, &sc->rirb_dma);
7366169277Sariff	hdac_dma_free(sc, &sc->corb_dma);
7367182999Smav	for (i = 0; i < sc->num_chans; i++) {
7368182999Smav    		if (sc->chans[i].blkcnt > 0)
7369182999Smav    			hdac_dma_free(sc, &sc->chans[i].bdl_dma);
7370182999Smav	}
7371182999Smav	free(sc->chans, M_HDAC);
7372167702Sariff	if (sc->chan_dmat != NULL) {
7373167702Sariff		bus_dma_tag_destroy(sc->chan_dmat);
7374167702Sariff		sc->chan_dmat = NULL;
7375167702Sariff	}
7376163057Sariff	hdac_mem_free(sc);
7377169277Sariff	snd_mtxfree(sc->lock);
7378163057Sariff}
7379163057Sariff
7380163057Sariff/* This function surely going to make its way into upper level someday. */
7381163057Sariffstatic void
7382163057Sariffhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
7383163057Sariff{
7384163057Sariff	const char *res = NULL;
7385163057Sariff	int i = 0, j, k, len, inv;
7386163057Sariff
7387163057Sariff	if (on != NULL)
7388163057Sariff		*on = 0;
7389163057Sariff	if (off != NULL)
7390163057Sariff		*off = 0;
7391163057Sariff	if (sc == NULL)
7392163057Sariff		return;
7393163057Sariff	if (resource_string_value(device_get_name(sc->dev),
7394163057Sariff	    device_get_unit(sc->dev), "config", &res) != 0)
7395163057Sariff		return;
7396163057Sariff	if (!(res != NULL && strlen(res) > 0))
7397163057Sariff		return;
7398163057Sariff	HDA_BOOTVERBOSE(
7399182999Smav		device_printf(sc->dev, "HDA Config:");
7400163057Sariff	);
7401163057Sariff	for (;;) {
7402163057Sariff		while (res[i] != '\0' &&
7403163057Sariff		    (res[i] == ',' || isspace(res[i]) != 0))
7404163057Sariff			i++;
7405163057Sariff		if (res[i] == '\0') {
7406163057Sariff			HDA_BOOTVERBOSE(
7407163057Sariff				printf("\n");
7408163057Sariff			);
7409163057Sariff			return;
7410163057Sariff		}
7411163057Sariff		j = i;
7412163057Sariff		while (res[j] != '\0' &&
7413163057Sariff		    !(res[j] == ',' || isspace(res[j]) != 0))
7414163057Sariff			j++;
7415163057Sariff		len = j - i;
7416163057Sariff		if (len > 2 && strncmp(res + i, "no", 2) == 0)
7417163057Sariff			inv = 2;
7418163057Sariff		else
7419163057Sariff			inv = 0;
7420163057Sariff		for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) {
7421163057Sariff			if (strncmp(res + i + inv,
7422163057Sariff			    hdac_quirks_tab[k].key, len - inv) != 0)
7423163057Sariff				continue;
7424163057Sariff			if (len - inv != strlen(hdac_quirks_tab[k].key))
7425187944Smav				continue;
7426163057Sariff			HDA_BOOTVERBOSE(
7427163057Sariff				printf(" %s%s", (inv != 0) ? "no" : "",
7428163057Sariff				    hdac_quirks_tab[k].key);
7429163057Sariff			);
7430163057Sariff			if (inv == 0 && on != NULL)
7431163057Sariff				*on |= hdac_quirks_tab[k].value;
7432163057Sariff			else if (inv != 0 && off != NULL)
7433163057Sariff				*off |= hdac_quirks_tab[k].value;
7434163057Sariff			break;
7435163057Sariff		}
7436163057Sariff		i = j;
7437163057Sariff	}
7438163057Sariff}
7439163057Sariff
7440164614Sariffstatic int
7441164614Sariffsysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
7442164614Sariff{
7443164614Sariff	struct hdac_softc *sc;
7444164614Sariff	device_t dev;
7445164614Sariff	uint32_t ctl;
7446164614Sariff	int err, val;
7447164614Sariff
7448164614Sariff	dev = oidp->oid_arg1;
7449182999Smav	sc = device_get_softc(dev);
7450182999Smav	if (sc == NULL)
7451164614Sariff		return (EINVAL);
7452164614Sariff	hdac_lock(sc);
7453164614Sariff	val = sc->polling;
7454164614Sariff	hdac_unlock(sc);
7455170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
7456164614Sariff
7457169277Sariff	if (err != 0 || req->newptr == NULL)
7458164614Sariff		return (err);
7459164614Sariff	if (val < 0 || val > 1)
7460164614Sariff		return (EINVAL);
7461164614Sariff
7462164614Sariff	hdac_lock(sc);
7463164614Sariff	if (val != sc->polling) {
7464182999Smav		if (val == 0) {
7465182999Smav			callout_stop(&sc->poll_hda);
7466164614Sariff			callout_stop(&sc->poll_hdac);
7467169277Sariff			hdac_unlock(sc);
7468182999Smav			callout_drain(&sc->poll_hda);
7469169277Sariff			callout_drain(&sc->poll_hdac);
7470169277Sariff			hdac_lock(sc);
7471164614Sariff			sc->polling = 0;
7472182999Smav			ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
7473182999Smav			ctl |= HDAC_INTCTL_GIE;
7474182999Smav			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
7475164614Sariff		} else {
7476182999Smav			ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
7477182999Smav			ctl &= ~HDAC_INTCTL_GIE;
7478182999Smav			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
7479171141Sariff			hdac_unlock(sc);
7480171141Sariff			taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
7481171141Sariff			hdac_lock(sc);
7482164614Sariff			sc->polling = 1;
7483182999Smav			hdac_poll_reinit(sc);
7484182999Smav			callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
7485164614Sariff		}
7486164614Sariff	}
7487164614Sariff	hdac_unlock(sc);
7488164614Sariff
7489164614Sariff	return (err);
7490164614Sariff}
7491169277Sariff
7492169277Sariffstatic int
7493169277Sariffsysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS)
7494169277Sariff{
7495169277Sariff	struct hdac_softc *sc;
7496169277Sariff	device_t dev;
7497169277Sariff	int err, val;
7498169277Sariff
7499169277Sariff	dev = oidp->oid_arg1;
7500182999Smav	sc = device_get_softc(dev);
7501182999Smav	if (sc == NULL)
7502169277Sariff		return (EINVAL);
7503169277Sariff	hdac_lock(sc);
7504169277Sariff	val = ((uint64_t)sc->poll_ival * 1000) / hz;
7505169277Sariff	hdac_unlock(sc);
7506170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
7507169277Sariff
7508169277Sariff	if (err != 0 || req->newptr == NULL)
7509169277Sariff		return (err);
7510169277Sariff
7511169277Sariff	if (val < 1)
7512169277Sariff		val = 1;
7513169277Sariff	if (val > 5000)
7514169277Sariff		val = 5000;
7515169277Sariff	val = ((uint64_t)val * hz) / 1000;
7516169277Sariff	if (val < 1)
7517169277Sariff		val = 1;
7518169277Sariff	if (val > (hz * 5))
7519169277Sariff		val = hz * 5;
7520169277Sariff
7521169277Sariff	hdac_lock(sc);
7522169277Sariff	sc->poll_ival = val;
7523169277Sariff	hdac_unlock(sc);
7524169277Sariff
7525169277Sariff	return (err);
7526169277Sariff}
7527169277Sariff
7528169277Sariffstatic int
7529171141Sariffsysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)
7530169277Sariff{
7531169277Sariff	struct hdac_softc *sc;
7532182999Smav	struct hdac_codec *codec;
7533169277Sariff	struct hdac_devinfo *devinfo;
7534169277Sariff	struct hdac_widget *w;
7535169277Sariff	device_t dev;
7536182999Smav	uint32_t res, pincap, delay;
7537182999Smav	int codec_index, fg_index;
7538169277Sariff	int i, err, val;
7539169277Sariff	nid_t cad;
7540169277Sariff
7541169277Sariff	dev = oidp->oid_arg1;
7542182999Smav	sc = device_get_softc(dev);
7543182999Smav	if (sc == NULL)
7544169277Sariff		return (EINVAL);
7545169277Sariff	val = 0;
7546170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
7547169277Sariff	if (err != 0 || req->newptr == NULL || val == 0)
7548169277Sariff		return (err);
7549182999Smav
7550182999Smav	/* XXX: Temporary. For debugging. */
7551182999Smav	if (val == 100) {
7552182999Smav		hdac_suspend(dev);
7553182999Smav		return (0);
7554182999Smav	} else if (val == 101) {
7555182999Smav		hdac_resume(dev);
7556182999Smav		return (0);
7557182999Smav	}
7558182999Smav
7559169277Sariff	hdac_lock(sc);
7560182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7561182999Smav		codec = sc->codecs[codec_index];
7562182999Smav		if (codec == NULL)
7563169277Sariff			continue;
7564182999Smav		cad = codec->cad;
7565182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7566182999Smav			devinfo = &codec->fgs[fg_index];
7567182999Smav			if (devinfo->node_type !=
7568182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
7569182999Smav				continue;
7570182999Smav
7571182999Smav			device_printf(dev, "Dumping AFG cad=%d nid=%d pins:\n",
7572182999Smav			    codec_index, devinfo->nid);
7573182999Smav			for (i = devinfo->startnode; i < devinfo->endnode; i++) {
7574182999Smav					w = hdac_widget_get(devinfo, i);
7575182999Smav				if (w == NULL || w->type !=
7576182999Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
7577182999Smav					continue;
7578182999Smav				hdac_dump_pin_config(w, w->wclass.pin.config);
7579182999Smav				pincap = w->wclass.pin.cap;
7580182999Smav				device_printf(dev, "       Caps: %2s %3s %2s %4s %4s",
7581182999Smav				    HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)?"IN":"",
7582182999Smav				    HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)?"OUT":"",
7583182999Smav				    HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)?"HP":"",
7584182999Smav				    HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)?"EAPD":"",
7585182999Smav				    HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)?"VREF":"");
7586182999Smav				if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) ||
7587182999Smav				    HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) {
7588182999Smav					if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) {
7589182999Smav						delay = 0;
7590182999Smav						hdac_command(sc,
7591182999Smav						    HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad);
7592182999Smav						do {
7593182999Smav							res = hdac_command(sc,
7594182999Smav							    HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
7595182999Smav							if (res != 0x7fffffff && res != 0xffffffff)
7596182999Smav								break;
7597182999Smav							DELAY(10);
7598182999Smav						} while (++delay < 10000);
7599182999Smav					} else {
7600182999Smav						delay = 0;
7601182999Smav						res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad,
7602182999Smav						    w->nid), cad);
7603182999Smav					}
7604182999Smav					printf(" Sense: 0x%08x", res);
7605182999Smav					if (delay > 0)
7606182999Smav						printf(" delay %dus", delay * 10);
7607182999Smav				}
7608182999Smav				printf("\n");
7609182999Smav			}
7610182999Smav			device_printf(dev,
7611182999Smav			    "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
7612182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
7613182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
7614182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
7615182999Smav			    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
7616182999Smav			    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
7617182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) {
7618182999Smav				device_printf(dev, " GPI:");
7619171141Sariff				res = hdac_command(sc,
7620182999Smav				    HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad);
7621182999Smav				printf(" data=0x%08x", res);
7622182999Smav				res = hdac_command(sc,
7623182999Smav				    HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid),
7624182999Smav				    cad);
7625182999Smav				printf(" wake=0x%08x", res);
7626182999Smav				res = hdac_command(sc,
7627182999Smav				    HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
7628182999Smav				    cad);
7629182999Smav				printf(" unsol=0x%08x", res);
7630182999Smav				res = hdac_command(sc,
7631182999Smav				    HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad);
7632182999Smav				printf(" sticky=0x%08x\n", res);
7633182999Smav			}
7634182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) {
7635182999Smav				device_printf(dev, " GPO:");
7636182999Smav				res = hdac_command(sc,
7637182999Smav				    HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad);
7638182999Smav				printf(" data=0x%08x\n", res);
7639182999Smav			}
7640182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) {
7641182999Smav				device_printf(dev, "GPIO:");
7642182999Smav				res = hdac_command(sc,
7643182999Smav				    HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad);
7644182999Smav				printf(" data=0x%08x", res);
7645182999Smav				res = hdac_command(sc,
7646182999Smav				    HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad);
7647182999Smav				printf(" enable=0x%08x", res);
7648182999Smav				res = hdac_command(sc,
7649182999Smav				    HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad);
7650182999Smav				printf(" direction=0x%08x\n", res);
7651182999Smav				res = hdac_command(sc,
7652182999Smav				    HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad);
7653182999Smav				device_printf(dev, "      wake=0x%08x", res);
7654182999Smav				res = hdac_command(sc,
7655182999Smav				    HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
7656182999Smav				    cad);
7657182999Smav				printf("  unsol=0x%08x", res);
7658182999Smav				res = hdac_command(sc,
7659182999Smav				    HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad);
7660182999Smav				printf("    sticky=0x%08x\n", res);
7661182999Smav			}
7662171141Sariff		}
7663169277Sariff	}
7664169277Sariff	hdac_unlock(sc);
7665169277Sariff	return (0);
7666169277Sariff}
7667164614Sariff
7668163057Sariffstatic void
7669162922Sariffhdac_attach2(void *arg)
7670162922Sariff{
7671182999Smav	struct hdac_codec *codec;
7672162922Sariff	struct hdac_softc *sc;
7673162922Sariff	struct hdac_audio_ctl *ctl;
7674163057Sariff	uint32_t quirks_on, quirks_off;
7675182999Smav	int codec_index, fg_index;
7676185225Smav	int i, dmaalloc = 0;
7677182999Smav	struct hdac_devinfo *devinfo;
7678162922Sariff
7679162922Sariff	sc = (struct hdac_softc *)arg;
7680162922Sariff
7681163057Sariff	hdac_config_fetch(sc, &quirks_on, &quirks_off);
7682162922Sariff
7683183097Smav	HDA_BOOTHVERBOSE(
7684182999Smav		device_printf(sc->dev, "HDA Config: on=0x%08x off=0x%08x\n",
7685163057Sariff		    quirks_on, quirks_off);
7686163057Sariff	);
7687163057Sariff
7688162922Sariff	hdac_lock(sc);
7689162922Sariff
7690162922Sariff	/* Remove ourselves from the config hooks */
7691162922Sariff	if (sc->intrhook.ich_func != NULL) {
7692162922Sariff		config_intrhook_disestablish(&sc->intrhook);
7693162922Sariff		sc->intrhook.ich_func = NULL;
7694162922Sariff	}
7695162922Sariff
7696162922Sariff	/* Start the corb and rirb engines */
7697183097Smav	HDA_BOOTHVERBOSE(
7698182999Smav		device_printf(sc->dev, "Starting CORB Engine...\n");
7699162922Sariff	);
7700162922Sariff	hdac_corb_start(sc);
7701183097Smav	HDA_BOOTHVERBOSE(
7702182999Smav		device_printf(sc->dev, "Starting RIRB Engine...\n");
7703162922Sariff	);
7704162922Sariff	hdac_rirb_start(sc);
7705162922Sariff
7706183097Smav	HDA_BOOTHVERBOSE(
7707162922Sariff		device_printf(sc->dev,
7708182999Smav		    "Enabling controller interrupt...\n");
7709162922Sariff	);
7710182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
7711182999Smav	    HDAC_GCTL_UNSOL);
7712182999Smav	if (sc->polling == 0) {
7713164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
7714164614Sariff		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
7715182999Smav	} else {
7716182999Smav		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
7717182999Smav	}
7718162922Sariff	DELAY(1000);
7719162922Sariff
7720183097Smav	HDA_BOOTHVERBOSE(
7721172811Sariff		device_printf(sc->dev,
7722182999Smav		    "Scanning HDA codecs ...\n");
7723162922Sariff	);
7724182999Smav	hdac_scan_codecs(sc);
7725182999Smav
7726182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7727182999Smav		codec = sc->codecs[codec_index];
7728182999Smav		if (codec == NULL)
7729182999Smav			continue;
7730182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7731182999Smav			devinfo = &codec->fgs[fg_index];
7732183019Smav			HDA_BOOTVERBOSE(
7733183019Smav				device_printf(sc->dev, "\n");
7734183097Smav				device_printf(sc->dev,
7735183097Smav				    "Processing %s FG cad=%d nid=%d...\n",
7736183097Smav				    (devinfo->node_type == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
7737183097Smav				    (devinfo->node_type == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
7738183097Smav				    "unknown",
7739183097Smav				    devinfo->codec->cad, devinfo->nid);
7740183019Smav			);
7741182999Smav			if (devinfo->node_type !=
7742182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
7743183097Smav				HDA_BOOTHVERBOSE(
7744182999Smav					device_printf(sc->dev,
7745183097Smav					    "Powering down...\n");
7746182999Smav				);
7747182999Smav				hdac_command(sc,
7748182999Smav				    HDA_CMD_SET_POWER_STATE(codec->cad,
7749182999Smav				    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7750182999Smav				    codec->cad);
7751182999Smav				continue;
7752182999Smav			}
7753162922Sariff
7754183097Smav			HDA_BOOTHVERBOSE(
7755183097Smav				device_printf(sc->dev, "Powering up...\n");
7756182999Smav			);
7757182999Smav			hdac_powerup(devinfo);
7758183097Smav			HDA_BOOTHVERBOSE(
7759182999Smav				device_printf(sc->dev, "Parsing audio FG...\n");
7760182999Smav			);
7761182999Smav			hdac_audio_parse(devinfo);
7762183097Smav			HDA_BOOTHVERBOSE(
7763182999Smav				device_printf(sc->dev, "Parsing Ctls...\n");
7764182999Smav			);
7765182999Smav		    	hdac_audio_ctl_parse(devinfo);
7766183097Smav			HDA_BOOTHVERBOSE(
7767182999Smav				device_printf(sc->dev, "Parsing vendor patch...\n");
7768182999Smav			);
7769182999Smav			hdac_vendor_patch_parse(devinfo);
7770182999Smav			devinfo->function.audio.quirks |= quirks_on;
7771182999Smav			devinfo->function.audio.quirks &= ~quirks_off;
7772162922Sariff
7773183097Smav			HDA_BOOTHVERBOSE(
7774182999Smav				device_printf(sc->dev, "Disabling nonaudio...\n");
7775182999Smav			);
7776182999Smav			hdac_audio_disable_nonaudio(devinfo);
7777183097Smav			HDA_BOOTHVERBOSE(
7778182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7779182999Smav			);
7780182999Smav			hdac_audio_disable_useless(devinfo);
7781182999Smav			HDA_BOOTVERBOSE(
7782182999Smav				device_printf(sc->dev, "Patched pins configuration:\n");
7783182999Smav				hdac_dump_pin_configs(devinfo);
7784183097Smav			);
7785183097Smav			HDA_BOOTHVERBOSE(
7786182999Smav				device_printf(sc->dev, "Parsing pin associations...\n");
7787182999Smav			);
7788182999Smav			hdac_audio_as_parse(devinfo);
7789183097Smav			HDA_BOOTHVERBOSE(
7790182999Smav				device_printf(sc->dev, "Building AFG tree...\n");
7791182999Smav			);
7792182999Smav			hdac_audio_build_tree(devinfo);
7793183097Smav			HDA_BOOTHVERBOSE(
7794182999Smav				device_printf(sc->dev, "Disabling unassociated "
7795182999Smav				    "widgets...\n");
7796182999Smav			);
7797182999Smav			hdac_audio_disable_unas(devinfo);
7798183097Smav			HDA_BOOTHVERBOSE(
7799182999Smav				device_printf(sc->dev, "Disabling nonselected "
7800182999Smav				    "inputs...\n");
7801182999Smav			);
7802182999Smav			hdac_audio_disable_notselected(devinfo);
7803183097Smav			HDA_BOOTHVERBOSE(
7804182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7805182999Smav			);
7806182999Smav			hdac_audio_disable_useless(devinfo);
7807183097Smav			HDA_BOOTHVERBOSE(
7808182999Smav				device_printf(sc->dev, "Disabling "
7809182999Smav				    "crossassociatement connections...\n");
7810182999Smav			);
7811182999Smav			hdac_audio_disable_crossas(devinfo);
7812183097Smav			HDA_BOOTHVERBOSE(
7813182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7814182999Smav			);
7815182999Smav			hdac_audio_disable_useless(devinfo);
7816183097Smav			HDA_BOOTHVERBOSE(
7817182999Smav				device_printf(sc->dev, "Binding associations to channels...\n");
7818182999Smav			);
7819182999Smav			hdac_audio_bind_as(devinfo);
7820183097Smav			HDA_BOOTHVERBOSE(
7821182999Smav				device_printf(sc->dev, "Assigning names to signal sources...\n");
7822182999Smav			);
7823182999Smav			hdac_audio_assign_names(devinfo);
7824183097Smav			HDA_BOOTHVERBOSE(
7825182999Smav				device_printf(sc->dev, "Assigning mixers to the tree...\n");
7826182999Smav			);
7827182999Smav			hdac_audio_assign_mixers(devinfo);
7828183097Smav			HDA_BOOTHVERBOSE(
7829182999Smav				device_printf(sc->dev, "Preparing pin controls...\n");
7830182999Smav			);
7831182999Smav			hdac_audio_prepare_pin_ctrl(devinfo);
7832183097Smav			HDA_BOOTHVERBOSE(
7833182999Smav				device_printf(sc->dev, "AFG commit...\n");
7834182999Smav		    	);
7835182999Smav			hdac_audio_commit(devinfo);
7836183097Smav		    	HDA_BOOTHVERBOSE(
7837182999Smav				device_printf(sc->dev, "HP switch init...\n");
7838182999Smav			);
7839182999Smav			hdac_hp_switch_init(devinfo);
7840182999Smav
7841182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) &&
7842182999Smav			    dmaalloc == 0) {
7843182999Smav				if (hdac_dma_alloc(sc, &sc->pos_dma,
7844182999Smav				    (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) {
7845182999Smav					HDA_BOOTVERBOSE(
7846182999Smav						device_printf(sc->dev, "Failed to "
7847182999Smav						    "allocate DMA pos buffer "
7848182999Smav						    "(non-fatal)\n");
7849182999Smav					);
7850182999Smav				} else
7851182999Smav					dmaalloc = 1;
7852182999Smav			}
7853182999Smav
7854185225Smav		    	HDA_BOOTHVERBOSE(
7855185225Smav				device_printf(sc->dev, "Creating PCM devices...\n");
7856185225Smav			);
7857185225Smav			hdac_create_pcms(devinfo);
7858182999Smav
7859182999Smav			HDA_BOOTVERBOSE(
7860182999Smav				if (devinfo->function.audio.quirks != 0) {
7861183097Smav					device_printf(sc->dev, "FG config/quirks:");
7862182999Smav					for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
7863182999Smav						if ((devinfo->function.audio.quirks &
7864182999Smav						    hdac_quirks_tab[i].value) ==
7865182999Smav						    hdac_quirks_tab[i].value)
7866182999Smav							printf(" %s", hdac_quirks_tab[i].key);
7867182999Smav					}
7868182999Smav					printf("\n");
7869182999Smav				}
7870182999Smav
7871182999Smav				device_printf(sc->dev, "\n");
7872182999Smav				device_printf(sc->dev, "+-------------------+\n");
7873182999Smav				device_printf(sc->dev, "| DUMPING HDA NODES |\n");
7874182999Smav				device_printf(sc->dev, "+-------------------+\n");
7875182999Smav				hdac_dump_nodes(devinfo);
7876183097Smav			);
7877182999Smav
7878183097Smav			HDA_BOOTHVERBOSE(
7879182999Smav				device_printf(sc->dev, "\n");
7880182999Smav				device_printf(sc->dev, "+------------------------+\n");
7881182999Smav				device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
7882182999Smav				device_printf(sc->dev, "+------------------------+\n");
7883182999Smav				device_printf(sc->dev, "\n");
7884182999Smav				i = 0;
7885182999Smav				while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
7886182999Smav					device_printf(sc->dev, "%3d: nid %3d %s (%s) index %d", i,
7887182999Smav					    (ctl->widget != NULL) ? ctl->widget->nid : -1,
7888182999Smav					    (ctl->ndir == HDA_CTL_IN)?"in ":"out",
7889182999Smav					    (ctl->dir == HDA_CTL_IN)?"in ":"out",
7890182999Smav					    ctl->index);
7891182999Smav					if (ctl->childwidget != NULL)
7892182999Smav						printf(" cnid %3d", ctl->childwidget->nid);
7893182999Smav					else
7894182999Smav						printf("         ");
7895182999Smav					printf(" ossmask=0x%08x\n",
7896182999Smav					    ctl->ossmask);
7897182999Smav					device_printf(sc->dev,
7898182999Smav					    "       mute: %d step: %3d size: %3d off: %3d%s\n",
7899182999Smav					    ctl->mute, ctl->step, ctl->size, ctl->offset,
7900182999Smav					    (ctl->enable == 0) ? " [DISABLED]" :
7901182999Smav					    ((ctl->ossmask == 0) ? " [UNUSED]" : ""));
7902182999Smav				}
7903182999Smav			);
7904182999Smav		}
7905162922Sariff	}
7906182999Smav	hdac_unlock(sc);
7907162922Sariff
7908163057Sariff	HDA_BOOTVERBOSE(
7909182999Smav		device_printf(sc->dev, "\n");
7910162922Sariff	);
7911182999Smav
7912182999Smav	bus_generic_attach(sc->dev);
7913182999Smav
7914182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7915182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7916182999Smav	    "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
7917182999Smav	    sysctl_hdac_polling, "I", "Enable polling mode");
7918182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7919182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7920182999Smav	    "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
7921182999Smav	    sizeof(sc->dev), sysctl_hdac_polling_interval, "I",
7922182999Smav	    "Controller/Jack Sense polling interval (1-1000 ms)");
7923182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7924182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7925182999Smav	    "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
7926182999Smav	    sysctl_hdac_pindump, "I", "Dump pin states/data");
7927182999Smav}
7928182999Smav
7929182999Smav/****************************************************************************
7930182999Smav * int hdac_suspend(device_t)
7931182999Smav *
7932182999Smav * Suspend and power down HDA bus and codecs.
7933182999Smav ****************************************************************************/
7934182999Smavstatic int
7935182999Smavhdac_suspend(device_t dev)
7936182999Smav{
7937182999Smav	struct hdac_softc *sc;
7938182999Smav	struct hdac_codec *codec;
7939182999Smav	struct hdac_devinfo *devinfo;
7940182999Smav	int codec_index, fg_index, i;
7941182999Smav
7942183097Smav	HDA_BOOTHVERBOSE(
7943182999Smav		device_printf(dev, "Suspend...\n");
7944162922Sariff	);
7945182999Smav
7946182999Smav	sc = device_get_softc(dev);
7947182999Smav	hdac_lock(sc);
7948182999Smav
7949183097Smav	HDA_BOOTHVERBOSE(
7950182999Smav		device_printf(dev, "Stop streams...\n");
7951162922Sariff	);
7952182999Smav	for (i = 0; i < sc->num_chans; i++) {
7953182999Smav		if (sc->chans[i].flags & HDAC_CHN_RUNNING) {
7954182999Smav			sc->chans[i].flags |= HDAC_CHN_SUSPEND;
7955182999Smav			hdac_channel_stop(sc, &sc->chans[i]);
7956182999Smav		}
7957182999Smav	}
7958162922Sariff
7959182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7960182999Smav		codec = sc->codecs[codec_index];
7961182999Smav		if (codec == NULL)
7962162922Sariff			continue;
7963182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7964182999Smav			devinfo = &codec->fgs[fg_index];
7965183097Smav			HDA_BOOTHVERBOSE(
7966182999Smav				device_printf(dev,
7967182999Smav				    "Power down FG"
7968182999Smav				    " cad=%d nid=%d to the D3 state...\n",
7969182999Smav				    codec->cad, devinfo->nid);
7970182999Smav			);
7971182999Smav			hdac_command(sc,
7972182999Smav			    HDA_CMD_SET_POWER_STATE(codec->cad,
7973182999Smav			    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7974182999Smav			    codec->cad);
7975162922Sariff		}
7976162922Sariff	}
7977162922Sariff
7978183097Smav	HDA_BOOTHVERBOSE(
7979182999Smav		device_printf(dev, "Reset controller...\n");
7980162922Sariff	);
7981182999Smav	callout_stop(&sc->poll_hda);
7982182999Smav	callout_stop(&sc->poll_hdac);
7983182999Smav	callout_stop(&sc->poll_jack);
7984182999Smav	hdac_reset(sc, 0);
7985182999Smav	hdac_unlock(sc);
7986182999Smav	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
7987182999Smav	callout_drain(&sc->poll_hda);
7988182999Smav	callout_drain(&sc->poll_hdac);
7989182999Smav	callout_drain(&sc->poll_jack);
7990162922Sariff
7991183097Smav	HDA_BOOTHVERBOSE(
7992182999Smav		device_printf(dev, "Suspend done\n");
7993162922Sariff	);
7994182999Smav
7995182999Smav	return (0);
7996182999Smav}
7997182999Smav
7998182999Smav/****************************************************************************
7999182999Smav * int hdac_resume(device_t)
8000182999Smav *
8001182999Smav * Powerup and restore HDA bus and codecs state.
8002182999Smav ****************************************************************************/
8003182999Smavstatic int
8004182999Smavhdac_resume(device_t dev)
8005182999Smav{
8006182999Smav	struct hdac_softc *sc;
8007182999Smav	struct hdac_codec *codec;
8008182999Smav	struct hdac_devinfo *devinfo;
8009182999Smav	int codec_index, fg_index, i;
8010182999Smav
8011183097Smav	HDA_BOOTHVERBOSE(
8012182999Smav		device_printf(dev, "Resume...\n");
8013162922Sariff	);
8014162922Sariff
8015182999Smav	sc = device_get_softc(dev);
8016182999Smav	hdac_lock(sc);
8017182999Smav
8018182999Smav	/* Quiesce everything */
8019183097Smav	HDA_BOOTHVERBOSE(
8020182999Smav		device_printf(dev, "Reset controller...\n");
8021162922Sariff	);
8022182999Smav	hdac_reset(sc, 1);
8023182999Smav
8024182999Smav	/* Initialize the CORB and RIRB */
8025182999Smav	hdac_corb_init(sc);
8026182999Smav	hdac_rirb_init(sc);
8027182999Smav
8028182999Smav	/* Start the corb and rirb engines */
8029183097Smav	HDA_BOOTHVERBOSE(
8030182999Smav		device_printf(dev, "Starting CORB Engine...\n");
8031162922Sariff	);
8032182999Smav	hdac_corb_start(sc);
8033183097Smav	HDA_BOOTHVERBOSE(
8034182999Smav		device_printf(dev, "Starting RIRB Engine...\n");
8035162922Sariff	);
8036182999Smav	hdac_rirb_start(sc);
8037163057Sariff
8038183097Smav	HDA_BOOTHVERBOSE(
8039182999Smav		device_printf(dev,
8040182999Smav		    "Enabling controller interrupt...\n");
8041162922Sariff	);
8042182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
8043182999Smav	    HDAC_GCTL_UNSOL);
8044182999Smav	if (sc->polling == 0) {
8045182999Smav		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
8046182999Smav		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
8047182999Smav	} else {
8048182999Smav		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
8049182999Smav	}
8050182999Smav	DELAY(1000);
8051162922Sariff
8052182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
8053182999Smav		codec = sc->codecs[codec_index];
8054182999Smav		if (codec == NULL)
8055182999Smav			continue;
8056182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
8057182999Smav			devinfo = &codec->fgs[fg_index];
8058182999Smav			if (devinfo->node_type !=
8059182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
8060183097Smav				HDA_BOOTHVERBOSE(
8061182999Smav					device_printf(dev,
8062182999Smav					    "Power down unsupported non-audio FG"
8063182999Smav					    " cad=%d nid=%d to the D3 state...\n",
8064182999Smav					    codec->cad, devinfo->nid);
8065182999Smav				);
8066182999Smav				hdac_command(sc,
8067182999Smav				    HDA_CMD_SET_POWER_STATE(codec->cad,
8068182999Smav				    devinfo->nid, HDA_CMD_POWER_STATE_D3),
8069182999Smav				    codec->cad);
8070182999Smav				continue;
8071182999Smav			}
8072162922Sariff
8073183097Smav			HDA_BOOTHVERBOSE(
8074182999Smav				device_printf(dev,
8075182999Smav				    "Power up audio FG cad=%d nid=%d...\n",
8076182999Smav				    devinfo->codec->cad, devinfo->nid);
8077182999Smav			);
8078182999Smav			hdac_powerup(devinfo);
8079183097Smav			HDA_BOOTHVERBOSE(
8080182999Smav				device_printf(dev, "AFG commit...\n");
8081182999Smav		    	);
8082182999Smav			hdac_audio_commit(devinfo);
8083183097Smav		    	HDA_BOOTHVERBOSE(
8084182999Smav				device_printf(dev, "HP switch init...\n");
8085182999Smav			);
8086182999Smav			hdac_hp_switch_init(devinfo);
8087182999Smav
8088182999Smav			hdac_unlock(sc);
8089182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
8090182999Smav				struct hdac_pcm_devinfo *pdevinfo =
8091182999Smav				    &devinfo->function.audio.devs[i];
8092183097Smav				HDA_BOOTHVERBOSE(
8093182999Smav					device_printf(pdevinfo->dev,
8094182999Smav					    "OSS mixer reinitialization...\n");
8095182999Smav				);
8096182999Smav				if (mixer_reinit(pdevinfo->dev) == -1)
8097182999Smav					device_printf(pdevinfo->dev,
8098182999Smav					    "unable to reinitialize the mixer\n");
8099182999Smav			}
8100182999Smav			hdac_lock(sc);
8101182999Smav		}
8102169277Sariff	}
8103169277Sariff
8104183097Smav	HDA_BOOTHVERBOSE(
8105182999Smav		device_printf(dev, "Start streams...\n");
8106163057Sariff	);
8107182999Smav	for (i = 0; i < sc->num_chans; i++) {
8108182999Smav		if (sc->chans[i].flags & HDAC_CHN_SUSPEND) {
8109182999Smav			sc->chans[i].flags &= ~HDAC_CHN_SUSPEND;
8110182999Smav			hdac_channel_start(sc, &sc->chans[i]);
8111182999Smav		}
8112182999Smav	}
8113162922Sariff
8114182999Smav	hdac_unlock(sc);
8115182999Smav
8116183097Smav	HDA_BOOTHVERBOSE(
8117182999Smav		device_printf(dev, "Resume done\n");
8118162922Sariff	);
8119164614Sariff
8120182999Smav	return (0);
8121162922Sariff}
8122162922Sariff/****************************************************************************
8123162922Sariff * int hdac_detach(device_t)
8124162922Sariff *
8125162922Sariff * Detach and free up resources utilized by the hdac device.
8126162922Sariff ****************************************************************************/
8127162922Sariffstatic int
8128162922Sariffhdac_detach(device_t dev)
8129162922Sariff{
8130182999Smav	struct hdac_softc *sc;
8131185177Smav	device_t *devlist;
8132185177Smav	int i, devcount, error;
8133162922Sariff
8134185177Smav	if ((error = device_get_children(dev, &devlist, &devcount)) != 0)
8135185177Smav		return (error);
8136185177Smav	for (i = 0; i < devcount; i++) {
8137185177Smav		if ((error = device_delete_child(dev, devlist[i])) != 0) {
8138185178Smav			free(devlist, M_TEMP);
8139185178Smav			return (error);
8140185178Smav		}
8141185177Smav	}
8142185177Smav	free(devlist, M_TEMP);
8143185177Smav
8144182999Smav	sc = device_get_softc(dev);
8145163057Sariff	hdac_release_resources(sc);
8146162922Sariff
8147162922Sariff	return (0);
8148162922Sariff}
8149162922Sariff
8150184095Smavstatic int
8151184095Smavhdac_print_child(device_t dev, device_t child)
8152184095Smav{
8153184095Smav	struct hdac_pcm_devinfo *pdevinfo =
8154184095Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(child);
8155184095Smav	int retval;
8156184095Smav
8157184095Smav	retval = bus_print_child_header(dev, child);
8158184095Smav	retval += printf(" at cad %d nid %d",
8159184095Smav	    pdevinfo->devinfo->codec->cad, pdevinfo->devinfo->nid);
8160184095Smav	retval += bus_print_child_footer(dev, child);
8161184095Smav
8162184095Smav	return (retval);
8163184095Smav}
8164184095Smav
8165162922Sariffstatic device_method_t hdac_methods[] = {
8166162922Sariff	/* device interface */
8167162922Sariff	DEVMETHOD(device_probe,		hdac_probe),
8168162922Sariff	DEVMETHOD(device_attach,	hdac_attach),
8169162922Sariff	DEVMETHOD(device_detach,	hdac_detach),
8170182999Smav	DEVMETHOD(device_suspend,	hdac_suspend),
8171182999Smav	DEVMETHOD(device_resume,	hdac_resume),
8172184095Smav	/* Bus interface */
8173184095Smav	DEVMETHOD(bus_print_child,	hdac_print_child),
8174162922Sariff	{ 0, 0 }
8175162922Sariff};
8176162922Sariff
8177162922Sariffstatic driver_t hdac_driver = {
8178182999Smav	"hdac",
8179162922Sariff	hdac_methods,
8180182999Smav	sizeof(struct hdac_softc),
8181162922Sariff};
8182162922Sariff
8183182999Smavstatic devclass_t hdac_devclass;
8184182999Smav
8185182999SmavDRIVER_MODULE(snd_hda, pci, hdac_driver, hdac_devclass, 0, 0);
8186162922SariffMODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
8187162922SariffMODULE_VERSION(snd_hda, 1);
8188182999Smav
8189182999Smavstatic int
8190182999Smavhdac_pcm_probe(device_t dev)
8191182999Smav{
8192182999Smav	struct hdac_pcm_devinfo *pdevinfo =
8193182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
8194182999Smav	char buf[128];
8195182999Smav
8196185225Smav	snprintf(buf, sizeof(buf), "HDA %s PCM #%d %s",
8197182999Smav	    hdac_codec_name(pdevinfo->devinfo->codec),
8198185225Smav	    pdevinfo->index,
8199197611Smav	    (pdevinfo->digital == 3)?"DisplayPort":
8200197611Smav	    ((pdevinfo->digital == 2)?"HDMI":
8201197611Smav	    ((pdevinfo->digital)?"Digital":"Analog")));
8202182999Smav	device_set_desc_copy(dev, buf);
8203182999Smav	return (0);
8204182999Smav}
8205182999Smav
8206182999Smavstatic int
8207182999Smavhdac_pcm_attach(device_t dev)
8208182999Smav{
8209182999Smav	struct hdac_pcm_devinfo *pdevinfo =
8210182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
8211182999Smav	struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
8212182999Smav	char status[SND_STATUSLEN];
8213182999Smav	int i;
8214182999Smav
8215182999Smav	pdevinfo->chan_size = pcm_getbuffersize(dev,
8216182999Smav	    HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
8217182999Smav
8218182999Smav	HDA_BOOTVERBOSE(
8219182999Smav		device_printf(dev, "+--------------------------------------+\n");
8220182999Smav		device_printf(dev, "| DUMPING PCM Playback/Record Channels |\n");
8221182999Smav		device_printf(dev, "+--------------------------------------+\n");
8222182999Smav		hdac_dump_pcmchannels(pdevinfo);
8223182999Smav		device_printf(dev, "\n");
8224189876Smav		device_printf(dev, "+-------------------------------+\n");
8225189876Smav		device_printf(dev, "| DUMPING Playback/Record Paths |\n");
8226189876Smav		device_printf(dev, "+-------------------------------+\n");
8227182999Smav		hdac_dump_dac(pdevinfo);
8228182999Smav		hdac_dump_adc(pdevinfo);
8229182999Smav		hdac_dump_mix(pdevinfo);
8230182999Smav		device_printf(dev, "\n");
8231182999Smav		device_printf(dev, "+-------------------------+\n");
8232182999Smav		device_printf(dev, "| DUMPING Volume Controls |\n");
8233182999Smav		device_printf(dev, "+-------------------------+\n");
8234182999Smav		hdac_dump_ctls(pdevinfo, "Master Volume", SOUND_MASK_VOLUME);
8235182999Smav		hdac_dump_ctls(pdevinfo, "PCM Volume", SOUND_MASK_PCM);
8236182999Smav		hdac_dump_ctls(pdevinfo, "CD Volume", SOUND_MASK_CD);
8237182999Smav		hdac_dump_ctls(pdevinfo, "Microphone Volume", SOUND_MASK_MIC);
8238182999Smav		hdac_dump_ctls(pdevinfo, "Microphone2 Volume", SOUND_MASK_MONITOR);
8239182999Smav		hdac_dump_ctls(pdevinfo, "Line-in Volume", SOUND_MASK_LINE);
8240182999Smav		hdac_dump_ctls(pdevinfo, "Speaker/Beep Volume", SOUND_MASK_SPEAKER);
8241182999Smav		hdac_dump_ctls(pdevinfo, "Recording Level", SOUND_MASK_RECLEV);
8242202796Smav		hdac_dump_ctls(pdevinfo, "Input Mix Level", SOUND_MASK_IMIX);
8243202796Smav		hdac_dump_ctls(pdevinfo, "Input Monitoring Level", SOUND_MASK_IGAIN);
8244182999Smav		hdac_dump_ctls(pdevinfo, NULL, 0);
8245182999Smav		device_printf(dev, "\n");
8246182999Smav	);
8247182999Smav
8248182999Smav	if (resource_int_value(device_get_name(dev),
8249182999Smav	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
8250182999Smav		i &= HDA_BLK_ALIGN;
8251182999Smav		if (i < HDA_BLK_MIN)
8252182999Smav			i = HDA_BLK_MIN;
8253182999Smav		pdevinfo->chan_blkcnt = pdevinfo->chan_size / i;
8254182999Smav		i = 0;
8255182999Smav		while (pdevinfo->chan_blkcnt >> i)
8256182999Smav			i++;
8257182999Smav		pdevinfo->chan_blkcnt = 1 << (i - 1);
8258182999Smav		if (pdevinfo->chan_blkcnt < HDA_BDL_MIN)
8259182999Smav			pdevinfo->chan_blkcnt = HDA_BDL_MIN;
8260182999Smav		else if (pdevinfo->chan_blkcnt > HDA_BDL_MAX)
8261182999Smav			pdevinfo->chan_blkcnt = HDA_BDL_MAX;
8262182999Smav	} else
8263182999Smav		pdevinfo->chan_blkcnt = HDA_BDL_DEFAULT;
8264182999Smav
8265182999Smav	/*
8266182999Smav	 * We don't register interrupt handler with snd_setup_intr
8267182999Smav	 * in pcm device. Mark pcm device as MPSAFE manually.
8268182999Smav	 */
8269182999Smav	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
8270182999Smav
8271183097Smav	HDA_BOOTHVERBOSE(
8272182999Smav		device_printf(dev, "OSS mixer initialization...\n");
8273182999Smav	);
8274182999Smav	if (mixer_init(dev, &hdac_audio_ctl_ossmixer_class, pdevinfo) != 0)
8275182999Smav		device_printf(dev, "Can't register mixer\n");
8276182999Smav
8277183097Smav	HDA_BOOTHVERBOSE(
8278182999Smav		device_printf(dev, "Registering PCM channels...\n");
8279182999Smav	);
8280182999Smav	if (pcm_register(dev, pdevinfo, (pdevinfo->play >= 0)?1:0,
8281182999Smav	    (pdevinfo->rec >= 0)?1:0) != 0)
8282182999Smav		device_printf(dev, "Can't register PCM\n");
8283182999Smav
8284182999Smav	pdevinfo->registered++;
8285182999Smav
8286182999Smav	if (pdevinfo->play >= 0)
8287182999Smav		pcm_addchan(dev, PCMDIR_PLAY, &hdac_channel_class, pdevinfo);
8288182999Smav	if (pdevinfo->rec >= 0)
8289182999Smav		pcm_addchan(dev, PCMDIR_REC, &hdac_channel_class, pdevinfo);
8290182999Smav
8291184095Smav	snprintf(status, SND_STATUSLEN, "at cad %d nid %d on %s %s",
8292184095Smav	    pdevinfo->devinfo->codec->cad, pdevinfo->devinfo->nid,
8293184095Smav	    device_get_nameunit(sc->dev), PCM_KLDSTRING(snd_hda));
8294182999Smav	pcm_setstatus(dev, status);
8295182999Smav
8296182999Smav	return (0);
8297182999Smav}
8298182999Smav
8299182999Smavstatic int
8300182999Smavhdac_pcm_detach(device_t dev)
8301182999Smav{
8302182999Smav	struct hdac_pcm_devinfo *pdevinfo =
8303182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
8304182999Smav	int err;
8305182999Smav
8306182999Smav	if (pdevinfo->registered > 0) {
8307182999Smav		err = pcm_unregister(dev);
8308182999Smav		if (err != 0)
8309182999Smav			return (err);
8310182999Smav	}
8311182999Smav
8312182999Smav	return (0);
8313182999Smav}
8314182999Smav
8315182999Smavstatic device_method_t hdac_pcm_methods[] = {
8316182999Smav	/* device interface */
8317182999Smav	DEVMETHOD(device_probe,		hdac_pcm_probe),
8318182999Smav	DEVMETHOD(device_attach,	hdac_pcm_attach),
8319182999Smav	DEVMETHOD(device_detach,	hdac_pcm_detach),
8320182999Smav	{ 0, 0 }
8321182999Smav};
8322182999Smav
8323182999Smavstatic driver_t hdac_pcm_driver = {
8324182999Smav	"pcm",
8325182999Smav	hdac_pcm_methods,
8326182999Smav	PCM_SOFTC_SIZE,
8327182999Smav};
8328182999Smav
8329182999SmavDRIVER_MODULE(snd_hda_pcm, hdac, hdac_pcm_driver, pcm_devclass, 0, 0);
8330182999Smav
8331