hdac.c revision 185178
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 *        - HDMI
42162922Sariff *     3) Widget parser - the real magic of why this driver works on so
43162922Sariff *        many hardwares with minimal vendor specific quirk. The original
44162922Sariff *        parser was written using Ruby and can be found at
45162922Sariff *        http://people.freebsd.org/~ariff/HDA/parser.rb . This crude
46162922Sariff *        ruby parser take the verbose dmesg dump as its input. Refer to
47162922Sariff *        http://www.microsoft.com/whdc/device/audio/default.mspx for various
48164614Sariff *        interesting documents, especially UAA (Universal Audio Architecture).
49162922Sariff *     4) Possible vendor specific support.
50162922Sariff *        (snd_hda_intel, snd_hda_ati, etc..)
51162922Sariff *
52162922Sariff * Thanks to Ahmad Ubaidah Omar @ Defenxis Sdn. Bhd. for the
53162922Sariff * Compaq V3000 with Conexant HDA.
54162922Sariff *
55162922Sariff *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
56162922Sariff *    *                                                                 *
57162922Sariff *    *        This driver is a collaborative effort made by:           *
58162922Sariff *    *                                                                 *
59162922Sariff *    *          Stephane E. Potvin <sepotvin@videotron.ca>             *
60162922Sariff *    *               Andrea Bittau <a.bittau@cs.ucl.ac.uk>             *
61162922Sariff *    *               Wesley Morgan <morganw@chemikals.org>             *
62162922Sariff *    *              Daniel Eischen <deischen@FreeBSD.org>              *
63162922Sariff *    *             Maxime Guillaud <bsd-ports@mguillaud.net>           *
64162922Sariff *    *              Ariff Abdullah <ariff@FreeBSD.org>                 *
65182999Smav *    *             Alexander Motin <mav@FreeBSD.org>                   *
66162922Sariff *    *                                                                 *
67162922Sariff *    *   ....and various people from freebsd-multimedia@FreeBSD.org    *
68162922Sariff *    *                                                                 *
69162922Sariff *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
70162922Sariff */
71162922Sariff
72162922Sariff#include <dev/sound/pcm/sound.h>
73162922Sariff#include <dev/pci/pcireg.h>
74162922Sariff#include <dev/pci/pcivar.h>
75162922Sariff
76171141Sariff#include <sys/ctype.h>
77171141Sariff#include <sys/taskqueue.h>
78171141Sariff
79162922Sariff#include <dev/sound/pci/hda/hdac_private.h>
80162922Sariff#include <dev/sound/pci/hda/hdac_reg.h>
81162922Sariff#include <dev/sound/pci/hda/hda_reg.h>
82162922Sariff#include <dev/sound/pci/hda/hdac.h>
83162922Sariff
84162922Sariff#include "mixer_if.h"
85162922Sariff
86185176Smav#define HDA_DRV_TEST_REV	"20081122_0117"
87162922Sariff
88162922SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 185178 2008-11-22 15:38:24Z mav $");
89162922Sariff
90169277Sariff#define HDA_BOOTVERBOSE(stmt)	do {			\
91169277Sariff	if (bootverbose != 0 || snd_verbose > 3) {	\
92169277Sariff		stmt					\
93169277Sariff	}						\
94162922Sariff} while(0)
95162922Sariff
96183097Smav#define HDA_BOOTHVERBOSE(stmt)	do {			\
97183097Smav	if (snd_verbose > 3) {				\
98183097Smav		stmt					\
99183097Smav	}						\
100183097Smav} while(0)
101183097Smav
102162965Sariff#if 1
103162922Sariff#undef HDAC_INTR_EXTRA
104162922Sariff#define HDAC_INTR_EXTRA		1
105162922Sariff#endif
106162922Sariff
107162965Sariff#define hdac_lock(sc)		snd_mtxlock((sc)->lock)
108162965Sariff#define hdac_unlock(sc)		snd_mtxunlock((sc)->lock)
109163057Sariff#define hdac_lockassert(sc)	snd_mtxassert((sc)->lock)
110163057Sariff#define hdac_lockowned(sc)	mtx_owned((sc)->lock)
111162922Sariff
112178155Sariff#undef HDAC_MSI_ENABLED
113178155Sariff#if __FreeBSD_version >= 700026 ||					\
114178155Sariff    (__FreeBSD_version < 700000 && __FreeBSD_version >= 602106)
115178155Sariff#define HDAC_MSI_ENABLED	1
116178155Sariff#endif
117178155Sariff
118162965Sariff#define HDA_FLAG_MATCH(fl, v)	(((fl) & (v)) == (v))
119163257Sariff#define HDA_DEV_MATCH(fl, v)	((fl) == (v) || \
120163257Sariff				(fl) == 0xffffffff || \
121163257Sariff				(((fl) & 0xffff0000) == 0xffff0000 && \
122163257Sariff				((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \
123163257Sariff				(((fl) & 0x0000ffff) == 0x0000ffff && \
124163257Sariff				((fl) & 0xffff0000) == ((v) & 0xffff0000)))
125162965Sariff#define HDA_MATCH_ALL		0xffffffff
126162965Sariff#define HDAC_INVALID		0xffffffff
127162965Sariff
128169277Sariff/* Default controller / jack sense poll: 250ms */
129169277Sariff#define HDAC_POLL_INTERVAL	max(hz >> 2, 1)
130169277Sariff
131171141Sariff/*
132171141Sariff * Make room for possible 4096 playback/record channels, in 100 years to come.
133171141Sariff */
134171141Sariff#define HDAC_TRIGGER_NONE	0x00000000
135171141Sariff#define HDAC_TRIGGER_PLAY	0x00000fff
136171141Sariff#define HDAC_TRIGGER_REC	0x00fff000
137171141Sariff#define HDAC_TRIGGER_UNSOL	0x80000000
138171141Sariff
139162922Sariff#define HDA_MODEL_CONSTRUCT(vendor, model)	\
140162922Sariff		(((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff))
141162922Sariff
142162922Sariff/* Controller models */
143162922Sariff
144162922Sariff/* Intel */
145162922Sariff#define INTEL_VENDORID		0x8086
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)
151184207Smav#define HDA_INTEL_82801J	HDA_MODEL_CONSTRUCT(INTEL, 0x3a3e)
152184207Smav#define HDA_INTEL_SCH		HDA_MODEL_CONSTRUCT(INTEL, 0x811b)
153162922Sariff#define HDA_INTEL_ALL		HDA_MODEL_CONSTRUCT(INTEL, 0xffff)
154162922Sariff
155162922Sariff/* Nvidia */
156162922Sariff#define NVIDIA_VENDORID		0x10de
157162922Sariff#define HDA_NVIDIA_MCP51	HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c)
158162922Sariff#define HDA_NVIDIA_MCP55	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371)
159173817Sariff#define HDA_NVIDIA_MCP61_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4)
160173817Sariff#define HDA_NVIDIA_MCP61_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0)
161173817Sariff#define HDA_NVIDIA_MCP65_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a)
162173817Sariff#define HDA_NVIDIA_MCP65_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b)
163173817Sariff#define HDA_NVIDIA_MCP67_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x055c)
164173817Sariff#define HDA_NVIDIA_MCP67_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x055d)
165162922Sariff#define HDA_NVIDIA_ALL		HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff)
166162922Sariff
167162922Sariff/* ATI */
168162922Sariff#define ATI_VENDORID		0x1002
169162922Sariff#define HDA_ATI_SB450		HDA_MODEL_CONSTRUCT(ATI, 0x437b)
170163136Sariff#define HDA_ATI_SB600		HDA_MODEL_CONSTRUCT(ATI, 0x4383)
171162922Sariff#define HDA_ATI_ALL		HDA_MODEL_CONSTRUCT(ATI, 0xffff)
172162922Sariff
173163136Sariff/* VIA */
174163136Sariff#define VIA_VENDORID		0x1106
175163136Sariff#define HDA_VIA_VT82XX		HDA_MODEL_CONSTRUCT(VIA, 0x3288)
176163136Sariff#define HDA_VIA_ALL		HDA_MODEL_CONSTRUCT(VIA, 0xffff)
177163136Sariff
178163136Sariff/* SiS */
179163136Sariff#define SIS_VENDORID		0x1039
180163136Sariff#define HDA_SIS_966		HDA_MODEL_CONSTRUCT(SIS, 0x7502)
181163136Sariff#define HDA_SIS_ALL		HDA_MODEL_CONSTRUCT(SIS, 0xffff)
182163136Sariff
183162922Sariff/* OEM/subvendors */
184162922Sariff
185165466Sariff/* Intel */
186165466Sariff#define INTEL_D101GGC_SUBVENDOR	HDA_MODEL_CONSTRUCT(INTEL, 0xd600)
187165466Sariff
188162922Sariff/* HP/Compaq */
189162922Sariff#define HP_VENDORID		0x103c
190162922Sariff#define HP_V3000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b5)
191162922Sariff#define HP_NX7400_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a2)
192162922Sariff#define HP_NX6310_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30aa)
193165281Sariff#define HP_NX6325_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b0)
194166294Sariff#define HP_XW4300_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3013)
195169277Sariff#define HP_3010_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3010)
196169277Sariff#define HP_DV5000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a5)
197174579Sariff#define HP_DC7700S_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x2801)
198172811Sariff#define HP_DC7700_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x2802)
199162922Sariff#define HP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0xffff)
200165281Sariff/* What is wrong with XN 2563 anyway? (Got the picture ?) */
201165281Sariff#define HP_NX6325_SUBVENDORX	0x103c30b0
202162922Sariff
203162922Sariff/* Dell */
204162922Sariff#define DELL_VENDORID		0x1028
205180532Sdelphij#define DELL_D630_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01f9)
206162922Sariff#define DELL_D820_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01cc)
207184483Smav#define DELL_V1400_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x0227)
208178155Sariff#define DELL_V1500_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x0228)
209162922Sariff#define DELL_I1300_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01c9)
210169277Sariff#define DELL_XPSM1210_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01d7)
211169277Sariff#define DELL_OPLX745_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01da)
212162922Sariff#define DELL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0xffff)
213162922Sariff
214162922Sariff/* Clevo */
215162922Sariff#define CLEVO_VENDORID		0x1558
216162922Sariff#define CLEVO_D900T_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0x0900)
217162922Sariff#define CLEVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0xffff)
218162922Sariff
219162922Sariff/* Acer */
220162922Sariff#define ACER_VENDORID		0x1025
221165992Sariff#define ACER_A5050_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x010f)
222173817Sariff#define ACER_A4520_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0127)
223174182Sariff#define ACER_A4710_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x012f)
224182854Sjoel#define ACER_A4715_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0133)
225169277Sariff#define ACER_3681WXM_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0110)
226182999Smav#define ACER_T6292_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x011b)
227162922Sariff#define ACER_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0xffff)
228162922Sariff
229162965Sariff/* Asus */
230162965Sariff#define ASUS_VENDORID		0x1043
231178155Sariff#define ASUS_A8X_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1153)
232163276Sariff#define ASUS_U5F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
233178155Sariff#define ASUS_W6F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
234165281Sariff#define ASUS_A7M_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1323)
235178155Sariff#define ASUS_F3JC_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1338)
236178155Sariff#define ASUS_G2K_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1339)
237167623Sariff#define ASUS_A7T_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x13c2)
238169277Sariff#define ASUS_W2J_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1971)
239178155Sariff#define ASUS_M5200_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
240178155Sariff#define ASUS_P1AH2_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
241178155Sariff#define ASUS_M2NPVMX_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
242170518Sariff#define ASUS_M2V_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81e7)
243178155Sariff#define ASUS_P5BWD_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81ec)
244169277Sariff#define ASUS_M2N_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x8234)
245171141Sariff#define ASUS_A8NVMCSM_SUBVENDOR	HDA_MODEL_CONSTRUCT(NVIDIA, 0xcb84)
246162965Sariff#define ASUS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
247162922Sariff
248163257Sariff/* IBM / Lenovo */
249163257Sariff#define IBM_VENDORID		0x1014
250163257Sariff#define IBM_M52_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0x02f6)
251163257Sariff#define IBM_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0xffff)
252162965Sariff
253164614Sariff/* Lenovo */
254164657Sariff#define LENOVO_VENDORID		0x17aa
255164657Sariff#define LENOVO_3KN100_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x2066)
256182854Sjoel#define LENOVO_3KN200_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x384e)
257172811Sariff#define LENOVO_TCA55_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x1015)
258164657Sariff#define LENOVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0xffff)
259163257Sariff
260164657Sariff/* Samsung */
261164657Sariff#define SAMSUNG_VENDORID	0x144d
262164657Sariff#define SAMSUNG_Q1_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027)
263164657Sariff#define SAMSUNG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff)
264164614Sariff
265164750Sariff/* Medion ? */
266164750Sariff#define MEDION_VENDORID			0x161f
267164750Sariff#define MEDION_MD95257_SUBVENDOR	HDA_MODEL_CONSTRUCT(MEDION, 0x203d)
268164750Sariff#define MEDION_ALL_SUBVENDOR		HDA_MODEL_CONSTRUCT(MEDION, 0xffff)
269164750Sariff
270173817Sariff/* Apple Computer Inc. */
271173817Sariff#define APPLE_VENDORID		0x106b
272173817Sariff#define APPLE_MB3_SUBVENDOR	HDA_MODEL_CONSTRUCT(APPLE, 0x00a1)
273173817Sariff
274182999Smav/* Sony */
275182999Smav#define SONY_VENDORID		0x104d
276182999Smav#define SONY_S5_SUBVENDOR	HDA_MODEL_CONSTRUCT(SONY, 0x81cc)
277182999Smav#define SONY_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SONY, 0xffff)
278182999Smav
279164828Sariff/*
280164828Sariff * Apple Intel MacXXXX seems using Sigmatel codec/vendor id
281164828Sariff * instead of their own, which is beyond my comprehension
282164828Sariff * (see HDA_CODEC_STAC9221 below).
283164828Sariff */
284164828Sariff#define APPLE_INTEL_MAC		0x76808384
285164828Sariff
286165281Sariff/* LG Electronics */
287165281Sariff#define LG_VENDORID		0x1854
288165281Sariff#define LG_LW20_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0x0018)
289165281Sariff#define LG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0xffff)
290165281Sariff
291165351Sariff/* Fujitsu Siemens */
292165351Sariff#define FS_VENDORID		0x1734
293165351Sariff#define FS_PA1510_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10b8)
294172811Sariff#define FS_SI1848_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10cd)
295165351Sariff#define FS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0xffff)
296165351Sariff
297172811Sariff/* Fujitsu Limited */
298172811Sariff#define FL_VENDORID		0x10cf
299172811Sariff#define FL_S7020D_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x1326)
300182854Sjoel#define FL_U1010_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x142d)
301172811Sariff#define FL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0xffff)
302172811Sariff
303165770Sariff/* Toshiba */
304165770Sariff#define TOSHIBA_VENDORID	0x1179
305165770Sariff#define TOSHIBA_U200_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001)
306173817Sariff#define TOSHIBA_A135_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xff01)
307165770Sariff#define TOSHIBA_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff)
308165770Sariff
309165992Sariff/* Micro-Star International (MSI) */
310165992Sariff#define MSI_VENDORID		0x1462
311165992Sariff#define MSI_MS1034_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x0349)
312172811Sariff#define MSI_MS034A_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x034a)
313165992Sariff#define MSI_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0xffff)
314165992Sariff
315172811Sariff/* Giga-Byte Technology */
316172811Sariff#define GB_VENDORID		0x1458
317172811Sariff#define GB_G33S2H_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xa022)
318172811Sariff#define GP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xffff)
319172811Sariff
320169277Sariff/* Uniwill ? */
321169277Sariff#define UNIWILL_VENDORID	0x1584
322169277Sariff#define UNIWILL_9075_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075)
323170944Sariff#define UNIWILL_9080_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9080)
324169277Sariff
325169277Sariff
326162922Sariff/* Misc constants.. */
327182999Smav#define HDA_AMP_VOL_DEFAULT	(-1)
328162922Sariff#define HDA_AMP_MUTE_DEFAULT	(0xffffffff)
329162922Sariff#define HDA_AMP_MUTE_NONE	(0)
330162922Sariff#define HDA_AMP_MUTE_LEFT	(1 << 0)
331162922Sariff#define HDA_AMP_MUTE_RIGHT	(1 << 1)
332162922Sariff#define HDA_AMP_MUTE_ALL	(HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT)
333162922Sariff
334162922Sariff#define HDA_AMP_LEFT_MUTED(v)	((v) & (HDA_AMP_MUTE_LEFT))
335162922Sariff#define HDA_AMP_RIGHT_MUTED(v)	(((v) & HDA_AMP_MUTE_RIGHT) >> 1)
336162922Sariff
337182999Smav#define HDA_ADC_MONITOR		(1 << 0)
338162922Sariff
339182999Smav#define HDA_CTL_OUT		1
340182999Smav#define HDA_CTL_IN		2
341169277Sariff
342169277Sariff#define HDA_GPIO_MAX		8
343169277Sariff/* 0 - 7 = GPIO , 8 = Flush */
344163057Sariff#define HDA_QUIRK_GPIO0		(1 << 0)
345163057Sariff#define HDA_QUIRK_GPIO1		(1 << 1)
346163057Sariff#define HDA_QUIRK_GPIO2		(1 << 2)
347169277Sariff#define HDA_QUIRK_GPIO3		(1 << 3)
348169277Sariff#define HDA_QUIRK_GPIO4		(1 << 4)
349169277Sariff#define HDA_QUIRK_GPIO5		(1 << 5)
350169277Sariff#define HDA_QUIRK_GPIO6		(1 << 6)
351169277Sariff#define HDA_QUIRK_GPIO7		(1 << 7)
352169277Sariff#define HDA_QUIRK_GPIOFLUSH	(1 << 8)
353162922Sariff
354169277Sariff/* 9 - 25 = anything else */
355169277Sariff#define HDA_QUIRK_SOFTPCMVOL	(1 << 9)
356169277Sariff#define HDA_QUIRK_FIXEDRATE	(1 << 10)
357169277Sariff#define HDA_QUIRK_FORCESTEREO	(1 << 11)
358169277Sariff#define HDA_QUIRK_EAPDINV	(1 << 12)
359169277Sariff#define HDA_QUIRK_DMAPOS	(1 << 13)
360182999Smav#define HDA_QUIRK_SENSEINV	(1 << 14)
361169277Sariff
362169277Sariff/* 26 - 31 = vrefs */
363169277Sariff#define HDA_QUIRK_IVREF50	(1 << 26)
364169277Sariff#define HDA_QUIRK_IVREF80	(1 << 27)
365169277Sariff#define HDA_QUIRK_IVREF100	(1 << 28)
366169277Sariff#define HDA_QUIRK_OVREF50	(1 << 29)
367169277Sariff#define HDA_QUIRK_OVREF80	(1 << 30)
368169277Sariff#define HDA_QUIRK_OVREF100	(1 << 31)
369169277Sariff
370169277Sariff#define HDA_QUIRK_IVREF		(HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 | \
371169277Sariff							HDA_QUIRK_IVREF100)
372169277Sariff#define HDA_QUIRK_OVREF		(HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 | \
373169277Sariff							HDA_QUIRK_OVREF100)
374169277Sariff#define HDA_QUIRK_VREF		(HDA_QUIRK_IVREF | HDA_QUIRK_OVREF)
375169277Sariff
376171141Sariff#if __FreeBSD_version < 600000
377171141Sariff#define taskqueue_drain(...)
378171141Sariff#endif
379171141Sariff
380163057Sariffstatic const struct {
381163057Sariff	char *key;
382163057Sariff	uint32_t value;
383163057Sariff} hdac_quirks_tab[] = {
384163057Sariff	{ "gpio0", HDA_QUIRK_GPIO0 },
385163057Sariff	{ "gpio1", HDA_QUIRK_GPIO1 },
386163057Sariff	{ "gpio2", HDA_QUIRK_GPIO2 },
387169277Sariff	{ "gpio3", HDA_QUIRK_GPIO3 },
388169277Sariff	{ "gpio4", HDA_QUIRK_GPIO4 },
389169277Sariff	{ "gpio5", HDA_QUIRK_GPIO5 },
390169277Sariff	{ "gpio6", HDA_QUIRK_GPIO6 },
391169277Sariff	{ "gpio7", HDA_QUIRK_GPIO7 },
392165039Sariff	{ "gpioflush", HDA_QUIRK_GPIOFLUSH },
393163057Sariff	{ "softpcmvol", HDA_QUIRK_SOFTPCMVOL },
394163057Sariff	{ "fixedrate", HDA_QUIRK_FIXEDRATE },
395163136Sariff	{ "forcestereo", HDA_QUIRK_FORCESTEREO },
396163276Sariff	{ "eapdinv", HDA_QUIRK_EAPDINV },
397169277Sariff	{ "dmapos", HDA_QUIRK_DMAPOS },
398182999Smav	{ "senseinv", HDA_QUIRK_SENSEINV },
399169277Sariff	{ "ivref50", HDA_QUIRK_IVREF50 },
400169277Sariff	{ "ivref80", HDA_QUIRK_IVREF80 },
401169277Sariff	{ "ivref100", HDA_QUIRK_IVREF100 },
402169277Sariff	{ "ovref50", HDA_QUIRK_OVREF50 },
403169277Sariff	{ "ovref80", HDA_QUIRK_OVREF80 },
404169277Sariff	{ "ovref100", HDA_QUIRK_OVREF100 },
405169277Sariff	{ "ivref", HDA_QUIRK_IVREF },
406169277Sariff	{ "ovref", HDA_QUIRK_OVREF },
407165069Sariff	{ "vref", HDA_QUIRK_VREF },
408163057Sariff};
409163057Sariff#define HDAC_QUIRKS_TAB_LEN	\
410163057Sariff		(sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0]))
411163057Sariff
412162922Sariff#define HDA_BDL_MIN	2
413162922Sariff#define HDA_BDL_MAX	256
414162922Sariff#define HDA_BDL_DEFAULT	HDA_BDL_MIN
415162922Sariff
416169277Sariff#define HDA_BLK_MIN	HDAC_DMA_ALIGNMENT
417167648Sariff#define HDA_BLK_ALIGN	(~(HDA_BLK_MIN - 1))
418167648Sariff
419162922Sariff#define HDA_BUFSZ_MIN		4096
420162922Sariff#define HDA_BUFSZ_MAX		65536
421162922Sariff#define HDA_BUFSZ_DEFAULT	16384
422162922Sariff
423162922Sariff#define HDA_PARSE_MAXDEPTH	10
424162922Sariff
425169277Sariff#define HDAC_UNSOLTAG_EVENT_HP		0x00
426162922Sariff
427165239SariffMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
428162922Sariff
429182999Smavconst char *HDA_COLORS[16] = {"Unknown", "Black", "Grey", "Blue", "Green", "Red",
430182999Smav    "Orange", "Yellow", "Purple", "Pink", "Res.A", "Res.B", "Res.C", "Res.D",
431182999Smav    "White", "Other"};
432162922Sariff
433182999Smavconst char *HDA_DEVS[16] = {"Line-out", "Speaker", "Headphones", "CD",
434182999Smav    "SPDIF-out", "Digital-out", "Modem-line", "Modem-handset", "Line-in",
435182999Smav    "AUX", "Mic", "Telephony", "SPDIF-in", "Digital-in", "Res.E", "Other"};
436182999Smav
437182999Smavconst char *HDA_CONNS[4] = {"Jack", "None", "Fixed", "Both"};
438182999Smav
439162922Sariff/* Default */
440162922Sariffstatic uint32_t hdac_fmt[] = {
441162922Sariff	AFMT_STEREO | AFMT_S16_LE,
442162922Sariff	0
443162922Sariff};
444162922Sariff
445162922Sariffstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0};
446162922Sariff
447162922Sariffstatic const struct {
448162922Sariff	uint32_t	model;
449162922Sariff	char		*desc;
450162922Sariff} hdac_devices[] = {
451162922Sariff	{ HDA_INTEL_82801F,  "Intel 82801F" },
452171330Sariff	{ HDA_INTEL_63XXESB, "Intel 631x/632xESB" },
453162922Sariff	{ HDA_INTEL_82801G,  "Intel 82801G" },
454163136Sariff	{ HDA_INTEL_82801H,  "Intel 82801H" },
455171330Sariff	{ HDA_INTEL_82801I,  "Intel 82801I" },
456184207Smav	{ HDA_INTEL_82801J,  "Intel 82801J" },
457184207Smav	{ HDA_INTEL_SCH,     "Intel SCH" },
458162922Sariff	{ HDA_NVIDIA_MCP51,  "NVidia MCP51" },
459162922Sariff	{ HDA_NVIDIA_MCP55,  "NVidia MCP55" },
460173817Sariff	{ HDA_NVIDIA_MCP61_1, "NVidia MCP61" },
461173817Sariff	{ HDA_NVIDIA_MCP61_2, "NVidia MCP61" },
462173817Sariff	{ HDA_NVIDIA_MCP65_1, "NVidia MCP65" },
463174004Sariff	{ HDA_NVIDIA_MCP65_2, "NVidia MCP65" },
464173817Sariff	{ HDA_NVIDIA_MCP67_1, "NVidia MCP67" },
465173817Sariff	{ HDA_NVIDIA_MCP67_2, "NVidia MCP67" },
466162922Sariff	{ HDA_ATI_SB450,     "ATI SB450"    },
467163136Sariff	{ HDA_ATI_SB600,     "ATI SB600"    },
468163136Sariff	{ HDA_VIA_VT82XX,    "VIA VT8251/8237A" },
469163136Sariff	{ HDA_SIS_966,       "SiS 966" },
470162922Sariff	/* Unknown */
471162922Sariff	{ HDA_INTEL_ALL,  "Intel (Unknown)"  },
472162922Sariff	{ HDA_NVIDIA_ALL, "NVidia (Unknown)" },
473162922Sariff	{ HDA_ATI_ALL,    "ATI (Unknown)"    },
474163136Sariff	{ HDA_VIA_ALL,    "VIA (Unknown)"    },
475163136Sariff	{ HDA_SIS_ALL,    "SiS (Unknown)"    },
476162922Sariff};
477162922Sariff#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0]))
478162922Sariff
479162922Sariffstatic const struct {
480169277Sariff	uint16_t vendor;
481169277Sariff	uint8_t reg;
482169277Sariff	uint8_t mask;
483169277Sariff	uint8_t enable;
484169277Sariff} hdac_pcie_snoop[] = {
485169277Sariff	{  INTEL_VENDORID, 0x00, 0x00, 0x00 },
486169277Sariff	{    ATI_VENDORID, 0x42, 0xf8, 0x02 },
487169277Sariff	{ NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f },
488169277Sariff};
489169277Sariff#define HDAC_PCIESNOOP_LEN	\
490169277Sariff			(sizeof(hdac_pcie_snoop) / sizeof(hdac_pcie_snoop[0]))
491169277Sariff
492169277Sariffstatic const struct {
493162922Sariff	uint32_t	rate;
494162922Sariff	int		valid;
495162922Sariff	uint16_t	base;
496162922Sariff	uint16_t	mul;
497162922Sariff	uint16_t	div;
498162922Sariff} hda_rate_tab[] = {
499162922Sariff	{   8000, 1, 0x0000, 0x0000, 0x0500 },	/* (48000 * 1) / 6 */
500162922Sariff	{   9600, 0, 0x0000, 0x0000, 0x0400 },	/* (48000 * 1) / 5 */
501162922Sariff	{  12000, 0, 0x0000, 0x0000, 0x0300 },	/* (48000 * 1) / 4 */
502162922Sariff	{  16000, 1, 0x0000, 0x0000, 0x0200 },	/* (48000 * 1) / 3 */
503162922Sariff	{  18000, 0, 0x0000, 0x1000, 0x0700 },	/* (48000 * 3) / 8 */
504162922Sariff	{  19200, 0, 0x0000, 0x0800, 0x0400 },	/* (48000 * 2) / 5 */
505162922Sariff	{  24000, 0, 0x0000, 0x0000, 0x0100 },	/* (48000 * 1) / 2 */
506162922Sariff	{  28800, 0, 0x0000, 0x1000, 0x0400 },	/* (48000 * 3) / 5 */
507162922Sariff	{  32000, 1, 0x0000, 0x0800, 0x0200 },	/* (48000 * 2) / 3 */
508162922Sariff	{  36000, 0, 0x0000, 0x1000, 0x0300 },	/* (48000 * 3) / 4 */
509162922Sariff	{  38400, 0, 0x0000, 0x1800, 0x0400 },	/* (48000 * 4) / 5 */
510162922Sariff	{  48000, 1, 0x0000, 0x0000, 0x0000 },	/* (48000 * 1) / 1 */
511162922Sariff	{  64000, 0, 0x0000, 0x1800, 0x0200 },	/* (48000 * 4) / 3 */
512162922Sariff	{  72000, 0, 0x0000, 0x1000, 0x0100 },	/* (48000 * 3) / 2 */
513162922Sariff	{  96000, 1, 0x0000, 0x0800, 0x0000 },	/* (48000 * 2) / 1 */
514162922Sariff	{ 144000, 0, 0x0000, 0x1000, 0x0000 },	/* (48000 * 3) / 1 */
515162922Sariff	{ 192000, 1, 0x0000, 0x1800, 0x0000 },	/* (48000 * 4) / 1 */
516162922Sariff	{   8820, 0, 0x4000, 0x0000, 0x0400 },	/* (44100 * 1) / 5 */
517162922Sariff	{  11025, 1, 0x4000, 0x0000, 0x0300 },	/* (44100 * 1) / 4 */
518162922Sariff	{  12600, 0, 0x4000, 0x0800, 0x0600 },	/* (44100 * 2) / 7 */
519162922Sariff	{  14700, 0, 0x4000, 0x0000, 0x0200 },	/* (44100 * 1) / 3 */
520162922Sariff	{  17640, 0, 0x4000, 0x0800, 0x0400 },	/* (44100 * 2) / 5 */
521162922Sariff	{  18900, 0, 0x4000, 0x1000, 0x0600 },	/* (44100 * 3) / 7 */
522162922Sariff	{  22050, 1, 0x4000, 0x0000, 0x0100 },	/* (44100 * 1) / 2 */
523162922Sariff	{  25200, 0, 0x4000, 0x1800, 0x0600 },	/* (44100 * 4) / 7 */
524162922Sariff	{  26460, 0, 0x4000, 0x1000, 0x0400 },	/* (44100 * 3) / 5 */
525162922Sariff	{  29400, 0, 0x4000, 0x0800, 0x0200 },	/* (44100 * 2) / 3 */
526162922Sariff	{  33075, 0, 0x4000, 0x1000, 0x0300 },	/* (44100 * 3) / 4 */
527162922Sariff	{  35280, 0, 0x4000, 0x1800, 0x0400 },	/* (44100 * 4) / 5 */
528162922Sariff	{  44100, 1, 0x4000, 0x0000, 0x0000 },	/* (44100 * 1) / 1 */
529162922Sariff	{  58800, 0, 0x4000, 0x1800, 0x0200 },	/* (44100 * 4) / 3 */
530162922Sariff	{  66150, 0, 0x4000, 0x1000, 0x0100 },	/* (44100 * 3) / 2 */
531162922Sariff	{  88200, 1, 0x4000, 0x0800, 0x0000 },	/* (44100 * 2) / 1 */
532162922Sariff	{ 132300, 0, 0x4000, 0x1000, 0x0000 },	/* (44100 * 3) / 1 */
533162922Sariff	{ 176400, 1, 0x4000, 0x1800, 0x0000 },	/* (44100 * 4) / 1 */
534162922Sariff};
535162922Sariff#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
536162922Sariff
537162922Sariff/* All codecs you can eat... */
538162922Sariff#define HDA_CODEC_CONSTRUCT(vendor, id) \
539162922Sariff		(((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff))
540162922Sariff
541162922Sariff/* Realtek */
542162922Sariff#define REALTEK_VENDORID	0x10ec
543162922Sariff#define HDA_CODEC_ALC260	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
544169277Sariff#define HDA_CODEC_ALC262	HDA_CODEC_CONSTRUCT(REALTEK, 0x0262)
545183024Smav#define HDA_CODEC_ALC267	HDA_CODEC_CONSTRUCT(REALTEK, 0x0267)
546171330Sariff#define HDA_CODEC_ALC268	HDA_CODEC_CONSTRUCT(REALTEK, 0x0268)
547183024Smav#define HDA_CODEC_ALC269	HDA_CODEC_CONSTRUCT(REALTEK, 0x0269)
548183024Smav#define HDA_CODEC_ALC272	HDA_CODEC_CONSTRUCT(REALTEK, 0x0272)
549170518Sariff#define HDA_CODEC_ALC660	HDA_CODEC_CONSTRUCT(REALTEK, 0x0660)
550183024Smav#define HDA_CODEC_ALC662	HDA_CODEC_CONSTRUCT(REALTEK, 0x0662)
551183025Smav#define HDA_CODEC_ALC663	HDA_CODEC_CONSTRUCT(REALTEK, 0x0663)
552162922Sariff#define HDA_CODEC_ALC861	HDA_CODEC_CONSTRUCT(REALTEK, 0x0861)
553169277Sariff#define HDA_CODEC_ALC861VD	HDA_CODEC_CONSTRUCT(REALTEK, 0x0862)
554162922Sariff#define HDA_CODEC_ALC880	HDA_CODEC_CONSTRUCT(REALTEK, 0x0880)
555163057Sariff#define HDA_CODEC_ALC882	HDA_CODEC_CONSTRUCT(REALTEK, 0x0882)
556163057Sariff#define HDA_CODEC_ALC883	HDA_CODEC_CONSTRUCT(REALTEK, 0x0883)
557169277Sariff#define HDA_CODEC_ALC885	HDA_CODEC_CONSTRUCT(REALTEK, 0x0885)
558165305Sariff#define HDA_CODEC_ALC888	HDA_CODEC_CONSTRUCT(REALTEK, 0x0888)
559182999Smav#define HDA_CODEC_ALC889	HDA_CODEC_CONSTRUCT(REALTEK, 0x0889)
560162922Sariff#define HDA_CODEC_ALCXXXX	HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
561162922Sariff
562169277Sariff/* Analog Devices */
563169277Sariff#define ANALOGDEVICES_VENDORID	0x11d4
564169277Sariff#define HDA_CODEC_AD1981HD	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981)
565169277Sariff#define HDA_CODEC_AD1983	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983)
566174025Sariff#define HDA_CODEC_AD1984	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1984)
567169277Sariff#define HDA_CODEC_AD1986A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986)
568169277Sariff#define HDA_CODEC_AD1988	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988)
569170518Sariff#define HDA_CODEC_AD1988B	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x198b)
570169277Sariff#define HDA_CODEC_ADXXXX	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff)
571162922Sariff
572162922Sariff/* CMedia */
573162922Sariff#define CMEDIA_VENDORID		0x434d
574162922Sariff#define HDA_CODEC_CMI9880	HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980)
575162922Sariff#define HDA_CODEC_CMIXXXX	HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff)
576162922Sariff
577162922Sariff/* Sigmatel */
578162922Sariff#define SIGMATEL_VENDORID	0x8384
579182999Smav#define HDA_CODEC_STAC9230X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7612)
580182999Smav#define HDA_CODEC_STAC9230D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7613)
581182999Smav#define HDA_CODEC_STAC9229X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7614)
582182999Smav#define HDA_CODEC_STAC9229D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7615)
583182999Smav#define HDA_CODEC_STAC9228X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7616)
584182999Smav#define HDA_CODEC_STAC9228D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7617)
585182999Smav#define HDA_CODEC_STAC9227X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
586182999Smav#define HDA_CODEC_STAC9227D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7619)
587183894Smav#define HDA_CODEC_STAC9274	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7620)
588183894Smav#define HDA_CODEC_STAC9274D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7621)
589183894Smav#define HDA_CODEC_STAC9273X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7622)
590183894Smav#define HDA_CODEC_STAC9273D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7623)
591183894Smav#define HDA_CODEC_STAC9272X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7624)
592183894Smav#define HDA_CODEC_STAC9272D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7625)
593183894Smav#define HDA_CODEC_STAC9271X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7626)
594182999Smav#define HDA_CODEC_STAC9271D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
595183894Smav#define HDA_CODEC_STAC9274X5NH	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7628)
596183894Smav#define HDA_CODEC_STAC9274D5NH	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7629)
597183894Smav#define HDA_CODEC_STAC9250	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7634)
598183894Smav#define HDA_CODEC_STAC9251	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7636)
599183894Smav#define HDA_CODEC_IDT92HD700X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7638)
600183894Smav#define HDA_CODEC_IDT92HD700D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7639)
601183894Smav#define HDA_CODEC_IDT92HD206X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7645)
602183894Smav#define HDA_CODEC_IDT92HD206D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7646)
603182999Smav#define HDA_CODEC_STAC9872AK	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7662)
604162922Sariff#define HDA_CODEC_STAC9221	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
605182999Smav#define HDA_CODEC_STAC922XD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
606183894Smav#define HDA_CODEC_STAC9221_A2	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7682)
607162922Sariff#define HDA_CODEC_STAC9221D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
608162922Sariff#define HDA_CODEC_STAC9220	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
609183894Smav#define HDA_CODEC_STAC9200D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7691)
610183894Smav#define HDA_CODEC_IDT92HD005	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7698)
611183894Smav#define HDA_CODEC_IDT92HD005D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7699)
612183894Smav#define HDA_CODEC_STAC9205X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0)
613183894Smav#define HDA_CODEC_STAC9205D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a1)
614183894Smav#define HDA_CODEC_STAC9204X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a2)
615183894Smav#define HDA_CODEC_STAC9204D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a3)
616183894Smav#define HDA_CODEC_STAC9220_A2	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7880)
617183894Smav#define HDA_CODEC_STAC9220_A1	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7882)
618162922Sariff#define HDA_CODEC_STACXXXX	HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
619162922Sariff
620183894Smav/* IDT */
621183894Smav#define IDT_VENDORID		0x111d
622183894Smav#define HDA_CODEC_IDT92HD75BX	HDA_CODEC_CONSTRUCT(IDT, 0x7603)
623183894Smav#define HDA_CODEC_IDT92HD83C1X	HDA_CODEC_CONSTRUCT(IDT, 0x7604)
624183894Smav#define HDA_CODEC_IDT92HD81B1X	HDA_CODEC_CONSTRUCT(IDT, 0x7605)
625183894Smav#define HDA_CODEC_IDT92HD75B3	HDA_CODEC_CONSTRUCT(IDT, 0x7608)
626183894Smav#define HDA_CODEC_IDT92HD73D1	HDA_CODEC_CONSTRUCT(IDT, 0x7674)
627183894Smav#define HDA_CODEC_IDT92HD73C1	HDA_CODEC_CONSTRUCT(IDT, 0x7675)
628183894Smav#define HDA_CODEC_IDT92HD73E1	HDA_CODEC_CONSTRUCT(IDT, 0x7676)
629183894Smav#define HDA_CODEC_IDT92HD71B8	HDA_CODEC_CONSTRUCT(IDT, 0x76b0)
630183894Smav#define HDA_CODEC_IDT92HD71B7	HDA_CODEC_CONSTRUCT(IDT, 0x76b2)
631183894Smav#define HDA_CODEC_IDT92HD71B5	HDA_CODEC_CONSTRUCT(IDT, 0x76b6)
632183894Smav#define HDA_CODEC_IDT92HD83C1C	HDA_CODEC_CONSTRUCT(IDT, 0x76d4)
633183894Smav#define HDA_CODEC_IDT92HD81B1C	HDA_CODEC_CONSTRUCT(IDT, 0x76d5)
634183894Smav#define HDA_CODEC_IDTXXXX	HDA_CODEC_CONSTRUCT(IDT, 0xffff)
635183894Smav
636182999Smav/* Silicon Image */
637182999Smav#define SII_VENDORID	0x1095
638182999Smav#define HDA_CODEC_SIIXXXX	HDA_CODEC_CONSTRUCT(SII, 0xffff)
639182999Smav
640182999Smav/* Lucent/Agere */
641182999Smav#define AGERE_VENDORID	0x11c1
642182999Smav#define HDA_CODEC_AGEREXXXX	HDA_CODEC_CONSTRUCT(AGERE, 0xffff)
643182999Smav
644162922Sariff/*
645162922Sariff * Conexant
646162922Sariff *
647162922Sariff * Ok, the truth is, I don't have any idea at all whether
648162922Sariff * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only
649162922Sariff * place that tell me it is "Venice" is from its Windows driver INF.
650163057Sariff *
651163057Sariff *  Venice - CX?????
652163057Sariff * Waikiki - CX20551-22
653162922Sariff */
654162922Sariff#define CONEXANT_VENDORID	0x14f1
655162922Sariff#define HDA_CODEC_CXVENICE	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045)
656163057Sariff#define HDA_CODEC_CXWAIKIKI	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047)
657162922Sariff#define HDA_CODEC_CXXXXX	HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff)
658162922Sariff
659169277Sariff/* VIA */
660169277Sariff#define HDA_CODEC_VT1708_8	HDA_CODEC_CONSTRUCT(VIA, 0x1708)
661169277Sariff#define HDA_CODEC_VT1708_9	HDA_CODEC_CONSTRUCT(VIA, 0x1709)
662169277Sariff#define HDA_CODEC_VT1708_A	HDA_CODEC_CONSTRUCT(VIA, 0x170a)
663169277Sariff#define HDA_CODEC_VT1708_B	HDA_CODEC_CONSTRUCT(VIA, 0x170b)
664169277Sariff#define HDA_CODEC_VT1709_0	HDA_CODEC_CONSTRUCT(VIA, 0xe710)
665169277Sariff#define HDA_CODEC_VT1709_1	HDA_CODEC_CONSTRUCT(VIA, 0xe711)
666169277Sariff#define HDA_CODEC_VT1709_2	HDA_CODEC_CONSTRUCT(VIA, 0xe712)
667169277Sariff#define HDA_CODEC_VT1709_3	HDA_CODEC_CONSTRUCT(VIA, 0xe713)
668169277Sariff#define HDA_CODEC_VT1709_4	HDA_CODEC_CONSTRUCT(VIA, 0xe714)
669169277Sariff#define HDA_CODEC_VT1709_5	HDA_CODEC_CONSTRUCT(VIA, 0xe715)
670169277Sariff#define HDA_CODEC_VT1709_6	HDA_CODEC_CONSTRUCT(VIA, 0xe716)
671169277Sariff#define HDA_CODEC_VT1709_7	HDA_CODEC_CONSTRUCT(VIA, 0xe717)
672169277Sariff#define HDA_CODEC_VTXXXX	HDA_CODEC_CONSTRUCT(VIA, 0xffff)
673162922Sariff
674182999Smav/* ATI */
675182999Smav#define HDA_CODEC_ATIXXXX	HDA_CODEC_CONSTRUCT(ATI, 0xffff)
676169277Sariff
677182999Smav/* NVIDIA */
678182999Smav#define HDA_CODEC_NVIDIAXXXX	HDA_CODEC_CONSTRUCT(NVIDIA, 0xffff)
679182999Smav
680183894Smav/* INTEL */
681183894Smav#define HDA_CODEC_INTELXXXX	HDA_CODEC_CONSTRUCT(INTEL, 0xffff)
682183894Smav
683162922Sariff/* Codecs */
684162922Sariffstatic const struct {
685162922Sariff	uint32_t id;
686162922Sariff	char *name;
687162922Sariff} hdac_codecs[] = {
688162922Sariff	{ HDA_CODEC_ALC260,    "Realtek ALC260" },
689169277Sariff	{ HDA_CODEC_ALC262,    "Realtek ALC262" },
690183024Smav	{ HDA_CODEC_ALC267,    "Realtek ALC267" },
691171330Sariff	{ HDA_CODEC_ALC268,    "Realtek ALC268" },
692183024Smav	{ HDA_CODEC_ALC269,    "Realtek ALC269" },
693183024Smav	{ HDA_CODEC_ALC272,    "Realtek ALC272" },
694170518Sariff	{ HDA_CODEC_ALC660,    "Realtek ALC660" },
695183024Smav	{ HDA_CODEC_ALC662,    "Realtek ALC662" },
696183024Smav	{ HDA_CODEC_ALC663,    "Realtek ALC663" },
697162922Sariff	{ HDA_CODEC_ALC861,    "Realtek ALC861" },
698169277Sariff	{ HDA_CODEC_ALC861VD,  "Realtek ALC861-VD" },
699162922Sariff	{ HDA_CODEC_ALC880,    "Realtek ALC880" },
700162922Sariff	{ HDA_CODEC_ALC882,    "Realtek ALC882" },
701163057Sariff	{ HDA_CODEC_ALC883,    "Realtek ALC883" },
702169277Sariff	{ HDA_CODEC_ALC885,    "Realtek ALC885" },
703165305Sariff	{ HDA_CODEC_ALC888,    "Realtek ALC888" },
704182999Smav	{ HDA_CODEC_ALC889,    "Realtek ALC889" },
705169277Sariff	{ HDA_CODEC_AD1981HD,  "Analog Devices AD1981HD" },
706169277Sariff	{ HDA_CODEC_AD1983,    "Analog Devices AD1983" },
707174025Sariff	{ HDA_CODEC_AD1984,    "Analog Devices AD1984" },
708169277Sariff	{ HDA_CODEC_AD1986A,   "Analog Devices AD1986A" },
709169277Sariff	{ HDA_CODEC_AD1988,    "Analog Devices AD1988" },
710170518Sariff	{ HDA_CODEC_AD1988B,   "Analog Devices AD1988B" },
711162922Sariff	{ HDA_CODEC_CMI9880,   "CMedia CMI9880" },
712183894Smav	{ HDA_CODEC_STAC9200D, "Sigmatel STAC9200D" },
713183894Smav	{ HDA_CODEC_STAC9204X, "Sigmatel STAC9204X" },
714183894Smav	{ HDA_CODEC_STAC9204D, "Sigmatel STAC9204D" },
715183894Smav	{ HDA_CODEC_STAC9205X, "Sigmatel STAC9205X" },
716183894Smav	{ HDA_CODEC_STAC9205D, "Sigmatel STAC9205D" },
717183894Smav	{ HDA_CODEC_STAC9220,  "Sigmatel STAC9220" },
718183894Smav	{ HDA_CODEC_STAC9220_A1, "Sigmatel STAC9220_A1" },
719183894Smav	{ HDA_CODEC_STAC9220_A2, "Sigmatel STAC9220_A2" },
720162922Sariff	{ HDA_CODEC_STAC9221,  "Sigmatel STAC9221" },
721183894Smav	{ HDA_CODEC_STAC9221_A2, "Sigmatel STAC9221_A2" },
722162922Sariff	{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
723162922Sariff	{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
724183894Smav	{ HDA_CODEC_STAC9227X, "Sigmatel STAC9227X" },
725183894Smav	{ HDA_CODEC_STAC9227D, "Sigmatel STAC9227D" },
726183894Smav	{ HDA_CODEC_STAC9228X, "Sigmatel STAC9228X" },
727183894Smav	{ HDA_CODEC_STAC9228D, "Sigmatel STAC9228D" },
728183894Smav	{ HDA_CODEC_STAC9229X, "Sigmatel STAC9229X" },
729183894Smav	{ HDA_CODEC_STAC9229D, "Sigmatel STAC9229D" },
730182999Smav	{ HDA_CODEC_STAC9230X, "Sigmatel STAC9230X" },
731182999Smav	{ HDA_CODEC_STAC9230D, "Sigmatel STAC9230D" },
732183894Smav	{ HDA_CODEC_STAC9250,  "Sigmatel STAC9250" },
733183894Smav	{ HDA_CODEC_STAC9251,  "Sigmatel STAC9251" },
734183894Smav	{ HDA_CODEC_STAC9271X, "Sigmatel STAC9271X" },
735166796Sariff	{ HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" },
736183894Smav	{ HDA_CODEC_STAC9272X, "Sigmatel STAC9272X" },
737183894Smav	{ HDA_CODEC_STAC9272D, "Sigmatel STAC9272D" },
738183894Smav	{ HDA_CODEC_STAC9273X, "Sigmatel STAC9273X" },
739183894Smav	{ HDA_CODEC_STAC9273D, "Sigmatel STAC9273D" },
740183894Smav	{ HDA_CODEC_STAC9274,  "Sigmatel STAC9274" },
741183894Smav	{ HDA_CODEC_STAC9274D, "Sigmatel STAC9274D" },
742183894Smav	{ HDA_CODEC_STAC9274X5NH, "Sigmatel STAC9274X5NH" },
743183894Smav	{ HDA_CODEC_STAC9274D5NH, "Sigmatel STAC9274D5NH" },
744183894Smav	{ HDA_CODEC_STAC9872AK, "Sigmatel STAC9872AK" },
745183894Smav	{ HDA_CODEC_IDT92HD005, "IDT 92HD005" },
746183894Smav	{ HDA_CODEC_IDT92HD005D, "IDT 92HD005D" },
747183894Smav	{ HDA_CODEC_IDT92HD206X, "IDT 92HD206X" },
748183894Smav	{ HDA_CODEC_IDT92HD206D, "IDT 92HD206D" },
749183894Smav	{ HDA_CODEC_IDT92HD700X, "IDT 92HD700X" },
750183894Smav	{ HDA_CODEC_IDT92HD700D, "IDT 92HD700D" },
751183894Smav	{ HDA_CODEC_IDT92HD71B5, "IDT 92HD71B5" },
752183894Smav	{ HDA_CODEC_IDT92HD71B7, "IDT 92HD71B7" },
753183894Smav	{ HDA_CODEC_IDT92HD71B8, "IDT 92HD71B8" },
754183894Smav	{ HDA_CODEC_IDT92HD73C1, "IDT 92HD73C1" },
755183894Smav	{ HDA_CODEC_IDT92HD73D1, "IDT 92HD73D1" },
756183894Smav	{ HDA_CODEC_IDT92HD73E1, "IDT 92HD73E1" },
757183894Smav	{ HDA_CODEC_IDT92HD75B3, "IDT 92HD75B3" },
758183894Smav	{ HDA_CODEC_IDT92HD75BX, "IDT 92HD75BX" },
759183894Smav	{ HDA_CODEC_IDT92HD81B1C, "IDT 92HD81B1C" },
760183894Smav	{ HDA_CODEC_IDT92HD81B1X, "IDT 92HD81B1X" },
761183894Smav	{ HDA_CODEC_IDT92HD83C1C, "IDT 92HD83C1C" },
762183894Smav	{ HDA_CODEC_IDT92HD83C1X, "IDT 92HD83C1X" },
763162922Sariff	{ HDA_CODEC_CXVENICE,  "Conexant Venice" },
764163057Sariff	{ HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" },
765169277Sariff	{ HDA_CODEC_VT1708_8,  "VIA VT1708_8" },
766169277Sariff	{ HDA_CODEC_VT1708_9,  "VIA VT1708_9" },
767169277Sariff	{ HDA_CODEC_VT1708_A,  "VIA VT1708_A" },
768169277Sariff	{ HDA_CODEC_VT1708_B,  "VIA VT1708_B" },
769169277Sariff	{ HDA_CODEC_VT1709_0,  "VIA VT1709_0" },
770169277Sariff	{ HDA_CODEC_VT1709_1,  "VIA VT1709_1" },
771169277Sariff	{ HDA_CODEC_VT1709_2,  "VIA VT1709_2" },
772169277Sariff	{ HDA_CODEC_VT1709_3,  "VIA VT1709_3" },
773169277Sariff	{ HDA_CODEC_VT1709_4,  "VIA VT1709_4" },
774169277Sariff	{ HDA_CODEC_VT1709_5,  "VIA VT1709_5" },
775169277Sariff	{ HDA_CODEC_VT1709_6,  "VIA VT1709_6" },
776169277Sariff	{ HDA_CODEC_VT1709_7,  "VIA VT1709_7" },
777162922Sariff	/* Unknown codec */
778162922Sariff	{ HDA_CODEC_ALCXXXX,   "Realtek (Unknown)" },
779169277Sariff	{ HDA_CODEC_ADXXXX,    "Analog Devices (Unknown)" },
780162922Sariff	{ HDA_CODEC_CMIXXXX,   "CMedia (Unknown)" },
781162922Sariff	{ HDA_CODEC_STACXXXX,  "Sigmatel (Unknown)" },
782182999Smav	{ HDA_CODEC_SIIXXXX,   "Silicon Image (Unknown)" },
783182999Smav	{ HDA_CODEC_AGEREXXXX, "Lucent/Agere Systems (Unknown)" },
784162922Sariff	{ HDA_CODEC_CXXXXX,    "Conexant (Unknown)" },
785169277Sariff	{ HDA_CODEC_VTXXXX,    "VIA (Unknown)" },
786182999Smav	{ HDA_CODEC_ATIXXXX,   "ATI (Unknown)" },
787182999Smav	{ HDA_CODEC_NVIDIAXXXX,"NVidia (Unknown)" },
788183894Smav	{ HDA_CODEC_INTELXXXX, "Intel (Unknown)" },
789183894Smav	{ HDA_CODEC_IDTXXXX,   "IDT (Unknown)" },
790162922Sariff};
791162922Sariff#define HDAC_CODECS_LEN	(sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
792162922Sariff
793162922Sariff
794162922Sariff/****************************************************************************
795162922Sariff * Function prototypes
796162922Sariff ****************************************************************************/
797162922Sariffstatic void	hdac_intr_handler(void *);
798182999Smavstatic int	hdac_reset(struct hdac_softc *, int);
799162922Sariffstatic int	hdac_get_capabilities(struct hdac_softc *);
800162922Sariffstatic void	hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
801162922Sariffstatic int	hdac_dma_alloc(struct hdac_softc *,
802162922Sariff					struct hdac_dma *, bus_size_t);
803169277Sariffstatic void	hdac_dma_free(struct hdac_softc *, struct hdac_dma *);
804162922Sariffstatic int	hdac_mem_alloc(struct hdac_softc *);
805162922Sariffstatic void	hdac_mem_free(struct hdac_softc *);
806162922Sariffstatic int	hdac_irq_alloc(struct hdac_softc *);
807162922Sariffstatic void	hdac_irq_free(struct hdac_softc *);
808162922Sariffstatic void	hdac_corb_init(struct hdac_softc *);
809162922Sariffstatic void	hdac_rirb_init(struct hdac_softc *);
810162922Sariffstatic void	hdac_corb_start(struct hdac_softc *);
811162922Sariffstatic void	hdac_rirb_start(struct hdac_softc *);
812182999Smavstatic void	hdac_scan_codecs(struct hdac_softc *);
813182999Smavstatic void	hdac_probe_codec(struct hdac_codec *);
814182999Smavstatic void	hdac_probe_function(struct hdac_codec *, nid_t);
815182999Smavstatic int	hdac_pcmchannel_setup(struct hdac_chan *);
816162922Sariff
817162922Sariffstatic void	hdac_attach2(void *);
818162922Sariff
819162922Sariffstatic uint32_t	hdac_command_sendone_internal(struct hdac_softc *,
820162922Sariff							uint32_t, int);
821162922Sariffstatic void	hdac_command_send_internal(struct hdac_softc *,
822162922Sariff					struct hdac_command_list *, int);
823162922Sariff
824162922Sariffstatic int	hdac_probe(device_t);
825162922Sariffstatic int	hdac_attach(device_t);
826162922Sariffstatic int	hdac_detach(device_t);
827182999Smavstatic int	hdac_suspend(device_t);
828182999Smavstatic int	hdac_resume(device_t);
829162922Sariffstatic void	hdac_widget_connection_select(struct hdac_widget *, uint8_t);
830162922Sariffstatic void	hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
831162922Sariff						uint32_t, int, int);
832162922Sariffstatic struct	hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
833182999Smav							nid_t, int, int, int);
834162922Sariffstatic void	hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
835162922Sariff				nid_t, nid_t, int, int, int, int, int, int);
836162922Sariffstatic struct	hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
837162922Sariff
838164614Sariffstatic int	hdac_rirb_flush(struct hdac_softc *sc);
839164614Sariffstatic int	hdac_unsolq_flush(struct hdac_softc *sc);
840164614Sariff
841182999Smavstatic void	hdac_dump_pin_config(struct hdac_widget *w, uint32_t conf);
842182999Smav
843162922Sariff#define hdac_command(a1, a2, a3)	\
844162922Sariff		hdac_command_sendone_internal(a1, a2, a3)
845162922Sariff
846182999Smav#define hdac_codec_id(c)							\
847182999Smav		((uint32_t)((c == NULL) ? 0x00000000 :	\
848182999Smav		((((uint32_t)(c)->vendor_id & 0x0000ffff) << 16) |	\
849182999Smav		((uint32_t)(c)->device_id & 0x0000ffff))))
850162922Sariff
851162922Sariffstatic char *
852182999Smavhdac_codec_name(struct hdac_codec *codec)
853162922Sariff{
854162922Sariff	uint32_t id;
855162922Sariff	int i;
856162922Sariff
857182999Smav	id = hdac_codec_id(codec);
858162922Sariff
859162922Sariff	for (i = 0; i < HDAC_CODECS_LEN; i++) {
860163257Sariff		if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
861162922Sariff			return (hdac_codecs[i].name);
862162922Sariff	}
863162922Sariff
864162922Sariff	return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec");
865162922Sariff}
866162922Sariff
867162922Sariffstatic char *
868162922Sariffhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
869162922Sariff{
870162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
871162922Sariff	int i, first = 1;
872162922Sariff
873162922Sariff	bzero(buf, len);
874162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
875162922Sariff		if (mask & (1 << i)) {
876162922Sariff			if (first == 0)
877162922Sariff				strlcat(buf, ", ", len);
878162922Sariff			strlcat(buf, ossname[i], len);
879162922Sariff			first = 0;
880162922Sariff		}
881162922Sariff	}
882182999Smav	return (buf);
883162922Sariff}
884162922Sariff
885162922Sariffstatic struct hdac_audio_ctl *
886162922Sariffhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
887162922Sariff{
888162922Sariff	if (devinfo == NULL ||
889162922Sariff	    devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO ||
890162922Sariff	    index == NULL || devinfo->function.audio.ctl == NULL ||
891162922Sariff	    devinfo->function.audio.ctlcnt < 1 ||
892162922Sariff	    *index < 0 || *index >= devinfo->function.audio.ctlcnt)
893162922Sariff		return (NULL);
894162922Sariff	return (&devinfo->function.audio.ctl[(*index)++]);
895162922Sariff}
896162922Sariff
897162922Sariffstatic struct hdac_audio_ctl *
898182999Smavhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid, int dir,
899162922Sariff						int index, int cnt)
900162922Sariff{
901182999Smav	struct hdac_audio_ctl *ctl;
902182999Smav	int i, found = 0;
903162922Sariff
904162922Sariff	if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
905162922Sariff		return (NULL);
906162922Sariff
907162922Sariff	i = 0;
908162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
909182999Smav		if (ctl->enable == 0)
910162922Sariff			continue;
911182999Smav		if (ctl->widget->nid != nid)
912162922Sariff			continue;
913182999Smav		if (dir && ctl->ndir != dir)
914182999Smav			continue;
915182999Smav		if (index >= 0 && ctl->ndir == HDA_CTL_IN &&
916182999Smav		    ctl->dir == ctl->ndir && ctl->index != index)
917182999Smav			continue;
918162922Sariff		found++;
919182999Smav		if (found == cnt || cnt <= 0)
920162922Sariff			return (ctl);
921162922Sariff	}
922162922Sariff
923182999Smav	return (NULL);
924162922Sariff}
925162922Sariff
926182999Smav/*
927182999Smav * Jack detection (Speaker/HP redirection) event handler.
928182999Smav */
929162922Sariffstatic void
930162922Sariffhdac_hp_switch_handler(struct hdac_devinfo *devinfo)
931162922Sariff{
932182999Smav	struct hdac_audio_as *as;
933162922Sariff	struct hdac_softc *sc;
934162922Sariff	struct hdac_widget *w;
935162922Sariff	struct hdac_audio_ctl *ctl;
936182999Smav	uint32_t val, res;
937182999Smav	int i, j;
938162922Sariff	nid_t cad;
939162922Sariff
940162922Sariff	if (devinfo == NULL || devinfo->codec == NULL ||
941162922Sariff	    devinfo->codec->sc == NULL)
942162922Sariff		return;
943162922Sariff
944162922Sariff	sc = devinfo->codec->sc;
945162922Sariff	cad = devinfo->codec->cad;
946182999Smav	as = devinfo->function.audio.as;
947182999Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
948182999Smav		if (as[i].hpredir < 0)
949182999Smav			continue;
950182999Smav
951182999Smav		w = hdac_widget_get(devinfo, as[i].pins[15]);
952182999Smav		if (w == NULL || w->enable == 0 || w->type !=
953182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
954182999Smav			continue;
955162922Sariff
956171141Sariff		res = hdac_command(sc,
957182999Smav		    HDA_CMD_GET_PIN_SENSE(cad, as[i].pins[15]), cad);
958171141Sariff
959182999Smav		HDA_BOOTVERBOSE(
960182999Smav			device_printf(sc->dev,
961182999Smav			    "Pin sense: nid=%d res=0x%08x\n",
962182999Smav			    as[i].pins[15], res);
963182999Smav		);
964171141Sariff
965182999Smav		res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res);
966182999Smav		if (devinfo->function.audio.quirks & HDA_QUIRK_SENSEINV)
967182999Smav			res ^= 1;
968162922Sariff
969182999Smav		/* (Un)Mute headphone pin. */
970162922Sariff		ctl = hdac_audio_ctl_amp_get(devinfo,
971182999Smav		    as[i].pins[15], HDA_CTL_IN, -1, 1);
972182999Smav		if (ctl != NULL && ctl->mute) {
973182999Smav			/* If pin has muter - use it. */
974182999Smav			val = (res != 0) ? 0 : 1;
975182999Smav			if (val != ctl->forcemute) {
976182999Smav				ctl->forcemute = val;
977162922Sariff				hdac_audio_ctl_amp_set(ctl,
978182999Smav				    HDA_AMP_MUTE_DEFAULT,
979182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
980162922Sariff			}
981182999Smav		} else {
982182999Smav			/* If there is no muter - disable pin output. */
983182999Smav			w = hdac_widget_get(devinfo, as[i].pins[15]);
984163057Sariff			if (w != NULL && w->type ==
985163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
986182999Smav				if (res != 0)
987169277Sariff					val = w->wclass.pin.ctrl |
988162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
989162922Sariff				else
990169277Sariff					val = w->wclass.pin.ctrl &
991162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
992169277Sariff				if (val != w->wclass.pin.ctrl) {
993169277Sariff					w->wclass.pin.ctrl = val;
994169277Sariff					hdac_command(sc,
995169277Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
996169277Sariff					    w->nid, w->wclass.pin.ctrl), cad);
997169277Sariff				}
998162922Sariff			}
999182999Smav		}
1000182999Smav		/* (Un)Mute other pins. */
1001182999Smav		for (j = 0; j < 15; j++) {
1002182999Smav			if (as[i].pins[j] <= 0)
1003182999Smav				continue;
1004182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
1005182999Smav			    as[i].pins[j], HDA_CTL_IN, -1, 1);
1006182999Smav			if (ctl != NULL && ctl->mute) {
1007182999Smav				/* If pin has muter - use it. */
1008182999Smav				val = (res != 0) ? 1 : 0;
1009182999Smav				if (val == ctl->forcemute)
1010169277Sariff					continue;
1011182999Smav				ctl->forcemute = val;
1012182999Smav				hdac_audio_ctl_amp_set(ctl,
1013182999Smav				    HDA_AMP_MUTE_DEFAULT,
1014182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
1015182999Smav				continue;
1016162922Sariff			}
1017182999Smav			/* If there is no muter - disable pin output. */
1018182999Smav			w = hdac_widget_get(devinfo, as[i].pins[j]);
1019163057Sariff			if (w != NULL && w->type ==
1020163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
1021182999Smav				if (res != 0)
1022182999Smav					val = w->wclass.pin.ctrl &
1023182999Smav					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1024182999Smav				else
1025182999Smav					val = w->wclass.pin.ctrl |
1026182999Smav					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1027169277Sariff				if (val != w->wclass.pin.ctrl) {
1028169277Sariff					w->wclass.pin.ctrl = val;
1029169277Sariff					hdac_command(sc,
1030169277Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
1031169277Sariff					    w->nid, w->wclass.pin.ctrl), cad);
1032169277Sariff				}
1033162922Sariff			}
1034162922Sariff		}
1035182999Smav	}
1036182999Smav}
1037182999Smav
1038182999Smav/*
1039182999Smav * Callback for poll based jack detection.
1040182999Smav */
1041182999Smavstatic void
1042182999Smavhdac_jack_poll_callback(void *arg)
1043182999Smav{
1044182999Smav	struct hdac_devinfo *devinfo = arg;
1045182999Smav	struct hdac_softc *sc;
1046182999Smav
1047182999Smav	if (devinfo == NULL || devinfo->codec == NULL ||
1048182999Smav	    devinfo->codec->sc == NULL)
1049182999Smav		return;
1050182999Smav	sc = devinfo->codec->sc;
1051182999Smav	hdac_lock(sc);
1052182999Smav	if (sc->poll_ival == 0) {
1053182999Smav		hdac_unlock(sc);
1054182999Smav		return;
1055182999Smav	}
1056182999Smav	hdac_hp_switch_handler(devinfo);
1057182999Smav	callout_reset(&sc->poll_jack, sc->poll_ival,
1058182999Smav	    hdac_jack_poll_callback, devinfo);
1059182999Smav	hdac_unlock(sc);
1060182999Smav}
1061182999Smav
1062182999Smav/*
1063182999Smav * Jack detection initializer.
1064182999Smav */
1065182999Smavstatic void
1066182999Smavhdac_hp_switch_init(struct hdac_devinfo *devinfo)
1067182999Smav{
1068182999Smav        struct hdac_softc *sc = devinfo->codec->sc;
1069182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
1070182999Smav        struct hdac_widget *w;
1071182999Smav        uint32_t id;
1072182999Smav        int i, enable = 0, poll = 0;
1073182999Smav        nid_t cad;
1074182999Smav
1075182999Smav	id = hdac_codec_id(devinfo->codec);
1076182999Smav	cad = devinfo->codec->cad;
1077182999Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
1078182999Smav		if (as[i].hpredir < 0)
1079182999Smav			continue;
1080182999Smav
1081182999Smav		w = hdac_widget_get(devinfo, as[i].pins[15]);
1082182999Smav		if (w == NULL || w->enable == 0 || w->type !=
1083182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1084182999Smav			continue;
1085182999Smav		if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
1086182999Smav		    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
1087182999Smav			device_printf(sc->dev,
1088182999Smav			    "No jack detection support at pin %d\n",
1089182999Smav			    as[i].pins[15]);
1090182999Smav			continue;
1091182999Smav		}
1092182999Smav		enable = 1;
1093182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
1094169277Sariff			hdac_command(sc,
1095182999Smav			    HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid,
1096182999Smav			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
1097182999Smav			    HDAC_UNSOLTAG_EVENT_HP), cad);
1098182999Smav		} else
1099182999Smav			poll = 1;
1100182999Smav		HDA_BOOTVERBOSE(
1101169277Sariff			device_printf(sc->dev,
1102182999Smav			    "Enabling headphone/speaker "
1103182999Smav			    "audio routing switching:\n");
1104182999Smav			device_printf(sc->dev, "\tas=%d sense nid=%d [%s]\n",
1105182999Smav			    i, w->nid, (poll != 0) ? "POLL" : "UNSOL");
1106182999Smav		);
1107182999Smav	}
1108182999Smav	if (enable) {
1109182999Smav		hdac_hp_switch_handler(devinfo);
1110182999Smav		if (poll) {
1111182999Smav			callout_reset(&sc->poll_jack, 1,
1112182999Smav			    hdac_jack_poll_callback, devinfo);
1113169277Sariff		}
1114162922Sariff	}
1115162922Sariff}
1116162922Sariff
1117182999Smav/*
1118182999Smav * Unsolicited messages handler.
1119182999Smav */
1120162922Sariffstatic void
1121162922Sariffhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
1122162922Sariff{
1123162922Sariff	struct hdac_softc *sc;
1124162922Sariff	struct hdac_devinfo *devinfo = NULL;
1125182999Smav	int i;
1126162922Sariff
1127162922Sariff	if (codec == NULL || codec->sc == NULL)
1128162922Sariff		return;
1129162922Sariff
1130162922Sariff	sc = codec->sc;
1131162922Sariff
1132163057Sariff	HDA_BOOTVERBOSE(
1133182999Smav		device_printf(sc->dev, "Unsol Tag: 0x%08x\n", tag);
1134162922Sariff	);
1135162922Sariff
1136182999Smav	for (i = 0; i < codec->num_fgs; i++) {
1137182999Smav		if (codec->fgs[i].node_type ==
1138182999Smav		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
1139182999Smav			devinfo = &codec->fgs[i];
1140162965Sariff			break;
1141182999Smav		}
1142162922Sariff	}
1143162965Sariff
1144162922Sariff	if (devinfo == NULL)
1145162922Sariff		return;
1146162922Sariff
1147162922Sariff	switch (tag) {
1148162922Sariff	case HDAC_UNSOLTAG_EVENT_HP:
1149162922Sariff		hdac_hp_switch_handler(devinfo);
1150162922Sariff		break;
1151162922Sariff	default:
1152182999Smav		device_printf(sc->dev, "Unknown unsol tag: 0x%08x!\n", tag);
1153162922Sariff		break;
1154162922Sariff	}
1155162922Sariff}
1156162922Sariff
1157164614Sariffstatic int
1158162922Sariffhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
1159162922Sariff{
1160162922Sariff	/* XXX to be removed */
1161162922Sariff#ifdef HDAC_INTR_EXTRA
1162162922Sariff	uint32_t res;
1163162922Sariff#endif
1164162922Sariff
1165171330Sariff	if (!(ch->flags & HDAC_CHN_RUNNING))
1166164614Sariff		return (0);
1167162922Sariff
1168162922Sariff	/* XXX to be removed */
1169162922Sariff#ifdef HDAC_INTR_EXTRA
1170162922Sariff	res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS);
1171162922Sariff#endif
1172162922Sariff
1173162922Sariff	/* XXX to be removed */
1174162922Sariff#ifdef HDAC_INTR_EXTRA
1175163057Sariff	HDA_BOOTVERBOSE(
1176163057Sariff		if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE))
1177182999Smav			device_printf(ch->pdevinfo->dev,
1178163057Sariff			    "PCMDIR_%s intr triggered beyond stream boundary:"
1179163057Sariff			    "%08x\n",
1180163057Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
1181163057Sariff	);
1182162922Sariff#endif
1183162922Sariff
1184162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS,
1185163057Sariff	    HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS );
1186162922Sariff
1187162922Sariff	/* XXX to be removed */
1188162922Sariff#ifdef HDAC_INTR_EXTRA
1189162922Sariff	if (res & HDAC_SDSTS_BCIS) {
1190162922Sariff#endif
1191164614Sariff		return (1);
1192162922Sariff	/* XXX to be removed */
1193162922Sariff#ifdef HDAC_INTR_EXTRA
1194162922Sariff	}
1195162922Sariff#endif
1196164614Sariff
1197164614Sariff	return (0);
1198162922Sariff}
1199162922Sariff
1200162922Sariff/****************************************************************************
1201162922Sariff * void hdac_intr_handler(void *)
1202162922Sariff *
1203162922Sariff * Interrupt handler. Processes interrupts received from the hdac.
1204162922Sariff ****************************************************************************/
1205162922Sariffstatic void
1206162922Sariffhdac_intr_handler(void *context)
1207162922Sariff{
1208162922Sariff	struct hdac_softc *sc;
1209162922Sariff	uint32_t intsts;
1210162922Sariff	uint8_t rirbsts;
1211164614Sariff	struct hdac_rirb *rirb_base;
1212171141Sariff	uint32_t trigger;
1213182999Smav	int i;
1214162922Sariff
1215162922Sariff	sc = (struct hdac_softc *)context;
1216162922Sariff
1217162922Sariff	hdac_lock(sc);
1218164614Sariff	if (sc->polling != 0) {
1219164614Sariff		hdac_unlock(sc);
1220164614Sariff		return;
1221164614Sariff	}
1222171141Sariff
1223162922Sariff	/* Do we have anything to do? */
1224162922Sariff	intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
1225163057Sariff	if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) {
1226162922Sariff		hdac_unlock(sc);
1227162922Sariff		return;
1228162922Sariff	}
1229162922Sariff
1230171141Sariff	trigger = 0;
1231171141Sariff
1232162922Sariff	/* Was this a controller interrupt? */
1233163057Sariff	if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) {
1234162922Sariff		rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
1235162922Sariff		rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1236162922Sariff		/* Get as many responses that we can */
1237163057Sariff		while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) {
1238164614Sariff			HDAC_WRITE_1(&sc->mem,
1239164614Sariff			    HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
1240171141Sariff			if (hdac_rirb_flush(sc) != 0)
1241171141Sariff				trigger |= HDAC_TRIGGER_UNSOL;
1242162922Sariff			rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1243162922Sariff		}
1244162922Sariff		/* XXX to be removed */
1245162922Sariff		/* Clear interrupt and exit */
1246162922Sariff#ifdef HDAC_INTR_EXTRA
1247162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS);
1248162922Sariff#endif
1249162922Sariff	}
1250164614Sariff
1251163057Sariff	if (intsts & HDAC_INTSTS_SIS_MASK) {
1252182999Smav		for (i = 0; i < sc->num_chans; i++) {
1253182999Smav			if ((intsts & (1 << (sc->chans[i].off >> 5))) &&
1254182999Smav			    hdac_stream_intr(sc, &sc->chans[i]) != 0)
1255182999Smav				trigger |= (1 << i);
1256182999Smav		}
1257162922Sariff		/* XXX to be removed */
1258162922Sariff#ifdef HDAC_INTR_EXTRA
1259164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts &
1260164614Sariff		    HDAC_INTSTS_SIS_MASK);
1261162922Sariff#endif
1262162922Sariff	}
1263162922Sariff
1264164614Sariff	hdac_unlock(sc);
1265162922Sariff
1266182999Smav	for (i = 0; i < sc->num_chans; i++) {
1267182999Smav		if (trigger & (1 << i))
1268182999Smav			chn_intr(sc->chans[i].c);
1269182999Smav	}
1270171141Sariff	if (trigger & HDAC_TRIGGER_UNSOL)
1271171141Sariff		taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
1272162922Sariff}
1273162922Sariff
1274162922Sariff/****************************************************************************
1275182999Smav * int hdac_reset(hdac_softc *, int)
1276162922Sariff *
1277162922Sariff * Reset the hdac to a quiescent and known state.
1278162922Sariff ****************************************************************************/
1279162922Sariffstatic int
1280182999Smavhdac_reset(struct hdac_softc *sc, int wakeup)
1281162922Sariff{
1282162922Sariff	uint32_t gctl;
1283162922Sariff	int count, i;
1284162922Sariff
1285162922Sariff	/*
1286162922Sariff	 * Stop all Streams DMA engine
1287162922Sariff	 */
1288162922Sariff	for (i = 0; i < sc->num_iss; i++)
1289162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
1290162922Sariff	for (i = 0; i < sc->num_oss; i++)
1291162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
1292162922Sariff	for (i = 0; i < sc->num_bss; i++)
1293162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
1294162922Sariff
1295162922Sariff	/*
1296169277Sariff	 * Stop Control DMA engines.
1297162922Sariff	 */
1298162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
1299162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
1300162922Sariff
1301162922Sariff	/*
1302169277Sariff	 * Reset DMA position buffer.
1303169277Sariff	 */
1304169277Sariff	HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0);
1305169277Sariff	HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0);
1306169277Sariff
1307169277Sariff	/*
1308162922Sariff	 * Reset the controller. The reset must remain asserted for
1309162922Sariff	 * a minimum of 100us.
1310162922Sariff	 */
1311162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1312162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
1313162922Sariff	count = 10000;
1314162922Sariff	do {
1315162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1316162922Sariff		if (!(gctl & HDAC_GCTL_CRST))
1317162922Sariff			break;
1318162922Sariff		DELAY(10);
1319162922Sariff	} while	(--count);
1320162922Sariff	if (gctl & HDAC_GCTL_CRST) {
1321162922Sariff		device_printf(sc->dev, "Unable to put hdac in reset\n");
1322162922Sariff		return (ENXIO);
1323162922Sariff	}
1324182999Smav
1325182999Smav	/* If wakeup is not requested - leave the controller in reset state. */
1326182999Smav	if (!wakeup)
1327182999Smav		return (0);
1328182999Smav
1329162922Sariff	DELAY(100);
1330162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1331162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
1332162922Sariff	count = 10000;
1333162922Sariff	do {
1334162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1335163057Sariff		if (gctl & HDAC_GCTL_CRST)
1336162922Sariff			break;
1337162922Sariff		DELAY(10);
1338162922Sariff	} while (--count);
1339162922Sariff	if (!(gctl & HDAC_GCTL_CRST)) {
1340162922Sariff		device_printf(sc->dev, "Device stuck in reset\n");
1341162922Sariff		return (ENXIO);
1342162922Sariff	}
1343162922Sariff
1344162922Sariff	/*
1345162922Sariff	 * Wait for codecs to finish their own reset sequence. The delay here
1346162922Sariff	 * should be of 250us but for some reasons, on it's not enough on my
1347162922Sariff	 * computer. Let's use twice as much as necessary to make sure that
1348162922Sariff	 * it's reset properly.
1349162922Sariff	 */
1350162922Sariff	DELAY(1000);
1351162922Sariff
1352162922Sariff	return (0);
1353162922Sariff}
1354162922Sariff
1355162922Sariff
1356162922Sariff/****************************************************************************
1357162922Sariff * int hdac_get_capabilities(struct hdac_softc *);
1358162922Sariff *
1359162922Sariff * Retreive the general capabilities of the hdac;
1360162922Sariff *	Number of Input Streams
1361162922Sariff *	Number of Output Streams
1362162922Sariff *	Number of bidirectional Streams
1363162922Sariff *	64bit ready
1364162922Sariff *	CORB and RIRB sizes
1365162922Sariff ****************************************************************************/
1366162922Sariffstatic int
1367162922Sariffhdac_get_capabilities(struct hdac_softc *sc)
1368162922Sariff{
1369162922Sariff	uint16_t gcap;
1370162922Sariff	uint8_t corbsize, rirbsize;
1371162922Sariff
1372162922Sariff	gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
1373162922Sariff	sc->num_iss = HDAC_GCAP_ISS(gcap);
1374162922Sariff	sc->num_oss = HDAC_GCAP_OSS(gcap);
1375162922Sariff	sc->num_bss = HDAC_GCAP_BSS(gcap);
1376162922Sariff
1377163057Sariff	sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK);
1378162922Sariff
1379162922Sariff	corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
1380162922Sariff	if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
1381162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_256)
1382162922Sariff		sc->corb_size = 256;
1383162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
1384162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_16)
1385162922Sariff		sc->corb_size = 16;
1386162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
1387162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_2)
1388162922Sariff		sc->corb_size = 2;
1389162922Sariff	else {
1390162922Sariff		device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
1391162922Sariff		    __func__, corbsize);
1392162922Sariff		return (ENXIO);
1393162922Sariff	}
1394162922Sariff
1395162922Sariff	rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
1396162922Sariff	if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
1397162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_256)
1398162922Sariff		sc->rirb_size = 256;
1399162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
1400162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_16)
1401162922Sariff		sc->rirb_size = 16;
1402162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
1403162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_2)
1404162922Sariff		sc->rirb_size = 2;
1405162922Sariff	else {
1406162922Sariff		device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
1407162922Sariff		    __func__, rirbsize);
1408162922Sariff		return (ENXIO);
1409162922Sariff	}
1410162922Sariff
1411183097Smav	HDA_BOOTHVERBOSE(
1412182999Smav		device_printf(sc->dev, "    CORB size: %d\n", sc->corb_size);
1413182999Smav		device_printf(sc->dev, "    RIRB size: %d\n", sc->rirb_size);
1414182999Smav		device_printf(sc->dev, "      Streams: ISS=%d OSS=%d BSS=%d\n",
1415182999Smav		    sc->num_iss, sc->num_oss, sc->num_bss);
1416182999Smav	);
1417182999Smav
1418162922Sariff	return (0);
1419162922Sariff}
1420162922Sariff
1421162922Sariff
1422162922Sariff/****************************************************************************
1423162922Sariff * void hdac_dma_cb
1424162922Sariff *
1425162922Sariff * This function is called by bus_dmamap_load when the mapping has been
1426162922Sariff * established. We just record the physical address of the mapping into
1427162922Sariff * the struct hdac_dma passed in.
1428162922Sariff ****************************************************************************/
1429162922Sariffstatic void
1430162922Sariffhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
1431162922Sariff{
1432162922Sariff	struct hdac_dma *dma;
1433162922Sariff
1434162922Sariff	if (error == 0) {
1435162922Sariff		dma = (struct hdac_dma *)callback_arg;
1436162922Sariff		dma->dma_paddr = segs[0].ds_addr;
1437162922Sariff	}
1438162922Sariff}
1439162922Sariff
1440162922Sariff
1441162922Sariff/****************************************************************************
1442162922Sariff * int hdac_dma_alloc
1443162922Sariff *
1444162922Sariff * This function allocate and setup a dma region (struct hdac_dma).
1445162922Sariff * It must be freed by a corresponding hdac_dma_free.
1446162922Sariff ****************************************************************************/
1447162922Sariffstatic int
1448162922Sariffhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
1449162922Sariff{
1450169277Sariff	bus_size_t roundsz;
1451162922Sariff	int result;
1452162922Sariff	int lowaddr;
1453162922Sariff
1454169277Sariff	roundsz = roundup2(size, HDAC_DMA_ALIGNMENT);
1455162922Sariff	lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR :
1456162922Sariff	    BUS_SPACE_MAXADDR_32BIT;
1457162922Sariff	bzero(dma, sizeof(*dma));
1458162922Sariff
1459162922Sariff	/*
1460162922Sariff	 * Create a DMA tag
1461162922Sariff	 */
1462162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
1463162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
1464162922Sariff	    0,					/* boundary */
1465162922Sariff	    lowaddr,				/* lowaddr */
1466162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
1467162922Sariff	    NULL,				/* filtfunc */
1468162922Sariff	    NULL,				/* fistfuncarg */
1469169277Sariff	    roundsz, 				/* maxsize */
1470162922Sariff	    1,					/* nsegments */
1471169277Sariff	    roundsz, 				/* maxsegsz */
1472162922Sariff	    0,					/* flags */
1473162922Sariff	    NULL,				/* lockfunc */
1474162922Sariff	    NULL,				/* lockfuncarg */
1475162922Sariff	    &dma->dma_tag);			/* dmat */
1476162922Sariff	if (result != 0) {
1477162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
1478162922Sariff		    __func__, result);
1479167773Sariff		goto hdac_dma_alloc_fail;
1480162922Sariff	}
1481162922Sariff
1482162922Sariff	/*
1483162922Sariff	 * Allocate DMA memory
1484162922Sariff	 */
1485162965Sariff	result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
1486169277Sariff	    BUS_DMA_NOWAIT | BUS_DMA_ZERO |
1487171330Sariff	    ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0),
1488171330Sariff	    &dma->dma_map);
1489162922Sariff	if (result != 0) {
1490162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n",
1491162922Sariff		    __func__, result);
1492167773Sariff		goto hdac_dma_alloc_fail;
1493162922Sariff	}
1494162922Sariff
1495169277Sariff	dma->dma_size = roundsz;
1496169277Sariff
1497162922Sariff	/*
1498162922Sariff	 * Map the memory
1499162922Sariff	 */
1500162922Sariff	result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
1501169277Sariff	    (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0);
1502162922Sariff	if (result != 0 || dma->dma_paddr == 0) {
1503167773Sariff		if (result == 0)
1504167773Sariff			result = ENOMEM;
1505162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n",
1506162922Sariff		    __func__, result);
1507167773Sariff		goto hdac_dma_alloc_fail;
1508162922Sariff	}
1509162922Sariff
1510183097Smav	HDA_BOOTHVERBOSE(
1511169277Sariff		device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n",
1512169277Sariff		    __func__, (uintmax_t)size, (uintmax_t)roundsz);
1513169277Sariff	);
1514169277Sariff
1515162922Sariff	return (0);
1516169277Sariff
1517167773Sariffhdac_dma_alloc_fail:
1518169277Sariff	hdac_dma_free(sc, dma);
1519167773Sariff
1520162922Sariff	return (result);
1521162922Sariff}
1522162922Sariff
1523162922Sariff
1524162922Sariff/****************************************************************************
1525169277Sariff * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *)
1526162922Sariff *
1527162922Sariff * Free a struct dhac_dma that has been previously allocated via the
1528162922Sariff * hdac_dma_alloc function.
1529162922Sariff ****************************************************************************/
1530162922Sariffstatic void
1531169277Sariffhdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma)
1532162922Sariff{
1533167773Sariff	if (dma->dma_map != NULL) {
1534169277Sariff#if 0
1535162922Sariff		/* Flush caches */
1536162922Sariff		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
1537162922Sariff		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1538169277Sariff#endif
1539162922Sariff		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1540167773Sariff	}
1541167773Sariff	if (dma->dma_vaddr != NULL) {
1542162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1543167773Sariff		dma->dma_vaddr = NULL;
1544167773Sariff	}
1545167773Sariff	dma->dma_map = NULL;
1546167773Sariff	if (dma->dma_tag != NULL) {
1547162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1548167773Sariff		dma->dma_tag = NULL;
1549162922Sariff	}
1550167773Sariff	dma->dma_size = 0;
1551162922Sariff}
1552162922Sariff
1553162922Sariff/****************************************************************************
1554162922Sariff * int hdac_mem_alloc(struct hdac_softc *)
1555162922Sariff *
1556162922Sariff * Allocate all the bus resources necessary to speak with the physical
1557162922Sariff * controller.
1558162922Sariff ****************************************************************************/
1559162922Sariffstatic int
1560162922Sariffhdac_mem_alloc(struct hdac_softc *sc)
1561162922Sariff{
1562162922Sariff	struct hdac_mem *mem;
1563162922Sariff
1564162922Sariff	mem = &sc->mem;
1565162922Sariff	mem->mem_rid = PCIR_BAR(0);
1566162922Sariff	mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1567162922Sariff	    &mem->mem_rid, RF_ACTIVE);
1568162922Sariff	if (mem->mem_res == NULL) {
1569162922Sariff		device_printf(sc->dev,
1570162922Sariff		    "%s: Unable to allocate memory resource\n", __func__);
1571162922Sariff		return (ENOMEM);
1572162922Sariff	}
1573162922Sariff	mem->mem_tag = rman_get_bustag(mem->mem_res);
1574162922Sariff	mem->mem_handle = rman_get_bushandle(mem->mem_res);
1575162922Sariff
1576162922Sariff	return (0);
1577162922Sariff}
1578162922Sariff
1579162922Sariff/****************************************************************************
1580162922Sariff * void hdac_mem_free(struct hdac_softc *)
1581162922Sariff *
1582162922Sariff * Free up resources previously allocated by hdac_mem_alloc.
1583162922Sariff ****************************************************************************/
1584162922Sariffstatic void
1585162922Sariffhdac_mem_free(struct hdac_softc *sc)
1586162922Sariff{
1587162922Sariff	struct hdac_mem *mem;
1588162922Sariff
1589162922Sariff	mem = &sc->mem;
1590162922Sariff	if (mem->mem_res != NULL)
1591162922Sariff		bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
1592162922Sariff		    mem->mem_res);
1593164614Sariff	mem->mem_res = NULL;
1594162922Sariff}
1595162922Sariff
1596162922Sariff/****************************************************************************
1597162922Sariff * int hdac_irq_alloc(struct hdac_softc *)
1598162922Sariff *
1599162922Sariff * Allocate and setup the resources necessary for interrupt handling.
1600162922Sariff ****************************************************************************/
1601162922Sariffstatic int
1602162922Sariffhdac_irq_alloc(struct hdac_softc *sc)
1603162922Sariff{
1604162922Sariff	struct hdac_irq *irq;
1605162922Sariff	int result;
1606162922Sariff
1607162922Sariff	irq = &sc->irq;
1608162922Sariff	irq->irq_rid = 0x0;
1609171330Sariff
1610178155Sariff#ifdef HDAC_MSI_ENABLED
1611171330Sariff	if ((sc->flags & HDAC_F_MSI) &&
1612171330Sariff	    (result = pci_msi_count(sc->dev)) == 1 &&
1613171330Sariff	    pci_alloc_msi(sc->dev, &result) == 0)
1614171330Sariff		irq->irq_rid = 0x1;
1615171330Sariff	else
1616171330Sariff#endif
1617171330Sariff		sc->flags &= ~HDAC_F_MSI;
1618171330Sariff
1619162922Sariff	irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1620162922Sariff	    &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
1621162922Sariff	if (irq->irq_res == NULL) {
1622162922Sariff		device_printf(sc->dev, "%s: Unable to allocate irq\n",
1623162922Sariff		    __func__);
1624167773Sariff		goto hdac_irq_alloc_fail;
1625162922Sariff	}
1626182999Smav	result = bus_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE | INTR_TYPE_AV,
1627182999Smav	    NULL, hdac_intr_handler, sc, &irq->irq_handle);
1628162922Sariff	if (result != 0) {
1629162922Sariff		device_printf(sc->dev,
1630162922Sariff		    "%s: Unable to setup interrupt handler (%x)\n",
1631162922Sariff		    __func__, result);
1632167773Sariff		goto hdac_irq_alloc_fail;
1633162922Sariff	}
1634162922Sariff
1635162922Sariff	return (0);
1636162922Sariff
1637167773Sariffhdac_irq_alloc_fail:
1638164614Sariff	hdac_irq_free(sc);
1639164614Sariff
1640162922Sariff	return (ENXIO);
1641162922Sariff}
1642162922Sariff
1643162922Sariff/****************************************************************************
1644162922Sariff * void hdac_irq_free(struct hdac_softc *)
1645162922Sariff *
1646162922Sariff * Free up resources previously allocated by hdac_irq_alloc.
1647162922Sariff ****************************************************************************/
1648162922Sariffstatic void
1649162922Sariffhdac_irq_free(struct hdac_softc *sc)
1650162922Sariff{
1651162922Sariff	struct hdac_irq *irq;
1652162922Sariff
1653162922Sariff	irq = &sc->irq;
1654164614Sariff	if (irq->irq_res != NULL && irq->irq_handle != NULL)
1655162922Sariff		bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
1656162922Sariff	if (irq->irq_res != NULL)
1657162922Sariff		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1658162922Sariff		    irq->irq_res);
1659178155Sariff#ifdef HDAC_MSI_ENABLED
1660171330Sariff	if ((sc->flags & HDAC_F_MSI) && irq->irq_rid == 0x1)
1661171330Sariff		pci_release_msi(sc->dev);
1662171330Sariff#endif
1663164614Sariff	irq->irq_handle = NULL;
1664164614Sariff	irq->irq_res = NULL;
1665171330Sariff	irq->irq_rid = 0x0;
1666162922Sariff}
1667162922Sariff
1668162922Sariff/****************************************************************************
1669162922Sariff * void hdac_corb_init(struct hdac_softc *)
1670162922Sariff *
1671162922Sariff * Initialize the corb registers for operations but do not start it up yet.
1672162922Sariff * The CORB engine must not be running when this function is called.
1673162922Sariff ****************************************************************************/
1674162922Sariffstatic void
1675162922Sariffhdac_corb_init(struct hdac_softc *sc)
1676162922Sariff{
1677162922Sariff	uint8_t corbsize;
1678162922Sariff	uint64_t corbpaddr;
1679162922Sariff
1680162922Sariff	/* Setup the CORB size. */
1681162922Sariff	switch (sc->corb_size) {
1682162922Sariff	case 256:
1683162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
1684162922Sariff		break;
1685162922Sariff	case 16:
1686162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
1687162922Sariff		break;
1688162922Sariff	case 2:
1689162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
1690162922Sariff		break;
1691162922Sariff	default:
1692162922Sariff		panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
1693162922Sariff	}
1694162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
1695162922Sariff
1696162922Sariff	/* Setup the CORB Address in the hdac */
1697162922Sariff	corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
1698162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
1699162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
1700162922Sariff
1701162922Sariff	/* Set the WP and RP */
1702162922Sariff	sc->corb_wp = 0;
1703162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
1704162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
1705162922Sariff	/*
1706162922Sariff	 * The HDA specification indicates that the CORBRPRST bit will always
1707162922Sariff	 * read as zero. Unfortunately, it seems that at least the 82801G
1708162922Sariff	 * doesn't reset the bit to zero, which stalls the corb engine.
1709162922Sariff	 * manually reset the bit to zero before continuing.
1710162922Sariff	 */
1711162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
1712162922Sariff
1713162922Sariff	/* Enable CORB error reporting */
1714162922Sariff#if 0
1715162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
1716162922Sariff#endif
1717162922Sariff}
1718162922Sariff
1719162922Sariff/****************************************************************************
1720162922Sariff * void hdac_rirb_init(struct hdac_softc *)
1721162922Sariff *
1722162922Sariff * Initialize the rirb registers for operations but do not start it up yet.
1723162922Sariff * The RIRB engine must not be running when this function is called.
1724162922Sariff ****************************************************************************/
1725162922Sariffstatic void
1726162922Sariffhdac_rirb_init(struct hdac_softc *sc)
1727162922Sariff{
1728162922Sariff	uint8_t rirbsize;
1729162922Sariff	uint64_t rirbpaddr;
1730162922Sariff
1731162922Sariff	/* Setup the RIRB size. */
1732162922Sariff	switch (sc->rirb_size) {
1733162922Sariff	case 256:
1734162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
1735162922Sariff		break;
1736162922Sariff	case 16:
1737162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
1738162922Sariff		break;
1739162922Sariff	case 2:
1740162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
1741162922Sariff		break;
1742162922Sariff	default:
1743162922Sariff		panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
1744162922Sariff	}
1745162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
1746162922Sariff
1747162922Sariff	/* Setup the RIRB Address in the hdac */
1748162922Sariff	rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
1749162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
1750162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
1751162922Sariff
1752162922Sariff	/* Setup the WP and RP */
1753162922Sariff	sc->rirb_rp = 0;
1754162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
1755162922Sariff
1756182999Smav	/* Setup the interrupt threshold */
1757182999Smav	HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
1758162922Sariff
1759182999Smav	/* Enable Overrun and response received reporting */
1760162922Sariff#if 0
1761182999Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
1762182999Smav	    HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
1763162922Sariff#else
1764182999Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
1765162922Sariff#endif
1766162922Sariff
1767169277Sariff#if 0
1768162922Sariff	/*
1769162922Sariff	 * Make sure that the Host CPU cache doesn't contain any dirty
1770162922Sariff	 * cache lines that falls in the rirb. If I understood correctly, it
1771162922Sariff	 * should be sufficient to do this only once as the rirb is purely
1772162922Sariff	 * read-only from now on.
1773162922Sariff	 */
1774162922Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
1775162922Sariff	    BUS_DMASYNC_PREREAD);
1776169277Sariff#endif
1777162922Sariff}
1778162922Sariff
1779162922Sariff/****************************************************************************
1780162922Sariff * void hdac_corb_start(hdac_softc *)
1781162922Sariff *
1782162922Sariff * Startup the corb DMA engine
1783162922Sariff ****************************************************************************/
1784162922Sariffstatic void
1785162922Sariffhdac_corb_start(struct hdac_softc *sc)
1786162922Sariff{
1787162922Sariff	uint32_t corbctl;
1788162922Sariff
1789162922Sariff	corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
1790162922Sariff	corbctl |= HDAC_CORBCTL_CORBRUN;
1791162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
1792162922Sariff}
1793162922Sariff
1794162922Sariff/****************************************************************************
1795162922Sariff * void hdac_rirb_start(hdac_softc *)
1796162922Sariff *
1797162922Sariff * Startup the rirb DMA engine
1798162922Sariff ****************************************************************************/
1799162922Sariffstatic void
1800162922Sariffhdac_rirb_start(struct hdac_softc *sc)
1801162922Sariff{
1802162922Sariff	uint32_t rirbctl;
1803162922Sariff
1804162922Sariff	rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
1805162922Sariff	rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
1806162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
1807162922Sariff}
1808162922Sariff
1809162922Sariff
1810162922Sariff/****************************************************************************
1811172811Sariff * void hdac_scan_codecs(struct hdac_softc *, int)
1812162922Sariff *
1813172811Sariff * Scan the bus for available codecs, starting with num.
1814162922Sariff ****************************************************************************/
1815162922Sariffstatic void
1816182999Smavhdac_scan_codecs(struct hdac_softc *sc)
1817162922Sariff{
1818162922Sariff	struct hdac_codec *codec;
1819162922Sariff	int i;
1820162922Sariff	uint16_t statests;
1821162922Sariff
1822162922Sariff	statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
1823182999Smav	for (i = 0; i < HDAC_CODEC_MAX; i++) {
1824162922Sariff		if (HDAC_STATESTS_SDIWAKE(statests, i)) {
1825162922Sariff			/* We have found a codec. */
1826162922Sariff			codec = (struct hdac_codec *)malloc(sizeof(*codec),
1827162922Sariff			    M_HDAC, M_ZERO | M_NOWAIT);
1828162922Sariff			if (codec == NULL) {
1829162922Sariff				device_printf(sc->dev,
1830162922Sariff				    "Unable to allocate memory for codec\n");
1831162922Sariff				continue;
1832162922Sariff			}
1833164614Sariff			codec->commands = NULL;
1834164614Sariff			codec->responses_received = 0;
1835162922Sariff			codec->verbs_sent = 0;
1836162922Sariff			codec->sc = sc;
1837162922Sariff			codec->cad = i;
1838162922Sariff			sc->codecs[i] = codec;
1839182999Smav			hdac_probe_codec(codec);
1840162922Sariff		}
1841162922Sariff	}
1842162922Sariff	/* All codecs have been probed, now try to attach drivers to them */
1843163057Sariff	/* bus_generic_attach(sc->dev); */
1844162922Sariff}
1845162922Sariff
1846162922Sariff/****************************************************************************
1847162922Sariff * void hdac_probe_codec(struct hdac_softc *, int)
1848162922Sariff *
1849162922Sariff * Probe a the given codec_id for available function groups.
1850162922Sariff ****************************************************************************/
1851182999Smavstatic void
1852162922Sariffhdac_probe_codec(struct hdac_codec *codec)
1853162922Sariff{
1854162922Sariff	struct hdac_softc *sc = codec->sc;
1855162922Sariff	uint32_t vendorid, revisionid, subnode;
1856162922Sariff	int startnode;
1857162922Sariff	int endnode;
1858162922Sariff	int i;
1859162922Sariff	nid_t cad = codec->cad;
1860162922Sariff
1861163057Sariff	HDA_BOOTVERBOSE(
1862184089Smav		device_printf(sc->dev, "Probing codec #%d...\n", cad);
1863162922Sariff	);
1864162922Sariff	vendorid = hdac_command(sc,
1865162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
1866162922Sariff	    cad);
1867162922Sariff	revisionid = hdac_command(sc,
1868162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
1869162922Sariff	    cad);
1870182999Smav	codec->vendor_id = HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
1871182999Smav	codec->device_id = HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
1872182999Smav	codec->revision_id = HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
1873182999Smav	codec->stepping_id = HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
1874182999Smav
1875182999Smav	if (vendorid == HDAC_INVALID && revisionid == HDAC_INVALID) {
1876182999Smav		device_printf(sc->dev, "Codec #%d is not responding!"
1877182999Smav		    " Probing aborted.\n", cad);
1878182999Smav		return;
1879182999Smav	}
1880182999Smav
1881184089Smav	device_printf(sc->dev, "HDA Codec #%d: %s\n",
1882182999Smav	    cad, hdac_codec_name(codec));
1883182999Smav	HDA_BOOTVERBOSE(
1884184089Smav		device_printf(sc->dev, " HDA Codec ID: 0x%08x\n",
1885182999Smav		    hdac_codec_id(codec));
1886182999Smav		device_printf(sc->dev, "       Vendor: 0x%04x\n",
1887182999Smav		    codec->vendor_id);
1888182999Smav		device_printf(sc->dev, "       Device: 0x%04x\n",
1889182999Smav		    codec->device_id);
1890182999Smav		device_printf(sc->dev, "     Revision: 0x%02x\n",
1891182999Smav		    codec->revision_id);
1892182999Smav		device_printf(sc->dev, "     Stepping: 0x%02x\n",
1893182999Smav		    codec->stepping_id);
1894182999Smav		device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
1895182999Smav		    sc->pci_subvendor);
1896182999Smav	);
1897162922Sariff	subnode = hdac_command(sc,
1898162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
1899162922Sariff	    cad);
1900162922Sariff	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
1901162922Sariff	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
1902162922Sariff
1903183097Smav	HDA_BOOTHVERBOSE(
1904182999Smav		device_printf(sc->dev, "\tstartnode=%d endnode=%d\n",
1905163057Sariff		    startnode, endnode);
1906162922Sariff	);
1907182999Smav
1908182999Smav	codec->fgs = (struct hdac_devinfo *)malloc(sizeof(struct hdac_devinfo) *
1909182999Smav	    (endnode - startnode), M_HDAC, M_NOWAIT | M_ZERO);
1910182999Smav	if (codec->fgs == NULL) {
1911183024Smav		device_printf(sc->dev, "%s: Unable to allocate function groups\n",
1912182999Smav		    __func__);
1913182999Smav		return;
1914162922Sariff	}
1915162922Sariff
1916182999Smav	for (i = startnode; i < endnode; i++)
1917182999Smav		hdac_probe_function(codec, i);
1918182999Smav	return;
1919162922Sariff}
1920162922Sariff
1921182999Smav/*
1922182999Smav * Probe codec function and add it to the list.
1923182999Smav */
1924182999Smavstatic void
1925162922Sariffhdac_probe_function(struct hdac_codec *codec, nid_t nid)
1926162922Sariff{
1927162922Sariff	struct hdac_softc *sc = codec->sc;
1928182999Smav	struct hdac_devinfo *devinfo = &codec->fgs[codec->num_fgs];
1929162922Sariff	uint32_t fctgrptype;
1930182999Smav	uint32_t res;
1931162922Sariff	nid_t cad = codec->cad;
1932162922Sariff
1933162965Sariff	fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
1934162965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
1935162922Sariff
1936162922Sariff	devinfo->nid = nid;
1937162965Sariff	devinfo->node_type = fctgrptype;
1938162922Sariff	devinfo->codec = codec;
1939162922Sariff
1940182999Smav	res = hdac_command(sc,
1941182999Smav	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
1942162922Sariff
1943182999Smav	devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
1944182999Smav	devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
1945182999Smav	devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
1946162922Sariff
1947182999Smav	HDA_BOOTVERBOSE(
1948182999Smav		device_printf(sc->dev,
1949182999Smav		    "\tFound %s FG nid=%d startnode=%d endnode=%d total=%d\n",
1950182999Smav		    (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
1951182999Smav		    (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
1952182999Smav		    "unknown", nid, devinfo->startnode, devinfo->endnode,
1953182999Smav		    devinfo->nodecnt);
1954182999Smav	);
1955182999Smav
1956182999Smav	if (devinfo->nodecnt > 0)
1957182999Smav		devinfo->widget = (struct hdac_widget *)malloc(
1958182999Smav		    sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
1959182999Smav		    M_NOWAIT | M_ZERO);
1960182999Smav	else
1961182999Smav		devinfo->widget = NULL;
1962182999Smav
1963182999Smav	if (devinfo->widget == NULL) {
1964182999Smav		device_printf(sc->dev, "unable to allocate widgets!\n");
1965182999Smav		devinfo->endnode = devinfo->startnode;
1966182999Smav		devinfo->nodecnt = 0;
1967182999Smav		return;
1968182999Smav	}
1969182999Smav
1970182999Smav	codec->num_fgs++;
1971162922Sariff}
1972162922Sariff
1973162922Sariffstatic void
1974162922Sariffhdac_widget_connection_parse(struct hdac_widget *w)
1975162922Sariff{
1976162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1977162922Sariff	uint32_t res;
1978169277Sariff	int i, j, max, ents, entnum;
1979162922Sariff	nid_t cad = w->devinfo->codec->cad;
1980162922Sariff	nid_t nid = w->nid;
1981169277Sariff	nid_t cnid, addcnid, prevcnid;
1982162922Sariff
1983169277Sariff	w->nconns = 0;
1984169277Sariff
1985162922Sariff	res = hdac_command(sc,
1986162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad);
1987162922Sariff
1988169277Sariff	ents = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res);
1989162922Sariff
1990169277Sariff	if (ents < 1)
1991162922Sariff		return;
1992162922Sariff
1993162922Sariff	entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4;
1994162922Sariff	max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1;
1995169277Sariff	prevcnid = 0;
1996162922Sariff
1997169277Sariff#define CONN_RMASK(e)		(1 << ((32 / (e)) - 1))
1998169277Sariff#define CONN_NMASK(e)		(CONN_RMASK(e) - 1)
1999169277Sariff#define CONN_RESVAL(r, e, n)	((r) >> ((32 / (e)) * (n)))
2000169277Sariff#define CONN_RANGE(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_RMASK(e))
2001169277Sariff#define CONN_CNID(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_NMASK(e))
2002169277Sariff
2003169277Sariff	for (i = 0; i < ents; i += entnum) {
2004162922Sariff		res = hdac_command(sc,
2005162922Sariff		    HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad);
2006162922Sariff		for (j = 0; j < entnum; j++) {
2007169277Sariff			cnid = CONN_CNID(res, entnum, j);
2008169277Sariff			if (cnid == 0) {
2009169277Sariff				if (w->nconns < ents)
2010169277Sariff					device_printf(sc->dev,
2011169277Sariff					    "%s: nid=%d WARNING: zero cnid "
2012169277Sariff					    "entnum=%d j=%d index=%d "
2013169277Sariff					    "entries=%d found=%d res=0x%08x\n",
2014169277Sariff					    __func__, nid, entnum, j, i,
2015169277Sariff					    ents, w->nconns, res);
2016169277Sariff				else
2017169277Sariff					goto getconns_out;
2018169277Sariff			}
2019169277Sariff			if (cnid < w->devinfo->startnode ||
2020169277Sariff			    cnid >= w->devinfo->endnode) {
2021169277Sariff				HDA_BOOTVERBOSE(
2022169277Sariff					device_printf(sc->dev,
2023182999Smav					    "GHOST: nid=%d j=%d "
2024169277Sariff					    "entnum=%d index=%d res=0x%08x\n",
2025182999Smav					    nid, j, entnum, i, res);
2026169277Sariff				);
2027169277Sariff			}
2028169277Sariff			if (CONN_RANGE(res, entnum, j) == 0)
2029169277Sariff				addcnid = cnid;
2030169277Sariff			else if (prevcnid == 0 || prevcnid >= cnid) {
2031162922Sariff				device_printf(sc->dev,
2032169277Sariff				    "%s: WARNING: Invalid child range "
2033169277Sariff				    "nid=%d index=%d j=%d entnum=%d "
2034169277Sariff				    "prevcnid=%d cnid=%d res=0x%08x\n",
2035169277Sariff				    __func__, nid, i, j, entnum, prevcnid,
2036169277Sariff				    cnid, res);
2037169277Sariff				addcnid = cnid;
2038169277Sariff			} else
2039169277Sariff				addcnid = prevcnid + 1;
2040169277Sariff			while (addcnid <= cnid) {
2041169277Sariff				if (w->nconns > max) {
2042169277Sariff					device_printf(sc->dev,
2043182999Smav					    "Adding %d (nid=%d): "
2044169277Sariff					    "Max connection reached! max=%d\n",
2045182999Smav					    addcnid, nid, max + 1);
2046169277Sariff					goto getconns_out;
2047169277Sariff				}
2048182999Smav				w->connsenable[w->nconns] = 1;
2049169277Sariff				w->conns[w->nconns++] = addcnid++;
2050162922Sariff			}
2051169277Sariff			prevcnid = cnid;
2052162922Sariff		}
2053162922Sariff	}
2054162922Sariff
2055169277Sariffgetconns_out:
2056169277Sariff	return;
2057162922Sariff}
2058162922Sariff
2059162922Sariffstatic uint32_t
2060182999Smavhdac_widget_pin_patch(uint32_t config, const char *str)
2061182999Smav{
2062182999Smav	char buf[256];
2063182999Smav	char *key, *value, *rest, *bad;
2064182999Smav	int ival, i;
2065182999Smav
2066182999Smav	strlcpy(buf, str, sizeof(buf));
2067182999Smav	rest = buf;
2068182999Smav	while ((key = strsep(&rest, "=")) != NULL) {
2069182999Smav		value = strsep(&rest, " \t");
2070182999Smav		if (value == NULL)
2071182999Smav			break;
2072182999Smav		ival = strtol(value, &bad, 10);
2073182999Smav		if (strcmp(key, "seq") == 0) {
2074182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK;
2075182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) &
2076182999Smav			    HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK);
2077182999Smav		} else if (strcmp(key, "as") == 0) {
2078182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK;
2079182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) &
2080182999Smav			    HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK);
2081182999Smav		} else if (strcmp(key, "misc") == 0) {
2082182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_MISC_MASK;
2083182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) &
2084182999Smav			    HDA_CONFIG_DEFAULTCONF_MISC_MASK);
2085182999Smav		} else if (strcmp(key, "color") == 0) {
2086182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_COLOR_MASK;
2087182999Smav			if (bad[0] == 0) {
2088182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) &
2089182999Smav				    HDA_CONFIG_DEFAULTCONF_COLOR_MASK);
2090182999Smav			};
2091182999Smav			for (i = 0; i < 16; i++) {
2092182999Smav				if (strcasecmp(HDA_COLORS[i], value) == 0) {
2093182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT);
2094182999Smav					break;
2095182999Smav				}
2096182999Smav			}
2097182999Smav		} else if (strcmp(key, "ctype") == 0) {
2098182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK;
2099182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) &
2100182999Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK);
2101182999Smav		} else if (strcmp(key, "device") == 0) {
2102182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2103182999Smav			if (bad[0] == 0) {
2104182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) &
2105182999Smav				    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK);
2106182999Smav				continue;
2107182999Smav			};
2108182999Smav			for (i = 0; i < 16; i++) {
2109182999Smav				if (strcasecmp(HDA_DEVS[i], value) == 0) {
2110182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT);
2111182999Smav					break;
2112182999Smav				}
2113182999Smav			}
2114182999Smav		} else if (strcmp(key, "loc") == 0) {
2115182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_LOCATION_MASK;
2116182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) &
2117182999Smav			    HDA_CONFIG_DEFAULTCONF_LOCATION_MASK);
2118182999Smav		} else if (strcmp(key, "conn") == 0) {
2119182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2120182999Smav			if (bad[0] == 0) {
2121182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) &
2122182999Smav				    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2123182999Smav				continue;
2124182999Smav			};
2125182999Smav			for (i = 0; i < 4; i++) {
2126182999Smav				if (strcasecmp(HDA_CONNS[i], value) == 0) {
2127182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT);
2128182999Smav					break;
2129182999Smav				}
2130182999Smav			}
2131182999Smav		}
2132182999Smav	}
2133182999Smav	return (config);
2134182999Smav}
2135182999Smav
2136182999Smavstatic uint32_t
2137162922Sariffhdac_widget_pin_getconfig(struct hdac_widget *w)
2138162922Sariff{
2139162922Sariff	struct hdac_softc *sc;
2140166965Sariff	uint32_t config, orig, id;
2141162922Sariff	nid_t cad, nid;
2142182999Smav	char buf[32];
2143182999Smav	const char *res = NULL, *patch = NULL;
2144162922Sariff
2145162922Sariff	sc = w->devinfo->codec->sc;
2146162922Sariff	cad = w->devinfo->codec->cad;
2147162922Sariff	nid = w->nid;
2148182999Smav	id = hdac_codec_id(w->devinfo->codec);
2149162922Sariff
2150162922Sariff	config = hdac_command(sc,
2151162922Sariff	    HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
2152162922Sariff	    cad);
2153166965Sariff	orig = config;
2154166965Sariff
2155182999Smav	HDA_BOOTVERBOSE(
2156182999Smav		hdac_dump_pin_config(w, orig);
2157182999Smav	);
2158182999Smav
2159182999Smav	/* XXX: Old patches require complete review.
2160182999Smav	 * Now they may create more problem then solve due to
2161182999Smav	 * incorrect associations.
2162162965Sariff	 */
2163165281Sariff	if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) {
2164165281Sariff		switch (nid) {
2165165281Sariff		case 26:
2166165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2167165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2168165281Sariff			break;
2169165281Sariff		case 27:
2170165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2171165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
2172165281Sariff			break;
2173167610Sariff		default:
2174167610Sariff			break;
2175165281Sariff		}
2176165281Sariff	} else if (id == HDA_CODEC_ALC880 &&
2177162965Sariff	    (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR ||
2178162965Sariff	    sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) {
2179162922Sariff		/*
2180162965Sariff		 * Super broken BIOS
2181162922Sariff		 */
2182162922Sariff		switch (nid) {
2183162922Sariff		case 24:	/* MIC1 */
2184162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2185162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2186162922Sariff			break;
2187162922Sariff		case 25:	/* XXX MIC2 */
2188162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2189162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2190162922Sariff			break;
2191162922Sariff		case 26:	/* LINE1 */
2192162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2193162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2194162922Sariff			break;
2195162922Sariff		case 27:	/* XXX LINE2 */
2196162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2197162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2198162922Sariff			break;
2199162922Sariff		case 28:	/* CD */
2200162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2201162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
2202162922Sariff			break;
2203162922Sariff		}
2204166965Sariff	} else if (id == HDA_CODEC_ALC883 &&
2205172811Sariff	    (sc->pci_subvendor == MSI_MS034A_SUBVENDOR ||
2206172811Sariff	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor))) {
2207166965Sariff		switch (nid) {
2208166965Sariff		case 25:
2209166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2210166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2211166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2212166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2213166965Sariff			break;
2214169277Sariff		case 28:
2215169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2216169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2217169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2218169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2219169277Sariff			break;
2220166965Sariff		}
2221166965Sariff	} else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor ==
2222166965Sariff	    HP_V3000_SUBVENDOR) {
2223166965Sariff		switch (nid) {
2224166965Sariff		case 18:
2225166965Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2226166965Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2227166965Sariff			break;
2228166965Sariff		case 20:
2229166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2230166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2231166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2232166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2233166965Sariff			break;
2234167454Sariff		case 21:
2235167454Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2236167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2237167454Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2238167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2239167454Sariff			break;
2240166965Sariff		}
2241169277Sariff	} else if (id == HDA_CODEC_CXWAIKIKI && sc->pci_subvendor ==
2242169277Sariff	    HP_DV5000_SUBVENDOR) {
2243169277Sariff		switch (nid) {
2244169277Sariff		case 20:
2245169277Sariff		case 21:
2246169277Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2247169277Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2248169277Sariff			break;
2249169277Sariff		}
2250169277Sariff	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2251169277Sariff	    ASUS_W6F_SUBVENDOR) {
2252169277Sariff		switch (nid) {
2253169277Sariff		case 11:
2254169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2255169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2256169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
2257169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2258169277Sariff			break;
2259178324Sariff		case 12:
2260178324Sariff		case 14:
2261178324Sariff		case 16:
2262178324Sariff		case 31:
2263178324Sariff		case 32:
2264178324Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2265178324Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2266178324Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2267178324Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2268178324Sariff			break;
2269169277Sariff		case 15:
2270169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2271169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2272169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2273169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2274169277Sariff			break;
2275169277Sariff		}
2276169277Sariff	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2277169277Sariff	    UNIWILL_9075_SUBVENDOR) {
2278169277Sariff		switch (nid) {
2279169277Sariff		case 15:
2280169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2281169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2282169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2283169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2284169277Sariff			break;
2285169277Sariff		}
2286182999Smav	}
2287182999Smav
2288182999Smav	/* New patches */
2289182999Smav	if (id == HDA_CODEC_AD1986A &&
2290171141Sariff	    (sc->pci_subvendor == ASUS_M2NPVMX_SUBVENDOR ||
2291171141Sariff	    sc->pci_subvendor == ASUS_A8NVMCSM_SUBVENDOR)) {
2292169277Sariff		switch (nid) {
2293182999Smav		case 28: /* 5.1 out => 2.0 out + 2 inputs */
2294182999Smav			patch = "device=Line-in as=8 seq=1";
2295169277Sariff			break;
2296182999Smav		case 29:
2297182999Smav			patch = "device=Mic as=8 seq=2";
2298169277Sariff			break;
2299182999Smav		case 31: /* Lot of inputs configured with as=15 and unusable */
2300182999Smav			patch = "as=8 seq=3";
2301169277Sariff			break;
2302182999Smav		case 32:
2303182999Smav			patch = "as=8 seq=4";
2304182999Smav			break;
2305182999Smav		case 34:
2306182999Smav			patch = "as=8 seq=5";
2307182999Smav			break;
2308182999Smav		case 36:
2309182999Smav			patch = "as=8 seq=6";
2310182999Smav			break;
2311169277Sariff		}
2312182999Smav	} else if (id == HDA_CODEC_ALC260 &&
2313182999Smav	    HDA_DEV_MATCH(SONY_S5_SUBVENDOR, sc->pci_subvendor)) {
2314182999Smav		switch (nid) {
2315182999Smav		case 16:
2316182999Smav			patch = "seq=15 device=Headphones";
2317182999Smav			break;
2318182999Smav		}
2319174578Sariff	} else if (id == HDA_CODEC_ALC268 &&
2320174578Sariff	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) {
2321174578Sariff		switch (nid) {
2322174578Sariff		case 28:
2323182999Smav			patch = "device=CD conn=fixed";
2324174578Sariff			break;
2325174578Sariff		}
2326162922Sariff	}
2327162922Sariff
2328182999Smav	if (patch != NULL)
2329182999Smav		config = hdac_widget_pin_patch(config, patch);
2330182999Smav
2331182999Smav	snprintf(buf, sizeof(buf), "cad%u.nid%u.config", cad, nid);
2332182999Smav	if (resource_string_value(device_get_name(sc->dev),
2333182999Smav	    device_get_unit(sc->dev), buf, &res) == 0) {
2334182999Smav		if (strncmp(res, "0x", 2) == 0) {
2335182999Smav			config = strtol(res + 2, NULL, 16);
2336182999Smav		} else {
2337182999Smav			config = hdac_widget_pin_patch(config, res);
2338182999Smav		}
2339182999Smav	}
2340182999Smav
2341166965Sariff	HDA_BOOTVERBOSE(
2342166965Sariff		if (config != orig)
2343166965Sariff			device_printf(sc->dev,
2344182999Smav			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
2345166965Sariff			    nid, orig, config);
2346166965Sariff	);
2347166965Sariff
2348162922Sariff	return (config);
2349162922Sariff}
2350162922Sariff
2351166965Sariffstatic uint32_t
2352166965Sariffhdac_widget_pin_getcaps(struct hdac_widget *w)
2353166965Sariff{
2354166965Sariff	struct hdac_softc *sc;
2355166965Sariff	uint32_t caps, orig, id;
2356166965Sariff	nid_t cad, nid;
2357166965Sariff
2358166965Sariff	sc = w->devinfo->codec->sc;
2359166965Sariff	cad = w->devinfo->codec->cad;
2360166965Sariff	nid = w->nid;
2361182999Smav	id = hdac_codec_id(w->devinfo->codec);
2362166965Sariff
2363166965Sariff	caps = hdac_command(sc,
2364166965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
2365166965Sariff	orig = caps;
2366166965Sariff
2367166965Sariff	HDA_BOOTVERBOSE(
2368166965Sariff		if (caps != orig)
2369166965Sariff			device_printf(sc->dev,
2370182999Smav			    "Patching pin caps nid=%u 0x%08x -> 0x%08x\n",
2371166965Sariff			    nid, orig, caps);
2372166965Sariff	);
2373166965Sariff
2374166965Sariff	return (caps);
2375166965Sariff}
2376166965Sariff
2377162922Sariffstatic void
2378162922Sariffhdac_widget_pin_parse(struct hdac_widget *w)
2379162922Sariff{
2380162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2381162922Sariff	uint32_t config, pincap;
2382182999Smav	const char *devstr, *connstr;
2383162922Sariff	nid_t cad = w->devinfo->codec->cad;
2384162922Sariff	nid_t nid = w->nid;
2385162922Sariff
2386162922Sariff	config = hdac_widget_pin_getconfig(w);
2387162922Sariff	w->wclass.pin.config = config;
2388162922Sariff
2389166965Sariff	pincap = hdac_widget_pin_getcaps(w);
2390162922Sariff	w->wclass.pin.cap = pincap;
2391162922Sariff
2392162922Sariff	w->wclass.pin.ctrl = hdac_command(sc,
2393182999Smav	    HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad);
2394162922Sariff
2395162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
2396162922Sariff		w->param.eapdbtl = hdac_command(sc,
2397162922Sariff		    HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
2398162922Sariff		w->param.eapdbtl &= 0x7;
2399162922Sariff		w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
2400162922Sariff	} else
2401162965Sariff		w->param.eapdbtl = HDAC_INVALID;
2402162922Sariff
2403182999Smav	devstr = HDA_DEVS[(config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >>
2404182999Smav	    HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT];
2405162922Sariff
2406182999Smav	connstr = HDA_CONNS[(config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >>
2407182999Smav	    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT];
2408162922Sariff
2409162922Sariff	strlcat(w->name, ": ", sizeof(w->name));
2410162922Sariff	strlcat(w->name, devstr, sizeof(w->name));
2411162922Sariff	strlcat(w->name, " (", sizeof(w->name));
2412162922Sariff	strlcat(w->name, connstr, sizeof(w->name));
2413162922Sariff	strlcat(w->name, ")", sizeof(w->name));
2414162922Sariff}
2415162922Sariff
2416182999Smavstatic uint32_t
2417182999Smavhdac_widget_getcaps(struct hdac_widget *w, int *waspin)
2418182999Smav{
2419182999Smav	struct hdac_softc *sc;
2420182999Smav	uint32_t caps, orig, id;
2421182999Smav	nid_t cad, nid, beeper = -1;
2422182999Smav
2423182999Smav	sc = w->devinfo->codec->sc;
2424182999Smav	cad = w->devinfo->codec->cad;
2425182999Smav	nid = w->nid;
2426182999Smav	id = hdac_codec_id(w->devinfo->codec);
2427182999Smav
2428182999Smav	caps = hdac_command(sc,
2429182999Smav	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
2430182999Smav	    cad);
2431182999Smav	orig = caps;
2432182999Smav
2433182999Smav	/* On some codecs beeper is an input pin, but it is not recordable
2434182999Smav	   alone. Also most of BIOSes does not declare beeper pin.
2435182999Smav	   Change beeper pin node type to beeper to help parser. */
2436182999Smav	*waspin = 0;
2437182999Smav	switch (id) {
2438182999Smav	case HDA_CODEC_AD1988:
2439182999Smav	case HDA_CODEC_AD1988B:
2440182999Smav		beeper = 26;
2441182999Smav		break;
2442182999Smav	case HDA_CODEC_ALC260:
2443182999Smav		beeper = 23;
2444182999Smav		break;
2445182999Smav	case HDA_CODEC_ALC262:
2446182999Smav	case HDA_CODEC_ALC268:
2447182999Smav	case HDA_CODEC_ALC880:
2448182999Smav	case HDA_CODEC_ALC882:
2449182999Smav	case HDA_CODEC_ALC883:
2450182999Smav	case HDA_CODEC_ALC885:
2451182999Smav	case HDA_CODEC_ALC888:
2452182999Smav	case HDA_CODEC_ALC889:
2453182999Smav		beeper = 29;
2454182999Smav		break;
2455182999Smav	}
2456182999Smav	if (nid == beeper) {
2457182999Smav		caps &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
2458182999Smav		caps |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
2459182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
2460182999Smav		*waspin = 1;
2461182999Smav	}
2462182999Smav
2463182999Smav	HDA_BOOTVERBOSE(
2464182999Smav		if (caps != orig) {
2465182999Smav			device_printf(sc->dev,
2466182999Smav			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
2467182999Smav			    nid, orig, caps);
2468182999Smav		}
2469182999Smav	);
2470182999Smav
2471182999Smav	return (caps);
2472182999Smav}
2473182999Smav
2474162922Sariffstatic void
2475162922Sariffhdac_widget_parse(struct hdac_widget *w)
2476162922Sariff{
2477162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2478162922Sariff	uint32_t wcap, cap;
2479162922Sariff	char *typestr;
2480162922Sariff	nid_t cad = w->devinfo->codec->cad;
2481162922Sariff	nid_t nid = w->nid;
2482162922Sariff
2483182999Smav	wcap = hdac_widget_getcaps(w, &w->waspin);
2484182999Smav
2485162922Sariff	w->param.widget_cap = wcap;
2486162922Sariff	w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
2487162922Sariff
2488162922Sariff	switch (w->type) {
2489162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
2490162922Sariff		typestr = "audio output";
2491162922Sariff		break;
2492162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
2493162922Sariff		typestr = "audio input";
2494162922Sariff		break;
2495162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
2496162922Sariff		typestr = "audio mixer";
2497162922Sariff		break;
2498162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
2499162922Sariff		typestr = "audio selector";
2500162922Sariff		break;
2501162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
2502162922Sariff		typestr = "pin";
2503162922Sariff		break;
2504162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET:
2505162922Sariff		typestr = "power widget";
2506162922Sariff		break;
2507162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET:
2508162922Sariff		typestr = "volume widget";
2509162922Sariff		break;
2510162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
2511162922Sariff		typestr = "beep widget";
2512162922Sariff		break;
2513162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET:
2514162922Sariff		typestr = "vendor widget";
2515162922Sariff		break;
2516162922Sariff	default:
2517162922Sariff		typestr = "unknown type";
2518162922Sariff		break;
2519162922Sariff	}
2520162922Sariff
2521162922Sariff	strlcpy(w->name, typestr, sizeof(w->name));
2522162922Sariff
2523162922Sariff	hdac_widget_connection_parse(w);
2524162922Sariff
2525162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
2526162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2527162922Sariff			w->param.outamp_cap =
2528162922Sariff			    hdac_command(sc,
2529162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2530162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP), cad);
2531162922Sariff		else
2532162922Sariff			w->param.outamp_cap =
2533162922Sariff			    w->devinfo->function.audio.outamp_cap;
2534162922Sariff	} else
2535162922Sariff		w->param.outamp_cap = 0;
2536162922Sariff
2537162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) {
2538162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2539162922Sariff			w->param.inamp_cap =
2540162922Sariff			    hdac_command(sc,
2541162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2542162922Sariff			    HDA_PARAM_INPUT_AMP_CAP), cad);
2543162922Sariff		else
2544162922Sariff			w->param.inamp_cap =
2545162922Sariff			    w->devinfo->function.audio.inamp_cap;
2546162922Sariff	} else
2547162922Sariff		w->param.inamp_cap = 0;
2548162922Sariff
2549162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
2550162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
2551162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) {
2552162922Sariff			cap = hdac_command(sc,
2553162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2554162922Sariff			    HDA_PARAM_SUPP_STREAM_FORMATS), cad);
2555162922Sariff			w->param.supp_stream_formats = (cap != 0) ? cap :
2556162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2557162922Sariff			cap = hdac_command(sc,
2558162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2559162922Sariff			    HDA_PARAM_SUPP_PCM_SIZE_RATE), cad);
2560162922Sariff			w->param.supp_pcm_size_rate = (cap != 0) ? cap :
2561162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2562162922Sariff		} else {
2563162922Sariff			w->param.supp_stream_formats =
2564162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2565162922Sariff			w->param.supp_pcm_size_rate =
2566162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2567162922Sariff		}
2568162922Sariff	} else {
2569162922Sariff		w->param.supp_stream_formats = 0;
2570162922Sariff		w->param.supp_pcm_size_rate = 0;
2571162922Sariff	}
2572162922Sariff
2573162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
2574162922Sariff		hdac_widget_pin_parse(w);
2575162922Sariff}
2576162922Sariff
2577162922Sariffstatic struct hdac_widget *
2578162922Sariffhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid)
2579162922Sariff{
2580162922Sariff	if (devinfo == NULL || devinfo->widget == NULL ||
2581162922Sariff		    nid < devinfo->startnode || nid >= devinfo->endnode)
2582162922Sariff		return (NULL);
2583162922Sariff	return (&devinfo->widget[nid - devinfo->startnode]);
2584162922Sariff}
2585162922Sariff
2586164614Sariffstatic __inline int
2587164614Sariffhda_poll_channel(struct hdac_chan *ch)
2588164614Sariff{
2589164614Sariff	uint32_t sz, delta;
2590164614Sariff	volatile uint32_t ptr;
2591164614Sariff
2592171330Sariff	if (!(ch->flags & HDAC_CHN_RUNNING))
2593164614Sariff		return (0);
2594164614Sariff
2595164614Sariff	sz = ch->blksz * ch->blkcnt;
2596169277Sariff	if (ch->dmapos != NULL)
2597169277Sariff		ptr = *(ch->dmapos);
2598169277Sariff	else
2599169277Sariff		ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem,
2600169277Sariff		    ch->off + HDAC_SDLPIB);
2601164614Sariff	ch->ptr = ptr;
2602164614Sariff	ptr %= sz;
2603164614Sariff	ptr &= ~(ch->blksz - 1);
2604164614Sariff	delta = (sz + ptr - ch->prevptr) % sz;
2605164614Sariff
2606164614Sariff	if (delta < ch->blksz)
2607164614Sariff		return (0);
2608164614Sariff
2609164614Sariff	ch->prevptr = ptr;
2610164614Sariff
2611164614Sariff	return (1);
2612164614Sariff}
2613164614Sariff
2614162922Sariffstatic void
2615164614Sariffhda_poll_callback(void *arg)
2616164614Sariff{
2617164614Sariff	struct hdac_softc *sc = arg;
2618171141Sariff	uint32_t trigger;
2619182999Smav	int i, active = 0;
2620164614Sariff
2621164614Sariff	if (sc == NULL)
2622164614Sariff		return;
2623164614Sariff
2624164614Sariff	hdac_lock(sc);
2625182999Smav	if (sc->polling == 0) {
2626164614Sariff		hdac_unlock(sc);
2627164614Sariff		return;
2628164614Sariff	}
2629164614Sariff
2630171141Sariff	trigger = 0;
2631182999Smav	for (i = 0; i < sc->num_chans; i++) {
2632182999Smav		if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
2633182999Smav		    continue;
2634182999Smav		active = 1;
2635182999Smav		if (hda_poll_channel(&sc->chans[i]))
2636182999Smav		    trigger |= (1 << i);
2637182999Smav	}
2638164614Sariff
2639164614Sariff	/* XXX */
2640182999Smav	if (active)
2641182999Smav		callout_reset(&sc->poll_hda, sc->poll_ticks,
2642182999Smav		    hda_poll_callback, sc);
2643164614Sariff
2644164614Sariff	hdac_unlock(sc);
2645164614Sariff
2646182999Smav	for (i = 0; i < sc->num_chans; i++) {
2647182999Smav		if (trigger & (1 << i))
2648182999Smav			chn_intr(sc->chans[i].c);
2649182999Smav	}
2650164614Sariff}
2651164614Sariff
2652164614Sariffstatic int
2653164614Sariffhdac_rirb_flush(struct hdac_softc *sc)
2654164614Sariff{
2655164614Sariff	struct hdac_rirb *rirb_base, *rirb;
2656164614Sariff	struct hdac_codec *codec;
2657164614Sariff	struct hdac_command_list *commands;
2658164614Sariff	nid_t cad;
2659164614Sariff	uint32_t resp;
2660164614Sariff	uint8_t rirbwp;
2661171141Sariff	int ret;
2662164614Sariff
2663164614Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2664164614Sariff	rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
2665169277Sariff#if 0
2666164614Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2667164614Sariff	    BUS_DMASYNC_POSTREAD);
2668169277Sariff#endif
2669164614Sariff
2670171141Sariff	ret = 0;
2671171141Sariff
2672164614Sariff	while (sc->rirb_rp != rirbwp) {
2673164614Sariff		sc->rirb_rp++;
2674164614Sariff		sc->rirb_rp %= sc->rirb_size;
2675164614Sariff		rirb = &rirb_base[sc->rirb_rp];
2676164614Sariff		cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
2677164614Sariff		if (cad < 0 || cad >= HDAC_CODEC_MAX ||
2678164614Sariff		    sc->codecs[cad] == NULL)
2679164614Sariff			continue;
2680164614Sariff		resp = rirb->response;
2681164614Sariff		codec = sc->codecs[cad];
2682164614Sariff		commands = codec->commands;
2683164614Sariff		if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
2684164614Sariff			sc->unsolq[sc->unsolq_wp++] = (cad << 16) |
2685164614Sariff			    ((resp >> 26) & 0xffff);
2686164614Sariff			sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
2687164614Sariff		} else if (commands != NULL && commands->num_commands > 0 &&
2688164614Sariff		    codec->responses_received < commands->num_commands)
2689164614Sariff			commands->responses[codec->responses_received++] =
2690164614Sariff			    resp;
2691164614Sariff		ret++;
2692164614Sariff	}
2693164614Sariff
2694164614Sariff	return (ret);
2695164614Sariff}
2696164614Sariff
2697164614Sariffstatic int
2698164614Sariffhdac_unsolq_flush(struct hdac_softc *sc)
2699164614Sariff{
2700164614Sariff	nid_t cad;
2701164614Sariff	uint32_t tag;
2702164614Sariff	int ret = 0;
2703164614Sariff
2704164614Sariff	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
2705164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
2706164614Sariff		while (sc->unsolq_rp != sc->unsolq_wp) {
2707164614Sariff			cad = sc->unsolq[sc->unsolq_rp] >> 16;
2708164614Sariff			tag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
2709164614Sariff			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
2710164614Sariff			hdac_unsolicited_handler(sc->codecs[cad], tag);
2711164614Sariff			ret++;
2712164614Sariff		}
2713164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_READY;
2714164614Sariff	}
2715164614Sariff
2716164614Sariff	return (ret);
2717164614Sariff}
2718164614Sariff
2719164614Sariffstatic void
2720164614Sariffhdac_poll_callback(void *arg)
2721164614Sariff{
2722164614Sariff	struct hdac_softc *sc = arg;
2723164614Sariff	if (sc == NULL)
2724164614Sariff		return;
2725166796Sariff
2726164614Sariff	hdac_lock(sc);
2727169277Sariff	if (sc->polling == 0 || sc->poll_ival == 0) {
2728164614Sariff		hdac_unlock(sc);
2729164614Sariff		return;
2730164614Sariff	}
2731171141Sariff	if (hdac_rirb_flush(sc) != 0)
2732171141Sariff		hdac_unsolq_flush(sc);
2733169277Sariff	callout_reset(&sc->poll_hdac, sc->poll_ival, hdac_poll_callback, sc);
2734164614Sariff	hdac_unlock(sc);
2735164614Sariff}
2736164614Sariff
2737164614Sariffstatic void
2738182999Smavhdac_poll_reinit(struct hdac_softc *sc)
2739182999Smav{
2740182999Smav	int i, pollticks, min = 1000000;
2741182999Smav	struct hdac_chan *ch;
2742182999Smav
2743182999Smav	for (i = 0; i < sc->num_chans; i++) {
2744182999Smav		if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
2745182999Smav			continue;
2746182999Smav		ch = &sc->chans[i];
2747182999Smav		pollticks = ((uint64_t)hz * ch->blksz) /
2748182999Smav		    ((uint64_t)sndbuf_getbps(ch->b) *
2749182999Smav		    sndbuf_getspd(ch->b));
2750182999Smav		pollticks >>= 1;
2751182999Smav		if (pollticks > hz)
2752182999Smav			pollticks = hz;
2753182999Smav		if (pollticks < 1) {
2754182999Smav			HDA_BOOTVERBOSE(
2755182999Smav				device_printf(sc->dev,
2756182999Smav				    "%s: pollticks=%d < 1 !\n",
2757182999Smav				    __func__, pollticks);
2758182999Smav			);
2759182999Smav			pollticks = 1;
2760182999Smav		}
2761182999Smav		if (min > pollticks)
2762182999Smav			min = pollticks;
2763182999Smav	}
2764182999Smav	HDA_BOOTVERBOSE(
2765182999Smav		device_printf(sc->dev,
2766182999Smav		    "%s: pollticks %d -> %d\n",
2767182999Smav		    __func__, sc->poll_ticks, min);
2768182999Smav	);
2769182999Smav	sc->poll_ticks = min;
2770182999Smav	if (min == 1000000)
2771182999Smav		callout_stop(&sc->poll_hda);
2772182999Smav	else
2773182999Smav		callout_reset(&sc->poll_hda, 1, hda_poll_callback, sc);
2774182999Smav}
2775182999Smav
2776182999Smavstatic void
2777162922Sariffhdac_stream_stop(struct hdac_chan *ch)
2778162922Sariff{
2779162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2780162922Sariff	uint32_t ctl;
2781162922Sariff
2782162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2783162922Sariff	ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2784162922Sariff	    HDAC_SDCTL_RUN);
2785162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2786162922Sariff
2787171330Sariff	ch->flags &= ~HDAC_CHN_RUNNING;
2788164614Sariff
2789182999Smav	if (sc->polling != 0)
2790182999Smav		hdac_poll_reinit(sc);
2791164614Sariff
2792182999Smav	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2793182999Smav	ctl &= ~(1 << (ch->off >> 5));
2794182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2795162922Sariff}
2796162922Sariff
2797162922Sariffstatic void
2798162922Sariffhdac_stream_start(struct hdac_chan *ch)
2799162922Sariff{
2800162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2801162922Sariff	uint32_t ctl;
2802162922Sariff
2803182999Smav	ch->flags |= HDAC_CHN_RUNNING;
2804162922Sariff
2805182999Smav	if (sc->polling != 0)
2806182999Smav		hdac_poll_reinit(sc);
2807182999Smav
2808182999Smav	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2809182999Smav	ctl |= 1 << (ch->off >> 5);
2810182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2811182999Smav
2812182999Smav	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2813182999Smav	ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2814182999Smav	    HDAC_SDCTL_RUN;
2815162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2816162922Sariff}
2817162922Sariff
2818162922Sariffstatic void
2819162922Sariffhdac_stream_reset(struct hdac_chan *ch)
2820162922Sariff{
2821162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2822162922Sariff	int timeout = 1000;
2823162922Sariff	int to = timeout;
2824162922Sariff	uint32_t ctl;
2825162922Sariff
2826162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2827162922Sariff	ctl |= HDAC_SDCTL_SRST;
2828162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2829162922Sariff	do {
2830162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2831162922Sariff		if (ctl & HDAC_SDCTL_SRST)
2832162922Sariff			break;
2833162922Sariff		DELAY(10);
2834162922Sariff	} while (--to);
2835162922Sariff	if (!(ctl & HDAC_SDCTL_SRST)) {
2836162922Sariff		device_printf(sc->dev, "timeout in reset\n");
2837162922Sariff	}
2838162922Sariff	ctl &= ~HDAC_SDCTL_SRST;
2839162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2840162922Sariff	to = timeout;
2841162922Sariff	do {
2842162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2843162922Sariff		if (!(ctl & HDAC_SDCTL_SRST))
2844162922Sariff			break;
2845162922Sariff		DELAY(10);
2846162922Sariff	} while (--to);
2847163057Sariff	if (ctl & HDAC_SDCTL_SRST)
2848162922Sariff		device_printf(sc->dev, "can't reset!\n");
2849162922Sariff}
2850162922Sariff
2851162922Sariffstatic void
2852162922Sariffhdac_stream_setid(struct hdac_chan *ch)
2853162922Sariff{
2854162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2855162922Sariff	uint32_t ctl;
2856162922Sariff
2857162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2);
2858162922Sariff	ctl &= ~HDAC_SDCTL2_STRM_MASK;
2859162922Sariff	ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT;
2860162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl);
2861162922Sariff}
2862162922Sariff
2863162922Sariffstatic void
2864162922Sariffhdac_bdl_setup(struct hdac_chan *ch)
2865162922Sariff{
2866162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2867164614Sariff	struct hdac_bdle *bdle;
2868162922Sariff	uint64_t addr;
2869164614Sariff	uint32_t blksz, blkcnt;
2870162922Sariff	int i;
2871162922Sariff
2872162922Sariff	addr = (uint64_t)sndbuf_getbufaddr(ch->b);
2873164614Sariff	bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr;
2874162922Sariff
2875182999Smav	blksz = ch->blksz;
2876182999Smav	blkcnt = ch->blkcnt;
2877164614Sariff
2878164614Sariff	for (i = 0; i < blkcnt; i++, bdle++) {
2879162922Sariff		bdle->addrl = (uint32_t)addr;
2880162922Sariff		bdle->addrh = (uint32_t)(addr >> 32);
2881164614Sariff		bdle->len = blksz;
2882182999Smav		bdle->ioc = 1;
2883164614Sariff		addr += blksz;
2884162922Sariff	}
2885162922Sariff
2886164614Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt);
2887164614Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1);
2888162922Sariff	addr = ch->bdl_dma.dma_paddr;
2889162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr);
2890162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
2891169277Sariff	if (ch->dmapos != NULL &&
2892169277Sariff	    !(HDAC_READ_4(&sc->mem, HDAC_DPIBLBASE) & 0x00000001)) {
2893169277Sariff		addr = sc->pos_dma.dma_paddr;
2894169277Sariff		HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE,
2895169277Sariff		    ((uint32_t)addr & HDAC_DPLBASE_DPLBASE_MASK) | 0x00000001);
2896169277Sariff		HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, (uint32_t)(addr >> 32));
2897169277Sariff	}
2898162922Sariff}
2899162922Sariff
2900162922Sariffstatic int
2901162922Sariffhdac_bdl_alloc(struct hdac_chan *ch)
2902162922Sariff{
2903162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2904162922Sariff	int rc;
2905162922Sariff
2906162922Sariff	rc = hdac_dma_alloc(sc, &ch->bdl_dma,
2907162922Sariff	    sizeof(struct hdac_bdle) * HDA_BDL_MAX);
2908162922Sariff	if (rc) {
2909162922Sariff		device_printf(sc->dev, "can't alloc bdl\n");
2910162922Sariff		return (rc);
2911162922Sariff	}
2912162922Sariff
2913162922Sariff	return (0);
2914162922Sariff}
2915162922Sariff
2916162922Sariffstatic void
2917162922Sariffhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid,
2918162922Sariff					int index, int lmute, int rmute,
2919162922Sariff					int left, int right, int dir)
2920162922Sariff{
2921162922Sariff	uint16_t v = 0;
2922162922Sariff
2923162922Sariff	if (sc == NULL)
2924162922Sariff		return;
2925162922Sariff
2926162922Sariff	if (left != right || lmute != rmute) {
2927162922Sariff		v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
2928162922Sariff		    (lmute << 7) | left;
2929162922Sariff		hdac_command(sc,
2930164614Sariff		    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2931162922Sariff		v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
2932162922Sariff		    (rmute << 7) | right;
2933162922Sariff	} else
2934162922Sariff		v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
2935162922Sariff		    (lmute << 7) | left;
2936162922Sariff
2937162922Sariff	hdac_command(sc,
2938162922Sariff	    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2939162922Sariff}
2940162922Sariff
2941162922Sariffstatic void
2942162922Sariffhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
2943162922Sariff						int left, int right)
2944162922Sariff{
2945162922Sariff	struct hdac_softc *sc;
2946162922Sariff	nid_t nid, cad;
2947162922Sariff	int lmute, rmute;
2948162922Sariff
2949162922Sariff	sc = ctl->widget->devinfo->codec->sc;
2950162922Sariff	cad = ctl->widget->devinfo->codec->cad;
2951162922Sariff	nid = ctl->widget->nid;
2952162922Sariff
2953182999Smav	/* Save new values if valid. */
2954182999Smav	if (mute != HDA_AMP_MUTE_DEFAULT)
2955182999Smav		ctl->muted = mute;
2956182999Smav	if (left != HDA_AMP_VOL_DEFAULT)
2957182999Smav		ctl->left = left;
2958182999Smav	if (right != HDA_AMP_VOL_DEFAULT)
2959182999Smav		ctl->right = right;
2960182999Smav	/* Prepare effective values */
2961182999Smav	if (ctl->forcemute) {
2962182999Smav		lmute = 1;
2963182999Smav		rmute = 1;
2964182999Smav		left = 0;
2965182999Smav		right = 0;
2966182999Smav	} else {
2967162922Sariff		lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
2968162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
2969182999Smav		left = ctl->left;
2970182999Smav		right = ctl->right;
2971162922Sariff	}
2972182999Smav	/* Apply effective values */
2973162922Sariff	if (ctl->dir & HDA_CTL_OUT)
2974162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2975162922Sariff		    lmute, rmute, left, right, 0);
2976162922Sariff	if (ctl->dir & HDA_CTL_IN)
2977182999Smav    		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2978162922Sariff		    lmute, rmute, left, right, 1);
2979162922Sariff}
2980162922Sariff
2981162922Sariffstatic void
2982162922Sariffhdac_widget_connection_select(struct hdac_widget *w, uint8_t index)
2983162922Sariff{
2984162922Sariff	if (w == NULL || w->nconns < 1 || index > (w->nconns - 1))
2985162922Sariff		return;
2986162922Sariff	hdac_command(w->devinfo->codec->sc,
2987162922Sariff	    HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad,
2988162922Sariff	    w->nid, index), w->devinfo->codec->cad);
2989162922Sariff	w->selconn = index;
2990162922Sariff}
2991162922Sariff
2992162922Sariff
2993162922Sariff/****************************************************************************
2994162922Sariff * uint32_t hdac_command_sendone_internal
2995162922Sariff *
2996162922Sariff * Wrapper function that sends only one command to a given codec
2997162922Sariff ****************************************************************************/
2998162922Sariffstatic uint32_t
2999162922Sariffhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad)
3000162922Sariff{
3001162922Sariff	struct hdac_command_list cl;
3002162965Sariff	uint32_t response = HDAC_INVALID;
3003162922Sariff
3004163057Sariff	if (!hdac_lockowned(sc))
3005162922Sariff		device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n");
3006162922Sariff	cl.num_commands = 1;
3007162922Sariff	cl.verbs = &verb;
3008162922Sariff	cl.responses = &response;
3009162922Sariff
3010162922Sariff	hdac_command_send_internal(sc, &cl, cad);
3011162922Sariff
3012162922Sariff	return (response);
3013162922Sariff}
3014162922Sariff
3015162922Sariff/****************************************************************************
3016162922Sariff * hdac_command_send_internal
3017162922Sariff *
3018162922Sariff * Send a command list to the codec via the corb. We queue as much verbs as
3019162922Sariff * we can and msleep on the codec. When the interrupt get the responses
3020162922Sariff * back from the rirb, it will wake us up so we can queue the remaining verbs
3021162922Sariff * if any.
3022162922Sariff ****************************************************************************/
3023162922Sariffstatic void
3024162922Sariffhdac_command_send_internal(struct hdac_softc *sc,
3025162922Sariff			struct hdac_command_list *commands, nid_t cad)
3026162922Sariff{
3027162922Sariff	struct hdac_codec *codec;
3028162922Sariff	int corbrp;
3029162922Sariff	uint32_t *corb;
3030162922Sariff	int timeout;
3031162922Sariff	int retry = 10;
3032164614Sariff	struct hdac_rirb *rirb_base;
3033162922Sariff
3034164614Sariff	if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL ||
3035164614Sariff	    commands->num_commands < 1)
3036162922Sariff		return;
3037162922Sariff
3038162922Sariff	codec = sc->codecs[cad];
3039162922Sariff	codec->commands = commands;
3040162922Sariff	codec->responses_received = 0;
3041162922Sariff	codec->verbs_sent = 0;
3042162922Sariff	corb = (uint32_t *)sc->corb_dma.dma_vaddr;
3043162922Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
3044162922Sariff
3045162922Sariff	do {
3046162922Sariff		if (codec->verbs_sent != commands->num_commands) {
3047162922Sariff			/* Queue as many verbs as possible */
3048162922Sariff			corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP);
3049169277Sariff#if 0
3050162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
3051162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
3052169277Sariff#endif
3053162922Sariff			while (codec->verbs_sent != commands->num_commands &&
3054162922Sariff			    ((sc->corb_wp + 1) % sc->corb_size) != corbrp) {
3055162922Sariff				sc->corb_wp++;
3056162922Sariff				sc->corb_wp %= sc->corb_size;
3057162922Sariff				corb[sc->corb_wp] =
3058162922Sariff				    commands->verbs[codec->verbs_sent++];
3059162922Sariff			}
3060162922Sariff
3061162922Sariff			/* Send the verbs to the codecs */
3062169277Sariff#if 0
3063162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
3064162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
3065169277Sariff#endif
3066162922Sariff			HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
3067162922Sariff		}
3068162922Sariff
3069162922Sariff		timeout = 1000;
3070164614Sariff		while (hdac_rirb_flush(sc) == 0 && --timeout)
3071162922Sariff			DELAY(10);
3072162922Sariff	} while ((codec->verbs_sent != commands->num_commands ||
3073164614Sariff	    codec->responses_received != commands->num_commands) && --retry);
3074162922Sariff
3075162922Sariff	if (retry == 0)
3076162922Sariff		device_printf(sc->dev,
3077164614Sariff		    "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n",
3078164614Sariff		    __func__, commands->num_commands, codec->verbs_sent,
3079164614Sariff		    codec->responses_received);
3080162922Sariff
3081164614Sariff	codec->commands = NULL;
3082164614Sariff	codec->responses_received = 0;
3083162922Sariff	codec->verbs_sent = 0;
3084162922Sariff
3085164614Sariff	hdac_unsolq_flush(sc);
3086162922Sariff}
3087162922Sariff
3088162922Sariff
3089162922Sariff/****************************************************************************
3090162922Sariff * Device Methods
3091162922Sariff ****************************************************************************/
3092162922Sariff
3093162922Sariff/****************************************************************************
3094162922Sariff * int hdac_probe(device_t)
3095162922Sariff *
3096162922Sariff * Probe for the presence of an hdac. If none is found, check for a generic
3097162922Sariff * match using the subclass of the device.
3098162922Sariff ****************************************************************************/
3099162922Sariffstatic int
3100162922Sariffhdac_probe(device_t dev)
3101162922Sariff{
3102162922Sariff	int i, result;
3103163257Sariff	uint32_t model;
3104163257Sariff	uint16_t class, subclass;
3105162922Sariff	char desc[64];
3106162922Sariff
3107162922Sariff	model = (uint32_t)pci_get_device(dev) << 16;
3108162922Sariff	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
3109162922Sariff	class = pci_get_class(dev);
3110162922Sariff	subclass = pci_get_subclass(dev);
3111162922Sariff
3112162922Sariff	bzero(desc, sizeof(desc));
3113162922Sariff	result = ENXIO;
3114162922Sariff	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
3115162922Sariff		if (hdac_devices[i].model == model) {
3116162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3117162922Sariff		    	result = BUS_PROBE_DEFAULT;
3118162922Sariff			break;
3119162922Sariff		}
3120163257Sariff		if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
3121162922Sariff		    class == PCIC_MULTIMEDIA &&
3122162922Sariff		    subclass == PCIS_MULTIMEDIA_HDA) {
3123162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3124162922Sariff		    	result = BUS_PROBE_GENERIC;
3125162922Sariff			break;
3126162922Sariff		}
3127162922Sariff	}
3128162922Sariff	if (result == ENXIO && class == PCIC_MULTIMEDIA &&
3129162922Sariff	    subclass == PCIS_MULTIMEDIA_HDA) {
3130162922Sariff		strlcpy(desc, "Generic", sizeof(desc));
3131162922Sariff	    	result = BUS_PROBE_GENERIC;
3132162922Sariff	}
3133162922Sariff	if (result != ENXIO) {
3134162922Sariff		strlcat(desc, " High Definition Audio Controller",
3135162922Sariff		    sizeof(desc));
3136162922Sariff		device_set_desc_copy(dev, desc);
3137162922Sariff	}
3138162922Sariff
3139162922Sariff	return (result);
3140162922Sariff}
3141162922Sariff
3142162922Sariffstatic void *
3143162922Sariffhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
3144162922Sariff					struct pcm_channel *c, int dir)
3145162922Sariff{
3146182999Smav	struct hdac_pcm_devinfo *pdevinfo = data;
3147182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3148162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3149162922Sariff	struct hdac_chan *ch;
3150182999Smav	int i, ord = 0, chid;
3151162922Sariff
3152162922Sariff	hdac_lock(sc);
3153182999Smav
3154182999Smav	chid = (dir == PCMDIR_PLAY)?pdevinfo->play:pdevinfo->rec;
3155182999Smav	ch = &sc->chans[chid];
3156182999Smav	for (i = 0; i < sc->num_chans && i < chid; i++) {
3157182999Smav		if (ch->dir == sc->chans[i].dir)
3158182999Smav			ord++;
3159182999Smav	}
3160162922Sariff	if (dir == PCMDIR_PLAY) {
3161182999Smav		ch->off = (sc->num_iss + ord) << 5;
3162162922Sariff	} else {
3163182999Smav		ch->off = ord << 5;
3164162922Sariff	}
3165182999Smav
3166162922Sariff	if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
3167162922Sariff		ch->caps.minspeed = ch->caps.maxspeed = 48000;
3168162922Sariff		ch->pcmrates[0] = 48000;
3169162922Sariff		ch->pcmrates[1] = 0;
3170162922Sariff	}
3171169277Sariff	if (sc->pos_dma.dma_vaddr != NULL)
3172169277Sariff		ch->dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr +
3173169277Sariff		    (sc->streamcnt * 8));
3174169277Sariff	else
3175169277Sariff		ch->dmapos = NULL;
3176169277Sariff	ch->sid = ++sc->streamcnt;
3177169277Sariff	ch->dir = dir;
3178162922Sariff	ch->b = b;
3179162922Sariff	ch->c = c;
3180182999Smav	ch->blksz = pdevinfo->chan_size / pdevinfo->chan_blkcnt;
3181182999Smav	ch->blkcnt = pdevinfo->chan_blkcnt;
3182162922Sariff	hdac_unlock(sc);
3183162922Sariff
3184162922Sariff	if (hdac_bdl_alloc(ch) != 0) {
3185162922Sariff		ch->blkcnt = 0;
3186162922Sariff		return (NULL);
3187162922Sariff	}
3188162922Sariff
3189169277Sariff	if (sndbuf_alloc(ch->b, sc->chan_dmat,
3190171330Sariff	    (sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0,
3191182999Smav	    pdevinfo->chan_size) != 0)
3192162922Sariff		return (NULL);
3193162922Sariff
3194162922Sariff	return (ch);
3195162922Sariff}
3196162922Sariff
3197162922Sariffstatic int
3198162922Sariffhdac_channel_setformat(kobj_t obj, void *data, uint32_t format)
3199162922Sariff{
3200162922Sariff	struct hdac_chan *ch = data;
3201162922Sariff	int i;
3202162922Sariff
3203162922Sariff	for (i = 0; ch->caps.fmtlist[i] != 0; i++) {
3204162922Sariff		if (format == ch->caps.fmtlist[i]) {
3205162922Sariff			ch->fmt = format;
3206162922Sariff			return (0);
3207162922Sariff		}
3208162922Sariff	}
3209162922Sariff
3210162922Sariff	return (EINVAL);
3211162922Sariff}
3212162922Sariff
3213162922Sariffstatic int
3214162922Sariffhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed)
3215162922Sariff{
3216162922Sariff	struct hdac_chan *ch = data;
3217164614Sariff	uint32_t spd = 0, threshold;
3218162922Sariff	int i;
3219162922Sariff
3220162922Sariff	for (i = 0; ch->pcmrates[i] != 0; i++) {
3221162922Sariff		spd = ch->pcmrates[i];
3222164614Sariff		threshold = spd + ((ch->pcmrates[i + 1] != 0) ?
3223164614Sariff		    ((ch->pcmrates[i + 1] - spd) >> 1) : 0);
3224164614Sariff		if (speed < threshold)
3225162922Sariff			break;
3226162922Sariff	}
3227162922Sariff
3228164614Sariff	if (spd == 0)	/* impossible */
3229162922Sariff		ch->spd = 48000;
3230162922Sariff	else
3231162922Sariff		ch->spd = spd;
3232162922Sariff
3233162922Sariff	return (ch->spd);
3234162922Sariff}
3235162922Sariff
3236162922Sariffstatic void
3237162922Sariffhdac_stream_setup(struct hdac_chan *ch)
3238162922Sariff{
3239162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3240182999Smav	struct hdac_audio_as *as = &ch->devinfo->function.audio.as[ch->as];
3241173817Sariff	struct hdac_widget *w;
3242182999Smav	int i, chn, totalchn, c;
3243162922Sariff	nid_t cad = ch->devinfo->codec->cad;
3244182999Smav	uint16_t fmt, dfmt;
3245162922Sariff
3246183097Smav	HDA_BOOTHVERBOSE(
3247182999Smav		device_printf(ch->pdevinfo->dev,
3248182999Smav		    "PCMDIR_%s: Stream setup fmt=%08x speed=%d\n",
3249182999Smav		    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3250182999Smav		    ch->fmt, ch->spd);
3251182999Smav	);
3252162922Sariff	fmt = 0;
3253162922Sariff	if (ch->fmt & AFMT_S16_LE)
3254162922Sariff		fmt |= ch->bit16 << 4;
3255162922Sariff	else if (ch->fmt & AFMT_S32_LE)
3256162922Sariff		fmt |= ch->bit32 << 4;
3257162922Sariff	else
3258162922Sariff		fmt |= 1 << 4;
3259162922Sariff
3260162922Sariff	for (i = 0; i < HDA_RATE_TAB_LEN; i++) {
3261162922Sariff		if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) {
3262162922Sariff			fmt |= hda_rate_tab[i].base;
3263162922Sariff			fmt |= hda_rate_tab[i].mul;
3264162922Sariff			fmt |= hda_rate_tab[i].div;
3265162922Sariff			break;
3266162922Sariff		}
3267162922Sariff	}
3268162922Sariff
3269182999Smav	if (ch->fmt & (AFMT_STEREO | AFMT_AC3)) {
3270162922Sariff		fmt |= 1;
3271173817Sariff		totalchn = 2;
3272173817Sariff	} else
3273173817Sariff		totalchn = 1;
3274162922Sariff
3275162922Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
3276182999Smav
3277182999Smav	dfmt = HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN;
3278182999Smav	if (ch->fmt & AFMT_AC3)
3279182999Smav		dfmt |= HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO;
3280162922Sariff
3281173817Sariff	chn = 0;
3282162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
3283173817Sariff		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3284173817Sariff		if (w == NULL)
3285173817Sariff			continue;
3286182999Smav
3287182999Smav		if (as->hpredir >= 0 && i == as->pincnt)
3288182999Smav			chn = 0;
3289183097Smav		HDA_BOOTHVERBOSE(
3290182999Smav			device_printf(ch->pdevinfo->dev,
3291182999Smav			    "PCMDIR_%s: Stream setup nid=%d: "
3292182999Smav			    "fmt=0x%04x, dfmt=0x%04x\n",
3293162922Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3294182999Smav			    ch->io[i], fmt, dfmt);
3295162922Sariff		);
3296162922Sariff		hdac_command(sc,
3297162922Sariff		    HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
3298182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
3299174025Sariff			hdac_command(sc,
3300182999Smav			    HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], dfmt),
3301174025Sariff			    cad);
3302182999Smav		}
3303182999Smav		/* If HP redirection is enabled, but failed to use same
3304182999Smav		   DAC make last DAC one to duplicate first one. */
3305182999Smav		if (as->hpredir >= 0 && i == as->pincnt) {
3306182999Smav			c = (ch->sid << 4);
3307182999Smav		} else if (chn >= totalchn) {
3308182999Smav			/* This is until OSS will support multichannel.
3309182999Smav			   Should be: c = 0; to disable unused DAC */
3310182999Smav			c = (ch->sid << 4);
3311182999Smav		}else {
3312182999Smav			c = (ch->sid << 4) | chn;
3313182999Smav		}
3314182999Smav		hdac_command(sc,
3315182999Smav		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], c), cad);
3316173817Sariff		chn +=
3317173817Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap) ?
3318173817Sariff		    2 : 1;
3319162922Sariff	}
3320162922Sariff}
3321162922Sariff
3322162922Sariffstatic int
3323167648Sariffhdac_channel_setfragments(kobj_t obj, void *data,
3324167648Sariff					uint32_t blksz, uint32_t blkcnt)
3325162922Sariff{
3326162922Sariff	struct hdac_chan *ch = data;
3327164614Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3328162922Sariff
3329167648Sariff	blksz &= HDA_BLK_ALIGN;
3330162922Sariff
3331167648Sariff	if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN))
3332167648Sariff		blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN;
3333167648Sariff	if (blksz < HDA_BLK_MIN)
3334167648Sariff		blksz = HDA_BLK_MIN;
3335167648Sariff	if (blkcnt > HDA_BDL_MAX)
3336167648Sariff		blkcnt = HDA_BDL_MAX;
3337167648Sariff	if (blkcnt < HDA_BDL_MIN)
3338167648Sariff		blkcnt = HDA_BDL_MIN;
3339164614Sariff
3340167648Sariff	while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) {
3341167648Sariff		if ((blkcnt >> 1) >= HDA_BDL_MIN)
3342167648Sariff			blkcnt >>= 1;
3343167648Sariff		else if ((blksz >> 1) >= HDA_BLK_MIN)
3344167648Sariff			blksz >>= 1;
3345167648Sariff		else
3346167648Sariff			break;
3347167648Sariff	}
3348167648Sariff
3349164614Sariff	if ((sndbuf_getblksz(ch->b) != blksz ||
3350167648Sariff	    sndbuf_getblkcnt(ch->b) != blkcnt) &&
3351167648Sariff	    sndbuf_resize(ch->b, blkcnt, blksz) != 0)
3352164614Sariff		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
3353167648Sariff		    __func__, blksz, blkcnt);
3354164614Sariff
3355164614Sariff	ch->blksz = sndbuf_getblksz(ch->b);
3356167648Sariff	ch->blkcnt = sndbuf_getblkcnt(ch->b);
3357164614Sariff
3358167648Sariff	return (1);
3359167648Sariff}
3360167648Sariff
3361167648Sariffstatic int
3362167648Sariffhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
3363167648Sariff{
3364167648Sariff	struct hdac_chan *ch = data;
3365167648Sariff
3366182999Smav	hdac_channel_setfragments(obj, data, blksz, ch->pdevinfo->chan_blkcnt);
3367167648Sariff
3368162922Sariff	return (ch->blksz);
3369162922Sariff}
3370162922Sariff
3371162922Sariffstatic void
3372162922Sariffhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
3373162922Sariff{
3374162922Sariff	struct hdac_devinfo *devinfo = ch->devinfo;
3375182999Smav	struct hdac_widget *w;
3376162922Sariff	nid_t cad = devinfo->codec->cad;
3377162922Sariff	int i;
3378162922Sariff
3379162922Sariff	hdac_stream_stop(ch);
3380162922Sariff
3381162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
3382182999Smav		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3383182999Smav		if (w == NULL)
3384182999Smav			continue;
3385182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
3386182999Smav			hdac_command(sc,
3387182999Smav			    HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], 0),
3388182999Smav			    cad);
3389182999Smav		}
3390162922Sariff		hdac_command(sc,
3391162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
3392162922Sariff		    0), cad);
3393162922Sariff	}
3394162922Sariff}
3395162922Sariff
3396162922Sariffstatic void
3397162922Sariffhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch)
3398162922Sariff{
3399162922Sariff	ch->ptr = 0;
3400162922Sariff	ch->prevptr = 0;
3401162922Sariff	hdac_stream_stop(ch);
3402162922Sariff	hdac_stream_reset(ch);
3403162922Sariff	hdac_bdl_setup(ch);
3404162922Sariff	hdac_stream_setid(ch);
3405162922Sariff	hdac_stream_setup(ch);
3406162922Sariff	hdac_stream_start(ch);
3407162922Sariff}
3408162922Sariff
3409162922Sariffstatic int
3410162922Sariffhdac_channel_trigger(kobj_t obj, void *data, int go)
3411162922Sariff{
3412162922Sariff	struct hdac_chan *ch = data;
3413162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3414162922Sariff
3415170521Sariff	if (!PCMTRIG_COMMON(go))
3416170521Sariff		return (0);
3417170521Sariff
3418162922Sariff	hdac_lock(sc);
3419162922Sariff	switch (go) {
3420162922Sariff	case PCMTRIG_START:
3421162922Sariff		hdac_channel_start(sc, ch);
3422162922Sariff		break;
3423162922Sariff	case PCMTRIG_STOP:
3424162922Sariff	case PCMTRIG_ABORT:
3425162922Sariff		hdac_channel_stop(sc, ch);
3426162922Sariff		break;
3427167610Sariff	default:
3428167610Sariff		break;
3429162922Sariff	}
3430162922Sariff	hdac_unlock(sc);
3431162922Sariff
3432162922Sariff	return (0);
3433162922Sariff}
3434162922Sariff
3435162922Sariffstatic int
3436162922Sariffhdac_channel_getptr(kobj_t obj, void *data)
3437162922Sariff{
3438162922Sariff	struct hdac_chan *ch = data;
3439162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3440162922Sariff	uint32_t ptr;
3441162922Sariff
3442162922Sariff	hdac_lock(sc);
3443164614Sariff	if (sc->polling != 0)
3444164614Sariff		ptr = ch->ptr;
3445169277Sariff	else if (ch->dmapos != NULL)
3446169277Sariff		ptr = *(ch->dmapos);
3447164614Sariff	else
3448164614Sariff		ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB);
3449162922Sariff	hdac_unlock(sc);
3450162922Sariff
3451164614Sariff	/*
3452164614Sariff	 * Round to available space and force 128 bytes aligment.
3453164614Sariff	 */
3454164614Sariff	ptr %= ch->blksz * ch->blkcnt;
3455167648Sariff	ptr &= HDA_BLK_ALIGN;
3456162922Sariff
3457162922Sariff	return (ptr);
3458162922Sariff}
3459162922Sariff
3460162922Sariffstatic struct pcmchan_caps *
3461162922Sariffhdac_channel_getcaps(kobj_t obj, void *data)
3462162922Sariff{
3463162922Sariff	return (&((struct hdac_chan *)data)->caps);
3464162922Sariff}
3465162922Sariff
3466162922Sariffstatic kobj_method_t hdac_channel_methods[] = {
3467162922Sariff	KOBJMETHOD(channel_init,		hdac_channel_init),
3468162922Sariff	KOBJMETHOD(channel_setformat,		hdac_channel_setformat),
3469162922Sariff	KOBJMETHOD(channel_setspeed,		hdac_channel_setspeed),
3470162922Sariff	KOBJMETHOD(channel_setblocksize,	hdac_channel_setblocksize),
3471167648Sariff	KOBJMETHOD(channel_setfragments,	hdac_channel_setfragments),
3472162922Sariff	KOBJMETHOD(channel_trigger,		hdac_channel_trigger),
3473162922Sariff	KOBJMETHOD(channel_getptr,		hdac_channel_getptr),
3474162922Sariff	KOBJMETHOD(channel_getcaps,		hdac_channel_getcaps),
3475162922Sariff	{ 0, 0 }
3476162922Sariff};
3477162922SariffCHANNEL_DECLARE(hdac_channel);
3478162922Sariff
3479162922Sariffstatic int
3480162922Sariffhdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
3481162922Sariff{
3482182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3483182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3484162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3485162922Sariff	struct hdac_widget *w, *cw;
3486162922Sariff	struct hdac_audio_ctl *ctl;
3487162922Sariff	uint32_t mask, recmask, id;
3488162922Sariff	int i, j, softpcmvol;
3489162922Sariff
3490162922Sariff	hdac_lock(sc);
3491162922Sariff
3492182999Smav	/* Make sure that in case of soft volume it won't stay muted. */
3493182999Smav	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
3494182999Smav		pdevinfo->left[i] = 100;
3495182999Smav		pdevinfo->right[i] = 100;
3496182999Smav	}
3497182999Smav
3498162922Sariff	mask = 0;
3499162922Sariff	recmask = 0;
3500182999Smav	id = hdac_codec_id(devinfo->codec);
3501162922Sariff
3502182999Smav	/* Declate EAPD as ogain control. */
3503182999Smav	if (pdevinfo->play >= 0) {
3504182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3505182999Smav			w = hdac_widget_get(devinfo, i);
3506182999Smav			if (w == NULL || w->enable == 0)
3507182999Smav				continue;
3508182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3509182999Smav			    w->param.eapdbtl == HDAC_INVALID ||
3510182999Smav			    w->bindas != sc->chans[pdevinfo->play].as)
3511182999Smav				continue;
3512182999Smav			mask |= SOUND_MASK_OGAIN;
3513162922Sariff			break;
3514162922Sariff		}
3515162922Sariff	}
3516162922Sariff
3517182999Smav	/* Declare volume controls assigned to this association. */
3518162922Sariff	i = 0;
3519162922Sariff	ctl = NULL;
3520162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3521182999Smav		if (ctl->enable == 0)
3522162922Sariff			continue;
3523182999Smav		if ((pdevinfo->play >= 0 &&
3524182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
3525182999Smav		    (pdevinfo->rec >= 0 &&
3526182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
3527182999Smav		    (ctl->widget->bindas == -2 && pdevinfo->index == 0))
3528182999Smav			mask |= ctl->ossmask;
3529162922Sariff	}
3530162922Sariff
3531182999Smav	/* Declare record sources available to this association. */
3532182999Smav	if (pdevinfo->rec >= 0) {
3533182999Smav		struct hdac_chan *ch = &sc->chans[pdevinfo->rec];
3534182999Smav		for (i = 0; ch->io[i] != -1; i++) {
3535182999Smav			w = hdac_widget_get(devinfo, ch->io[i]);
3536182999Smav			if (w == NULL || w->enable == 0)
3537182999Smav				continue;
3538182999Smav			for (j = 0; j < w->nconns; j++) {
3539182999Smav				if (w->connsenable[j] == 0)
3540162922Sariff					continue;
3541182999Smav				cw = hdac_widget_get(devinfo, w->conns[j]);
3542182999Smav				if (cw == NULL || cw->enable == 0)
3543165992Sariff					continue;
3544182999Smav				if (cw->bindas != sc->chans[pdevinfo->rec].as &&
3545182999Smav				    cw->bindas != -2)
3546165992Sariff					continue;
3547182999Smav				recmask |= cw->ossmask;
3548165992Sariff			}
3549182999Smav		}
3550182999Smav	}
3551182999Smav
3552182999Smav	/* Declare soft PCM and master volume if needed. */
3553182999Smav	if (pdevinfo->play >= 0) {
3554182999Smav		ctl = NULL;
3555182999Smav		if ((mask & SOUND_MASK_PCM) == 0 ||
3556182999Smav		    (devinfo->function.audio.quirks & HDA_QUIRK_SOFTPCMVOL)) {
3557182999Smav			softpcmvol = 1;
3558182999Smav			mask |= SOUND_MASK_PCM;
3559162922Sariff		} else {
3560182999Smav			softpcmvol = 0;
3561182999Smav			i = 0;
3562182999Smav			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3563182999Smav				if (ctl->enable == 0)
3564162922Sariff					continue;
3565182999Smav				if (ctl->widget->bindas != sc->chans[pdevinfo->play].as &&
3566182999Smav				    (ctl->widget->bindas != -2 || pdevinfo->index != 0))
3567162922Sariff					continue;
3568182999Smav				if (!(ctl->ossmask & SOUND_MASK_PCM))
3569182999Smav					continue;
3570182999Smav				if (ctl->step > 0)
3571182999Smav					break;
3572162922Sariff			}
3573162922Sariff		}
3574182999Smav
3575182999Smav		if (softpcmvol == 1 || ctl == NULL) {
3576182999Smav			pcm_setflags(pdevinfo->dev, pcm_getflags(pdevinfo->dev) | SD_F_SOFTPCMVOL);
3577182999Smav			HDA_BOOTVERBOSE(
3578182999Smav				device_printf(pdevinfo->dev,
3579182999Smav				    "%s Soft PCM volume\n",
3580182999Smav				    (softpcmvol == 1) ? "Forcing" : "Enabling");
3581182999Smav			);
3582182999Smav		}
3583182999Smav
3584182999Smav		if ((mask & SOUND_MASK_VOLUME) == 0) {
3585182999Smav			mask |= SOUND_MASK_VOLUME;
3586182999Smav			mix_setparentchild(m, SOUND_MIXER_VOLUME,
3587182999Smav			    SOUND_MASK_PCM);
3588182999Smav			mix_setrealdev(m, SOUND_MIXER_VOLUME,
3589182999Smav			    SOUND_MIXER_NONE);
3590182999Smav			HDA_BOOTVERBOSE(
3591182999Smav				device_printf(pdevinfo->dev,
3592182999Smav				    "Forcing master volume with PCM\n");
3593182999Smav			);
3594182999Smav		}
3595162922Sariff	}
3596162922Sariff
3597169277Sariff	recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3598169277Sariff	mask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3599162922Sariff
3600162922Sariff	mix_setrecdevs(m, recmask);
3601162922Sariff	mix_setdevs(m, mask);
3602162922Sariff
3603162922Sariff	hdac_unlock(sc);
3604162922Sariff
3605162922Sariff	return (0);
3606162922Sariff}
3607162922Sariff
3608162922Sariffstatic int
3609162922Sariffhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
3610162922Sariff					unsigned left, unsigned right)
3611162922Sariff{
3612182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3613182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3614162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3615162922Sariff	struct hdac_widget *w;
3616162922Sariff	struct hdac_audio_ctl *ctl;
3617182999Smav	uint32_t mute;
3618182999Smav	int lvol, rvol;
3619182999Smav	int i, j;
3620162922Sariff
3621162922Sariff	hdac_lock(sc);
3622182999Smav	/* Save new values. */
3623182999Smav	pdevinfo->left[dev] = left;
3624182999Smav	pdevinfo->right[dev] = right;
3625182999Smav
3626182999Smav	/* 'ogain' is the special case implemented with EAPD. */
3627162922Sariff	if (dev == SOUND_MIXER_OGAIN) {
3628163257Sariff		uint32_t orig;
3629182999Smav		w = NULL;
3630182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3631182999Smav			w = hdac_widget_get(devinfo, i);
3632182999Smav			if (w == NULL || w->enable == 0)
3633182999Smav				continue;
3634182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3635182999Smav			    w->param.eapdbtl == HDAC_INVALID)
3636182999Smav				continue;
3637182999Smav			break;
3638162922Sariff		}
3639182999Smav		if (i >= devinfo->endnode) {
3640162922Sariff			hdac_unlock(sc);
3641162922Sariff			return (-1);
3642162922Sariff		}
3643163257Sariff		orig = w->param.eapdbtl;
3644163432Sariff		if (left == 0)
3645162922Sariff			w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3646162922Sariff		else
3647162922Sariff			w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3648163257Sariff		if (orig != w->param.eapdbtl) {
3649163432Sariff			uint32_t val;
3650163432Sariff
3651163432Sariff			val = w->param.eapdbtl;
3652163432Sariff			if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV)
3653163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3654163257Sariff			hdac_command(sc,
3655163257Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad,
3656163432Sariff			    w->nid, val), devinfo->codec->cad);
3657163257Sariff		}
3658162922Sariff		hdac_unlock(sc);
3659162922Sariff		return (left | (left << 8));
3660162922Sariff	}
3661162922Sariff
3662182999Smav	/* Recalculate all controls related to this OSS device. */
3663162922Sariff	i = 0;
3664162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3665182999Smav		if (ctl->enable == 0 ||
3666162922Sariff		    !(ctl->ossmask & (1 << dev)))
3667162922Sariff			continue;
3668182999Smav		if (!((pdevinfo->play >= 0 &&
3669182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
3670182999Smav		    (pdevinfo->rec >= 0 &&
3671182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
3672182999Smav		    ctl->widget->bindas == -2))
3673182999Smav			continue;
3674182999Smav
3675182999Smav		lvol = 100;
3676182999Smav		rvol = 100;
3677182999Smav		for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
3678182999Smav			if (ctl->ossmask & (1 << j)) {
3679182999Smav				lvol = lvol * pdevinfo->left[j] / 100;
3680182999Smav				rvol = rvol * pdevinfo->right[j] / 100;
3681162922Sariff			}
3682162922Sariff		}
3683182999Smav		mute = (left == 0) ? HDA_AMP_MUTE_LEFT : 0;
3684182999Smav		mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT : 0;
3685182999Smav		lvol = (lvol * ctl->step + 50) / 100;
3686182999Smav		rvol = (rvol * ctl->step + 50) / 100;
3687162922Sariff		hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
3688162922Sariff	}
3689162922Sariff	hdac_unlock(sc);
3690162922Sariff
3691162922Sariff	return (left | (right << 8));
3692162922Sariff}
3693162922Sariff
3694182999Smav/*
3695182999Smav * Commutate specified record source.
3696182999Smav */
3697182999Smavstatic uint32_t
3698182999Smavhdac_audio_ctl_recsel_comm(struct hdac_pcm_devinfo *pdevinfo, uint32_t src, nid_t nid, int depth)
3699162922Sariff{
3700182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3701162922Sariff	struct hdac_widget *w, *cw;
3702182999Smav	struct hdac_audio_ctl *ctl;
3703182999Smav	char buf[64];
3704182999Smav	int i, muted;
3705182999Smav	uint32_t res = 0;
3706162922Sariff
3707182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
3708182999Smav		return (0);
3709182999Smav
3710182999Smav	w = hdac_widget_get(devinfo, nid);
3711182999Smav	if (w == NULL || w->enable == 0)
3712182999Smav		return (0);
3713182999Smav
3714182999Smav	for (i = 0; i < w->nconns; i++) {
3715182999Smav		if (w->connsenable[i] == 0)
3716182999Smav			continue;
3717182999Smav		cw = hdac_widget_get(devinfo, w->conns[i]);
3718182999Smav		if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
3719182999Smav			continue;
3720182999Smav		/* Call recursively to trace signal to it's source if needed. */
3721182999Smav		if ((src & cw->ossmask) != 0) {
3722182999Smav			if (cw->ossdev < 0) {
3723182999Smav				res |= hdac_audio_ctl_recsel_comm(pdevinfo, src,
3724182999Smav				    w->conns[i], depth + 1);
3725182999Smav			} else {
3726182999Smav				res |= cw->ossmask;
3727182999Smav			}
3728182999Smav		}
3729182999Smav		/* We have two special cases: mixers and others (selectors). */
3730182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
3731182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
3732182999Smav			    w->nid, HDA_CTL_IN, i, 1);
3733182999Smav			if (ctl == NULL)
3734182999Smav				continue;
3735182999Smav			/* If we have input control on this node mute them
3736182999Smav			 * according to requested sources. */
3737182999Smav			muted = (src & cw->ossmask) ? 0 : 1;
3738182999Smav	    		if (muted != ctl->forcemute) {
3739182999Smav				ctl->forcemute = muted;
3740182999Smav				hdac_audio_ctl_amp_set(ctl,
3741182999Smav				    HDA_AMP_MUTE_DEFAULT,
3742182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
3743182999Smav			}
3744183097Smav			HDA_BOOTHVERBOSE(
3745182999Smav				device_printf(pdevinfo->dev,
3746182999Smav				    "Recsel (%s): nid %d source %d %s\n",
3747182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(
3748182999Smav				    src, buf, sizeof(buf)),
3749182999Smav				    nid, i, muted?"mute":"unmute");
3750182999Smav			);
3751182999Smav		} else {
3752182999Smav			if (w->nconns == 1)
3753182999Smav				break;
3754182999Smav			if ((src & cw->ossmask) == 0)
3755182999Smav				continue;
3756182999Smav			/* If we found requested source - select it and exit. */
3757182999Smav			hdac_widget_connection_select(w, i);
3758183097Smav			HDA_BOOTHVERBOSE(
3759182999Smav				device_printf(pdevinfo->dev,
3760182999Smav				    "Recsel (%s): nid %d source %d select\n",
3761182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(
3762182999Smav			    	    src, buf, sizeof(buf)),
3763182999Smav				    nid, i);
3764182999Smav			);
3765162922Sariff			break;
3766162922Sariff		}
3767162922Sariff	}
3768182999Smav	return (res);
3769182999Smav}
3770162922Sariff
3771182999Smavstatic uint32_t
3772182999Smavhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
3773182999Smav{
3774182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3775182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3776182999Smav	struct hdac_widget *w;
3777182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
3778182999Smav	struct hdac_chan *ch;
3779182999Smav	int i;
3780182999Smav	uint32_t ret = 0xffffffff;
3781182999Smav
3782162922Sariff	hdac_lock(sc);
3783162922Sariff
3784182999Smav	/* Commutate requested recsrc for each ADC. */
3785182999Smav	ch = &sc->chans[pdevinfo->rec];
3786182999Smav	for (i = 0; ch->io[i] != -1; i++) {
3787182999Smav		w = hdac_widget_get(devinfo, ch->io[i]);
3788162965Sariff		if (w == NULL || w->enable == 0)
3789162922Sariff			continue;
3790182999Smav		ret &= hdac_audio_ctl_recsel_comm(pdevinfo, src, ch->io[i], 0);
3791162922Sariff	}
3792162922Sariff
3793162922Sariff	hdac_unlock(sc);
3794162922Sariff
3795182999Smav	return ((ret == 0xffffffff)? 0 : ret);
3796162922Sariff}
3797162922Sariff
3798162922Sariffstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
3799162922Sariff	KOBJMETHOD(mixer_init,		hdac_audio_ctl_ossmixer_init),
3800162922Sariff	KOBJMETHOD(mixer_set,		hdac_audio_ctl_ossmixer_set),
3801162922Sariff	KOBJMETHOD(mixer_setrecsrc,	hdac_audio_ctl_ossmixer_setrecsrc),
3802162922Sariff	{ 0, 0 }
3803162922Sariff};
3804162922SariffMIXER_DECLARE(hdac_audio_ctl_ossmixer);
3805162922Sariff
3806171141Sariffstatic void
3807171141Sariffhdac_unsolq_task(void *context, int pending)
3808171141Sariff{
3809171141Sariff	struct hdac_softc *sc;
3810171141Sariff
3811171141Sariff	sc = (struct hdac_softc *)context;
3812171141Sariff
3813171141Sariff	hdac_lock(sc);
3814171141Sariff	hdac_unsolq_flush(sc);
3815171141Sariff	hdac_unlock(sc);
3816171141Sariff}
3817171141Sariff
3818162922Sariff/****************************************************************************
3819162922Sariff * int hdac_attach(device_t)
3820162922Sariff *
3821162922Sariff * Attach the device into the kernel. Interrupts usually won't be enabled
3822162922Sariff * when this function is called. Setup everything that doesn't require
3823162922Sariff * interrupts and defer probing of codecs until interrupts are enabled.
3824162922Sariff ****************************************************************************/
3825162922Sariffstatic int
3826162922Sariffhdac_attach(device_t dev)
3827162922Sariff{
3828162922Sariff	struct hdac_softc *sc;
3829162922Sariff	int result;
3830169277Sariff	int i;
3831169277Sariff	uint16_t vendor;
3832169277Sariff	uint8_t v;
3833162922Sariff
3834184089Smav	device_printf(dev, "HDA Driver Revision: %s\n", HDA_DRV_TEST_REV);
3835182999Smav
3836182999Smav	sc = device_get_softc(dev);
3837163057Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
3838162922Sariff	sc->dev = dev;
3839163257Sariff	sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
3840163257Sariff	sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff;
3841169277Sariff	vendor = pci_get_vendor(dev);
3842162922Sariff
3843165281Sariff	if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) {
3844165281Sariff		/* Screw nx6325 - subdevice/subvendor swapped */
3845165281Sariff		sc->pci_subvendor = HP_NX6325_SUBVENDOR;
3846165281Sariff	}
3847165281Sariff
3848164614Sariff	callout_init(&sc->poll_hda, CALLOUT_MPSAFE);
3849164614Sariff	callout_init(&sc->poll_hdac, CALLOUT_MPSAFE);
3850169277Sariff	callout_init(&sc->poll_jack, CALLOUT_MPSAFE);
3851164614Sariff
3852171141Sariff	TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc);
3853171141Sariff
3854182999Smav	sc->poll_ticks = 1000000;
3855169277Sariff	sc->poll_ival = HDAC_POLL_INTERVAL;
3856169277Sariff	if (resource_int_value(device_get_name(dev),
3857169277Sariff	    device_get_unit(dev), "polling", &i) == 0 && i != 0)
3858164614Sariff		sc->polling = 1;
3859164614Sariff	else
3860164614Sariff		sc->polling = 0;
3861164614Sariff
3862162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
3863162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
3864162922Sariff	    0,					/* boundary */
3865162922Sariff	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
3866162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
3867162922Sariff	    NULL,				/* filtfunc */
3868162922Sariff	    NULL,				/* fistfuncarg */
3869182999Smav	    HDA_BUFSZ_MAX, 			/* maxsize */
3870162922Sariff	    1,					/* nsegments */
3871182999Smav	    HDA_BUFSZ_MAX, 			/* maxsegsz */
3872162922Sariff	    0,					/* flags */
3873162922Sariff	    NULL,				/* lockfunc */
3874162922Sariff	    NULL,				/* lockfuncarg */
3875162922Sariff	    &sc->chan_dmat);			/* dmat */
3876162922Sariff	if (result != 0) {
3877169277Sariff		device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n",
3878162922Sariff		     __func__, result);
3879163057Sariff		snd_mtxfree(sc->lock);
3880162922Sariff		free(sc, M_DEVBUF);
3881162922Sariff		return (ENXIO);
3882162922Sariff	}
3883162922Sariff
3884162922Sariff
3885162922Sariff	sc->hdabus = NULL;
3886162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++)
3887162922Sariff		sc->codecs[i] = NULL;
3888162922Sariff
3889162922Sariff	pci_enable_busmaster(dev);
3890162922Sariff
3891169277Sariff	if (vendor == INTEL_VENDORID) {
3892169277Sariff		/* TCSEL -> TC0 */
3893169277Sariff		v = pci_read_config(dev, 0x44, 1);
3894169277Sariff		pci_write_config(dev, 0x44, v & 0xf8, 1);
3895183097Smav		HDA_BOOTHVERBOSE(
3896169277Sariff			device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v,
3897169277Sariff			    pci_read_config(dev, 0x44, 1));
3898169277Sariff		);
3899169277Sariff	}
3900169277Sariff
3901178155Sariff#ifdef HDAC_MSI_ENABLED
3902171330Sariff	if (resource_int_value(device_get_name(dev),
3903171330Sariff	    device_get_unit(dev), "msi", &i) == 0 && i != 0 &&
3904171330Sariff	    pci_msi_count(dev) == 1)
3905171330Sariff		sc->flags |= HDAC_F_MSI;
3906171330Sariff	else
3907171330Sariff#endif
3908171330Sariff		sc->flags &= ~HDAC_F_MSI;
3909171330Sariff
3910169277Sariff#if defined(__i386__) || defined(__amd64__)
3911171330Sariff	sc->flags |= HDAC_F_DMA_NOCACHE;
3912169277Sariff
3913169277Sariff	if (resource_int_value(device_get_name(dev),
3914169277Sariff	    device_get_unit(dev), "snoop", &i) == 0 && i != 0) {
3915169277Sariff#else
3916171330Sariff	sc->flags &= ~HDAC_F_DMA_NOCACHE;
3917169277Sariff#endif
3918169277Sariff		/*
3919169277Sariff		 * Try to enable PCIe snoop to avoid messing around with
3920169277Sariff		 * uncacheable DMA attribute. Since PCIe snoop register
3921169277Sariff		 * config is pretty much vendor specific, there are no
3922169277Sariff		 * general solutions on how to enable it, forcing us (even
3923169277Sariff		 * Microsoft) to enable uncacheable or write combined DMA
3924169277Sariff		 * by default.
3925169277Sariff		 *
3926169277Sariff		 * http://msdn2.microsoft.com/en-us/library/ms790324.aspx
3927169277Sariff		 */
3928169277Sariff		for (i = 0; i < HDAC_PCIESNOOP_LEN; i++) {
3929169277Sariff			if (hdac_pcie_snoop[i].vendor != vendor)
3930169277Sariff				continue;
3931171330Sariff			sc->flags &= ~HDAC_F_DMA_NOCACHE;
3932169277Sariff			if (hdac_pcie_snoop[i].reg == 0x00)
3933169277Sariff				break;
3934169277Sariff			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
3935169277Sariff			if ((v & hdac_pcie_snoop[i].enable) ==
3936169277Sariff			    hdac_pcie_snoop[i].enable)
3937169277Sariff				break;
3938169277Sariff			v &= hdac_pcie_snoop[i].mask;
3939169277Sariff			v |= hdac_pcie_snoop[i].enable;
3940169277Sariff			pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1);
3941169277Sariff			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
3942169277Sariff			if ((v & hdac_pcie_snoop[i].enable) !=
3943169277Sariff			    hdac_pcie_snoop[i].enable) {
3944169277Sariff				HDA_BOOTVERBOSE(
3945169277Sariff					device_printf(dev,
3946169277Sariff					    "WARNING: Failed to enable PCIe "
3947169277Sariff					    "snoop!\n");
3948169277Sariff				);
3949169277Sariff#if defined(__i386__) || defined(__amd64__)
3950171330Sariff				sc->flags |= HDAC_F_DMA_NOCACHE;
3951169277Sariff#endif
3952169277Sariff			}
3953169277Sariff			break;
3954169277Sariff		}
3955169277Sariff#if defined(__i386__) || defined(__amd64__)
3956169277Sariff	}
3957169277Sariff#endif
3958169277Sariff
3959183097Smav	HDA_BOOTHVERBOSE(
3960169277Sariff		device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n",
3961171330Sariff		    (sc->flags & HDAC_F_DMA_NOCACHE) ?
3962171330Sariff		    "Uncacheable" : "PCIe snoop", vendor);
3963169277Sariff	);
3964169277Sariff
3965162922Sariff	/* Allocate resources */
3966162922Sariff	result = hdac_mem_alloc(sc);
3967162922Sariff	if (result != 0)
3968163057Sariff		goto hdac_attach_fail;
3969162922Sariff	result = hdac_irq_alloc(sc);
3970162922Sariff	if (result != 0)
3971163057Sariff		goto hdac_attach_fail;
3972162922Sariff
3973162922Sariff	/* Get Capabilities */
3974162922Sariff	result = hdac_get_capabilities(sc);
3975162922Sariff	if (result != 0)
3976163057Sariff		goto hdac_attach_fail;
3977162922Sariff
3978162922Sariff	/* Allocate CORB and RIRB dma memory */
3979162922Sariff	result = hdac_dma_alloc(sc, &sc->corb_dma,
3980162922Sariff	    sc->corb_size * sizeof(uint32_t));
3981162922Sariff	if (result != 0)
3982163057Sariff		goto hdac_attach_fail;
3983162922Sariff	result = hdac_dma_alloc(sc, &sc->rirb_dma,
3984162922Sariff	    sc->rirb_size * sizeof(struct hdac_rirb));
3985162922Sariff	if (result != 0)
3986163057Sariff		goto hdac_attach_fail;
3987162922Sariff
3988162922Sariff	/* Quiesce everything */
3989183097Smav	HDA_BOOTHVERBOSE(
3990182999Smav		device_printf(dev, "Reset controller...\n");
3991182999Smav	);
3992182999Smav	hdac_reset(sc, 1);
3993162922Sariff
3994162922Sariff	/* Initialize the CORB and RIRB */
3995162922Sariff	hdac_corb_init(sc);
3996162922Sariff	hdac_rirb_init(sc);
3997162922Sariff
3998162922Sariff	/* Defer remaining of initialization until interrupts are enabled */
3999162922Sariff	sc->intrhook.ich_func = hdac_attach2;
4000162922Sariff	sc->intrhook.ich_arg = (void *)sc;
4001162922Sariff	if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
4002162922Sariff		sc->intrhook.ich_func = NULL;
4003162922Sariff		hdac_attach2((void *)sc);
4004162922Sariff	}
4005162922Sariff
4006163057Sariff	return (0);
4007162922Sariff
4008163057Sariffhdac_attach_fail:
4009162922Sariff	hdac_irq_free(sc);
4010169277Sariff	hdac_dma_free(sc, &sc->rirb_dma);
4011169277Sariff	hdac_dma_free(sc, &sc->corb_dma);
4012162922Sariff	hdac_mem_free(sc);
4013162922Sariff	snd_mtxfree(sc->lock);
4014163057Sariff	free(sc, M_DEVBUF);
4015162922Sariff
4016163057Sariff	return (ENXIO);
4017162922Sariff}
4018162922Sariff
4019162922Sariffstatic void
4020162922Sariffhdac_audio_parse(struct hdac_devinfo *devinfo)
4021162922Sariff{
4022182999Smav	struct hdac_codec *codec = devinfo->codec;
4023182999Smav	struct hdac_softc *sc = codec->sc;
4024162922Sariff	struct hdac_widget *w;
4025162922Sariff	uint32_t res;
4026162922Sariff	int i;
4027162922Sariff	nid_t cad, nid;
4028162922Sariff
4029162922Sariff	cad = devinfo->codec->cad;
4030162922Sariff	nid = devinfo->nid;
4031162922Sariff
4032162922Sariff	res = hdac_command(sc,
4033169277Sariff	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad);
4034169277Sariff	devinfo->function.audio.gpio = res;
4035169277Sariff
4036163057Sariff	HDA_BOOTVERBOSE(
4037183097Smav		device_printf(sc->dev, "GPIO: 0x%08x "
4038183097Smav		    "NumGPIO=%d NumGPO=%d "
4039169277Sariff		    "NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
4040183097Smav		    devinfo->function.audio.gpio,
4041169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
4042169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
4043169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
4044169277Sariff		    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
4045169277Sariff		    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
4046162922Sariff	);
4047162922Sariff
4048162922Sariff	res = hdac_command(sc,
4049162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS),
4050162922Sariff	    cad);
4051162922Sariff	devinfo->function.audio.supp_stream_formats = res;
4052162922Sariff
4053162922Sariff	res = hdac_command(sc,
4054162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE),
4055162922Sariff	    cad);
4056162922Sariff	devinfo->function.audio.supp_pcm_size_rate = res;
4057162922Sariff
4058162922Sariff	res = hdac_command(sc,
4059162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP),
4060162922Sariff	    cad);
4061162922Sariff	devinfo->function.audio.outamp_cap = res;
4062162922Sariff
4063162922Sariff	res = hdac_command(sc,
4064162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP),
4065162922Sariff	    cad);
4066162922Sariff	devinfo->function.audio.inamp_cap = res;
4067162922Sariff
4068162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4069162922Sariff		w = hdac_widget_get(devinfo, i);
4070162922Sariff		if (w == NULL)
4071162922Sariff			device_printf(sc->dev, "Ghost widget! nid=%d!\n", i);
4072162922Sariff		else {
4073162922Sariff			w->devinfo = devinfo;
4074162922Sariff			w->nid = i;
4075162922Sariff			w->enable = 1;
4076162922Sariff			w->selconn = -1;
4077162922Sariff			w->pflags = 0;
4078182999Smav			w->ossdev = -1;
4079182999Smav			w->bindas = -1;
4080162965Sariff			w->param.eapdbtl = HDAC_INVALID;
4081162922Sariff			hdac_widget_parse(w);
4082162922Sariff		}
4083162922Sariff	}
4084162922Sariff}
4085162922Sariff
4086162922Sariffstatic void
4087162922Sariffhdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
4088162922Sariff{
4089162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4090162922Sariff	struct hdac_audio_ctl *ctls;
4091162922Sariff	struct hdac_widget *w, *cw;
4092162922Sariff	int i, j, cnt, max, ocap, icap;
4093163057Sariff	int mute, offset, step, size;
4094162922Sariff
4095162922Sariff	/* XXX This is redundant */
4096162922Sariff	max = 0;
4097162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4098162922Sariff		w = hdac_widget_get(devinfo, i);
4099162922Sariff		if (w == NULL || w->enable == 0)
4100162922Sariff			continue;
4101162922Sariff		if (w->param.outamp_cap != 0)
4102162922Sariff			max++;
4103162922Sariff		if (w->param.inamp_cap != 0) {
4104162922Sariff			switch (w->type) {
4105162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4106162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4107162922Sariff				for (j = 0; j < w->nconns; j++) {
4108162922Sariff					cw = hdac_widget_get(devinfo,
4109162922Sariff					    w->conns[j]);
4110162922Sariff					if (cw == NULL || cw->enable == 0)
4111162922Sariff						continue;
4112162922Sariff					max++;
4113162922Sariff				}
4114162922Sariff				break;
4115162922Sariff			default:
4116162922Sariff				max++;
4117162922Sariff				break;
4118162922Sariff			}
4119162922Sariff		}
4120162922Sariff	}
4121162922Sariff
4122162922Sariff	devinfo->function.audio.ctlcnt = max;
4123162922Sariff
4124162922Sariff	if (max < 1)
4125162922Sariff		return;
4126162922Sariff
4127162922Sariff	ctls = (struct hdac_audio_ctl *)malloc(
4128162922Sariff	    sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT);
4129162922Sariff
4130162922Sariff	if (ctls == NULL) {
4131162922Sariff		/* Blekh! */
4132162922Sariff		device_printf(sc->dev, "unable to allocate ctls!\n");
4133162922Sariff		devinfo->function.audio.ctlcnt = 0;
4134162922Sariff		return;
4135162922Sariff	}
4136162922Sariff
4137162922Sariff	cnt = 0;
4138162922Sariff	for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) {
4139162922Sariff		if (cnt >= max) {
4140162922Sariff			device_printf(sc->dev, "%s: Ctl overflow!\n",
4141162922Sariff			    __func__);
4142162922Sariff			break;
4143162922Sariff		}
4144162922Sariff		w = hdac_widget_get(devinfo, i);
4145162922Sariff		if (w == NULL || w->enable == 0)
4146162922Sariff			continue;
4147162922Sariff		ocap = w->param.outamp_cap;
4148162922Sariff		icap = w->param.inamp_cap;
4149162922Sariff		if (ocap != 0) {
4150163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap);
4151163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap);
4152163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap);
4153163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap);
4154163057Sariff			/*if (offset > step) {
4155163057Sariff				HDA_BOOTVERBOSE(
4156163057Sariff					device_printf(sc->dev,
4157182999Smav					    "BUGGY outamp: nid=%d "
4158163057Sariff					    "[offset=%d > step=%d]\n",
4159163057Sariff					    w->nid, offset, step);
4160163057Sariff				);
4161163057Sariff				offset = step;
4162163057Sariff			}*/
4163162922Sariff			ctls[cnt].enable = 1;
4164162922Sariff			ctls[cnt].widget = w;
4165163057Sariff			ctls[cnt].mute = mute;
4166163057Sariff			ctls[cnt].step = step;
4167163057Sariff			ctls[cnt].size = size;
4168163057Sariff			ctls[cnt].offset = offset;
4169163057Sariff			ctls[cnt].left = offset;
4170163057Sariff			ctls[cnt].right = offset;
4171182999Smav			if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
4172182999Smav			    w->waspin)
4173182999Smav				ctls[cnt].ndir = HDA_CTL_IN;
4174182999Smav			else
4175182999Smav				ctls[cnt].ndir = HDA_CTL_OUT;
4176162922Sariff			ctls[cnt++].dir = HDA_CTL_OUT;
4177162922Sariff		}
4178162922Sariff
4179162922Sariff		if (icap != 0) {
4180163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap);
4181163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap);
4182163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap);
4183163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap);
4184163057Sariff			/*if (offset > step) {
4185163057Sariff				HDA_BOOTVERBOSE(
4186163057Sariff					device_printf(sc->dev,
4187182999Smav					    "BUGGY inamp: nid=%d "
4188163057Sariff					    "[offset=%d > step=%d]\n",
4189163057Sariff					    w->nid, offset, step);
4190163057Sariff				);
4191163057Sariff				offset = step;
4192163057Sariff			}*/
4193162922Sariff			switch (w->type) {
4194162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4195162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4196162922Sariff				for (j = 0; j < w->nconns; j++) {
4197162922Sariff					if (cnt >= max) {
4198162922Sariff						device_printf(sc->dev,
4199162922Sariff						    "%s: Ctl overflow!\n",
4200162922Sariff						    __func__);
4201162922Sariff						break;
4202162922Sariff					}
4203162922Sariff					cw = hdac_widget_get(devinfo,
4204162922Sariff					    w->conns[j]);
4205162922Sariff					if (cw == NULL || cw->enable == 0)
4206162922Sariff						continue;
4207162922Sariff					ctls[cnt].enable = 1;
4208162922Sariff					ctls[cnt].widget = w;
4209162922Sariff					ctls[cnt].childwidget = cw;
4210162922Sariff					ctls[cnt].index = j;
4211163057Sariff					ctls[cnt].mute = mute;
4212163057Sariff					ctls[cnt].step = step;
4213163057Sariff					ctls[cnt].size = size;
4214163057Sariff					ctls[cnt].offset = offset;
4215163057Sariff					ctls[cnt].left = offset;
4216163057Sariff					ctls[cnt].right = offset;
4217182999Smav	    				ctls[cnt].ndir = HDA_CTL_IN;
4218162922Sariff					ctls[cnt++].dir = HDA_CTL_IN;
4219162922Sariff				}
4220162922Sariff				break;
4221162922Sariff			default:
4222162922Sariff				if (cnt >= max) {
4223162922Sariff					device_printf(sc->dev,
4224162922Sariff					    "%s: Ctl overflow!\n",
4225162922Sariff					    __func__);
4226162922Sariff					break;
4227162922Sariff				}
4228162922Sariff				ctls[cnt].enable = 1;
4229162922Sariff				ctls[cnt].widget = w;
4230163057Sariff				ctls[cnt].mute = mute;
4231163057Sariff				ctls[cnt].step = step;
4232163057Sariff				ctls[cnt].size = size;
4233163057Sariff				ctls[cnt].offset = offset;
4234163057Sariff				ctls[cnt].left = offset;
4235163057Sariff				ctls[cnt].right = offset;
4236182999Smav				if (w->type ==
4237182999Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4238182999Smav					ctls[cnt].ndir = HDA_CTL_OUT;
4239182999Smav				else
4240182999Smav					ctls[cnt].ndir = HDA_CTL_IN;
4241162922Sariff				ctls[cnt++].dir = HDA_CTL_IN;
4242162922Sariff				break;
4243162922Sariff			}
4244162922Sariff		}
4245162922Sariff	}
4246162922Sariff
4247162922Sariff	devinfo->function.audio.ctl = ctls;
4248162922Sariff}
4249162922Sariff
4250182999Smavstatic void
4251182999Smavhdac_audio_as_parse(struct hdac_devinfo *devinfo)
4252182999Smav{
4253182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
4254182999Smav	struct hdac_audio_as *as;
4255182999Smav	struct hdac_widget *w;
4256182999Smav	int i, j, cnt, max, type, dir, assoc, seq, first, hpredir;
4257182999Smav
4258184991Smav	/* Count present associations */
4259182999Smav	max = 0;
4260184991Smav	for (j = 1; j < 16; j++) {
4261182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4262182999Smav			w = hdac_widget_get(devinfo, i);
4263182999Smav			if (w == NULL || w->enable == 0)
4264182999Smav				continue;
4265182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4266182999Smav				continue;
4267182999Smav			if (HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config)
4268182999Smav			    != j)
4269182999Smav				continue;
4270182999Smav			max++;
4271182999Smav			if (j != 15)  /* There could be many 1-pin assocs #15 */
4272182999Smav				break;
4273182999Smav		}
4274182999Smav	}
4275182999Smav
4276182999Smav	devinfo->function.audio.ascnt = max;
4277182999Smav
4278182999Smav	if (max < 1)
4279182999Smav		return;
4280182999Smav
4281182999Smav	as = (struct hdac_audio_as *)malloc(
4282182999Smav	    sizeof(*as) * max, M_HDAC, M_ZERO | M_NOWAIT);
4283182999Smav
4284182999Smav	if (as == NULL) {
4285182999Smav		/* Blekh! */
4286182999Smav		device_printf(sc->dev, "unable to allocate assocs!\n");
4287182999Smav		devinfo->function.audio.ascnt = 0;
4288182999Smav		return;
4289182999Smav	}
4290182999Smav
4291182999Smav	for (i = 0; i < max; i++) {
4292182999Smav		as[i].hpredir = -1;
4293182999Smav		as[i].chan = -1;
4294182999Smav	}
4295182999Smav
4296182999Smav	/* Scan associations skipping as=0. */
4297182999Smav	cnt = 0;
4298182999Smav	for (j = 1; j < 16; j++) {
4299182999Smav		first = 16;
4300182999Smav		hpredir = 0;
4301182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4302182999Smav			w = hdac_widget_get(devinfo, i);
4303182999Smav			if (w == NULL || w->enable == 0)
4304182999Smav				continue;
4305182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4306182999Smav				continue;
4307182999Smav			assoc = HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config);
4308182999Smav			seq = HDA_CONFIG_DEFAULTCONF_SEQUENCE(w->wclass.pin.config);
4309182999Smav			if (assoc != j) {
4310182999Smav				continue;
4311182999Smav			}
4312182999Smav			KASSERT(cnt < max,
4313182999Smav			    ("%s: Associations owerflow (%d of %d)",
4314182999Smav			    __func__, cnt, max));
4315182999Smav			type = w->wclass.pin.config &
4316182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4317182999Smav			/* Get pin direction. */
4318182999Smav			if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT ||
4319182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
4320182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
4321182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT ||
4322182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT)
4323182999Smav				dir = HDA_CTL_OUT;
4324182999Smav			else
4325182999Smav				dir = HDA_CTL_IN;
4326182999Smav			/* If this is a first pin - create new association. */
4327182999Smav			if (as[cnt].pincnt == 0) {
4328182999Smav				as[cnt].enable = 1;
4329182999Smav				as[cnt].index = j;
4330182999Smav				as[cnt].dir = dir;
4331182999Smav			}
4332182999Smav			if (seq < first)
4333182999Smav				first = seq;
4334182999Smav			/* Check association correctness. */
4335182999Smav			if (as[cnt].pins[seq] != 0) {
4336182999Smav				device_printf(sc->dev, "%s: Duplicate pin %d (%d) "
4337182999Smav				    "in association %d! Disabling association.\n",
4338182999Smav				    __func__, seq, w->nid, j);
4339182999Smav				as[cnt].enable = 0;
4340182999Smav			}
4341182999Smav			if (dir != as[cnt].dir) {
4342182999Smav				device_printf(sc->dev, "%s: Pin %d has wrong "
4343182999Smav				    "direction for association %d! Disabling "
4344182999Smav				    "association.\n",
4345182999Smav				    __func__, w->nid, j);
4346182999Smav				as[cnt].enable = 0;
4347182999Smav			}
4348182999Smav			/* Headphones with seq=15 may mean redirection. */
4349182999Smav			if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT &&
4350182999Smav			    seq == 15)
4351182999Smav				hpredir = 1;
4352182999Smav			as[cnt].pins[seq] = w->nid;
4353182999Smav			as[cnt].pincnt++;
4354182999Smav			/* Association 15 is a multiple unassociated pins. */
4355182999Smav			if (j == 15)
4356182999Smav				cnt++;
4357182999Smav		}
4358182999Smav		if (j != 15 && as[cnt].pincnt > 0) {
4359182999Smav			if (hpredir && as[cnt].pincnt > 1)
4360182999Smav				as[cnt].hpredir = first;
4361182999Smav			cnt++;
4362182999Smav		}
4363182999Smav	}
4364182999Smav	HDA_BOOTVERBOSE(
4365182999Smav		device_printf(sc->dev,
4366183097Smav		    "%d associations found:\n", max);
4367182999Smav		for (i = 0; i < max; i++) {
4368182999Smav			device_printf(sc->dev,
4369182999Smav			    "Association %d (%d) %s%s:\n",
4370182999Smav			    i, as[i].index, (as[i].dir == HDA_CTL_IN)?"in":"out",
4371182999Smav			    as[i].enable?"":" (disabled)");
4372182999Smav			for (j = 0; j < 16; j++) {
4373182999Smav				if (as[i].pins[j] == 0)
4374182999Smav					continue;
4375182999Smav				device_printf(sc->dev,
4376183097Smav				    " Pin nid=%d seq=%d\n",
4377182999Smav				    as[i].pins[j], j);
4378182999Smav			}
4379182999Smav		}
4380182999Smav	);
4381182999Smav
4382182999Smav	devinfo->function.audio.as = as;
4383182999Smav}
4384182999Smav
4385162965Sariffstatic const struct {
4386162965Sariff	uint32_t model;
4387162965Sariff	uint32_t id;
4388162965Sariff	uint32_t set, unset;
4389162965Sariff} hdac_quirks[] = {
4390163057Sariff	/*
4391163057Sariff	 * XXX Force stereo quirk. Monoural recording / playback
4392163057Sariff	 *     on few codecs (especially ALC880) seems broken or
4393163057Sariff	 *     perhaps unsupported.
4394163057Sariff	 */
4395163057Sariff	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
4396169277Sariff	    HDA_QUIRK_FORCESTEREO | HDA_QUIRK_IVREF, 0 },
4397162965Sariff	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
4398165039Sariff	    HDA_QUIRK_GPIO0, 0 },
4399178155Sariff	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
4400178155Sariff	    HDA_QUIRK_GPIO0, 0 },
4401162965Sariff	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
4402165039Sariff	    HDA_QUIRK_GPIO0, 0 },
4403165281Sariff	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
4404165281Sariff	    HDA_QUIRK_GPIO0, 0 },
4405167623Sariff	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
4406167623Sariff	    HDA_QUIRK_GPIO0, 0 },
4407169277Sariff	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
4408169277Sariff	    HDA_QUIRK_GPIO0, 0 },
4409163276Sariff	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
4410163276Sariff	    HDA_QUIRK_EAPDINV, 0 },
4411178155Sariff	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
4412163432Sariff	    HDA_QUIRK_EAPDINV, 0 },
4413169277Sariff	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
4414169277Sariff	    HDA_QUIRK_OVREF, 0 },
4415169277Sariff	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
4416169277Sariff	    HDA_QUIRK_OVREF, 0 },
4417169277Sariff	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
4418169277Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },*/
4419165281Sariff	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
4420165281Sariff	    HDA_QUIRK_GPIO1, 0 },
4421164657Sariff	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
4422182999Smav	    HDA_QUIRK_EAPDINV | HDA_QUIRK_SENSEINV, 0 },
4423164657Sariff	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
4424164657Sariff	    HDA_QUIRK_EAPDINV, 0 },
4425173817Sariff	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
4426173817Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0},
4427165039Sariff	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
4428165039Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 },
4429183894Smav	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
4430180532Sdelphij	    HDA_QUIRK_GPIO0, 0 },
4431184483Smav	{ DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X,
4432184483Smav	    HDA_QUIRK_GPIO2, 0 },
4433183894Smav	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
4434178155Sariff	    HDA_QUIRK_GPIO0, 0 },
4435169277Sariff	{ HDA_MATCH_ALL, HDA_CODEC_AD1988,
4436169277Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4437170518Sariff	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
4438170518Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4439162965Sariff	{ HDA_MATCH_ALL, HDA_CODEC_CXVENICE,
4440182999Smav	    0, HDA_QUIRK_FORCESTEREO }
4441162965Sariff};
4442162965Sariff#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
4443162965Sariff
4444162922Sariffstatic void
4445162922Sariffhdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
4446162922Sariff{
4447162922Sariff	struct hdac_widget *w;
4448162965Sariff	uint32_t id, subvendor;
4449162922Sariff	int i;
4450162922Sariff
4451182999Smav	id = hdac_codec_id(devinfo->codec);
4452163057Sariff	subvendor = devinfo->codec->sc->pci_subvendor;
4453163057Sariff
4454162922Sariff	/*
4455163057Sariff	 * Quirks
4456162922Sariff	 */
4457163057Sariff	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
4458163257Sariff		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) &&
4459163257Sariff		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
4460163057Sariff			continue;
4461163057Sariff		if (hdac_quirks[i].set != 0)
4462163057Sariff			devinfo->function.audio.quirks |=
4463163057Sariff			    hdac_quirks[i].set;
4464163057Sariff		if (hdac_quirks[i].unset != 0)
4465163057Sariff			devinfo->function.audio.quirks &=
4466163057Sariff			    ~(hdac_quirks[i].unset);
4467163057Sariff	}
4468163057Sariff
4469162922Sariff	switch (id) {
4470166965Sariff	case HDA_CODEC_ALC883:
4471166965Sariff		/*
4472166965Sariff		 * nid: 24/25 = External (jack) or Internal (fixed) Mic.
4473166965Sariff		 *              Clear vref cap for jack connectivity.
4474166965Sariff		 */
4475166965Sariff		w = hdac_widget_get(devinfo, 24);
4476166965Sariff		if (w != NULL && w->enable != 0 && w->type ==
4477166965Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4478166965Sariff		    (w->wclass.pin.config &
4479166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4480166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
4481166965Sariff			w->wclass.pin.cap &= ~(
4482166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
4483166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
4484166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
4485166965Sariff		w = hdac_widget_get(devinfo, 25);
4486166965Sariff		if (w != NULL && w->enable != 0 && w->type ==
4487166965Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4488166965Sariff		    (w->wclass.pin.config &
4489166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4490166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
4491166965Sariff			w->wclass.pin.cap &= ~(
4492166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
4493166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
4494166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
4495166965Sariff		/*
4496166965Sariff		 * nid: 26 = Line-in, leave it alone.
4497166965Sariff		 */
4498166965Sariff		break;
4499162922Sariff	case HDA_CODEC_AD1986A:
4500182999Smav		if (subvendor == ASUS_A8X_SUBVENDOR) {
4501178155Sariff			/*
4502178155Sariff			 * This is just plain ridiculous.. There
4503178155Sariff			 * are several A8 series that share the same
4504178155Sariff			 * pci id but works differently (EAPD).
4505178155Sariff			 */
4506178155Sariff			w = hdac_widget_get(devinfo, 26);
4507178155Sariff			if (w != NULL && w->type ==
4508178155Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4509178155Sariff			    (w->wclass.pin.config &
4510178155Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
4511178155Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
4512178155Sariff				devinfo->function.audio.quirks &=
4513178155Sariff				    ~HDA_QUIRK_EAPDINV;
4514169277Sariff		}
4515162922Sariff		break;
4516184230Smav	case HDA_CODEC_AD1981HD:
4517184230Smav		/*
4518184230Smav		 * This codec has very unusual design with several
4519184254Smav		 * points inappropriate for the present parser.
4520184230Smav		 */
4521184230Smav		/* Disable recording from mono playback mix. */
4522184230Smav		w = hdac_widget_get(devinfo, 21);
4523184230Smav		if (w != NULL)
4524184230Smav			w->connsenable[3] = 0;
4525184230Smav		/* Disable rear to front mic mixer, use separately. */
4526184230Smav		w = hdac_widget_get(devinfo, 31);
4527184230Smav		if (w != NULL)
4528184230Smav			w->enable = 0;
4529184230Smav		/* Disable playback mixer, use direct bypass. */
4530184230Smav		w = hdac_widget_get(devinfo, 14);
4531184230Smav		if (w != NULL)
4532184230Smav			w->enable = 0;
4533184230Smav		break;
4534182999Smav	}
4535182999Smav}
4536182999Smav
4537182999Smav/*
4538182999Smav * Trace path from DAC to pin.
4539182999Smav */
4540182999Smavstatic nid_t
4541182999Smavhdac_audio_trace_dac(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
4542182999Smav    int dupseq, int min, int only, int depth)
4543182999Smav{
4544182999Smav	struct hdac_widget *w;
4545182999Smav	int i, im = -1;
4546182999Smav	nid_t m = 0, ret;
4547182999Smav
4548182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
4549182999Smav		return (0);
4550182999Smav	w = hdac_widget_get(devinfo, nid);
4551182999Smav	if (w == NULL || w->enable == 0)
4552182999Smav		return (0);
4553183097Smav	HDA_BOOTHVERBOSE(
4554182999Smav		if (!only) {
4555182999Smav			device_printf(devinfo->codec->sc->dev,
4556182999Smav			    " %*stracing via nid %d\n",
4557182999Smav				depth + 1, "", w->nid);
4558169277Sariff		}
4559182999Smav	);
4560182999Smav	/* Use only unused widgets */
4561182999Smav	if (w->bindas >= 0 && w->bindas != as) {
4562183097Smav		HDA_BOOTHVERBOSE(
4563182999Smav			if (!only) {
4564182999Smav				device_printf(devinfo->codec->sc->dev,
4565182999Smav				    " %*snid %d busy by association %d\n",
4566182999Smav					depth + 1, "", w->nid, w->bindas);
4567182999Smav			}
4568182999Smav		);
4569182999Smav		return (0);
4570182999Smav	}
4571182999Smav	if (dupseq < 0) {
4572182999Smav		if (w->bindseqmask != 0) {
4573183097Smav			HDA_BOOTHVERBOSE(
4574182999Smav				if (!only) {
4575182999Smav					device_printf(devinfo->codec->sc->dev,
4576182999Smav					    " %*snid %d busy by seqmask %x\n",
4577182999Smav						depth + 1, "", w->nid, w->bindseqmask);
4578182999Smav				}
4579182999Smav			);
4580182999Smav			return (0);
4581169277Sariff		}
4582182999Smav	} else {
4583182999Smav		/* If this is headphones - allow duplicate first pin. */
4584182999Smav		if (w->bindseqmask != 0 &&
4585182999Smav		    (w->bindseqmask & (1 << dupseq)) == 0) {
4586183097Smav			HDA_BOOTHVERBOSE(
4587182999Smav				device_printf(devinfo->codec->sc->dev,
4588182999Smav				    " %*snid %d busy by seqmask %x\n",
4589182999Smav					depth + 1, "", w->nid, w->bindseqmask);
4590182999Smav			);
4591182999Smav			return (0);
4592169277Sariff		}
4593182999Smav	}
4594182999Smav
4595182999Smav	switch (w->type) {
4596182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4597182999Smav		/* Do not traverse input. AD1988 has digital monitor
4598182999Smav		for which we are not ready. */
4599169277Sariff		break;
4600182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
4601182999Smav		/* If we are tracing HP take only dac of first pin. */
4602182999Smav		if ((only == 0 || only == w->nid) &&
4603182999Smav		    (w->nid >= min) && (dupseq < 0 || w->nid ==
4604182999Smav		    devinfo->function.audio.as[as].dacs[dupseq]))
4605182999Smav			m = w->nid;
4606178155Sariff		break;
4607182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4608182999Smav		if (depth > 0)
4609169277Sariff			break;
4610182999Smav		/* Fall */
4611182999Smav	default:
4612182999Smav		/* Find reachable DACs with smallest nid respecting constraints. */
4613182999Smav		for (i = 0; i < w->nconns; i++) {
4614182999Smav			if (w->connsenable[i] == 0)
4615162922Sariff				continue;
4616182999Smav			if (w->selconn != -1 && w->selconn != i)
4617162922Sariff				continue;
4618182999Smav			if ((ret = hdac_audio_trace_dac(devinfo, as, seq,
4619182999Smav			    w->conns[i], dupseq, min, only, depth + 1)) != 0) {
4620182999Smav				if (m == 0 || ret < m) {
4621182999Smav					m = ret;
4622182999Smav					im = i;
4623182999Smav				}
4624182999Smav				if (only || dupseq >= 0)
4625182999Smav					break;
4626182999Smav			}
4627162922Sariff		}
4628182999Smav		if (m && only && ((w->nconns > 1 &&
4629182999Smav		    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
4630182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4631182999Smav			w->selconn = im;
4632162922Sariff		break;
4633182999Smav	}
4634182999Smav	if (m && only) {
4635182999Smav		w->bindas = as;
4636182999Smav		w->bindseqmask |= (1 << seq);
4637182999Smav	}
4638183097Smav	HDA_BOOTHVERBOSE(
4639182999Smav		if (!only) {
4640182999Smav			device_printf(devinfo->codec->sc->dev,
4641182999Smav			    " %*snid %d returned %d\n",
4642182999Smav				depth + 1, "", w->nid, m);
4643182999Smav		}
4644182999Smav	);
4645182999Smav	return (m);
4646182999Smav}
4647162922Sariff
4648182999Smav/*
4649182999Smav * Trace path from widget to ADC.
4650182999Smav */
4651182999Smavstatic nid_t
4652182999Smavhdac_audio_trace_adc(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
4653182999Smav    int only, int depth)
4654182999Smav{
4655182999Smav	struct hdac_widget *w, *wc;
4656182999Smav	int i, j;
4657182999Smav	nid_t res = 0;
4658182999Smav
4659182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
4660182999Smav		return (0);
4661182999Smav	w = hdac_widget_get(devinfo, nid);
4662182999Smav	if (w == NULL || w->enable == 0)
4663182999Smav		return (0);
4664183097Smav	HDA_BOOTHVERBOSE(
4665182999Smav		device_printf(devinfo->codec->sc->dev,
4666182999Smav		    " %*stracing via nid %d\n",
4667182999Smav			depth + 1, "", w->nid);
4668182999Smav	);
4669182999Smav	/* Use only unused widgets */
4670182999Smav	if (w->bindas >= 0 && w->bindas != as) {
4671183097Smav		HDA_BOOTHVERBOSE(
4672182999Smav			device_printf(devinfo->codec->sc->dev,
4673182999Smav			    " %*snid %d busy by association %d\n",
4674182999Smav				depth + 1, "", w->nid, w->bindas);
4675182999Smav		);
4676182999Smav		return (0);
4677182999Smav	}
4678182999Smav
4679182999Smav	switch (w->type) {
4680182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4681182999Smav		/* If we are tracing HP take only dac of first pin. */
4682182999Smav		if (only == w->nid)
4683182999Smav			res = 1;
4684162922Sariff		break;
4685182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4686182999Smav		if (depth > 0)
4687182999Smav			break;
4688182999Smav		/* Fall */
4689182999Smav	default:
4690182999Smav		/* Try to find reachable ADCs with specified nid. */
4691182999Smav		for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4692182999Smav			wc = hdac_widget_get(devinfo, j);
4693182999Smav			if (wc == NULL || wc->enable == 0)
4694182999Smav				continue;
4695182999Smav			for (i = 0; i < wc->nconns; i++) {
4696182999Smav				if (wc->connsenable[i] == 0)
4697182999Smav					continue;
4698182999Smav				if (wc->conns[i] != nid)
4699182999Smav					continue;
4700182999Smav				if (hdac_audio_trace_adc(devinfo, as, seq,
4701182999Smav				    j, only, depth + 1) != 0) {
4702182999Smav					res = 1;
4703182999Smav					if (((wc->nconns > 1 &&
4704182999Smav					    wc->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
4705182999Smav					    wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) &&
4706182999Smav					    wc->selconn == -1)
4707182999Smav						wc->selconn = i;
4708182999Smav				}
4709182999Smav			}
4710169277Sariff		}
4711169277Sariff		break;
4712162922Sariff	}
4713182999Smav	if (res) {
4714182999Smav		w->bindas = as;
4715182999Smav		w->bindseqmask |= (1 << seq);
4716182999Smav	}
4717183097Smav	HDA_BOOTHVERBOSE(
4718182999Smav		device_printf(devinfo->codec->sc->dev,
4719182999Smav		    " %*snid %d returned %d\n",
4720182999Smav			depth + 1, "", w->nid, res);
4721182999Smav	);
4722182999Smav	return (res);
4723162922Sariff}
4724162922Sariff
4725182999Smav/*
4726182999Smav * Erase trace path of the specified association.
4727182999Smav */
4728182999Smavstatic void
4729182999Smavhdac_audio_undo_trace(struct hdac_devinfo *devinfo, int as, int seq)
4730182999Smav{
4731182999Smav	struct hdac_widget *w;
4732182999Smav	int i;
4733182999Smav
4734182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4735182999Smav		w = hdac_widget_get(devinfo, i);
4736182999Smav		if (w == NULL || w->enable == 0)
4737182999Smav			continue;
4738182999Smav		if (w->bindas == as) {
4739182999Smav			if (seq >= 0) {
4740182999Smav				w->bindseqmask &= ~(1 << seq);
4741182999Smav				if (w->bindseqmask == 0) {
4742182999Smav					w->bindas = -1;
4743182999Smav					w->selconn = -1;
4744182999Smav				}
4745182999Smav			} else {
4746182999Smav				w->bindas = -1;
4747182999Smav				w->bindseqmask = 0;
4748182999Smav				w->selconn = -1;
4749182999Smav			}
4750182999Smav		}
4751182999Smav	}
4752182999Smav}
4753182999Smav
4754182999Smav/*
4755182999Smav * Trace association path from DAC to output
4756182999Smav */
4757162922Sariffstatic int
4758182999Smavhdac_audio_trace_as_out(struct hdac_devinfo *devinfo, int as, int seq)
4759162922Sariff{
4760182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
4761182999Smav	int i, hpredir;
4762182999Smav	nid_t min, res;
4763162922Sariff
4764182999Smav	/* Find next pin */
4765185176Smav	for (i = seq; i < 16 && ases[as].pins[i] == 0; i++)
4766182999Smav		;
4767182999Smav	/* Check if there is no any left. If so - we succeded. */
4768182999Smav	if (i == 16)
4769182999Smav		return (1);
4770182999Smav
4771182999Smav	hpredir = (i == 15 && ases[as].fakeredir == 0)?ases[as].hpredir:-1;
4772182999Smav	min = 0;
4773182999Smav	res = 0;
4774182999Smav	do {
4775183097Smav		HDA_BOOTHVERBOSE(
4776182999Smav			device_printf(devinfo->codec->sc->dev,
4777182999Smav			    " Tracing pin %d with min nid %d",
4778182999Smav			    ases[as].pins[i], min);
4779182999Smav			if (hpredir >= 0)
4780183097Smav				printf(" and hpredir %d", hpredir);
4781183097Smav			printf("\n");
4782182999Smav		);
4783182999Smav		/* Trace this pin taking min nid into account. */
4784182999Smav		res = hdac_audio_trace_dac(devinfo, as, i,
4785182999Smav		    ases[as].pins[i], hpredir, min, 0, 0);
4786182999Smav		if (res == 0) {
4787182999Smav			/* If we failed - return to previous and redo it. */
4788182999Smav			HDA_BOOTVERBOSE(
4789182999Smav				device_printf(devinfo->codec->sc->dev,
4790182999Smav				    " Unable to trace pin %d seq %d with min "
4791183097Smav				    "nid %d",
4792183097Smav				    ases[as].pins[i], i, min);
4793183097Smav				if (hpredir >= 0)
4794183097Smav					printf(" and hpredir %d", hpredir);
4795183097Smav				printf("\n");
4796182999Smav			);
4797182999Smav			return (0);
4798162922Sariff		}
4799182999Smav		HDA_BOOTVERBOSE(
4800182999Smav			device_printf(devinfo->codec->sc->dev,
4801183097Smav			    " Pin %d traced to DAC %d",
4802183097Smav			    ases[as].pins[i], res);
4803183097Smav			if (hpredir >= 0)
4804183097Smav				printf(" and hpredir %d", hpredir);
4805183097Smav			if (ases[as].fakeredir)
4806183097Smav				printf(" with fake redirection");
4807183097Smav			printf("\n");
4808182999Smav		);
4809182999Smav		/* Trace again to mark the path */
4810182999Smav		hdac_audio_trace_dac(devinfo, as, i,
4811182999Smav		    ases[as].pins[i], hpredir, min, res, 0);
4812182999Smav		ases[as].dacs[i] = res;
4813182999Smav		/* We succeded, so call next. */
4814182999Smav		if (hdac_audio_trace_as_out(devinfo, as, i + 1))
4815182999Smav			return (1);
4816182999Smav		/* If next failed, we should retry with next min */
4817182999Smav		hdac_audio_undo_trace(devinfo, as, i);
4818182999Smav		ases[as].dacs[i] = 0;
4819182999Smav		min = res + 1;
4820182999Smav	} while (1);
4821162922Sariff}
4822162922Sariff
4823182999Smav/*
4824182999Smav * Trace association path from input to ADC
4825182999Smav */
4826162922Sariffstatic int
4827182999Smavhdac_audio_trace_as_in(struct hdac_devinfo *devinfo, int as)
4828162922Sariff{
4829182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
4830162922Sariff	struct hdac_widget *w;
4831182999Smav	int i, j, k;
4832162922Sariff
4833182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4834182999Smav		w = hdac_widget_get(devinfo, j);
4835182999Smav		if (w == NULL || w->enable == 0)
4836182999Smav			continue;
4837182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
4838182999Smav			continue;
4839182999Smav		if (w->bindas >= 0 && w->bindas != as)
4840182999Smav			continue;
4841182999Smav
4842182999Smav		/* Find next pin */
4843182999Smav		for (i = 0; i < 16; i++) {
4844182999Smav			if (ases[as].pins[i] == 0)
4845182999Smav				continue;
4846182999Smav
4847183097Smav			HDA_BOOTHVERBOSE(
4848182999Smav				device_printf(devinfo->codec->sc->dev,
4849182999Smav				    " Tracing pin %d to ADC %d\n",
4850182999Smav				    ases[as].pins[i], j);
4851182999Smav			);
4852182999Smav			/* Trace this pin taking goal into account. */
4853182999Smav			if (hdac_audio_trace_adc(devinfo, as, i,
4854182999Smav			    ases[as].pins[i], j, 0) == 0) {
4855182999Smav				/* If we failed - return to previous and redo it. */
4856182999Smav				HDA_BOOTVERBOSE(
4857182999Smav					device_printf(devinfo->codec->sc->dev,
4858183097Smav					    " Unable to trace pin %d to ADC %d, undo traces\n",
4859182999Smav					    ases[as].pins[i], j);
4860182999Smav				);
4861182999Smav				hdac_audio_undo_trace(devinfo, as, -1);
4862182999Smav				for (k = 0; k < 16; k++)
4863182999Smav					ases[as].dacs[k] = 0;
4864182999Smav				break;
4865162922Sariff			}
4866182999Smav			HDA_BOOTVERBOSE(
4867182999Smav				device_printf(devinfo->codec->sc->dev,
4868183097Smav				    " Pin %d traced to ADC %d\n",
4869183097Smav				    ases[as].pins[i], j);
4870182999Smav			);
4871182999Smav			ases[as].dacs[i] = j;
4872162922Sariff		}
4873182999Smav		if (i == 16)
4874182999Smav			return (1);
4875162922Sariff	}
4876182999Smav	return (0);
4877162922Sariff}
4878162922Sariff
4879182999Smav/*
4880182999Smav * Trace input monitor path from mixer to output association.
4881182999Smav */
4882183097Smavstatic int
4883182999Smavhdac_audio_trace_to_out(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4884162922Sariff{
4885182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
4886182999Smav	struct hdac_widget *w, *wc;
4887182999Smav	int i, j;
4888182999Smav	nid_t res = 0;
4889162922Sariff
4890162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
4891162922Sariff		return (0);
4892162922Sariff	w = hdac_widget_get(devinfo, nid);
4893162922Sariff	if (w == NULL || w->enable == 0)
4894162922Sariff		return (0);
4895183097Smav	HDA_BOOTHVERBOSE(
4896182999Smav		device_printf(devinfo->codec->sc->dev,
4897182999Smav		    " %*stracing via nid %d\n",
4898182999Smav			depth + 1, "", w->nid);
4899182999Smav	);
4900182999Smav	/* Use only unused widgets */
4901182999Smav	if (depth > 0 && w->bindas != -1) {
4902182999Smav		if (w->bindas < 0 || ases[w->bindas].dir == HDA_CTL_OUT) {
4903183097Smav			HDA_BOOTHVERBOSE(
4904182999Smav				device_printf(devinfo->codec->sc->dev,
4905182999Smav				    " %*snid %d found output association %d\n",
4906182999Smav					depth + 1, "", w->nid, w->bindas);
4907182999Smav			);
4908182999Smav			return (1);
4909182999Smav		} else {
4910183097Smav			HDA_BOOTHVERBOSE(
4911182999Smav				device_printf(devinfo->codec->sc->dev,
4912182999Smav				    " %*snid %d busy by input association %d\n",
4913182999Smav					depth + 1, "", w->nid, w->bindas);
4914182999Smav			);
4915182999Smav			return (0);
4916182999Smav		}
4917182999Smav	}
4918182999Smav
4919162922Sariff	switch (w->type) {
4920162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4921182999Smav		/* Do not traverse input. AD1988 has digital monitor
4922182999Smav		for which we are not ready. */
4923162922Sariff		break;
4924162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4925182999Smav		if (depth > 0)
4926182999Smav			break;
4927182999Smav		/* Fall */
4928182999Smav	default:
4929182999Smav		/* Try to find reachable ADCs with specified nid. */
4930182999Smav		for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4931182999Smav			wc = hdac_widget_get(devinfo, j);
4932182999Smav			if (wc == NULL || wc->enable == 0)
4933182999Smav				continue;
4934182999Smav			for (i = 0; i < wc->nconns; i++) {
4935182999Smav				if (wc->connsenable[i] == 0)
4936182999Smav					continue;
4937182999Smav				if (wc->conns[i] != nid)
4938182999Smav					continue;
4939182999Smav				if (hdac_audio_trace_to_out(devinfo,
4940182999Smav				    j, depth + 1) != 0) {
4941182999Smav					res = 1;
4942182999Smav					if (wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4943182999Smav					    wc->selconn == -1)
4944182999Smav						wc->selconn = i;
4945182999Smav				}
4946182999Smav			}
4947162922Sariff		}
4948162922Sariff		break;
4949182999Smav	}
4950182999Smav	if (res)
4951182999Smav		w->bindas = -2;
4952182999Smav
4953183097Smav	HDA_BOOTHVERBOSE(
4954182999Smav		device_printf(devinfo->codec->sc->dev,
4955182999Smav		    " %*snid %d returned %d\n",
4956182999Smav			depth + 1, "", w->nid, res);
4957182999Smav	);
4958182999Smav	return (res);
4959182999Smav}
4960182999Smav
4961182999Smav/*
4962182999Smav * Trace extra associations (beeper, monitor)
4963182999Smav */
4964182999Smavstatic void
4965182999Smavhdac_audio_trace_as_extra(struct hdac_devinfo *devinfo)
4966182999Smav{
4967182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
4968182999Smav	struct hdac_widget *w;
4969182999Smav	int j;
4970182999Smav
4971182999Smav	/* Input monitor */
4972182999Smav	/* Find mixer associated with input, but supplying signal
4973182999Smav	   for output associations. Hope it will be input monitor. */
4974182999Smav	HDA_BOOTVERBOSE(
4975182999Smav		device_printf(devinfo->codec->sc->dev,
4976182999Smav		    "Tracing input monitor\n");
4977182999Smav	);
4978182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4979182999Smav		w = hdac_widget_get(devinfo, j);
4980182999Smav		if (w == NULL || w->enable == 0)
4981182999Smav			continue;
4982182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
4983182999Smav			continue;
4984182999Smav		if (w->bindas < 0 || as[w->bindas].dir != HDA_CTL_IN)
4985182999Smav			continue;
4986182999Smav		HDA_BOOTVERBOSE(
4987182999Smav			device_printf(devinfo->codec->sc->dev,
4988182999Smav			    " Tracing nid %d to out\n",
4989182999Smav			    j);
4990182999Smav		);
4991182999Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
4992182999Smav			HDA_BOOTVERBOSE(
4993182999Smav				device_printf(devinfo->codec->sc->dev,
4994182999Smav				    " nid %d is input monitor\n",
4995182999Smav					w->nid);
4996182999Smav			);
4997182999Smav			w->pflags |= HDA_ADC_MONITOR;
4998182999Smav			w->ossdev = SOUND_MIXER_IMIX;
4999162922Sariff		}
5000162922Sariff	}
5001182999Smav
5002182999Smav	/* Beeper */
5003182999Smav	HDA_BOOTVERBOSE(
5004182999Smav		device_printf(devinfo->codec->sc->dev,
5005182999Smav		    "Tracing beeper\n");
5006182999Smav	);
5007182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5008182999Smav		w = hdac_widget_get(devinfo, j);
5009182999Smav		if (w == NULL || w->enable == 0)
5010182999Smav			continue;
5011182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET)
5012182999Smav			continue;
5013183097Smav		HDA_BOOTHVERBOSE(
5014182999Smav			device_printf(devinfo->codec->sc->dev,
5015182999Smav			    " Tracing nid %d to out\n",
5016182999Smav			    j);
5017182999Smav		);
5018183097Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
5019183097Smav			HDA_BOOTVERBOSE(
5020183097Smav				device_printf(devinfo->codec->sc->dev,
5021183097Smav				    " nid %d traced to out\n",
5022183097Smav				    j);
5023183097Smav			);
5024183097Smav		}
5025182999Smav		w->bindas = -2;
5026182999Smav	}
5027162922Sariff}
5028162922Sariff
5029182999Smav/*
5030182999Smav * Bind assotiations to PCM channels
5031182999Smav */
5032182999Smavstatic void
5033182999Smavhdac_audio_bind_as(struct hdac_devinfo *devinfo)
5034162922Sariff{
5035182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
5036182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5037182999Smav	int j, cnt = 0, free;
5038162922Sariff
5039182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5040182999Smav		if (as[j].enable)
5041182999Smav			cnt++;
5042182999Smav	}
5043182999Smav	if (sc->num_chans == 0) {
5044182999Smav		sc->chans = (struct hdac_chan *)malloc(
5045182999Smav		    sizeof(struct hdac_chan) * cnt,
5046182999Smav		    M_HDAC, M_ZERO | M_NOWAIT);
5047182999Smav		if (sc->chans == NULL) {
5048182999Smav			device_printf(devinfo->codec->sc->dev,
5049182999Smav			    "Channels memory allocation failed!\n");
5050182999Smav			return;
5051182999Smav		}
5052182999Smav	} else {
5053182999Smav		sc->chans = (struct hdac_chan *)realloc(sc->chans,
5054183810Smav		    sizeof(struct hdac_chan) * (sc->num_chans + cnt),
5055182999Smav		    M_HDAC, M_ZERO | M_NOWAIT);
5056182999Smav		if (sc->chans == NULL) {
5057182999Smav			sc->num_chans = 0;
5058182999Smav			device_printf(devinfo->codec->sc->dev,
5059182999Smav			    "Channels memory allocation failed!\n");
5060182999Smav			return;
5061182999Smav		}
5062182999Smav	}
5063182999Smav	free = sc->num_chans;
5064182999Smav	sc->num_chans += cnt;
5065162922Sariff
5066182999Smav	for (j = free; j < free + cnt; j++) {
5067182999Smav		devinfo->codec->sc->chans[j].devinfo = devinfo;
5068182999Smav		devinfo->codec->sc->chans[j].as = -1;
5069182999Smav	}
5070162922Sariff
5071182999Smav	/* Assign associations in order of their numbers, */
5072182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5073182999Smav		if (as[j].enable == 0)
5074182999Smav			continue;
5075182999Smav
5076182999Smav		as[j].chan = free;
5077182999Smav		devinfo->codec->sc->chans[free].as = j;
5078182999Smav		if (as[j].dir == HDA_CTL_IN) {
5079182999Smav			devinfo->codec->sc->chans[free].dir = PCMDIR_REC;
5080182999Smav			devinfo->function.audio.reccnt++;
5081182999Smav		} else {
5082182999Smav			devinfo->codec->sc->chans[free].dir = PCMDIR_PLAY;
5083182999Smav			devinfo->function.audio.playcnt++;
5084182999Smav		}
5085182999Smav		hdac_pcmchannel_setup(&devinfo->codec->sc->chans[free]);
5086182999Smav		free++;
5087182999Smav	}
5088182999Smav}
5089162922Sariff
5090182999Smavstatic void
5091182999Smavhdac_audio_disable_nonaudio(struct hdac_devinfo *devinfo)
5092182999Smav{
5093182999Smav	struct hdac_widget *w;
5094182999Smav	int i;
5095182999Smav
5096182999Smav	/* Disable power and volume widgets. */
5097182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5098182999Smav		w = hdac_widget_get(devinfo, i);
5099182999Smav		if (w == NULL || w->enable == 0)
5100182999Smav			continue;
5101182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET ||
5102182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET) {
5103182999Smav			w->enable = 0;
5104183097Smav			HDA_BOOTHVERBOSE(
5105182999Smav				device_printf(devinfo->codec->sc->dev,
5106182999Smav				    " Disabling nid %d due to it's"
5107182999Smav				    " non-audio type.\n",
5108182999Smav				    w->nid);
5109182999Smav			);
5110162922Sariff		}
5111182999Smav	}
5112182999Smav}
5113182999Smav
5114182999Smavstatic void
5115182999Smavhdac_audio_disable_useless(struct hdac_devinfo *devinfo)
5116182999Smav{
5117182999Smav	struct hdac_widget *w, *cw;
5118182999Smav	struct hdac_audio_ctl *ctl;
5119182999Smav	int done, found, i, j, k;
5120182999Smav
5121182999Smav	/* Disable useless pins. */
5122182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5123182999Smav		w = hdac_widget_get(devinfo, i);
5124182999Smav		if (w == NULL || w->enable == 0)
5125182999Smav			continue;
5126184991Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
5127184991Smav			if ((w->wclass.pin.config &
5128184991Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
5129184991Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) {
5130184991Smav				w->enable = 0;
5131184991Smav				HDA_BOOTHVERBOSE(
5132184991Smav					device_printf(devinfo->codec->sc->dev,
5133184991Smav					    " Disabling pin nid %d due"
5134184991Smav					    " to None connectivity.\n",
5135184991Smav					    w->nid);
5136184991Smav				);
5137184991Smav			} else if ((w->wclass.pin.config &
5138184991Smav			    HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK) == 0) {
5139184991Smav				w->enable = 0;
5140184991Smav				HDA_BOOTHVERBOSE(
5141184991Smav					device_printf(devinfo->codec->sc->dev,
5142184991Smav					    " Disabling unassociated"
5143184991Smav					    " pin nid %d.\n",
5144184991Smav					    w->nid);
5145184991Smav				);
5146184991Smav			}
5147182999Smav		}
5148182999Smav	}
5149182999Smav	do {
5150182999Smav		done = 1;
5151182999Smav		/* Disable and mute controls for disabled widgets. */
5152162922Sariff		i = 0;
5153162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5154182999Smav			if (ctl->enable == 0)
5155162922Sariff				continue;
5156182999Smav			if (ctl->widget->enable == 0 ||
5157182999Smav			    (ctl->childwidget != NULL &&
5158182999Smav			    ctl->childwidget->enable == 0)) {
5159182999Smav				ctl->forcemute = 1;
5160182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5161182999Smav				ctl->left = 0;
5162182999Smav				ctl->right = 0;
5163182999Smav				ctl->enable = 0;
5164182999Smav				if (ctl->ndir == HDA_CTL_IN)
5165182999Smav					ctl->widget->connsenable[ctl->index] = 0;
5166182999Smav				done = 0;
5167183097Smav				HDA_BOOTHVERBOSE(
5168182999Smav					device_printf(devinfo->codec->sc->dev,
5169182999Smav					    " Disabling ctl %d nid %d cnid %d due"
5170182999Smav					    " to disabled widget.\n", i,
5171182999Smav					    ctl->widget->nid,
5172182999Smav					    (ctl->childwidget != NULL)?
5173182999Smav					    ctl->childwidget->nid:-1);
5174182999Smav				);
5175182999Smav			}
5176182999Smav		}
5177182999Smav		/* Disable useless widgets. */
5178182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5179182999Smav			w = hdac_widget_get(devinfo, i);
5180182999Smav			if (w == NULL || w->enable == 0)
5181182999Smav				continue;
5182182999Smav			/* Disable inputs with disabled child widgets. */
5183182999Smav			for (j = 0; j < w->nconns; j++) {
5184182999Smav				if (w->connsenable[j]) {
5185182999Smav					cw = hdac_widget_get(devinfo, w->conns[j]);
5186182999Smav					if (cw == NULL || cw->enable == 0) {
5187182999Smav						w->connsenable[j] = 0;
5188183097Smav						HDA_BOOTHVERBOSE(
5189182999Smav							device_printf(devinfo->codec->sc->dev,
5190182999Smav							    " Disabling nid %d connection %d due"
5191182999Smav							    " to disabled child widget.\n",
5192182999Smav							    i, j);
5193182999Smav						);
5194163057Sariff					}
5195163057Sariff				}
5196162922Sariff			}
5197182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5198182999Smav			    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5199162922Sariff				continue;
5200182999Smav			/* Disable mixers and selectors without inputs. */
5201182999Smav			found = 0;
5202182999Smav			for (j = 0; j < w->nconns; j++) {
5203182999Smav				if (w->connsenable[j]) {
5204182999Smav					found = 1;
5205162922Sariff					break;
5206162922Sariff				}
5207182999Smav			}
5208182999Smav			if (found == 0) {
5209182999Smav				w->enable = 0;
5210182999Smav				done = 0;
5211183097Smav				HDA_BOOTHVERBOSE(
5212182999Smav					device_printf(devinfo->codec->sc->dev,
5213182999Smav					    " Disabling nid %d due to all it's"
5214182999Smav					    " inputs disabled.\n", w->nid);
5215182999Smav				);
5216182999Smav			}
5217182999Smav			/* Disable nodes without consumers. */
5218182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5219182999Smav			    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5220182999Smav				continue;
5221182999Smav			found = 0;
5222182999Smav			for (k = devinfo->startnode; k < devinfo->endnode; k++) {
5223182999Smav				cw = hdac_widget_get(devinfo, k);
5224182999Smav				if (cw == NULL || cw->enable == 0)
5225182999Smav					continue;
5226182999Smav				for (j = 0; j < cw->nconns; j++) {
5227182999Smav					if (cw->connsenable[j] && cw->conns[j] == i) {
5228182999Smav						found = 1;
5229182999Smav						break;
5230182999Smav					}
5231162922Sariff				}
5232162922Sariff			}
5233182999Smav			if (found == 0) {
5234182999Smav				w->enable = 0;
5235182999Smav				done = 0;
5236183097Smav				HDA_BOOTHVERBOSE(
5237182999Smav					device_printf(devinfo->codec->sc->dev,
5238182999Smav					    " Disabling nid %d due to all it's"
5239182999Smav					    " consumers disabled.\n", w->nid);
5240182999Smav				);
5241182999Smav			}
5242162922Sariff		}
5243182999Smav	} while (done == 0);
5244182999Smav
5245182999Smav}
5246182999Smav
5247182999Smavstatic void
5248182999Smavhdac_audio_disable_unas(struct hdac_devinfo *devinfo)
5249182999Smav{
5250182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5251182999Smav	struct hdac_widget *w, *cw;
5252182999Smav	struct hdac_audio_ctl *ctl;
5253182999Smav	int i, j, k;
5254182999Smav
5255182999Smav	/* Disable unassosiated widgets. */
5256182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5257182999Smav		w = hdac_widget_get(devinfo, i);
5258182999Smav		if (w == NULL || w->enable == 0)
5259182999Smav			continue;
5260182999Smav		if (w->bindas == -1) {
5261182999Smav			w->enable = 0;
5262183097Smav			HDA_BOOTHVERBOSE(
5263182999Smav				device_printf(devinfo->codec->sc->dev,
5264182999Smav				    " Disabling unassociated nid %d.\n",
5265182999Smav				    w->nid);
5266182999Smav			);
5267182999Smav		}
5268182999Smav	}
5269182999Smav	/* Disable input connections on input pin and
5270182999Smav	 * output on output. */
5271182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5272182999Smav		w = hdac_widget_get(devinfo, i);
5273182999Smav		if (w == NULL || w->enable == 0)
5274182999Smav			continue;
5275182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5276182999Smav			continue;
5277182999Smav		if (w->bindas < 0)
5278182999Smav			continue;
5279182999Smav		if (as[w->bindas].dir == HDA_CTL_IN) {
5280182999Smav			for (j = 0; j < w->nconns; j++) {
5281182999Smav				if (w->connsenable[j] == 0)
5282182999Smav					continue;
5283182999Smav				w->connsenable[j] = 0;
5284183097Smav				HDA_BOOTHVERBOSE(
5285182999Smav					device_printf(devinfo->codec->sc->dev,
5286182999Smav					    " Disabling connection to input pin "
5287182999Smav					    "nid %d conn %d.\n",
5288182999Smav					    i, j);
5289182999Smav				);
5290162922Sariff			}
5291182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5292182999Smav			    HDA_CTL_IN, -1, 1);
5293182999Smav			if (ctl && ctl->enable) {
5294182999Smav				ctl->forcemute = 1;
5295182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5296182999Smav				ctl->left = 0;
5297182999Smav				ctl->right = 0;
5298182999Smav				ctl->enable = 0;
5299182999Smav			}
5300182999Smav		} else {
5301182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5302182999Smav			    HDA_CTL_OUT, -1, 1);
5303182999Smav			if (ctl && ctl->enable) {
5304182999Smav				ctl->forcemute = 1;
5305182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5306182999Smav				ctl->left = 0;
5307182999Smav				ctl->right = 0;
5308182999Smav				ctl->enable = 0;
5309182999Smav			}
5310182999Smav			for (k = devinfo->startnode; k < devinfo->endnode; k++) {
5311182999Smav				cw = hdac_widget_get(devinfo, k);
5312182999Smav				if (cw == NULL || cw->enable == 0)
5313182999Smav					continue;
5314182999Smav				for (j = 0; j < cw->nconns; j++) {
5315182999Smav					if (cw->connsenable[j] && cw->conns[j] == i) {
5316182999Smav						cw->connsenable[j] = 0;
5317183097Smav						HDA_BOOTHVERBOSE(
5318182999Smav							device_printf(devinfo->codec->sc->dev,
5319182999Smav							    " Disabling connection from output pin "
5320182999Smav							    "nid %d conn %d cnid %d.\n",
5321182999Smav							    k, j, i);
5322182999Smav						);
5323182999Smav						if (cw->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5324182999Smav						    cw->nconns > 1)
5325182999Smav							continue;
5326182999Smav						ctl = hdac_audio_ctl_amp_get(devinfo, k,
5327182999Smav		    				    HDA_CTL_IN, j, 1);
5328182999Smav						if (ctl && ctl->enable) {
5329182999Smav							ctl->forcemute = 1;
5330182999Smav							ctl->muted = HDA_AMP_MUTE_ALL;
5331182999Smav							ctl->left = 0;
5332182999Smav							ctl->right = 0;
5333182999Smav							ctl->enable = 0;
5334182999Smav						}
5335182999Smav					}
5336182999Smav				}
5337182999Smav			}
5338162922Sariff		}
5339162922Sariff	}
5340162922Sariff}
5341162922Sariff
5342182999Smavstatic void
5343182999Smavhdac_audio_disable_notselected(struct hdac_devinfo *devinfo)
5344162922Sariff{
5345182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5346182999Smav	struct hdac_widget *w;
5347182999Smav	int i, j;
5348182999Smav
5349182999Smav	/* On playback path we can safely disable all unseleted inputs. */
5350182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5351182999Smav		w = hdac_widget_get(devinfo, i);
5352182999Smav		if (w == NULL || w->enable == 0)
5353182999Smav			continue;
5354182999Smav		if (w->nconns <= 1)
5355182999Smav			continue;
5356182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5357182999Smav			continue;
5358182999Smav		if (w->bindas < 0 || as[w->bindas].dir == HDA_CTL_IN)
5359182999Smav			continue;
5360182999Smav		for (j = 0; j < w->nconns; j++) {
5361182999Smav			if (w->connsenable[j] == 0)
5362182999Smav				continue;
5363182999Smav			if (w->selconn < 0 || w->selconn == j)
5364182999Smav				continue;
5365182999Smav			w->connsenable[j] = 0;
5366183097Smav			HDA_BOOTHVERBOSE(
5367182999Smav				device_printf(devinfo->codec->sc->dev,
5368182999Smav				    " Disabling unselected connection "
5369182999Smav				    "nid %d conn %d.\n",
5370182999Smav				    i, j);
5371182999Smav			);
5372182999Smav		}
5373182999Smav	}
5374182999Smav}
5375182999Smav
5376182999Smavstatic void
5377182999Smavhdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
5378182999Smav{
5379162922Sariff	struct hdac_widget *w, *cw;
5380162922Sariff	struct hdac_audio_ctl *ctl;
5381182999Smav	int i, j;
5382162922Sariff
5383182999Smav	/* Disable crossassociatement connections. */
5384182999Smav	/* ... using selectors */
5385182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5386182999Smav		w = hdac_widget_get(devinfo, i);
5387182999Smav		if (w == NULL || w->enable == 0)
5388182999Smav			continue;
5389182999Smav		if (w->nconns <= 1)
5390182999Smav			continue;
5391182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5392182999Smav			continue;
5393182999Smav		if (w->bindas == -2)
5394182999Smav			continue;
5395182999Smav		for (j = 0; j < w->nconns; j++) {
5396182999Smav			if (w->connsenable[j] == 0)
5397182999Smav				continue;
5398182999Smav			cw = hdac_widget_get(devinfo, w->conns[j]);
5399182999Smav			if (cw == NULL || w->enable == 0)
5400182999Smav				continue;
5401182999Smav			if (w->bindas == cw->bindas || cw->bindas == -2)
5402182999Smav				continue;
5403182999Smav			w->connsenable[j] = 0;
5404183097Smav			HDA_BOOTHVERBOSE(
5405182999Smav				device_printf(devinfo->codec->sc->dev,
5406182999Smav				    " Disabling crossassociatement connection "
5407182999Smav				    "nid %d conn %d cnid %d.\n",
5408182999Smav				    i, j, cw->nid);
5409182999Smav			);
5410182999Smav		}
5411182999Smav	}
5412182999Smav	/* ... using controls */
5413182999Smav	i = 0;
5414182999Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5415182999Smav		if (ctl->enable == 0 || ctl->childwidget == NULL)
5416182999Smav			continue;
5417182999Smav		if (ctl->widget->bindas == -2 ||
5418182999Smav		    ctl->childwidget->bindas == -2)
5419182999Smav			continue;
5420182999Smav		if (ctl->widget->bindas != ctl->childwidget->bindas) {
5421182999Smav			ctl->forcemute = 1;
5422182999Smav			ctl->muted = HDA_AMP_MUTE_ALL;
5423182999Smav			ctl->left = 0;
5424182999Smav			ctl->right = 0;
5425182999Smav			ctl->enable = 0;
5426182999Smav			if (ctl->ndir == HDA_CTL_IN)
5427182999Smav				ctl->widget->connsenable[ctl->index] = 0;
5428183097Smav			HDA_BOOTHVERBOSE(
5429182999Smav				device_printf(devinfo->codec->sc->dev,
5430182999Smav				    " Disabling crossassociatement connection "
5431182999Smav				    "ctl %d nid %d cnid %d.\n", i,
5432182999Smav				    ctl->widget->nid,
5433182999Smav				    ctl->childwidget->nid);
5434182999Smav			);
5435182999Smav		}
5436182999Smav	}
5437182999Smav
5438182999Smav}
5439182999Smav
5440182999Smav#define HDA_CTL_GIVE(ctl)	((ctl)->step?1:0)
5441182999Smav
5442182999Smav/*
5443182999Smav * Find controls to control amplification for source.
5444182999Smav */
5445182999Smavstatic int
5446182999Smavhdac_audio_ctl_source_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
5447182999Smav    int ossdev, int ctlable, int depth, int need)
5448182999Smav{
5449182999Smav	struct hdac_widget *w, *wc;
5450182999Smav	struct hdac_audio_ctl *ctl;
5451182999Smav	int i, j, conns = 0, rneed;
5452182999Smav
5453162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
5454182999Smav		return (need);
5455162922Sariff
5456162922Sariff	w = hdac_widget_get(devinfo, nid);
5457162922Sariff	if (w == NULL || w->enable == 0)
5458182999Smav		return (need);
5459182999Smav
5460182999Smav	/* Count number of active inputs. */
5461182999Smav	if (depth > 0) {
5462182999Smav		for (j = 0; j < w->nconns; j++) {
5463182999Smav			if (w->connsenable[j])
5464182999Smav				conns++;
5465162922Sariff		}
5466162922Sariff	}
5467182999Smav
5468182999Smav	/* If this is not a first step - use input mixer.
5469182999Smav	   Pins have common input ctl so care must be taken. */
5470182999Smav	if (depth > 0 && ctlable && (conns == 1 ||
5471182999Smav	    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)) {
5472182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_IN,
5473182999Smav		    index, 1);
5474182999Smav		if (ctl) {
5475182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5476182999Smav				ctl->ossmask |= (1 << ossdev);
5477182999Smav			else
5478182999Smav				ctl->possmask |= (1 << ossdev);
5479182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5480182999Smav		}
5481182999Smav	}
5482182999Smav
5483182999Smav	/* If widget has own ossdev - not traverse it.
5484182999Smav	   It will be traversed on it's own. */
5485182999Smav	if (w->ossdev >= 0 && depth > 0)
5486182999Smav		return (need);
5487182999Smav
5488182999Smav	/* We must not traverse pin */
5489182999Smav	if ((w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
5490182999Smav	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
5491182999Smav	    depth > 0)
5492182999Smav		return (need);
5493182999Smav
5494182999Smav	/* record that this widget exports such signal, */
5495182999Smav	w->ossmask |= (1 << ossdev);
5496182999Smav
5497182999Smav	/* If signals mixed, we can't assign controls farther.
5498182999Smav	 * Ignore this on depth zero. Caller must knows why.
5499182999Smav	 * Ignore this for static selectors if this input selected.
5500182999Smav	 */
5501182999Smav	if (conns > 1)
5502182999Smav		ctlable = 0;
5503182999Smav
5504182999Smav	if (ctlable) {
5505182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_OUT, -1, 1);
5506182999Smav		if (ctl) {
5507182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5508182999Smav				ctl->ossmask |= (1 << ossdev);
5509182999Smav			else
5510182999Smav				ctl->possmask |= (1 << ossdev);
5511182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5512182999Smav		}
5513182999Smav	}
5514182999Smav
5515182999Smav	rneed = 0;
5516182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5517182999Smav		wc = hdac_widget_get(devinfo, i);
5518182999Smav		if (wc == NULL || wc->enable == 0)
5519162922Sariff			continue;
5520182999Smav		for (j = 0; j < wc->nconns; j++) {
5521182999Smav			if (wc->connsenable[j] && wc->conns[j] == nid) {
5522182999Smav				rneed |= hdac_audio_ctl_source_amp(devinfo,
5523182999Smav				    wc->nid, j, ossdev, ctlable, depth + 1, need);
5524182999Smav			}
5525162922Sariff		}
5526162922Sariff	}
5527182999Smav	rneed &= need;
5528182999Smav
5529182999Smav	return (rneed);
5530162922Sariff}
5531162922Sariff
5532182999Smav/*
5533182999Smav * Find controls to control amplification for destination.
5534182999Smav */
5535182999Smavstatic void
5536182999Smavhdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid,
5537182999Smav    int ossdev, int depth, int need)
5538162922Sariff{
5539182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5540182999Smav	struct hdac_widget *w, *wc;
5541182999Smav	struct hdac_audio_ctl *ctl;
5542182999Smav	int i, j, consumers;
5543182999Smav
5544162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
5545182999Smav		return;
5546162922Sariff
5547162922Sariff	w = hdac_widget_get(devinfo, nid);
5548162922Sariff	if (w == NULL || w->enable == 0)
5549182999Smav		return;
5550182999Smav
5551182999Smav	if (depth > 0) {
5552182999Smav		/* If this node produce output for several consumers,
5553182999Smav		   we can't touch it. */
5554182999Smav		consumers = 0;
5555182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5556182999Smav			wc = hdac_widget_get(devinfo, i);
5557182999Smav			if (wc == NULL || wc->enable == 0)
5558182999Smav				continue;
5559182999Smav			for (j = 0; j < wc->nconns; j++) {
5560182999Smav				if (wc->connsenable[j] && wc->conns[j] == nid)
5561182999Smav					consumers++;
5562182999Smav			}
5563182999Smav		}
5564182999Smav		/* The only exception is if real HP redirection is configured
5565182999Smav		   and this is a duplication point.
5566182999Smav		   XXX: Actually exception is not completely correct.
5567182999Smav		   XXX: Duplication point check is not perfect. */
5568182999Smav		if ((consumers == 2 && (w->bindas < 0 ||
5569182999Smav		    as[w->bindas].hpredir < 0 || as[w->bindas].fakeredir ||
5570182999Smav		    (w->bindseqmask & (1 << 15)) == 0)) ||
5571182999Smav		    consumers > 2)
5572182999Smav			return;
5573182999Smav
5574182999Smav		/* Else use it's output mixer. */
5575182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5576182999Smav		    HDA_CTL_OUT, -1, 1);
5577182999Smav		if (ctl) {
5578182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5579182999Smav				ctl->ossmask |= (1 << ossdev);
5580182999Smav			else
5581182999Smav				ctl->possmask |= (1 << ossdev);
5582182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5583182999Smav		}
5584182999Smav	}
5585182999Smav
5586182999Smav	/* We must not traverse pin */
5587182999Smav	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5588182999Smav	    depth > 0)
5589182999Smav		return;
5590182999Smav
5591162922Sariff	for (i = 0; i < w->nconns; i++) {
5592182999Smav		int tneed = need;
5593182999Smav		if (w->connsenable[i] == 0)
5594162922Sariff			continue;
5595182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5596182999Smav		    HDA_CTL_IN, i, 1);
5597182999Smav		if (ctl) {
5598182999Smav			if (HDA_CTL_GIVE(ctl) & tneed)
5599182999Smav				ctl->ossmask |= (1 << ossdev);
5600182999Smav			else
5601182999Smav				ctl->possmask |= (1 << ossdev);
5602182999Smav			tneed &= ~HDA_CTL_GIVE(ctl);
5603162922Sariff		}
5604182999Smav		hdac_audio_ctl_dest_amp(devinfo, w->conns[i], ossdev,
5605182999Smav		    depth + 1, tneed);
5606162922Sariff	}
5607162922Sariff}
5608162922Sariff
5609182999Smav/*
5610182999Smav * Assign OSS names to sound sources
5611182999Smav */
5612182999Smavstatic void
5613182999Smavhdac_audio_assign_names(struct hdac_devinfo *devinfo)
5614162922Sariff{
5615182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5616182999Smav	struct hdac_widget *w;
5617182999Smav	int i, j;
5618182999Smav	int type = -1, use, used = 0;
5619182999Smav	static const int types[7][13] = {
5620182999Smav	    { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
5621182999Smav	      SOUND_MIXER_LINE3, -1 },	/* line */
5622182999Smav	    { SOUND_MIXER_MONITOR, SOUND_MIXER_MIC, -1 }, /* int mic */
5623182999Smav	    { SOUND_MIXER_MIC, SOUND_MIXER_MONITOR, -1 }, /* ext mic */
5624182999Smav	    { SOUND_MIXER_CD, -1 },	/* cd */
5625182999Smav	    { SOUND_MIXER_SPEAKER, -1 },	/* speaker */
5626182999Smav	    { SOUND_MIXER_DIGITAL1, SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3,
5627182999Smav	      -1 },	/* digital */
5628182999Smav	    { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
5629182999Smav	      SOUND_MIXER_LINE3, SOUND_MIXER_PHONEIN, SOUND_MIXER_PHONEOUT,
5630182999Smav	      SOUND_MIXER_VIDEO, SOUND_MIXER_RADIO, SOUND_MIXER_DIGITAL1,
5631182999Smav	      SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3, SOUND_MIXER_MONITOR,
5632182999Smav	      -1 }	/* others */
5633182999Smav	};
5634162922Sariff
5635182999Smav	/* Surely known names */
5636162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5637162922Sariff		w = hdac_widget_get(devinfo, i);
5638162922Sariff		if (w == NULL || w->enable == 0)
5639162922Sariff			continue;
5640182999Smav		if (w->bindas == -1)
5641182999Smav			continue;
5642182999Smav		use = -1;
5643182999Smav		switch (w->type) {
5644182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
5645182999Smav			if (as[w->bindas].dir == HDA_CTL_OUT)
5646182999Smav				break;
5647182999Smav			type = -1;
5648182999Smav			switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
5649182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
5650182999Smav				type = 0;
5651182999Smav				break;
5652182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
5653182999Smav				if ((w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK)
5654182999Smav				    == HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
5655182999Smav					break;
5656182999Smav				type = 1;
5657182999Smav				break;
5658182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
5659182999Smav				type = 3;
5660182999Smav				break;
5661182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
5662182999Smav				type = 4;
5663182999Smav				break;
5664182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
5665182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
5666182999Smav				type = 5;
5667182999Smav				break;
5668182999Smav			}
5669182999Smav			if (type == -1)
5670182999Smav				break;
5671182999Smav			j = 0;
5672182999Smav			while (types[type][j] >= 0 &&
5673182999Smav			    (used & (1 << types[type][j])) != 0) {
5674182999Smav				j++;
5675182999Smav			}
5676182999Smav			if (types[type][j] >= 0)
5677182999Smav				use = types[type][j];
5678182999Smav			break;
5679182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
5680182999Smav			use = SOUND_MIXER_PCM;
5681182999Smav			break;
5682182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
5683182999Smav			use = SOUND_MIXER_SPEAKER;
5684182999Smav			break;
5685182999Smav		default:
5686182999Smav			break;
5687182999Smav		}
5688182999Smav		if (use >= 0) {
5689182999Smav			w->ossdev = use;
5690182999Smav			used |= (1 << use);
5691182999Smav		}
5692182999Smav	}
5693182999Smav	/* Semi-known names */
5694182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5695182999Smav		w = hdac_widget_get(devinfo, i);
5696182999Smav		if (w == NULL || w->enable == 0)
5697182999Smav			continue;
5698182999Smav		if (w->ossdev >= 0)
5699182999Smav			continue;
5700182999Smav		if (w->bindas == -1)
5701182999Smav			continue;
5702162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5703162922Sariff			continue;
5704182999Smav		if (as[w->bindas].dir == HDA_CTL_OUT)
5705162922Sariff			continue;
5706182999Smav		type = -1;
5707182999Smav		switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
5708182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
5709182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
5710182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
5711182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
5712182999Smav			type = 0;
5713182999Smav			break;
5714182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
5715182999Smav			type = 2;
5716182999Smav			break;
5717182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
5718182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
5719182999Smav			type = 5;
5720182999Smav			break;
5721182999Smav		}
5722182999Smav		if (type == -1)
5723182999Smav			break;
5724182999Smav		j = 0;
5725182999Smav		while (types[type][j] >= 0 &&
5726182999Smav		    (used & (1 << types[type][j])) != 0) {
5727182999Smav			j++;
5728182999Smav		}
5729182999Smav		if (types[type][j] >= 0) {
5730182999Smav			w->ossdev = types[type][j];
5731182999Smav			used |= (1 << types[type][j]);
5732182999Smav		}
5733182999Smav	}
5734182999Smav	/* Others */
5735182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5736182999Smav		w = hdac_widget_get(devinfo, i);
5737182999Smav		if (w == NULL || w->enable == 0)
5738162922Sariff			continue;
5739182999Smav		if (w->ossdev >= 0)
5740182999Smav			continue;
5741182999Smav		if (w->bindas == -1)
5742182999Smav			continue;
5743182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5744182999Smav			continue;
5745182999Smav		if (as[w->bindas].dir == HDA_CTL_OUT)
5746182999Smav			continue;
5747182999Smav		j = 0;
5748182999Smav		while (types[6][j] >= 0 &&
5749182999Smav		    (used & (1 << types[6][j])) != 0) {
5750182999Smav			j++;
5751162922Sariff		}
5752182999Smav		if (types[6][j] >= 0) {
5753182999Smav			w->ossdev = types[6][j];
5754182999Smav			used |= (1 << types[6][j]);
5755182999Smav		}
5756162922Sariff	}
5757162922Sariff}
5758162922Sariff
5759162922Sariffstatic void
5760162922Sariffhdac_audio_build_tree(struct hdac_devinfo *devinfo)
5761162922Sariff{
5762182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5763182999Smav	int j, res;
5764162922Sariff
5765182999Smav	/* Trace all associations in order of their numbers, */
5766182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5767182999Smav		if (as[j].enable == 0)
5768182999Smav			continue;
5769163057Sariff		HDA_BOOTVERBOSE(
5770162922Sariff			device_printf(devinfo->codec->sc->dev,
5771182999Smav			    "Tracing association %d (%d)\n", j, as[j].index);
5772162922Sariff		);
5773182999Smav		if (as[j].dir == HDA_CTL_OUT) {
5774182999Smavretry:
5775182999Smav			res = hdac_audio_trace_as_out(devinfo, j, 0);
5776182999Smav			if (res == 0 && as[j].hpredir >= 0 &&
5777182999Smav			    as[j].fakeredir == 0) {
5778182999Smav				/* If codec can't do analog HP redirection
5779182999Smav				   try to make it using one more DAC. */
5780182999Smav				as[j].fakeredir = 1;
5781182999Smav				goto retry;
5782182999Smav			}
5783182999Smav		} else {
5784182999Smav			res = hdac_audio_trace_as_in(devinfo, j);
5785182999Smav		}
5786182999Smav		if (res) {
5787182999Smav			HDA_BOOTVERBOSE(
5788182999Smav				device_printf(devinfo->codec->sc->dev,
5789182999Smav				    "Association %d (%d) trace succeded\n",
5790182999Smav				    j, as[j].index);
5791182999Smav			);
5792182999Smav		} else {
5793182999Smav			HDA_BOOTVERBOSE(
5794182999Smav				device_printf(devinfo->codec->sc->dev,
5795182999Smav				    "Association %d (%d) trace failed\n",
5796182999Smav				    j, as[j].index);
5797182999Smav			);
5798182999Smav			as[j].enable = 0;
5799182999Smav		}
5800162922Sariff	}
5801162922Sariff
5802182999Smav	/* Trace mixer and beeper pseudo associations. */
5803182999Smav	hdac_audio_trace_as_extra(devinfo);
5804182999Smav}
5805162922Sariff
5806182999Smavstatic void
5807182999Smavhdac_audio_assign_mixers(struct hdac_devinfo *devinfo)
5808182999Smav{
5809182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5810182999Smav	struct hdac_audio_ctl *ctl;
5811182999Smav	struct hdac_widget *w;
5812182999Smav	int i;
5813162922Sariff
5814182999Smav	/* Assign mixers to the tree. */
5815162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5816162922Sariff		w = hdac_widget_get(devinfo, i);
5817162922Sariff		if (w == NULL || w->enable == 0)
5818162922Sariff			continue;
5819182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
5820182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET ||
5821182999Smav		    (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5822182999Smav		    as[w->bindas].dir == HDA_CTL_IN)) {
5823182999Smav			if (w->ossdev < 0)
5824182999Smav				continue;
5825182999Smav			hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
5826182999Smav			    w->ossdev, 1, 0, 1);
5827182999Smav		} else if ((w->pflags & HDA_ADC_MONITOR) != 0) {
5828182999Smav			if (w->ossdev < 0)
5829182999Smav				continue;
5830182999Smav			if (hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
5831182999Smav			    w->ossdev, 1, 0, 1)) {
5832182999Smav				/* If we are unable to control input monitor
5833182999Smav				   as source - try to control it as destination. */
5834182999Smav				hdac_audio_ctl_dest_amp(devinfo, w->nid,
5835182999Smav				    w->ossdev, 0, 1);
5836162922Sariff			}
5837182999Smav		} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
5838182999Smav			hdac_audio_ctl_dest_amp(devinfo, w->nid,
5839182999Smav			    SOUND_MIXER_RECLEV, 0, 1);
5840182999Smav		} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5841182999Smav		    as[w->bindas].dir == HDA_CTL_OUT) {
5842182999Smav			hdac_audio_ctl_dest_amp(devinfo, w->nid,
5843182999Smav			    SOUND_MIXER_VOLUME, 0, 1);
5844162922Sariff		}
5845162922Sariff	}
5846182999Smav	/* Treat unrequired as possible. */
5847182999Smav	i = 0;
5848182999Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5849182999Smav		if (ctl->ossmask == 0)
5850182999Smav			ctl->ossmask = ctl->possmask;
5851182999Smav	}
5852182999Smav}
5853162922Sariff
5854182999Smavstatic void
5855182999Smavhdac_audio_prepare_pin_ctrl(struct hdac_devinfo *devinfo)
5856182999Smav{
5857182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5858182999Smav	struct hdac_widget *w;
5859182999Smav	uint32_t pincap;
5860182999Smav	int i;
5861182999Smav
5862182999Smav	for (i = 0; i < devinfo->nodecnt; i++) {
5863182999Smav		w = &devinfo->widget[i];
5864182999Smav		if (w == NULL)
5865162922Sariff			continue;
5866182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5867162922Sariff			continue;
5868182999Smav
5869182999Smav		pincap = w->wclass.pin.cap;
5870182999Smav
5871182999Smav		/* Disable everything. */
5872182999Smav		w->wclass.pin.ctrl &= ~(
5873182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
5874182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
5875182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
5876182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
5877182999Smav
5878182999Smav		if (w->enable == 0 ||
5879182999Smav		    w->bindas < 0 || as[w->bindas].enable == 0) {
5880182999Smav			/* Pin is unused so left it disabled. */
5881182999Smav			continue;
5882182999Smav		} else if (as[w->bindas].dir == HDA_CTL_IN) {
5883182999Smav			/* Input pin, configure for input. */
5884182999Smav			if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
5885182999Smav				w->wclass.pin.ctrl |=
5886182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
5887182999Smav
5888182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) &&
5889182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5890182999Smav				w->wclass.pin.ctrl |=
5891182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5892182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
5893182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) &&
5894182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5895182999Smav				w->wclass.pin.ctrl |=
5896182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5897182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
5898182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) &&
5899182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5900182999Smav				w->wclass.pin.ctrl |=
5901182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5902182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
5903182999Smav		} else {
5904182999Smav			/* Output pin, configure for output. */
5905182999Smav			if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
5906182999Smav				w->wclass.pin.ctrl |=
5907182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
5908182999Smav
5909182999Smav			if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap) &&
5910182999Smav			    (w->wclass.pin.config &
5911182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
5912182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
5913182999Smav				w->wclass.pin.ctrl |=
5914182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
5915182999Smav
5916182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) &&
5917182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5918182999Smav				w->wclass.pin.ctrl |=
5919182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5920182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
5921182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) &&
5922182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5923182999Smav				w->wclass.pin.ctrl |=
5924182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5925182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
5926182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) &&
5927182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5928182999Smav				w->wclass.pin.ctrl |=
5929182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5930182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
5931182999Smav		}
5932162922Sariff	}
5933162922Sariff}
5934162922Sariff
5935162922Sariffstatic void
5936182999Smavhdac_audio_commit(struct hdac_devinfo *devinfo)
5937162922Sariff{
5938162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
5939162922Sariff	struct hdac_widget *w;
5940164750Sariff	nid_t cad;
5941182999Smav	uint32_t gdata, gmask, gdir;
5942182999Smav	int commitgpio, numgpio;
5943164750Sariff	int i;
5944162922Sariff
5945162922Sariff	cad = devinfo->codec->cad;
5946162922Sariff
5947182999Smav	if (sc->pci_subvendor == APPLE_INTEL_MAC)
5948182999Smav		hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
5949182999Smav		    0x7e7, 0), cad);
5950169277Sariff
5951182999Smav	gdata = 0;
5952182999Smav	gmask = 0;
5953182999Smav	gdir = 0;
5954182999Smav	commitgpio = 0;
5955164828Sariff
5956182999Smav	numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO(
5957182999Smav	    devinfo->function.audio.gpio);
5958166796Sariff
5959182999Smav	if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
5960182999Smav		commitgpio = (numgpio > 0) ? 1 : 0;
5961182999Smav	else {
5962182999Smav		for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) {
5963182999Smav			if (!(devinfo->function.audio.quirks &
5964182999Smav			    (1 << i)))
5965182999Smav				continue;
5966182999Smav			if (commitgpio == 0) {
5967182999Smav				commitgpio = 1;
5968182999Smav				HDA_BOOTVERBOSE(
5969182999Smav					gdata = hdac_command(sc,
5970182999Smav					    HDA_CMD_GET_GPIO_DATA(cad,
5971182999Smav					    devinfo->nid), cad);
5972182999Smav					gmask = hdac_command(sc,
5973182999Smav					    HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
5974182999Smav					    devinfo->nid), cad);
5975182999Smav					gdir = hdac_command(sc,
5976182999Smav					    HDA_CMD_GET_GPIO_DIRECTION(cad,
5977182999Smav					    devinfo->nid), cad);
5978182999Smav					device_printf(sc->dev,
5979182999Smav					    "GPIO init: data=0x%08x "
5980182999Smav					    "mask=0x%08x dir=0x%08x\n",
5981182999Smav					    gdata, gmask, gdir);
5982182999Smav					gdata = 0;
5983182999Smav					gmask = 0;
5984182999Smav					gdir = 0;
5985182999Smav				);
5986165039Sariff			}
5987182999Smav			gdata |= 1 << i;
5988182999Smav			gmask |= 1 << i;
5989182999Smav			gdir |= 1 << i;
5990165039Sariff		}
5991182999Smav	}
5992165039Sariff
5993182999Smav	if (commitgpio != 0) {
5994182999Smav		HDA_BOOTVERBOSE(
5995182999Smav			device_printf(sc->dev,
5996182999Smav			    "GPIO commit: data=0x%08x mask=0x%08x "
5997182999Smav			    "dir=0x%08x\n",
5998182999Smav			    gdata, gmask, gdir);
5999182999Smav		);
6000182999Smav		hdac_command(sc,
6001182999Smav		    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
6002182999Smav		    gmask), cad);
6003182999Smav		hdac_command(sc,
6004182999Smav		    HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
6005182999Smav		    gdir), cad);
6006182999Smav		hdac_command(sc,
6007182999Smav		    HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
6008182999Smav		    gdata), cad);
6009162922Sariff	}
6010162922Sariff
6011162922Sariff	for (i = 0; i < devinfo->nodecnt; i++) {
6012162922Sariff		w = &devinfo->widget[i];
6013182999Smav		if (w == NULL)
6014162922Sariff			continue;
6015182999Smav		if (w->selconn == -1)
6016182999Smav			w->selconn = 0;
6017182999Smav		if (w->nconns > 0)
6018182999Smav			hdac_widget_connection_select(w, w->selconn);
6019182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
6020162922Sariff			hdac_command(sc,
6021162922Sariff			    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
6022162922Sariff			    w->wclass.pin.ctrl), cad);
6023162922Sariff		}
6024182999Smav		if (w->param.eapdbtl != HDAC_INVALID) {
6025163432Sariff		    	uint32_t val;
6026163432Sariff
6027163432Sariff			val = w->param.eapdbtl;
6028163276Sariff			if (devinfo->function.audio.quirks &
6029163432Sariff			    HDA_QUIRK_EAPDINV)
6030163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
6031162922Sariff			hdac_command(sc,
6032162922Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid,
6033163432Sariff			    val), cad);
6034162922Sariff
6035163276Sariff		}
6036162922Sariff		DELAY(1000);
6037162922Sariff	}
6038162922Sariff}
6039162922Sariff
6040162922Sariffstatic void
6041162922Sariffhdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
6042162922Sariff{
6043162922Sariff	struct hdac_audio_ctl *ctl;
6044182999Smav	int i, z;
6045162922Sariff
6046162922Sariff	i = 0;
6047162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6048182999Smav		if (ctl->enable == 0) {
6049182999Smav			/* Mute disabled controls. */
6050182999Smav			hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_ALL, 0, 0);
6051162922Sariff			continue;
6052162922Sariff		}
6053182999Smav		/* Init controls to 0dB amplification. */
6054182999Smav		z = ctl->offset;
6055182999Smav		if (z > ctl->step)
6056182999Smav			z = ctl->step;
6057182999Smav		hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_NONE, z, z);
6058162922Sariff	}
6059162922Sariff}
6060162922Sariff
6061182999Smavstatic void
6062182999Smavhdac_powerup(struct hdac_devinfo *devinfo)
6063182999Smav{
6064182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
6065182999Smav	nid_t cad = devinfo->codec->cad;
6066182999Smav	int i;
6067182999Smav
6068182999Smav	hdac_command(sc,
6069182999Smav	    HDA_CMD_SET_POWER_STATE(cad,
6070182999Smav	    devinfo->nid, HDA_CMD_POWER_STATE_D0),
6071182999Smav	    cad);
6072182999Smav	DELAY(100);
6073182999Smav
6074182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6075182999Smav		hdac_command(sc,
6076182999Smav		    HDA_CMD_SET_POWER_STATE(cad,
6077182999Smav		    i, HDA_CMD_POWER_STATE_D0),
6078182999Smav		    cad);
6079182999Smav	}
6080182999Smav	DELAY(1000);
6081182999Smav}
6082182999Smav
6083162922Sariffstatic int
6084182999Smavhdac_pcmchannel_setup(struct hdac_chan *ch)
6085162922Sariff{
6086182999Smav	struct hdac_devinfo *devinfo = ch->devinfo;
6087182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6088162922Sariff	struct hdac_widget *w;
6089182999Smav	uint32_t cap, fmtcap, pcmcap;
6090182999Smav	int i, j, ret, max;
6091162922Sariff
6092162922Sariff	ch->caps = hdac_caps;
6093162922Sariff	ch->caps.fmtlist = ch->fmtlist;
6094162922Sariff	ch->bit16 = 1;
6095162922Sariff	ch->bit32 = 0;
6096162922Sariff	ch->pcmrates[0] = 48000;
6097162922Sariff	ch->pcmrates[1] = 0;
6098162922Sariff
6099162922Sariff	ret = 0;
6100162922Sariff	fmtcap = devinfo->function.audio.supp_stream_formats;
6101162922Sariff	pcmcap = devinfo->function.audio.supp_pcm_size_rate;
6102162922Sariff	max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1;
6103162922Sariff
6104182999Smav	for (i = 0; i < 16 && ret < max; i++) {
6105182999Smav		/* Check as is correct */
6106182999Smav		if (ch->as < 0)
6107182999Smav			break;
6108182999Smav		/* Cound only present DACs */
6109182999Smav		if (as[ch->as].dacs[i] <= 0)
6110162922Sariff			continue;
6111182999Smav		/* Ignore duplicates */
6112182999Smav		for (j = 0; j < ret; j++) {
6113182999Smav			if (ch->io[j] == as[ch->as].dacs[i])
6114182999Smav				break;
6115182999Smav		}
6116182999Smav		if (j < ret)
6117162922Sariff			continue;
6118182999Smav
6119182999Smav		w = hdac_widget_get(devinfo, as[ch->as].dacs[i]);
6120182999Smav		if (w == NULL || w->enable == 0)
6121182999Smav			continue;
6122182999Smav		if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap))
6123182999Smav			continue;
6124162922Sariff		cap = w->param.supp_stream_formats;
6125182999Smav		/*if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
6126162922Sariff		}*/
6127182999Smav		if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap) &&
6128182999Smav		    !HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
6129162922Sariff			continue;
6130182999Smav		/* Many codec does not declare AC3 support on SPDIF.
6131182999Smav		   I don't beleave that they doesn't support it! */
6132182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6133182999Smav			cap |= HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK;
6134164614Sariff		if (ret == 0) {
6135182999Smav			fmtcap = cap;
6136164614Sariff			pcmcap = w->param.supp_pcm_size_rate;
6137164614Sariff		} else {
6138182999Smav			fmtcap &= cap;
6139164614Sariff			pcmcap &= w->param.supp_pcm_size_rate;
6140164614Sariff		}
6141182999Smav		ch->io[ret++] = as[ch->as].dacs[i];
6142162922Sariff	}
6143162922Sariff	ch->io[ret] = -1;
6144162922Sariff
6145162922Sariff	ch->supp_stream_formats = fmtcap;
6146162922Sariff	ch->supp_pcm_size_rate = pcmcap;
6147162922Sariff
6148162922Sariff	/*
6149162922Sariff	 *  8bit = 0
6150162922Sariff	 * 16bit = 1
6151162922Sariff	 * 20bit = 2
6152162922Sariff	 * 24bit = 3
6153162922Sariff	 * 32bit = 4
6154162922Sariff	 */
6155162922Sariff	if (ret > 0) {
6156162922Sariff		i = 0;
6157182999Smav		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(fmtcap)) {
6158182999Smav			if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(pcmcap))
6159182999Smav				ch->bit16 = 1;
6160182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(pcmcap))
6161182999Smav				ch->bit16 = 0;
6162182999Smav			if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(pcmcap))
6163182999Smav				ch->bit32 = 4;
6164182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(pcmcap))
6165182999Smav				ch->bit32 = 3;
6166182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(pcmcap))
6167182999Smav				ch->bit32 = 2;
6168182999Smav			if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
6169182999Smav				ch->fmtlist[i++] = AFMT_S16_LE;
6170182999Smav			ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
6171182999Smav			if (ch->bit32 > 0) {
6172182999Smav				if (!(devinfo->function.audio.quirks &
6173182999Smav				    HDA_QUIRK_FORCESTEREO))
6174182999Smav					ch->fmtlist[i++] = AFMT_S32_LE;
6175182999Smav				ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
6176182999Smav			}
6177162922Sariff		}
6178182999Smav		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(fmtcap)) {
6179182999Smav			ch->fmtlist[i++] = AFMT_AC3;
6180182999Smav		}
6181162922Sariff		ch->fmtlist[i] = 0;
6182162922Sariff		i = 0;
6183182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(pcmcap))
6184162922Sariff			ch->pcmrates[i++] = 8000;
6185182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(pcmcap))
6186162922Sariff			ch->pcmrates[i++] = 11025;
6187182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(pcmcap))
6188162922Sariff			ch->pcmrates[i++] = 16000;
6189182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(pcmcap))
6190162922Sariff			ch->pcmrates[i++] = 22050;
6191182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(pcmcap))
6192162922Sariff			ch->pcmrates[i++] = 32000;
6193182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(pcmcap))
6194162922Sariff			ch->pcmrates[i++] = 44100;
6195182999Smav		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(pcmcap)) */
6196162922Sariff		ch->pcmrates[i++] = 48000;
6197182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(pcmcap))
6198162922Sariff			ch->pcmrates[i++] = 88200;
6199182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(pcmcap))
6200162922Sariff			ch->pcmrates[i++] = 96000;
6201182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(pcmcap))
6202162922Sariff			ch->pcmrates[i++] = 176400;
6203182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(pcmcap))
6204162922Sariff			ch->pcmrates[i++] = 192000;
6205182999Smav		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(pcmcap)) */
6206162922Sariff		ch->pcmrates[i] = 0;
6207162922Sariff		if (i > 0) {
6208162922Sariff			ch->caps.minspeed = ch->pcmrates[0];
6209162922Sariff			ch->caps.maxspeed = ch->pcmrates[i - 1];
6210162922Sariff		}
6211162922Sariff	}
6212162922Sariff
6213162922Sariff	return (ret);
6214162922Sariff}
6215162922Sariff
6216162922Sariffstatic void
6217182999Smavhdac_dump_ctls(struct hdac_pcm_devinfo *pdevinfo, const char *banner, uint32_t flag)
6218162922Sariff{
6219182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6220162922Sariff	struct hdac_audio_ctl *ctl;
6221162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6222182999Smav	char buf[64];
6223182999Smav	int i, j, printed;
6224162922Sariff
6225162922Sariff	if (flag == 0) {
6226182999Smav		flag = ~(SOUND_MASK_VOLUME | SOUND_MASK_PCM |
6227162922Sariff		    SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
6228182999Smav		    SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN |
6229182999Smav		    SOUND_MASK_IMIX | SOUND_MASK_MONITOR);
6230162922Sariff	}
6231162922Sariff
6232182999Smav	for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
6233182999Smav		if ((flag & (1 << j)) == 0)
6234162922Sariff			continue;
6235182999Smav		i = 0;
6236182999Smav		printed = 0;
6237182999Smav		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6238182999Smav			if (ctl->enable == 0 ||
6239182999Smav			    ctl->widget->enable == 0)
6240182999Smav				continue;
6241182999Smav			if (!((pdevinfo->play >= 0 &&
6242182999Smav			    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
6243182999Smav			    (pdevinfo->rec >= 0 &&
6244182999Smav			    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
6245182999Smav			    (ctl->widget->bindas == -2 && pdevinfo->index == 0)))
6246182999Smav				continue;
6247182999Smav			if ((ctl->ossmask & (1 << j)) == 0)
6248182999Smav				continue;
6249182999Smav
6250182999Smav	    		if (printed == 0) {
6251182999Smav				device_printf(pdevinfo->dev, "\n");
6252182999Smav				if (banner != NULL) {
6253182999Smav					device_printf(pdevinfo->dev, "%s", banner);
6254182999Smav				} else {
6255182999Smav					device_printf(pdevinfo->dev, "Unknown Ctl");
6256182999Smav				}
6257182999Smav				printf(" (OSS: %s)\n",
6258182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(1 << j,
6259182999Smav				    buf, sizeof(buf)));
6260182999Smav				device_printf(pdevinfo->dev, "   |\n");
6261182999Smav				printed = 1;
6262162922Sariff			}
6263182999Smav			device_printf(pdevinfo->dev, "   +- ctl %2d (nid %3d %s", i,
6264182999Smav				ctl->widget->nid,
6265182999Smav				(ctl->ndir == HDA_CTL_IN)?"in ":"out");
6266182999Smav			if (ctl->ndir == HDA_CTL_IN && ctl->ndir == ctl->dir)
6267182999Smav				printf(" %2d): ", ctl->index);
6268182999Smav			else
6269182999Smav				printf("):    ");
6270182999Smav			if (ctl->step > 0) {
6271182999Smav				printf("%+d/%+ddB (%d steps)%s\n",
6272182999Smav			    	    (0 - ctl->offset) * (ctl->size + 1) / 4,
6273182999Smav				    (ctl->step - ctl->offset) * (ctl->size + 1) / 4,
6274182999Smav				    ctl->step + 1,
6275182999Smav				    ctl->mute?" + mute":"");
6276182999Smav			} else
6277182999Smav				printf("%s\n", ctl->mute?"mute":"");
6278162922Sariff		}
6279162922Sariff	}
6280162922Sariff}
6281162922Sariff
6282162922Sariffstatic void
6283182999Smavhdac_dump_audio_formats(device_t dev, uint32_t fcap, uint32_t pcmcap)
6284162922Sariff{
6285162922Sariff	uint32_t cap;
6286162922Sariff
6287162922Sariff	cap = fcap;
6288162922Sariff	if (cap != 0) {
6289182999Smav		device_printf(dev, "     Stream cap: 0x%08x\n", cap);
6290183097Smav		device_printf(dev, "                ");
6291162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
6292162922Sariff			printf(" AC3");
6293162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
6294162922Sariff			printf(" FLOAT32");
6295162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
6296162922Sariff			printf(" PCM");
6297162922Sariff		printf("\n");
6298162922Sariff	}
6299162922Sariff	cap = pcmcap;
6300162922Sariff	if (cap != 0) {
6301182999Smav		device_printf(dev, "        PCM cap: 0x%08x\n", cap);
6302183097Smav		device_printf(dev, "                ");
6303162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
6304162922Sariff			printf(" 8");
6305162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
6306162922Sariff			printf(" 16");
6307162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
6308162922Sariff			printf(" 20");
6309162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
6310162922Sariff			printf(" 24");
6311162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
6312162922Sariff			printf(" 32");
6313183097Smav		printf(" bits,");
6314162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
6315162922Sariff			printf(" 8");
6316162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
6317162922Sariff			printf(" 11");
6318162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
6319162922Sariff			printf(" 16");
6320162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
6321162922Sariff			printf(" 22");
6322162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
6323162922Sariff			printf(" 32");
6324162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
6325162922Sariff			printf(" 44");
6326162922Sariff		printf(" 48");
6327162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
6328162922Sariff			printf(" 88");
6329162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
6330162922Sariff			printf(" 96");
6331162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
6332162922Sariff			printf(" 176");
6333162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
6334162922Sariff			printf(" 192");
6335183097Smav		printf(" KHz\n");
6336162922Sariff	}
6337162922Sariff}
6338162922Sariff
6339162922Sariffstatic void
6340162922Sariffhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
6341162922Sariff{
6342183097Smav	uint32_t pincap;
6343162922Sariff
6344162922Sariff	pincap = w->wclass.pin.cap;
6345162922Sariff
6346162922Sariff	device_printf(sc->dev, "        Pin cap: 0x%08x\n", pincap);
6347162922Sariff	device_printf(sc->dev, "                ");
6348162922Sariff	if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap))
6349162922Sariff		printf(" ISC");
6350162922Sariff	if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap))
6351162922Sariff		printf(" TRQD");
6352162922Sariff	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap))
6353162922Sariff		printf(" PDC");
6354162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
6355162922Sariff		printf(" HP");
6356162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
6357162922Sariff		printf(" OUT");
6358162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
6359162922Sariff		printf(" IN");
6360162922Sariff	if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap))
6361162922Sariff		printf(" BAL");
6362165069Sariff	if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) {
6363165069Sariff		printf(" VREF[");
6364165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
6365165069Sariff			printf(" 50");
6366165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
6367165069Sariff			printf(" 80");
6368165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
6369165069Sariff			printf(" 100");
6370165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap))
6371165069Sariff			printf(" GROUND");
6372165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap))
6373165069Sariff			printf(" HIZ");
6374165069Sariff		printf(" ]");
6375165069Sariff	}
6376162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap))
6377162922Sariff		printf(" EAPD");
6378162922Sariff	printf("\n");
6379162922Sariff	device_printf(sc->dev, "     Pin config: 0x%08x\n",
6380162922Sariff	    w->wclass.pin.config);
6381162922Sariff	device_printf(sc->dev, "    Pin control: 0x%08x", w->wclass.pin.ctrl);
6382162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE)
6383162922Sariff		printf(" HP");
6384162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE)
6385162922Sariff		printf(" IN");
6386162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
6387162922Sariff		printf(" OUT");
6388182999Smav	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK)
6389182999Smav		printf(" VREFs");
6390162922Sariff	printf("\n");
6391162922Sariff}
6392162922Sariff
6393162922Sariffstatic void
6394182999Smavhdac_dump_pin_config(struct hdac_widget *w, uint32_t conf)
6395182999Smav{
6396182999Smav	struct hdac_softc *sc = w->devinfo->codec->sc;
6397182999Smav
6398183097Smav	device_printf(sc->dev, " nid %d 0x%08x as %2d seq %2d %13s %5s "
6399182999Smav	    "jack %2d loc %2d color %7s misc %d%s\n",
6400182999Smav	    w->nid, conf,
6401182999Smav	    HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf),
6402182999Smav	    HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf),
6403182999Smav	    HDA_DEVS[HDA_CONFIG_DEFAULTCONF_DEVICE(conf)],
6404182999Smav	    HDA_CONNS[HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf)],
6405182999Smav	    HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf),
6406182999Smav	    HDA_CONFIG_DEFAULTCONF_LOCATION(conf),
6407182999Smav	    HDA_COLORS[HDA_CONFIG_DEFAULTCONF_COLOR(conf)],
6408182999Smav	    HDA_CONFIG_DEFAULTCONF_MISC(conf),
6409182999Smav	    (w->enable == 0)?" [DISABLED]":"");
6410182999Smav}
6411182999Smav
6412182999Smavstatic void
6413182999Smavhdac_dump_pin_configs(struct hdac_devinfo *devinfo)
6414182999Smav{
6415182999Smav	struct hdac_widget *w;
6416182999Smav	int i;
6417182999Smav
6418182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6419182999Smav		w = hdac_widget_get(devinfo, i);
6420182999Smav		if (w == NULL)
6421182999Smav			continue;
6422182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6423182999Smav			continue;
6424182999Smav		hdac_dump_pin_config(w, w->wclass.pin.config);
6425182999Smav	}
6426182999Smav}
6427182999Smav
6428182999Smavstatic void
6429162922Sariffhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
6430162922Sariff{
6431163057Sariff	device_printf(sc->dev, "     %s amp: 0x%08x\n", banner, cap);
6432162922Sariff	device_printf(sc->dev, "                 "
6433162922Sariff	    "mute=%d step=%d size=%d offset=%d\n",
6434162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap),
6435162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap),
6436162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap),
6437162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap));
6438162922Sariff}
6439162922Sariff
6440162922Sariffstatic void
6441162922Sariffhdac_dump_nodes(struct hdac_devinfo *devinfo)
6442162922Sariff{
6443162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6444182999Smav	static char *ossname[] = SOUND_DEVICE_NAMES;
6445162922Sariff	struct hdac_widget *w, *cw;
6446182999Smav	char buf[64];
6447162922Sariff	int i, j;
6448162922Sariff
6449162922Sariff	device_printf(sc->dev, "\n");
6450162922Sariff	device_printf(sc->dev, "Default Parameter\n");
6451162922Sariff	device_printf(sc->dev, "-----------------\n");
6452182999Smav	hdac_dump_audio_formats(sc->dev,
6453162922Sariff	    devinfo->function.audio.supp_stream_formats,
6454162922Sariff	    devinfo->function.audio.supp_pcm_size_rate);
6455162922Sariff	device_printf(sc->dev, "         IN amp: 0x%08x\n",
6456162922Sariff	    devinfo->function.audio.inamp_cap);
6457162922Sariff	device_printf(sc->dev, "        OUT amp: 0x%08x\n",
6458162922Sariff	    devinfo->function.audio.outamp_cap);
6459162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6460162922Sariff		w = hdac_widget_get(devinfo, i);
6461162922Sariff		if (w == NULL) {
6462162922Sariff			device_printf(sc->dev, "Ghost widget nid=%d\n", i);
6463162922Sariff			continue;
6464162922Sariff		}
6465162922Sariff		device_printf(sc->dev, "\n");
6466183097Smav		device_printf(sc->dev, "            nid: %d%s\n", w->nid,
6467162922Sariff		    (w->enable == 0) ? " [DISABLED]" : "");
6468183097Smav		device_printf(sc->dev, "           Name: %s\n", w->name);
6469183097Smav		device_printf(sc->dev, "     Widget cap: 0x%08x\n",
6470162922Sariff		    w->param.widget_cap);
6471183097Smav		if (w->param.widget_cap & 0x0ee1) {
6472183097Smav			device_printf(sc->dev, "                ");
6473183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(w->param.widget_cap))
6474183097Smav			    printf(" LRSWAP");
6475183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(w->param.widget_cap))
6476183097Smav			    printf(" PWR");
6477183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6478183097Smav			    printf(" DIGITAL");
6479183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap))
6480183097Smav			    printf(" UNSOL");
6481183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(w->param.widget_cap))
6482183097Smav			    printf(" PROC");
6483183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(w->param.widget_cap))
6484183097Smav			    printf(" STRIPE");
6485183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap))
6486183097Smav			    printf(" STEREO");
6487183097Smav			printf("\n");
6488183097Smav		}
6489183097Smav		if (w->bindas != -1) {
6490183097Smav			device_printf(sc->dev, "    Association: %d (0x%08x)\n",
6491183097Smav			    w->bindas, w->bindseqmask);
6492183097Smav		}
6493183097Smav		if (w->ossmask != 0 || w->ossdev >= 0) {
6494183097Smav			device_printf(sc->dev, "            OSS: %s",
6495183097Smav			    hdac_audio_ctl_ossmixer_mask2allname(w->ossmask, buf, sizeof(buf)));
6496183097Smav			if (w->ossdev >= 0)
6497183097Smav			    printf(" (%s)", ossname[w->ossdev]);
6498183097Smav			printf("\n");
6499183097Smav		}
6500162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
6501162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
6502182999Smav			hdac_dump_audio_formats(sc->dev,
6503162922Sariff			    w->param.supp_stream_formats,
6504162922Sariff			    w->param.supp_pcm_size_rate);
6505162922Sariff		} else if (w->type ==
6506162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6507162922Sariff			hdac_dump_pin(sc, w);
6508162965Sariff		if (w->param.eapdbtl != HDAC_INVALID)
6509162922Sariff			device_printf(sc->dev, "           EAPD: 0x%08x\n",
6510162922Sariff			    w->param.eapdbtl);
6511163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) &&
6512163057Sariff		    w->param.outamp_cap != 0)
6513162922Sariff			hdac_dump_amp(sc, w->param.outamp_cap, "Output");
6514163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) &&
6515163057Sariff		    w->param.inamp_cap != 0)
6516162922Sariff			hdac_dump_amp(sc, w->param.inamp_cap, " Input");
6517183097Smav		if (w->nconns > 0) {
6518183097Smav			device_printf(sc->dev, "    connections: %d\n", w->nconns);
6519182999Smav			device_printf(sc->dev, "          |\n");
6520183097Smav		}
6521162922Sariff		for (j = 0; j < w->nconns; j++) {
6522162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
6523182999Smav			device_printf(sc->dev, "          + %s<- nid=%d [%s]",
6524182999Smav			    (w->connsenable[j] == 0)?"[DISABLED] ":"",
6525162922Sariff			    w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
6526162922Sariff			if (cw == NULL)
6527162922Sariff				printf(" [UNKNOWN]");
6528162922Sariff			else if (cw->enable == 0)
6529162922Sariff				printf(" [DISABLED]");
6530162922Sariff			if (w->nconns > 1 && w->selconn == j && w->type !=
6531162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
6532162922Sariff				printf(" (selected)");
6533162922Sariff			printf("\n");
6534162922Sariff		}
6535162922Sariff	}
6536162922Sariff
6537162922Sariff}
6538162922Sariff
6539182999Smavstatic void
6540182999Smavhdac_dump_dst_nid(struct hdac_pcm_devinfo *pdevinfo, nid_t nid, int depth)
6541163057Sariff{
6542182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6543163057Sariff	struct hdac_widget *w, *cw;
6544182999Smav	char buf[64];
6545182999Smav	int i, printed = 0;
6546163057Sariff
6547163057Sariff	if (depth > HDA_PARSE_MAXDEPTH)
6548182999Smav		return;
6549163057Sariff
6550163057Sariff	w = hdac_widget_get(devinfo, nid);
6551182999Smav	if (w == NULL || w->enable == 0)
6552182999Smav		return;
6553163057Sariff
6554182999Smav	if (depth == 0)
6555182999Smav		device_printf(pdevinfo->dev, "%*s", 4, "");
6556182999Smav	else
6557182999Smav		device_printf(pdevinfo->dev, "%*s  + <- ", 4 + (depth - 1) * 7, "");
6558182999Smav	printf("nid=%d [%s]", w->nid, w->name);
6559163057Sariff
6560182999Smav	if (depth > 0) {
6561182999Smav		if (w->ossmask == 0) {
6562182999Smav			printf("\n");
6563182999Smav			return;
6564163057Sariff		}
6565182999Smav		printf(" [src: %s]",
6566182999Smav		    hdac_audio_ctl_ossmixer_mask2allname(
6567182999Smav			w->ossmask, buf, sizeof(buf)));
6568182999Smav		if (w->ossdev >= 0) {
6569182999Smav			printf("\n");
6570182999Smav			return;
6571182999Smav		}
6572163057Sariff	}
6573182999Smav	printf("\n");
6574182999Smav
6575182999Smav	for (i = 0; i < w->nconns; i++) {
6576182999Smav		if (w->connsenable[i] == 0)
6577182999Smav			continue;
6578182999Smav		cw = hdac_widget_get(devinfo, w->conns[i]);
6579182999Smav		if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
6580182999Smav			continue;
6581182999Smav		if (printed == 0) {
6582182999Smav			device_printf(pdevinfo->dev, "%*s  |\n", 4 + (depth) * 7, "");
6583182999Smav			printed = 1;
6584182999Smav		}
6585182999Smav		hdac_dump_dst_nid(pdevinfo, w->conns[i], depth + 1);
6586182999Smav	}
6587163057Sariff
6588163057Sariff}
6589163057Sariff
6590162922Sariffstatic void
6591182999Smavhdac_dump_dac(struct hdac_pcm_devinfo *pdevinfo)
6592162922Sariff{
6593182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6594182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
6595163057Sariff	struct hdac_widget *w;
6596163057Sariff	int i, printed = 0;
6597163057Sariff
6598182999Smav	if (pdevinfo->play < 0)
6599182999Smav		return;
6600182999Smav
6601163057Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6602163057Sariff		w = hdac_widget_get(devinfo, i);
6603163057Sariff		if (w == NULL || w->enable == 0)
6604163057Sariff			continue;
6605182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6606163057Sariff			continue;
6607182999Smav		if (w->bindas != sc->chans[pdevinfo->play].as)
6608182999Smav			continue;
6609163057Sariff		if (printed == 0) {
6610163057Sariff			printed = 1;
6611182999Smav			device_printf(pdevinfo->dev, "\n");
6612182999Smav			device_printf(pdevinfo->dev, "Playback:\n");
6613163057Sariff		}
6614182999Smav		device_printf(pdevinfo->dev, "\n");
6615182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
6616163057Sariff	}
6617162922Sariff}
6618162922Sariff
6619162922Sariffstatic void
6620182999Smavhdac_dump_adc(struct hdac_pcm_devinfo *pdevinfo)
6621162922Sariff{
6622182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6623162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6624182999Smav	struct hdac_widget *w;
6625182999Smav	int i;
6626162922Sariff	int printed = 0;
6627162922Sariff
6628182999Smav	if (pdevinfo->rec < 0)
6629182999Smav		return;
6630182999Smav
6631162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6632162922Sariff		w = hdac_widget_get(devinfo, i);
6633162922Sariff		if (w == NULL || w->enable == 0)
6634162922Sariff			continue;
6635182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
6636162922Sariff			continue;
6637182999Smav		if (w->bindas != sc->chans[pdevinfo->rec].as)
6638182999Smav			continue;
6639162922Sariff		if (printed == 0) {
6640162922Sariff			printed = 1;
6641182999Smav			device_printf(pdevinfo->dev, "\n");
6642182999Smav			device_printf(pdevinfo->dev, "Record:\n");
6643162922Sariff		}
6644182999Smav		device_printf(pdevinfo->dev, "\n");
6645182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
6646182999Smav	}
6647182999Smav}
6648182999Smav
6649182999Smavstatic void
6650182999Smavhdac_dump_mix(struct hdac_pcm_devinfo *pdevinfo)
6651182999Smav{
6652182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6653182999Smav	struct hdac_widget *w;
6654182999Smav	int i;
6655182999Smav	int printed = 0;
6656182999Smav
6657182999Smav	if (pdevinfo->index != 0)
6658182999Smav		return;
6659182999Smav
6660182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6661182999Smav		w = hdac_widget_get(devinfo, i);
6662182999Smav		if (w == NULL || w->enable == 0)
6663182999Smav			continue;
6664182999Smav		if ((w->pflags & HDA_ADC_MONITOR) == 0)
6665182999Smav			continue;
6666182999Smav		if (printed == 0) {
6667182999Smav			printed = 1;
6668182999Smav			device_printf(pdevinfo->dev, "\n");
6669182999Smav			device_printf(pdevinfo->dev, "Input Mix:\n");
6670162922Sariff		}
6671182999Smav		device_printf(pdevinfo->dev, "\n");
6672182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
6673162922Sariff	}
6674162922Sariff}
6675162922Sariff
6676162922Sariffstatic void
6677182999Smavhdac_dump_pcmchannels(struct hdac_pcm_devinfo *pdevinfo)
6678162922Sariff{
6679182999Smav	struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
6680162922Sariff	nid_t *nids;
6681182999Smav	int i;
6682162922Sariff
6683182999Smav	if (pdevinfo->play >= 0) {
6684182999Smav		i = pdevinfo->play;
6685182999Smav		device_printf(pdevinfo->dev, "\n");
6686182999Smav		device_printf(pdevinfo->dev, "Playback:\n");
6687182999Smav		device_printf(pdevinfo->dev, "\n");
6688182999Smav		hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
6689182999Smav		    sc->chans[i].supp_pcm_size_rate);
6690182999Smav		device_printf(pdevinfo->dev, "            DAC:");
6691182999Smav		for (nids = sc->chans[i].io; *nids != -1; nids++)
6692162922Sariff			printf(" %d", *nids);
6693162922Sariff		printf("\n");
6694162922Sariff	}
6695182999Smav	if (pdevinfo->rec >= 0) {
6696182999Smav		i = pdevinfo->rec;
6697182999Smav		device_printf(pdevinfo->dev, "\n");
6698182999Smav		device_printf(pdevinfo->dev, "Record:\n");
6699182999Smav		device_printf(pdevinfo->dev, "\n");
6700182999Smav		hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
6701182999Smav		    sc->chans[i].supp_pcm_size_rate);
6702182999Smav		device_printf(pdevinfo->dev, "            ADC:");
6703182999Smav		for (nids = sc->chans[i].io; *nids != -1; nids++)
6704162922Sariff			printf(" %d", *nids);
6705162922Sariff		printf("\n");
6706162922Sariff	}
6707162922Sariff}
6708162922Sariff
6709162922Sariffstatic void
6710163057Sariffhdac_release_resources(struct hdac_softc *sc)
6711163057Sariff{
6712182999Smav        int i, j;
6713163057Sariff
6714163057Sariff	if (sc == NULL)
6715163057Sariff		return;
6716163057Sariff
6717163057Sariff	hdac_lock(sc);
6718169277Sariff	sc->polling = 0;
6719169277Sariff	sc->poll_ival = 0;
6720170721Sariff	callout_stop(&sc->poll_hda);
6721169277Sariff	callout_stop(&sc->poll_hdac);
6722169277Sariff	callout_stop(&sc->poll_jack);
6723182999Smav	hdac_reset(sc, 0);
6724163057Sariff	hdac_unlock(sc);
6725171141Sariff	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
6726170721Sariff	callout_drain(&sc->poll_hda);
6727169277Sariff	callout_drain(&sc->poll_hdac);
6728169277Sariff	callout_drain(&sc->poll_jack);
6729163057Sariff
6730169277Sariff	hdac_irq_free(sc);
6731169277Sariff
6732182999Smav	for (i = 0; i < HDAC_CODEC_MAX; i++) {
6733182999Smav		if (sc->codecs[i] == NULL)
6734163057Sariff			continue;
6735182999Smav		for (j = 0; j < sc->codecs[i]->num_fgs; j++) {
6736182999Smav			free(sc->codecs[i]->fgs[j].widget, M_HDAC);
6737182999Smav			if (sc->codecs[i]->fgs[j].node_type ==
6738182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
6739182999Smav				free(sc->codecs[i]->fgs[j].function.audio.ctl,
6740182999Smav				    M_HDAC);
6741182999Smav				free(sc->codecs[i]->fgs[j].function.audio.as,
6742182999Smav				    M_HDAC);
6743182999Smav				free(sc->codecs[i]->fgs[j].function.audio.devs,
6744182999Smav				    M_HDAC);
6745182999Smav			}
6746182999Smav		}
6747182999Smav		free(sc->codecs[i]->fgs, M_HDAC);
6748182999Smav		free(sc->codecs[i], M_HDAC);
6749163057Sariff		sc->codecs[i] = NULL;
6750163057Sariff	}
6751163057Sariff
6752169277Sariff	hdac_dma_free(sc, &sc->pos_dma);
6753169277Sariff	hdac_dma_free(sc, &sc->rirb_dma);
6754169277Sariff	hdac_dma_free(sc, &sc->corb_dma);
6755182999Smav	for (i = 0; i < sc->num_chans; i++) {
6756182999Smav    		if (sc->chans[i].blkcnt > 0)
6757182999Smav    			hdac_dma_free(sc, &sc->chans[i].bdl_dma);
6758182999Smav	}
6759182999Smav	free(sc->chans, M_HDAC);
6760167702Sariff	if (sc->chan_dmat != NULL) {
6761167702Sariff		bus_dma_tag_destroy(sc->chan_dmat);
6762167702Sariff		sc->chan_dmat = NULL;
6763167702Sariff	}
6764163057Sariff	hdac_mem_free(sc);
6765169277Sariff	snd_mtxfree(sc->lock);
6766163057Sariff}
6767163057Sariff
6768163057Sariff/* This function surely going to make its way into upper level someday. */
6769163057Sariffstatic void
6770163057Sariffhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
6771163057Sariff{
6772163057Sariff	const char *res = NULL;
6773163057Sariff	int i = 0, j, k, len, inv;
6774163057Sariff
6775163057Sariff	if (on != NULL)
6776163057Sariff		*on = 0;
6777163057Sariff	if (off != NULL)
6778163057Sariff		*off = 0;
6779163057Sariff	if (sc == NULL)
6780163057Sariff		return;
6781163057Sariff	if (resource_string_value(device_get_name(sc->dev),
6782163057Sariff	    device_get_unit(sc->dev), "config", &res) != 0)
6783163057Sariff		return;
6784163057Sariff	if (!(res != NULL && strlen(res) > 0))
6785163057Sariff		return;
6786163057Sariff	HDA_BOOTVERBOSE(
6787182999Smav		device_printf(sc->dev, "HDA Config:");
6788163057Sariff	);
6789163057Sariff	for (;;) {
6790163057Sariff		while (res[i] != '\0' &&
6791163057Sariff		    (res[i] == ',' || isspace(res[i]) != 0))
6792163057Sariff			i++;
6793163057Sariff		if (res[i] == '\0') {
6794163057Sariff			HDA_BOOTVERBOSE(
6795163057Sariff				printf("\n");
6796163057Sariff			);
6797163057Sariff			return;
6798163057Sariff		}
6799163057Sariff		j = i;
6800163057Sariff		while (res[j] != '\0' &&
6801163057Sariff		    !(res[j] == ',' || isspace(res[j]) != 0))
6802163057Sariff			j++;
6803163057Sariff		len = j - i;
6804163057Sariff		if (len > 2 && strncmp(res + i, "no", 2) == 0)
6805163057Sariff			inv = 2;
6806163057Sariff		else
6807163057Sariff			inv = 0;
6808163057Sariff		for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) {
6809163057Sariff			if (strncmp(res + i + inv,
6810163057Sariff			    hdac_quirks_tab[k].key, len - inv) != 0)
6811163057Sariff				continue;
6812163057Sariff			if (len - inv != strlen(hdac_quirks_tab[k].key))
6813163057Sariff				break;
6814163057Sariff			HDA_BOOTVERBOSE(
6815163057Sariff				printf(" %s%s", (inv != 0) ? "no" : "",
6816163057Sariff				    hdac_quirks_tab[k].key);
6817163057Sariff			);
6818163057Sariff			if (inv == 0 && on != NULL)
6819163057Sariff				*on |= hdac_quirks_tab[k].value;
6820163057Sariff			else if (inv != 0 && off != NULL)
6821163057Sariff				*off |= hdac_quirks_tab[k].value;
6822163057Sariff			break;
6823163057Sariff		}
6824163057Sariff		i = j;
6825163057Sariff	}
6826163057Sariff}
6827163057Sariff
6828164614Sariff#ifdef SND_DYNSYSCTL
6829164614Sariffstatic int
6830164614Sariffsysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
6831164614Sariff{
6832164614Sariff	struct hdac_softc *sc;
6833164614Sariff	device_t dev;
6834164614Sariff	uint32_t ctl;
6835164614Sariff	int err, val;
6836164614Sariff
6837164614Sariff	dev = oidp->oid_arg1;
6838182999Smav	sc = device_get_softc(dev);
6839182999Smav	if (sc == NULL)
6840164614Sariff		return (EINVAL);
6841164614Sariff	hdac_lock(sc);
6842164614Sariff	val = sc->polling;
6843164614Sariff	hdac_unlock(sc);
6844170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
6845164614Sariff
6846169277Sariff	if (err != 0 || req->newptr == NULL)
6847164614Sariff		return (err);
6848164614Sariff	if (val < 0 || val > 1)
6849164614Sariff		return (EINVAL);
6850164614Sariff
6851164614Sariff	hdac_lock(sc);
6852164614Sariff	if (val != sc->polling) {
6853182999Smav		if (val == 0) {
6854182999Smav			callout_stop(&sc->poll_hda);
6855164614Sariff			callout_stop(&sc->poll_hdac);
6856169277Sariff			hdac_unlock(sc);
6857182999Smav			callout_drain(&sc->poll_hda);
6858169277Sariff			callout_drain(&sc->poll_hdac);
6859169277Sariff			hdac_lock(sc);
6860164614Sariff			sc->polling = 0;
6861182999Smav			ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
6862182999Smav			ctl |= HDAC_INTCTL_GIE;
6863182999Smav			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
6864164614Sariff		} else {
6865182999Smav			ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
6866182999Smav			ctl &= ~HDAC_INTCTL_GIE;
6867182999Smav			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
6868171141Sariff			hdac_unlock(sc);
6869171141Sariff			taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
6870171141Sariff			hdac_lock(sc);
6871164614Sariff			sc->polling = 1;
6872182999Smav			hdac_poll_reinit(sc);
6873182999Smav			callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
6874164614Sariff		}
6875164614Sariff	}
6876164614Sariff	hdac_unlock(sc);
6877164614Sariff
6878164614Sariff	return (err);
6879164614Sariff}
6880169277Sariff
6881169277Sariffstatic int
6882169277Sariffsysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS)
6883169277Sariff{
6884169277Sariff	struct hdac_softc *sc;
6885169277Sariff	device_t dev;
6886169277Sariff	int err, val;
6887169277Sariff
6888169277Sariff	dev = oidp->oid_arg1;
6889182999Smav	sc = device_get_softc(dev);
6890182999Smav	if (sc == NULL)
6891169277Sariff		return (EINVAL);
6892169277Sariff	hdac_lock(sc);
6893169277Sariff	val = ((uint64_t)sc->poll_ival * 1000) / hz;
6894169277Sariff	hdac_unlock(sc);
6895170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
6896169277Sariff
6897169277Sariff	if (err != 0 || req->newptr == NULL)
6898169277Sariff		return (err);
6899169277Sariff
6900169277Sariff	if (val < 1)
6901169277Sariff		val = 1;
6902169277Sariff	if (val > 5000)
6903169277Sariff		val = 5000;
6904169277Sariff	val = ((uint64_t)val * hz) / 1000;
6905169277Sariff	if (val < 1)
6906169277Sariff		val = 1;
6907169277Sariff	if (val > (hz * 5))
6908169277Sariff		val = hz * 5;
6909169277Sariff
6910169277Sariff	hdac_lock(sc);
6911169277Sariff	sc->poll_ival = val;
6912169277Sariff	hdac_unlock(sc);
6913169277Sariff
6914169277Sariff	return (err);
6915169277Sariff}
6916169277Sariff
6917169277Sariffstatic int
6918171141Sariffsysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)
6919169277Sariff{
6920169277Sariff	struct hdac_softc *sc;
6921182999Smav	struct hdac_codec *codec;
6922169277Sariff	struct hdac_devinfo *devinfo;
6923169277Sariff	struct hdac_widget *w;
6924169277Sariff	device_t dev;
6925182999Smav	uint32_t res, pincap, delay;
6926182999Smav	int codec_index, fg_index;
6927169277Sariff	int i, err, val;
6928169277Sariff	nid_t cad;
6929169277Sariff
6930169277Sariff	dev = oidp->oid_arg1;
6931182999Smav	sc = device_get_softc(dev);
6932182999Smav	if (sc == NULL)
6933169277Sariff		return (EINVAL);
6934169277Sariff	val = 0;
6935170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
6936169277Sariff	if (err != 0 || req->newptr == NULL || val == 0)
6937169277Sariff		return (err);
6938182999Smav
6939182999Smav	/* XXX: Temporary. For debugging. */
6940182999Smav	if (val == 100) {
6941182999Smav		hdac_suspend(dev);
6942182999Smav		return (0);
6943182999Smav	} else if (val == 101) {
6944182999Smav		hdac_resume(dev);
6945182999Smav		return (0);
6946182999Smav	}
6947182999Smav
6948169277Sariff	hdac_lock(sc);
6949182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
6950182999Smav		codec = sc->codecs[codec_index];
6951182999Smav		if (codec == NULL)
6952169277Sariff			continue;
6953182999Smav		cad = codec->cad;
6954182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
6955182999Smav			devinfo = &codec->fgs[fg_index];
6956182999Smav			if (devinfo->node_type !=
6957182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
6958182999Smav				continue;
6959182999Smav
6960182999Smav			device_printf(dev, "Dumping AFG cad=%d nid=%d pins:\n",
6961182999Smav			    codec_index, devinfo->nid);
6962182999Smav			for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6963182999Smav					w = hdac_widget_get(devinfo, i);
6964182999Smav				if (w == NULL || w->type !=
6965182999Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6966182999Smav					continue;
6967182999Smav				hdac_dump_pin_config(w, w->wclass.pin.config);
6968182999Smav				pincap = w->wclass.pin.cap;
6969182999Smav				device_printf(dev, "       Caps: %2s %3s %2s %4s %4s",
6970182999Smav				    HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)?"IN":"",
6971182999Smav				    HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)?"OUT":"",
6972182999Smav				    HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)?"HP":"",
6973182999Smav				    HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)?"EAPD":"",
6974182999Smav				    HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)?"VREF":"");
6975182999Smav				if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) ||
6976182999Smav				    HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) {
6977182999Smav					if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) {
6978182999Smav						delay = 0;
6979182999Smav						hdac_command(sc,
6980182999Smav						    HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad);
6981182999Smav						do {
6982182999Smav							res = hdac_command(sc,
6983182999Smav							    HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
6984182999Smav							if (res != 0x7fffffff && res != 0xffffffff)
6985182999Smav								break;
6986182999Smav							DELAY(10);
6987182999Smav						} while (++delay < 10000);
6988182999Smav					} else {
6989182999Smav						delay = 0;
6990182999Smav						res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad,
6991182999Smav						    w->nid), cad);
6992182999Smav					}
6993182999Smav					printf(" Sense: 0x%08x", res);
6994182999Smav					if (delay > 0)
6995182999Smav						printf(" delay %dus", delay * 10);
6996182999Smav				}
6997182999Smav				printf("\n");
6998182999Smav			}
6999182999Smav			device_printf(dev,
7000182999Smav			    "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
7001182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
7002182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
7003182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
7004182999Smav			    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
7005182999Smav			    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
7006182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) {
7007182999Smav				device_printf(dev, " GPI:");
7008171141Sariff				res = hdac_command(sc,
7009182999Smav				    HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad);
7010182999Smav				printf(" data=0x%08x", res);
7011182999Smav				res = hdac_command(sc,
7012182999Smav				    HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid),
7013182999Smav				    cad);
7014182999Smav				printf(" wake=0x%08x", res);
7015182999Smav				res = hdac_command(sc,
7016182999Smav				    HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
7017182999Smav				    cad);
7018182999Smav				printf(" unsol=0x%08x", res);
7019182999Smav				res = hdac_command(sc,
7020182999Smav				    HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad);
7021182999Smav				printf(" sticky=0x%08x\n", res);
7022182999Smav			}
7023182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) {
7024182999Smav				device_printf(dev, " GPO:");
7025182999Smav				res = hdac_command(sc,
7026182999Smav				    HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad);
7027182999Smav				printf(" data=0x%08x\n", res);
7028182999Smav			}
7029182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) {
7030182999Smav				device_printf(dev, "GPIO:");
7031182999Smav				res = hdac_command(sc,
7032182999Smav				    HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad);
7033182999Smav				printf(" data=0x%08x", res);
7034182999Smav				res = hdac_command(sc,
7035182999Smav				    HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad);
7036182999Smav				printf(" enable=0x%08x", res);
7037182999Smav				res = hdac_command(sc,
7038182999Smav				    HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad);
7039182999Smav				printf(" direction=0x%08x\n", res);
7040182999Smav				res = hdac_command(sc,
7041182999Smav				    HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad);
7042182999Smav				device_printf(dev, "      wake=0x%08x", res);
7043182999Smav				res = hdac_command(sc,
7044182999Smav				    HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
7045182999Smav				    cad);
7046182999Smav				printf("  unsol=0x%08x", res);
7047182999Smav				res = hdac_command(sc,
7048182999Smav				    HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad);
7049182999Smav				printf("    sticky=0x%08x\n", res);
7050182999Smav			}
7051171141Sariff		}
7052169277Sariff	}
7053169277Sariff	hdac_unlock(sc);
7054169277Sariff	return (0);
7055169277Sariff}
7056164614Sariff#endif
7057164614Sariff
7058163057Sariffstatic void
7059162922Sariffhdac_attach2(void *arg)
7060162922Sariff{
7061182999Smav	struct hdac_codec *codec;
7062162922Sariff	struct hdac_softc *sc;
7063162922Sariff	struct hdac_audio_ctl *ctl;
7064163057Sariff	uint32_t quirks_on, quirks_off;
7065182999Smav	int codec_index, fg_index;
7066182999Smav	int i, pdev, rdev, dmaalloc = 0;
7067182999Smav	struct hdac_devinfo *devinfo;
7068162922Sariff
7069162922Sariff	sc = (struct hdac_softc *)arg;
7070162922Sariff
7071163057Sariff	hdac_config_fetch(sc, &quirks_on, &quirks_off);
7072162922Sariff
7073183097Smav	HDA_BOOTHVERBOSE(
7074182999Smav		device_printf(sc->dev, "HDA Config: on=0x%08x off=0x%08x\n",
7075163057Sariff		    quirks_on, quirks_off);
7076163057Sariff	);
7077163057Sariff
7078162922Sariff	hdac_lock(sc);
7079162922Sariff
7080162922Sariff	/* Remove ourselves from the config hooks */
7081162922Sariff	if (sc->intrhook.ich_func != NULL) {
7082162922Sariff		config_intrhook_disestablish(&sc->intrhook);
7083162922Sariff		sc->intrhook.ich_func = NULL;
7084162922Sariff	}
7085162922Sariff
7086162922Sariff	/* Start the corb and rirb engines */
7087183097Smav	HDA_BOOTHVERBOSE(
7088182999Smav		device_printf(sc->dev, "Starting CORB Engine...\n");
7089162922Sariff	);
7090162922Sariff	hdac_corb_start(sc);
7091183097Smav	HDA_BOOTHVERBOSE(
7092182999Smav		device_printf(sc->dev, "Starting RIRB Engine...\n");
7093162922Sariff	);
7094162922Sariff	hdac_rirb_start(sc);
7095162922Sariff
7096183097Smav	HDA_BOOTHVERBOSE(
7097162922Sariff		device_printf(sc->dev,
7098182999Smav		    "Enabling controller interrupt...\n");
7099162922Sariff	);
7100182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
7101182999Smav	    HDAC_GCTL_UNSOL);
7102182999Smav	if (sc->polling == 0) {
7103164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
7104164614Sariff		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
7105182999Smav	} else {
7106182999Smav		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
7107182999Smav	}
7108162922Sariff	DELAY(1000);
7109162922Sariff
7110183097Smav	HDA_BOOTHVERBOSE(
7111172811Sariff		device_printf(sc->dev,
7112182999Smav		    "Scanning HDA codecs ...\n");
7113162922Sariff	);
7114182999Smav	hdac_scan_codecs(sc);
7115182999Smav
7116182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7117182999Smav		codec = sc->codecs[codec_index];
7118182999Smav		if (codec == NULL)
7119182999Smav			continue;
7120182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7121182999Smav			devinfo = &codec->fgs[fg_index];
7122183019Smav			HDA_BOOTVERBOSE(
7123183019Smav				device_printf(sc->dev, "\n");
7124183097Smav				device_printf(sc->dev,
7125183097Smav				    "Processing %s FG cad=%d nid=%d...\n",
7126183097Smav				    (devinfo->node_type == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
7127183097Smav				    (devinfo->node_type == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
7128183097Smav				    "unknown",
7129183097Smav				    devinfo->codec->cad, devinfo->nid);
7130183019Smav			);
7131182999Smav			if (devinfo->node_type !=
7132182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
7133183097Smav				HDA_BOOTHVERBOSE(
7134182999Smav					device_printf(sc->dev,
7135183097Smav					    "Powering down...\n");
7136182999Smav				);
7137182999Smav				hdac_command(sc,
7138182999Smav				    HDA_CMD_SET_POWER_STATE(codec->cad,
7139182999Smav				    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7140182999Smav				    codec->cad);
7141182999Smav				continue;
7142182999Smav			}
7143162922Sariff
7144183097Smav			HDA_BOOTHVERBOSE(
7145183097Smav				device_printf(sc->dev, "Powering up...\n");
7146182999Smav			);
7147182999Smav			hdac_powerup(devinfo);
7148183097Smav			HDA_BOOTHVERBOSE(
7149182999Smav				device_printf(sc->dev, "Parsing audio FG...\n");
7150182999Smav			);
7151182999Smav			hdac_audio_parse(devinfo);
7152183097Smav			HDA_BOOTHVERBOSE(
7153182999Smav				device_printf(sc->dev, "Parsing Ctls...\n");
7154182999Smav			);
7155182999Smav		    	hdac_audio_ctl_parse(devinfo);
7156183097Smav			HDA_BOOTHVERBOSE(
7157182999Smav				device_printf(sc->dev, "Parsing vendor patch...\n");
7158182999Smav			);
7159182999Smav			hdac_vendor_patch_parse(devinfo);
7160182999Smav			devinfo->function.audio.quirks |= quirks_on;
7161182999Smav			devinfo->function.audio.quirks &= ~quirks_off;
7162162922Sariff
7163183097Smav			HDA_BOOTHVERBOSE(
7164182999Smav				device_printf(sc->dev, "Disabling nonaudio...\n");
7165182999Smav			);
7166182999Smav			hdac_audio_disable_nonaudio(devinfo);
7167183097Smav			HDA_BOOTHVERBOSE(
7168182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7169182999Smav			);
7170182999Smav			hdac_audio_disable_useless(devinfo);
7171182999Smav			HDA_BOOTVERBOSE(
7172182999Smav				device_printf(sc->dev, "Patched pins configuration:\n");
7173182999Smav				hdac_dump_pin_configs(devinfo);
7174183097Smav			);
7175183097Smav			HDA_BOOTHVERBOSE(
7176182999Smav				device_printf(sc->dev, "Parsing pin associations...\n");
7177182999Smav			);
7178182999Smav			hdac_audio_as_parse(devinfo);
7179183097Smav			HDA_BOOTHVERBOSE(
7180182999Smav				device_printf(sc->dev, "Building AFG tree...\n");
7181182999Smav			);
7182182999Smav			hdac_audio_build_tree(devinfo);
7183183097Smav			HDA_BOOTHVERBOSE(
7184182999Smav				device_printf(sc->dev, "Disabling unassociated "
7185182999Smav				    "widgets...\n");
7186182999Smav			);
7187182999Smav			hdac_audio_disable_unas(devinfo);
7188183097Smav			HDA_BOOTHVERBOSE(
7189182999Smav				device_printf(sc->dev, "Disabling nonselected "
7190182999Smav				    "inputs...\n");
7191182999Smav			);
7192182999Smav			hdac_audio_disable_notselected(devinfo);
7193183097Smav			HDA_BOOTHVERBOSE(
7194182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7195182999Smav			);
7196182999Smav			hdac_audio_disable_useless(devinfo);
7197183097Smav			HDA_BOOTHVERBOSE(
7198182999Smav				device_printf(sc->dev, "Disabling "
7199182999Smav				    "crossassociatement connections...\n");
7200182999Smav			);
7201182999Smav			hdac_audio_disable_crossas(devinfo);
7202183097Smav			HDA_BOOTHVERBOSE(
7203182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7204182999Smav			);
7205182999Smav			hdac_audio_disable_useless(devinfo);
7206183097Smav			HDA_BOOTHVERBOSE(
7207182999Smav				device_printf(sc->dev, "Binding associations to channels...\n");
7208182999Smav			);
7209182999Smav			hdac_audio_bind_as(devinfo);
7210183097Smav			HDA_BOOTHVERBOSE(
7211182999Smav				device_printf(sc->dev, "Assigning names to signal sources...\n");
7212182999Smav			);
7213182999Smav			hdac_audio_assign_names(devinfo);
7214183097Smav			HDA_BOOTHVERBOSE(
7215182999Smav				device_printf(sc->dev, "Assigning mixers to the tree...\n");
7216182999Smav			);
7217182999Smav			hdac_audio_assign_mixers(devinfo);
7218183097Smav			HDA_BOOTHVERBOSE(
7219182999Smav				device_printf(sc->dev, "Preparing pin controls...\n");
7220182999Smav			);
7221182999Smav			hdac_audio_prepare_pin_ctrl(devinfo);
7222183097Smav			HDA_BOOTHVERBOSE(
7223182999Smav				device_printf(sc->dev, "AFG commit...\n");
7224182999Smav		    	);
7225182999Smav			hdac_audio_commit(devinfo);
7226183097Smav		    	HDA_BOOTHVERBOSE(
7227182999Smav				device_printf(sc->dev, "Ctls commit...\n");
7228182999Smav			);
7229182999Smav			hdac_audio_ctl_commit(devinfo);
7230183097Smav		    	HDA_BOOTHVERBOSE(
7231182999Smav				device_printf(sc->dev, "HP switch init...\n");
7232182999Smav			);
7233182999Smav			hdac_hp_switch_init(devinfo);
7234182999Smav
7235182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) &&
7236182999Smav			    dmaalloc == 0) {
7237182999Smav				if (hdac_dma_alloc(sc, &sc->pos_dma,
7238182999Smav				    (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) {
7239182999Smav					HDA_BOOTVERBOSE(
7240182999Smav						device_printf(sc->dev, "Failed to "
7241182999Smav						    "allocate DMA pos buffer "
7242182999Smav						    "(non-fatal)\n");
7243182999Smav					);
7244182999Smav				} else
7245182999Smav					dmaalloc = 1;
7246182999Smav			}
7247182999Smav
7248182999Smav			i = devinfo->function.audio.playcnt;
7249182999Smav			if (devinfo->function.audio.reccnt > i)
7250182999Smav				i = devinfo->function.audio.reccnt;
7251182999Smav			devinfo->function.audio.devs =
7252182999Smav			    (struct hdac_pcm_devinfo *)malloc(
7253182999Smav			    sizeof(struct hdac_pcm_devinfo) * i,
7254182999Smav			    M_HDAC, M_ZERO | M_NOWAIT);
7255182999Smav			if (devinfo->function.audio.devs == NULL) {
7256182999Smav				device_printf(sc->dev,
7257182999Smav				    "Unable to allocate memory for devices\n");
7258182999Smav				continue;
7259182999Smav			}
7260182999Smav			devinfo->function.audio.num_devs = i;
7261182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
7262182999Smav				devinfo->function.audio.devs[i].index = i;
7263182999Smav				devinfo->function.audio.devs[i].devinfo = devinfo;
7264182999Smav				devinfo->function.audio.devs[i].play = -1;
7265182999Smav				devinfo->function.audio.devs[i].rec = -1;
7266182999Smav			}
7267182999Smav			pdev = 0;
7268182999Smav			rdev = 0;
7269182999Smav			for (i = 0; i < devinfo->function.audio.ascnt; i++) {
7270182999Smav				if (devinfo->function.audio.as[i].enable == 0)
7271182999Smav					continue;
7272182999Smav				if (devinfo->function.audio.as[i].dir ==
7273182999Smav				    HDA_CTL_IN) {
7274182999Smav					devinfo->function.audio.devs[rdev].rec
7275182999Smav					    = devinfo->function.audio.as[i].chan;
7276182999Smav					sc->chans[devinfo->function.audio.as[i].chan].pdevinfo =
7277182999Smav					    &devinfo->function.audio.devs[rdev];
7278182999Smav					rdev++;
7279182999Smav				} else {
7280182999Smav					devinfo->function.audio.devs[pdev].play
7281182999Smav					    = devinfo->function.audio.as[i].chan;
7282182999Smav					sc->chans[devinfo->function.audio.as[i].chan].pdevinfo =
7283182999Smav					    &devinfo->function.audio.devs[pdev];
7284182999Smav					pdev++;
7285182999Smav				}
7286182999Smav			}
7287182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
7288182999Smav				struct hdac_pcm_devinfo *pdevinfo =
7289182999Smav				    &devinfo->function.audio.devs[i];
7290182999Smav				pdevinfo->dev =
7291182999Smav				    device_add_child(sc->dev, "pcm", -1);
7292182999Smav				device_set_ivars(pdevinfo->dev,
7293182999Smav				     (void *)pdevinfo);
7294182999Smav			}
7295182999Smav
7296182999Smav			HDA_BOOTVERBOSE(
7297182999Smav				if (devinfo->function.audio.quirks != 0) {
7298183097Smav					device_printf(sc->dev, "FG config/quirks:");
7299182999Smav					for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
7300182999Smav						if ((devinfo->function.audio.quirks &
7301182999Smav						    hdac_quirks_tab[i].value) ==
7302182999Smav						    hdac_quirks_tab[i].value)
7303182999Smav							printf(" %s", hdac_quirks_tab[i].key);
7304182999Smav					}
7305182999Smav					printf("\n");
7306182999Smav				}
7307182999Smav
7308182999Smav				device_printf(sc->dev, "\n");
7309182999Smav				device_printf(sc->dev, "+-------------------+\n");
7310182999Smav				device_printf(sc->dev, "| DUMPING HDA NODES |\n");
7311182999Smav				device_printf(sc->dev, "+-------------------+\n");
7312182999Smav				hdac_dump_nodes(devinfo);
7313183097Smav			);
7314182999Smav
7315183097Smav			HDA_BOOTHVERBOSE(
7316182999Smav				device_printf(sc->dev, "\n");
7317182999Smav				device_printf(sc->dev, "+------------------------+\n");
7318182999Smav				device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
7319182999Smav				device_printf(sc->dev, "+------------------------+\n");
7320182999Smav				device_printf(sc->dev, "\n");
7321182999Smav				i = 0;
7322182999Smav				while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
7323182999Smav					device_printf(sc->dev, "%3d: nid %3d %s (%s) index %d", i,
7324182999Smav					    (ctl->widget != NULL) ? ctl->widget->nid : -1,
7325182999Smav					    (ctl->ndir == HDA_CTL_IN)?"in ":"out",
7326182999Smav					    (ctl->dir == HDA_CTL_IN)?"in ":"out",
7327182999Smav					    ctl->index);
7328182999Smav					if (ctl->childwidget != NULL)
7329182999Smav						printf(" cnid %3d", ctl->childwidget->nid);
7330182999Smav					else
7331182999Smav						printf("         ");
7332182999Smav					printf(" ossmask=0x%08x\n",
7333182999Smav					    ctl->ossmask);
7334182999Smav					device_printf(sc->dev,
7335182999Smav					    "       mute: %d step: %3d size: %3d off: %3d%s\n",
7336182999Smav					    ctl->mute, ctl->step, ctl->size, ctl->offset,
7337182999Smav					    (ctl->enable == 0) ? " [DISABLED]" :
7338182999Smav					    ((ctl->ossmask == 0) ? " [UNUSED]" : ""));
7339182999Smav				}
7340182999Smav			);
7341182999Smav		}
7342162922Sariff	}
7343182999Smav	hdac_unlock(sc);
7344162922Sariff
7345163057Sariff	HDA_BOOTVERBOSE(
7346182999Smav		device_printf(sc->dev, "\n");
7347162922Sariff	);
7348182999Smav
7349182999Smav	bus_generic_attach(sc->dev);
7350182999Smav
7351182999Smav#ifdef SND_DYNSYSCTL
7352182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7353182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7354182999Smav	    "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
7355182999Smav	    sysctl_hdac_polling, "I", "Enable polling mode");
7356182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7357182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7358182999Smav	    "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
7359182999Smav	    sizeof(sc->dev), sysctl_hdac_polling_interval, "I",
7360182999Smav	    "Controller/Jack Sense polling interval (1-1000 ms)");
7361182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7362182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7363182999Smav	    "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
7364182999Smav	    sysctl_hdac_pindump, "I", "Dump pin states/data");
7365182999Smav#endif
7366182999Smav}
7367182999Smav
7368182999Smav/****************************************************************************
7369182999Smav * int hdac_suspend(device_t)
7370182999Smav *
7371182999Smav * Suspend and power down HDA bus and codecs.
7372182999Smav ****************************************************************************/
7373182999Smavstatic int
7374182999Smavhdac_suspend(device_t dev)
7375182999Smav{
7376182999Smav	struct hdac_softc *sc;
7377182999Smav	struct hdac_codec *codec;
7378182999Smav	struct hdac_devinfo *devinfo;
7379182999Smav	int codec_index, fg_index, i;
7380182999Smav
7381183097Smav	HDA_BOOTHVERBOSE(
7382182999Smav		device_printf(dev, "Suspend...\n");
7383162922Sariff	);
7384182999Smav
7385182999Smav	sc = device_get_softc(dev);
7386182999Smav	hdac_lock(sc);
7387182999Smav
7388183097Smav	HDA_BOOTHVERBOSE(
7389182999Smav		device_printf(dev, "Stop streams...\n");
7390162922Sariff	);
7391182999Smav	for (i = 0; i < sc->num_chans; i++) {
7392182999Smav		if (sc->chans[i].flags & HDAC_CHN_RUNNING) {
7393182999Smav			sc->chans[i].flags |= HDAC_CHN_SUSPEND;
7394182999Smav			hdac_channel_stop(sc, &sc->chans[i]);
7395182999Smav		}
7396182999Smav	}
7397162922Sariff
7398182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7399182999Smav		codec = sc->codecs[codec_index];
7400182999Smav		if (codec == NULL)
7401162922Sariff			continue;
7402182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7403182999Smav			devinfo = &codec->fgs[fg_index];
7404183097Smav			HDA_BOOTHVERBOSE(
7405182999Smav				device_printf(dev,
7406182999Smav				    "Power down FG"
7407182999Smav				    " cad=%d nid=%d to the D3 state...\n",
7408182999Smav				    codec->cad, devinfo->nid);
7409182999Smav			);
7410182999Smav			hdac_command(sc,
7411182999Smav			    HDA_CMD_SET_POWER_STATE(codec->cad,
7412182999Smav			    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7413182999Smav			    codec->cad);
7414162922Sariff		}
7415162922Sariff	}
7416162922Sariff
7417183097Smav	HDA_BOOTHVERBOSE(
7418182999Smav		device_printf(dev, "Reset controller...\n");
7419162922Sariff	);
7420182999Smav	callout_stop(&sc->poll_hda);
7421182999Smav	callout_stop(&sc->poll_hdac);
7422182999Smav	callout_stop(&sc->poll_jack);
7423182999Smav	hdac_reset(sc, 0);
7424182999Smav	hdac_unlock(sc);
7425182999Smav	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
7426182999Smav	callout_drain(&sc->poll_hda);
7427182999Smav	callout_drain(&sc->poll_hdac);
7428182999Smav	callout_drain(&sc->poll_jack);
7429162922Sariff
7430183097Smav	HDA_BOOTHVERBOSE(
7431182999Smav		device_printf(dev, "Suspend done\n");
7432162922Sariff	);
7433182999Smav
7434182999Smav	return (0);
7435182999Smav}
7436182999Smav
7437182999Smav/****************************************************************************
7438182999Smav * int hdac_resume(device_t)
7439182999Smav *
7440182999Smav * Powerup and restore HDA bus and codecs state.
7441182999Smav ****************************************************************************/
7442182999Smavstatic int
7443182999Smavhdac_resume(device_t dev)
7444182999Smav{
7445182999Smav	struct hdac_softc *sc;
7446182999Smav	struct hdac_codec *codec;
7447182999Smav	struct hdac_devinfo *devinfo;
7448182999Smav	int codec_index, fg_index, i;
7449182999Smav
7450183097Smav	HDA_BOOTHVERBOSE(
7451182999Smav		device_printf(dev, "Resume...\n");
7452162922Sariff	);
7453162922Sariff
7454182999Smav	sc = device_get_softc(dev);
7455182999Smav	hdac_lock(sc);
7456182999Smav
7457182999Smav	/* Quiesce everything */
7458183097Smav	HDA_BOOTHVERBOSE(
7459182999Smav		device_printf(dev, "Reset controller...\n");
7460162922Sariff	);
7461182999Smav	hdac_reset(sc, 1);
7462182999Smav
7463182999Smav	/* Initialize the CORB and RIRB */
7464182999Smav	hdac_corb_init(sc);
7465182999Smav	hdac_rirb_init(sc);
7466182999Smav
7467182999Smav	/* Start the corb and rirb engines */
7468183097Smav	HDA_BOOTHVERBOSE(
7469182999Smav		device_printf(dev, "Starting CORB Engine...\n");
7470162922Sariff	);
7471182999Smav	hdac_corb_start(sc);
7472183097Smav	HDA_BOOTHVERBOSE(
7473182999Smav		device_printf(dev, "Starting RIRB Engine...\n");
7474162922Sariff	);
7475182999Smav	hdac_rirb_start(sc);
7476163057Sariff
7477183097Smav	HDA_BOOTHVERBOSE(
7478182999Smav		device_printf(dev,
7479182999Smav		    "Enabling controller interrupt...\n");
7480162922Sariff	);
7481182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
7482182999Smav	    HDAC_GCTL_UNSOL);
7483182999Smav	if (sc->polling == 0) {
7484182999Smav		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
7485182999Smav		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
7486182999Smav	} else {
7487182999Smav		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
7488182999Smav	}
7489182999Smav	DELAY(1000);
7490162922Sariff
7491182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7492182999Smav		codec = sc->codecs[codec_index];
7493182999Smav		if (codec == NULL)
7494182999Smav			continue;
7495182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7496182999Smav			devinfo = &codec->fgs[fg_index];
7497182999Smav			if (devinfo->node_type !=
7498182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
7499183097Smav				HDA_BOOTHVERBOSE(
7500182999Smav					device_printf(dev,
7501182999Smav					    "Power down unsupported non-audio FG"
7502182999Smav					    " cad=%d nid=%d to the D3 state...\n",
7503182999Smav					    codec->cad, devinfo->nid);
7504182999Smav				);
7505182999Smav				hdac_command(sc,
7506182999Smav				    HDA_CMD_SET_POWER_STATE(codec->cad,
7507182999Smav				    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7508182999Smav				    codec->cad);
7509182999Smav				continue;
7510182999Smav			}
7511162922Sariff
7512183097Smav			HDA_BOOTHVERBOSE(
7513182999Smav				device_printf(dev,
7514182999Smav				    "Power up audio FG cad=%d nid=%d...\n",
7515182999Smav				    devinfo->codec->cad, devinfo->nid);
7516182999Smav			);
7517182999Smav			hdac_powerup(devinfo);
7518183097Smav			HDA_BOOTHVERBOSE(
7519182999Smav				device_printf(dev, "AFG commit...\n");
7520182999Smav		    	);
7521182999Smav			hdac_audio_commit(devinfo);
7522183097Smav		    	HDA_BOOTHVERBOSE(
7523182999Smav				device_printf(dev, "Ctls commit...\n");
7524182999Smav			);
7525182999Smav			hdac_audio_ctl_commit(devinfo);
7526183097Smav		    	HDA_BOOTHVERBOSE(
7527182999Smav				device_printf(dev, "HP switch init...\n");
7528182999Smav			);
7529182999Smav			hdac_hp_switch_init(devinfo);
7530182999Smav
7531182999Smav			hdac_unlock(sc);
7532182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
7533182999Smav				struct hdac_pcm_devinfo *pdevinfo =
7534182999Smav				    &devinfo->function.audio.devs[i];
7535183097Smav				HDA_BOOTHVERBOSE(
7536182999Smav					device_printf(pdevinfo->dev,
7537182999Smav					    "OSS mixer reinitialization...\n");
7538182999Smav				);
7539182999Smav				if (mixer_reinit(pdevinfo->dev) == -1)
7540182999Smav					device_printf(pdevinfo->dev,
7541182999Smav					    "unable to reinitialize the mixer\n");
7542182999Smav			}
7543182999Smav			hdac_lock(sc);
7544182999Smav		}
7545169277Sariff	}
7546169277Sariff
7547183097Smav	HDA_BOOTHVERBOSE(
7548182999Smav		device_printf(dev, "Start streams...\n");
7549163057Sariff	);
7550182999Smav	for (i = 0; i < sc->num_chans; i++) {
7551182999Smav		if (sc->chans[i].flags & HDAC_CHN_SUSPEND) {
7552182999Smav			sc->chans[i].flags &= ~HDAC_CHN_SUSPEND;
7553182999Smav			hdac_channel_start(sc, &sc->chans[i]);
7554182999Smav		}
7555182999Smav	}
7556162922Sariff
7557182999Smav	hdac_unlock(sc);
7558182999Smav
7559183097Smav	HDA_BOOTHVERBOSE(
7560182999Smav		device_printf(dev, "Resume done\n");
7561162922Sariff	);
7562164614Sariff
7563182999Smav	return (0);
7564162922Sariff}
7565162922Sariff/****************************************************************************
7566162922Sariff * int hdac_detach(device_t)
7567162922Sariff *
7568162922Sariff * Detach and free up resources utilized by the hdac device.
7569162922Sariff ****************************************************************************/
7570162922Sariffstatic int
7571162922Sariffhdac_detach(device_t dev)
7572162922Sariff{
7573182999Smav	struct hdac_softc *sc;
7574185177Smav	device_t *devlist;
7575185177Smav	int i, devcount, error;
7576162922Sariff
7577185177Smav	if ((error = device_get_children(dev, &devlist, &devcount)) != 0)
7578185177Smav		return (error);
7579185177Smav	for (i = 0; i < devcount; i++) {
7580185177Smav		if ((error = device_delete_child(dev, devlist[i])) != 0) {
7581185178Smav			free(devlist, M_TEMP);
7582185178Smav			return (error);
7583185178Smav		}
7584185177Smav	}
7585185177Smav	free(devlist, M_TEMP);
7586185177Smav
7587182999Smav	sc = device_get_softc(dev);
7588163057Sariff	hdac_release_resources(sc);
7589162922Sariff
7590162922Sariff	return (0);
7591162922Sariff}
7592162922Sariff
7593184095Smavstatic int
7594184095Smavhdac_print_child(device_t dev, device_t child)
7595184095Smav{
7596184095Smav	struct hdac_pcm_devinfo *pdevinfo =
7597184095Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(child);
7598184095Smav	int retval;
7599184095Smav
7600184095Smav	retval = bus_print_child_header(dev, child);
7601184095Smav	retval += printf(" at cad %d nid %d",
7602184095Smav	    pdevinfo->devinfo->codec->cad, pdevinfo->devinfo->nid);
7603184095Smav	retval += bus_print_child_footer(dev, child);
7604184095Smav
7605184095Smav	return (retval);
7606184095Smav}
7607184095Smav
7608162922Sariffstatic device_method_t hdac_methods[] = {
7609162922Sariff	/* device interface */
7610162922Sariff	DEVMETHOD(device_probe,		hdac_probe),
7611162922Sariff	DEVMETHOD(device_attach,	hdac_attach),
7612162922Sariff	DEVMETHOD(device_detach,	hdac_detach),
7613182999Smav	DEVMETHOD(device_suspend,	hdac_suspend),
7614182999Smav	DEVMETHOD(device_resume,	hdac_resume),
7615184095Smav	/* Bus interface */
7616184095Smav	DEVMETHOD(bus_print_child,	hdac_print_child),
7617162922Sariff	{ 0, 0 }
7618162922Sariff};
7619162922Sariff
7620162922Sariffstatic driver_t hdac_driver = {
7621182999Smav	"hdac",
7622162922Sariff	hdac_methods,
7623182999Smav	sizeof(struct hdac_softc),
7624162922Sariff};
7625162922Sariff
7626182999Smavstatic devclass_t hdac_devclass;
7627182999Smav
7628182999SmavDRIVER_MODULE(snd_hda, pci, hdac_driver, hdac_devclass, 0, 0);
7629162922SariffMODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
7630162922SariffMODULE_VERSION(snd_hda, 1);
7631182999Smav
7632182999Smavstatic int
7633182999Smavhdac_pcm_probe(device_t dev)
7634182999Smav{
7635182999Smav	struct hdac_pcm_devinfo *pdevinfo =
7636182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
7637182999Smav	char buf[128];
7638182999Smav
7639184095Smav	snprintf(buf, sizeof(buf), "HDA %s PCM #%d",
7640182999Smav	    hdac_codec_name(pdevinfo->devinfo->codec),
7641182999Smav	    pdevinfo->index);
7642182999Smav	device_set_desc_copy(dev, buf);
7643182999Smav	return (0);
7644182999Smav}
7645182999Smav
7646182999Smavstatic int
7647182999Smavhdac_pcm_attach(device_t dev)
7648182999Smav{
7649182999Smav	struct hdac_pcm_devinfo *pdevinfo =
7650182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
7651182999Smav	struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
7652182999Smav	char status[SND_STATUSLEN];
7653182999Smav	int i;
7654182999Smav
7655182999Smav	pdevinfo->chan_size = pcm_getbuffersize(dev,
7656182999Smav	    HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
7657182999Smav
7658182999Smav	HDA_BOOTVERBOSE(
7659182999Smav		device_printf(dev, "+--------------------------------------+\n");
7660182999Smav		device_printf(dev, "| DUMPING PCM Playback/Record Channels |\n");
7661182999Smav		device_printf(dev, "+--------------------------------------+\n");
7662182999Smav		hdac_dump_pcmchannels(pdevinfo);
7663182999Smav		device_printf(dev, "\n");
7664182999Smav		device_printf(dev, "+--------------------------------+\n");
7665182999Smav		device_printf(dev, "| DUMPING Playback/Record Pathes |\n");
7666182999Smav		device_printf(dev, "+--------------------------------+\n");
7667182999Smav		hdac_dump_dac(pdevinfo);
7668182999Smav		hdac_dump_adc(pdevinfo);
7669182999Smav		hdac_dump_mix(pdevinfo);
7670182999Smav		device_printf(dev, "\n");
7671182999Smav		device_printf(dev, "+-------------------------+\n");
7672182999Smav		device_printf(dev, "| DUMPING Volume Controls |\n");
7673182999Smav		device_printf(dev, "+-------------------------+\n");
7674182999Smav		hdac_dump_ctls(pdevinfo, "Master Volume", SOUND_MASK_VOLUME);
7675182999Smav		hdac_dump_ctls(pdevinfo, "PCM Volume", SOUND_MASK_PCM);
7676182999Smav		hdac_dump_ctls(pdevinfo, "CD Volume", SOUND_MASK_CD);
7677182999Smav		hdac_dump_ctls(pdevinfo, "Microphone Volume", SOUND_MASK_MIC);
7678182999Smav		hdac_dump_ctls(pdevinfo, "Microphone2 Volume", SOUND_MASK_MONITOR);
7679182999Smav		hdac_dump_ctls(pdevinfo, "Line-in Volume", SOUND_MASK_LINE);
7680182999Smav		hdac_dump_ctls(pdevinfo, "Speaker/Beep Volume", SOUND_MASK_SPEAKER);
7681182999Smav		hdac_dump_ctls(pdevinfo, "Recording Level", SOUND_MASK_RECLEV);
7682182999Smav		hdac_dump_ctls(pdevinfo, "Input Mix Level", SOUND_MASK_IMIX);
7683182999Smav		hdac_dump_ctls(pdevinfo, NULL, 0);
7684182999Smav		device_printf(dev, "\n");
7685182999Smav	);
7686182999Smav
7687182999Smav	if (resource_int_value(device_get_name(dev),
7688182999Smav	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
7689182999Smav		i &= HDA_BLK_ALIGN;
7690182999Smav		if (i < HDA_BLK_MIN)
7691182999Smav			i = HDA_BLK_MIN;
7692182999Smav		pdevinfo->chan_blkcnt = pdevinfo->chan_size / i;
7693182999Smav		i = 0;
7694182999Smav		while (pdevinfo->chan_blkcnt >> i)
7695182999Smav			i++;
7696182999Smav		pdevinfo->chan_blkcnt = 1 << (i - 1);
7697182999Smav		if (pdevinfo->chan_blkcnt < HDA_BDL_MIN)
7698182999Smav			pdevinfo->chan_blkcnt = HDA_BDL_MIN;
7699182999Smav		else if (pdevinfo->chan_blkcnt > HDA_BDL_MAX)
7700182999Smav			pdevinfo->chan_blkcnt = HDA_BDL_MAX;
7701182999Smav	} else
7702182999Smav		pdevinfo->chan_blkcnt = HDA_BDL_DEFAULT;
7703182999Smav
7704182999Smav	/*
7705182999Smav	 * We don't register interrupt handler with snd_setup_intr
7706182999Smav	 * in pcm device. Mark pcm device as MPSAFE manually.
7707182999Smav	 */
7708182999Smav	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
7709182999Smav
7710183097Smav	HDA_BOOTHVERBOSE(
7711182999Smav		device_printf(dev, "OSS mixer initialization...\n");
7712182999Smav	);
7713182999Smav	if (mixer_init(dev, &hdac_audio_ctl_ossmixer_class, pdevinfo) != 0)
7714182999Smav		device_printf(dev, "Can't register mixer\n");
7715182999Smav
7716183097Smav	HDA_BOOTHVERBOSE(
7717182999Smav		device_printf(dev, "Registering PCM channels...\n");
7718182999Smav	);
7719182999Smav	if (pcm_register(dev, pdevinfo, (pdevinfo->play >= 0)?1:0,
7720182999Smav	    (pdevinfo->rec >= 0)?1:0) != 0)
7721182999Smav		device_printf(dev, "Can't register PCM\n");
7722182999Smav
7723182999Smav	pdevinfo->registered++;
7724182999Smav
7725182999Smav	if (pdevinfo->play >= 0)
7726182999Smav		pcm_addchan(dev, PCMDIR_PLAY, &hdac_channel_class, pdevinfo);
7727182999Smav	if (pdevinfo->rec >= 0)
7728182999Smav		pcm_addchan(dev, PCMDIR_REC, &hdac_channel_class, pdevinfo);
7729182999Smav
7730184095Smav	snprintf(status, SND_STATUSLEN, "at cad %d nid %d on %s %s",
7731184095Smav	    pdevinfo->devinfo->codec->cad, pdevinfo->devinfo->nid,
7732184095Smav	    device_get_nameunit(sc->dev), PCM_KLDSTRING(snd_hda));
7733182999Smav	pcm_setstatus(dev, status);
7734182999Smav
7735182999Smav	return (0);
7736182999Smav}
7737182999Smav
7738182999Smavstatic int
7739182999Smavhdac_pcm_detach(device_t dev)
7740182999Smav{
7741182999Smav	struct hdac_pcm_devinfo *pdevinfo =
7742182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
7743182999Smav	int err;
7744182999Smav
7745182999Smav	if (pdevinfo->registered > 0) {
7746182999Smav		err = pcm_unregister(dev);
7747182999Smav		if (err != 0)
7748182999Smav			return (err);
7749182999Smav	}
7750182999Smav
7751182999Smav	return (0);
7752182999Smav}
7753182999Smav
7754182999Smavstatic device_method_t hdac_pcm_methods[] = {
7755182999Smav	/* device interface */
7756182999Smav	DEVMETHOD(device_probe,		hdac_pcm_probe),
7757182999Smav	DEVMETHOD(device_attach,	hdac_pcm_attach),
7758182999Smav	DEVMETHOD(device_detach,	hdac_pcm_detach),
7759182999Smav	{ 0, 0 }
7760182999Smav};
7761182999Smav
7762182999Smavstatic driver_t hdac_pcm_driver = {
7763182999Smav	"pcm",
7764182999Smav	hdac_pcm_methods,
7765182999Smav	PCM_SOFTC_SIZE,
7766182999Smav};
7767182999Smav
7768182999SmavDRIVER_MODULE(snd_hda_pcm, hdac, hdac_pcm_driver, pcm_devclass, 0, 0);
7769182999Smav
7770