hdac.c revision 184254
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
86184231Smav#define HDA_DRV_TEST_REV	"20081024_0114"
87162922Sariff
88162922SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 184254 2008-10-25 08:31:20Z 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)
207178155Sariff#define DELL_V1500_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x0228)
208162922Sariff#define DELL_I1300_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01c9)
209169277Sariff#define DELL_XPSM1210_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01d7)
210169277Sariff#define DELL_OPLX745_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01da)
211162922Sariff#define DELL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0xffff)
212162922Sariff
213162922Sariff/* Clevo */
214162922Sariff#define CLEVO_VENDORID		0x1558
215162922Sariff#define CLEVO_D900T_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0x0900)
216162922Sariff#define CLEVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0xffff)
217162922Sariff
218162922Sariff/* Acer */
219162922Sariff#define ACER_VENDORID		0x1025
220165992Sariff#define ACER_A5050_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x010f)
221173817Sariff#define ACER_A4520_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0127)
222174182Sariff#define ACER_A4710_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x012f)
223182854Sjoel#define ACER_A4715_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0133)
224169277Sariff#define ACER_3681WXM_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0110)
225182999Smav#define ACER_T6292_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x011b)
226162922Sariff#define ACER_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0xffff)
227162922Sariff
228162965Sariff/* Asus */
229162965Sariff#define ASUS_VENDORID		0x1043
230178155Sariff#define ASUS_A8X_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1153)
231163276Sariff#define ASUS_U5F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
232178155Sariff#define ASUS_W6F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
233165281Sariff#define ASUS_A7M_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1323)
234178155Sariff#define ASUS_F3JC_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1338)
235178155Sariff#define ASUS_G2K_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1339)
236167623Sariff#define ASUS_A7T_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x13c2)
237169277Sariff#define ASUS_W2J_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1971)
238178155Sariff#define ASUS_M5200_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
239178155Sariff#define ASUS_P1AH2_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
240178155Sariff#define ASUS_M2NPVMX_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
241170518Sariff#define ASUS_M2V_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81e7)
242178155Sariff#define ASUS_P5BWD_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81ec)
243169277Sariff#define ASUS_M2N_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x8234)
244171141Sariff#define ASUS_A8NVMCSM_SUBVENDOR	HDA_MODEL_CONSTRUCT(NVIDIA, 0xcb84)
245162965Sariff#define ASUS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
246162922Sariff
247163257Sariff/* IBM / Lenovo */
248163257Sariff#define IBM_VENDORID		0x1014
249163257Sariff#define IBM_M52_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0x02f6)
250163257Sariff#define IBM_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0xffff)
251162965Sariff
252164614Sariff/* Lenovo */
253164657Sariff#define LENOVO_VENDORID		0x17aa
254164657Sariff#define LENOVO_3KN100_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x2066)
255182854Sjoel#define LENOVO_3KN200_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x384e)
256172811Sariff#define LENOVO_TCA55_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x1015)
257164657Sariff#define LENOVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0xffff)
258163257Sariff
259164657Sariff/* Samsung */
260164657Sariff#define SAMSUNG_VENDORID	0x144d
261164657Sariff#define SAMSUNG_Q1_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027)
262164657Sariff#define SAMSUNG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff)
263164614Sariff
264164750Sariff/* Medion ? */
265164750Sariff#define MEDION_VENDORID			0x161f
266164750Sariff#define MEDION_MD95257_SUBVENDOR	HDA_MODEL_CONSTRUCT(MEDION, 0x203d)
267164750Sariff#define MEDION_ALL_SUBVENDOR		HDA_MODEL_CONSTRUCT(MEDION, 0xffff)
268164750Sariff
269173817Sariff/* Apple Computer Inc. */
270173817Sariff#define APPLE_VENDORID		0x106b
271173817Sariff#define APPLE_MB3_SUBVENDOR	HDA_MODEL_CONSTRUCT(APPLE, 0x00a1)
272173817Sariff
273182999Smav/* Sony */
274182999Smav#define SONY_VENDORID		0x104d
275182999Smav#define SONY_S5_SUBVENDOR	HDA_MODEL_CONSTRUCT(SONY, 0x81cc)
276182999Smav#define SONY_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SONY, 0xffff)
277182999Smav
278164828Sariff/*
279164828Sariff * Apple Intel MacXXXX seems using Sigmatel codec/vendor id
280164828Sariff * instead of their own, which is beyond my comprehension
281164828Sariff * (see HDA_CODEC_STAC9221 below).
282164828Sariff */
283164828Sariff#define APPLE_INTEL_MAC		0x76808384
284164828Sariff
285165281Sariff/* LG Electronics */
286165281Sariff#define LG_VENDORID		0x1854
287165281Sariff#define LG_LW20_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0x0018)
288165281Sariff#define LG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0xffff)
289165281Sariff
290165351Sariff/* Fujitsu Siemens */
291165351Sariff#define FS_VENDORID		0x1734
292165351Sariff#define FS_PA1510_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10b8)
293172811Sariff#define FS_SI1848_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10cd)
294165351Sariff#define FS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0xffff)
295165351Sariff
296172811Sariff/* Fujitsu Limited */
297172811Sariff#define FL_VENDORID		0x10cf
298172811Sariff#define FL_S7020D_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x1326)
299182854Sjoel#define FL_U1010_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x142d)
300172811Sariff#define FL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0xffff)
301172811Sariff
302165770Sariff/* Toshiba */
303165770Sariff#define TOSHIBA_VENDORID	0x1179
304165770Sariff#define TOSHIBA_U200_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001)
305173817Sariff#define TOSHIBA_A135_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xff01)
306165770Sariff#define TOSHIBA_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff)
307165770Sariff
308165992Sariff/* Micro-Star International (MSI) */
309165992Sariff#define MSI_VENDORID		0x1462
310165992Sariff#define MSI_MS1034_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x0349)
311172811Sariff#define MSI_MS034A_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x034a)
312165992Sariff#define MSI_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0xffff)
313165992Sariff
314172811Sariff/* Giga-Byte Technology */
315172811Sariff#define GB_VENDORID		0x1458
316172811Sariff#define GB_G33S2H_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xa022)
317172811Sariff#define GP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xffff)
318172811Sariff
319169277Sariff/* Uniwill ? */
320169277Sariff#define UNIWILL_VENDORID	0x1584
321169277Sariff#define UNIWILL_9075_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075)
322170944Sariff#define UNIWILL_9080_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9080)
323169277Sariff
324169277Sariff
325162922Sariff/* Misc constants.. */
326182999Smav#define HDA_AMP_VOL_DEFAULT	(-1)
327162922Sariff#define HDA_AMP_MUTE_DEFAULT	(0xffffffff)
328162922Sariff#define HDA_AMP_MUTE_NONE	(0)
329162922Sariff#define HDA_AMP_MUTE_LEFT	(1 << 0)
330162922Sariff#define HDA_AMP_MUTE_RIGHT	(1 << 1)
331162922Sariff#define HDA_AMP_MUTE_ALL	(HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT)
332162922Sariff
333162922Sariff#define HDA_AMP_LEFT_MUTED(v)	((v) & (HDA_AMP_MUTE_LEFT))
334162922Sariff#define HDA_AMP_RIGHT_MUTED(v)	(((v) & HDA_AMP_MUTE_RIGHT) >> 1)
335162922Sariff
336182999Smav#define HDA_ADC_MONITOR		(1 << 0)
337162922Sariff
338182999Smav#define HDA_CTL_OUT		1
339182999Smav#define HDA_CTL_IN		2
340169277Sariff
341169277Sariff#define HDA_GPIO_MAX		8
342169277Sariff/* 0 - 7 = GPIO , 8 = Flush */
343163057Sariff#define HDA_QUIRK_GPIO0		(1 << 0)
344163057Sariff#define HDA_QUIRK_GPIO1		(1 << 1)
345163057Sariff#define HDA_QUIRK_GPIO2		(1 << 2)
346169277Sariff#define HDA_QUIRK_GPIO3		(1 << 3)
347169277Sariff#define HDA_QUIRK_GPIO4		(1 << 4)
348169277Sariff#define HDA_QUIRK_GPIO5		(1 << 5)
349169277Sariff#define HDA_QUIRK_GPIO6		(1 << 6)
350169277Sariff#define HDA_QUIRK_GPIO7		(1 << 7)
351169277Sariff#define HDA_QUIRK_GPIOFLUSH	(1 << 8)
352162922Sariff
353169277Sariff/* 9 - 25 = anything else */
354169277Sariff#define HDA_QUIRK_SOFTPCMVOL	(1 << 9)
355169277Sariff#define HDA_QUIRK_FIXEDRATE	(1 << 10)
356169277Sariff#define HDA_QUIRK_FORCESTEREO	(1 << 11)
357169277Sariff#define HDA_QUIRK_EAPDINV	(1 << 12)
358169277Sariff#define HDA_QUIRK_DMAPOS	(1 << 13)
359182999Smav#define HDA_QUIRK_SENSEINV	(1 << 14)
360169277Sariff
361169277Sariff/* 26 - 31 = vrefs */
362169277Sariff#define HDA_QUIRK_IVREF50	(1 << 26)
363169277Sariff#define HDA_QUIRK_IVREF80	(1 << 27)
364169277Sariff#define HDA_QUIRK_IVREF100	(1 << 28)
365169277Sariff#define HDA_QUIRK_OVREF50	(1 << 29)
366169277Sariff#define HDA_QUIRK_OVREF80	(1 << 30)
367169277Sariff#define HDA_QUIRK_OVREF100	(1 << 31)
368169277Sariff
369169277Sariff#define HDA_QUIRK_IVREF		(HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 | \
370169277Sariff							HDA_QUIRK_IVREF100)
371169277Sariff#define HDA_QUIRK_OVREF		(HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 | \
372169277Sariff							HDA_QUIRK_OVREF100)
373169277Sariff#define HDA_QUIRK_VREF		(HDA_QUIRK_IVREF | HDA_QUIRK_OVREF)
374169277Sariff
375171141Sariff#if __FreeBSD_version < 600000
376171141Sariff#define taskqueue_drain(...)
377171141Sariff#endif
378171141Sariff
379163057Sariffstatic const struct {
380163057Sariff	char *key;
381163057Sariff	uint32_t value;
382163057Sariff} hdac_quirks_tab[] = {
383163057Sariff	{ "gpio0", HDA_QUIRK_GPIO0 },
384163057Sariff	{ "gpio1", HDA_QUIRK_GPIO1 },
385163057Sariff	{ "gpio2", HDA_QUIRK_GPIO2 },
386169277Sariff	{ "gpio3", HDA_QUIRK_GPIO3 },
387169277Sariff	{ "gpio4", HDA_QUIRK_GPIO4 },
388169277Sariff	{ "gpio5", HDA_QUIRK_GPIO5 },
389169277Sariff	{ "gpio6", HDA_QUIRK_GPIO6 },
390169277Sariff	{ "gpio7", HDA_QUIRK_GPIO7 },
391165039Sariff	{ "gpioflush", HDA_QUIRK_GPIOFLUSH },
392163057Sariff	{ "softpcmvol", HDA_QUIRK_SOFTPCMVOL },
393163057Sariff	{ "fixedrate", HDA_QUIRK_FIXEDRATE },
394163136Sariff	{ "forcestereo", HDA_QUIRK_FORCESTEREO },
395163276Sariff	{ "eapdinv", HDA_QUIRK_EAPDINV },
396169277Sariff	{ "dmapos", HDA_QUIRK_DMAPOS },
397182999Smav	{ "senseinv", HDA_QUIRK_SENSEINV },
398169277Sariff	{ "ivref50", HDA_QUIRK_IVREF50 },
399169277Sariff	{ "ivref80", HDA_QUIRK_IVREF80 },
400169277Sariff	{ "ivref100", HDA_QUIRK_IVREF100 },
401169277Sariff	{ "ovref50", HDA_QUIRK_OVREF50 },
402169277Sariff	{ "ovref80", HDA_QUIRK_OVREF80 },
403169277Sariff	{ "ovref100", HDA_QUIRK_OVREF100 },
404169277Sariff	{ "ivref", HDA_QUIRK_IVREF },
405169277Sariff	{ "ovref", HDA_QUIRK_OVREF },
406165069Sariff	{ "vref", HDA_QUIRK_VREF },
407163057Sariff};
408163057Sariff#define HDAC_QUIRKS_TAB_LEN	\
409163057Sariff		(sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0]))
410163057Sariff
411162922Sariff#define HDA_BDL_MIN	2
412162922Sariff#define HDA_BDL_MAX	256
413162922Sariff#define HDA_BDL_DEFAULT	HDA_BDL_MIN
414162922Sariff
415169277Sariff#define HDA_BLK_MIN	HDAC_DMA_ALIGNMENT
416167648Sariff#define HDA_BLK_ALIGN	(~(HDA_BLK_MIN - 1))
417167648Sariff
418162922Sariff#define HDA_BUFSZ_MIN		4096
419162922Sariff#define HDA_BUFSZ_MAX		65536
420162922Sariff#define HDA_BUFSZ_DEFAULT	16384
421162922Sariff
422162922Sariff#define HDA_PARSE_MAXDEPTH	10
423162922Sariff
424169277Sariff#define HDAC_UNSOLTAG_EVENT_HP		0x00
425162922Sariff
426165239SariffMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
427162922Sariff
428182999Smavconst char *HDA_COLORS[16] = {"Unknown", "Black", "Grey", "Blue", "Green", "Red",
429182999Smav    "Orange", "Yellow", "Purple", "Pink", "Res.A", "Res.B", "Res.C", "Res.D",
430182999Smav    "White", "Other"};
431162922Sariff
432182999Smavconst char *HDA_DEVS[16] = {"Line-out", "Speaker", "Headphones", "CD",
433182999Smav    "SPDIF-out", "Digital-out", "Modem-line", "Modem-handset", "Line-in",
434182999Smav    "AUX", "Mic", "Telephony", "SPDIF-in", "Digital-in", "Res.E", "Other"};
435182999Smav
436182999Smavconst char *HDA_CONNS[4] = {"Jack", "None", "Fixed", "Both"};
437182999Smav
438162922Sariff/* Default */
439162922Sariffstatic uint32_t hdac_fmt[] = {
440162922Sariff	AFMT_STEREO | AFMT_S16_LE,
441162922Sariff	0
442162922Sariff};
443162922Sariff
444162922Sariffstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0};
445162922Sariff
446162922Sariffstatic const struct {
447162922Sariff	uint32_t	model;
448162922Sariff	char		*desc;
449162922Sariff} hdac_devices[] = {
450162922Sariff	{ HDA_INTEL_82801F,  "Intel 82801F" },
451171330Sariff	{ HDA_INTEL_63XXESB, "Intel 631x/632xESB" },
452162922Sariff	{ HDA_INTEL_82801G,  "Intel 82801G" },
453163136Sariff	{ HDA_INTEL_82801H,  "Intel 82801H" },
454171330Sariff	{ HDA_INTEL_82801I,  "Intel 82801I" },
455184207Smav	{ HDA_INTEL_82801J,  "Intel 82801J" },
456184207Smav	{ HDA_INTEL_SCH,     "Intel SCH" },
457162922Sariff	{ HDA_NVIDIA_MCP51,  "NVidia MCP51" },
458162922Sariff	{ HDA_NVIDIA_MCP55,  "NVidia MCP55" },
459173817Sariff	{ HDA_NVIDIA_MCP61_1, "NVidia MCP61" },
460173817Sariff	{ HDA_NVIDIA_MCP61_2, "NVidia MCP61" },
461173817Sariff	{ HDA_NVIDIA_MCP65_1, "NVidia MCP65" },
462174004Sariff	{ HDA_NVIDIA_MCP65_2, "NVidia MCP65" },
463173817Sariff	{ HDA_NVIDIA_MCP67_1, "NVidia MCP67" },
464173817Sariff	{ HDA_NVIDIA_MCP67_2, "NVidia MCP67" },
465162922Sariff	{ HDA_ATI_SB450,     "ATI SB450"    },
466163136Sariff	{ HDA_ATI_SB600,     "ATI SB600"    },
467163136Sariff	{ HDA_VIA_VT82XX,    "VIA VT8251/8237A" },
468163136Sariff	{ HDA_SIS_966,       "SiS 966" },
469162922Sariff	/* Unknown */
470162922Sariff	{ HDA_INTEL_ALL,  "Intel (Unknown)"  },
471162922Sariff	{ HDA_NVIDIA_ALL, "NVidia (Unknown)" },
472162922Sariff	{ HDA_ATI_ALL,    "ATI (Unknown)"    },
473163136Sariff	{ HDA_VIA_ALL,    "VIA (Unknown)"    },
474163136Sariff	{ HDA_SIS_ALL,    "SiS (Unknown)"    },
475162922Sariff};
476162922Sariff#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0]))
477162922Sariff
478162922Sariffstatic const struct {
479169277Sariff	uint16_t vendor;
480169277Sariff	uint8_t reg;
481169277Sariff	uint8_t mask;
482169277Sariff	uint8_t enable;
483169277Sariff} hdac_pcie_snoop[] = {
484169277Sariff	{  INTEL_VENDORID, 0x00, 0x00, 0x00 },
485169277Sariff	{    ATI_VENDORID, 0x42, 0xf8, 0x02 },
486169277Sariff	{ NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f },
487169277Sariff};
488169277Sariff#define HDAC_PCIESNOOP_LEN	\
489169277Sariff			(sizeof(hdac_pcie_snoop) / sizeof(hdac_pcie_snoop[0]))
490169277Sariff
491169277Sariffstatic const struct {
492162922Sariff	uint32_t	rate;
493162922Sariff	int		valid;
494162922Sariff	uint16_t	base;
495162922Sariff	uint16_t	mul;
496162922Sariff	uint16_t	div;
497162922Sariff} hda_rate_tab[] = {
498162922Sariff	{   8000, 1, 0x0000, 0x0000, 0x0500 },	/* (48000 * 1) / 6 */
499162922Sariff	{   9600, 0, 0x0000, 0x0000, 0x0400 },	/* (48000 * 1) / 5 */
500162922Sariff	{  12000, 0, 0x0000, 0x0000, 0x0300 },	/* (48000 * 1) / 4 */
501162922Sariff	{  16000, 1, 0x0000, 0x0000, 0x0200 },	/* (48000 * 1) / 3 */
502162922Sariff	{  18000, 0, 0x0000, 0x1000, 0x0700 },	/* (48000 * 3) / 8 */
503162922Sariff	{  19200, 0, 0x0000, 0x0800, 0x0400 },	/* (48000 * 2) / 5 */
504162922Sariff	{  24000, 0, 0x0000, 0x0000, 0x0100 },	/* (48000 * 1) / 2 */
505162922Sariff	{  28800, 0, 0x0000, 0x1000, 0x0400 },	/* (48000 * 3) / 5 */
506162922Sariff	{  32000, 1, 0x0000, 0x0800, 0x0200 },	/* (48000 * 2) / 3 */
507162922Sariff	{  36000, 0, 0x0000, 0x1000, 0x0300 },	/* (48000 * 3) / 4 */
508162922Sariff	{  38400, 0, 0x0000, 0x1800, 0x0400 },	/* (48000 * 4) / 5 */
509162922Sariff	{  48000, 1, 0x0000, 0x0000, 0x0000 },	/* (48000 * 1) / 1 */
510162922Sariff	{  64000, 0, 0x0000, 0x1800, 0x0200 },	/* (48000 * 4) / 3 */
511162922Sariff	{  72000, 0, 0x0000, 0x1000, 0x0100 },	/* (48000 * 3) / 2 */
512162922Sariff	{  96000, 1, 0x0000, 0x0800, 0x0000 },	/* (48000 * 2) / 1 */
513162922Sariff	{ 144000, 0, 0x0000, 0x1000, 0x0000 },	/* (48000 * 3) / 1 */
514162922Sariff	{ 192000, 1, 0x0000, 0x1800, 0x0000 },	/* (48000 * 4) / 1 */
515162922Sariff	{   8820, 0, 0x4000, 0x0000, 0x0400 },	/* (44100 * 1) / 5 */
516162922Sariff	{  11025, 1, 0x4000, 0x0000, 0x0300 },	/* (44100 * 1) / 4 */
517162922Sariff	{  12600, 0, 0x4000, 0x0800, 0x0600 },	/* (44100 * 2) / 7 */
518162922Sariff	{  14700, 0, 0x4000, 0x0000, 0x0200 },	/* (44100 * 1) / 3 */
519162922Sariff	{  17640, 0, 0x4000, 0x0800, 0x0400 },	/* (44100 * 2) / 5 */
520162922Sariff	{  18900, 0, 0x4000, 0x1000, 0x0600 },	/* (44100 * 3) / 7 */
521162922Sariff	{  22050, 1, 0x4000, 0x0000, 0x0100 },	/* (44100 * 1) / 2 */
522162922Sariff	{  25200, 0, 0x4000, 0x1800, 0x0600 },	/* (44100 * 4) / 7 */
523162922Sariff	{  26460, 0, 0x4000, 0x1000, 0x0400 },	/* (44100 * 3) / 5 */
524162922Sariff	{  29400, 0, 0x4000, 0x0800, 0x0200 },	/* (44100 * 2) / 3 */
525162922Sariff	{  33075, 0, 0x4000, 0x1000, 0x0300 },	/* (44100 * 3) / 4 */
526162922Sariff	{  35280, 0, 0x4000, 0x1800, 0x0400 },	/* (44100 * 4) / 5 */
527162922Sariff	{  44100, 1, 0x4000, 0x0000, 0x0000 },	/* (44100 * 1) / 1 */
528162922Sariff	{  58800, 0, 0x4000, 0x1800, 0x0200 },	/* (44100 * 4) / 3 */
529162922Sariff	{  66150, 0, 0x4000, 0x1000, 0x0100 },	/* (44100 * 3) / 2 */
530162922Sariff	{  88200, 1, 0x4000, 0x0800, 0x0000 },	/* (44100 * 2) / 1 */
531162922Sariff	{ 132300, 0, 0x4000, 0x1000, 0x0000 },	/* (44100 * 3) / 1 */
532162922Sariff	{ 176400, 1, 0x4000, 0x1800, 0x0000 },	/* (44100 * 4) / 1 */
533162922Sariff};
534162922Sariff#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
535162922Sariff
536162922Sariff/* All codecs you can eat... */
537162922Sariff#define HDA_CODEC_CONSTRUCT(vendor, id) \
538162922Sariff		(((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff))
539162922Sariff
540162922Sariff/* Realtek */
541162922Sariff#define REALTEK_VENDORID	0x10ec
542162922Sariff#define HDA_CODEC_ALC260	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
543169277Sariff#define HDA_CODEC_ALC262	HDA_CODEC_CONSTRUCT(REALTEK, 0x0262)
544183024Smav#define HDA_CODEC_ALC267	HDA_CODEC_CONSTRUCT(REALTEK, 0x0267)
545171330Sariff#define HDA_CODEC_ALC268	HDA_CODEC_CONSTRUCT(REALTEK, 0x0268)
546183024Smav#define HDA_CODEC_ALC269	HDA_CODEC_CONSTRUCT(REALTEK, 0x0269)
547183024Smav#define HDA_CODEC_ALC272	HDA_CODEC_CONSTRUCT(REALTEK, 0x0272)
548170518Sariff#define HDA_CODEC_ALC660	HDA_CODEC_CONSTRUCT(REALTEK, 0x0660)
549183024Smav#define HDA_CODEC_ALC662	HDA_CODEC_CONSTRUCT(REALTEK, 0x0662)
550183025Smav#define HDA_CODEC_ALC663	HDA_CODEC_CONSTRUCT(REALTEK, 0x0663)
551162922Sariff#define HDA_CODEC_ALC861	HDA_CODEC_CONSTRUCT(REALTEK, 0x0861)
552169277Sariff#define HDA_CODEC_ALC861VD	HDA_CODEC_CONSTRUCT(REALTEK, 0x0862)
553162922Sariff#define HDA_CODEC_ALC880	HDA_CODEC_CONSTRUCT(REALTEK, 0x0880)
554163057Sariff#define HDA_CODEC_ALC882	HDA_CODEC_CONSTRUCT(REALTEK, 0x0882)
555163057Sariff#define HDA_CODEC_ALC883	HDA_CODEC_CONSTRUCT(REALTEK, 0x0883)
556169277Sariff#define HDA_CODEC_ALC885	HDA_CODEC_CONSTRUCT(REALTEK, 0x0885)
557165305Sariff#define HDA_CODEC_ALC888	HDA_CODEC_CONSTRUCT(REALTEK, 0x0888)
558182999Smav#define HDA_CODEC_ALC889	HDA_CODEC_CONSTRUCT(REALTEK, 0x0889)
559162922Sariff#define HDA_CODEC_ALCXXXX	HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
560162922Sariff
561169277Sariff/* Analog Devices */
562169277Sariff#define ANALOGDEVICES_VENDORID	0x11d4
563169277Sariff#define HDA_CODEC_AD1981HD	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981)
564169277Sariff#define HDA_CODEC_AD1983	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983)
565174025Sariff#define HDA_CODEC_AD1984	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1984)
566169277Sariff#define HDA_CODEC_AD1986A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986)
567169277Sariff#define HDA_CODEC_AD1988	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988)
568170518Sariff#define HDA_CODEC_AD1988B	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x198b)
569169277Sariff#define HDA_CODEC_ADXXXX	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff)
570162922Sariff
571162922Sariff/* CMedia */
572162922Sariff#define CMEDIA_VENDORID		0x434d
573162922Sariff#define HDA_CODEC_CMI9880	HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980)
574162922Sariff#define HDA_CODEC_CMIXXXX	HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff)
575162922Sariff
576162922Sariff/* Sigmatel */
577162922Sariff#define SIGMATEL_VENDORID	0x8384
578182999Smav#define HDA_CODEC_STAC9230X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7612)
579182999Smav#define HDA_CODEC_STAC9230D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7613)
580182999Smav#define HDA_CODEC_STAC9229X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7614)
581182999Smav#define HDA_CODEC_STAC9229D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7615)
582182999Smav#define HDA_CODEC_STAC9228X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7616)
583182999Smav#define HDA_CODEC_STAC9228D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7617)
584182999Smav#define HDA_CODEC_STAC9227X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
585182999Smav#define HDA_CODEC_STAC9227D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7619)
586183894Smav#define HDA_CODEC_STAC9274	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7620)
587183894Smav#define HDA_CODEC_STAC9274D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7621)
588183894Smav#define HDA_CODEC_STAC9273X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7622)
589183894Smav#define HDA_CODEC_STAC9273D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7623)
590183894Smav#define HDA_CODEC_STAC9272X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7624)
591183894Smav#define HDA_CODEC_STAC9272D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7625)
592183894Smav#define HDA_CODEC_STAC9271X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7626)
593182999Smav#define HDA_CODEC_STAC9271D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
594183894Smav#define HDA_CODEC_STAC9274X5NH	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7628)
595183894Smav#define HDA_CODEC_STAC9274D5NH	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7629)
596183894Smav#define HDA_CODEC_STAC9250	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7634)
597183894Smav#define HDA_CODEC_STAC9251	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7636)
598183894Smav#define HDA_CODEC_IDT92HD700X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7638)
599183894Smav#define HDA_CODEC_IDT92HD700D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7639)
600183894Smav#define HDA_CODEC_IDT92HD206X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7645)
601183894Smav#define HDA_CODEC_IDT92HD206D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7646)
602182999Smav#define HDA_CODEC_STAC9872AK	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7662)
603162922Sariff#define HDA_CODEC_STAC9221	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
604182999Smav#define HDA_CODEC_STAC922XD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
605183894Smav#define HDA_CODEC_STAC9221_A2	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7682)
606162922Sariff#define HDA_CODEC_STAC9221D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
607162922Sariff#define HDA_CODEC_STAC9220	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
608183894Smav#define HDA_CODEC_STAC9200D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7691)
609183894Smav#define HDA_CODEC_IDT92HD005	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7698)
610183894Smav#define HDA_CODEC_IDT92HD005D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7699)
611183894Smav#define HDA_CODEC_STAC9205X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0)
612183894Smav#define HDA_CODEC_STAC9205D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a1)
613183894Smav#define HDA_CODEC_STAC9204X	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a2)
614183894Smav#define HDA_CODEC_STAC9204D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a3)
615183894Smav#define HDA_CODEC_STAC9220_A2	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7880)
616183894Smav#define HDA_CODEC_STAC9220_A1	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7882)
617162922Sariff#define HDA_CODEC_STACXXXX	HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
618162922Sariff
619183894Smav/* IDT */
620183894Smav#define IDT_VENDORID		0x111d
621183894Smav#define HDA_CODEC_IDT92HD75BX	HDA_CODEC_CONSTRUCT(IDT, 0x7603)
622183894Smav#define HDA_CODEC_IDT92HD83C1X	HDA_CODEC_CONSTRUCT(IDT, 0x7604)
623183894Smav#define HDA_CODEC_IDT92HD81B1X	HDA_CODEC_CONSTRUCT(IDT, 0x7605)
624183894Smav#define HDA_CODEC_IDT92HD75B3	HDA_CODEC_CONSTRUCT(IDT, 0x7608)
625183894Smav#define HDA_CODEC_IDT92HD73D1	HDA_CODEC_CONSTRUCT(IDT, 0x7674)
626183894Smav#define HDA_CODEC_IDT92HD73C1	HDA_CODEC_CONSTRUCT(IDT, 0x7675)
627183894Smav#define HDA_CODEC_IDT92HD73E1	HDA_CODEC_CONSTRUCT(IDT, 0x7676)
628183894Smav#define HDA_CODEC_IDT92HD71B8	HDA_CODEC_CONSTRUCT(IDT, 0x76b0)
629183894Smav#define HDA_CODEC_IDT92HD71B7	HDA_CODEC_CONSTRUCT(IDT, 0x76b2)
630183894Smav#define HDA_CODEC_IDT92HD71B5	HDA_CODEC_CONSTRUCT(IDT, 0x76b6)
631183894Smav#define HDA_CODEC_IDT92HD83C1C	HDA_CODEC_CONSTRUCT(IDT, 0x76d4)
632183894Smav#define HDA_CODEC_IDT92HD81B1C	HDA_CODEC_CONSTRUCT(IDT, 0x76d5)
633183894Smav#define HDA_CODEC_IDTXXXX	HDA_CODEC_CONSTRUCT(IDT, 0xffff)
634183894Smav
635182999Smav/* Silicon Image */
636182999Smav#define SII_VENDORID	0x1095
637182999Smav#define HDA_CODEC_SIIXXXX	HDA_CODEC_CONSTRUCT(SII, 0xffff)
638182999Smav
639182999Smav/* Lucent/Agere */
640182999Smav#define AGERE_VENDORID	0x11c1
641182999Smav#define HDA_CODEC_AGEREXXXX	HDA_CODEC_CONSTRUCT(AGERE, 0xffff)
642182999Smav
643162922Sariff/*
644162922Sariff * Conexant
645162922Sariff *
646162922Sariff * Ok, the truth is, I don't have any idea at all whether
647162922Sariff * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only
648162922Sariff * place that tell me it is "Venice" is from its Windows driver INF.
649163057Sariff *
650163057Sariff *  Venice - CX?????
651163057Sariff * Waikiki - CX20551-22
652162922Sariff */
653162922Sariff#define CONEXANT_VENDORID	0x14f1
654162922Sariff#define HDA_CODEC_CXVENICE	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045)
655163057Sariff#define HDA_CODEC_CXWAIKIKI	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047)
656162922Sariff#define HDA_CODEC_CXXXXX	HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff)
657162922Sariff
658169277Sariff/* VIA */
659169277Sariff#define HDA_CODEC_VT1708_8	HDA_CODEC_CONSTRUCT(VIA, 0x1708)
660169277Sariff#define HDA_CODEC_VT1708_9	HDA_CODEC_CONSTRUCT(VIA, 0x1709)
661169277Sariff#define HDA_CODEC_VT1708_A	HDA_CODEC_CONSTRUCT(VIA, 0x170a)
662169277Sariff#define HDA_CODEC_VT1708_B	HDA_CODEC_CONSTRUCT(VIA, 0x170b)
663169277Sariff#define HDA_CODEC_VT1709_0	HDA_CODEC_CONSTRUCT(VIA, 0xe710)
664169277Sariff#define HDA_CODEC_VT1709_1	HDA_CODEC_CONSTRUCT(VIA, 0xe711)
665169277Sariff#define HDA_CODEC_VT1709_2	HDA_CODEC_CONSTRUCT(VIA, 0xe712)
666169277Sariff#define HDA_CODEC_VT1709_3	HDA_CODEC_CONSTRUCT(VIA, 0xe713)
667169277Sariff#define HDA_CODEC_VT1709_4	HDA_CODEC_CONSTRUCT(VIA, 0xe714)
668169277Sariff#define HDA_CODEC_VT1709_5	HDA_CODEC_CONSTRUCT(VIA, 0xe715)
669169277Sariff#define HDA_CODEC_VT1709_6	HDA_CODEC_CONSTRUCT(VIA, 0xe716)
670169277Sariff#define HDA_CODEC_VT1709_7	HDA_CODEC_CONSTRUCT(VIA, 0xe717)
671169277Sariff#define HDA_CODEC_VTXXXX	HDA_CODEC_CONSTRUCT(VIA, 0xffff)
672162922Sariff
673182999Smav/* ATI */
674182999Smav#define HDA_CODEC_ATIXXXX	HDA_CODEC_CONSTRUCT(ATI, 0xffff)
675169277Sariff
676182999Smav/* NVIDIA */
677182999Smav#define HDA_CODEC_NVIDIAXXXX	HDA_CODEC_CONSTRUCT(NVIDIA, 0xffff)
678182999Smav
679183894Smav/* INTEL */
680183894Smav#define HDA_CODEC_INTELXXXX	HDA_CODEC_CONSTRUCT(INTEL, 0xffff)
681183894Smav
682162922Sariff/* Codecs */
683162922Sariffstatic const struct {
684162922Sariff	uint32_t id;
685162922Sariff	char *name;
686162922Sariff} hdac_codecs[] = {
687162922Sariff	{ HDA_CODEC_ALC260,    "Realtek ALC260" },
688169277Sariff	{ HDA_CODEC_ALC262,    "Realtek ALC262" },
689183024Smav	{ HDA_CODEC_ALC267,    "Realtek ALC267" },
690171330Sariff	{ HDA_CODEC_ALC268,    "Realtek ALC268" },
691183024Smav	{ HDA_CODEC_ALC269,    "Realtek ALC269" },
692183024Smav	{ HDA_CODEC_ALC272,    "Realtek ALC272" },
693170518Sariff	{ HDA_CODEC_ALC660,    "Realtek ALC660" },
694183024Smav	{ HDA_CODEC_ALC662,    "Realtek ALC662" },
695183024Smav	{ HDA_CODEC_ALC663,    "Realtek ALC663" },
696162922Sariff	{ HDA_CODEC_ALC861,    "Realtek ALC861" },
697169277Sariff	{ HDA_CODEC_ALC861VD,  "Realtek ALC861-VD" },
698162922Sariff	{ HDA_CODEC_ALC880,    "Realtek ALC880" },
699162922Sariff	{ HDA_CODEC_ALC882,    "Realtek ALC882" },
700163057Sariff	{ HDA_CODEC_ALC883,    "Realtek ALC883" },
701169277Sariff	{ HDA_CODEC_ALC885,    "Realtek ALC885" },
702165305Sariff	{ HDA_CODEC_ALC888,    "Realtek ALC888" },
703182999Smav	{ HDA_CODEC_ALC889,    "Realtek ALC889" },
704169277Sariff	{ HDA_CODEC_AD1981HD,  "Analog Devices AD1981HD" },
705169277Sariff	{ HDA_CODEC_AD1983,    "Analog Devices AD1983" },
706174025Sariff	{ HDA_CODEC_AD1984,    "Analog Devices AD1984" },
707169277Sariff	{ HDA_CODEC_AD1986A,   "Analog Devices AD1986A" },
708169277Sariff	{ HDA_CODEC_AD1988,    "Analog Devices AD1988" },
709170518Sariff	{ HDA_CODEC_AD1988B,   "Analog Devices AD1988B" },
710162922Sariff	{ HDA_CODEC_CMI9880,   "CMedia CMI9880" },
711183894Smav	{ HDA_CODEC_STAC9200D, "Sigmatel STAC9200D" },
712183894Smav	{ HDA_CODEC_STAC9204X, "Sigmatel STAC9204X" },
713183894Smav	{ HDA_CODEC_STAC9204D, "Sigmatel STAC9204D" },
714183894Smav	{ HDA_CODEC_STAC9205X, "Sigmatel STAC9205X" },
715183894Smav	{ HDA_CODEC_STAC9205D, "Sigmatel STAC9205D" },
716183894Smav	{ HDA_CODEC_STAC9220,  "Sigmatel STAC9220" },
717183894Smav	{ HDA_CODEC_STAC9220_A1, "Sigmatel STAC9220_A1" },
718183894Smav	{ HDA_CODEC_STAC9220_A2, "Sigmatel STAC9220_A2" },
719162922Sariff	{ HDA_CODEC_STAC9221,  "Sigmatel STAC9221" },
720183894Smav	{ HDA_CODEC_STAC9221_A2, "Sigmatel STAC9221_A2" },
721162922Sariff	{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
722162922Sariff	{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
723183894Smav	{ HDA_CODEC_STAC9227X, "Sigmatel STAC9227X" },
724183894Smav	{ HDA_CODEC_STAC9227D, "Sigmatel STAC9227D" },
725183894Smav	{ HDA_CODEC_STAC9228X, "Sigmatel STAC9228X" },
726183894Smav	{ HDA_CODEC_STAC9228D, "Sigmatel STAC9228D" },
727183894Smav	{ HDA_CODEC_STAC9229X, "Sigmatel STAC9229X" },
728183894Smav	{ HDA_CODEC_STAC9229D, "Sigmatel STAC9229D" },
729182999Smav	{ HDA_CODEC_STAC9230X, "Sigmatel STAC9230X" },
730182999Smav	{ HDA_CODEC_STAC9230D, "Sigmatel STAC9230D" },
731183894Smav	{ HDA_CODEC_STAC9250,  "Sigmatel STAC9250" },
732183894Smav	{ HDA_CODEC_STAC9251,  "Sigmatel STAC9251" },
733183894Smav	{ HDA_CODEC_STAC9271X, "Sigmatel STAC9271X" },
734166796Sariff	{ HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" },
735183894Smav	{ HDA_CODEC_STAC9272X, "Sigmatel STAC9272X" },
736183894Smav	{ HDA_CODEC_STAC9272D, "Sigmatel STAC9272D" },
737183894Smav	{ HDA_CODEC_STAC9273X, "Sigmatel STAC9273X" },
738183894Smav	{ HDA_CODEC_STAC9273D, "Sigmatel STAC9273D" },
739183894Smav	{ HDA_CODEC_STAC9274,  "Sigmatel STAC9274" },
740183894Smav	{ HDA_CODEC_STAC9274D, "Sigmatel STAC9274D" },
741183894Smav	{ HDA_CODEC_STAC9274X5NH, "Sigmatel STAC9274X5NH" },
742183894Smav	{ HDA_CODEC_STAC9274D5NH, "Sigmatel STAC9274D5NH" },
743183894Smav	{ HDA_CODEC_STAC9872AK, "Sigmatel STAC9872AK" },
744183894Smav	{ HDA_CODEC_IDT92HD005, "IDT 92HD005" },
745183894Smav	{ HDA_CODEC_IDT92HD005D, "IDT 92HD005D" },
746183894Smav	{ HDA_CODEC_IDT92HD206X, "IDT 92HD206X" },
747183894Smav	{ HDA_CODEC_IDT92HD206D, "IDT 92HD206D" },
748183894Smav	{ HDA_CODEC_IDT92HD700X, "IDT 92HD700X" },
749183894Smav	{ HDA_CODEC_IDT92HD700D, "IDT 92HD700D" },
750183894Smav	{ HDA_CODEC_IDT92HD71B5, "IDT 92HD71B5" },
751183894Smav	{ HDA_CODEC_IDT92HD71B7, "IDT 92HD71B7" },
752183894Smav	{ HDA_CODEC_IDT92HD71B8, "IDT 92HD71B8" },
753183894Smav	{ HDA_CODEC_IDT92HD73C1, "IDT 92HD73C1" },
754183894Smav	{ HDA_CODEC_IDT92HD73D1, "IDT 92HD73D1" },
755183894Smav	{ HDA_CODEC_IDT92HD73E1, "IDT 92HD73E1" },
756183894Smav	{ HDA_CODEC_IDT92HD75B3, "IDT 92HD75B3" },
757183894Smav	{ HDA_CODEC_IDT92HD75BX, "IDT 92HD75BX" },
758183894Smav	{ HDA_CODEC_IDT92HD81B1C, "IDT 92HD81B1C" },
759183894Smav	{ HDA_CODEC_IDT92HD81B1X, "IDT 92HD81B1X" },
760183894Smav	{ HDA_CODEC_IDT92HD83C1C, "IDT 92HD83C1C" },
761183894Smav	{ HDA_CODEC_IDT92HD83C1X, "IDT 92HD83C1X" },
762162922Sariff	{ HDA_CODEC_CXVENICE,  "Conexant Venice" },
763163057Sariff	{ HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" },
764169277Sariff	{ HDA_CODEC_VT1708_8,  "VIA VT1708_8" },
765169277Sariff	{ HDA_CODEC_VT1708_9,  "VIA VT1708_9" },
766169277Sariff	{ HDA_CODEC_VT1708_A,  "VIA VT1708_A" },
767169277Sariff	{ HDA_CODEC_VT1708_B,  "VIA VT1708_B" },
768169277Sariff	{ HDA_CODEC_VT1709_0,  "VIA VT1709_0" },
769169277Sariff	{ HDA_CODEC_VT1709_1,  "VIA VT1709_1" },
770169277Sariff	{ HDA_CODEC_VT1709_2,  "VIA VT1709_2" },
771169277Sariff	{ HDA_CODEC_VT1709_3,  "VIA VT1709_3" },
772169277Sariff	{ HDA_CODEC_VT1709_4,  "VIA VT1709_4" },
773169277Sariff	{ HDA_CODEC_VT1709_5,  "VIA VT1709_5" },
774169277Sariff	{ HDA_CODEC_VT1709_6,  "VIA VT1709_6" },
775169277Sariff	{ HDA_CODEC_VT1709_7,  "VIA VT1709_7" },
776162922Sariff	/* Unknown codec */
777162922Sariff	{ HDA_CODEC_ALCXXXX,   "Realtek (Unknown)" },
778169277Sariff	{ HDA_CODEC_ADXXXX,    "Analog Devices (Unknown)" },
779162922Sariff	{ HDA_CODEC_CMIXXXX,   "CMedia (Unknown)" },
780162922Sariff	{ HDA_CODEC_STACXXXX,  "Sigmatel (Unknown)" },
781182999Smav	{ HDA_CODEC_SIIXXXX,   "Silicon Image (Unknown)" },
782182999Smav	{ HDA_CODEC_AGEREXXXX, "Lucent/Agere Systems (Unknown)" },
783162922Sariff	{ HDA_CODEC_CXXXXX,    "Conexant (Unknown)" },
784169277Sariff	{ HDA_CODEC_VTXXXX,    "VIA (Unknown)" },
785182999Smav	{ HDA_CODEC_ATIXXXX,   "ATI (Unknown)" },
786182999Smav	{ HDA_CODEC_NVIDIAXXXX,"NVidia (Unknown)" },
787183894Smav	{ HDA_CODEC_INTELXXXX, "Intel (Unknown)" },
788183894Smav	{ HDA_CODEC_IDTXXXX,   "IDT (Unknown)" },
789162922Sariff};
790162922Sariff#define HDAC_CODECS_LEN	(sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
791162922Sariff
792162922Sariff
793162922Sariff/****************************************************************************
794162922Sariff * Function prototypes
795162922Sariff ****************************************************************************/
796162922Sariffstatic void	hdac_intr_handler(void *);
797182999Smavstatic int	hdac_reset(struct hdac_softc *, int);
798162922Sariffstatic int	hdac_get_capabilities(struct hdac_softc *);
799162922Sariffstatic void	hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
800162922Sariffstatic int	hdac_dma_alloc(struct hdac_softc *,
801162922Sariff					struct hdac_dma *, bus_size_t);
802169277Sariffstatic void	hdac_dma_free(struct hdac_softc *, struct hdac_dma *);
803162922Sariffstatic int	hdac_mem_alloc(struct hdac_softc *);
804162922Sariffstatic void	hdac_mem_free(struct hdac_softc *);
805162922Sariffstatic int	hdac_irq_alloc(struct hdac_softc *);
806162922Sariffstatic void	hdac_irq_free(struct hdac_softc *);
807162922Sariffstatic void	hdac_corb_init(struct hdac_softc *);
808162922Sariffstatic void	hdac_rirb_init(struct hdac_softc *);
809162922Sariffstatic void	hdac_corb_start(struct hdac_softc *);
810162922Sariffstatic void	hdac_rirb_start(struct hdac_softc *);
811182999Smavstatic void	hdac_scan_codecs(struct hdac_softc *);
812182999Smavstatic void	hdac_probe_codec(struct hdac_codec *);
813182999Smavstatic void	hdac_probe_function(struct hdac_codec *, nid_t);
814182999Smavstatic int	hdac_pcmchannel_setup(struct hdac_chan *);
815162922Sariff
816162922Sariffstatic void	hdac_attach2(void *);
817162922Sariff
818162922Sariffstatic uint32_t	hdac_command_sendone_internal(struct hdac_softc *,
819162922Sariff							uint32_t, int);
820162922Sariffstatic void	hdac_command_send_internal(struct hdac_softc *,
821162922Sariff					struct hdac_command_list *, int);
822162922Sariff
823162922Sariffstatic int	hdac_probe(device_t);
824162922Sariffstatic int	hdac_attach(device_t);
825162922Sariffstatic int	hdac_detach(device_t);
826182999Smavstatic int	hdac_suspend(device_t);
827182999Smavstatic int	hdac_resume(device_t);
828162922Sariffstatic void	hdac_widget_connection_select(struct hdac_widget *, uint8_t);
829162922Sariffstatic void	hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
830162922Sariff						uint32_t, int, int);
831162922Sariffstatic struct	hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
832182999Smav							nid_t, int, int, int);
833162922Sariffstatic void	hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
834162922Sariff				nid_t, nid_t, int, int, int, int, int, int);
835162922Sariffstatic struct	hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
836162922Sariff
837164614Sariffstatic int	hdac_rirb_flush(struct hdac_softc *sc);
838164614Sariffstatic int	hdac_unsolq_flush(struct hdac_softc *sc);
839164614Sariff
840182999Smavstatic void	hdac_dump_pin_config(struct hdac_widget *w, uint32_t conf);
841182999Smav
842162922Sariff#define hdac_command(a1, a2, a3)	\
843162922Sariff		hdac_command_sendone_internal(a1, a2, a3)
844162922Sariff
845182999Smav#define hdac_codec_id(c)							\
846182999Smav		((uint32_t)((c == NULL) ? 0x00000000 :	\
847182999Smav		((((uint32_t)(c)->vendor_id & 0x0000ffff) << 16) |	\
848182999Smav		((uint32_t)(c)->device_id & 0x0000ffff))))
849162922Sariff
850162922Sariffstatic char *
851182999Smavhdac_codec_name(struct hdac_codec *codec)
852162922Sariff{
853162922Sariff	uint32_t id;
854162922Sariff	int i;
855162922Sariff
856182999Smav	id = hdac_codec_id(codec);
857162922Sariff
858162922Sariff	for (i = 0; i < HDAC_CODECS_LEN; i++) {
859163257Sariff		if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
860162922Sariff			return (hdac_codecs[i].name);
861162922Sariff	}
862162922Sariff
863162922Sariff	return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec");
864162922Sariff}
865162922Sariff
866162922Sariffstatic char *
867162922Sariffhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
868162922Sariff{
869162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
870162922Sariff	int i, first = 1;
871162922Sariff
872162922Sariff	bzero(buf, len);
873162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
874162922Sariff		if (mask & (1 << i)) {
875162922Sariff			if (first == 0)
876162922Sariff				strlcat(buf, ", ", len);
877162922Sariff			strlcat(buf, ossname[i], len);
878162922Sariff			first = 0;
879162922Sariff		}
880162922Sariff	}
881182999Smav	return (buf);
882162922Sariff}
883162922Sariff
884162922Sariffstatic struct hdac_audio_ctl *
885162922Sariffhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
886162922Sariff{
887162922Sariff	if (devinfo == NULL ||
888162922Sariff	    devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO ||
889162922Sariff	    index == NULL || devinfo->function.audio.ctl == NULL ||
890162922Sariff	    devinfo->function.audio.ctlcnt < 1 ||
891162922Sariff	    *index < 0 || *index >= devinfo->function.audio.ctlcnt)
892162922Sariff		return (NULL);
893162922Sariff	return (&devinfo->function.audio.ctl[(*index)++]);
894162922Sariff}
895162922Sariff
896162922Sariffstatic struct hdac_audio_ctl *
897182999Smavhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid, int dir,
898162922Sariff						int index, int cnt)
899162922Sariff{
900182999Smav	struct hdac_audio_ctl *ctl;
901182999Smav	int i, found = 0;
902162922Sariff
903162922Sariff	if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
904162922Sariff		return (NULL);
905162922Sariff
906162922Sariff	i = 0;
907162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
908182999Smav		if (ctl->enable == 0)
909162922Sariff			continue;
910182999Smav		if (ctl->widget->nid != nid)
911162922Sariff			continue;
912182999Smav		if (dir && ctl->ndir != dir)
913182999Smav			continue;
914182999Smav		if (index >= 0 && ctl->ndir == HDA_CTL_IN &&
915182999Smav		    ctl->dir == ctl->ndir && ctl->index != index)
916182999Smav			continue;
917162922Sariff		found++;
918182999Smav		if (found == cnt || cnt <= 0)
919162922Sariff			return (ctl);
920162922Sariff	}
921162922Sariff
922182999Smav	return (NULL);
923162922Sariff}
924162922Sariff
925182999Smav/*
926182999Smav * Jack detection (Speaker/HP redirection) event handler.
927182999Smav */
928162922Sariffstatic void
929162922Sariffhdac_hp_switch_handler(struct hdac_devinfo *devinfo)
930162922Sariff{
931182999Smav	struct hdac_audio_as *as;
932162922Sariff	struct hdac_softc *sc;
933162922Sariff	struct hdac_widget *w;
934162922Sariff	struct hdac_audio_ctl *ctl;
935182999Smav	uint32_t val, res;
936182999Smav	int i, j;
937162922Sariff	nid_t cad;
938162922Sariff
939162922Sariff	if (devinfo == NULL || devinfo->codec == NULL ||
940162922Sariff	    devinfo->codec->sc == NULL)
941162922Sariff		return;
942162922Sariff
943162922Sariff	sc = devinfo->codec->sc;
944162922Sariff	cad = devinfo->codec->cad;
945182999Smav	as = devinfo->function.audio.as;
946182999Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
947182999Smav		if (as[i].hpredir < 0)
948182999Smav			continue;
949182999Smav
950182999Smav		w = hdac_widget_get(devinfo, as[i].pins[15]);
951182999Smav		if (w == NULL || w->enable == 0 || w->type !=
952182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
953182999Smav			continue;
954162922Sariff
955171141Sariff		res = hdac_command(sc,
956182999Smav		    HDA_CMD_GET_PIN_SENSE(cad, as[i].pins[15]), cad);
957171141Sariff
958182999Smav		HDA_BOOTVERBOSE(
959182999Smav			device_printf(sc->dev,
960182999Smav			    "Pin sense: nid=%d res=0x%08x\n",
961182999Smav			    as[i].pins[15], res);
962182999Smav		);
963171141Sariff
964182999Smav		res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res);
965182999Smav		if (devinfo->function.audio.quirks & HDA_QUIRK_SENSEINV)
966182999Smav			res ^= 1;
967162922Sariff
968182999Smav		/* (Un)Mute headphone pin. */
969162922Sariff		ctl = hdac_audio_ctl_amp_get(devinfo,
970182999Smav		    as[i].pins[15], HDA_CTL_IN, -1, 1);
971182999Smav		if (ctl != NULL && ctl->mute) {
972182999Smav			/* If pin has muter - use it. */
973182999Smav			val = (res != 0) ? 0 : 1;
974182999Smav			if (val != ctl->forcemute) {
975182999Smav				ctl->forcemute = val;
976162922Sariff				hdac_audio_ctl_amp_set(ctl,
977182999Smav				    HDA_AMP_MUTE_DEFAULT,
978182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
979162922Sariff			}
980182999Smav		} else {
981182999Smav			/* If there is no muter - disable pin output. */
982182999Smav			w = hdac_widget_get(devinfo, as[i].pins[15]);
983163057Sariff			if (w != NULL && w->type ==
984163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
985182999Smav				if (res != 0)
986169277Sariff					val = w->wclass.pin.ctrl |
987162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
988162922Sariff				else
989169277Sariff					val = w->wclass.pin.ctrl &
990162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
991169277Sariff				if (val != w->wclass.pin.ctrl) {
992169277Sariff					w->wclass.pin.ctrl = val;
993169277Sariff					hdac_command(sc,
994169277Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
995169277Sariff					    w->nid, w->wclass.pin.ctrl), cad);
996169277Sariff				}
997162922Sariff			}
998182999Smav		}
999182999Smav		/* (Un)Mute other pins. */
1000182999Smav		for (j = 0; j < 15; j++) {
1001182999Smav			if (as[i].pins[j] <= 0)
1002182999Smav				continue;
1003182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
1004182999Smav			    as[i].pins[j], HDA_CTL_IN, -1, 1);
1005182999Smav			if (ctl != NULL && ctl->mute) {
1006182999Smav				/* If pin has muter - use it. */
1007182999Smav				val = (res != 0) ? 1 : 0;
1008182999Smav				if (val == ctl->forcemute)
1009169277Sariff					continue;
1010182999Smav				ctl->forcemute = val;
1011182999Smav				hdac_audio_ctl_amp_set(ctl,
1012182999Smav				    HDA_AMP_MUTE_DEFAULT,
1013182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
1014182999Smav				continue;
1015162922Sariff			}
1016182999Smav			/* If there is no muter - disable pin output. */
1017182999Smav			w = hdac_widget_get(devinfo, as[i].pins[j]);
1018163057Sariff			if (w != NULL && w->type ==
1019163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
1020182999Smav				if (res != 0)
1021182999Smav					val = w->wclass.pin.ctrl &
1022182999Smav					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1023182999Smav				else
1024182999Smav					val = w->wclass.pin.ctrl |
1025182999Smav					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1026169277Sariff				if (val != w->wclass.pin.ctrl) {
1027169277Sariff					w->wclass.pin.ctrl = val;
1028169277Sariff					hdac_command(sc,
1029169277Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
1030169277Sariff					    w->nid, w->wclass.pin.ctrl), cad);
1031169277Sariff				}
1032162922Sariff			}
1033162922Sariff		}
1034182999Smav	}
1035182999Smav}
1036182999Smav
1037182999Smav/*
1038182999Smav * Callback for poll based jack detection.
1039182999Smav */
1040182999Smavstatic void
1041182999Smavhdac_jack_poll_callback(void *arg)
1042182999Smav{
1043182999Smav	struct hdac_devinfo *devinfo = arg;
1044182999Smav	struct hdac_softc *sc;
1045182999Smav
1046182999Smav	if (devinfo == NULL || devinfo->codec == NULL ||
1047182999Smav	    devinfo->codec->sc == NULL)
1048182999Smav		return;
1049182999Smav	sc = devinfo->codec->sc;
1050182999Smav	hdac_lock(sc);
1051182999Smav	if (sc->poll_ival == 0) {
1052182999Smav		hdac_unlock(sc);
1053182999Smav		return;
1054182999Smav	}
1055182999Smav	hdac_hp_switch_handler(devinfo);
1056182999Smav	callout_reset(&sc->poll_jack, sc->poll_ival,
1057182999Smav	    hdac_jack_poll_callback, devinfo);
1058182999Smav	hdac_unlock(sc);
1059182999Smav}
1060182999Smav
1061182999Smav/*
1062182999Smav * Jack detection initializer.
1063182999Smav */
1064182999Smavstatic void
1065182999Smavhdac_hp_switch_init(struct hdac_devinfo *devinfo)
1066182999Smav{
1067182999Smav        struct hdac_softc *sc = devinfo->codec->sc;
1068182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
1069182999Smav        struct hdac_widget *w;
1070182999Smav        uint32_t id;
1071182999Smav        int i, enable = 0, poll = 0;
1072182999Smav        nid_t cad;
1073182999Smav
1074182999Smav	id = hdac_codec_id(devinfo->codec);
1075182999Smav	cad = devinfo->codec->cad;
1076182999Smav	for (i = 0; i < devinfo->function.audio.ascnt; i++) {
1077182999Smav		if (as[i].hpredir < 0)
1078182999Smav			continue;
1079182999Smav
1080182999Smav		w = hdac_widget_get(devinfo, as[i].pins[15]);
1081182999Smav		if (w == NULL || w->enable == 0 || w->type !=
1082182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1083182999Smav			continue;
1084182999Smav		if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(w->wclass.pin.cap) == 0 ||
1085182999Smav		    (HDA_CONFIG_DEFAULTCONF_MISC(w->wclass.pin.config) & 1) != 0) {
1086182999Smav			device_printf(sc->dev,
1087182999Smav			    "No jack detection support at pin %d\n",
1088182999Smav			    as[i].pins[15]);
1089182999Smav			continue;
1090182999Smav		}
1091182999Smav		enable = 1;
1092182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
1093169277Sariff			hdac_command(sc,
1094182999Smav			    HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid,
1095182999Smav			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
1096182999Smav			    HDAC_UNSOLTAG_EVENT_HP), cad);
1097182999Smav		} else
1098182999Smav			poll = 1;
1099182999Smav		HDA_BOOTVERBOSE(
1100169277Sariff			device_printf(sc->dev,
1101182999Smav			    "Enabling headphone/speaker "
1102182999Smav			    "audio routing switching:\n");
1103182999Smav			device_printf(sc->dev, "\tas=%d sense nid=%d [%s]\n",
1104182999Smav			    i, w->nid, (poll != 0) ? "POLL" : "UNSOL");
1105182999Smav		);
1106182999Smav	}
1107182999Smav	if (enable) {
1108182999Smav		hdac_hp_switch_handler(devinfo);
1109182999Smav		if (poll) {
1110182999Smav			callout_reset(&sc->poll_jack, 1,
1111182999Smav			    hdac_jack_poll_callback, devinfo);
1112169277Sariff		}
1113162922Sariff	}
1114162922Sariff}
1115162922Sariff
1116182999Smav/*
1117182999Smav * Unsolicited messages handler.
1118182999Smav */
1119162922Sariffstatic void
1120162922Sariffhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
1121162922Sariff{
1122162922Sariff	struct hdac_softc *sc;
1123162922Sariff	struct hdac_devinfo *devinfo = NULL;
1124182999Smav	int i;
1125162922Sariff
1126162922Sariff	if (codec == NULL || codec->sc == NULL)
1127162922Sariff		return;
1128162922Sariff
1129162922Sariff	sc = codec->sc;
1130162922Sariff
1131163057Sariff	HDA_BOOTVERBOSE(
1132182999Smav		device_printf(sc->dev, "Unsol Tag: 0x%08x\n", tag);
1133162922Sariff	);
1134162922Sariff
1135182999Smav	for (i = 0; i < codec->num_fgs; i++) {
1136182999Smav		if (codec->fgs[i].node_type ==
1137182999Smav		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
1138182999Smav			devinfo = &codec->fgs[i];
1139162965Sariff			break;
1140182999Smav		}
1141162922Sariff	}
1142162965Sariff
1143162922Sariff	if (devinfo == NULL)
1144162922Sariff		return;
1145162922Sariff
1146162922Sariff	switch (tag) {
1147162922Sariff	case HDAC_UNSOLTAG_EVENT_HP:
1148162922Sariff		hdac_hp_switch_handler(devinfo);
1149162922Sariff		break;
1150162922Sariff	default:
1151182999Smav		device_printf(sc->dev, "Unknown unsol tag: 0x%08x!\n", tag);
1152162922Sariff		break;
1153162922Sariff	}
1154162922Sariff}
1155162922Sariff
1156164614Sariffstatic int
1157162922Sariffhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
1158162922Sariff{
1159162922Sariff	/* XXX to be removed */
1160162922Sariff#ifdef HDAC_INTR_EXTRA
1161162922Sariff	uint32_t res;
1162162922Sariff#endif
1163162922Sariff
1164171330Sariff	if (!(ch->flags & HDAC_CHN_RUNNING))
1165164614Sariff		return (0);
1166162922Sariff
1167162922Sariff	/* XXX to be removed */
1168162922Sariff#ifdef HDAC_INTR_EXTRA
1169162922Sariff	res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS);
1170162922Sariff#endif
1171162922Sariff
1172162922Sariff	/* XXX to be removed */
1173162922Sariff#ifdef HDAC_INTR_EXTRA
1174163057Sariff	HDA_BOOTVERBOSE(
1175163057Sariff		if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE))
1176182999Smav			device_printf(ch->pdevinfo->dev,
1177163057Sariff			    "PCMDIR_%s intr triggered beyond stream boundary:"
1178163057Sariff			    "%08x\n",
1179163057Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
1180163057Sariff	);
1181162922Sariff#endif
1182162922Sariff
1183162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS,
1184163057Sariff	    HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS );
1185162922Sariff
1186162922Sariff	/* XXX to be removed */
1187162922Sariff#ifdef HDAC_INTR_EXTRA
1188162922Sariff	if (res & HDAC_SDSTS_BCIS) {
1189162922Sariff#endif
1190164614Sariff		return (1);
1191162922Sariff	/* XXX to be removed */
1192162922Sariff#ifdef HDAC_INTR_EXTRA
1193162922Sariff	}
1194162922Sariff#endif
1195164614Sariff
1196164614Sariff	return (0);
1197162922Sariff}
1198162922Sariff
1199162922Sariff/****************************************************************************
1200162922Sariff * void hdac_intr_handler(void *)
1201162922Sariff *
1202162922Sariff * Interrupt handler. Processes interrupts received from the hdac.
1203162922Sariff ****************************************************************************/
1204162922Sariffstatic void
1205162922Sariffhdac_intr_handler(void *context)
1206162922Sariff{
1207162922Sariff	struct hdac_softc *sc;
1208162922Sariff	uint32_t intsts;
1209162922Sariff	uint8_t rirbsts;
1210164614Sariff	struct hdac_rirb *rirb_base;
1211171141Sariff	uint32_t trigger;
1212182999Smav	int i;
1213162922Sariff
1214162922Sariff	sc = (struct hdac_softc *)context;
1215162922Sariff
1216162922Sariff	hdac_lock(sc);
1217164614Sariff	if (sc->polling != 0) {
1218164614Sariff		hdac_unlock(sc);
1219164614Sariff		return;
1220164614Sariff	}
1221171141Sariff
1222162922Sariff	/* Do we have anything to do? */
1223162922Sariff	intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
1224163057Sariff	if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) {
1225162922Sariff		hdac_unlock(sc);
1226162922Sariff		return;
1227162922Sariff	}
1228162922Sariff
1229171141Sariff	trigger = 0;
1230171141Sariff
1231162922Sariff	/* Was this a controller interrupt? */
1232163057Sariff	if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) {
1233162922Sariff		rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
1234162922Sariff		rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1235162922Sariff		/* Get as many responses that we can */
1236163057Sariff		while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) {
1237164614Sariff			HDAC_WRITE_1(&sc->mem,
1238164614Sariff			    HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
1239171141Sariff			if (hdac_rirb_flush(sc) != 0)
1240171141Sariff				trigger |= HDAC_TRIGGER_UNSOL;
1241162922Sariff			rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1242162922Sariff		}
1243162922Sariff		/* XXX to be removed */
1244162922Sariff		/* Clear interrupt and exit */
1245162922Sariff#ifdef HDAC_INTR_EXTRA
1246162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS);
1247162922Sariff#endif
1248162922Sariff	}
1249164614Sariff
1250163057Sariff	if (intsts & HDAC_INTSTS_SIS_MASK) {
1251182999Smav		for (i = 0; i < sc->num_chans; i++) {
1252182999Smav			if ((intsts & (1 << (sc->chans[i].off >> 5))) &&
1253182999Smav			    hdac_stream_intr(sc, &sc->chans[i]) != 0)
1254182999Smav				trigger |= (1 << i);
1255182999Smav		}
1256162922Sariff		/* XXX to be removed */
1257162922Sariff#ifdef HDAC_INTR_EXTRA
1258164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts &
1259164614Sariff		    HDAC_INTSTS_SIS_MASK);
1260162922Sariff#endif
1261162922Sariff	}
1262162922Sariff
1263164614Sariff	hdac_unlock(sc);
1264162922Sariff
1265182999Smav	for (i = 0; i < sc->num_chans; i++) {
1266182999Smav		if (trigger & (1 << i))
1267182999Smav			chn_intr(sc->chans[i].c);
1268182999Smav	}
1269171141Sariff	if (trigger & HDAC_TRIGGER_UNSOL)
1270171141Sariff		taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
1271162922Sariff}
1272162922Sariff
1273162922Sariff/****************************************************************************
1274182999Smav * int hdac_reset(hdac_softc *, int)
1275162922Sariff *
1276162922Sariff * Reset the hdac to a quiescent and known state.
1277162922Sariff ****************************************************************************/
1278162922Sariffstatic int
1279182999Smavhdac_reset(struct hdac_softc *sc, int wakeup)
1280162922Sariff{
1281162922Sariff	uint32_t gctl;
1282162922Sariff	int count, i;
1283162922Sariff
1284162922Sariff	/*
1285162922Sariff	 * Stop all Streams DMA engine
1286162922Sariff	 */
1287162922Sariff	for (i = 0; i < sc->num_iss; i++)
1288162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
1289162922Sariff	for (i = 0; i < sc->num_oss; i++)
1290162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
1291162922Sariff	for (i = 0; i < sc->num_bss; i++)
1292162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
1293162922Sariff
1294162922Sariff	/*
1295169277Sariff	 * Stop Control DMA engines.
1296162922Sariff	 */
1297162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
1298162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
1299162922Sariff
1300162922Sariff	/*
1301169277Sariff	 * Reset DMA position buffer.
1302169277Sariff	 */
1303169277Sariff	HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0);
1304169277Sariff	HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0);
1305169277Sariff
1306169277Sariff	/*
1307162922Sariff	 * Reset the controller. The reset must remain asserted for
1308162922Sariff	 * a minimum of 100us.
1309162922Sariff	 */
1310162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1311162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
1312162922Sariff	count = 10000;
1313162922Sariff	do {
1314162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1315162922Sariff		if (!(gctl & HDAC_GCTL_CRST))
1316162922Sariff			break;
1317162922Sariff		DELAY(10);
1318162922Sariff	} while	(--count);
1319162922Sariff	if (gctl & HDAC_GCTL_CRST) {
1320162922Sariff		device_printf(sc->dev, "Unable to put hdac in reset\n");
1321162922Sariff		return (ENXIO);
1322162922Sariff	}
1323182999Smav
1324182999Smav	/* If wakeup is not requested - leave the controller in reset state. */
1325182999Smav	if (!wakeup)
1326182999Smav		return (0);
1327182999Smav
1328162922Sariff	DELAY(100);
1329162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1330162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
1331162922Sariff	count = 10000;
1332162922Sariff	do {
1333162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1334163057Sariff		if (gctl & HDAC_GCTL_CRST)
1335162922Sariff			break;
1336162922Sariff		DELAY(10);
1337162922Sariff	} while (--count);
1338162922Sariff	if (!(gctl & HDAC_GCTL_CRST)) {
1339162922Sariff		device_printf(sc->dev, "Device stuck in reset\n");
1340162922Sariff		return (ENXIO);
1341162922Sariff	}
1342162922Sariff
1343162922Sariff	/*
1344162922Sariff	 * Wait for codecs to finish their own reset sequence. The delay here
1345162922Sariff	 * should be of 250us but for some reasons, on it's not enough on my
1346162922Sariff	 * computer. Let's use twice as much as necessary to make sure that
1347162922Sariff	 * it's reset properly.
1348162922Sariff	 */
1349162922Sariff	DELAY(1000);
1350162922Sariff
1351162922Sariff	return (0);
1352162922Sariff}
1353162922Sariff
1354162922Sariff
1355162922Sariff/****************************************************************************
1356162922Sariff * int hdac_get_capabilities(struct hdac_softc *);
1357162922Sariff *
1358162922Sariff * Retreive the general capabilities of the hdac;
1359162922Sariff *	Number of Input Streams
1360162922Sariff *	Number of Output Streams
1361162922Sariff *	Number of bidirectional Streams
1362162922Sariff *	64bit ready
1363162922Sariff *	CORB and RIRB sizes
1364162922Sariff ****************************************************************************/
1365162922Sariffstatic int
1366162922Sariffhdac_get_capabilities(struct hdac_softc *sc)
1367162922Sariff{
1368162922Sariff	uint16_t gcap;
1369162922Sariff	uint8_t corbsize, rirbsize;
1370162922Sariff
1371162922Sariff	gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
1372162922Sariff	sc->num_iss = HDAC_GCAP_ISS(gcap);
1373162922Sariff	sc->num_oss = HDAC_GCAP_OSS(gcap);
1374162922Sariff	sc->num_bss = HDAC_GCAP_BSS(gcap);
1375162922Sariff
1376163057Sariff	sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK);
1377162922Sariff
1378162922Sariff	corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
1379162922Sariff	if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
1380162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_256)
1381162922Sariff		sc->corb_size = 256;
1382162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
1383162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_16)
1384162922Sariff		sc->corb_size = 16;
1385162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
1386162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_2)
1387162922Sariff		sc->corb_size = 2;
1388162922Sariff	else {
1389162922Sariff		device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
1390162922Sariff		    __func__, corbsize);
1391162922Sariff		return (ENXIO);
1392162922Sariff	}
1393162922Sariff
1394162922Sariff	rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
1395162922Sariff	if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
1396162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_256)
1397162922Sariff		sc->rirb_size = 256;
1398162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
1399162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_16)
1400162922Sariff		sc->rirb_size = 16;
1401162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
1402162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_2)
1403162922Sariff		sc->rirb_size = 2;
1404162922Sariff	else {
1405162922Sariff		device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
1406162922Sariff		    __func__, rirbsize);
1407162922Sariff		return (ENXIO);
1408162922Sariff	}
1409162922Sariff
1410183097Smav	HDA_BOOTHVERBOSE(
1411182999Smav		device_printf(sc->dev, "    CORB size: %d\n", sc->corb_size);
1412182999Smav		device_printf(sc->dev, "    RIRB size: %d\n", sc->rirb_size);
1413182999Smav		device_printf(sc->dev, "      Streams: ISS=%d OSS=%d BSS=%d\n",
1414182999Smav		    sc->num_iss, sc->num_oss, sc->num_bss);
1415182999Smav	);
1416182999Smav
1417162922Sariff	return (0);
1418162922Sariff}
1419162922Sariff
1420162922Sariff
1421162922Sariff/****************************************************************************
1422162922Sariff * void hdac_dma_cb
1423162922Sariff *
1424162922Sariff * This function is called by bus_dmamap_load when the mapping has been
1425162922Sariff * established. We just record the physical address of the mapping into
1426162922Sariff * the struct hdac_dma passed in.
1427162922Sariff ****************************************************************************/
1428162922Sariffstatic void
1429162922Sariffhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
1430162922Sariff{
1431162922Sariff	struct hdac_dma *dma;
1432162922Sariff
1433162922Sariff	if (error == 0) {
1434162922Sariff		dma = (struct hdac_dma *)callback_arg;
1435162922Sariff		dma->dma_paddr = segs[0].ds_addr;
1436162922Sariff	}
1437162922Sariff}
1438162922Sariff
1439162922Sariff
1440162922Sariff/****************************************************************************
1441162922Sariff * int hdac_dma_alloc
1442162922Sariff *
1443162922Sariff * This function allocate and setup a dma region (struct hdac_dma).
1444162922Sariff * It must be freed by a corresponding hdac_dma_free.
1445162922Sariff ****************************************************************************/
1446162922Sariffstatic int
1447162922Sariffhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
1448162922Sariff{
1449169277Sariff	bus_size_t roundsz;
1450162922Sariff	int result;
1451162922Sariff	int lowaddr;
1452162922Sariff
1453169277Sariff	roundsz = roundup2(size, HDAC_DMA_ALIGNMENT);
1454162922Sariff	lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR :
1455162922Sariff	    BUS_SPACE_MAXADDR_32BIT;
1456162922Sariff	bzero(dma, sizeof(*dma));
1457162922Sariff
1458162922Sariff	/*
1459162922Sariff	 * Create a DMA tag
1460162922Sariff	 */
1461162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
1462162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
1463162922Sariff	    0,					/* boundary */
1464162922Sariff	    lowaddr,				/* lowaddr */
1465162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
1466162922Sariff	    NULL,				/* filtfunc */
1467162922Sariff	    NULL,				/* fistfuncarg */
1468169277Sariff	    roundsz, 				/* maxsize */
1469162922Sariff	    1,					/* nsegments */
1470169277Sariff	    roundsz, 				/* maxsegsz */
1471162922Sariff	    0,					/* flags */
1472162922Sariff	    NULL,				/* lockfunc */
1473162922Sariff	    NULL,				/* lockfuncarg */
1474162922Sariff	    &dma->dma_tag);			/* dmat */
1475162922Sariff	if (result != 0) {
1476162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
1477162922Sariff		    __func__, result);
1478167773Sariff		goto hdac_dma_alloc_fail;
1479162922Sariff	}
1480162922Sariff
1481162922Sariff	/*
1482162922Sariff	 * Allocate DMA memory
1483162922Sariff	 */
1484162965Sariff	result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
1485169277Sariff	    BUS_DMA_NOWAIT | BUS_DMA_ZERO |
1486171330Sariff	    ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0),
1487171330Sariff	    &dma->dma_map);
1488162922Sariff	if (result != 0) {
1489162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n",
1490162922Sariff		    __func__, result);
1491167773Sariff		goto hdac_dma_alloc_fail;
1492162922Sariff	}
1493162922Sariff
1494169277Sariff	dma->dma_size = roundsz;
1495169277Sariff
1496162922Sariff	/*
1497162922Sariff	 * Map the memory
1498162922Sariff	 */
1499162922Sariff	result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
1500169277Sariff	    (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0);
1501162922Sariff	if (result != 0 || dma->dma_paddr == 0) {
1502167773Sariff		if (result == 0)
1503167773Sariff			result = ENOMEM;
1504162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n",
1505162922Sariff		    __func__, result);
1506167773Sariff		goto hdac_dma_alloc_fail;
1507162922Sariff	}
1508162922Sariff
1509183097Smav	HDA_BOOTHVERBOSE(
1510169277Sariff		device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n",
1511169277Sariff		    __func__, (uintmax_t)size, (uintmax_t)roundsz);
1512169277Sariff	);
1513169277Sariff
1514162922Sariff	return (0);
1515169277Sariff
1516167773Sariffhdac_dma_alloc_fail:
1517169277Sariff	hdac_dma_free(sc, dma);
1518167773Sariff
1519162922Sariff	return (result);
1520162922Sariff}
1521162922Sariff
1522162922Sariff
1523162922Sariff/****************************************************************************
1524169277Sariff * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *)
1525162922Sariff *
1526162922Sariff * Free a struct dhac_dma that has been previously allocated via the
1527162922Sariff * hdac_dma_alloc function.
1528162922Sariff ****************************************************************************/
1529162922Sariffstatic void
1530169277Sariffhdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma)
1531162922Sariff{
1532167773Sariff	if (dma->dma_map != NULL) {
1533169277Sariff#if 0
1534162922Sariff		/* Flush caches */
1535162922Sariff		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
1536162922Sariff		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1537169277Sariff#endif
1538162922Sariff		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1539167773Sariff	}
1540167773Sariff	if (dma->dma_vaddr != NULL) {
1541162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1542167773Sariff		dma->dma_vaddr = NULL;
1543167773Sariff	}
1544167773Sariff	dma->dma_map = NULL;
1545167773Sariff	if (dma->dma_tag != NULL) {
1546162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1547167773Sariff		dma->dma_tag = NULL;
1548162922Sariff	}
1549167773Sariff	dma->dma_size = 0;
1550162922Sariff}
1551162922Sariff
1552162922Sariff/****************************************************************************
1553162922Sariff * int hdac_mem_alloc(struct hdac_softc *)
1554162922Sariff *
1555162922Sariff * Allocate all the bus resources necessary to speak with the physical
1556162922Sariff * controller.
1557162922Sariff ****************************************************************************/
1558162922Sariffstatic int
1559162922Sariffhdac_mem_alloc(struct hdac_softc *sc)
1560162922Sariff{
1561162922Sariff	struct hdac_mem *mem;
1562162922Sariff
1563162922Sariff	mem = &sc->mem;
1564162922Sariff	mem->mem_rid = PCIR_BAR(0);
1565162922Sariff	mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1566162922Sariff	    &mem->mem_rid, RF_ACTIVE);
1567162922Sariff	if (mem->mem_res == NULL) {
1568162922Sariff		device_printf(sc->dev,
1569162922Sariff		    "%s: Unable to allocate memory resource\n", __func__);
1570162922Sariff		return (ENOMEM);
1571162922Sariff	}
1572162922Sariff	mem->mem_tag = rman_get_bustag(mem->mem_res);
1573162922Sariff	mem->mem_handle = rman_get_bushandle(mem->mem_res);
1574162922Sariff
1575162922Sariff	return (0);
1576162922Sariff}
1577162922Sariff
1578162922Sariff/****************************************************************************
1579162922Sariff * void hdac_mem_free(struct hdac_softc *)
1580162922Sariff *
1581162922Sariff * Free up resources previously allocated by hdac_mem_alloc.
1582162922Sariff ****************************************************************************/
1583162922Sariffstatic void
1584162922Sariffhdac_mem_free(struct hdac_softc *sc)
1585162922Sariff{
1586162922Sariff	struct hdac_mem *mem;
1587162922Sariff
1588162922Sariff	mem = &sc->mem;
1589162922Sariff	if (mem->mem_res != NULL)
1590162922Sariff		bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
1591162922Sariff		    mem->mem_res);
1592164614Sariff	mem->mem_res = NULL;
1593162922Sariff}
1594162922Sariff
1595162922Sariff/****************************************************************************
1596162922Sariff * int hdac_irq_alloc(struct hdac_softc *)
1597162922Sariff *
1598162922Sariff * Allocate and setup the resources necessary for interrupt handling.
1599162922Sariff ****************************************************************************/
1600162922Sariffstatic int
1601162922Sariffhdac_irq_alloc(struct hdac_softc *sc)
1602162922Sariff{
1603162922Sariff	struct hdac_irq *irq;
1604162922Sariff	int result;
1605162922Sariff
1606162922Sariff	irq = &sc->irq;
1607162922Sariff	irq->irq_rid = 0x0;
1608171330Sariff
1609178155Sariff#ifdef HDAC_MSI_ENABLED
1610171330Sariff	if ((sc->flags & HDAC_F_MSI) &&
1611171330Sariff	    (result = pci_msi_count(sc->dev)) == 1 &&
1612171330Sariff	    pci_alloc_msi(sc->dev, &result) == 0)
1613171330Sariff		irq->irq_rid = 0x1;
1614171330Sariff	else
1615171330Sariff#endif
1616171330Sariff		sc->flags &= ~HDAC_F_MSI;
1617171330Sariff
1618162922Sariff	irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1619162922Sariff	    &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
1620162922Sariff	if (irq->irq_res == NULL) {
1621162922Sariff		device_printf(sc->dev, "%s: Unable to allocate irq\n",
1622162922Sariff		    __func__);
1623167773Sariff		goto hdac_irq_alloc_fail;
1624162922Sariff	}
1625182999Smav	result = bus_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE | INTR_TYPE_AV,
1626182999Smav	    NULL, hdac_intr_handler, sc, &irq->irq_handle);
1627162922Sariff	if (result != 0) {
1628162922Sariff		device_printf(sc->dev,
1629162922Sariff		    "%s: Unable to setup interrupt handler (%x)\n",
1630162922Sariff		    __func__, result);
1631167773Sariff		goto hdac_irq_alloc_fail;
1632162922Sariff	}
1633162922Sariff
1634162922Sariff	return (0);
1635162922Sariff
1636167773Sariffhdac_irq_alloc_fail:
1637164614Sariff	hdac_irq_free(sc);
1638164614Sariff
1639162922Sariff	return (ENXIO);
1640162922Sariff}
1641162922Sariff
1642162922Sariff/****************************************************************************
1643162922Sariff * void hdac_irq_free(struct hdac_softc *)
1644162922Sariff *
1645162922Sariff * Free up resources previously allocated by hdac_irq_alloc.
1646162922Sariff ****************************************************************************/
1647162922Sariffstatic void
1648162922Sariffhdac_irq_free(struct hdac_softc *sc)
1649162922Sariff{
1650162922Sariff	struct hdac_irq *irq;
1651162922Sariff
1652162922Sariff	irq = &sc->irq;
1653164614Sariff	if (irq->irq_res != NULL && irq->irq_handle != NULL)
1654162922Sariff		bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
1655162922Sariff	if (irq->irq_res != NULL)
1656162922Sariff		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1657162922Sariff		    irq->irq_res);
1658178155Sariff#ifdef HDAC_MSI_ENABLED
1659171330Sariff	if ((sc->flags & HDAC_F_MSI) && irq->irq_rid == 0x1)
1660171330Sariff		pci_release_msi(sc->dev);
1661171330Sariff#endif
1662164614Sariff	irq->irq_handle = NULL;
1663164614Sariff	irq->irq_res = NULL;
1664171330Sariff	irq->irq_rid = 0x0;
1665162922Sariff}
1666162922Sariff
1667162922Sariff/****************************************************************************
1668162922Sariff * void hdac_corb_init(struct hdac_softc *)
1669162922Sariff *
1670162922Sariff * Initialize the corb registers for operations but do not start it up yet.
1671162922Sariff * The CORB engine must not be running when this function is called.
1672162922Sariff ****************************************************************************/
1673162922Sariffstatic void
1674162922Sariffhdac_corb_init(struct hdac_softc *sc)
1675162922Sariff{
1676162922Sariff	uint8_t corbsize;
1677162922Sariff	uint64_t corbpaddr;
1678162922Sariff
1679162922Sariff	/* Setup the CORB size. */
1680162922Sariff	switch (sc->corb_size) {
1681162922Sariff	case 256:
1682162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
1683162922Sariff		break;
1684162922Sariff	case 16:
1685162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
1686162922Sariff		break;
1687162922Sariff	case 2:
1688162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
1689162922Sariff		break;
1690162922Sariff	default:
1691162922Sariff		panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
1692162922Sariff	}
1693162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
1694162922Sariff
1695162922Sariff	/* Setup the CORB Address in the hdac */
1696162922Sariff	corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
1697162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
1698162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
1699162922Sariff
1700162922Sariff	/* Set the WP and RP */
1701162922Sariff	sc->corb_wp = 0;
1702162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
1703162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
1704162922Sariff	/*
1705162922Sariff	 * The HDA specification indicates that the CORBRPRST bit will always
1706162922Sariff	 * read as zero. Unfortunately, it seems that at least the 82801G
1707162922Sariff	 * doesn't reset the bit to zero, which stalls the corb engine.
1708162922Sariff	 * manually reset the bit to zero before continuing.
1709162922Sariff	 */
1710162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
1711162922Sariff
1712162922Sariff	/* Enable CORB error reporting */
1713162922Sariff#if 0
1714162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
1715162922Sariff#endif
1716162922Sariff}
1717162922Sariff
1718162922Sariff/****************************************************************************
1719162922Sariff * void hdac_rirb_init(struct hdac_softc *)
1720162922Sariff *
1721162922Sariff * Initialize the rirb registers for operations but do not start it up yet.
1722162922Sariff * The RIRB engine must not be running when this function is called.
1723162922Sariff ****************************************************************************/
1724162922Sariffstatic void
1725162922Sariffhdac_rirb_init(struct hdac_softc *sc)
1726162922Sariff{
1727162922Sariff	uint8_t rirbsize;
1728162922Sariff	uint64_t rirbpaddr;
1729162922Sariff
1730162922Sariff	/* Setup the RIRB size. */
1731162922Sariff	switch (sc->rirb_size) {
1732162922Sariff	case 256:
1733162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
1734162922Sariff		break;
1735162922Sariff	case 16:
1736162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
1737162922Sariff		break;
1738162922Sariff	case 2:
1739162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
1740162922Sariff		break;
1741162922Sariff	default:
1742162922Sariff		panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
1743162922Sariff	}
1744162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
1745162922Sariff
1746162922Sariff	/* Setup the RIRB Address in the hdac */
1747162922Sariff	rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
1748162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
1749162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
1750162922Sariff
1751162922Sariff	/* Setup the WP and RP */
1752162922Sariff	sc->rirb_rp = 0;
1753162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
1754162922Sariff
1755182999Smav	/* Setup the interrupt threshold */
1756182999Smav	HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
1757162922Sariff
1758182999Smav	/* Enable Overrun and response received reporting */
1759162922Sariff#if 0
1760182999Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
1761182999Smav	    HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
1762162922Sariff#else
1763182999Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
1764162922Sariff#endif
1765162922Sariff
1766169277Sariff#if 0
1767162922Sariff	/*
1768162922Sariff	 * Make sure that the Host CPU cache doesn't contain any dirty
1769162922Sariff	 * cache lines that falls in the rirb. If I understood correctly, it
1770162922Sariff	 * should be sufficient to do this only once as the rirb is purely
1771162922Sariff	 * read-only from now on.
1772162922Sariff	 */
1773162922Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
1774162922Sariff	    BUS_DMASYNC_PREREAD);
1775169277Sariff#endif
1776162922Sariff}
1777162922Sariff
1778162922Sariff/****************************************************************************
1779162922Sariff * void hdac_corb_start(hdac_softc *)
1780162922Sariff *
1781162922Sariff * Startup the corb DMA engine
1782162922Sariff ****************************************************************************/
1783162922Sariffstatic void
1784162922Sariffhdac_corb_start(struct hdac_softc *sc)
1785162922Sariff{
1786162922Sariff	uint32_t corbctl;
1787162922Sariff
1788162922Sariff	corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
1789162922Sariff	corbctl |= HDAC_CORBCTL_CORBRUN;
1790162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
1791162922Sariff}
1792162922Sariff
1793162922Sariff/****************************************************************************
1794162922Sariff * void hdac_rirb_start(hdac_softc *)
1795162922Sariff *
1796162922Sariff * Startup the rirb DMA engine
1797162922Sariff ****************************************************************************/
1798162922Sariffstatic void
1799162922Sariffhdac_rirb_start(struct hdac_softc *sc)
1800162922Sariff{
1801162922Sariff	uint32_t rirbctl;
1802162922Sariff
1803162922Sariff	rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
1804162922Sariff	rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
1805162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
1806162922Sariff}
1807162922Sariff
1808162922Sariff
1809162922Sariff/****************************************************************************
1810172811Sariff * void hdac_scan_codecs(struct hdac_softc *, int)
1811162922Sariff *
1812172811Sariff * Scan the bus for available codecs, starting with num.
1813162922Sariff ****************************************************************************/
1814162922Sariffstatic void
1815182999Smavhdac_scan_codecs(struct hdac_softc *sc)
1816162922Sariff{
1817162922Sariff	struct hdac_codec *codec;
1818162922Sariff	int i;
1819162922Sariff	uint16_t statests;
1820162922Sariff
1821162922Sariff	statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
1822182999Smav	for (i = 0; i < HDAC_CODEC_MAX; i++) {
1823162922Sariff		if (HDAC_STATESTS_SDIWAKE(statests, i)) {
1824162922Sariff			/* We have found a codec. */
1825162922Sariff			codec = (struct hdac_codec *)malloc(sizeof(*codec),
1826162922Sariff			    M_HDAC, M_ZERO | M_NOWAIT);
1827162922Sariff			if (codec == NULL) {
1828162922Sariff				device_printf(sc->dev,
1829162922Sariff				    "Unable to allocate memory for codec\n");
1830162922Sariff				continue;
1831162922Sariff			}
1832164614Sariff			codec->commands = NULL;
1833164614Sariff			codec->responses_received = 0;
1834162922Sariff			codec->verbs_sent = 0;
1835162922Sariff			codec->sc = sc;
1836162922Sariff			codec->cad = i;
1837162922Sariff			sc->codecs[i] = codec;
1838182999Smav			hdac_probe_codec(codec);
1839162922Sariff		}
1840162922Sariff	}
1841162922Sariff	/* All codecs have been probed, now try to attach drivers to them */
1842163057Sariff	/* bus_generic_attach(sc->dev); */
1843162922Sariff}
1844162922Sariff
1845162922Sariff/****************************************************************************
1846162922Sariff * void hdac_probe_codec(struct hdac_softc *, int)
1847162922Sariff *
1848162922Sariff * Probe a the given codec_id for available function groups.
1849162922Sariff ****************************************************************************/
1850182999Smavstatic void
1851162922Sariffhdac_probe_codec(struct hdac_codec *codec)
1852162922Sariff{
1853162922Sariff	struct hdac_softc *sc = codec->sc;
1854162922Sariff	uint32_t vendorid, revisionid, subnode;
1855162922Sariff	int startnode;
1856162922Sariff	int endnode;
1857162922Sariff	int i;
1858162922Sariff	nid_t cad = codec->cad;
1859162922Sariff
1860163057Sariff	HDA_BOOTVERBOSE(
1861184089Smav		device_printf(sc->dev, "Probing codec #%d...\n", cad);
1862162922Sariff	);
1863162922Sariff	vendorid = hdac_command(sc,
1864162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
1865162922Sariff	    cad);
1866162922Sariff	revisionid = hdac_command(sc,
1867162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
1868162922Sariff	    cad);
1869182999Smav	codec->vendor_id = HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
1870182999Smav	codec->device_id = HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
1871182999Smav	codec->revision_id = HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
1872182999Smav	codec->stepping_id = HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
1873182999Smav
1874182999Smav	if (vendorid == HDAC_INVALID && revisionid == HDAC_INVALID) {
1875182999Smav		device_printf(sc->dev, "Codec #%d is not responding!"
1876182999Smav		    " Probing aborted.\n", cad);
1877182999Smav		return;
1878182999Smav	}
1879182999Smav
1880184089Smav	device_printf(sc->dev, "HDA Codec #%d: %s\n",
1881182999Smav	    cad, hdac_codec_name(codec));
1882182999Smav	HDA_BOOTVERBOSE(
1883184089Smav		device_printf(sc->dev, " HDA Codec ID: 0x%08x\n",
1884182999Smav		    hdac_codec_id(codec));
1885182999Smav		device_printf(sc->dev, "       Vendor: 0x%04x\n",
1886182999Smav		    codec->vendor_id);
1887182999Smav		device_printf(sc->dev, "       Device: 0x%04x\n",
1888182999Smav		    codec->device_id);
1889182999Smav		device_printf(sc->dev, "     Revision: 0x%02x\n",
1890182999Smav		    codec->revision_id);
1891182999Smav		device_printf(sc->dev, "     Stepping: 0x%02x\n",
1892182999Smav		    codec->stepping_id);
1893182999Smav		device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
1894182999Smav		    sc->pci_subvendor);
1895182999Smav	);
1896162922Sariff	subnode = hdac_command(sc,
1897162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
1898162922Sariff	    cad);
1899162922Sariff	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
1900162922Sariff	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
1901162922Sariff
1902183097Smav	HDA_BOOTHVERBOSE(
1903182999Smav		device_printf(sc->dev, "\tstartnode=%d endnode=%d\n",
1904163057Sariff		    startnode, endnode);
1905162922Sariff	);
1906182999Smav
1907182999Smav	codec->fgs = (struct hdac_devinfo *)malloc(sizeof(struct hdac_devinfo) *
1908182999Smav	    (endnode - startnode), M_HDAC, M_NOWAIT | M_ZERO);
1909182999Smav	if (codec->fgs == NULL) {
1910183024Smav		device_printf(sc->dev, "%s: Unable to allocate function groups\n",
1911182999Smav		    __func__);
1912182999Smav		return;
1913162922Sariff	}
1914162922Sariff
1915182999Smav	for (i = startnode; i < endnode; i++)
1916182999Smav		hdac_probe_function(codec, i);
1917182999Smav	return;
1918162922Sariff}
1919162922Sariff
1920182999Smav/*
1921182999Smav * Probe codec function and add it to the list.
1922182999Smav */
1923182999Smavstatic void
1924162922Sariffhdac_probe_function(struct hdac_codec *codec, nid_t nid)
1925162922Sariff{
1926162922Sariff	struct hdac_softc *sc = codec->sc;
1927182999Smav	struct hdac_devinfo *devinfo = &codec->fgs[codec->num_fgs];
1928162922Sariff	uint32_t fctgrptype;
1929182999Smav	uint32_t res;
1930162922Sariff	nid_t cad = codec->cad;
1931162922Sariff
1932162965Sariff	fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
1933162965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
1934162922Sariff
1935162922Sariff	devinfo->nid = nid;
1936162965Sariff	devinfo->node_type = fctgrptype;
1937162922Sariff	devinfo->codec = codec;
1938162922Sariff
1939182999Smav	res = hdac_command(sc,
1940182999Smav	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
1941162922Sariff
1942182999Smav	devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
1943182999Smav	devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
1944182999Smav	devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
1945162922Sariff
1946182999Smav	HDA_BOOTVERBOSE(
1947182999Smav		device_printf(sc->dev,
1948182999Smav		    "\tFound %s FG nid=%d startnode=%d endnode=%d total=%d\n",
1949182999Smav		    (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
1950182999Smav		    (fctgrptype == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
1951182999Smav		    "unknown", nid, devinfo->startnode, devinfo->endnode,
1952182999Smav		    devinfo->nodecnt);
1953182999Smav	);
1954182999Smav
1955182999Smav	if (devinfo->nodecnt > 0)
1956182999Smav		devinfo->widget = (struct hdac_widget *)malloc(
1957182999Smav		    sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
1958182999Smav		    M_NOWAIT | M_ZERO);
1959182999Smav	else
1960182999Smav		devinfo->widget = NULL;
1961182999Smav
1962182999Smav	if (devinfo->widget == NULL) {
1963182999Smav		device_printf(sc->dev, "unable to allocate widgets!\n");
1964182999Smav		devinfo->endnode = devinfo->startnode;
1965182999Smav		devinfo->nodecnt = 0;
1966182999Smav		return;
1967182999Smav	}
1968182999Smav
1969182999Smav	codec->num_fgs++;
1970162922Sariff}
1971162922Sariff
1972162922Sariffstatic void
1973162922Sariffhdac_widget_connection_parse(struct hdac_widget *w)
1974162922Sariff{
1975162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1976162922Sariff	uint32_t res;
1977169277Sariff	int i, j, max, ents, entnum;
1978162922Sariff	nid_t cad = w->devinfo->codec->cad;
1979162922Sariff	nid_t nid = w->nid;
1980169277Sariff	nid_t cnid, addcnid, prevcnid;
1981162922Sariff
1982169277Sariff	w->nconns = 0;
1983169277Sariff
1984162922Sariff	res = hdac_command(sc,
1985162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad);
1986162922Sariff
1987169277Sariff	ents = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res);
1988162922Sariff
1989169277Sariff	if (ents < 1)
1990162922Sariff		return;
1991162922Sariff
1992162922Sariff	entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4;
1993162922Sariff	max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1;
1994169277Sariff	prevcnid = 0;
1995162922Sariff
1996169277Sariff#define CONN_RMASK(e)		(1 << ((32 / (e)) - 1))
1997169277Sariff#define CONN_NMASK(e)		(CONN_RMASK(e) - 1)
1998169277Sariff#define CONN_RESVAL(r, e, n)	((r) >> ((32 / (e)) * (n)))
1999169277Sariff#define CONN_RANGE(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_RMASK(e))
2000169277Sariff#define CONN_CNID(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_NMASK(e))
2001169277Sariff
2002169277Sariff	for (i = 0; i < ents; i += entnum) {
2003162922Sariff		res = hdac_command(sc,
2004162922Sariff		    HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad);
2005162922Sariff		for (j = 0; j < entnum; j++) {
2006169277Sariff			cnid = CONN_CNID(res, entnum, j);
2007169277Sariff			if (cnid == 0) {
2008169277Sariff				if (w->nconns < ents)
2009169277Sariff					device_printf(sc->dev,
2010169277Sariff					    "%s: nid=%d WARNING: zero cnid "
2011169277Sariff					    "entnum=%d j=%d index=%d "
2012169277Sariff					    "entries=%d found=%d res=0x%08x\n",
2013169277Sariff					    __func__, nid, entnum, j, i,
2014169277Sariff					    ents, w->nconns, res);
2015169277Sariff				else
2016169277Sariff					goto getconns_out;
2017169277Sariff			}
2018169277Sariff			if (cnid < w->devinfo->startnode ||
2019169277Sariff			    cnid >= w->devinfo->endnode) {
2020169277Sariff				HDA_BOOTVERBOSE(
2021169277Sariff					device_printf(sc->dev,
2022182999Smav					    "GHOST: nid=%d j=%d "
2023169277Sariff					    "entnum=%d index=%d res=0x%08x\n",
2024182999Smav					    nid, j, entnum, i, res);
2025169277Sariff				);
2026169277Sariff			}
2027169277Sariff			if (CONN_RANGE(res, entnum, j) == 0)
2028169277Sariff				addcnid = cnid;
2029169277Sariff			else if (prevcnid == 0 || prevcnid >= cnid) {
2030162922Sariff				device_printf(sc->dev,
2031169277Sariff				    "%s: WARNING: Invalid child range "
2032169277Sariff				    "nid=%d index=%d j=%d entnum=%d "
2033169277Sariff				    "prevcnid=%d cnid=%d res=0x%08x\n",
2034169277Sariff				    __func__, nid, i, j, entnum, prevcnid,
2035169277Sariff				    cnid, res);
2036169277Sariff				addcnid = cnid;
2037169277Sariff			} else
2038169277Sariff				addcnid = prevcnid + 1;
2039169277Sariff			while (addcnid <= cnid) {
2040169277Sariff				if (w->nconns > max) {
2041169277Sariff					device_printf(sc->dev,
2042182999Smav					    "Adding %d (nid=%d): "
2043169277Sariff					    "Max connection reached! max=%d\n",
2044182999Smav					    addcnid, nid, max + 1);
2045169277Sariff					goto getconns_out;
2046169277Sariff				}
2047182999Smav				w->connsenable[w->nconns] = 1;
2048169277Sariff				w->conns[w->nconns++] = addcnid++;
2049162922Sariff			}
2050169277Sariff			prevcnid = cnid;
2051162922Sariff		}
2052162922Sariff	}
2053162922Sariff
2054169277Sariffgetconns_out:
2055169277Sariff	return;
2056162922Sariff}
2057162922Sariff
2058162922Sariffstatic uint32_t
2059182999Smavhdac_widget_pin_patch(uint32_t config, const char *str)
2060182999Smav{
2061182999Smav	char buf[256];
2062182999Smav	char *key, *value, *rest, *bad;
2063182999Smav	int ival, i;
2064182999Smav
2065182999Smav	strlcpy(buf, str, sizeof(buf));
2066182999Smav	rest = buf;
2067182999Smav	while ((key = strsep(&rest, "=")) != NULL) {
2068182999Smav		value = strsep(&rest, " \t");
2069182999Smav		if (value == NULL)
2070182999Smav			break;
2071182999Smav		ival = strtol(value, &bad, 10);
2072182999Smav		if (strcmp(key, "seq") == 0) {
2073182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK;
2074182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_SEQUENCE_SHIFT) &
2075182999Smav			    HDA_CONFIG_DEFAULTCONF_SEQUENCE_MASK);
2076182999Smav		} else if (strcmp(key, "as") == 0) {
2077182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK;
2078182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_ASSOCIATION_SHIFT) &
2079182999Smav			    HDA_CONFIG_DEFAULTCONF_ASSOCIATION_MASK);
2080182999Smav		} else if (strcmp(key, "misc") == 0) {
2081182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_MISC_MASK;
2082182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_MISC_SHIFT) &
2083182999Smav			    HDA_CONFIG_DEFAULTCONF_MISC_MASK);
2084182999Smav		} else if (strcmp(key, "color") == 0) {
2085182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_COLOR_MASK;
2086182999Smav			if (bad[0] == 0) {
2087182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT) &
2088182999Smav				    HDA_CONFIG_DEFAULTCONF_COLOR_MASK);
2089182999Smav			};
2090182999Smav			for (i = 0; i < 16; i++) {
2091182999Smav				if (strcasecmp(HDA_COLORS[i], value) == 0) {
2092182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_COLOR_SHIFT);
2093182999Smav					break;
2094182999Smav				}
2095182999Smav			}
2096182999Smav		} else if (strcmp(key, "ctype") == 0) {
2097182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK;
2098182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_SHIFT) &
2099182999Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE_MASK);
2100182999Smav		} else if (strcmp(key, "device") == 0) {
2101182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2102182999Smav			if (bad[0] == 0) {
2103182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT) &
2104182999Smav				    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK);
2105182999Smav				continue;
2106182999Smav			};
2107182999Smav			for (i = 0; i < 16; i++) {
2108182999Smav				if (strcasecmp(HDA_DEVS[i], value) == 0) {
2109182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT);
2110182999Smav					break;
2111182999Smav				}
2112182999Smav			}
2113182999Smav		} else if (strcmp(key, "loc") == 0) {
2114182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_LOCATION_MASK;
2115182999Smav			config |= ((ival << HDA_CONFIG_DEFAULTCONF_LOCATION_SHIFT) &
2116182999Smav			    HDA_CONFIG_DEFAULTCONF_LOCATION_MASK);
2117182999Smav		} else if (strcmp(key, "conn") == 0) {
2118182999Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2119182999Smav			if (bad[0] == 0) {
2120182999Smav				config |= ((ival << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT) &
2121182999Smav				    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2122182999Smav				continue;
2123182999Smav			};
2124182999Smav			for (i = 0; i < 4; i++) {
2125182999Smav				if (strcasecmp(HDA_CONNS[i], value) == 0) {
2126182999Smav					config |= (i << HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT);
2127182999Smav					break;
2128182999Smav				}
2129182999Smav			}
2130182999Smav		}
2131182999Smav	}
2132182999Smav	return (config);
2133182999Smav}
2134182999Smav
2135182999Smavstatic uint32_t
2136162922Sariffhdac_widget_pin_getconfig(struct hdac_widget *w)
2137162922Sariff{
2138162922Sariff	struct hdac_softc *sc;
2139166965Sariff	uint32_t config, orig, id;
2140162922Sariff	nid_t cad, nid;
2141182999Smav	char buf[32];
2142182999Smav	const char *res = NULL, *patch = NULL;
2143162922Sariff
2144162922Sariff	sc = w->devinfo->codec->sc;
2145162922Sariff	cad = w->devinfo->codec->cad;
2146162922Sariff	nid = w->nid;
2147182999Smav	id = hdac_codec_id(w->devinfo->codec);
2148162922Sariff
2149162922Sariff	config = hdac_command(sc,
2150162922Sariff	    HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
2151162922Sariff	    cad);
2152166965Sariff	orig = config;
2153166965Sariff
2154182999Smav	HDA_BOOTVERBOSE(
2155182999Smav		hdac_dump_pin_config(w, orig);
2156182999Smav	);
2157182999Smav
2158182999Smav	/* XXX: Old patches require complete review.
2159182999Smav	 * Now they may create more problem then solve due to
2160182999Smav	 * incorrect associations.
2161162965Sariff	 */
2162165281Sariff	if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) {
2163165281Sariff		switch (nid) {
2164165281Sariff		case 26:
2165165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2166165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2167165281Sariff			break;
2168165281Sariff		case 27:
2169165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2170165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
2171165281Sariff			break;
2172167610Sariff		default:
2173167610Sariff			break;
2174165281Sariff		}
2175165281Sariff	} else if (id == HDA_CODEC_ALC880 &&
2176162965Sariff	    (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR ||
2177162965Sariff	    sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) {
2178162922Sariff		/*
2179162965Sariff		 * Super broken BIOS
2180162922Sariff		 */
2181162922Sariff		switch (nid) {
2182162922Sariff		case 24:	/* MIC1 */
2183162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2184162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2185162922Sariff			break;
2186162922Sariff		case 25:	/* XXX MIC2 */
2187162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2188162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2189162922Sariff			break;
2190162922Sariff		case 26:	/* LINE1 */
2191162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2192162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2193162922Sariff			break;
2194162922Sariff		case 27:	/* XXX LINE2 */
2195162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2196162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2197162922Sariff			break;
2198162922Sariff		case 28:	/* CD */
2199162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2200162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
2201162922Sariff			break;
2202162922Sariff		}
2203166965Sariff	} else if (id == HDA_CODEC_ALC883 &&
2204172811Sariff	    (sc->pci_subvendor == MSI_MS034A_SUBVENDOR ||
2205172811Sariff	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor))) {
2206166965Sariff		switch (nid) {
2207166965Sariff		case 25:
2208166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2209166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2210166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2211166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2212166965Sariff			break;
2213169277Sariff		case 28:
2214169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2215169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2216169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2217169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2218169277Sariff			break;
2219166965Sariff		}
2220166965Sariff	} else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor ==
2221166965Sariff	    HP_V3000_SUBVENDOR) {
2222166965Sariff		switch (nid) {
2223166965Sariff		case 18:
2224166965Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2225166965Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2226166965Sariff			break;
2227166965Sariff		case 20:
2228166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2229166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2230166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2231166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2232166965Sariff			break;
2233167454Sariff		case 21:
2234167454Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2235167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2236167454Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2237167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2238167454Sariff			break;
2239166965Sariff		}
2240169277Sariff	} else if (id == HDA_CODEC_CXWAIKIKI && sc->pci_subvendor ==
2241169277Sariff	    HP_DV5000_SUBVENDOR) {
2242169277Sariff		switch (nid) {
2243169277Sariff		case 20:
2244169277Sariff		case 21:
2245169277Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2246169277Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2247169277Sariff			break;
2248169277Sariff		}
2249169277Sariff	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2250169277Sariff	    ASUS_W6F_SUBVENDOR) {
2251169277Sariff		switch (nid) {
2252169277Sariff		case 11:
2253169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2254169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2255169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
2256169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2257169277Sariff			break;
2258178324Sariff		case 12:
2259178324Sariff		case 14:
2260178324Sariff		case 16:
2261178324Sariff		case 31:
2262178324Sariff		case 32:
2263178324Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2264178324Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2265178324Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2266178324Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2267178324Sariff			break;
2268169277Sariff		case 15:
2269169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2270169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2271169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2272169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2273169277Sariff			break;
2274169277Sariff		}
2275169277Sariff	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2276169277Sariff	    UNIWILL_9075_SUBVENDOR) {
2277169277Sariff		switch (nid) {
2278169277Sariff		case 15:
2279169277Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2280169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2281169277Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2282169277Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2283169277Sariff			break;
2284169277Sariff		}
2285182999Smav	}
2286182999Smav
2287182999Smav	/* New patches */
2288182999Smav	if (id == HDA_CODEC_AD1986A &&
2289171141Sariff	    (sc->pci_subvendor == ASUS_M2NPVMX_SUBVENDOR ||
2290171141Sariff	    sc->pci_subvendor == ASUS_A8NVMCSM_SUBVENDOR)) {
2291169277Sariff		switch (nid) {
2292182999Smav		case 28: /* 5.1 out => 2.0 out + 2 inputs */
2293182999Smav			patch = "device=Line-in as=8 seq=1";
2294169277Sariff			break;
2295182999Smav		case 29:
2296182999Smav			patch = "device=Mic as=8 seq=2";
2297169277Sariff			break;
2298182999Smav		case 31: /* Lot of inputs configured with as=15 and unusable */
2299182999Smav			patch = "as=8 seq=3";
2300169277Sariff			break;
2301182999Smav		case 32:
2302182999Smav			patch = "as=8 seq=4";
2303182999Smav			break;
2304182999Smav		case 34:
2305182999Smav			patch = "as=8 seq=5";
2306182999Smav			break;
2307182999Smav		case 36:
2308182999Smav			patch = "as=8 seq=6";
2309182999Smav			break;
2310169277Sariff		}
2311182999Smav	} else if (id == HDA_CODEC_ALC260 &&
2312182999Smav	    HDA_DEV_MATCH(SONY_S5_SUBVENDOR, sc->pci_subvendor)) {
2313182999Smav		switch (nid) {
2314182999Smav		case 16:
2315182999Smav			patch = "seq=15 device=Headphones";
2316182999Smav			break;
2317182999Smav		}
2318174578Sariff	} else if (id == HDA_CODEC_ALC268 &&
2319174578Sariff	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) {
2320174578Sariff		switch (nid) {
2321174578Sariff		case 28:
2322182999Smav			patch = "device=CD conn=fixed";
2323174578Sariff			break;
2324174578Sariff		}
2325162922Sariff	}
2326162922Sariff
2327182999Smav	if (patch != NULL)
2328182999Smav		config = hdac_widget_pin_patch(config, patch);
2329182999Smav
2330182999Smav	snprintf(buf, sizeof(buf), "cad%u.nid%u.config", cad, nid);
2331182999Smav	if (resource_string_value(device_get_name(sc->dev),
2332182999Smav	    device_get_unit(sc->dev), buf, &res) == 0) {
2333182999Smav		if (strncmp(res, "0x", 2) == 0) {
2334182999Smav			config = strtol(res + 2, NULL, 16);
2335182999Smav		} else {
2336182999Smav			config = hdac_widget_pin_patch(config, res);
2337182999Smav		}
2338182999Smav	}
2339182999Smav
2340166965Sariff	HDA_BOOTVERBOSE(
2341166965Sariff		if (config != orig)
2342166965Sariff			device_printf(sc->dev,
2343182999Smav			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
2344166965Sariff			    nid, orig, config);
2345166965Sariff	);
2346166965Sariff
2347162922Sariff	return (config);
2348162922Sariff}
2349162922Sariff
2350166965Sariffstatic uint32_t
2351166965Sariffhdac_widget_pin_getcaps(struct hdac_widget *w)
2352166965Sariff{
2353166965Sariff	struct hdac_softc *sc;
2354166965Sariff	uint32_t caps, orig, id;
2355166965Sariff	nid_t cad, nid;
2356166965Sariff
2357166965Sariff	sc = w->devinfo->codec->sc;
2358166965Sariff	cad = w->devinfo->codec->cad;
2359166965Sariff	nid = w->nid;
2360182999Smav	id = hdac_codec_id(w->devinfo->codec);
2361166965Sariff
2362166965Sariff	caps = hdac_command(sc,
2363166965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
2364166965Sariff	orig = caps;
2365166965Sariff
2366166965Sariff	HDA_BOOTVERBOSE(
2367166965Sariff		if (caps != orig)
2368166965Sariff			device_printf(sc->dev,
2369182999Smav			    "Patching pin caps nid=%u 0x%08x -> 0x%08x\n",
2370166965Sariff			    nid, orig, caps);
2371166965Sariff	);
2372166965Sariff
2373166965Sariff	return (caps);
2374166965Sariff}
2375166965Sariff
2376162922Sariffstatic void
2377162922Sariffhdac_widget_pin_parse(struct hdac_widget *w)
2378162922Sariff{
2379162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2380162922Sariff	uint32_t config, pincap;
2381182999Smav	const char *devstr, *connstr;
2382162922Sariff	nid_t cad = w->devinfo->codec->cad;
2383162922Sariff	nid_t nid = w->nid;
2384162922Sariff
2385162922Sariff	config = hdac_widget_pin_getconfig(w);
2386162922Sariff	w->wclass.pin.config = config;
2387162922Sariff
2388166965Sariff	pincap = hdac_widget_pin_getcaps(w);
2389162922Sariff	w->wclass.pin.cap = pincap;
2390162922Sariff
2391162922Sariff	w->wclass.pin.ctrl = hdac_command(sc,
2392182999Smav	    HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad);
2393162922Sariff
2394162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
2395162922Sariff		w->param.eapdbtl = hdac_command(sc,
2396162922Sariff		    HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
2397162922Sariff		w->param.eapdbtl &= 0x7;
2398162922Sariff		w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
2399162922Sariff	} else
2400162965Sariff		w->param.eapdbtl = HDAC_INVALID;
2401162922Sariff
2402182999Smav	devstr = HDA_DEVS[(config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) >>
2403182999Smav	    HDA_CONFIG_DEFAULTCONF_DEVICE_SHIFT];
2404162922Sariff
2405182999Smav	connstr = HDA_CONNS[(config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) >>
2406182999Smav	    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_SHIFT];
2407162922Sariff
2408162922Sariff	strlcat(w->name, ": ", sizeof(w->name));
2409162922Sariff	strlcat(w->name, devstr, sizeof(w->name));
2410162922Sariff	strlcat(w->name, " (", sizeof(w->name));
2411162922Sariff	strlcat(w->name, connstr, sizeof(w->name));
2412162922Sariff	strlcat(w->name, ")", sizeof(w->name));
2413162922Sariff}
2414162922Sariff
2415182999Smavstatic uint32_t
2416182999Smavhdac_widget_getcaps(struct hdac_widget *w, int *waspin)
2417182999Smav{
2418182999Smav	struct hdac_softc *sc;
2419182999Smav	uint32_t caps, orig, id;
2420182999Smav	nid_t cad, nid, beeper = -1;
2421182999Smav
2422182999Smav	sc = w->devinfo->codec->sc;
2423182999Smav	cad = w->devinfo->codec->cad;
2424182999Smav	nid = w->nid;
2425182999Smav	id = hdac_codec_id(w->devinfo->codec);
2426182999Smav
2427182999Smav	caps = hdac_command(sc,
2428182999Smav	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
2429182999Smav	    cad);
2430182999Smav	orig = caps;
2431182999Smav
2432182999Smav	/* On some codecs beeper is an input pin, but it is not recordable
2433182999Smav	   alone. Also most of BIOSes does not declare beeper pin.
2434182999Smav	   Change beeper pin node type to beeper to help parser. */
2435182999Smav	*waspin = 0;
2436182999Smav	switch (id) {
2437182999Smav	case HDA_CODEC_AD1988:
2438182999Smav	case HDA_CODEC_AD1988B:
2439182999Smav		beeper = 26;
2440182999Smav		break;
2441182999Smav	case HDA_CODEC_ALC260:
2442182999Smav		beeper = 23;
2443182999Smav		break;
2444182999Smav	case HDA_CODEC_ALC262:
2445182999Smav	case HDA_CODEC_ALC268:
2446182999Smav	case HDA_CODEC_ALC880:
2447182999Smav	case HDA_CODEC_ALC882:
2448182999Smav	case HDA_CODEC_ALC883:
2449182999Smav	case HDA_CODEC_ALC885:
2450182999Smav	case HDA_CODEC_ALC888:
2451182999Smav	case HDA_CODEC_ALC889:
2452182999Smav		beeper = 29;
2453182999Smav		break;
2454182999Smav	}
2455182999Smav	if (nid == beeper) {
2456182999Smav		caps &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
2457182999Smav		caps |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
2458182999Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
2459182999Smav		*waspin = 1;
2460182999Smav	}
2461182999Smav
2462182999Smav	HDA_BOOTVERBOSE(
2463182999Smav		if (caps != orig) {
2464182999Smav			device_printf(sc->dev,
2465182999Smav			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
2466182999Smav			    nid, orig, caps);
2467182999Smav		}
2468182999Smav	);
2469182999Smav
2470182999Smav	return (caps);
2471182999Smav}
2472182999Smav
2473162922Sariffstatic void
2474162922Sariffhdac_widget_parse(struct hdac_widget *w)
2475162922Sariff{
2476162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
2477162922Sariff	uint32_t wcap, cap;
2478162922Sariff	char *typestr;
2479162922Sariff	nid_t cad = w->devinfo->codec->cad;
2480162922Sariff	nid_t nid = w->nid;
2481162922Sariff
2482182999Smav	wcap = hdac_widget_getcaps(w, &w->waspin);
2483182999Smav
2484162922Sariff	w->param.widget_cap = wcap;
2485162922Sariff	w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
2486162922Sariff
2487162922Sariff	switch (w->type) {
2488162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
2489162922Sariff		typestr = "audio output";
2490162922Sariff		break;
2491162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
2492162922Sariff		typestr = "audio input";
2493162922Sariff		break;
2494162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
2495162922Sariff		typestr = "audio mixer";
2496162922Sariff		break;
2497162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
2498162922Sariff		typestr = "audio selector";
2499162922Sariff		break;
2500162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
2501162922Sariff		typestr = "pin";
2502162922Sariff		break;
2503162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET:
2504162922Sariff		typestr = "power widget";
2505162922Sariff		break;
2506162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET:
2507162922Sariff		typestr = "volume widget";
2508162922Sariff		break;
2509162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
2510162922Sariff		typestr = "beep widget";
2511162922Sariff		break;
2512162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET:
2513162922Sariff		typestr = "vendor widget";
2514162922Sariff		break;
2515162922Sariff	default:
2516162922Sariff		typestr = "unknown type";
2517162922Sariff		break;
2518162922Sariff	}
2519162922Sariff
2520162922Sariff	strlcpy(w->name, typestr, sizeof(w->name));
2521162922Sariff
2522162922Sariff	hdac_widget_connection_parse(w);
2523162922Sariff
2524162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
2525162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2526162922Sariff			w->param.outamp_cap =
2527162922Sariff			    hdac_command(sc,
2528162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2529162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP), cad);
2530162922Sariff		else
2531162922Sariff			w->param.outamp_cap =
2532162922Sariff			    w->devinfo->function.audio.outamp_cap;
2533162922Sariff	} else
2534162922Sariff		w->param.outamp_cap = 0;
2535162922Sariff
2536162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) {
2537162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2538162922Sariff			w->param.inamp_cap =
2539162922Sariff			    hdac_command(sc,
2540162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2541162922Sariff			    HDA_PARAM_INPUT_AMP_CAP), cad);
2542162922Sariff		else
2543162922Sariff			w->param.inamp_cap =
2544162922Sariff			    w->devinfo->function.audio.inamp_cap;
2545162922Sariff	} else
2546162922Sariff		w->param.inamp_cap = 0;
2547162922Sariff
2548162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
2549162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
2550162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) {
2551162922Sariff			cap = hdac_command(sc,
2552162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2553162922Sariff			    HDA_PARAM_SUPP_STREAM_FORMATS), cad);
2554162922Sariff			w->param.supp_stream_formats = (cap != 0) ? cap :
2555162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2556162922Sariff			cap = hdac_command(sc,
2557162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2558162922Sariff			    HDA_PARAM_SUPP_PCM_SIZE_RATE), cad);
2559162922Sariff			w->param.supp_pcm_size_rate = (cap != 0) ? cap :
2560162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2561162922Sariff		} else {
2562162922Sariff			w->param.supp_stream_formats =
2563162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2564162922Sariff			w->param.supp_pcm_size_rate =
2565162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2566162922Sariff		}
2567162922Sariff	} else {
2568162922Sariff		w->param.supp_stream_formats = 0;
2569162922Sariff		w->param.supp_pcm_size_rate = 0;
2570162922Sariff	}
2571162922Sariff
2572162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
2573162922Sariff		hdac_widget_pin_parse(w);
2574162922Sariff}
2575162922Sariff
2576162922Sariffstatic struct hdac_widget *
2577162922Sariffhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid)
2578162922Sariff{
2579162922Sariff	if (devinfo == NULL || devinfo->widget == NULL ||
2580162922Sariff		    nid < devinfo->startnode || nid >= devinfo->endnode)
2581162922Sariff		return (NULL);
2582162922Sariff	return (&devinfo->widget[nid - devinfo->startnode]);
2583162922Sariff}
2584162922Sariff
2585164614Sariffstatic __inline int
2586164614Sariffhda_poll_channel(struct hdac_chan *ch)
2587164614Sariff{
2588164614Sariff	uint32_t sz, delta;
2589164614Sariff	volatile uint32_t ptr;
2590164614Sariff
2591171330Sariff	if (!(ch->flags & HDAC_CHN_RUNNING))
2592164614Sariff		return (0);
2593164614Sariff
2594164614Sariff	sz = ch->blksz * ch->blkcnt;
2595169277Sariff	if (ch->dmapos != NULL)
2596169277Sariff		ptr = *(ch->dmapos);
2597169277Sariff	else
2598169277Sariff		ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem,
2599169277Sariff		    ch->off + HDAC_SDLPIB);
2600164614Sariff	ch->ptr = ptr;
2601164614Sariff	ptr %= sz;
2602164614Sariff	ptr &= ~(ch->blksz - 1);
2603164614Sariff	delta = (sz + ptr - ch->prevptr) % sz;
2604164614Sariff
2605164614Sariff	if (delta < ch->blksz)
2606164614Sariff		return (0);
2607164614Sariff
2608164614Sariff	ch->prevptr = ptr;
2609164614Sariff
2610164614Sariff	return (1);
2611164614Sariff}
2612164614Sariff
2613162922Sariffstatic void
2614164614Sariffhda_poll_callback(void *arg)
2615164614Sariff{
2616164614Sariff	struct hdac_softc *sc = arg;
2617171141Sariff	uint32_t trigger;
2618182999Smav	int i, active = 0;
2619164614Sariff
2620164614Sariff	if (sc == NULL)
2621164614Sariff		return;
2622164614Sariff
2623164614Sariff	hdac_lock(sc);
2624182999Smav	if (sc->polling == 0) {
2625164614Sariff		hdac_unlock(sc);
2626164614Sariff		return;
2627164614Sariff	}
2628164614Sariff
2629171141Sariff	trigger = 0;
2630182999Smav	for (i = 0; i < sc->num_chans; i++) {
2631182999Smav		if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
2632182999Smav		    continue;
2633182999Smav		active = 1;
2634182999Smav		if (hda_poll_channel(&sc->chans[i]))
2635182999Smav		    trigger |= (1 << i);
2636182999Smav	}
2637164614Sariff
2638164614Sariff	/* XXX */
2639182999Smav	if (active)
2640182999Smav		callout_reset(&sc->poll_hda, sc->poll_ticks,
2641182999Smav		    hda_poll_callback, sc);
2642164614Sariff
2643164614Sariff	hdac_unlock(sc);
2644164614Sariff
2645182999Smav	for (i = 0; i < sc->num_chans; i++) {
2646182999Smav		if (trigger & (1 << i))
2647182999Smav			chn_intr(sc->chans[i].c);
2648182999Smav	}
2649164614Sariff}
2650164614Sariff
2651164614Sariffstatic int
2652164614Sariffhdac_rirb_flush(struct hdac_softc *sc)
2653164614Sariff{
2654164614Sariff	struct hdac_rirb *rirb_base, *rirb;
2655164614Sariff	struct hdac_codec *codec;
2656164614Sariff	struct hdac_command_list *commands;
2657164614Sariff	nid_t cad;
2658164614Sariff	uint32_t resp;
2659164614Sariff	uint8_t rirbwp;
2660171141Sariff	int ret;
2661164614Sariff
2662164614Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2663164614Sariff	rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
2664169277Sariff#if 0
2665164614Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2666164614Sariff	    BUS_DMASYNC_POSTREAD);
2667169277Sariff#endif
2668164614Sariff
2669171141Sariff	ret = 0;
2670171141Sariff
2671164614Sariff	while (sc->rirb_rp != rirbwp) {
2672164614Sariff		sc->rirb_rp++;
2673164614Sariff		sc->rirb_rp %= sc->rirb_size;
2674164614Sariff		rirb = &rirb_base[sc->rirb_rp];
2675164614Sariff		cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
2676164614Sariff		if (cad < 0 || cad >= HDAC_CODEC_MAX ||
2677164614Sariff		    sc->codecs[cad] == NULL)
2678164614Sariff			continue;
2679164614Sariff		resp = rirb->response;
2680164614Sariff		codec = sc->codecs[cad];
2681164614Sariff		commands = codec->commands;
2682164614Sariff		if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
2683164614Sariff			sc->unsolq[sc->unsolq_wp++] = (cad << 16) |
2684164614Sariff			    ((resp >> 26) & 0xffff);
2685164614Sariff			sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
2686164614Sariff		} else if (commands != NULL && commands->num_commands > 0 &&
2687164614Sariff		    codec->responses_received < commands->num_commands)
2688164614Sariff			commands->responses[codec->responses_received++] =
2689164614Sariff			    resp;
2690164614Sariff		ret++;
2691164614Sariff	}
2692164614Sariff
2693164614Sariff	return (ret);
2694164614Sariff}
2695164614Sariff
2696164614Sariffstatic int
2697164614Sariffhdac_unsolq_flush(struct hdac_softc *sc)
2698164614Sariff{
2699164614Sariff	nid_t cad;
2700164614Sariff	uint32_t tag;
2701164614Sariff	int ret = 0;
2702164614Sariff
2703164614Sariff	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
2704164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
2705164614Sariff		while (sc->unsolq_rp != sc->unsolq_wp) {
2706164614Sariff			cad = sc->unsolq[sc->unsolq_rp] >> 16;
2707164614Sariff			tag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
2708164614Sariff			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
2709164614Sariff			hdac_unsolicited_handler(sc->codecs[cad], tag);
2710164614Sariff			ret++;
2711164614Sariff		}
2712164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_READY;
2713164614Sariff	}
2714164614Sariff
2715164614Sariff	return (ret);
2716164614Sariff}
2717164614Sariff
2718164614Sariffstatic void
2719164614Sariffhdac_poll_callback(void *arg)
2720164614Sariff{
2721164614Sariff	struct hdac_softc *sc = arg;
2722164614Sariff	if (sc == NULL)
2723164614Sariff		return;
2724166796Sariff
2725164614Sariff	hdac_lock(sc);
2726169277Sariff	if (sc->polling == 0 || sc->poll_ival == 0) {
2727164614Sariff		hdac_unlock(sc);
2728164614Sariff		return;
2729164614Sariff	}
2730171141Sariff	if (hdac_rirb_flush(sc) != 0)
2731171141Sariff		hdac_unsolq_flush(sc);
2732169277Sariff	callout_reset(&sc->poll_hdac, sc->poll_ival, hdac_poll_callback, sc);
2733164614Sariff	hdac_unlock(sc);
2734164614Sariff}
2735164614Sariff
2736164614Sariffstatic void
2737182999Smavhdac_poll_reinit(struct hdac_softc *sc)
2738182999Smav{
2739182999Smav	int i, pollticks, min = 1000000;
2740182999Smav	struct hdac_chan *ch;
2741182999Smav
2742182999Smav	for (i = 0; i < sc->num_chans; i++) {
2743182999Smav		if ((sc->chans[i].flags & HDAC_CHN_RUNNING) == 0)
2744182999Smav			continue;
2745182999Smav		ch = &sc->chans[i];
2746182999Smav		pollticks = ((uint64_t)hz * ch->blksz) /
2747182999Smav		    ((uint64_t)sndbuf_getbps(ch->b) *
2748182999Smav		    sndbuf_getspd(ch->b));
2749182999Smav		pollticks >>= 1;
2750182999Smav		if (pollticks > hz)
2751182999Smav			pollticks = hz;
2752182999Smav		if (pollticks < 1) {
2753182999Smav			HDA_BOOTVERBOSE(
2754182999Smav				device_printf(sc->dev,
2755182999Smav				    "%s: pollticks=%d < 1 !\n",
2756182999Smav				    __func__, pollticks);
2757182999Smav			);
2758182999Smav			pollticks = 1;
2759182999Smav		}
2760182999Smav		if (min > pollticks)
2761182999Smav			min = pollticks;
2762182999Smav	}
2763182999Smav	HDA_BOOTVERBOSE(
2764182999Smav		device_printf(sc->dev,
2765182999Smav		    "%s: pollticks %d -> %d\n",
2766182999Smav		    __func__, sc->poll_ticks, min);
2767182999Smav	);
2768182999Smav	sc->poll_ticks = min;
2769182999Smav	if (min == 1000000)
2770182999Smav		callout_stop(&sc->poll_hda);
2771182999Smav	else
2772182999Smav		callout_reset(&sc->poll_hda, 1, hda_poll_callback, sc);
2773182999Smav}
2774182999Smav
2775182999Smavstatic void
2776162922Sariffhdac_stream_stop(struct hdac_chan *ch)
2777162922Sariff{
2778162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2779162922Sariff	uint32_t ctl;
2780162922Sariff
2781162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2782162922Sariff	ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2783162922Sariff	    HDAC_SDCTL_RUN);
2784162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2785162922Sariff
2786171330Sariff	ch->flags &= ~HDAC_CHN_RUNNING;
2787164614Sariff
2788182999Smav	if (sc->polling != 0)
2789182999Smav		hdac_poll_reinit(sc);
2790164614Sariff
2791182999Smav	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2792182999Smav	ctl &= ~(1 << (ch->off >> 5));
2793182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2794162922Sariff}
2795162922Sariff
2796162922Sariffstatic void
2797162922Sariffhdac_stream_start(struct hdac_chan *ch)
2798162922Sariff{
2799162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2800162922Sariff	uint32_t ctl;
2801162922Sariff
2802182999Smav	ch->flags |= HDAC_CHN_RUNNING;
2803162922Sariff
2804182999Smav	if (sc->polling != 0)
2805182999Smav		hdac_poll_reinit(sc);
2806182999Smav
2807182999Smav	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2808182999Smav	ctl |= 1 << (ch->off >> 5);
2809182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2810182999Smav
2811182999Smav	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2812182999Smav	ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2813182999Smav	    HDAC_SDCTL_RUN;
2814162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2815162922Sariff}
2816162922Sariff
2817162922Sariffstatic void
2818162922Sariffhdac_stream_reset(struct hdac_chan *ch)
2819162922Sariff{
2820162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2821162922Sariff	int timeout = 1000;
2822162922Sariff	int to = timeout;
2823162922Sariff	uint32_t ctl;
2824162922Sariff
2825162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2826162922Sariff	ctl |= HDAC_SDCTL_SRST;
2827162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2828162922Sariff	do {
2829162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2830162922Sariff		if (ctl & HDAC_SDCTL_SRST)
2831162922Sariff			break;
2832162922Sariff		DELAY(10);
2833162922Sariff	} while (--to);
2834162922Sariff	if (!(ctl & HDAC_SDCTL_SRST)) {
2835162922Sariff		device_printf(sc->dev, "timeout in reset\n");
2836162922Sariff	}
2837162922Sariff	ctl &= ~HDAC_SDCTL_SRST;
2838162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2839162922Sariff	to = timeout;
2840162922Sariff	do {
2841162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2842162922Sariff		if (!(ctl & HDAC_SDCTL_SRST))
2843162922Sariff			break;
2844162922Sariff		DELAY(10);
2845162922Sariff	} while (--to);
2846163057Sariff	if (ctl & HDAC_SDCTL_SRST)
2847162922Sariff		device_printf(sc->dev, "can't reset!\n");
2848162922Sariff}
2849162922Sariff
2850162922Sariffstatic void
2851162922Sariffhdac_stream_setid(struct hdac_chan *ch)
2852162922Sariff{
2853162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2854162922Sariff	uint32_t ctl;
2855162922Sariff
2856162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2);
2857162922Sariff	ctl &= ~HDAC_SDCTL2_STRM_MASK;
2858162922Sariff	ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT;
2859162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl);
2860162922Sariff}
2861162922Sariff
2862162922Sariffstatic void
2863162922Sariffhdac_bdl_setup(struct hdac_chan *ch)
2864162922Sariff{
2865162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2866164614Sariff	struct hdac_bdle *bdle;
2867162922Sariff	uint64_t addr;
2868164614Sariff	uint32_t blksz, blkcnt;
2869162922Sariff	int i;
2870162922Sariff
2871162922Sariff	addr = (uint64_t)sndbuf_getbufaddr(ch->b);
2872164614Sariff	bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr;
2873162922Sariff
2874182999Smav	blksz = ch->blksz;
2875182999Smav	blkcnt = ch->blkcnt;
2876164614Sariff
2877164614Sariff	for (i = 0; i < blkcnt; i++, bdle++) {
2878162922Sariff		bdle->addrl = (uint32_t)addr;
2879162922Sariff		bdle->addrh = (uint32_t)(addr >> 32);
2880164614Sariff		bdle->len = blksz;
2881182999Smav		bdle->ioc = 1;
2882164614Sariff		addr += blksz;
2883162922Sariff	}
2884162922Sariff
2885164614Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt);
2886164614Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1);
2887162922Sariff	addr = ch->bdl_dma.dma_paddr;
2888162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr);
2889162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
2890169277Sariff	if (ch->dmapos != NULL &&
2891169277Sariff	    !(HDAC_READ_4(&sc->mem, HDAC_DPIBLBASE) & 0x00000001)) {
2892169277Sariff		addr = sc->pos_dma.dma_paddr;
2893169277Sariff		HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE,
2894169277Sariff		    ((uint32_t)addr & HDAC_DPLBASE_DPLBASE_MASK) | 0x00000001);
2895169277Sariff		HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, (uint32_t)(addr >> 32));
2896169277Sariff	}
2897162922Sariff}
2898162922Sariff
2899162922Sariffstatic int
2900162922Sariffhdac_bdl_alloc(struct hdac_chan *ch)
2901162922Sariff{
2902162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2903162922Sariff	int rc;
2904162922Sariff
2905162922Sariff	rc = hdac_dma_alloc(sc, &ch->bdl_dma,
2906162922Sariff	    sizeof(struct hdac_bdle) * HDA_BDL_MAX);
2907162922Sariff	if (rc) {
2908162922Sariff		device_printf(sc->dev, "can't alloc bdl\n");
2909162922Sariff		return (rc);
2910162922Sariff	}
2911162922Sariff
2912162922Sariff	return (0);
2913162922Sariff}
2914162922Sariff
2915162922Sariffstatic void
2916162922Sariffhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid,
2917162922Sariff					int index, int lmute, int rmute,
2918162922Sariff					int left, int right, int dir)
2919162922Sariff{
2920162922Sariff	uint16_t v = 0;
2921162922Sariff
2922162922Sariff	if (sc == NULL)
2923162922Sariff		return;
2924162922Sariff
2925162922Sariff	if (left != right || lmute != rmute) {
2926162922Sariff		v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
2927162922Sariff		    (lmute << 7) | left;
2928162922Sariff		hdac_command(sc,
2929164614Sariff		    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2930162922Sariff		v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
2931162922Sariff		    (rmute << 7) | right;
2932162922Sariff	} else
2933162922Sariff		v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
2934162922Sariff		    (lmute << 7) | left;
2935162922Sariff
2936162922Sariff	hdac_command(sc,
2937162922Sariff	    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2938162922Sariff}
2939162922Sariff
2940162922Sariffstatic void
2941162922Sariffhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
2942162922Sariff						int left, int right)
2943162922Sariff{
2944162922Sariff	struct hdac_softc *sc;
2945162922Sariff	nid_t nid, cad;
2946162922Sariff	int lmute, rmute;
2947162922Sariff
2948162922Sariff	sc = ctl->widget->devinfo->codec->sc;
2949162922Sariff	cad = ctl->widget->devinfo->codec->cad;
2950162922Sariff	nid = ctl->widget->nid;
2951162922Sariff
2952182999Smav	/* Save new values if valid. */
2953182999Smav	if (mute != HDA_AMP_MUTE_DEFAULT)
2954182999Smav		ctl->muted = mute;
2955182999Smav	if (left != HDA_AMP_VOL_DEFAULT)
2956182999Smav		ctl->left = left;
2957182999Smav	if (right != HDA_AMP_VOL_DEFAULT)
2958182999Smav		ctl->right = right;
2959182999Smav	/* Prepare effective values */
2960182999Smav	if (ctl->forcemute) {
2961182999Smav		lmute = 1;
2962182999Smav		rmute = 1;
2963182999Smav		left = 0;
2964182999Smav		right = 0;
2965182999Smav	} else {
2966162922Sariff		lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
2967162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
2968182999Smav		left = ctl->left;
2969182999Smav		right = ctl->right;
2970162922Sariff	}
2971182999Smav	/* Apply effective values */
2972162922Sariff	if (ctl->dir & HDA_CTL_OUT)
2973162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2974162922Sariff		    lmute, rmute, left, right, 0);
2975162922Sariff	if (ctl->dir & HDA_CTL_IN)
2976182999Smav    		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2977162922Sariff		    lmute, rmute, left, right, 1);
2978162922Sariff}
2979162922Sariff
2980162922Sariffstatic void
2981162922Sariffhdac_widget_connection_select(struct hdac_widget *w, uint8_t index)
2982162922Sariff{
2983162922Sariff	if (w == NULL || w->nconns < 1 || index > (w->nconns - 1))
2984162922Sariff		return;
2985162922Sariff	hdac_command(w->devinfo->codec->sc,
2986162922Sariff	    HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad,
2987162922Sariff	    w->nid, index), w->devinfo->codec->cad);
2988162922Sariff	w->selconn = index;
2989162922Sariff}
2990162922Sariff
2991162922Sariff
2992162922Sariff/****************************************************************************
2993162922Sariff * uint32_t hdac_command_sendone_internal
2994162922Sariff *
2995162922Sariff * Wrapper function that sends only one command to a given codec
2996162922Sariff ****************************************************************************/
2997162922Sariffstatic uint32_t
2998162922Sariffhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad)
2999162922Sariff{
3000162922Sariff	struct hdac_command_list cl;
3001162965Sariff	uint32_t response = HDAC_INVALID;
3002162922Sariff
3003163057Sariff	if (!hdac_lockowned(sc))
3004162922Sariff		device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n");
3005162922Sariff	cl.num_commands = 1;
3006162922Sariff	cl.verbs = &verb;
3007162922Sariff	cl.responses = &response;
3008162922Sariff
3009162922Sariff	hdac_command_send_internal(sc, &cl, cad);
3010162922Sariff
3011162922Sariff	return (response);
3012162922Sariff}
3013162922Sariff
3014162922Sariff/****************************************************************************
3015162922Sariff * hdac_command_send_internal
3016162922Sariff *
3017162922Sariff * Send a command list to the codec via the corb. We queue as much verbs as
3018162922Sariff * we can and msleep on the codec. When the interrupt get the responses
3019162922Sariff * back from the rirb, it will wake us up so we can queue the remaining verbs
3020162922Sariff * if any.
3021162922Sariff ****************************************************************************/
3022162922Sariffstatic void
3023162922Sariffhdac_command_send_internal(struct hdac_softc *sc,
3024162922Sariff			struct hdac_command_list *commands, nid_t cad)
3025162922Sariff{
3026162922Sariff	struct hdac_codec *codec;
3027162922Sariff	int corbrp;
3028162922Sariff	uint32_t *corb;
3029162922Sariff	int timeout;
3030162922Sariff	int retry = 10;
3031164614Sariff	struct hdac_rirb *rirb_base;
3032162922Sariff
3033164614Sariff	if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL ||
3034164614Sariff	    commands->num_commands < 1)
3035162922Sariff		return;
3036162922Sariff
3037162922Sariff	codec = sc->codecs[cad];
3038162922Sariff	codec->commands = commands;
3039162922Sariff	codec->responses_received = 0;
3040162922Sariff	codec->verbs_sent = 0;
3041162922Sariff	corb = (uint32_t *)sc->corb_dma.dma_vaddr;
3042162922Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
3043162922Sariff
3044162922Sariff	do {
3045162922Sariff		if (codec->verbs_sent != commands->num_commands) {
3046162922Sariff			/* Queue as many verbs as possible */
3047162922Sariff			corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP);
3048169277Sariff#if 0
3049162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
3050162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
3051169277Sariff#endif
3052162922Sariff			while (codec->verbs_sent != commands->num_commands &&
3053162922Sariff			    ((sc->corb_wp + 1) % sc->corb_size) != corbrp) {
3054162922Sariff				sc->corb_wp++;
3055162922Sariff				sc->corb_wp %= sc->corb_size;
3056162922Sariff				corb[sc->corb_wp] =
3057162922Sariff				    commands->verbs[codec->verbs_sent++];
3058162922Sariff			}
3059162922Sariff
3060162922Sariff			/* Send the verbs to the codecs */
3061169277Sariff#if 0
3062162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
3063162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
3064169277Sariff#endif
3065162922Sariff			HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
3066162922Sariff		}
3067162922Sariff
3068162922Sariff		timeout = 1000;
3069164614Sariff		while (hdac_rirb_flush(sc) == 0 && --timeout)
3070162922Sariff			DELAY(10);
3071162922Sariff	} while ((codec->verbs_sent != commands->num_commands ||
3072164614Sariff	    codec->responses_received != commands->num_commands) && --retry);
3073162922Sariff
3074162922Sariff	if (retry == 0)
3075162922Sariff		device_printf(sc->dev,
3076164614Sariff		    "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n",
3077164614Sariff		    __func__, commands->num_commands, codec->verbs_sent,
3078164614Sariff		    codec->responses_received);
3079162922Sariff
3080164614Sariff	codec->commands = NULL;
3081164614Sariff	codec->responses_received = 0;
3082162922Sariff	codec->verbs_sent = 0;
3083162922Sariff
3084164614Sariff	hdac_unsolq_flush(sc);
3085162922Sariff}
3086162922Sariff
3087162922Sariff
3088162922Sariff/****************************************************************************
3089162922Sariff * Device Methods
3090162922Sariff ****************************************************************************/
3091162922Sariff
3092162922Sariff/****************************************************************************
3093162922Sariff * int hdac_probe(device_t)
3094162922Sariff *
3095162922Sariff * Probe for the presence of an hdac. If none is found, check for a generic
3096162922Sariff * match using the subclass of the device.
3097162922Sariff ****************************************************************************/
3098162922Sariffstatic int
3099162922Sariffhdac_probe(device_t dev)
3100162922Sariff{
3101162922Sariff	int i, result;
3102163257Sariff	uint32_t model;
3103163257Sariff	uint16_t class, subclass;
3104162922Sariff	char desc[64];
3105162922Sariff
3106162922Sariff	model = (uint32_t)pci_get_device(dev) << 16;
3107162922Sariff	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
3108162922Sariff	class = pci_get_class(dev);
3109162922Sariff	subclass = pci_get_subclass(dev);
3110162922Sariff
3111162922Sariff	bzero(desc, sizeof(desc));
3112162922Sariff	result = ENXIO;
3113162922Sariff	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
3114162922Sariff		if (hdac_devices[i].model == model) {
3115162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3116162922Sariff		    	result = BUS_PROBE_DEFAULT;
3117162922Sariff			break;
3118162922Sariff		}
3119163257Sariff		if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
3120162922Sariff		    class == PCIC_MULTIMEDIA &&
3121162922Sariff		    subclass == PCIS_MULTIMEDIA_HDA) {
3122162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3123162922Sariff		    	result = BUS_PROBE_GENERIC;
3124162922Sariff			break;
3125162922Sariff		}
3126162922Sariff	}
3127162922Sariff	if (result == ENXIO && class == PCIC_MULTIMEDIA &&
3128162922Sariff	    subclass == PCIS_MULTIMEDIA_HDA) {
3129162922Sariff		strlcpy(desc, "Generic", sizeof(desc));
3130162922Sariff	    	result = BUS_PROBE_GENERIC;
3131162922Sariff	}
3132162922Sariff	if (result != ENXIO) {
3133162922Sariff		strlcat(desc, " High Definition Audio Controller",
3134162922Sariff		    sizeof(desc));
3135162922Sariff		device_set_desc_copy(dev, desc);
3136162922Sariff	}
3137162922Sariff
3138162922Sariff	return (result);
3139162922Sariff}
3140162922Sariff
3141162922Sariffstatic void *
3142162922Sariffhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
3143162922Sariff					struct pcm_channel *c, int dir)
3144162922Sariff{
3145182999Smav	struct hdac_pcm_devinfo *pdevinfo = data;
3146182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3147162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3148162922Sariff	struct hdac_chan *ch;
3149182999Smav	int i, ord = 0, chid;
3150162922Sariff
3151162922Sariff	hdac_lock(sc);
3152182999Smav
3153182999Smav	chid = (dir == PCMDIR_PLAY)?pdevinfo->play:pdevinfo->rec;
3154182999Smav	ch = &sc->chans[chid];
3155182999Smav	for (i = 0; i < sc->num_chans && i < chid; i++) {
3156182999Smav		if (ch->dir == sc->chans[i].dir)
3157182999Smav			ord++;
3158182999Smav	}
3159162922Sariff	if (dir == PCMDIR_PLAY) {
3160182999Smav		ch->off = (sc->num_iss + ord) << 5;
3161162922Sariff	} else {
3162182999Smav		ch->off = ord << 5;
3163162922Sariff	}
3164182999Smav
3165162922Sariff	if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
3166162922Sariff		ch->caps.minspeed = ch->caps.maxspeed = 48000;
3167162922Sariff		ch->pcmrates[0] = 48000;
3168162922Sariff		ch->pcmrates[1] = 0;
3169162922Sariff	}
3170169277Sariff	if (sc->pos_dma.dma_vaddr != NULL)
3171169277Sariff		ch->dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr +
3172169277Sariff		    (sc->streamcnt * 8));
3173169277Sariff	else
3174169277Sariff		ch->dmapos = NULL;
3175169277Sariff	ch->sid = ++sc->streamcnt;
3176169277Sariff	ch->dir = dir;
3177162922Sariff	ch->b = b;
3178162922Sariff	ch->c = c;
3179182999Smav	ch->blksz = pdevinfo->chan_size / pdevinfo->chan_blkcnt;
3180182999Smav	ch->blkcnt = pdevinfo->chan_blkcnt;
3181162922Sariff	hdac_unlock(sc);
3182162922Sariff
3183162922Sariff	if (hdac_bdl_alloc(ch) != 0) {
3184162922Sariff		ch->blkcnt = 0;
3185162922Sariff		return (NULL);
3186162922Sariff	}
3187162922Sariff
3188169277Sariff	if (sndbuf_alloc(ch->b, sc->chan_dmat,
3189171330Sariff	    (sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0,
3190182999Smav	    pdevinfo->chan_size) != 0)
3191162922Sariff		return (NULL);
3192162922Sariff
3193162922Sariff	return (ch);
3194162922Sariff}
3195162922Sariff
3196162922Sariffstatic int
3197162922Sariffhdac_channel_setformat(kobj_t obj, void *data, uint32_t format)
3198162922Sariff{
3199162922Sariff	struct hdac_chan *ch = data;
3200162922Sariff	int i;
3201162922Sariff
3202162922Sariff	for (i = 0; ch->caps.fmtlist[i] != 0; i++) {
3203162922Sariff		if (format == ch->caps.fmtlist[i]) {
3204162922Sariff			ch->fmt = format;
3205162922Sariff			return (0);
3206162922Sariff		}
3207162922Sariff	}
3208162922Sariff
3209162922Sariff	return (EINVAL);
3210162922Sariff}
3211162922Sariff
3212162922Sariffstatic int
3213162922Sariffhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed)
3214162922Sariff{
3215162922Sariff	struct hdac_chan *ch = data;
3216164614Sariff	uint32_t spd = 0, threshold;
3217162922Sariff	int i;
3218162922Sariff
3219162922Sariff	for (i = 0; ch->pcmrates[i] != 0; i++) {
3220162922Sariff		spd = ch->pcmrates[i];
3221164614Sariff		threshold = spd + ((ch->pcmrates[i + 1] != 0) ?
3222164614Sariff		    ((ch->pcmrates[i + 1] - spd) >> 1) : 0);
3223164614Sariff		if (speed < threshold)
3224162922Sariff			break;
3225162922Sariff	}
3226162922Sariff
3227164614Sariff	if (spd == 0)	/* impossible */
3228162922Sariff		ch->spd = 48000;
3229162922Sariff	else
3230162922Sariff		ch->spd = spd;
3231162922Sariff
3232162922Sariff	return (ch->spd);
3233162922Sariff}
3234162922Sariff
3235162922Sariffstatic void
3236162922Sariffhdac_stream_setup(struct hdac_chan *ch)
3237162922Sariff{
3238162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3239182999Smav	struct hdac_audio_as *as = &ch->devinfo->function.audio.as[ch->as];
3240173817Sariff	struct hdac_widget *w;
3241182999Smav	int i, chn, totalchn, c;
3242162922Sariff	nid_t cad = ch->devinfo->codec->cad;
3243182999Smav	uint16_t fmt, dfmt;
3244162922Sariff
3245183097Smav	HDA_BOOTHVERBOSE(
3246182999Smav		device_printf(ch->pdevinfo->dev,
3247182999Smav		    "PCMDIR_%s: Stream setup fmt=%08x speed=%d\n",
3248182999Smav		    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3249182999Smav		    ch->fmt, ch->spd);
3250182999Smav	);
3251162922Sariff	fmt = 0;
3252162922Sariff	if (ch->fmt & AFMT_S16_LE)
3253162922Sariff		fmt |= ch->bit16 << 4;
3254162922Sariff	else if (ch->fmt & AFMT_S32_LE)
3255162922Sariff		fmt |= ch->bit32 << 4;
3256162922Sariff	else
3257162922Sariff		fmt |= 1 << 4;
3258162922Sariff
3259162922Sariff	for (i = 0; i < HDA_RATE_TAB_LEN; i++) {
3260162922Sariff		if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) {
3261162922Sariff			fmt |= hda_rate_tab[i].base;
3262162922Sariff			fmt |= hda_rate_tab[i].mul;
3263162922Sariff			fmt |= hda_rate_tab[i].div;
3264162922Sariff			break;
3265162922Sariff		}
3266162922Sariff	}
3267162922Sariff
3268182999Smav	if (ch->fmt & (AFMT_STEREO | AFMT_AC3)) {
3269162922Sariff		fmt |= 1;
3270173817Sariff		totalchn = 2;
3271173817Sariff	} else
3272173817Sariff		totalchn = 1;
3273162922Sariff
3274162922Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
3275182999Smav
3276182999Smav	dfmt = HDA_CMD_SET_DIGITAL_CONV_FMT1_DIGEN;
3277182999Smav	if (ch->fmt & AFMT_AC3)
3278182999Smav		dfmt |= HDA_CMD_SET_DIGITAL_CONV_FMT1_NAUDIO;
3279162922Sariff
3280173817Sariff	chn = 0;
3281162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
3282173817Sariff		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3283173817Sariff		if (w == NULL)
3284173817Sariff			continue;
3285182999Smav
3286182999Smav		if (as->hpredir >= 0 && i == as->pincnt)
3287182999Smav			chn = 0;
3288183097Smav		HDA_BOOTHVERBOSE(
3289182999Smav			device_printf(ch->pdevinfo->dev,
3290182999Smav			    "PCMDIR_%s: Stream setup nid=%d: "
3291182999Smav			    "fmt=0x%04x, dfmt=0x%04x\n",
3292162922Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3293182999Smav			    ch->io[i], fmt, dfmt);
3294162922Sariff		);
3295162922Sariff		hdac_command(sc,
3296162922Sariff		    HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
3297182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
3298174025Sariff			hdac_command(sc,
3299182999Smav			    HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], dfmt),
3300174025Sariff			    cad);
3301182999Smav		}
3302182999Smav		/* If HP redirection is enabled, but failed to use same
3303182999Smav		   DAC make last DAC one to duplicate first one. */
3304182999Smav		if (as->hpredir >= 0 && i == as->pincnt) {
3305182999Smav			c = (ch->sid << 4);
3306182999Smav		} else if (chn >= totalchn) {
3307182999Smav			/* This is until OSS will support multichannel.
3308182999Smav			   Should be: c = 0; to disable unused DAC */
3309182999Smav			c = (ch->sid << 4);
3310182999Smav		}else {
3311182999Smav			c = (ch->sid << 4) | chn;
3312182999Smav		}
3313182999Smav		hdac_command(sc,
3314182999Smav		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i], c), cad);
3315173817Sariff		chn +=
3316173817Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap) ?
3317173817Sariff		    2 : 1;
3318162922Sariff	}
3319162922Sariff}
3320162922Sariff
3321162922Sariffstatic int
3322167648Sariffhdac_channel_setfragments(kobj_t obj, void *data,
3323167648Sariff					uint32_t blksz, uint32_t blkcnt)
3324162922Sariff{
3325162922Sariff	struct hdac_chan *ch = data;
3326164614Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3327162922Sariff
3328167648Sariff	blksz &= HDA_BLK_ALIGN;
3329162922Sariff
3330167648Sariff	if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN))
3331167648Sariff		blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN;
3332167648Sariff	if (blksz < HDA_BLK_MIN)
3333167648Sariff		blksz = HDA_BLK_MIN;
3334167648Sariff	if (blkcnt > HDA_BDL_MAX)
3335167648Sariff		blkcnt = HDA_BDL_MAX;
3336167648Sariff	if (blkcnt < HDA_BDL_MIN)
3337167648Sariff		blkcnt = HDA_BDL_MIN;
3338164614Sariff
3339167648Sariff	while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) {
3340167648Sariff		if ((blkcnt >> 1) >= HDA_BDL_MIN)
3341167648Sariff			blkcnt >>= 1;
3342167648Sariff		else if ((blksz >> 1) >= HDA_BLK_MIN)
3343167648Sariff			blksz >>= 1;
3344167648Sariff		else
3345167648Sariff			break;
3346167648Sariff	}
3347167648Sariff
3348164614Sariff	if ((sndbuf_getblksz(ch->b) != blksz ||
3349167648Sariff	    sndbuf_getblkcnt(ch->b) != blkcnt) &&
3350167648Sariff	    sndbuf_resize(ch->b, blkcnt, blksz) != 0)
3351164614Sariff		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
3352167648Sariff		    __func__, blksz, blkcnt);
3353164614Sariff
3354164614Sariff	ch->blksz = sndbuf_getblksz(ch->b);
3355167648Sariff	ch->blkcnt = sndbuf_getblkcnt(ch->b);
3356164614Sariff
3357167648Sariff	return (1);
3358167648Sariff}
3359167648Sariff
3360167648Sariffstatic int
3361167648Sariffhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
3362167648Sariff{
3363167648Sariff	struct hdac_chan *ch = data;
3364167648Sariff
3365182999Smav	hdac_channel_setfragments(obj, data, blksz, ch->pdevinfo->chan_blkcnt);
3366167648Sariff
3367162922Sariff	return (ch->blksz);
3368162922Sariff}
3369162922Sariff
3370162922Sariffstatic void
3371162922Sariffhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
3372162922Sariff{
3373162922Sariff	struct hdac_devinfo *devinfo = ch->devinfo;
3374182999Smav	struct hdac_widget *w;
3375162922Sariff	nid_t cad = devinfo->codec->cad;
3376162922Sariff	int i;
3377162922Sariff
3378162922Sariff	hdac_stream_stop(ch);
3379162922Sariff
3380162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
3381182999Smav		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3382182999Smav		if (w == NULL)
3383182999Smav			continue;
3384182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
3385182999Smav			hdac_command(sc,
3386182999Smav			    HDA_CMD_SET_DIGITAL_CONV_FMT1(cad, ch->io[i], 0),
3387182999Smav			    cad);
3388182999Smav		}
3389162922Sariff		hdac_command(sc,
3390162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
3391162922Sariff		    0), cad);
3392162922Sariff	}
3393162922Sariff}
3394162922Sariff
3395162922Sariffstatic void
3396162922Sariffhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch)
3397162922Sariff{
3398162922Sariff	ch->ptr = 0;
3399162922Sariff	ch->prevptr = 0;
3400162922Sariff	hdac_stream_stop(ch);
3401162922Sariff	hdac_stream_reset(ch);
3402162922Sariff	hdac_bdl_setup(ch);
3403162922Sariff	hdac_stream_setid(ch);
3404162922Sariff	hdac_stream_setup(ch);
3405162922Sariff	hdac_stream_start(ch);
3406162922Sariff}
3407162922Sariff
3408162922Sariffstatic int
3409162922Sariffhdac_channel_trigger(kobj_t obj, void *data, int go)
3410162922Sariff{
3411162922Sariff	struct hdac_chan *ch = data;
3412162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3413162922Sariff
3414170521Sariff	if (!PCMTRIG_COMMON(go))
3415170521Sariff		return (0);
3416170521Sariff
3417162922Sariff	hdac_lock(sc);
3418162922Sariff	switch (go) {
3419162922Sariff	case PCMTRIG_START:
3420162922Sariff		hdac_channel_start(sc, ch);
3421162922Sariff		break;
3422162922Sariff	case PCMTRIG_STOP:
3423162922Sariff	case PCMTRIG_ABORT:
3424162922Sariff		hdac_channel_stop(sc, ch);
3425162922Sariff		break;
3426167610Sariff	default:
3427167610Sariff		break;
3428162922Sariff	}
3429162922Sariff	hdac_unlock(sc);
3430162922Sariff
3431162922Sariff	return (0);
3432162922Sariff}
3433162922Sariff
3434162922Sariffstatic int
3435162922Sariffhdac_channel_getptr(kobj_t obj, void *data)
3436162922Sariff{
3437162922Sariff	struct hdac_chan *ch = data;
3438162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
3439162922Sariff	uint32_t ptr;
3440162922Sariff
3441162922Sariff	hdac_lock(sc);
3442164614Sariff	if (sc->polling != 0)
3443164614Sariff		ptr = ch->ptr;
3444169277Sariff	else if (ch->dmapos != NULL)
3445169277Sariff		ptr = *(ch->dmapos);
3446164614Sariff	else
3447164614Sariff		ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB);
3448162922Sariff	hdac_unlock(sc);
3449162922Sariff
3450164614Sariff	/*
3451164614Sariff	 * Round to available space and force 128 bytes aligment.
3452164614Sariff	 */
3453164614Sariff	ptr %= ch->blksz * ch->blkcnt;
3454167648Sariff	ptr &= HDA_BLK_ALIGN;
3455162922Sariff
3456162922Sariff	return (ptr);
3457162922Sariff}
3458162922Sariff
3459162922Sariffstatic struct pcmchan_caps *
3460162922Sariffhdac_channel_getcaps(kobj_t obj, void *data)
3461162922Sariff{
3462162922Sariff	return (&((struct hdac_chan *)data)->caps);
3463162922Sariff}
3464162922Sariff
3465162922Sariffstatic kobj_method_t hdac_channel_methods[] = {
3466162922Sariff	KOBJMETHOD(channel_init,		hdac_channel_init),
3467162922Sariff	KOBJMETHOD(channel_setformat,		hdac_channel_setformat),
3468162922Sariff	KOBJMETHOD(channel_setspeed,		hdac_channel_setspeed),
3469162922Sariff	KOBJMETHOD(channel_setblocksize,	hdac_channel_setblocksize),
3470167648Sariff	KOBJMETHOD(channel_setfragments,	hdac_channel_setfragments),
3471162922Sariff	KOBJMETHOD(channel_trigger,		hdac_channel_trigger),
3472162922Sariff	KOBJMETHOD(channel_getptr,		hdac_channel_getptr),
3473162922Sariff	KOBJMETHOD(channel_getcaps,		hdac_channel_getcaps),
3474162922Sariff	{ 0, 0 }
3475162922Sariff};
3476162922SariffCHANNEL_DECLARE(hdac_channel);
3477162922Sariff
3478162922Sariffstatic int
3479162922Sariffhdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
3480162922Sariff{
3481182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3482182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3483162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3484162922Sariff	struct hdac_widget *w, *cw;
3485162922Sariff	struct hdac_audio_ctl *ctl;
3486162922Sariff	uint32_t mask, recmask, id;
3487162922Sariff	int i, j, softpcmvol;
3488162922Sariff
3489162922Sariff	hdac_lock(sc);
3490162922Sariff
3491182999Smav	/* Make sure that in case of soft volume it won't stay muted. */
3492182999Smav	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
3493182999Smav		pdevinfo->left[i] = 100;
3494182999Smav		pdevinfo->right[i] = 100;
3495182999Smav	}
3496182999Smav
3497162922Sariff	mask = 0;
3498162922Sariff	recmask = 0;
3499182999Smav	id = hdac_codec_id(devinfo->codec);
3500162922Sariff
3501182999Smav	/* Declate EAPD as ogain control. */
3502182999Smav	if (pdevinfo->play >= 0) {
3503182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3504182999Smav			w = hdac_widget_get(devinfo, i);
3505182999Smav			if (w == NULL || w->enable == 0)
3506182999Smav				continue;
3507182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3508182999Smav			    w->param.eapdbtl == HDAC_INVALID ||
3509182999Smav			    w->bindas != sc->chans[pdevinfo->play].as)
3510182999Smav				continue;
3511182999Smav			mask |= SOUND_MASK_OGAIN;
3512162922Sariff			break;
3513162922Sariff		}
3514162922Sariff	}
3515162922Sariff
3516182999Smav	/* Declare volume controls assigned to this association. */
3517162922Sariff	i = 0;
3518162922Sariff	ctl = NULL;
3519162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3520182999Smav		if (ctl->enable == 0)
3521162922Sariff			continue;
3522182999Smav		if ((pdevinfo->play >= 0 &&
3523182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
3524182999Smav		    (pdevinfo->rec >= 0 &&
3525182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
3526182999Smav		    (ctl->widget->bindas == -2 && pdevinfo->index == 0))
3527182999Smav			mask |= ctl->ossmask;
3528162922Sariff	}
3529162922Sariff
3530182999Smav	/* Declare record sources available to this association. */
3531182999Smav	if (pdevinfo->rec >= 0) {
3532182999Smav		struct hdac_chan *ch = &sc->chans[pdevinfo->rec];
3533182999Smav		for (i = 0; ch->io[i] != -1; i++) {
3534182999Smav			w = hdac_widget_get(devinfo, ch->io[i]);
3535182999Smav			if (w == NULL || w->enable == 0)
3536182999Smav				continue;
3537182999Smav			for (j = 0; j < w->nconns; j++) {
3538182999Smav				if (w->connsenable[j] == 0)
3539162922Sariff					continue;
3540182999Smav				cw = hdac_widget_get(devinfo, w->conns[j]);
3541182999Smav				if (cw == NULL || cw->enable == 0)
3542165992Sariff					continue;
3543182999Smav				if (cw->bindas != sc->chans[pdevinfo->rec].as &&
3544182999Smav				    cw->bindas != -2)
3545165992Sariff					continue;
3546182999Smav				recmask |= cw->ossmask;
3547165992Sariff			}
3548182999Smav		}
3549182999Smav	}
3550182999Smav
3551182999Smav	/* Declare soft PCM and master volume if needed. */
3552182999Smav	if (pdevinfo->play >= 0) {
3553182999Smav		ctl = NULL;
3554182999Smav		if ((mask & SOUND_MASK_PCM) == 0 ||
3555182999Smav		    (devinfo->function.audio.quirks & HDA_QUIRK_SOFTPCMVOL)) {
3556182999Smav			softpcmvol = 1;
3557182999Smav			mask |= SOUND_MASK_PCM;
3558162922Sariff		} else {
3559182999Smav			softpcmvol = 0;
3560182999Smav			i = 0;
3561182999Smav			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3562182999Smav				if (ctl->enable == 0)
3563162922Sariff					continue;
3564182999Smav				if (ctl->widget->bindas != sc->chans[pdevinfo->play].as &&
3565182999Smav				    (ctl->widget->bindas != -2 || pdevinfo->index != 0))
3566162922Sariff					continue;
3567182999Smav				if (!(ctl->ossmask & SOUND_MASK_PCM))
3568182999Smav					continue;
3569182999Smav				if (ctl->step > 0)
3570182999Smav					break;
3571162922Sariff			}
3572162922Sariff		}
3573182999Smav
3574182999Smav		if (softpcmvol == 1 || ctl == NULL) {
3575182999Smav			pcm_setflags(pdevinfo->dev, pcm_getflags(pdevinfo->dev) | SD_F_SOFTPCMVOL);
3576182999Smav			HDA_BOOTVERBOSE(
3577182999Smav				device_printf(pdevinfo->dev,
3578182999Smav				    "%s Soft PCM volume\n",
3579182999Smav				    (softpcmvol == 1) ? "Forcing" : "Enabling");
3580182999Smav			);
3581182999Smav		}
3582182999Smav
3583182999Smav		if ((mask & SOUND_MASK_VOLUME) == 0) {
3584182999Smav			mask |= SOUND_MASK_VOLUME;
3585182999Smav			mix_setparentchild(m, SOUND_MIXER_VOLUME,
3586182999Smav			    SOUND_MASK_PCM);
3587182999Smav			mix_setrealdev(m, SOUND_MIXER_VOLUME,
3588182999Smav			    SOUND_MIXER_NONE);
3589182999Smav			HDA_BOOTVERBOSE(
3590182999Smav				device_printf(pdevinfo->dev,
3591182999Smav				    "Forcing master volume with PCM\n");
3592182999Smav			);
3593182999Smav		}
3594162922Sariff	}
3595162922Sariff
3596169277Sariff	recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3597169277Sariff	mask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3598162922Sariff
3599162922Sariff	mix_setrecdevs(m, recmask);
3600162922Sariff	mix_setdevs(m, mask);
3601162922Sariff
3602162922Sariff	hdac_unlock(sc);
3603162922Sariff
3604162922Sariff	return (0);
3605162922Sariff}
3606162922Sariff
3607162922Sariffstatic int
3608162922Sariffhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
3609162922Sariff					unsigned left, unsigned right)
3610162922Sariff{
3611182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3612182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3613162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3614162922Sariff	struct hdac_widget *w;
3615162922Sariff	struct hdac_audio_ctl *ctl;
3616182999Smav	uint32_t mute;
3617182999Smav	int lvol, rvol;
3618182999Smav	int i, j;
3619162922Sariff
3620162922Sariff	hdac_lock(sc);
3621182999Smav	/* Save new values. */
3622182999Smav	pdevinfo->left[dev] = left;
3623182999Smav	pdevinfo->right[dev] = right;
3624182999Smav
3625182999Smav	/* 'ogain' is the special case implemented with EAPD. */
3626162922Sariff	if (dev == SOUND_MIXER_OGAIN) {
3627163257Sariff		uint32_t orig;
3628182999Smav		w = NULL;
3629182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3630182999Smav			w = hdac_widget_get(devinfo, i);
3631182999Smav			if (w == NULL || w->enable == 0)
3632182999Smav				continue;
3633182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3634182999Smav			    w->param.eapdbtl == HDAC_INVALID)
3635182999Smav				continue;
3636182999Smav			break;
3637162922Sariff		}
3638182999Smav		if (i >= devinfo->endnode) {
3639162922Sariff			hdac_unlock(sc);
3640162922Sariff			return (-1);
3641162922Sariff		}
3642163257Sariff		orig = w->param.eapdbtl;
3643163432Sariff		if (left == 0)
3644162922Sariff			w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3645162922Sariff		else
3646162922Sariff			w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3647163257Sariff		if (orig != w->param.eapdbtl) {
3648163432Sariff			uint32_t val;
3649163432Sariff
3650163432Sariff			val = w->param.eapdbtl;
3651163432Sariff			if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV)
3652163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3653163257Sariff			hdac_command(sc,
3654163257Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad,
3655163432Sariff			    w->nid, val), devinfo->codec->cad);
3656163257Sariff		}
3657162922Sariff		hdac_unlock(sc);
3658162922Sariff		return (left | (left << 8));
3659162922Sariff	}
3660162922Sariff
3661182999Smav	/* Recalculate all controls related to this OSS device. */
3662162922Sariff	i = 0;
3663162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3664182999Smav		if (ctl->enable == 0 ||
3665162922Sariff		    !(ctl->ossmask & (1 << dev)))
3666162922Sariff			continue;
3667182999Smav		if (!((pdevinfo->play >= 0 &&
3668182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
3669182999Smav		    (pdevinfo->rec >= 0 &&
3670182999Smav		    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
3671182999Smav		    ctl->widget->bindas == -2))
3672182999Smav			continue;
3673182999Smav
3674182999Smav		lvol = 100;
3675182999Smav		rvol = 100;
3676182999Smav		for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
3677182999Smav			if (ctl->ossmask & (1 << j)) {
3678182999Smav				lvol = lvol * pdevinfo->left[j] / 100;
3679182999Smav				rvol = rvol * pdevinfo->right[j] / 100;
3680162922Sariff			}
3681162922Sariff		}
3682182999Smav		mute = (left == 0) ? HDA_AMP_MUTE_LEFT : 0;
3683182999Smav		mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT : 0;
3684182999Smav		lvol = (lvol * ctl->step + 50) / 100;
3685182999Smav		rvol = (rvol * ctl->step + 50) / 100;
3686162922Sariff		hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
3687162922Sariff	}
3688162922Sariff	hdac_unlock(sc);
3689162922Sariff
3690162922Sariff	return (left | (right << 8));
3691162922Sariff}
3692162922Sariff
3693182999Smav/*
3694182999Smav * Commutate specified record source.
3695182999Smav */
3696182999Smavstatic uint32_t
3697182999Smavhdac_audio_ctl_recsel_comm(struct hdac_pcm_devinfo *pdevinfo, uint32_t src, nid_t nid, int depth)
3698162922Sariff{
3699182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3700162922Sariff	struct hdac_widget *w, *cw;
3701182999Smav	struct hdac_audio_ctl *ctl;
3702182999Smav	char buf[64];
3703182999Smav	int i, muted;
3704182999Smav	uint32_t res = 0;
3705162922Sariff
3706182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
3707182999Smav		return (0);
3708182999Smav
3709182999Smav	w = hdac_widget_get(devinfo, nid);
3710182999Smav	if (w == NULL || w->enable == 0)
3711182999Smav		return (0);
3712182999Smav
3713182999Smav	for (i = 0; i < w->nconns; i++) {
3714182999Smav		if (w->connsenable[i] == 0)
3715182999Smav			continue;
3716182999Smav		cw = hdac_widget_get(devinfo, w->conns[i]);
3717182999Smav		if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
3718182999Smav			continue;
3719182999Smav		/* Call recursively to trace signal to it's source if needed. */
3720182999Smav		if ((src & cw->ossmask) != 0) {
3721182999Smav			if (cw->ossdev < 0) {
3722182999Smav				res |= hdac_audio_ctl_recsel_comm(pdevinfo, src,
3723182999Smav				    w->conns[i], depth + 1);
3724182999Smav			} else {
3725182999Smav				res |= cw->ossmask;
3726182999Smav			}
3727182999Smav		}
3728182999Smav		/* We have two special cases: mixers and others (selectors). */
3729182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
3730182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
3731182999Smav			    w->nid, HDA_CTL_IN, i, 1);
3732182999Smav			if (ctl == NULL)
3733182999Smav				continue;
3734182999Smav			/* If we have input control on this node mute them
3735182999Smav			 * according to requested sources. */
3736182999Smav			muted = (src & cw->ossmask) ? 0 : 1;
3737182999Smav	    		if (muted != ctl->forcemute) {
3738182999Smav				ctl->forcemute = muted;
3739182999Smav				hdac_audio_ctl_amp_set(ctl,
3740182999Smav				    HDA_AMP_MUTE_DEFAULT,
3741182999Smav				    HDA_AMP_VOL_DEFAULT, HDA_AMP_VOL_DEFAULT);
3742182999Smav			}
3743183097Smav			HDA_BOOTHVERBOSE(
3744182999Smav				device_printf(pdevinfo->dev,
3745182999Smav				    "Recsel (%s): nid %d source %d %s\n",
3746182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(
3747182999Smav				    src, buf, sizeof(buf)),
3748182999Smav				    nid, i, muted?"mute":"unmute");
3749182999Smav			);
3750182999Smav		} else {
3751182999Smav			if (w->nconns == 1)
3752182999Smav				break;
3753182999Smav			if ((src & cw->ossmask) == 0)
3754182999Smav				continue;
3755182999Smav			/* If we found requested source - select it and exit. */
3756182999Smav			hdac_widget_connection_select(w, i);
3757183097Smav			HDA_BOOTHVERBOSE(
3758182999Smav				device_printf(pdevinfo->dev,
3759182999Smav				    "Recsel (%s): nid %d source %d select\n",
3760182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(
3761182999Smav			    	    src, buf, sizeof(buf)),
3762182999Smav				    nid, i);
3763182999Smav			);
3764162922Sariff			break;
3765162922Sariff		}
3766162922Sariff	}
3767182999Smav	return (res);
3768182999Smav}
3769162922Sariff
3770182999Smavstatic uint32_t
3771182999Smavhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
3772182999Smav{
3773182999Smav	struct hdac_pcm_devinfo *pdevinfo = mix_getdevinfo(m);
3774182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
3775182999Smav	struct hdac_widget *w;
3776182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
3777182999Smav	struct hdac_chan *ch;
3778182999Smav	int i;
3779182999Smav	uint32_t ret = 0xffffffff;
3780182999Smav
3781162922Sariff	hdac_lock(sc);
3782162922Sariff
3783182999Smav	/* Commutate requested recsrc for each ADC. */
3784182999Smav	ch = &sc->chans[pdevinfo->rec];
3785182999Smav	for (i = 0; ch->io[i] != -1; i++) {
3786182999Smav		w = hdac_widget_get(devinfo, ch->io[i]);
3787162965Sariff		if (w == NULL || w->enable == 0)
3788162922Sariff			continue;
3789182999Smav		ret &= hdac_audio_ctl_recsel_comm(pdevinfo, src, ch->io[i], 0);
3790162922Sariff	}
3791162922Sariff
3792162922Sariff	hdac_unlock(sc);
3793162922Sariff
3794182999Smav	return ((ret == 0xffffffff)? 0 : ret);
3795162922Sariff}
3796162922Sariff
3797162922Sariffstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
3798162922Sariff	KOBJMETHOD(mixer_init,		hdac_audio_ctl_ossmixer_init),
3799162922Sariff	KOBJMETHOD(mixer_set,		hdac_audio_ctl_ossmixer_set),
3800162922Sariff	KOBJMETHOD(mixer_setrecsrc,	hdac_audio_ctl_ossmixer_setrecsrc),
3801162922Sariff	{ 0, 0 }
3802162922Sariff};
3803162922SariffMIXER_DECLARE(hdac_audio_ctl_ossmixer);
3804162922Sariff
3805171141Sariffstatic void
3806171141Sariffhdac_unsolq_task(void *context, int pending)
3807171141Sariff{
3808171141Sariff	struct hdac_softc *sc;
3809171141Sariff
3810171141Sariff	sc = (struct hdac_softc *)context;
3811171141Sariff
3812171141Sariff	hdac_lock(sc);
3813171141Sariff	hdac_unsolq_flush(sc);
3814171141Sariff	hdac_unlock(sc);
3815171141Sariff}
3816171141Sariff
3817162922Sariff/****************************************************************************
3818162922Sariff * int hdac_attach(device_t)
3819162922Sariff *
3820162922Sariff * Attach the device into the kernel. Interrupts usually won't be enabled
3821162922Sariff * when this function is called. Setup everything that doesn't require
3822162922Sariff * interrupts and defer probing of codecs until interrupts are enabled.
3823162922Sariff ****************************************************************************/
3824162922Sariffstatic int
3825162922Sariffhdac_attach(device_t dev)
3826162922Sariff{
3827162922Sariff	struct hdac_softc *sc;
3828162922Sariff	int result;
3829169277Sariff	int i;
3830169277Sariff	uint16_t vendor;
3831169277Sariff	uint8_t v;
3832162922Sariff
3833184089Smav	device_printf(dev, "HDA Driver Revision: %s\n", HDA_DRV_TEST_REV);
3834182999Smav
3835182999Smav	sc = device_get_softc(dev);
3836163057Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
3837162922Sariff	sc->dev = dev;
3838163257Sariff	sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
3839163257Sariff	sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff;
3840169277Sariff	vendor = pci_get_vendor(dev);
3841162922Sariff
3842165281Sariff	if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) {
3843165281Sariff		/* Screw nx6325 - subdevice/subvendor swapped */
3844165281Sariff		sc->pci_subvendor = HP_NX6325_SUBVENDOR;
3845165281Sariff	}
3846165281Sariff
3847164614Sariff	callout_init(&sc->poll_hda, CALLOUT_MPSAFE);
3848164614Sariff	callout_init(&sc->poll_hdac, CALLOUT_MPSAFE);
3849169277Sariff	callout_init(&sc->poll_jack, CALLOUT_MPSAFE);
3850164614Sariff
3851171141Sariff	TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc);
3852171141Sariff
3853182999Smav	sc->poll_ticks = 1000000;
3854169277Sariff	sc->poll_ival = HDAC_POLL_INTERVAL;
3855169277Sariff	if (resource_int_value(device_get_name(dev),
3856169277Sariff	    device_get_unit(dev), "polling", &i) == 0 && i != 0)
3857164614Sariff		sc->polling = 1;
3858164614Sariff	else
3859164614Sariff		sc->polling = 0;
3860164614Sariff
3861162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
3862162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
3863162922Sariff	    0,					/* boundary */
3864162922Sariff	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
3865162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
3866162922Sariff	    NULL,				/* filtfunc */
3867162922Sariff	    NULL,				/* fistfuncarg */
3868182999Smav	    HDA_BUFSZ_MAX, 			/* maxsize */
3869162922Sariff	    1,					/* nsegments */
3870182999Smav	    HDA_BUFSZ_MAX, 			/* maxsegsz */
3871162922Sariff	    0,					/* flags */
3872162922Sariff	    NULL,				/* lockfunc */
3873162922Sariff	    NULL,				/* lockfuncarg */
3874162922Sariff	    &sc->chan_dmat);			/* dmat */
3875162922Sariff	if (result != 0) {
3876169277Sariff		device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n",
3877162922Sariff		     __func__, result);
3878163057Sariff		snd_mtxfree(sc->lock);
3879162922Sariff		free(sc, M_DEVBUF);
3880162922Sariff		return (ENXIO);
3881162922Sariff	}
3882162922Sariff
3883162922Sariff
3884162922Sariff	sc->hdabus = NULL;
3885162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++)
3886162922Sariff		sc->codecs[i] = NULL;
3887162922Sariff
3888162922Sariff	pci_enable_busmaster(dev);
3889162922Sariff
3890169277Sariff	if (vendor == INTEL_VENDORID) {
3891169277Sariff		/* TCSEL -> TC0 */
3892169277Sariff		v = pci_read_config(dev, 0x44, 1);
3893169277Sariff		pci_write_config(dev, 0x44, v & 0xf8, 1);
3894183097Smav		HDA_BOOTHVERBOSE(
3895169277Sariff			device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v,
3896169277Sariff			    pci_read_config(dev, 0x44, 1));
3897169277Sariff		);
3898169277Sariff	}
3899169277Sariff
3900178155Sariff#ifdef HDAC_MSI_ENABLED
3901171330Sariff	if (resource_int_value(device_get_name(dev),
3902171330Sariff	    device_get_unit(dev), "msi", &i) == 0 && i != 0 &&
3903171330Sariff	    pci_msi_count(dev) == 1)
3904171330Sariff		sc->flags |= HDAC_F_MSI;
3905171330Sariff	else
3906171330Sariff#endif
3907171330Sariff		sc->flags &= ~HDAC_F_MSI;
3908171330Sariff
3909169277Sariff#if defined(__i386__) || defined(__amd64__)
3910171330Sariff	sc->flags |= HDAC_F_DMA_NOCACHE;
3911169277Sariff
3912169277Sariff	if (resource_int_value(device_get_name(dev),
3913169277Sariff	    device_get_unit(dev), "snoop", &i) == 0 && i != 0) {
3914169277Sariff#else
3915171330Sariff	sc->flags &= ~HDAC_F_DMA_NOCACHE;
3916169277Sariff#endif
3917169277Sariff		/*
3918169277Sariff		 * Try to enable PCIe snoop to avoid messing around with
3919169277Sariff		 * uncacheable DMA attribute. Since PCIe snoop register
3920169277Sariff		 * config is pretty much vendor specific, there are no
3921169277Sariff		 * general solutions on how to enable it, forcing us (even
3922169277Sariff		 * Microsoft) to enable uncacheable or write combined DMA
3923169277Sariff		 * by default.
3924169277Sariff		 *
3925169277Sariff		 * http://msdn2.microsoft.com/en-us/library/ms790324.aspx
3926169277Sariff		 */
3927169277Sariff		for (i = 0; i < HDAC_PCIESNOOP_LEN; i++) {
3928169277Sariff			if (hdac_pcie_snoop[i].vendor != vendor)
3929169277Sariff				continue;
3930171330Sariff			sc->flags &= ~HDAC_F_DMA_NOCACHE;
3931169277Sariff			if (hdac_pcie_snoop[i].reg == 0x00)
3932169277Sariff				break;
3933169277Sariff			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
3934169277Sariff			if ((v & hdac_pcie_snoop[i].enable) ==
3935169277Sariff			    hdac_pcie_snoop[i].enable)
3936169277Sariff				break;
3937169277Sariff			v &= hdac_pcie_snoop[i].mask;
3938169277Sariff			v |= hdac_pcie_snoop[i].enable;
3939169277Sariff			pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1);
3940169277Sariff			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
3941169277Sariff			if ((v & hdac_pcie_snoop[i].enable) !=
3942169277Sariff			    hdac_pcie_snoop[i].enable) {
3943169277Sariff				HDA_BOOTVERBOSE(
3944169277Sariff					device_printf(dev,
3945169277Sariff					    "WARNING: Failed to enable PCIe "
3946169277Sariff					    "snoop!\n");
3947169277Sariff				);
3948169277Sariff#if defined(__i386__) || defined(__amd64__)
3949171330Sariff				sc->flags |= HDAC_F_DMA_NOCACHE;
3950169277Sariff#endif
3951169277Sariff			}
3952169277Sariff			break;
3953169277Sariff		}
3954169277Sariff#if defined(__i386__) || defined(__amd64__)
3955169277Sariff	}
3956169277Sariff#endif
3957169277Sariff
3958183097Smav	HDA_BOOTHVERBOSE(
3959169277Sariff		device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n",
3960171330Sariff		    (sc->flags & HDAC_F_DMA_NOCACHE) ?
3961171330Sariff		    "Uncacheable" : "PCIe snoop", vendor);
3962169277Sariff	);
3963169277Sariff
3964162922Sariff	/* Allocate resources */
3965162922Sariff	result = hdac_mem_alloc(sc);
3966162922Sariff	if (result != 0)
3967163057Sariff		goto hdac_attach_fail;
3968162922Sariff	result = hdac_irq_alloc(sc);
3969162922Sariff	if (result != 0)
3970163057Sariff		goto hdac_attach_fail;
3971162922Sariff
3972162922Sariff	/* Get Capabilities */
3973162922Sariff	result = hdac_get_capabilities(sc);
3974162922Sariff	if (result != 0)
3975163057Sariff		goto hdac_attach_fail;
3976162922Sariff
3977162922Sariff	/* Allocate CORB and RIRB dma memory */
3978162922Sariff	result = hdac_dma_alloc(sc, &sc->corb_dma,
3979162922Sariff	    sc->corb_size * sizeof(uint32_t));
3980162922Sariff	if (result != 0)
3981163057Sariff		goto hdac_attach_fail;
3982162922Sariff	result = hdac_dma_alloc(sc, &sc->rirb_dma,
3983162922Sariff	    sc->rirb_size * sizeof(struct hdac_rirb));
3984162922Sariff	if (result != 0)
3985163057Sariff		goto hdac_attach_fail;
3986162922Sariff
3987162922Sariff	/* Quiesce everything */
3988183097Smav	HDA_BOOTHVERBOSE(
3989182999Smav		device_printf(dev, "Reset controller...\n");
3990182999Smav	);
3991182999Smav	hdac_reset(sc, 1);
3992162922Sariff
3993162922Sariff	/* Initialize the CORB and RIRB */
3994162922Sariff	hdac_corb_init(sc);
3995162922Sariff	hdac_rirb_init(sc);
3996162922Sariff
3997162922Sariff	/* Defer remaining of initialization until interrupts are enabled */
3998162922Sariff	sc->intrhook.ich_func = hdac_attach2;
3999162922Sariff	sc->intrhook.ich_arg = (void *)sc;
4000162922Sariff	if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
4001162922Sariff		sc->intrhook.ich_func = NULL;
4002162922Sariff		hdac_attach2((void *)sc);
4003162922Sariff	}
4004162922Sariff
4005163057Sariff	return (0);
4006162922Sariff
4007163057Sariffhdac_attach_fail:
4008162922Sariff	hdac_irq_free(sc);
4009169277Sariff	hdac_dma_free(sc, &sc->rirb_dma);
4010169277Sariff	hdac_dma_free(sc, &sc->corb_dma);
4011162922Sariff	hdac_mem_free(sc);
4012162922Sariff	snd_mtxfree(sc->lock);
4013163057Sariff	free(sc, M_DEVBUF);
4014162922Sariff
4015163057Sariff	return (ENXIO);
4016162922Sariff}
4017162922Sariff
4018162922Sariffstatic void
4019162922Sariffhdac_audio_parse(struct hdac_devinfo *devinfo)
4020162922Sariff{
4021182999Smav	struct hdac_codec *codec = devinfo->codec;
4022182999Smav	struct hdac_softc *sc = codec->sc;
4023162922Sariff	struct hdac_widget *w;
4024162922Sariff	uint32_t res;
4025162922Sariff	int i;
4026162922Sariff	nid_t cad, nid;
4027162922Sariff
4028162922Sariff	cad = devinfo->codec->cad;
4029162922Sariff	nid = devinfo->nid;
4030162922Sariff
4031162922Sariff	res = hdac_command(sc,
4032169277Sariff	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad);
4033169277Sariff	devinfo->function.audio.gpio = res;
4034169277Sariff
4035163057Sariff	HDA_BOOTVERBOSE(
4036183097Smav		device_printf(sc->dev, "GPIO: 0x%08x "
4037183097Smav		    "NumGPIO=%d NumGPO=%d "
4038169277Sariff		    "NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
4039183097Smav		    devinfo->function.audio.gpio,
4040169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
4041169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
4042169277Sariff		    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
4043169277Sariff		    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
4044169277Sariff		    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
4045162922Sariff	);
4046162922Sariff
4047162922Sariff	res = hdac_command(sc,
4048162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS),
4049162922Sariff	    cad);
4050162922Sariff	devinfo->function.audio.supp_stream_formats = res;
4051162922Sariff
4052162922Sariff	res = hdac_command(sc,
4053162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE),
4054162922Sariff	    cad);
4055162922Sariff	devinfo->function.audio.supp_pcm_size_rate = res;
4056162922Sariff
4057162922Sariff	res = hdac_command(sc,
4058162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP),
4059162922Sariff	    cad);
4060162922Sariff	devinfo->function.audio.outamp_cap = res;
4061162922Sariff
4062162922Sariff	res = hdac_command(sc,
4063162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP),
4064162922Sariff	    cad);
4065162922Sariff	devinfo->function.audio.inamp_cap = res;
4066162922Sariff
4067162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4068162922Sariff		w = hdac_widget_get(devinfo, i);
4069162922Sariff		if (w == NULL)
4070162922Sariff			device_printf(sc->dev, "Ghost widget! nid=%d!\n", i);
4071162922Sariff		else {
4072162922Sariff			w->devinfo = devinfo;
4073162922Sariff			w->nid = i;
4074162922Sariff			w->enable = 1;
4075162922Sariff			w->selconn = -1;
4076162922Sariff			w->pflags = 0;
4077182999Smav			w->ossdev = -1;
4078182999Smav			w->bindas = -1;
4079162965Sariff			w->param.eapdbtl = HDAC_INVALID;
4080162922Sariff			hdac_widget_parse(w);
4081162922Sariff		}
4082162922Sariff	}
4083162922Sariff}
4084162922Sariff
4085162922Sariffstatic void
4086162922Sariffhdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
4087162922Sariff{
4088162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4089162922Sariff	struct hdac_audio_ctl *ctls;
4090162922Sariff	struct hdac_widget *w, *cw;
4091162922Sariff	int i, j, cnt, max, ocap, icap;
4092163057Sariff	int mute, offset, step, size;
4093162922Sariff
4094162922Sariff	/* XXX This is redundant */
4095162922Sariff	max = 0;
4096162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4097162922Sariff		w = hdac_widget_get(devinfo, i);
4098162922Sariff		if (w == NULL || w->enable == 0)
4099162922Sariff			continue;
4100162922Sariff		if (w->param.outamp_cap != 0)
4101162922Sariff			max++;
4102162922Sariff		if (w->param.inamp_cap != 0) {
4103162922Sariff			switch (w->type) {
4104162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4105162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4106162922Sariff				for (j = 0; j < w->nconns; j++) {
4107162922Sariff					cw = hdac_widget_get(devinfo,
4108162922Sariff					    w->conns[j]);
4109162922Sariff					if (cw == NULL || cw->enable == 0)
4110162922Sariff						continue;
4111162922Sariff					max++;
4112162922Sariff				}
4113162922Sariff				break;
4114162922Sariff			default:
4115162922Sariff				max++;
4116162922Sariff				break;
4117162922Sariff			}
4118162922Sariff		}
4119162922Sariff	}
4120162922Sariff
4121162922Sariff	devinfo->function.audio.ctlcnt = max;
4122162922Sariff
4123162922Sariff	if (max < 1)
4124162922Sariff		return;
4125162922Sariff
4126162922Sariff	ctls = (struct hdac_audio_ctl *)malloc(
4127162922Sariff	    sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT);
4128162922Sariff
4129162922Sariff	if (ctls == NULL) {
4130162922Sariff		/* Blekh! */
4131162922Sariff		device_printf(sc->dev, "unable to allocate ctls!\n");
4132162922Sariff		devinfo->function.audio.ctlcnt = 0;
4133162922Sariff		return;
4134162922Sariff	}
4135162922Sariff
4136162922Sariff	cnt = 0;
4137162922Sariff	for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) {
4138162922Sariff		if (cnt >= max) {
4139162922Sariff			device_printf(sc->dev, "%s: Ctl overflow!\n",
4140162922Sariff			    __func__);
4141162922Sariff			break;
4142162922Sariff		}
4143162922Sariff		w = hdac_widget_get(devinfo, i);
4144162922Sariff		if (w == NULL || w->enable == 0)
4145162922Sariff			continue;
4146162922Sariff		ocap = w->param.outamp_cap;
4147162922Sariff		icap = w->param.inamp_cap;
4148162922Sariff		if (ocap != 0) {
4149163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap);
4150163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap);
4151163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap);
4152163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap);
4153163057Sariff			/*if (offset > step) {
4154163057Sariff				HDA_BOOTVERBOSE(
4155163057Sariff					device_printf(sc->dev,
4156182999Smav					    "BUGGY outamp: nid=%d "
4157163057Sariff					    "[offset=%d > step=%d]\n",
4158163057Sariff					    w->nid, offset, step);
4159163057Sariff				);
4160163057Sariff				offset = step;
4161163057Sariff			}*/
4162162922Sariff			ctls[cnt].enable = 1;
4163162922Sariff			ctls[cnt].widget = w;
4164163057Sariff			ctls[cnt].mute = mute;
4165163057Sariff			ctls[cnt].step = step;
4166163057Sariff			ctls[cnt].size = size;
4167163057Sariff			ctls[cnt].offset = offset;
4168163057Sariff			ctls[cnt].left = offset;
4169163057Sariff			ctls[cnt].right = offset;
4170182999Smav			if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
4171182999Smav			    w->waspin)
4172182999Smav				ctls[cnt].ndir = HDA_CTL_IN;
4173182999Smav			else
4174182999Smav				ctls[cnt].ndir = HDA_CTL_OUT;
4175162922Sariff			ctls[cnt++].dir = HDA_CTL_OUT;
4176162922Sariff		}
4177162922Sariff
4178162922Sariff		if (icap != 0) {
4179163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap);
4180163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap);
4181163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap);
4182163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap);
4183163057Sariff			/*if (offset > step) {
4184163057Sariff				HDA_BOOTVERBOSE(
4185163057Sariff					device_printf(sc->dev,
4186182999Smav					    "BUGGY inamp: nid=%d "
4187163057Sariff					    "[offset=%d > step=%d]\n",
4188163057Sariff					    w->nid, offset, step);
4189163057Sariff				);
4190163057Sariff				offset = step;
4191163057Sariff			}*/
4192162922Sariff			switch (w->type) {
4193162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4194162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4195162922Sariff				for (j = 0; j < w->nconns; j++) {
4196162922Sariff					if (cnt >= max) {
4197162922Sariff						device_printf(sc->dev,
4198162922Sariff						    "%s: Ctl overflow!\n",
4199162922Sariff						    __func__);
4200162922Sariff						break;
4201162922Sariff					}
4202162922Sariff					cw = hdac_widget_get(devinfo,
4203162922Sariff					    w->conns[j]);
4204162922Sariff					if (cw == NULL || cw->enable == 0)
4205162922Sariff						continue;
4206162922Sariff					ctls[cnt].enable = 1;
4207162922Sariff					ctls[cnt].widget = w;
4208162922Sariff					ctls[cnt].childwidget = cw;
4209162922Sariff					ctls[cnt].index = j;
4210163057Sariff					ctls[cnt].mute = mute;
4211163057Sariff					ctls[cnt].step = step;
4212163057Sariff					ctls[cnt].size = size;
4213163057Sariff					ctls[cnt].offset = offset;
4214163057Sariff					ctls[cnt].left = offset;
4215163057Sariff					ctls[cnt].right = offset;
4216182999Smav	    				ctls[cnt].ndir = HDA_CTL_IN;
4217162922Sariff					ctls[cnt++].dir = HDA_CTL_IN;
4218162922Sariff				}
4219162922Sariff				break;
4220162922Sariff			default:
4221162922Sariff				if (cnt >= max) {
4222162922Sariff					device_printf(sc->dev,
4223162922Sariff					    "%s: Ctl overflow!\n",
4224162922Sariff					    __func__);
4225162922Sariff					break;
4226162922Sariff				}
4227162922Sariff				ctls[cnt].enable = 1;
4228162922Sariff				ctls[cnt].widget = w;
4229163057Sariff				ctls[cnt].mute = mute;
4230163057Sariff				ctls[cnt].step = step;
4231163057Sariff				ctls[cnt].size = size;
4232163057Sariff				ctls[cnt].offset = offset;
4233163057Sariff				ctls[cnt].left = offset;
4234163057Sariff				ctls[cnt].right = offset;
4235182999Smav				if (w->type ==
4236182999Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4237182999Smav					ctls[cnt].ndir = HDA_CTL_OUT;
4238182999Smav				else
4239182999Smav					ctls[cnt].ndir = HDA_CTL_IN;
4240162922Sariff				ctls[cnt++].dir = HDA_CTL_IN;
4241162922Sariff				break;
4242162922Sariff			}
4243162922Sariff		}
4244162922Sariff	}
4245162922Sariff
4246162922Sariff	devinfo->function.audio.ctl = ctls;
4247162922Sariff}
4248162922Sariff
4249182999Smavstatic void
4250182999Smavhdac_audio_as_parse(struct hdac_devinfo *devinfo)
4251182999Smav{
4252182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
4253182999Smav	struct hdac_audio_as *as;
4254182999Smav	struct hdac_widget *w;
4255182999Smav	int i, j, cnt, max, type, dir, assoc, seq, first, hpredir;
4256182999Smav
4257182999Smav	/* XXX This is redundant */
4258182999Smav	max = 0;
4259182999Smav	for (j = 0; j < 16; j++) {
4260182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4261182999Smav			w = hdac_widget_get(devinfo, i);
4262182999Smav			if (w == NULL || w->enable == 0)
4263182999Smav				continue;
4264182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4265182999Smav				continue;
4266182999Smav			if (HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config)
4267182999Smav			    != j)
4268182999Smav				continue;
4269182999Smav			max++;
4270182999Smav			if (j != 15)  /* There could be many 1-pin assocs #15 */
4271182999Smav				break;
4272182999Smav		}
4273182999Smav	}
4274182999Smav
4275182999Smav	devinfo->function.audio.ascnt = max;
4276182999Smav
4277182999Smav	if (max < 1)
4278182999Smav		return;
4279182999Smav
4280182999Smav	as = (struct hdac_audio_as *)malloc(
4281182999Smav	    sizeof(*as) * max, M_HDAC, M_ZERO | M_NOWAIT);
4282182999Smav
4283182999Smav	if (as == NULL) {
4284182999Smav		/* Blekh! */
4285182999Smav		device_printf(sc->dev, "unable to allocate assocs!\n");
4286182999Smav		devinfo->function.audio.ascnt = 0;
4287182999Smav		return;
4288182999Smav	}
4289182999Smav
4290182999Smav	for (i = 0; i < max; i++) {
4291182999Smav		as[i].hpredir = -1;
4292182999Smav		as[i].chan = -1;
4293182999Smav	}
4294182999Smav
4295182999Smav	/* Scan associations skipping as=0. */
4296182999Smav	cnt = 0;
4297182999Smav	for (j = 1; j < 16; j++) {
4298182999Smav		first = 16;
4299182999Smav		hpredir = 0;
4300182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4301182999Smav			w = hdac_widget_get(devinfo, i);
4302182999Smav			if (w == NULL || w->enable == 0)
4303182999Smav				continue;
4304182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4305182999Smav				continue;
4306182999Smav			assoc = HDA_CONFIG_DEFAULTCONF_ASSOCIATION(w->wclass.pin.config);
4307182999Smav			seq = HDA_CONFIG_DEFAULTCONF_SEQUENCE(w->wclass.pin.config);
4308182999Smav			if (assoc != j) {
4309182999Smav				continue;
4310182999Smav			}
4311182999Smav			KASSERT(cnt < max,
4312182999Smav			    ("%s: Associations owerflow (%d of %d)",
4313182999Smav			    __func__, cnt, max));
4314182999Smav			type = w->wclass.pin.config &
4315182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4316182999Smav			/* Get pin direction. */
4317182999Smav			if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT ||
4318182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
4319182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
4320182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT ||
4321182999Smav			    type == HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT)
4322182999Smav				dir = HDA_CTL_OUT;
4323182999Smav			else
4324182999Smav				dir = HDA_CTL_IN;
4325182999Smav			/* If this is a first pin - create new association. */
4326182999Smav			if (as[cnt].pincnt == 0) {
4327182999Smav				as[cnt].enable = 1;
4328182999Smav				as[cnt].index = j;
4329182999Smav				as[cnt].dir = dir;
4330182999Smav			}
4331182999Smav			if (seq < first)
4332182999Smav				first = seq;
4333182999Smav			/* Check association correctness. */
4334182999Smav			if (as[cnt].pins[seq] != 0) {
4335182999Smav				device_printf(sc->dev, "%s: Duplicate pin %d (%d) "
4336182999Smav				    "in association %d! Disabling association.\n",
4337182999Smav				    __func__, seq, w->nid, j);
4338182999Smav				as[cnt].enable = 0;
4339182999Smav			}
4340182999Smav			if (dir != as[cnt].dir) {
4341182999Smav				device_printf(sc->dev, "%s: Pin %d has wrong "
4342182999Smav				    "direction for association %d! Disabling "
4343182999Smav				    "association.\n",
4344182999Smav				    __func__, w->nid, j);
4345182999Smav				as[cnt].enable = 0;
4346182999Smav			}
4347182999Smav			/* Headphones with seq=15 may mean redirection. */
4348182999Smav			if (type == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT &&
4349182999Smav			    seq == 15)
4350182999Smav				hpredir = 1;
4351182999Smav			as[cnt].pins[seq] = w->nid;
4352182999Smav			as[cnt].pincnt++;
4353182999Smav			/* Association 15 is a multiple unassociated pins. */
4354182999Smav			if (j == 15)
4355182999Smav				cnt++;
4356182999Smav		}
4357182999Smav		if (j != 15 && as[cnt].pincnt > 0) {
4358182999Smav			if (hpredir && as[cnt].pincnt > 1)
4359182999Smav				as[cnt].hpredir = first;
4360182999Smav			cnt++;
4361182999Smav		}
4362182999Smav	}
4363182999Smav	HDA_BOOTVERBOSE(
4364182999Smav		device_printf(sc->dev,
4365183097Smav		    "%d associations found:\n", max);
4366182999Smav		for (i = 0; i < max; i++) {
4367182999Smav			device_printf(sc->dev,
4368182999Smav			    "Association %d (%d) %s%s:\n",
4369182999Smav			    i, as[i].index, (as[i].dir == HDA_CTL_IN)?"in":"out",
4370182999Smav			    as[i].enable?"":" (disabled)");
4371182999Smav			for (j = 0; j < 16; j++) {
4372182999Smav				if (as[i].pins[j] == 0)
4373182999Smav					continue;
4374182999Smav				device_printf(sc->dev,
4375183097Smav				    " Pin nid=%d seq=%d\n",
4376182999Smav				    as[i].pins[j], j);
4377182999Smav			}
4378182999Smav		}
4379182999Smav	);
4380182999Smav
4381182999Smav	devinfo->function.audio.as = as;
4382182999Smav}
4383182999Smav
4384162965Sariffstatic const struct {
4385162965Sariff	uint32_t model;
4386162965Sariff	uint32_t id;
4387162965Sariff	uint32_t set, unset;
4388162965Sariff} hdac_quirks[] = {
4389163057Sariff	/*
4390163057Sariff	 * XXX Force stereo quirk. Monoural recording / playback
4391163057Sariff	 *     on few codecs (especially ALC880) seems broken or
4392163057Sariff	 *     perhaps unsupported.
4393163057Sariff	 */
4394163057Sariff	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
4395169277Sariff	    HDA_QUIRK_FORCESTEREO | HDA_QUIRK_IVREF, 0 },
4396162965Sariff	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
4397165039Sariff	    HDA_QUIRK_GPIO0, 0 },
4398178155Sariff	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
4399178155Sariff	    HDA_QUIRK_GPIO0, 0 },
4400162965Sariff	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
4401165039Sariff	    HDA_QUIRK_GPIO0, 0 },
4402165281Sariff	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
4403165281Sariff	    HDA_QUIRK_GPIO0, 0 },
4404167623Sariff	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
4405167623Sariff	    HDA_QUIRK_GPIO0, 0 },
4406169277Sariff	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
4407169277Sariff	    HDA_QUIRK_GPIO0, 0 },
4408163276Sariff	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
4409163276Sariff	    HDA_QUIRK_EAPDINV, 0 },
4410178155Sariff	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
4411163432Sariff	    HDA_QUIRK_EAPDINV, 0 },
4412169277Sariff	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
4413169277Sariff	    HDA_QUIRK_OVREF, 0 },
4414169277Sariff	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
4415169277Sariff	    HDA_QUIRK_OVREF, 0 },
4416169277Sariff	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
4417169277Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },*/
4418165281Sariff	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
4419165281Sariff	    HDA_QUIRK_GPIO1, 0 },
4420164657Sariff	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
4421182999Smav	    HDA_QUIRK_EAPDINV | HDA_QUIRK_SENSEINV, 0 },
4422164657Sariff	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
4423164657Sariff	    HDA_QUIRK_EAPDINV, 0 },
4424173817Sariff	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
4425173817Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0},
4426165039Sariff	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
4427165039Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 },
4428183894Smav	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
4429180532Sdelphij	    HDA_QUIRK_GPIO0, 0 },
4430183894Smav	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
4431178155Sariff	    HDA_QUIRK_GPIO0, 0 },
4432169277Sariff	{ HDA_MATCH_ALL, HDA_CODEC_AD1988,
4433169277Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4434170518Sariff	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
4435170518Sariff	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4436162965Sariff	{ HDA_MATCH_ALL, HDA_CODEC_CXVENICE,
4437182999Smav	    0, HDA_QUIRK_FORCESTEREO }
4438162965Sariff};
4439162965Sariff#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
4440162965Sariff
4441162922Sariffstatic void
4442162922Sariffhdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
4443162922Sariff{
4444162922Sariff	struct hdac_widget *w;
4445162965Sariff	uint32_t id, subvendor;
4446162922Sariff	int i;
4447162922Sariff
4448182999Smav	id = hdac_codec_id(devinfo->codec);
4449163057Sariff	subvendor = devinfo->codec->sc->pci_subvendor;
4450163057Sariff
4451162922Sariff	/*
4452163057Sariff	 * Quirks
4453162922Sariff	 */
4454163057Sariff	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
4455163257Sariff		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) &&
4456163257Sariff		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
4457163057Sariff			continue;
4458163057Sariff		if (hdac_quirks[i].set != 0)
4459163057Sariff			devinfo->function.audio.quirks |=
4460163057Sariff			    hdac_quirks[i].set;
4461163057Sariff		if (hdac_quirks[i].unset != 0)
4462163057Sariff			devinfo->function.audio.quirks &=
4463163057Sariff			    ~(hdac_quirks[i].unset);
4464163057Sariff	}
4465163057Sariff
4466162922Sariff	switch (id) {
4467166965Sariff	case HDA_CODEC_ALC883:
4468166965Sariff		/*
4469166965Sariff		 * nid: 24/25 = External (jack) or Internal (fixed) Mic.
4470166965Sariff		 *              Clear vref cap for jack connectivity.
4471166965Sariff		 */
4472166965Sariff		w = hdac_widget_get(devinfo, 24);
4473166965Sariff		if (w != NULL && w->enable != 0 && w->type ==
4474166965Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4475166965Sariff		    (w->wclass.pin.config &
4476166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4477166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
4478166965Sariff			w->wclass.pin.cap &= ~(
4479166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
4480166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
4481166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
4482166965Sariff		w = hdac_widget_get(devinfo, 25);
4483166965Sariff		if (w != NULL && w->enable != 0 && w->type ==
4484166965Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4485166965Sariff		    (w->wclass.pin.config &
4486166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4487166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
4488166965Sariff			w->wclass.pin.cap &= ~(
4489166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
4490166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
4491166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
4492166965Sariff		/*
4493166965Sariff		 * nid: 26 = Line-in, leave it alone.
4494166965Sariff		 */
4495166965Sariff		break;
4496162922Sariff	case HDA_CODEC_AD1986A:
4497182999Smav		if (subvendor == ASUS_A8X_SUBVENDOR) {
4498178155Sariff			/*
4499178155Sariff			 * This is just plain ridiculous.. There
4500178155Sariff			 * are several A8 series that share the same
4501178155Sariff			 * pci id but works differently (EAPD).
4502178155Sariff			 */
4503178155Sariff			w = hdac_widget_get(devinfo, 26);
4504178155Sariff			if (w != NULL && w->type ==
4505178155Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4506178155Sariff			    (w->wclass.pin.config &
4507178155Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
4508178155Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
4509178155Sariff				devinfo->function.audio.quirks &=
4510178155Sariff				    ~HDA_QUIRK_EAPDINV;
4511169277Sariff		}
4512162922Sariff		break;
4513184230Smav	case HDA_CODEC_AD1981HD:
4514184230Smav		/*
4515184230Smav		 * This codec has very unusual design with several
4516184254Smav		 * points inappropriate for the present parser.
4517184230Smav		 */
4518184230Smav		/* Disable recording from mono playback mix. */
4519184230Smav		w = hdac_widget_get(devinfo, 21);
4520184230Smav		if (w != NULL)
4521184230Smav			w->connsenable[3] = 0;
4522184230Smav		/* Disable rear to front mic mixer, use separately. */
4523184230Smav		w = hdac_widget_get(devinfo, 31);
4524184230Smav		if (w != NULL)
4525184230Smav			w->enable = 0;
4526184230Smav		/* Disable playback mixer, use direct bypass. */
4527184230Smav		w = hdac_widget_get(devinfo, 14);
4528184230Smav		if (w != NULL)
4529184230Smav			w->enable = 0;
4530184230Smav		break;
4531182999Smav	}
4532182999Smav}
4533182999Smav
4534182999Smav/*
4535182999Smav * Trace path from DAC to pin.
4536182999Smav */
4537182999Smavstatic nid_t
4538182999Smavhdac_audio_trace_dac(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
4539182999Smav    int dupseq, int min, int only, int depth)
4540182999Smav{
4541182999Smav	struct hdac_widget *w;
4542182999Smav	int i, im = -1;
4543182999Smav	nid_t m = 0, ret;
4544182999Smav
4545182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
4546182999Smav		return (0);
4547182999Smav	w = hdac_widget_get(devinfo, nid);
4548182999Smav	if (w == NULL || w->enable == 0)
4549182999Smav		return (0);
4550183097Smav	HDA_BOOTHVERBOSE(
4551182999Smav		if (!only) {
4552182999Smav			device_printf(devinfo->codec->sc->dev,
4553182999Smav			    " %*stracing via nid %d\n",
4554182999Smav				depth + 1, "", w->nid);
4555169277Sariff		}
4556182999Smav	);
4557182999Smav	/* Use only unused widgets */
4558182999Smav	if (w->bindas >= 0 && w->bindas != as) {
4559183097Smav		HDA_BOOTHVERBOSE(
4560182999Smav			if (!only) {
4561182999Smav				device_printf(devinfo->codec->sc->dev,
4562182999Smav				    " %*snid %d busy by association %d\n",
4563182999Smav					depth + 1, "", w->nid, w->bindas);
4564182999Smav			}
4565182999Smav		);
4566182999Smav		return (0);
4567182999Smav	}
4568182999Smav	if (dupseq < 0) {
4569182999Smav		if (w->bindseqmask != 0) {
4570183097Smav			HDA_BOOTHVERBOSE(
4571182999Smav				if (!only) {
4572182999Smav					device_printf(devinfo->codec->sc->dev,
4573182999Smav					    " %*snid %d busy by seqmask %x\n",
4574182999Smav						depth + 1, "", w->nid, w->bindseqmask);
4575182999Smav				}
4576182999Smav			);
4577182999Smav			return (0);
4578169277Sariff		}
4579182999Smav	} else {
4580182999Smav		/* If this is headphones - allow duplicate first pin. */
4581182999Smav		if (w->bindseqmask != 0 &&
4582182999Smav		    (w->bindseqmask & (1 << dupseq)) == 0) {
4583183097Smav			HDA_BOOTHVERBOSE(
4584182999Smav				device_printf(devinfo->codec->sc->dev,
4585182999Smav				    " %*snid %d busy by seqmask %x\n",
4586182999Smav					depth + 1, "", w->nid, w->bindseqmask);
4587182999Smav			);
4588182999Smav			return (0);
4589169277Sariff		}
4590182999Smav	}
4591182999Smav
4592182999Smav	switch (w->type) {
4593182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4594182999Smav		/* Do not traverse input. AD1988 has digital monitor
4595182999Smav		for which we are not ready. */
4596169277Sariff		break;
4597182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
4598182999Smav		/* If we are tracing HP take only dac of first pin. */
4599182999Smav		if ((only == 0 || only == w->nid) &&
4600182999Smav		    (w->nid >= min) && (dupseq < 0 || w->nid ==
4601182999Smav		    devinfo->function.audio.as[as].dacs[dupseq]))
4602182999Smav			m = w->nid;
4603178155Sariff		break;
4604182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4605182999Smav		if (depth > 0)
4606169277Sariff			break;
4607182999Smav		/* Fall */
4608182999Smav	default:
4609182999Smav		/* Find reachable DACs with smallest nid respecting constraints. */
4610182999Smav		for (i = 0; i < w->nconns; i++) {
4611182999Smav			if (w->connsenable[i] == 0)
4612162922Sariff				continue;
4613182999Smav			if (w->selconn != -1 && w->selconn != i)
4614162922Sariff				continue;
4615182999Smav			if ((ret = hdac_audio_trace_dac(devinfo, as, seq,
4616182999Smav			    w->conns[i], dupseq, min, only, depth + 1)) != 0) {
4617182999Smav				if (m == 0 || ret < m) {
4618182999Smav					m = ret;
4619182999Smav					im = i;
4620182999Smav				}
4621182999Smav				if (only || dupseq >= 0)
4622182999Smav					break;
4623182999Smav			}
4624162922Sariff		}
4625182999Smav		if (m && only && ((w->nconns > 1 &&
4626182999Smav		    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
4627182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4628182999Smav			w->selconn = im;
4629162922Sariff		break;
4630182999Smav	}
4631182999Smav	if (m && only) {
4632182999Smav		w->bindas = as;
4633182999Smav		w->bindseqmask |= (1 << seq);
4634182999Smav	}
4635183097Smav	HDA_BOOTHVERBOSE(
4636182999Smav		if (!only) {
4637182999Smav			device_printf(devinfo->codec->sc->dev,
4638182999Smav			    " %*snid %d returned %d\n",
4639182999Smav				depth + 1, "", w->nid, m);
4640182999Smav		}
4641182999Smav	);
4642182999Smav	return (m);
4643182999Smav}
4644162922Sariff
4645182999Smav/*
4646182999Smav * Trace path from widget to ADC.
4647182999Smav */
4648182999Smavstatic nid_t
4649182999Smavhdac_audio_trace_adc(struct hdac_devinfo *devinfo, int as, int seq, nid_t nid,
4650182999Smav    int only, int depth)
4651182999Smav{
4652182999Smav	struct hdac_widget *w, *wc;
4653182999Smav	int i, j;
4654182999Smav	nid_t res = 0;
4655182999Smav
4656182999Smav	if (depth > HDA_PARSE_MAXDEPTH)
4657182999Smav		return (0);
4658182999Smav	w = hdac_widget_get(devinfo, nid);
4659182999Smav	if (w == NULL || w->enable == 0)
4660182999Smav		return (0);
4661183097Smav	HDA_BOOTHVERBOSE(
4662182999Smav		device_printf(devinfo->codec->sc->dev,
4663182999Smav		    " %*stracing via nid %d\n",
4664182999Smav			depth + 1, "", w->nid);
4665182999Smav	);
4666182999Smav	/* Use only unused widgets */
4667182999Smav	if (w->bindas >= 0 && w->bindas != as) {
4668183097Smav		HDA_BOOTHVERBOSE(
4669182999Smav			device_printf(devinfo->codec->sc->dev,
4670182999Smav			    " %*snid %d busy by association %d\n",
4671182999Smav				depth + 1, "", w->nid, w->bindas);
4672182999Smav		);
4673182999Smav		return (0);
4674182999Smav	}
4675182999Smav
4676182999Smav	switch (w->type) {
4677182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4678182999Smav		/* If we are tracing HP take only dac of first pin. */
4679182999Smav		if (only == w->nid)
4680182999Smav			res = 1;
4681162922Sariff		break;
4682182999Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4683182999Smav		if (depth > 0)
4684182999Smav			break;
4685182999Smav		/* Fall */
4686182999Smav	default:
4687182999Smav		/* Try to find reachable ADCs with specified nid. */
4688182999Smav		for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4689182999Smav			wc = hdac_widget_get(devinfo, j);
4690182999Smav			if (wc == NULL || wc->enable == 0)
4691182999Smav				continue;
4692182999Smav			for (i = 0; i < wc->nconns; i++) {
4693182999Smav				if (wc->connsenable[i] == 0)
4694182999Smav					continue;
4695182999Smav				if (wc->conns[i] != nid)
4696182999Smav					continue;
4697182999Smav				if (hdac_audio_trace_adc(devinfo, as, seq,
4698182999Smav				    j, only, depth + 1) != 0) {
4699182999Smav					res = 1;
4700182999Smav					if (((wc->nconns > 1 &&
4701182999Smav					    wc->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
4702182999Smav					    wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) &&
4703182999Smav					    wc->selconn == -1)
4704182999Smav						wc->selconn = i;
4705182999Smav				}
4706182999Smav			}
4707169277Sariff		}
4708169277Sariff		break;
4709162922Sariff	}
4710182999Smav	if (res) {
4711182999Smav		w->bindas = as;
4712182999Smav		w->bindseqmask |= (1 << seq);
4713182999Smav	}
4714183097Smav	HDA_BOOTHVERBOSE(
4715182999Smav		device_printf(devinfo->codec->sc->dev,
4716182999Smav		    " %*snid %d returned %d\n",
4717182999Smav			depth + 1, "", w->nid, res);
4718182999Smav	);
4719182999Smav	return (res);
4720162922Sariff}
4721162922Sariff
4722182999Smav/*
4723182999Smav * Erase trace path of the specified association.
4724182999Smav */
4725182999Smavstatic void
4726182999Smavhdac_audio_undo_trace(struct hdac_devinfo *devinfo, int as, int seq)
4727182999Smav{
4728182999Smav	struct hdac_widget *w;
4729182999Smav	int i;
4730182999Smav
4731182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4732182999Smav		w = hdac_widget_get(devinfo, i);
4733182999Smav		if (w == NULL || w->enable == 0)
4734182999Smav			continue;
4735182999Smav		if (w->bindas == as) {
4736182999Smav			if (seq >= 0) {
4737182999Smav				w->bindseqmask &= ~(1 << seq);
4738182999Smav				if (w->bindseqmask == 0) {
4739182999Smav					w->bindas = -1;
4740182999Smav					w->selconn = -1;
4741182999Smav				}
4742182999Smav			} else {
4743182999Smav				w->bindas = -1;
4744182999Smav				w->bindseqmask = 0;
4745182999Smav				w->selconn = -1;
4746182999Smav			}
4747182999Smav		}
4748182999Smav	}
4749182999Smav}
4750182999Smav
4751182999Smav/*
4752182999Smav * Trace association path from DAC to output
4753182999Smav */
4754162922Sariffstatic int
4755182999Smavhdac_audio_trace_as_out(struct hdac_devinfo *devinfo, int as, int seq)
4756162922Sariff{
4757182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
4758182999Smav	int i, hpredir;
4759182999Smav	nid_t min, res;
4760162922Sariff
4761182999Smav	/* Find next pin */
4762182999Smav	for (i = seq; ases[as].pins[i] == 0 && i < 16; i++)
4763182999Smav		;
4764182999Smav	/* Check if there is no any left. If so - we succeded. */
4765182999Smav	if (i == 16)
4766182999Smav		return (1);
4767182999Smav
4768182999Smav	hpredir = (i == 15 && ases[as].fakeredir == 0)?ases[as].hpredir:-1;
4769182999Smav	min = 0;
4770182999Smav	res = 0;
4771182999Smav	do {
4772183097Smav		HDA_BOOTHVERBOSE(
4773182999Smav			device_printf(devinfo->codec->sc->dev,
4774182999Smav			    " Tracing pin %d with min nid %d",
4775182999Smav			    ases[as].pins[i], min);
4776182999Smav			if (hpredir >= 0)
4777183097Smav				printf(" and hpredir %d", hpredir);
4778183097Smav			printf("\n");
4779182999Smav		);
4780182999Smav		/* Trace this pin taking min nid into account. */
4781182999Smav		res = hdac_audio_trace_dac(devinfo, as, i,
4782182999Smav		    ases[as].pins[i], hpredir, min, 0, 0);
4783182999Smav		if (res == 0) {
4784182999Smav			/* If we failed - return to previous and redo it. */
4785182999Smav			HDA_BOOTVERBOSE(
4786182999Smav				device_printf(devinfo->codec->sc->dev,
4787182999Smav				    " Unable to trace pin %d seq %d with min "
4788183097Smav				    "nid %d",
4789183097Smav				    ases[as].pins[i], i, min);
4790183097Smav				if (hpredir >= 0)
4791183097Smav					printf(" and hpredir %d", hpredir);
4792183097Smav				printf("\n");
4793182999Smav			);
4794182999Smav			return (0);
4795162922Sariff		}
4796182999Smav		HDA_BOOTVERBOSE(
4797182999Smav			device_printf(devinfo->codec->sc->dev,
4798183097Smav			    " Pin %d traced to DAC %d",
4799183097Smav			    ases[as].pins[i], res);
4800183097Smav			if (hpredir >= 0)
4801183097Smav				printf(" and hpredir %d", hpredir);
4802183097Smav			if (ases[as].fakeredir)
4803183097Smav				printf(" with fake redirection");
4804183097Smav			printf("\n");
4805182999Smav		);
4806182999Smav		/* Trace again to mark the path */
4807182999Smav		hdac_audio_trace_dac(devinfo, as, i,
4808182999Smav		    ases[as].pins[i], hpredir, min, res, 0);
4809182999Smav		ases[as].dacs[i] = res;
4810182999Smav		/* We succeded, so call next. */
4811182999Smav		if (hdac_audio_trace_as_out(devinfo, as, i + 1))
4812182999Smav			return (1);
4813182999Smav		/* If next failed, we should retry with next min */
4814182999Smav		hdac_audio_undo_trace(devinfo, as, i);
4815182999Smav		ases[as].dacs[i] = 0;
4816182999Smav		min = res + 1;
4817182999Smav	} while (1);
4818162922Sariff}
4819162922Sariff
4820182999Smav/*
4821182999Smav * Trace association path from input to ADC
4822182999Smav */
4823162922Sariffstatic int
4824182999Smavhdac_audio_trace_as_in(struct hdac_devinfo *devinfo, int as)
4825162922Sariff{
4826182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
4827162922Sariff	struct hdac_widget *w;
4828182999Smav	int i, j, k;
4829162922Sariff
4830182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4831182999Smav		w = hdac_widget_get(devinfo, j);
4832182999Smav		if (w == NULL || w->enable == 0)
4833182999Smav			continue;
4834182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
4835182999Smav			continue;
4836182999Smav		if (w->bindas >= 0 && w->bindas != as)
4837182999Smav			continue;
4838182999Smav
4839182999Smav		/* Find next pin */
4840182999Smav		for (i = 0; i < 16; i++) {
4841182999Smav			if (ases[as].pins[i] == 0)
4842182999Smav				continue;
4843182999Smav
4844183097Smav			HDA_BOOTHVERBOSE(
4845182999Smav				device_printf(devinfo->codec->sc->dev,
4846182999Smav				    " Tracing pin %d to ADC %d\n",
4847182999Smav				    ases[as].pins[i], j);
4848182999Smav			);
4849182999Smav			/* Trace this pin taking goal into account. */
4850182999Smav			if (hdac_audio_trace_adc(devinfo, as, i,
4851182999Smav			    ases[as].pins[i], j, 0) == 0) {
4852182999Smav				/* If we failed - return to previous and redo it. */
4853182999Smav				HDA_BOOTVERBOSE(
4854182999Smav					device_printf(devinfo->codec->sc->dev,
4855183097Smav					    " Unable to trace pin %d to ADC %d, undo traces\n",
4856182999Smav					    ases[as].pins[i], j);
4857182999Smav				);
4858182999Smav				hdac_audio_undo_trace(devinfo, as, -1);
4859182999Smav				for (k = 0; k < 16; k++)
4860182999Smav					ases[as].dacs[k] = 0;
4861182999Smav				break;
4862162922Sariff			}
4863182999Smav			HDA_BOOTVERBOSE(
4864182999Smav				device_printf(devinfo->codec->sc->dev,
4865183097Smav				    " Pin %d traced to ADC %d\n",
4866183097Smav				    ases[as].pins[i], j);
4867182999Smav			);
4868182999Smav			ases[as].dacs[i] = j;
4869162922Sariff		}
4870182999Smav		if (i == 16)
4871182999Smav			return (1);
4872162922Sariff	}
4873182999Smav	return (0);
4874162922Sariff}
4875162922Sariff
4876182999Smav/*
4877182999Smav * Trace input monitor path from mixer to output association.
4878182999Smav */
4879183097Smavstatic int
4880182999Smavhdac_audio_trace_to_out(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4881162922Sariff{
4882182999Smav	struct hdac_audio_as *ases = devinfo->function.audio.as;
4883182999Smav	struct hdac_widget *w, *wc;
4884182999Smav	int i, j;
4885182999Smav	nid_t res = 0;
4886162922Sariff
4887162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
4888162922Sariff		return (0);
4889162922Sariff	w = hdac_widget_get(devinfo, nid);
4890162922Sariff	if (w == NULL || w->enable == 0)
4891162922Sariff		return (0);
4892183097Smav	HDA_BOOTHVERBOSE(
4893182999Smav		device_printf(devinfo->codec->sc->dev,
4894182999Smav		    " %*stracing via nid %d\n",
4895182999Smav			depth + 1, "", w->nid);
4896182999Smav	);
4897182999Smav	/* Use only unused widgets */
4898182999Smav	if (depth > 0 && w->bindas != -1) {
4899182999Smav		if (w->bindas < 0 || ases[w->bindas].dir == HDA_CTL_OUT) {
4900183097Smav			HDA_BOOTHVERBOSE(
4901182999Smav				device_printf(devinfo->codec->sc->dev,
4902182999Smav				    " %*snid %d found output association %d\n",
4903182999Smav					depth + 1, "", w->nid, w->bindas);
4904182999Smav			);
4905182999Smav			return (1);
4906182999Smav		} else {
4907183097Smav			HDA_BOOTHVERBOSE(
4908182999Smav				device_printf(devinfo->codec->sc->dev,
4909182999Smav				    " %*snid %d busy by input association %d\n",
4910182999Smav					depth + 1, "", w->nid, w->bindas);
4911182999Smav			);
4912182999Smav			return (0);
4913182999Smav		}
4914182999Smav	}
4915182999Smav
4916162922Sariff	switch (w->type) {
4917162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4918182999Smav		/* Do not traverse input. AD1988 has digital monitor
4919182999Smav		for which we are not ready. */
4920162922Sariff		break;
4921162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4922182999Smav		if (depth > 0)
4923182999Smav			break;
4924182999Smav		/* Fall */
4925182999Smav	default:
4926182999Smav		/* Try to find reachable ADCs with specified nid. */
4927182999Smav		for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4928182999Smav			wc = hdac_widget_get(devinfo, j);
4929182999Smav			if (wc == NULL || wc->enable == 0)
4930182999Smav				continue;
4931182999Smav			for (i = 0; i < wc->nconns; i++) {
4932182999Smav				if (wc->connsenable[i] == 0)
4933182999Smav					continue;
4934182999Smav				if (wc->conns[i] != nid)
4935182999Smav					continue;
4936182999Smav				if (hdac_audio_trace_to_out(devinfo,
4937182999Smav				    j, depth + 1) != 0) {
4938182999Smav					res = 1;
4939182999Smav					if (wc->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4940182999Smav					    wc->selconn == -1)
4941182999Smav						wc->selconn = i;
4942182999Smav				}
4943182999Smav			}
4944162922Sariff		}
4945162922Sariff		break;
4946182999Smav	}
4947182999Smav	if (res)
4948182999Smav		w->bindas = -2;
4949182999Smav
4950183097Smav	HDA_BOOTHVERBOSE(
4951182999Smav		device_printf(devinfo->codec->sc->dev,
4952182999Smav		    " %*snid %d returned %d\n",
4953182999Smav			depth + 1, "", w->nid, res);
4954182999Smav	);
4955182999Smav	return (res);
4956182999Smav}
4957182999Smav
4958182999Smav/*
4959182999Smav * Trace extra associations (beeper, monitor)
4960182999Smav */
4961182999Smavstatic void
4962182999Smavhdac_audio_trace_as_extra(struct hdac_devinfo *devinfo)
4963182999Smav{
4964182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
4965182999Smav	struct hdac_widget *w;
4966182999Smav	int j;
4967182999Smav
4968182999Smav	/* Input monitor */
4969182999Smav	/* Find mixer associated with input, but supplying signal
4970182999Smav	   for output associations. Hope it will be input monitor. */
4971182999Smav	HDA_BOOTVERBOSE(
4972182999Smav		device_printf(devinfo->codec->sc->dev,
4973182999Smav		    "Tracing input monitor\n");
4974182999Smav	);
4975182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
4976182999Smav		w = hdac_widget_get(devinfo, j);
4977182999Smav		if (w == NULL || w->enable == 0)
4978182999Smav			continue;
4979182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
4980182999Smav			continue;
4981182999Smav		if (w->bindas < 0 || as[w->bindas].dir != HDA_CTL_IN)
4982182999Smav			continue;
4983182999Smav		HDA_BOOTVERBOSE(
4984182999Smav			device_printf(devinfo->codec->sc->dev,
4985182999Smav			    " Tracing nid %d to out\n",
4986182999Smav			    j);
4987182999Smav		);
4988182999Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
4989182999Smav			HDA_BOOTVERBOSE(
4990182999Smav				device_printf(devinfo->codec->sc->dev,
4991182999Smav				    " nid %d is input monitor\n",
4992182999Smav					w->nid);
4993182999Smav			);
4994182999Smav			w->pflags |= HDA_ADC_MONITOR;
4995182999Smav			w->ossdev = SOUND_MIXER_IMIX;
4996162922Sariff		}
4997162922Sariff	}
4998182999Smav
4999182999Smav	/* Beeper */
5000182999Smav	HDA_BOOTVERBOSE(
5001182999Smav		device_printf(devinfo->codec->sc->dev,
5002182999Smav		    "Tracing beeper\n");
5003182999Smav	);
5004182999Smav	for (j = devinfo->startnode; j < devinfo->endnode; j++) {
5005182999Smav		w = hdac_widget_get(devinfo, j);
5006182999Smav		if (w == NULL || w->enable == 0)
5007182999Smav			continue;
5008182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET)
5009182999Smav			continue;
5010183097Smav		HDA_BOOTHVERBOSE(
5011182999Smav			device_printf(devinfo->codec->sc->dev,
5012182999Smav			    " Tracing nid %d to out\n",
5013182999Smav			    j);
5014182999Smav		);
5015183097Smav		if (hdac_audio_trace_to_out(devinfo, w->nid, 0)) {
5016183097Smav			HDA_BOOTVERBOSE(
5017183097Smav				device_printf(devinfo->codec->sc->dev,
5018183097Smav				    " nid %d traced to out\n",
5019183097Smav				    j);
5020183097Smav			);
5021183097Smav		}
5022182999Smav		w->bindas = -2;
5023182999Smav	}
5024162922Sariff}
5025162922Sariff
5026182999Smav/*
5027182999Smav * Bind assotiations to PCM channels
5028182999Smav */
5029182999Smavstatic void
5030182999Smavhdac_audio_bind_as(struct hdac_devinfo *devinfo)
5031162922Sariff{
5032182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
5033182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5034182999Smav	int j, cnt = 0, free;
5035162922Sariff
5036182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5037182999Smav		if (as[j].enable)
5038182999Smav			cnt++;
5039182999Smav	}
5040182999Smav	if (sc->num_chans == 0) {
5041182999Smav		sc->chans = (struct hdac_chan *)malloc(
5042182999Smav		    sizeof(struct hdac_chan) * cnt,
5043182999Smav		    M_HDAC, M_ZERO | M_NOWAIT);
5044182999Smav		if (sc->chans == NULL) {
5045182999Smav			device_printf(devinfo->codec->sc->dev,
5046182999Smav			    "Channels memory allocation failed!\n");
5047182999Smav			return;
5048182999Smav		}
5049182999Smav	} else {
5050182999Smav		sc->chans = (struct hdac_chan *)realloc(sc->chans,
5051183810Smav		    sizeof(struct hdac_chan) * (sc->num_chans + cnt),
5052182999Smav		    M_HDAC, M_ZERO | M_NOWAIT);
5053182999Smav		if (sc->chans == NULL) {
5054182999Smav			sc->num_chans = 0;
5055182999Smav			device_printf(devinfo->codec->sc->dev,
5056182999Smav			    "Channels memory allocation failed!\n");
5057182999Smav			return;
5058182999Smav		}
5059182999Smav	}
5060182999Smav	free = sc->num_chans;
5061182999Smav	sc->num_chans += cnt;
5062162922Sariff
5063182999Smav	for (j = free; j < free + cnt; j++) {
5064182999Smav		devinfo->codec->sc->chans[j].devinfo = devinfo;
5065182999Smav		devinfo->codec->sc->chans[j].as = -1;
5066182999Smav	}
5067162922Sariff
5068182999Smav	/* Assign associations in order of their numbers, */
5069182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5070182999Smav		if (as[j].enable == 0)
5071182999Smav			continue;
5072182999Smav
5073182999Smav		as[j].chan = free;
5074182999Smav		devinfo->codec->sc->chans[free].as = j;
5075182999Smav		if (as[j].dir == HDA_CTL_IN) {
5076182999Smav			devinfo->codec->sc->chans[free].dir = PCMDIR_REC;
5077182999Smav			devinfo->function.audio.reccnt++;
5078182999Smav		} else {
5079182999Smav			devinfo->codec->sc->chans[free].dir = PCMDIR_PLAY;
5080182999Smav			devinfo->function.audio.playcnt++;
5081182999Smav		}
5082182999Smav		hdac_pcmchannel_setup(&devinfo->codec->sc->chans[free]);
5083182999Smav		free++;
5084182999Smav	}
5085182999Smav}
5086162922Sariff
5087182999Smavstatic void
5088182999Smavhdac_audio_disable_nonaudio(struct hdac_devinfo *devinfo)
5089182999Smav{
5090182999Smav	struct hdac_widget *w;
5091182999Smav	int i;
5092182999Smav
5093182999Smav	/* Disable power and volume widgets. */
5094182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5095182999Smav		w = hdac_widget_get(devinfo, i);
5096182999Smav		if (w == NULL || w->enable == 0)
5097182999Smav			continue;
5098182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET ||
5099182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET) {
5100182999Smav			w->enable = 0;
5101183097Smav			HDA_BOOTHVERBOSE(
5102182999Smav				device_printf(devinfo->codec->sc->dev,
5103182999Smav				    " Disabling nid %d due to it's"
5104182999Smav				    " non-audio type.\n",
5105182999Smav				    w->nid);
5106182999Smav			);
5107162922Sariff		}
5108182999Smav	}
5109182999Smav}
5110182999Smav
5111182999Smavstatic void
5112182999Smavhdac_audio_disable_useless(struct hdac_devinfo *devinfo)
5113182999Smav{
5114182999Smav	struct hdac_widget *w, *cw;
5115182999Smav	struct hdac_audio_ctl *ctl;
5116182999Smav	int done, found, i, j, k;
5117182999Smav
5118182999Smav	/* Disable useless pins. */
5119182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5120182999Smav		w = hdac_widget_get(devinfo, i);
5121182999Smav		if (w == NULL || w->enable == 0)
5122182999Smav			continue;
5123182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5124182999Smav		    (w->wclass.pin.config &
5125182999Smav		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
5126182999Smav		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE) {
5127182999Smav			w->enable = 0;
5128183097Smav			HDA_BOOTHVERBOSE(
5129182999Smav				device_printf(devinfo->codec->sc->dev,
5130182999Smav				    " Disabling pin nid %d due"
5131182999Smav				    " to None connectivity.\n",
5132182999Smav				    w->nid);
5133182999Smav			);
5134182999Smav		}
5135182999Smav	}
5136182999Smav	do {
5137182999Smav		done = 1;
5138182999Smav		/* Disable and mute controls for disabled widgets. */
5139162922Sariff		i = 0;
5140162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5141182999Smav			if (ctl->enable == 0)
5142162922Sariff				continue;
5143182999Smav			if (ctl->widget->enable == 0 ||
5144182999Smav			    (ctl->childwidget != NULL &&
5145182999Smav			    ctl->childwidget->enable == 0)) {
5146182999Smav				ctl->forcemute = 1;
5147182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5148182999Smav				ctl->left = 0;
5149182999Smav				ctl->right = 0;
5150182999Smav				ctl->enable = 0;
5151182999Smav				if (ctl->ndir == HDA_CTL_IN)
5152182999Smav					ctl->widget->connsenable[ctl->index] = 0;
5153182999Smav				done = 0;
5154183097Smav				HDA_BOOTHVERBOSE(
5155182999Smav					device_printf(devinfo->codec->sc->dev,
5156182999Smav					    " Disabling ctl %d nid %d cnid %d due"
5157182999Smav					    " to disabled widget.\n", i,
5158182999Smav					    ctl->widget->nid,
5159182999Smav					    (ctl->childwidget != NULL)?
5160182999Smav					    ctl->childwidget->nid:-1);
5161182999Smav				);
5162182999Smav			}
5163182999Smav		}
5164182999Smav		/* Disable useless widgets. */
5165182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5166182999Smav			w = hdac_widget_get(devinfo, i);
5167182999Smav			if (w == NULL || w->enable == 0)
5168182999Smav				continue;
5169182999Smav			/* Disable inputs with disabled child widgets. */
5170182999Smav			for (j = 0; j < w->nconns; j++) {
5171182999Smav				if (w->connsenable[j]) {
5172182999Smav					cw = hdac_widget_get(devinfo, w->conns[j]);
5173182999Smav					if (cw == NULL || cw->enable == 0) {
5174182999Smav						w->connsenable[j] = 0;
5175183097Smav						HDA_BOOTHVERBOSE(
5176182999Smav							device_printf(devinfo->codec->sc->dev,
5177182999Smav							    " Disabling nid %d connection %d due"
5178182999Smav							    " to disabled child widget.\n",
5179182999Smav							    i, j);
5180182999Smav						);
5181163057Sariff					}
5182163057Sariff				}
5183162922Sariff			}
5184182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5185182999Smav			    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5186162922Sariff				continue;
5187182999Smav			/* Disable mixers and selectors without inputs. */
5188182999Smav			found = 0;
5189182999Smav			for (j = 0; j < w->nconns; j++) {
5190182999Smav				if (w->connsenable[j]) {
5191182999Smav					found = 1;
5192162922Sariff					break;
5193162922Sariff				}
5194182999Smav			}
5195182999Smav			if (found == 0) {
5196182999Smav				w->enable = 0;
5197182999Smav				done = 0;
5198183097Smav				HDA_BOOTHVERBOSE(
5199182999Smav					device_printf(devinfo->codec->sc->dev,
5200182999Smav					    " Disabling nid %d due to all it's"
5201182999Smav					    " inputs disabled.\n", w->nid);
5202182999Smav				);
5203182999Smav			}
5204182999Smav			/* Disable nodes without consumers. */
5205182999Smav			if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
5206182999Smav			    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5207182999Smav				continue;
5208182999Smav			found = 0;
5209182999Smav			for (k = devinfo->startnode; k < devinfo->endnode; k++) {
5210182999Smav				cw = hdac_widget_get(devinfo, k);
5211182999Smav				if (cw == NULL || cw->enable == 0)
5212182999Smav					continue;
5213182999Smav				for (j = 0; j < cw->nconns; j++) {
5214182999Smav					if (cw->connsenable[j] && cw->conns[j] == i) {
5215182999Smav						found = 1;
5216182999Smav						break;
5217182999Smav					}
5218162922Sariff				}
5219162922Sariff			}
5220182999Smav			if (found == 0) {
5221182999Smav				w->enable = 0;
5222182999Smav				done = 0;
5223183097Smav				HDA_BOOTHVERBOSE(
5224182999Smav					device_printf(devinfo->codec->sc->dev,
5225182999Smav					    " Disabling nid %d due to all it's"
5226182999Smav					    " consumers disabled.\n", w->nid);
5227182999Smav				);
5228182999Smav			}
5229162922Sariff		}
5230182999Smav	} while (done == 0);
5231182999Smav
5232182999Smav}
5233182999Smav
5234182999Smavstatic void
5235182999Smavhdac_audio_disable_unas(struct hdac_devinfo *devinfo)
5236182999Smav{
5237182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5238182999Smav	struct hdac_widget *w, *cw;
5239182999Smav	struct hdac_audio_ctl *ctl;
5240182999Smav	int i, j, k;
5241182999Smav
5242182999Smav	/* Disable unassosiated widgets. */
5243182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5244182999Smav		w = hdac_widget_get(devinfo, i);
5245182999Smav		if (w == NULL || w->enable == 0)
5246182999Smav			continue;
5247182999Smav		if (w->bindas == -1) {
5248182999Smav			w->enable = 0;
5249183097Smav			HDA_BOOTHVERBOSE(
5250182999Smav				device_printf(devinfo->codec->sc->dev,
5251182999Smav				    " Disabling unassociated nid %d.\n",
5252182999Smav				    w->nid);
5253182999Smav			);
5254182999Smav		}
5255182999Smav	}
5256182999Smav	/* Disable input connections on input pin and
5257182999Smav	 * output on output. */
5258182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5259182999Smav		w = hdac_widget_get(devinfo, i);
5260182999Smav		if (w == NULL || w->enable == 0)
5261182999Smav			continue;
5262182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5263182999Smav			continue;
5264182999Smav		if (w->bindas < 0)
5265182999Smav			continue;
5266182999Smav		if (as[w->bindas].dir == HDA_CTL_IN) {
5267182999Smav			for (j = 0; j < w->nconns; j++) {
5268182999Smav				if (w->connsenable[j] == 0)
5269182999Smav					continue;
5270182999Smav				w->connsenable[j] = 0;
5271183097Smav				HDA_BOOTHVERBOSE(
5272182999Smav					device_printf(devinfo->codec->sc->dev,
5273182999Smav					    " Disabling connection to input pin "
5274182999Smav					    "nid %d conn %d.\n",
5275182999Smav					    i, j);
5276182999Smav				);
5277162922Sariff			}
5278182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5279182999Smav			    HDA_CTL_IN, -1, 1);
5280182999Smav			if (ctl && ctl->enable) {
5281182999Smav				ctl->forcemute = 1;
5282182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5283182999Smav				ctl->left = 0;
5284182999Smav				ctl->right = 0;
5285182999Smav				ctl->enable = 0;
5286182999Smav			}
5287182999Smav		} else {
5288182999Smav			ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5289182999Smav			    HDA_CTL_OUT, -1, 1);
5290182999Smav			if (ctl && ctl->enable) {
5291182999Smav				ctl->forcemute = 1;
5292182999Smav				ctl->muted = HDA_AMP_MUTE_ALL;
5293182999Smav				ctl->left = 0;
5294182999Smav				ctl->right = 0;
5295182999Smav				ctl->enable = 0;
5296182999Smav			}
5297182999Smav			for (k = devinfo->startnode; k < devinfo->endnode; k++) {
5298182999Smav				cw = hdac_widget_get(devinfo, k);
5299182999Smav				if (cw == NULL || cw->enable == 0)
5300182999Smav					continue;
5301182999Smav				for (j = 0; j < cw->nconns; j++) {
5302182999Smav					if (cw->connsenable[j] && cw->conns[j] == i) {
5303182999Smav						cw->connsenable[j] = 0;
5304183097Smav						HDA_BOOTHVERBOSE(
5305182999Smav							device_printf(devinfo->codec->sc->dev,
5306182999Smav							    " Disabling connection from output pin "
5307182999Smav							    "nid %d conn %d cnid %d.\n",
5308182999Smav							    k, j, i);
5309182999Smav						);
5310182999Smav						if (cw->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5311182999Smav						    cw->nconns > 1)
5312182999Smav							continue;
5313182999Smav						ctl = hdac_audio_ctl_amp_get(devinfo, k,
5314182999Smav		    				    HDA_CTL_IN, j, 1);
5315182999Smav						if (ctl && ctl->enable) {
5316182999Smav							ctl->forcemute = 1;
5317182999Smav							ctl->muted = HDA_AMP_MUTE_ALL;
5318182999Smav							ctl->left = 0;
5319182999Smav							ctl->right = 0;
5320182999Smav							ctl->enable = 0;
5321182999Smav						}
5322182999Smav					}
5323182999Smav				}
5324182999Smav			}
5325162922Sariff		}
5326162922Sariff	}
5327162922Sariff}
5328162922Sariff
5329182999Smavstatic void
5330182999Smavhdac_audio_disable_notselected(struct hdac_devinfo *devinfo)
5331162922Sariff{
5332182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5333182999Smav	struct hdac_widget *w;
5334182999Smav	int i, j;
5335182999Smav
5336182999Smav	/* On playback path we can safely disable all unseleted inputs. */
5337182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5338182999Smav		w = hdac_widget_get(devinfo, i);
5339182999Smav		if (w == NULL || w->enable == 0)
5340182999Smav			continue;
5341182999Smav		if (w->nconns <= 1)
5342182999Smav			continue;
5343182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5344182999Smav			continue;
5345182999Smav		if (w->bindas < 0 || as[w->bindas].dir == HDA_CTL_IN)
5346182999Smav			continue;
5347182999Smav		for (j = 0; j < w->nconns; j++) {
5348182999Smav			if (w->connsenable[j] == 0)
5349182999Smav				continue;
5350182999Smav			if (w->selconn < 0 || w->selconn == j)
5351182999Smav				continue;
5352182999Smav			w->connsenable[j] = 0;
5353183097Smav			HDA_BOOTHVERBOSE(
5354182999Smav				device_printf(devinfo->codec->sc->dev,
5355182999Smav				    " Disabling unselected connection "
5356182999Smav				    "nid %d conn %d.\n",
5357182999Smav				    i, j);
5358182999Smav			);
5359182999Smav		}
5360182999Smav	}
5361182999Smav}
5362182999Smav
5363182999Smavstatic void
5364182999Smavhdac_audio_disable_crossas(struct hdac_devinfo *devinfo)
5365182999Smav{
5366162922Sariff	struct hdac_widget *w, *cw;
5367162922Sariff	struct hdac_audio_ctl *ctl;
5368182999Smav	int i, j;
5369162922Sariff
5370182999Smav	/* Disable crossassociatement connections. */
5371182999Smav	/* ... using selectors */
5372182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5373182999Smav		w = hdac_widget_get(devinfo, i);
5374182999Smav		if (w == NULL || w->enable == 0)
5375182999Smav			continue;
5376182999Smav		if (w->nconns <= 1)
5377182999Smav			continue;
5378182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5379182999Smav			continue;
5380182999Smav		if (w->bindas == -2)
5381182999Smav			continue;
5382182999Smav		for (j = 0; j < w->nconns; j++) {
5383182999Smav			if (w->connsenable[j] == 0)
5384182999Smav				continue;
5385182999Smav			cw = hdac_widget_get(devinfo, w->conns[j]);
5386182999Smav			if (cw == NULL || w->enable == 0)
5387182999Smav				continue;
5388182999Smav			if (w->bindas == cw->bindas || cw->bindas == -2)
5389182999Smav				continue;
5390182999Smav			w->connsenable[j] = 0;
5391183097Smav			HDA_BOOTHVERBOSE(
5392182999Smav				device_printf(devinfo->codec->sc->dev,
5393182999Smav				    " Disabling crossassociatement connection "
5394182999Smav				    "nid %d conn %d cnid %d.\n",
5395182999Smav				    i, j, cw->nid);
5396182999Smav			);
5397182999Smav		}
5398182999Smav	}
5399182999Smav	/* ... using controls */
5400182999Smav	i = 0;
5401182999Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5402182999Smav		if (ctl->enable == 0 || ctl->childwidget == NULL)
5403182999Smav			continue;
5404182999Smav		if (ctl->widget->bindas == -2 ||
5405182999Smav		    ctl->childwidget->bindas == -2)
5406182999Smav			continue;
5407182999Smav		if (ctl->widget->bindas != ctl->childwidget->bindas) {
5408182999Smav			ctl->forcemute = 1;
5409182999Smav			ctl->muted = HDA_AMP_MUTE_ALL;
5410182999Smav			ctl->left = 0;
5411182999Smav			ctl->right = 0;
5412182999Smav			ctl->enable = 0;
5413182999Smav			if (ctl->ndir == HDA_CTL_IN)
5414182999Smav				ctl->widget->connsenable[ctl->index] = 0;
5415183097Smav			HDA_BOOTHVERBOSE(
5416182999Smav				device_printf(devinfo->codec->sc->dev,
5417182999Smav				    " Disabling crossassociatement connection "
5418182999Smav				    "ctl %d nid %d cnid %d.\n", i,
5419182999Smav				    ctl->widget->nid,
5420182999Smav				    ctl->childwidget->nid);
5421182999Smav			);
5422182999Smav		}
5423182999Smav	}
5424182999Smav
5425182999Smav}
5426182999Smav
5427182999Smav#define HDA_CTL_GIVE(ctl)	((ctl)->step?1:0)
5428182999Smav
5429182999Smav/*
5430182999Smav * Find controls to control amplification for source.
5431182999Smav */
5432182999Smavstatic int
5433182999Smavhdac_audio_ctl_source_amp(struct hdac_devinfo *devinfo, nid_t nid, int index,
5434182999Smav    int ossdev, int ctlable, int depth, int need)
5435182999Smav{
5436182999Smav	struct hdac_widget *w, *wc;
5437182999Smav	struct hdac_audio_ctl *ctl;
5438182999Smav	int i, j, conns = 0, rneed;
5439182999Smav
5440162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
5441182999Smav		return (need);
5442162922Sariff
5443162922Sariff	w = hdac_widget_get(devinfo, nid);
5444162922Sariff	if (w == NULL || w->enable == 0)
5445182999Smav		return (need);
5446182999Smav
5447182999Smav	/* Count number of active inputs. */
5448182999Smav	if (depth > 0) {
5449182999Smav		for (j = 0; j < w->nconns; j++) {
5450182999Smav			if (w->connsenable[j])
5451182999Smav				conns++;
5452162922Sariff		}
5453162922Sariff	}
5454182999Smav
5455182999Smav	/* If this is not a first step - use input mixer.
5456182999Smav	   Pins have common input ctl so care must be taken. */
5457182999Smav	if (depth > 0 && ctlable && (conns == 1 ||
5458182999Smav	    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)) {
5459182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_IN,
5460182999Smav		    index, 1);
5461182999Smav		if (ctl) {
5462182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5463182999Smav				ctl->ossmask |= (1 << ossdev);
5464182999Smav			else
5465182999Smav				ctl->possmask |= (1 << ossdev);
5466182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5467182999Smav		}
5468182999Smav	}
5469182999Smav
5470182999Smav	/* If widget has own ossdev - not traverse it.
5471182999Smav	   It will be traversed on it's own. */
5472182999Smav	if (w->ossdev >= 0 && depth > 0)
5473182999Smav		return (need);
5474182999Smav
5475182999Smav	/* We must not traverse pin */
5476182999Smav	if ((w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
5477182999Smav	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
5478182999Smav	    depth > 0)
5479182999Smav		return (need);
5480182999Smav
5481182999Smav	/* record that this widget exports such signal, */
5482182999Smav	w->ossmask |= (1 << ossdev);
5483182999Smav
5484182999Smav	/* If signals mixed, we can't assign controls farther.
5485182999Smav	 * Ignore this on depth zero. Caller must knows why.
5486182999Smav	 * Ignore this for static selectors if this input selected.
5487182999Smav	 */
5488182999Smav	if (conns > 1)
5489182999Smav		ctlable = 0;
5490182999Smav
5491182999Smav	if (ctlable) {
5492182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid, HDA_CTL_OUT, -1, 1);
5493182999Smav		if (ctl) {
5494182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5495182999Smav				ctl->ossmask |= (1 << ossdev);
5496182999Smav			else
5497182999Smav				ctl->possmask |= (1 << ossdev);
5498182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5499182999Smav		}
5500182999Smav	}
5501182999Smav
5502182999Smav	rneed = 0;
5503182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5504182999Smav		wc = hdac_widget_get(devinfo, i);
5505182999Smav		if (wc == NULL || wc->enable == 0)
5506162922Sariff			continue;
5507182999Smav		for (j = 0; j < wc->nconns; j++) {
5508182999Smav			if (wc->connsenable[j] && wc->conns[j] == nid) {
5509182999Smav				rneed |= hdac_audio_ctl_source_amp(devinfo,
5510182999Smav				    wc->nid, j, ossdev, ctlable, depth + 1, need);
5511182999Smav			}
5512162922Sariff		}
5513162922Sariff	}
5514182999Smav	rneed &= need;
5515182999Smav
5516182999Smav	return (rneed);
5517162922Sariff}
5518162922Sariff
5519182999Smav/*
5520182999Smav * Find controls to control amplification for destination.
5521182999Smav */
5522182999Smavstatic void
5523182999Smavhdac_audio_ctl_dest_amp(struct hdac_devinfo *devinfo, nid_t nid,
5524182999Smav    int ossdev, int depth, int need)
5525162922Sariff{
5526182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5527182999Smav	struct hdac_widget *w, *wc;
5528182999Smav	struct hdac_audio_ctl *ctl;
5529182999Smav	int i, j, consumers;
5530182999Smav
5531162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
5532182999Smav		return;
5533162922Sariff
5534162922Sariff	w = hdac_widget_get(devinfo, nid);
5535162922Sariff	if (w == NULL || w->enable == 0)
5536182999Smav		return;
5537182999Smav
5538182999Smav	if (depth > 0) {
5539182999Smav		/* If this node produce output for several consumers,
5540182999Smav		   we can't touch it. */
5541182999Smav		consumers = 0;
5542182999Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5543182999Smav			wc = hdac_widget_get(devinfo, i);
5544182999Smav			if (wc == NULL || wc->enable == 0)
5545182999Smav				continue;
5546182999Smav			for (j = 0; j < wc->nconns; j++) {
5547182999Smav				if (wc->connsenable[j] && wc->conns[j] == nid)
5548182999Smav					consumers++;
5549182999Smav			}
5550182999Smav		}
5551182999Smav		/* The only exception is if real HP redirection is configured
5552182999Smav		   and this is a duplication point.
5553182999Smav		   XXX: Actually exception is not completely correct.
5554182999Smav		   XXX: Duplication point check is not perfect. */
5555182999Smav		if ((consumers == 2 && (w->bindas < 0 ||
5556182999Smav		    as[w->bindas].hpredir < 0 || as[w->bindas].fakeredir ||
5557182999Smav		    (w->bindseqmask & (1 << 15)) == 0)) ||
5558182999Smav		    consumers > 2)
5559182999Smav			return;
5560182999Smav
5561182999Smav		/* Else use it's output mixer. */
5562182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5563182999Smav		    HDA_CTL_OUT, -1, 1);
5564182999Smav		if (ctl) {
5565182999Smav			if (HDA_CTL_GIVE(ctl) & need)
5566182999Smav				ctl->ossmask |= (1 << ossdev);
5567182999Smav			else
5568182999Smav				ctl->possmask |= (1 << ossdev);
5569182999Smav			need &= ~HDA_CTL_GIVE(ctl);
5570182999Smav		}
5571182999Smav	}
5572182999Smav
5573182999Smav	/* We must not traverse pin */
5574182999Smav	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5575182999Smav	    depth > 0)
5576182999Smav		return;
5577182999Smav
5578162922Sariff	for (i = 0; i < w->nconns; i++) {
5579182999Smav		int tneed = need;
5580182999Smav		if (w->connsenable[i] == 0)
5581162922Sariff			continue;
5582182999Smav		ctl = hdac_audio_ctl_amp_get(devinfo, w->nid,
5583182999Smav		    HDA_CTL_IN, i, 1);
5584182999Smav		if (ctl) {
5585182999Smav			if (HDA_CTL_GIVE(ctl) & tneed)
5586182999Smav				ctl->ossmask |= (1 << ossdev);
5587182999Smav			else
5588182999Smav				ctl->possmask |= (1 << ossdev);
5589182999Smav			tneed &= ~HDA_CTL_GIVE(ctl);
5590162922Sariff		}
5591182999Smav		hdac_audio_ctl_dest_amp(devinfo, w->conns[i], ossdev,
5592182999Smav		    depth + 1, tneed);
5593162922Sariff	}
5594162922Sariff}
5595162922Sariff
5596182999Smav/*
5597182999Smav * Assign OSS names to sound sources
5598182999Smav */
5599182999Smavstatic void
5600182999Smavhdac_audio_assign_names(struct hdac_devinfo *devinfo)
5601162922Sariff{
5602182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5603182999Smav	struct hdac_widget *w;
5604182999Smav	int i, j;
5605182999Smav	int type = -1, use, used = 0;
5606182999Smav	static const int types[7][13] = {
5607182999Smav	    { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
5608182999Smav	      SOUND_MIXER_LINE3, -1 },	/* line */
5609182999Smav	    { SOUND_MIXER_MONITOR, SOUND_MIXER_MIC, -1 }, /* int mic */
5610182999Smav	    { SOUND_MIXER_MIC, SOUND_MIXER_MONITOR, -1 }, /* ext mic */
5611182999Smav	    { SOUND_MIXER_CD, -1 },	/* cd */
5612182999Smav	    { SOUND_MIXER_SPEAKER, -1 },	/* speaker */
5613182999Smav	    { SOUND_MIXER_DIGITAL1, SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3,
5614182999Smav	      -1 },	/* digital */
5615182999Smav	    { SOUND_MIXER_LINE, SOUND_MIXER_LINE1, SOUND_MIXER_LINE2,
5616182999Smav	      SOUND_MIXER_LINE3, SOUND_MIXER_PHONEIN, SOUND_MIXER_PHONEOUT,
5617182999Smav	      SOUND_MIXER_VIDEO, SOUND_MIXER_RADIO, SOUND_MIXER_DIGITAL1,
5618182999Smav	      SOUND_MIXER_DIGITAL2, SOUND_MIXER_DIGITAL3, SOUND_MIXER_MONITOR,
5619182999Smav	      -1 }	/* others */
5620182999Smav	};
5621162922Sariff
5622182999Smav	/* Surely known names */
5623162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5624162922Sariff		w = hdac_widget_get(devinfo, i);
5625162922Sariff		if (w == NULL || w->enable == 0)
5626162922Sariff			continue;
5627182999Smav		if (w->bindas == -1)
5628182999Smav			continue;
5629182999Smav		use = -1;
5630182999Smav		switch (w->type) {
5631182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
5632182999Smav			if (as[w->bindas].dir == HDA_CTL_OUT)
5633182999Smav				break;
5634182999Smav			type = -1;
5635182999Smav			switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
5636182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
5637182999Smav				type = 0;
5638182999Smav				break;
5639182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
5640182999Smav				if ((w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK)
5641182999Smav				    == HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
5642182999Smav					break;
5643182999Smav				type = 1;
5644182999Smav				break;
5645182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
5646182999Smav				type = 3;
5647182999Smav				break;
5648182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
5649182999Smav				type = 4;
5650182999Smav				break;
5651182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
5652182999Smav			case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
5653182999Smav				type = 5;
5654182999Smav				break;
5655182999Smav			}
5656182999Smav			if (type == -1)
5657182999Smav				break;
5658182999Smav			j = 0;
5659182999Smav			while (types[type][j] >= 0 &&
5660182999Smav			    (used & (1 << types[type][j])) != 0) {
5661182999Smav				j++;
5662182999Smav			}
5663182999Smav			if (types[type][j] >= 0)
5664182999Smav				use = types[type][j];
5665182999Smav			break;
5666182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
5667182999Smav			use = SOUND_MIXER_PCM;
5668182999Smav			break;
5669182999Smav		case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
5670182999Smav			use = SOUND_MIXER_SPEAKER;
5671182999Smav			break;
5672182999Smav		default:
5673182999Smav			break;
5674182999Smav		}
5675182999Smav		if (use >= 0) {
5676182999Smav			w->ossdev = use;
5677182999Smav			used |= (1 << use);
5678182999Smav		}
5679182999Smav	}
5680182999Smav	/* Semi-known names */
5681182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5682182999Smav		w = hdac_widget_get(devinfo, i);
5683182999Smav		if (w == NULL || w->enable == 0)
5684182999Smav			continue;
5685182999Smav		if (w->ossdev >= 0)
5686182999Smav			continue;
5687182999Smav		if (w->bindas == -1)
5688182999Smav			continue;
5689162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5690162922Sariff			continue;
5691182999Smav		if (as[w->bindas].dir == HDA_CTL_OUT)
5692162922Sariff			continue;
5693182999Smav		type = -1;
5694182999Smav		switch (w->wclass.pin.config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
5695182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
5696182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
5697182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
5698182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
5699182999Smav			type = 0;
5700182999Smav			break;
5701182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
5702182999Smav			type = 2;
5703182999Smav			break;
5704182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
5705182999Smav		case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
5706182999Smav			type = 5;
5707182999Smav			break;
5708182999Smav		}
5709182999Smav		if (type == -1)
5710182999Smav			break;
5711182999Smav		j = 0;
5712182999Smav		while (types[type][j] >= 0 &&
5713182999Smav		    (used & (1 << types[type][j])) != 0) {
5714182999Smav			j++;
5715182999Smav		}
5716182999Smav		if (types[type][j] >= 0) {
5717182999Smav			w->ossdev = types[type][j];
5718182999Smav			used |= (1 << types[type][j]);
5719182999Smav		}
5720182999Smav	}
5721182999Smav	/* Others */
5722182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5723182999Smav		w = hdac_widget_get(devinfo, i);
5724182999Smav		if (w == NULL || w->enable == 0)
5725162922Sariff			continue;
5726182999Smav		if (w->ossdev >= 0)
5727182999Smav			continue;
5728182999Smav		if (w->bindas == -1)
5729182999Smav			continue;
5730182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5731182999Smav			continue;
5732182999Smav		if (as[w->bindas].dir == HDA_CTL_OUT)
5733182999Smav			continue;
5734182999Smav		j = 0;
5735182999Smav		while (types[6][j] >= 0 &&
5736182999Smav		    (used & (1 << types[6][j])) != 0) {
5737182999Smav			j++;
5738162922Sariff		}
5739182999Smav		if (types[6][j] >= 0) {
5740182999Smav			w->ossdev = types[6][j];
5741182999Smav			used |= (1 << types[6][j]);
5742182999Smav		}
5743162922Sariff	}
5744162922Sariff}
5745162922Sariff
5746162922Sariffstatic void
5747162922Sariffhdac_audio_build_tree(struct hdac_devinfo *devinfo)
5748162922Sariff{
5749182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5750182999Smav	int j, res;
5751162922Sariff
5752182999Smav	/* Trace all associations in order of their numbers, */
5753182999Smav	for (j = 0; j < devinfo->function.audio.ascnt; j++) {
5754182999Smav		if (as[j].enable == 0)
5755182999Smav			continue;
5756163057Sariff		HDA_BOOTVERBOSE(
5757162922Sariff			device_printf(devinfo->codec->sc->dev,
5758182999Smav			    "Tracing association %d (%d)\n", j, as[j].index);
5759162922Sariff		);
5760182999Smav		if (as[j].dir == HDA_CTL_OUT) {
5761182999Smavretry:
5762182999Smav			res = hdac_audio_trace_as_out(devinfo, j, 0);
5763182999Smav			if (res == 0 && as[j].hpredir >= 0 &&
5764182999Smav			    as[j].fakeredir == 0) {
5765182999Smav				/* If codec can't do analog HP redirection
5766182999Smav				   try to make it using one more DAC. */
5767182999Smav				as[j].fakeredir = 1;
5768182999Smav				goto retry;
5769182999Smav			}
5770182999Smav		} else {
5771182999Smav			res = hdac_audio_trace_as_in(devinfo, j);
5772182999Smav		}
5773182999Smav		if (res) {
5774182999Smav			HDA_BOOTVERBOSE(
5775182999Smav				device_printf(devinfo->codec->sc->dev,
5776182999Smav				    "Association %d (%d) trace succeded\n",
5777182999Smav				    j, as[j].index);
5778182999Smav			);
5779182999Smav		} else {
5780182999Smav			HDA_BOOTVERBOSE(
5781182999Smav				device_printf(devinfo->codec->sc->dev,
5782182999Smav				    "Association %d (%d) trace failed\n",
5783182999Smav				    j, as[j].index);
5784182999Smav			);
5785182999Smav			as[j].enable = 0;
5786182999Smav		}
5787162922Sariff	}
5788162922Sariff
5789182999Smav	/* Trace mixer and beeper pseudo associations. */
5790182999Smav	hdac_audio_trace_as_extra(devinfo);
5791182999Smav}
5792162922Sariff
5793182999Smavstatic void
5794182999Smavhdac_audio_assign_mixers(struct hdac_devinfo *devinfo)
5795182999Smav{
5796182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5797182999Smav	struct hdac_audio_ctl *ctl;
5798182999Smav	struct hdac_widget *w;
5799182999Smav	int i;
5800162922Sariff
5801182999Smav	/* Assign mixers to the tree. */
5802162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5803162922Sariff		w = hdac_widget_get(devinfo, i);
5804162922Sariff		if (w == NULL || w->enable == 0)
5805162922Sariff			continue;
5806182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
5807182999Smav		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET ||
5808182999Smav		    (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5809182999Smav		    as[w->bindas].dir == HDA_CTL_IN)) {
5810182999Smav			if (w->ossdev < 0)
5811182999Smav				continue;
5812182999Smav			hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
5813182999Smav			    w->ossdev, 1, 0, 1);
5814182999Smav		} else if ((w->pflags & HDA_ADC_MONITOR) != 0) {
5815182999Smav			if (w->ossdev < 0)
5816182999Smav				continue;
5817182999Smav			if (hdac_audio_ctl_source_amp(devinfo, w->nid, -1,
5818182999Smav			    w->ossdev, 1, 0, 1)) {
5819182999Smav				/* If we are unable to control input monitor
5820182999Smav				   as source - try to control it as destination. */
5821182999Smav				hdac_audio_ctl_dest_amp(devinfo, w->nid,
5822182999Smav				    w->ossdev, 0, 1);
5823162922Sariff			}
5824182999Smav		} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
5825182999Smav			hdac_audio_ctl_dest_amp(devinfo, w->nid,
5826182999Smav			    SOUND_MIXER_RECLEV, 0, 1);
5827182999Smav		} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5828182999Smav		    as[w->bindas].dir == HDA_CTL_OUT) {
5829182999Smav			hdac_audio_ctl_dest_amp(devinfo, w->nid,
5830182999Smav			    SOUND_MIXER_VOLUME, 0, 1);
5831162922Sariff		}
5832162922Sariff	}
5833182999Smav	/* Treat unrequired as possible. */
5834182999Smav	i = 0;
5835182999Smav	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5836182999Smav		if (ctl->ossmask == 0)
5837182999Smav			ctl->ossmask = ctl->possmask;
5838182999Smav	}
5839182999Smav}
5840162922Sariff
5841182999Smavstatic void
5842182999Smavhdac_audio_prepare_pin_ctrl(struct hdac_devinfo *devinfo)
5843182999Smav{
5844182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
5845182999Smav	struct hdac_widget *w;
5846182999Smav	uint32_t pincap;
5847182999Smav	int i;
5848182999Smav
5849182999Smav	for (i = 0; i < devinfo->nodecnt; i++) {
5850182999Smav		w = &devinfo->widget[i];
5851182999Smav		if (w == NULL)
5852162922Sariff			continue;
5853182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5854162922Sariff			continue;
5855182999Smav
5856182999Smav		pincap = w->wclass.pin.cap;
5857182999Smav
5858182999Smav		/* Disable everything. */
5859182999Smav		w->wclass.pin.ctrl &= ~(
5860182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
5861182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
5862182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
5863182999Smav		    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
5864182999Smav
5865182999Smav		if (w->enable == 0 ||
5866182999Smav		    w->bindas < 0 || as[w->bindas].enable == 0) {
5867182999Smav			/* Pin is unused so left it disabled. */
5868182999Smav			continue;
5869182999Smav		} else if (as[w->bindas].dir == HDA_CTL_IN) {
5870182999Smav			/* Input pin, configure for input. */
5871182999Smav			if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
5872182999Smav				w->wclass.pin.ctrl |=
5873182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
5874182999Smav
5875182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) &&
5876182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5877182999Smav				w->wclass.pin.ctrl |=
5878182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5879182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
5880182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) &&
5881182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5882182999Smav				w->wclass.pin.ctrl |=
5883182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5884182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
5885182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) &&
5886182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5887182999Smav				w->wclass.pin.ctrl |=
5888182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5889182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
5890182999Smav		} else {
5891182999Smav			/* Output pin, configure for output. */
5892182999Smav			if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
5893182999Smav				w->wclass.pin.ctrl |=
5894182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
5895182999Smav
5896182999Smav			if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap) &&
5897182999Smav			    (w->wclass.pin.config &
5898182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
5899182999Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
5900182999Smav				w->wclass.pin.ctrl |=
5901182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
5902182999Smav
5903182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) &&
5904182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5905182999Smav				w->wclass.pin.ctrl |=
5906182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5907182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
5908182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) &&
5909182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5910182999Smav				w->wclass.pin.ctrl |=
5911182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5912182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
5913182999Smav			else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) &&
5914182999Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5915182999Smav				w->wclass.pin.ctrl |=
5916182999Smav				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5917182999Smav				    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
5918182999Smav		}
5919162922Sariff	}
5920162922Sariff}
5921162922Sariff
5922162922Sariffstatic void
5923182999Smavhdac_audio_commit(struct hdac_devinfo *devinfo)
5924162922Sariff{
5925162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
5926162922Sariff	struct hdac_widget *w;
5927164750Sariff	nid_t cad;
5928182999Smav	uint32_t gdata, gmask, gdir;
5929182999Smav	int commitgpio, numgpio;
5930164750Sariff	int i;
5931162922Sariff
5932162922Sariff	cad = devinfo->codec->cad;
5933162922Sariff
5934182999Smav	if (sc->pci_subvendor == APPLE_INTEL_MAC)
5935182999Smav		hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
5936182999Smav		    0x7e7, 0), cad);
5937169277Sariff
5938182999Smav	gdata = 0;
5939182999Smav	gmask = 0;
5940182999Smav	gdir = 0;
5941182999Smav	commitgpio = 0;
5942164828Sariff
5943182999Smav	numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO(
5944182999Smav	    devinfo->function.audio.gpio);
5945166796Sariff
5946182999Smav	if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
5947182999Smav		commitgpio = (numgpio > 0) ? 1 : 0;
5948182999Smav	else {
5949182999Smav		for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) {
5950182999Smav			if (!(devinfo->function.audio.quirks &
5951182999Smav			    (1 << i)))
5952182999Smav				continue;
5953182999Smav			if (commitgpio == 0) {
5954182999Smav				commitgpio = 1;
5955182999Smav				HDA_BOOTVERBOSE(
5956182999Smav					gdata = hdac_command(sc,
5957182999Smav					    HDA_CMD_GET_GPIO_DATA(cad,
5958182999Smav					    devinfo->nid), cad);
5959182999Smav					gmask = hdac_command(sc,
5960182999Smav					    HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
5961182999Smav					    devinfo->nid), cad);
5962182999Smav					gdir = hdac_command(sc,
5963182999Smav					    HDA_CMD_GET_GPIO_DIRECTION(cad,
5964182999Smav					    devinfo->nid), cad);
5965182999Smav					device_printf(sc->dev,
5966182999Smav					    "GPIO init: data=0x%08x "
5967182999Smav					    "mask=0x%08x dir=0x%08x\n",
5968182999Smav					    gdata, gmask, gdir);
5969182999Smav					gdata = 0;
5970182999Smav					gmask = 0;
5971182999Smav					gdir = 0;
5972182999Smav				);
5973165039Sariff			}
5974182999Smav			gdata |= 1 << i;
5975182999Smav			gmask |= 1 << i;
5976182999Smav			gdir |= 1 << i;
5977165039Sariff		}
5978182999Smav	}
5979165039Sariff
5980182999Smav	if (commitgpio != 0) {
5981182999Smav		HDA_BOOTVERBOSE(
5982182999Smav			device_printf(sc->dev,
5983182999Smav			    "GPIO commit: data=0x%08x mask=0x%08x "
5984182999Smav			    "dir=0x%08x\n",
5985182999Smav			    gdata, gmask, gdir);
5986182999Smav		);
5987182999Smav		hdac_command(sc,
5988182999Smav		    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
5989182999Smav		    gmask), cad);
5990182999Smav		hdac_command(sc,
5991182999Smav		    HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
5992182999Smav		    gdir), cad);
5993182999Smav		hdac_command(sc,
5994182999Smav		    HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
5995182999Smav		    gdata), cad);
5996162922Sariff	}
5997162922Sariff
5998162922Sariff	for (i = 0; i < devinfo->nodecnt; i++) {
5999162922Sariff		w = &devinfo->widget[i];
6000182999Smav		if (w == NULL)
6001162922Sariff			continue;
6002182999Smav		if (w->selconn == -1)
6003182999Smav			w->selconn = 0;
6004182999Smav		if (w->nconns > 0)
6005182999Smav			hdac_widget_connection_select(w, w->selconn);
6006182999Smav		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
6007162922Sariff			hdac_command(sc,
6008162922Sariff			    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
6009162922Sariff			    w->wclass.pin.ctrl), cad);
6010162922Sariff		}
6011182999Smav		if (w->param.eapdbtl != HDAC_INVALID) {
6012163432Sariff		    	uint32_t val;
6013163432Sariff
6014163432Sariff			val = w->param.eapdbtl;
6015163276Sariff			if (devinfo->function.audio.quirks &
6016163432Sariff			    HDA_QUIRK_EAPDINV)
6017163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
6018162922Sariff			hdac_command(sc,
6019162922Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid,
6020163432Sariff			    val), cad);
6021162922Sariff
6022163276Sariff		}
6023162922Sariff		DELAY(1000);
6024162922Sariff	}
6025162922Sariff}
6026162922Sariff
6027162922Sariffstatic void
6028162922Sariffhdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
6029162922Sariff{
6030162922Sariff	struct hdac_audio_ctl *ctl;
6031182999Smav	int i, z;
6032162922Sariff
6033162922Sariff	i = 0;
6034162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6035182999Smav		if (ctl->enable == 0) {
6036182999Smav			/* Mute disabled controls. */
6037182999Smav			hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_ALL, 0, 0);
6038162922Sariff			continue;
6039162922Sariff		}
6040182999Smav		/* Init controls to 0dB amplification. */
6041182999Smav		z = ctl->offset;
6042182999Smav		if (z > ctl->step)
6043182999Smav			z = ctl->step;
6044182999Smav		hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_NONE, z, z);
6045162922Sariff	}
6046162922Sariff}
6047162922Sariff
6048182999Smavstatic void
6049182999Smavhdac_powerup(struct hdac_devinfo *devinfo)
6050182999Smav{
6051182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
6052182999Smav	nid_t cad = devinfo->codec->cad;
6053182999Smav	int i;
6054182999Smav
6055182999Smav	hdac_command(sc,
6056182999Smav	    HDA_CMD_SET_POWER_STATE(cad,
6057182999Smav	    devinfo->nid, HDA_CMD_POWER_STATE_D0),
6058182999Smav	    cad);
6059182999Smav	DELAY(100);
6060182999Smav
6061182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6062182999Smav		hdac_command(sc,
6063182999Smav		    HDA_CMD_SET_POWER_STATE(cad,
6064182999Smav		    i, HDA_CMD_POWER_STATE_D0),
6065182999Smav		    cad);
6066182999Smav	}
6067182999Smav	DELAY(1000);
6068182999Smav}
6069182999Smav
6070162922Sariffstatic int
6071182999Smavhdac_pcmchannel_setup(struct hdac_chan *ch)
6072162922Sariff{
6073182999Smav	struct hdac_devinfo *devinfo = ch->devinfo;
6074182999Smav	struct hdac_audio_as *as = devinfo->function.audio.as;
6075162922Sariff	struct hdac_widget *w;
6076182999Smav	uint32_t cap, fmtcap, pcmcap;
6077182999Smav	int i, j, ret, max;
6078162922Sariff
6079162922Sariff	ch->caps = hdac_caps;
6080162922Sariff	ch->caps.fmtlist = ch->fmtlist;
6081162922Sariff	ch->bit16 = 1;
6082162922Sariff	ch->bit32 = 0;
6083162922Sariff	ch->pcmrates[0] = 48000;
6084162922Sariff	ch->pcmrates[1] = 0;
6085162922Sariff
6086162922Sariff	ret = 0;
6087162922Sariff	fmtcap = devinfo->function.audio.supp_stream_formats;
6088162922Sariff	pcmcap = devinfo->function.audio.supp_pcm_size_rate;
6089162922Sariff	max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1;
6090162922Sariff
6091182999Smav	for (i = 0; i < 16 && ret < max; i++) {
6092182999Smav		/* Check as is correct */
6093182999Smav		if (ch->as < 0)
6094182999Smav			break;
6095182999Smav		/* Cound only present DACs */
6096182999Smav		if (as[ch->as].dacs[i] <= 0)
6097162922Sariff			continue;
6098182999Smav		/* Ignore duplicates */
6099182999Smav		for (j = 0; j < ret; j++) {
6100182999Smav			if (ch->io[j] == as[ch->as].dacs[i])
6101182999Smav				break;
6102182999Smav		}
6103182999Smav		if (j < ret)
6104162922Sariff			continue;
6105182999Smav
6106182999Smav		w = hdac_widget_get(devinfo, as[ch->as].dacs[i]);
6107182999Smav		if (w == NULL || w->enable == 0)
6108182999Smav			continue;
6109182999Smav		if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap))
6110182999Smav			continue;
6111162922Sariff		cap = w->param.supp_stream_formats;
6112182999Smav		/*if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
6113162922Sariff		}*/
6114182999Smav		if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap) &&
6115182999Smav		    !HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
6116162922Sariff			continue;
6117182999Smav		/* Many codec does not declare AC3 support on SPDIF.
6118182999Smav		   I don't beleave that they doesn't support it! */
6119182999Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6120182999Smav			cap |= HDA_PARAM_SUPP_STREAM_FORMATS_AC3_MASK;
6121164614Sariff		if (ret == 0) {
6122182999Smav			fmtcap = cap;
6123164614Sariff			pcmcap = w->param.supp_pcm_size_rate;
6124164614Sariff		} else {
6125182999Smav			fmtcap &= cap;
6126164614Sariff			pcmcap &= w->param.supp_pcm_size_rate;
6127164614Sariff		}
6128182999Smav		ch->io[ret++] = as[ch->as].dacs[i];
6129162922Sariff	}
6130162922Sariff	ch->io[ret] = -1;
6131162922Sariff
6132162922Sariff	ch->supp_stream_formats = fmtcap;
6133162922Sariff	ch->supp_pcm_size_rate = pcmcap;
6134162922Sariff
6135162922Sariff	/*
6136162922Sariff	 *  8bit = 0
6137162922Sariff	 * 16bit = 1
6138162922Sariff	 * 20bit = 2
6139162922Sariff	 * 24bit = 3
6140162922Sariff	 * 32bit = 4
6141162922Sariff	 */
6142162922Sariff	if (ret > 0) {
6143162922Sariff		i = 0;
6144182999Smav		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(fmtcap)) {
6145182999Smav			if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(pcmcap))
6146182999Smav				ch->bit16 = 1;
6147182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(pcmcap))
6148182999Smav				ch->bit16 = 0;
6149182999Smav			if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(pcmcap))
6150182999Smav				ch->bit32 = 4;
6151182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(pcmcap))
6152182999Smav				ch->bit32 = 3;
6153182999Smav			else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(pcmcap))
6154182999Smav				ch->bit32 = 2;
6155182999Smav			if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
6156182999Smav				ch->fmtlist[i++] = AFMT_S16_LE;
6157182999Smav			ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
6158182999Smav			if (ch->bit32 > 0) {
6159182999Smav				if (!(devinfo->function.audio.quirks &
6160182999Smav				    HDA_QUIRK_FORCESTEREO))
6161182999Smav					ch->fmtlist[i++] = AFMT_S32_LE;
6162182999Smav				ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
6163182999Smav			}
6164162922Sariff		}
6165182999Smav		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(fmtcap)) {
6166182999Smav			ch->fmtlist[i++] = AFMT_AC3;
6167182999Smav		}
6168162922Sariff		ch->fmtlist[i] = 0;
6169162922Sariff		i = 0;
6170182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(pcmcap))
6171162922Sariff			ch->pcmrates[i++] = 8000;
6172182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(pcmcap))
6173162922Sariff			ch->pcmrates[i++] = 11025;
6174182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(pcmcap))
6175162922Sariff			ch->pcmrates[i++] = 16000;
6176182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(pcmcap))
6177162922Sariff			ch->pcmrates[i++] = 22050;
6178182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(pcmcap))
6179162922Sariff			ch->pcmrates[i++] = 32000;
6180182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(pcmcap))
6181162922Sariff			ch->pcmrates[i++] = 44100;
6182182999Smav		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(pcmcap)) */
6183162922Sariff		ch->pcmrates[i++] = 48000;
6184182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(pcmcap))
6185162922Sariff			ch->pcmrates[i++] = 88200;
6186182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(pcmcap))
6187162922Sariff			ch->pcmrates[i++] = 96000;
6188182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(pcmcap))
6189162922Sariff			ch->pcmrates[i++] = 176400;
6190182999Smav		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(pcmcap))
6191162922Sariff			ch->pcmrates[i++] = 192000;
6192182999Smav		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(pcmcap)) */
6193162922Sariff		ch->pcmrates[i] = 0;
6194162922Sariff		if (i > 0) {
6195162922Sariff			ch->caps.minspeed = ch->pcmrates[0];
6196162922Sariff			ch->caps.maxspeed = ch->pcmrates[i - 1];
6197162922Sariff		}
6198162922Sariff	}
6199162922Sariff
6200162922Sariff	return (ret);
6201162922Sariff}
6202162922Sariff
6203162922Sariffstatic void
6204182999Smavhdac_dump_ctls(struct hdac_pcm_devinfo *pdevinfo, const char *banner, uint32_t flag)
6205162922Sariff{
6206182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6207162922Sariff	struct hdac_audio_ctl *ctl;
6208162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6209182999Smav	char buf[64];
6210182999Smav	int i, j, printed;
6211162922Sariff
6212162922Sariff	if (flag == 0) {
6213182999Smav		flag = ~(SOUND_MASK_VOLUME | SOUND_MASK_PCM |
6214162922Sariff		    SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
6215182999Smav		    SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN |
6216182999Smav		    SOUND_MASK_IMIX | SOUND_MASK_MONITOR);
6217162922Sariff	}
6218162922Sariff
6219182999Smav	for (j = 0; j < SOUND_MIXER_NRDEVICES; j++) {
6220182999Smav		if ((flag & (1 << j)) == 0)
6221162922Sariff			continue;
6222182999Smav		i = 0;
6223182999Smav		printed = 0;
6224182999Smav		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6225182999Smav			if (ctl->enable == 0 ||
6226182999Smav			    ctl->widget->enable == 0)
6227182999Smav				continue;
6228182999Smav			if (!((pdevinfo->play >= 0 &&
6229182999Smav			    ctl->widget->bindas == sc->chans[pdevinfo->play].as) ||
6230182999Smav			    (pdevinfo->rec >= 0 &&
6231182999Smav			    ctl->widget->bindas == sc->chans[pdevinfo->rec].as) ||
6232182999Smav			    (ctl->widget->bindas == -2 && pdevinfo->index == 0)))
6233182999Smav				continue;
6234182999Smav			if ((ctl->ossmask & (1 << j)) == 0)
6235182999Smav				continue;
6236182999Smav
6237182999Smav	    		if (printed == 0) {
6238182999Smav				device_printf(pdevinfo->dev, "\n");
6239182999Smav				if (banner != NULL) {
6240182999Smav					device_printf(pdevinfo->dev, "%s", banner);
6241182999Smav				} else {
6242182999Smav					device_printf(pdevinfo->dev, "Unknown Ctl");
6243182999Smav				}
6244182999Smav				printf(" (OSS: %s)\n",
6245182999Smav				    hdac_audio_ctl_ossmixer_mask2allname(1 << j,
6246182999Smav				    buf, sizeof(buf)));
6247182999Smav				device_printf(pdevinfo->dev, "   |\n");
6248182999Smav				printed = 1;
6249162922Sariff			}
6250182999Smav			device_printf(pdevinfo->dev, "   +- ctl %2d (nid %3d %s", i,
6251182999Smav				ctl->widget->nid,
6252182999Smav				(ctl->ndir == HDA_CTL_IN)?"in ":"out");
6253182999Smav			if (ctl->ndir == HDA_CTL_IN && ctl->ndir == ctl->dir)
6254182999Smav				printf(" %2d): ", ctl->index);
6255182999Smav			else
6256182999Smav				printf("):    ");
6257182999Smav			if (ctl->step > 0) {
6258182999Smav				printf("%+d/%+ddB (%d steps)%s\n",
6259182999Smav			    	    (0 - ctl->offset) * (ctl->size + 1) / 4,
6260182999Smav				    (ctl->step - ctl->offset) * (ctl->size + 1) / 4,
6261182999Smav				    ctl->step + 1,
6262182999Smav				    ctl->mute?" + mute":"");
6263182999Smav			} else
6264182999Smav				printf("%s\n", ctl->mute?"mute":"");
6265162922Sariff		}
6266162922Sariff	}
6267162922Sariff}
6268162922Sariff
6269162922Sariffstatic void
6270182999Smavhdac_dump_audio_formats(device_t dev, uint32_t fcap, uint32_t pcmcap)
6271162922Sariff{
6272162922Sariff	uint32_t cap;
6273162922Sariff
6274162922Sariff	cap = fcap;
6275162922Sariff	if (cap != 0) {
6276182999Smav		device_printf(dev, "     Stream cap: 0x%08x\n", cap);
6277183097Smav		device_printf(dev, "                ");
6278162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
6279162922Sariff			printf(" AC3");
6280162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
6281162922Sariff			printf(" FLOAT32");
6282162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
6283162922Sariff			printf(" PCM");
6284162922Sariff		printf("\n");
6285162922Sariff	}
6286162922Sariff	cap = pcmcap;
6287162922Sariff	if (cap != 0) {
6288182999Smav		device_printf(dev, "        PCM cap: 0x%08x\n", cap);
6289183097Smav		device_printf(dev, "                ");
6290162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
6291162922Sariff			printf(" 8");
6292162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
6293162922Sariff			printf(" 16");
6294162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
6295162922Sariff			printf(" 20");
6296162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
6297162922Sariff			printf(" 24");
6298162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
6299162922Sariff			printf(" 32");
6300183097Smav		printf(" bits,");
6301162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
6302162922Sariff			printf(" 8");
6303162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
6304162922Sariff			printf(" 11");
6305162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
6306162922Sariff			printf(" 16");
6307162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
6308162922Sariff			printf(" 22");
6309162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
6310162922Sariff			printf(" 32");
6311162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
6312162922Sariff			printf(" 44");
6313162922Sariff		printf(" 48");
6314162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
6315162922Sariff			printf(" 88");
6316162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
6317162922Sariff			printf(" 96");
6318162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
6319162922Sariff			printf(" 176");
6320162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
6321162922Sariff			printf(" 192");
6322183097Smav		printf(" KHz\n");
6323162922Sariff	}
6324162922Sariff}
6325162922Sariff
6326162922Sariffstatic void
6327162922Sariffhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
6328162922Sariff{
6329183097Smav	uint32_t pincap;
6330162922Sariff
6331162922Sariff	pincap = w->wclass.pin.cap;
6332162922Sariff
6333162922Sariff	device_printf(sc->dev, "        Pin cap: 0x%08x\n", pincap);
6334162922Sariff	device_printf(sc->dev, "                ");
6335162922Sariff	if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap))
6336162922Sariff		printf(" ISC");
6337162922Sariff	if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap))
6338162922Sariff		printf(" TRQD");
6339162922Sariff	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap))
6340162922Sariff		printf(" PDC");
6341162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
6342162922Sariff		printf(" HP");
6343162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
6344162922Sariff		printf(" OUT");
6345162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
6346162922Sariff		printf(" IN");
6347162922Sariff	if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap))
6348162922Sariff		printf(" BAL");
6349165069Sariff	if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) {
6350165069Sariff		printf(" VREF[");
6351165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
6352165069Sariff			printf(" 50");
6353165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
6354165069Sariff			printf(" 80");
6355165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
6356165069Sariff			printf(" 100");
6357165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap))
6358165069Sariff			printf(" GROUND");
6359165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap))
6360165069Sariff			printf(" HIZ");
6361165069Sariff		printf(" ]");
6362165069Sariff	}
6363162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap))
6364162922Sariff		printf(" EAPD");
6365162922Sariff	printf("\n");
6366162922Sariff	device_printf(sc->dev, "     Pin config: 0x%08x\n",
6367162922Sariff	    w->wclass.pin.config);
6368162922Sariff	device_printf(sc->dev, "    Pin control: 0x%08x", w->wclass.pin.ctrl);
6369162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE)
6370162922Sariff		printf(" HP");
6371162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE)
6372162922Sariff		printf(" IN");
6373162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
6374162922Sariff		printf(" OUT");
6375182999Smav	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK)
6376182999Smav		printf(" VREFs");
6377162922Sariff	printf("\n");
6378162922Sariff}
6379162922Sariff
6380162922Sariffstatic void
6381182999Smavhdac_dump_pin_config(struct hdac_widget *w, uint32_t conf)
6382182999Smav{
6383182999Smav	struct hdac_softc *sc = w->devinfo->codec->sc;
6384182999Smav
6385183097Smav	device_printf(sc->dev, " nid %d 0x%08x as %2d seq %2d %13s %5s "
6386182999Smav	    "jack %2d loc %2d color %7s misc %d%s\n",
6387182999Smav	    w->nid, conf,
6388182999Smav	    HDA_CONFIG_DEFAULTCONF_ASSOCIATION(conf),
6389182999Smav	    HDA_CONFIG_DEFAULTCONF_SEQUENCE(conf),
6390182999Smav	    HDA_DEVS[HDA_CONFIG_DEFAULTCONF_DEVICE(conf)],
6391182999Smav	    HDA_CONNS[HDA_CONFIG_DEFAULTCONF_CONNECTIVITY(conf)],
6392182999Smav	    HDA_CONFIG_DEFAULTCONF_CONNECTION_TYPE(conf),
6393182999Smav	    HDA_CONFIG_DEFAULTCONF_LOCATION(conf),
6394182999Smav	    HDA_COLORS[HDA_CONFIG_DEFAULTCONF_COLOR(conf)],
6395182999Smav	    HDA_CONFIG_DEFAULTCONF_MISC(conf),
6396182999Smav	    (w->enable == 0)?" [DISABLED]":"");
6397182999Smav}
6398182999Smav
6399182999Smavstatic void
6400182999Smavhdac_dump_pin_configs(struct hdac_devinfo *devinfo)
6401182999Smav{
6402182999Smav	struct hdac_widget *w;
6403182999Smav	int i;
6404182999Smav
6405182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6406182999Smav		w = hdac_widget_get(devinfo, i);
6407182999Smav		if (w == NULL)
6408182999Smav			continue;
6409182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6410182999Smav			continue;
6411182999Smav		hdac_dump_pin_config(w, w->wclass.pin.config);
6412182999Smav	}
6413182999Smav}
6414182999Smav
6415182999Smavstatic void
6416162922Sariffhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
6417162922Sariff{
6418163057Sariff	device_printf(sc->dev, "     %s amp: 0x%08x\n", banner, cap);
6419162922Sariff	device_printf(sc->dev, "                 "
6420162922Sariff	    "mute=%d step=%d size=%d offset=%d\n",
6421162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap),
6422162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap),
6423162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap),
6424162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap));
6425162922Sariff}
6426162922Sariff
6427162922Sariffstatic void
6428162922Sariffhdac_dump_nodes(struct hdac_devinfo *devinfo)
6429162922Sariff{
6430162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6431182999Smav	static char *ossname[] = SOUND_DEVICE_NAMES;
6432162922Sariff	struct hdac_widget *w, *cw;
6433182999Smav	char buf[64];
6434162922Sariff	int i, j;
6435162922Sariff
6436162922Sariff	device_printf(sc->dev, "\n");
6437162922Sariff	device_printf(sc->dev, "Default Parameter\n");
6438162922Sariff	device_printf(sc->dev, "-----------------\n");
6439182999Smav	hdac_dump_audio_formats(sc->dev,
6440162922Sariff	    devinfo->function.audio.supp_stream_formats,
6441162922Sariff	    devinfo->function.audio.supp_pcm_size_rate);
6442162922Sariff	device_printf(sc->dev, "         IN amp: 0x%08x\n",
6443162922Sariff	    devinfo->function.audio.inamp_cap);
6444162922Sariff	device_printf(sc->dev, "        OUT amp: 0x%08x\n",
6445162922Sariff	    devinfo->function.audio.outamp_cap);
6446162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6447162922Sariff		w = hdac_widget_get(devinfo, i);
6448162922Sariff		if (w == NULL) {
6449162922Sariff			device_printf(sc->dev, "Ghost widget nid=%d\n", i);
6450162922Sariff			continue;
6451162922Sariff		}
6452162922Sariff		device_printf(sc->dev, "\n");
6453183097Smav		device_printf(sc->dev, "            nid: %d%s\n", w->nid,
6454162922Sariff		    (w->enable == 0) ? " [DISABLED]" : "");
6455183097Smav		device_printf(sc->dev, "           Name: %s\n", w->name);
6456183097Smav		device_printf(sc->dev, "     Widget cap: 0x%08x\n",
6457162922Sariff		    w->param.widget_cap);
6458183097Smav		if (w->param.widget_cap & 0x0ee1) {
6459183097Smav			device_printf(sc->dev, "                ");
6460183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_LR_SWAP(w->param.widget_cap))
6461183097Smav			    printf(" LRSWAP");
6462183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(w->param.widget_cap))
6463183097Smav			    printf(" PWR");
6464183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6465183097Smav			    printf(" DIGITAL");
6466183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap))
6467183097Smav			    printf(" UNSOL");
6468183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_PROC_WIDGET(w->param.widget_cap))
6469183097Smav			    printf(" PROC");
6470183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_STRIPE(w->param.widget_cap))
6471183097Smav			    printf(" STRIPE");
6472183097Smav			if (HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap))
6473183097Smav			    printf(" STEREO");
6474183097Smav			printf("\n");
6475183097Smav		}
6476183097Smav		if (w->bindas != -1) {
6477183097Smav			device_printf(sc->dev, "    Association: %d (0x%08x)\n",
6478183097Smav			    w->bindas, w->bindseqmask);
6479183097Smav		}
6480183097Smav		if (w->ossmask != 0 || w->ossdev >= 0) {
6481183097Smav			device_printf(sc->dev, "            OSS: %s",
6482183097Smav			    hdac_audio_ctl_ossmixer_mask2allname(w->ossmask, buf, sizeof(buf)));
6483183097Smav			if (w->ossdev >= 0)
6484183097Smav			    printf(" (%s)", ossname[w->ossdev]);
6485183097Smav			printf("\n");
6486183097Smav		}
6487162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
6488162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
6489182999Smav			hdac_dump_audio_formats(sc->dev,
6490162922Sariff			    w->param.supp_stream_formats,
6491162922Sariff			    w->param.supp_pcm_size_rate);
6492162922Sariff		} else if (w->type ==
6493162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6494162922Sariff			hdac_dump_pin(sc, w);
6495162965Sariff		if (w->param.eapdbtl != HDAC_INVALID)
6496162922Sariff			device_printf(sc->dev, "           EAPD: 0x%08x\n",
6497162922Sariff			    w->param.eapdbtl);
6498163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) &&
6499163057Sariff		    w->param.outamp_cap != 0)
6500162922Sariff			hdac_dump_amp(sc, w->param.outamp_cap, "Output");
6501163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) &&
6502163057Sariff		    w->param.inamp_cap != 0)
6503162922Sariff			hdac_dump_amp(sc, w->param.inamp_cap, " Input");
6504183097Smav		if (w->nconns > 0) {
6505183097Smav			device_printf(sc->dev, "    connections: %d\n", w->nconns);
6506182999Smav			device_printf(sc->dev, "          |\n");
6507183097Smav		}
6508162922Sariff		for (j = 0; j < w->nconns; j++) {
6509162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
6510182999Smav			device_printf(sc->dev, "          + %s<- nid=%d [%s]",
6511182999Smav			    (w->connsenable[j] == 0)?"[DISABLED] ":"",
6512162922Sariff			    w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
6513162922Sariff			if (cw == NULL)
6514162922Sariff				printf(" [UNKNOWN]");
6515162922Sariff			else if (cw->enable == 0)
6516162922Sariff				printf(" [DISABLED]");
6517162922Sariff			if (w->nconns > 1 && w->selconn == j && w->type !=
6518162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
6519162922Sariff				printf(" (selected)");
6520162922Sariff			printf("\n");
6521162922Sariff		}
6522162922Sariff	}
6523162922Sariff
6524162922Sariff}
6525162922Sariff
6526182999Smavstatic void
6527182999Smavhdac_dump_dst_nid(struct hdac_pcm_devinfo *pdevinfo, nid_t nid, int depth)
6528163057Sariff{
6529182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6530163057Sariff	struct hdac_widget *w, *cw;
6531182999Smav	char buf[64];
6532182999Smav	int i, printed = 0;
6533163057Sariff
6534163057Sariff	if (depth > HDA_PARSE_MAXDEPTH)
6535182999Smav		return;
6536163057Sariff
6537163057Sariff	w = hdac_widget_get(devinfo, nid);
6538182999Smav	if (w == NULL || w->enable == 0)
6539182999Smav		return;
6540163057Sariff
6541182999Smav	if (depth == 0)
6542182999Smav		device_printf(pdevinfo->dev, "%*s", 4, "");
6543182999Smav	else
6544182999Smav		device_printf(pdevinfo->dev, "%*s  + <- ", 4 + (depth - 1) * 7, "");
6545182999Smav	printf("nid=%d [%s]", w->nid, w->name);
6546163057Sariff
6547182999Smav	if (depth > 0) {
6548182999Smav		if (w->ossmask == 0) {
6549182999Smav			printf("\n");
6550182999Smav			return;
6551163057Sariff		}
6552182999Smav		printf(" [src: %s]",
6553182999Smav		    hdac_audio_ctl_ossmixer_mask2allname(
6554182999Smav			w->ossmask, buf, sizeof(buf)));
6555182999Smav		if (w->ossdev >= 0) {
6556182999Smav			printf("\n");
6557182999Smav			return;
6558182999Smav		}
6559163057Sariff	}
6560182999Smav	printf("\n");
6561182999Smav
6562182999Smav	for (i = 0; i < w->nconns; i++) {
6563182999Smav		if (w->connsenable[i] == 0)
6564182999Smav			continue;
6565182999Smav		cw = hdac_widget_get(devinfo, w->conns[i]);
6566182999Smav		if (cw == NULL || cw->enable == 0 || cw->bindas == -1)
6567182999Smav			continue;
6568182999Smav		if (printed == 0) {
6569182999Smav			device_printf(pdevinfo->dev, "%*s  |\n", 4 + (depth) * 7, "");
6570182999Smav			printed = 1;
6571182999Smav		}
6572182999Smav		hdac_dump_dst_nid(pdevinfo, w->conns[i], depth + 1);
6573182999Smav	}
6574163057Sariff
6575163057Sariff}
6576163057Sariff
6577162922Sariffstatic void
6578182999Smavhdac_dump_dac(struct hdac_pcm_devinfo *pdevinfo)
6579162922Sariff{
6580182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6581182999Smav	struct hdac_softc *sc = devinfo->codec->sc;
6582163057Sariff	struct hdac_widget *w;
6583163057Sariff	int i, printed = 0;
6584163057Sariff
6585182999Smav	if (pdevinfo->play < 0)
6586182999Smav		return;
6587182999Smav
6588163057Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6589163057Sariff		w = hdac_widget_get(devinfo, i);
6590163057Sariff		if (w == NULL || w->enable == 0)
6591163057Sariff			continue;
6592182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6593163057Sariff			continue;
6594182999Smav		if (w->bindas != sc->chans[pdevinfo->play].as)
6595182999Smav			continue;
6596163057Sariff		if (printed == 0) {
6597163057Sariff			printed = 1;
6598182999Smav			device_printf(pdevinfo->dev, "\n");
6599182999Smav			device_printf(pdevinfo->dev, "Playback:\n");
6600163057Sariff		}
6601182999Smav		device_printf(pdevinfo->dev, "\n");
6602182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
6603163057Sariff	}
6604162922Sariff}
6605162922Sariff
6606162922Sariffstatic void
6607182999Smavhdac_dump_adc(struct hdac_pcm_devinfo *pdevinfo)
6608162922Sariff{
6609182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6610162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
6611182999Smav	struct hdac_widget *w;
6612182999Smav	int i;
6613162922Sariff	int printed = 0;
6614162922Sariff
6615182999Smav	if (pdevinfo->rec < 0)
6616182999Smav		return;
6617182999Smav
6618162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6619162922Sariff		w = hdac_widget_get(devinfo, i);
6620162922Sariff		if (w == NULL || w->enable == 0)
6621162922Sariff			continue;
6622182999Smav		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
6623162922Sariff			continue;
6624182999Smav		if (w->bindas != sc->chans[pdevinfo->rec].as)
6625182999Smav			continue;
6626162922Sariff		if (printed == 0) {
6627162922Sariff			printed = 1;
6628182999Smav			device_printf(pdevinfo->dev, "\n");
6629182999Smav			device_printf(pdevinfo->dev, "Record:\n");
6630162922Sariff		}
6631182999Smav		device_printf(pdevinfo->dev, "\n");
6632182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
6633182999Smav	}
6634182999Smav}
6635182999Smav
6636182999Smavstatic void
6637182999Smavhdac_dump_mix(struct hdac_pcm_devinfo *pdevinfo)
6638182999Smav{
6639182999Smav	struct hdac_devinfo *devinfo = pdevinfo->devinfo;
6640182999Smav	struct hdac_widget *w;
6641182999Smav	int i;
6642182999Smav	int printed = 0;
6643182999Smav
6644182999Smav	if (pdevinfo->index != 0)
6645182999Smav		return;
6646182999Smav
6647182999Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6648182999Smav		w = hdac_widget_get(devinfo, i);
6649182999Smav		if (w == NULL || w->enable == 0)
6650182999Smav			continue;
6651182999Smav		if ((w->pflags & HDA_ADC_MONITOR) == 0)
6652182999Smav			continue;
6653182999Smav		if (printed == 0) {
6654182999Smav			printed = 1;
6655182999Smav			device_printf(pdevinfo->dev, "\n");
6656182999Smav			device_printf(pdevinfo->dev, "Input Mix:\n");
6657162922Sariff		}
6658182999Smav		device_printf(pdevinfo->dev, "\n");
6659182999Smav		hdac_dump_dst_nid(pdevinfo, i, 0);
6660162922Sariff	}
6661162922Sariff}
6662162922Sariff
6663162922Sariffstatic void
6664182999Smavhdac_dump_pcmchannels(struct hdac_pcm_devinfo *pdevinfo)
6665162922Sariff{
6666182999Smav	struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
6667162922Sariff	nid_t *nids;
6668182999Smav	int i;
6669162922Sariff
6670182999Smav	if (pdevinfo->play >= 0) {
6671182999Smav		i = pdevinfo->play;
6672182999Smav		device_printf(pdevinfo->dev, "\n");
6673182999Smav		device_printf(pdevinfo->dev, "Playback:\n");
6674182999Smav		device_printf(pdevinfo->dev, "\n");
6675182999Smav		hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
6676182999Smav		    sc->chans[i].supp_pcm_size_rate);
6677182999Smav		device_printf(pdevinfo->dev, "            DAC:");
6678182999Smav		for (nids = sc->chans[i].io; *nids != -1; nids++)
6679162922Sariff			printf(" %d", *nids);
6680162922Sariff		printf("\n");
6681162922Sariff	}
6682182999Smav	if (pdevinfo->rec >= 0) {
6683182999Smav		i = pdevinfo->rec;
6684182999Smav		device_printf(pdevinfo->dev, "\n");
6685182999Smav		device_printf(pdevinfo->dev, "Record:\n");
6686182999Smav		device_printf(pdevinfo->dev, "\n");
6687182999Smav		hdac_dump_audio_formats(pdevinfo->dev, sc->chans[i].supp_stream_formats,
6688182999Smav		    sc->chans[i].supp_pcm_size_rate);
6689182999Smav		device_printf(pdevinfo->dev, "            ADC:");
6690182999Smav		for (nids = sc->chans[i].io; *nids != -1; nids++)
6691162922Sariff			printf(" %d", *nids);
6692162922Sariff		printf("\n");
6693162922Sariff	}
6694162922Sariff}
6695162922Sariff
6696162922Sariffstatic void
6697163057Sariffhdac_release_resources(struct hdac_softc *sc)
6698163057Sariff{
6699182999Smav        int i, j;
6700163057Sariff
6701163057Sariff	if (sc == NULL)
6702163057Sariff		return;
6703163057Sariff
6704163057Sariff	hdac_lock(sc);
6705169277Sariff	sc->polling = 0;
6706169277Sariff	sc->poll_ival = 0;
6707170721Sariff	callout_stop(&sc->poll_hda);
6708169277Sariff	callout_stop(&sc->poll_hdac);
6709169277Sariff	callout_stop(&sc->poll_jack);
6710182999Smav	hdac_reset(sc, 0);
6711163057Sariff	hdac_unlock(sc);
6712171141Sariff	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
6713170721Sariff	callout_drain(&sc->poll_hda);
6714169277Sariff	callout_drain(&sc->poll_hdac);
6715169277Sariff	callout_drain(&sc->poll_jack);
6716163057Sariff
6717169277Sariff	hdac_irq_free(sc);
6718169277Sariff
6719182999Smav	for (i = 0; i < HDAC_CODEC_MAX; i++) {
6720182999Smav		if (sc->codecs[i] == NULL)
6721163057Sariff			continue;
6722182999Smav		for (j = 0; j < sc->codecs[i]->num_fgs; j++) {
6723182999Smav			free(sc->codecs[i]->fgs[j].widget, M_HDAC);
6724182999Smav			if (sc->codecs[i]->fgs[j].node_type ==
6725182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
6726182999Smav				free(sc->codecs[i]->fgs[j].function.audio.ctl,
6727182999Smav				    M_HDAC);
6728182999Smav				free(sc->codecs[i]->fgs[j].function.audio.as,
6729182999Smav				    M_HDAC);
6730182999Smav				free(sc->codecs[i]->fgs[j].function.audio.devs,
6731182999Smav				    M_HDAC);
6732182999Smav			}
6733182999Smav		}
6734182999Smav		free(sc->codecs[i]->fgs, M_HDAC);
6735182999Smav		free(sc->codecs[i], M_HDAC);
6736163057Sariff		sc->codecs[i] = NULL;
6737163057Sariff	}
6738163057Sariff
6739169277Sariff	hdac_dma_free(sc, &sc->pos_dma);
6740169277Sariff	hdac_dma_free(sc, &sc->rirb_dma);
6741169277Sariff	hdac_dma_free(sc, &sc->corb_dma);
6742182999Smav	for (i = 0; i < sc->num_chans; i++) {
6743182999Smav    		if (sc->chans[i].blkcnt > 0)
6744182999Smav    			hdac_dma_free(sc, &sc->chans[i].bdl_dma);
6745182999Smav	}
6746182999Smav	free(sc->chans, M_HDAC);
6747167702Sariff	if (sc->chan_dmat != NULL) {
6748167702Sariff		bus_dma_tag_destroy(sc->chan_dmat);
6749167702Sariff		sc->chan_dmat = NULL;
6750167702Sariff	}
6751163057Sariff	hdac_mem_free(sc);
6752169277Sariff	snd_mtxfree(sc->lock);
6753163057Sariff}
6754163057Sariff
6755163057Sariff/* This function surely going to make its way into upper level someday. */
6756163057Sariffstatic void
6757163057Sariffhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
6758163057Sariff{
6759163057Sariff	const char *res = NULL;
6760163057Sariff	int i = 0, j, k, len, inv;
6761163057Sariff
6762163057Sariff	if (on != NULL)
6763163057Sariff		*on = 0;
6764163057Sariff	if (off != NULL)
6765163057Sariff		*off = 0;
6766163057Sariff	if (sc == NULL)
6767163057Sariff		return;
6768163057Sariff	if (resource_string_value(device_get_name(sc->dev),
6769163057Sariff	    device_get_unit(sc->dev), "config", &res) != 0)
6770163057Sariff		return;
6771163057Sariff	if (!(res != NULL && strlen(res) > 0))
6772163057Sariff		return;
6773163057Sariff	HDA_BOOTVERBOSE(
6774182999Smav		device_printf(sc->dev, "HDA Config:");
6775163057Sariff	);
6776163057Sariff	for (;;) {
6777163057Sariff		while (res[i] != '\0' &&
6778163057Sariff		    (res[i] == ',' || isspace(res[i]) != 0))
6779163057Sariff			i++;
6780163057Sariff		if (res[i] == '\0') {
6781163057Sariff			HDA_BOOTVERBOSE(
6782163057Sariff				printf("\n");
6783163057Sariff			);
6784163057Sariff			return;
6785163057Sariff		}
6786163057Sariff		j = i;
6787163057Sariff		while (res[j] != '\0' &&
6788163057Sariff		    !(res[j] == ',' || isspace(res[j]) != 0))
6789163057Sariff			j++;
6790163057Sariff		len = j - i;
6791163057Sariff		if (len > 2 && strncmp(res + i, "no", 2) == 0)
6792163057Sariff			inv = 2;
6793163057Sariff		else
6794163057Sariff			inv = 0;
6795163057Sariff		for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) {
6796163057Sariff			if (strncmp(res + i + inv,
6797163057Sariff			    hdac_quirks_tab[k].key, len - inv) != 0)
6798163057Sariff				continue;
6799163057Sariff			if (len - inv != strlen(hdac_quirks_tab[k].key))
6800163057Sariff				break;
6801163057Sariff			HDA_BOOTVERBOSE(
6802163057Sariff				printf(" %s%s", (inv != 0) ? "no" : "",
6803163057Sariff				    hdac_quirks_tab[k].key);
6804163057Sariff			);
6805163057Sariff			if (inv == 0 && on != NULL)
6806163057Sariff				*on |= hdac_quirks_tab[k].value;
6807163057Sariff			else if (inv != 0 && off != NULL)
6808163057Sariff				*off |= hdac_quirks_tab[k].value;
6809163057Sariff			break;
6810163057Sariff		}
6811163057Sariff		i = j;
6812163057Sariff	}
6813163057Sariff}
6814163057Sariff
6815164614Sariff#ifdef SND_DYNSYSCTL
6816164614Sariffstatic int
6817164614Sariffsysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
6818164614Sariff{
6819164614Sariff	struct hdac_softc *sc;
6820164614Sariff	device_t dev;
6821164614Sariff	uint32_t ctl;
6822164614Sariff	int err, val;
6823164614Sariff
6824164614Sariff	dev = oidp->oid_arg1;
6825182999Smav	sc = device_get_softc(dev);
6826182999Smav	if (sc == NULL)
6827164614Sariff		return (EINVAL);
6828164614Sariff	hdac_lock(sc);
6829164614Sariff	val = sc->polling;
6830164614Sariff	hdac_unlock(sc);
6831170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
6832164614Sariff
6833169277Sariff	if (err != 0 || req->newptr == NULL)
6834164614Sariff		return (err);
6835164614Sariff	if (val < 0 || val > 1)
6836164614Sariff		return (EINVAL);
6837164614Sariff
6838164614Sariff	hdac_lock(sc);
6839164614Sariff	if (val != sc->polling) {
6840182999Smav		if (val == 0) {
6841182999Smav			callout_stop(&sc->poll_hda);
6842164614Sariff			callout_stop(&sc->poll_hdac);
6843169277Sariff			hdac_unlock(sc);
6844182999Smav			callout_drain(&sc->poll_hda);
6845169277Sariff			callout_drain(&sc->poll_hdac);
6846169277Sariff			hdac_lock(sc);
6847164614Sariff			sc->polling = 0;
6848182999Smav			ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
6849182999Smav			ctl |= HDAC_INTCTL_GIE;
6850182999Smav			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
6851164614Sariff		} else {
6852182999Smav			ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
6853182999Smav			ctl &= ~HDAC_INTCTL_GIE;
6854182999Smav			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
6855171141Sariff			hdac_unlock(sc);
6856171141Sariff			taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
6857171141Sariff			hdac_lock(sc);
6858164614Sariff			sc->polling = 1;
6859182999Smav			hdac_poll_reinit(sc);
6860182999Smav			callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
6861164614Sariff		}
6862164614Sariff	}
6863164614Sariff	hdac_unlock(sc);
6864164614Sariff
6865164614Sariff	return (err);
6866164614Sariff}
6867169277Sariff
6868169277Sariffstatic int
6869169277Sariffsysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS)
6870169277Sariff{
6871169277Sariff	struct hdac_softc *sc;
6872169277Sariff	device_t dev;
6873169277Sariff	int err, val;
6874169277Sariff
6875169277Sariff	dev = oidp->oid_arg1;
6876182999Smav	sc = device_get_softc(dev);
6877182999Smav	if (sc == NULL)
6878169277Sariff		return (EINVAL);
6879169277Sariff	hdac_lock(sc);
6880169277Sariff	val = ((uint64_t)sc->poll_ival * 1000) / hz;
6881169277Sariff	hdac_unlock(sc);
6882170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
6883169277Sariff
6884169277Sariff	if (err != 0 || req->newptr == NULL)
6885169277Sariff		return (err);
6886169277Sariff
6887169277Sariff	if (val < 1)
6888169277Sariff		val = 1;
6889169277Sariff	if (val > 5000)
6890169277Sariff		val = 5000;
6891169277Sariff	val = ((uint64_t)val * hz) / 1000;
6892169277Sariff	if (val < 1)
6893169277Sariff		val = 1;
6894169277Sariff	if (val > (hz * 5))
6895169277Sariff		val = hz * 5;
6896169277Sariff
6897169277Sariff	hdac_lock(sc);
6898169277Sariff	sc->poll_ival = val;
6899169277Sariff	hdac_unlock(sc);
6900169277Sariff
6901169277Sariff	return (err);
6902169277Sariff}
6903169277Sariff
6904169277Sariffstatic int
6905171141Sariffsysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)
6906169277Sariff{
6907169277Sariff	struct hdac_softc *sc;
6908182999Smav	struct hdac_codec *codec;
6909169277Sariff	struct hdac_devinfo *devinfo;
6910169277Sariff	struct hdac_widget *w;
6911169277Sariff	device_t dev;
6912182999Smav	uint32_t res, pincap, delay;
6913182999Smav	int codec_index, fg_index;
6914169277Sariff	int i, err, val;
6915169277Sariff	nid_t cad;
6916169277Sariff
6917169277Sariff	dev = oidp->oid_arg1;
6918182999Smav	sc = device_get_softc(dev);
6919182999Smav	if (sc == NULL)
6920169277Sariff		return (EINVAL);
6921169277Sariff	val = 0;
6922170289Sdwmalone	err = sysctl_handle_int(oidp, &val, 0, req);
6923169277Sariff	if (err != 0 || req->newptr == NULL || val == 0)
6924169277Sariff		return (err);
6925182999Smav
6926182999Smav	/* XXX: Temporary. For debugging. */
6927182999Smav	if (val == 100) {
6928182999Smav		hdac_suspend(dev);
6929182999Smav		return (0);
6930182999Smav	} else if (val == 101) {
6931182999Smav		hdac_resume(dev);
6932182999Smav		return (0);
6933182999Smav	}
6934182999Smav
6935169277Sariff	hdac_lock(sc);
6936182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
6937182999Smav		codec = sc->codecs[codec_index];
6938182999Smav		if (codec == NULL)
6939169277Sariff			continue;
6940182999Smav		cad = codec->cad;
6941182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
6942182999Smav			devinfo = &codec->fgs[fg_index];
6943182999Smav			if (devinfo->node_type !=
6944182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
6945182999Smav				continue;
6946182999Smav
6947182999Smav			device_printf(dev, "Dumping AFG cad=%d nid=%d pins:\n",
6948182999Smav			    codec_index, devinfo->nid);
6949182999Smav			for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6950182999Smav					w = hdac_widget_get(devinfo, i);
6951182999Smav				if (w == NULL || w->type !=
6952182999Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6953182999Smav					continue;
6954182999Smav				hdac_dump_pin_config(w, w->wclass.pin.config);
6955182999Smav				pincap = w->wclass.pin.cap;
6956182999Smav				device_printf(dev, "       Caps: %2s %3s %2s %4s %4s",
6957182999Smav				    HDA_PARAM_PIN_CAP_INPUT_CAP(pincap)?"IN":"",
6958182999Smav				    HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap)?"OUT":"",
6959182999Smav				    HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap)?"HP":"",
6960182999Smav				    HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)?"EAPD":"",
6961182999Smav				    HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)?"VREF":"");
6962182999Smav				if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) ||
6963182999Smav				    HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) {
6964182999Smav					if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) {
6965182999Smav						delay = 0;
6966182999Smav						hdac_command(sc,
6967182999Smav						    HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad);
6968182999Smav						do {
6969182999Smav							res = hdac_command(sc,
6970182999Smav							    HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
6971182999Smav							if (res != 0x7fffffff && res != 0xffffffff)
6972182999Smav								break;
6973182999Smav							DELAY(10);
6974182999Smav						} while (++delay < 10000);
6975182999Smav					} else {
6976182999Smav						delay = 0;
6977182999Smav						res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad,
6978182999Smav						    w->nid), cad);
6979182999Smav					}
6980182999Smav					printf(" Sense: 0x%08x", res);
6981182999Smav					if (delay > 0)
6982182999Smav						printf(" delay %dus", delay * 10);
6983182999Smav				}
6984182999Smav				printf("\n");
6985182999Smav			}
6986182999Smav			device_printf(dev,
6987182999Smav			    "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
6988182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
6989182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
6990182999Smav			    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
6991182999Smav			    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
6992182999Smav			    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
6993182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) {
6994182999Smav				device_printf(dev, " GPI:");
6995171141Sariff				res = hdac_command(sc,
6996182999Smav				    HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad);
6997182999Smav				printf(" data=0x%08x", res);
6998182999Smav				res = hdac_command(sc,
6999182999Smav				    HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid),
7000182999Smav				    cad);
7001182999Smav				printf(" wake=0x%08x", res);
7002182999Smav				res = hdac_command(sc,
7003182999Smav				    HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
7004182999Smav				    cad);
7005182999Smav				printf(" unsol=0x%08x", res);
7006182999Smav				res = hdac_command(sc,
7007182999Smav				    HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad);
7008182999Smav				printf(" sticky=0x%08x\n", res);
7009182999Smav			}
7010182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) {
7011182999Smav				device_printf(dev, " GPO:");
7012182999Smav				res = hdac_command(sc,
7013182999Smav				    HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad);
7014182999Smav				printf(" data=0x%08x\n", res);
7015182999Smav			}
7016182999Smav			if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) {
7017182999Smav				device_printf(dev, "GPIO:");
7018182999Smav				res = hdac_command(sc,
7019182999Smav				    HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad);
7020182999Smav				printf(" data=0x%08x", res);
7021182999Smav				res = hdac_command(sc,
7022182999Smav				    HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad);
7023182999Smav				printf(" enable=0x%08x", res);
7024182999Smav				res = hdac_command(sc,
7025182999Smav				    HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad);
7026182999Smav				printf(" direction=0x%08x\n", res);
7027182999Smav				res = hdac_command(sc,
7028182999Smav				    HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad);
7029182999Smav				device_printf(dev, "      wake=0x%08x", res);
7030182999Smav				res = hdac_command(sc,
7031182999Smav				    HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
7032182999Smav				    cad);
7033182999Smav				printf("  unsol=0x%08x", res);
7034182999Smav				res = hdac_command(sc,
7035182999Smav				    HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad);
7036182999Smav				printf("    sticky=0x%08x\n", res);
7037182999Smav			}
7038171141Sariff		}
7039169277Sariff	}
7040169277Sariff	hdac_unlock(sc);
7041169277Sariff	return (0);
7042169277Sariff}
7043164614Sariff#endif
7044164614Sariff
7045163057Sariffstatic void
7046162922Sariffhdac_attach2(void *arg)
7047162922Sariff{
7048182999Smav	struct hdac_codec *codec;
7049162922Sariff	struct hdac_softc *sc;
7050162922Sariff	struct hdac_audio_ctl *ctl;
7051163057Sariff	uint32_t quirks_on, quirks_off;
7052182999Smav	int codec_index, fg_index;
7053182999Smav	int i, pdev, rdev, dmaalloc = 0;
7054182999Smav	struct hdac_devinfo *devinfo;
7055162922Sariff
7056162922Sariff	sc = (struct hdac_softc *)arg;
7057162922Sariff
7058163057Sariff	hdac_config_fetch(sc, &quirks_on, &quirks_off);
7059162922Sariff
7060183097Smav	HDA_BOOTHVERBOSE(
7061182999Smav		device_printf(sc->dev, "HDA Config: on=0x%08x off=0x%08x\n",
7062163057Sariff		    quirks_on, quirks_off);
7063163057Sariff	);
7064163057Sariff
7065162922Sariff	hdac_lock(sc);
7066162922Sariff
7067162922Sariff	/* Remove ourselves from the config hooks */
7068162922Sariff	if (sc->intrhook.ich_func != NULL) {
7069162922Sariff		config_intrhook_disestablish(&sc->intrhook);
7070162922Sariff		sc->intrhook.ich_func = NULL;
7071162922Sariff	}
7072162922Sariff
7073162922Sariff	/* Start the corb and rirb engines */
7074183097Smav	HDA_BOOTHVERBOSE(
7075182999Smav		device_printf(sc->dev, "Starting CORB Engine...\n");
7076162922Sariff	);
7077162922Sariff	hdac_corb_start(sc);
7078183097Smav	HDA_BOOTHVERBOSE(
7079182999Smav		device_printf(sc->dev, "Starting RIRB Engine...\n");
7080162922Sariff	);
7081162922Sariff	hdac_rirb_start(sc);
7082162922Sariff
7083183097Smav	HDA_BOOTHVERBOSE(
7084162922Sariff		device_printf(sc->dev,
7085182999Smav		    "Enabling controller interrupt...\n");
7086162922Sariff	);
7087182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
7088182999Smav	    HDAC_GCTL_UNSOL);
7089182999Smav	if (sc->polling == 0) {
7090164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
7091164614Sariff		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
7092182999Smav	} else {
7093182999Smav		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
7094182999Smav	}
7095162922Sariff	DELAY(1000);
7096162922Sariff
7097183097Smav	HDA_BOOTHVERBOSE(
7098172811Sariff		device_printf(sc->dev,
7099182999Smav		    "Scanning HDA codecs ...\n");
7100162922Sariff	);
7101182999Smav	hdac_scan_codecs(sc);
7102182999Smav
7103182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7104182999Smav		codec = sc->codecs[codec_index];
7105182999Smav		if (codec == NULL)
7106182999Smav			continue;
7107182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7108182999Smav			devinfo = &codec->fgs[fg_index];
7109183019Smav			HDA_BOOTVERBOSE(
7110183019Smav				device_printf(sc->dev, "\n");
7111183097Smav				device_printf(sc->dev,
7112183097Smav				    "Processing %s FG cad=%d nid=%d...\n",
7113183097Smav				    (devinfo->node_type == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) ? "audio":
7114183097Smav				    (devinfo->node_type == HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_MODEM) ? "modem":
7115183097Smav				    "unknown",
7116183097Smav				    devinfo->codec->cad, devinfo->nid);
7117183019Smav			);
7118182999Smav			if (devinfo->node_type !=
7119182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
7120183097Smav				HDA_BOOTHVERBOSE(
7121182999Smav					device_printf(sc->dev,
7122183097Smav					    "Powering down...\n");
7123182999Smav				);
7124182999Smav				hdac_command(sc,
7125182999Smav				    HDA_CMD_SET_POWER_STATE(codec->cad,
7126182999Smav				    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7127182999Smav				    codec->cad);
7128182999Smav				continue;
7129182999Smav			}
7130162922Sariff
7131183097Smav			HDA_BOOTHVERBOSE(
7132183097Smav				device_printf(sc->dev, "Powering up...\n");
7133182999Smav			);
7134182999Smav			hdac_powerup(devinfo);
7135183097Smav			HDA_BOOTHVERBOSE(
7136182999Smav				device_printf(sc->dev, "Parsing audio FG...\n");
7137182999Smav			);
7138182999Smav			hdac_audio_parse(devinfo);
7139183097Smav			HDA_BOOTHVERBOSE(
7140182999Smav				device_printf(sc->dev, "Parsing Ctls...\n");
7141182999Smav			);
7142182999Smav		    	hdac_audio_ctl_parse(devinfo);
7143183097Smav			HDA_BOOTHVERBOSE(
7144182999Smav				device_printf(sc->dev, "Parsing vendor patch...\n");
7145182999Smav			);
7146182999Smav			hdac_vendor_patch_parse(devinfo);
7147182999Smav			devinfo->function.audio.quirks |= quirks_on;
7148182999Smav			devinfo->function.audio.quirks &= ~quirks_off;
7149162922Sariff
7150183097Smav			HDA_BOOTHVERBOSE(
7151182999Smav				device_printf(sc->dev, "Disabling nonaudio...\n");
7152182999Smav			);
7153182999Smav			hdac_audio_disable_nonaudio(devinfo);
7154183097Smav			HDA_BOOTHVERBOSE(
7155182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7156182999Smav			);
7157182999Smav			hdac_audio_disable_useless(devinfo);
7158182999Smav			HDA_BOOTVERBOSE(
7159182999Smav				device_printf(sc->dev, "Patched pins configuration:\n");
7160182999Smav				hdac_dump_pin_configs(devinfo);
7161183097Smav			);
7162183097Smav			HDA_BOOTHVERBOSE(
7163182999Smav				device_printf(sc->dev, "Parsing pin associations...\n");
7164182999Smav			);
7165182999Smav			hdac_audio_as_parse(devinfo);
7166183097Smav			HDA_BOOTHVERBOSE(
7167182999Smav				device_printf(sc->dev, "Building AFG tree...\n");
7168182999Smav			);
7169182999Smav			hdac_audio_build_tree(devinfo);
7170183097Smav			HDA_BOOTHVERBOSE(
7171182999Smav				device_printf(sc->dev, "Disabling unassociated "
7172182999Smav				    "widgets...\n");
7173182999Smav			);
7174182999Smav			hdac_audio_disable_unas(devinfo);
7175183097Smav			HDA_BOOTHVERBOSE(
7176182999Smav				device_printf(sc->dev, "Disabling nonselected "
7177182999Smav				    "inputs...\n");
7178182999Smav			);
7179182999Smav			hdac_audio_disable_notselected(devinfo);
7180183097Smav			HDA_BOOTHVERBOSE(
7181182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7182182999Smav			);
7183182999Smav			hdac_audio_disable_useless(devinfo);
7184183097Smav			HDA_BOOTHVERBOSE(
7185182999Smav				device_printf(sc->dev, "Disabling "
7186182999Smav				    "crossassociatement connections...\n");
7187182999Smav			);
7188182999Smav			hdac_audio_disable_crossas(devinfo);
7189183097Smav			HDA_BOOTHVERBOSE(
7190182999Smav				device_printf(sc->dev, "Disabling useless...\n");
7191182999Smav			);
7192182999Smav			hdac_audio_disable_useless(devinfo);
7193183097Smav			HDA_BOOTHVERBOSE(
7194182999Smav				device_printf(sc->dev, "Binding associations to channels...\n");
7195182999Smav			);
7196182999Smav			hdac_audio_bind_as(devinfo);
7197183097Smav			HDA_BOOTHVERBOSE(
7198182999Smav				device_printf(sc->dev, "Assigning names to signal sources...\n");
7199182999Smav			);
7200182999Smav			hdac_audio_assign_names(devinfo);
7201183097Smav			HDA_BOOTHVERBOSE(
7202182999Smav				device_printf(sc->dev, "Assigning mixers to the tree...\n");
7203182999Smav			);
7204182999Smav			hdac_audio_assign_mixers(devinfo);
7205183097Smav			HDA_BOOTHVERBOSE(
7206182999Smav				device_printf(sc->dev, "Preparing pin controls...\n");
7207182999Smav			);
7208182999Smav			hdac_audio_prepare_pin_ctrl(devinfo);
7209183097Smav			HDA_BOOTHVERBOSE(
7210182999Smav				device_printf(sc->dev, "AFG commit...\n");
7211182999Smav		    	);
7212182999Smav			hdac_audio_commit(devinfo);
7213183097Smav		    	HDA_BOOTHVERBOSE(
7214182999Smav				device_printf(sc->dev, "Ctls commit...\n");
7215182999Smav			);
7216182999Smav			hdac_audio_ctl_commit(devinfo);
7217183097Smav		    	HDA_BOOTHVERBOSE(
7218182999Smav				device_printf(sc->dev, "HP switch init...\n");
7219182999Smav			);
7220182999Smav			hdac_hp_switch_init(devinfo);
7221182999Smav
7222182999Smav			if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) &&
7223182999Smav			    dmaalloc == 0) {
7224182999Smav				if (hdac_dma_alloc(sc, &sc->pos_dma,
7225182999Smav				    (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) {
7226182999Smav					HDA_BOOTVERBOSE(
7227182999Smav						device_printf(sc->dev, "Failed to "
7228182999Smav						    "allocate DMA pos buffer "
7229182999Smav						    "(non-fatal)\n");
7230182999Smav					);
7231182999Smav				} else
7232182999Smav					dmaalloc = 1;
7233182999Smav			}
7234182999Smav
7235182999Smav			i = devinfo->function.audio.playcnt;
7236182999Smav			if (devinfo->function.audio.reccnt > i)
7237182999Smav				i = devinfo->function.audio.reccnt;
7238182999Smav			devinfo->function.audio.devs =
7239182999Smav			    (struct hdac_pcm_devinfo *)malloc(
7240182999Smav			    sizeof(struct hdac_pcm_devinfo) * i,
7241182999Smav			    M_HDAC, M_ZERO | M_NOWAIT);
7242182999Smav			if (devinfo->function.audio.devs == NULL) {
7243182999Smav				device_printf(sc->dev,
7244182999Smav				    "Unable to allocate memory for devices\n");
7245182999Smav				continue;
7246182999Smav			}
7247182999Smav			devinfo->function.audio.num_devs = i;
7248182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
7249182999Smav				devinfo->function.audio.devs[i].index = i;
7250182999Smav				devinfo->function.audio.devs[i].devinfo = devinfo;
7251182999Smav				devinfo->function.audio.devs[i].play = -1;
7252182999Smav				devinfo->function.audio.devs[i].rec = -1;
7253182999Smav			}
7254182999Smav			pdev = 0;
7255182999Smav			rdev = 0;
7256182999Smav			for (i = 0; i < devinfo->function.audio.ascnt; i++) {
7257182999Smav				if (devinfo->function.audio.as[i].enable == 0)
7258182999Smav					continue;
7259182999Smav				if (devinfo->function.audio.as[i].dir ==
7260182999Smav				    HDA_CTL_IN) {
7261182999Smav					devinfo->function.audio.devs[rdev].rec
7262182999Smav					    = devinfo->function.audio.as[i].chan;
7263182999Smav					sc->chans[devinfo->function.audio.as[i].chan].pdevinfo =
7264182999Smav					    &devinfo->function.audio.devs[rdev];
7265182999Smav					rdev++;
7266182999Smav				} else {
7267182999Smav					devinfo->function.audio.devs[pdev].play
7268182999Smav					    = devinfo->function.audio.as[i].chan;
7269182999Smav					sc->chans[devinfo->function.audio.as[i].chan].pdevinfo =
7270182999Smav					    &devinfo->function.audio.devs[pdev];
7271182999Smav					pdev++;
7272182999Smav				}
7273182999Smav			}
7274182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
7275182999Smav				struct hdac_pcm_devinfo *pdevinfo =
7276182999Smav				    &devinfo->function.audio.devs[i];
7277182999Smav				pdevinfo->dev =
7278182999Smav				    device_add_child(sc->dev, "pcm", -1);
7279182999Smav				device_set_ivars(pdevinfo->dev,
7280182999Smav				     (void *)pdevinfo);
7281182999Smav			}
7282182999Smav
7283182999Smav			HDA_BOOTVERBOSE(
7284182999Smav				if (devinfo->function.audio.quirks != 0) {
7285183097Smav					device_printf(sc->dev, "FG config/quirks:");
7286182999Smav					for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
7287182999Smav						if ((devinfo->function.audio.quirks &
7288182999Smav						    hdac_quirks_tab[i].value) ==
7289182999Smav						    hdac_quirks_tab[i].value)
7290182999Smav							printf(" %s", hdac_quirks_tab[i].key);
7291182999Smav					}
7292182999Smav					printf("\n");
7293182999Smav				}
7294182999Smav
7295182999Smav				device_printf(sc->dev, "\n");
7296182999Smav				device_printf(sc->dev, "+-------------------+\n");
7297182999Smav				device_printf(sc->dev, "| DUMPING HDA NODES |\n");
7298182999Smav				device_printf(sc->dev, "+-------------------+\n");
7299182999Smav				hdac_dump_nodes(devinfo);
7300183097Smav			);
7301182999Smav
7302183097Smav			HDA_BOOTHVERBOSE(
7303182999Smav				device_printf(sc->dev, "\n");
7304182999Smav				device_printf(sc->dev, "+------------------------+\n");
7305182999Smav				device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
7306182999Smav				device_printf(sc->dev, "+------------------------+\n");
7307182999Smav				device_printf(sc->dev, "\n");
7308182999Smav				i = 0;
7309182999Smav				while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
7310182999Smav					device_printf(sc->dev, "%3d: nid %3d %s (%s) index %d", i,
7311182999Smav					    (ctl->widget != NULL) ? ctl->widget->nid : -1,
7312182999Smav					    (ctl->ndir == HDA_CTL_IN)?"in ":"out",
7313182999Smav					    (ctl->dir == HDA_CTL_IN)?"in ":"out",
7314182999Smav					    ctl->index);
7315182999Smav					if (ctl->childwidget != NULL)
7316182999Smav						printf(" cnid %3d", ctl->childwidget->nid);
7317182999Smav					else
7318182999Smav						printf("         ");
7319182999Smav					printf(" ossmask=0x%08x\n",
7320182999Smav					    ctl->ossmask);
7321182999Smav					device_printf(sc->dev,
7322182999Smav					    "       mute: %d step: %3d size: %3d off: %3d%s\n",
7323182999Smav					    ctl->mute, ctl->step, ctl->size, ctl->offset,
7324182999Smav					    (ctl->enable == 0) ? " [DISABLED]" :
7325182999Smav					    ((ctl->ossmask == 0) ? " [UNUSED]" : ""));
7326182999Smav				}
7327182999Smav			);
7328182999Smav		}
7329162922Sariff	}
7330182999Smav	hdac_unlock(sc);
7331162922Sariff
7332163057Sariff	HDA_BOOTVERBOSE(
7333182999Smav		device_printf(sc->dev, "\n");
7334162922Sariff	);
7335182999Smav
7336182999Smav	bus_generic_attach(sc->dev);
7337182999Smav
7338182999Smav#ifdef SND_DYNSYSCTL
7339182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7340182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7341182999Smav	    "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
7342182999Smav	    sysctl_hdac_polling, "I", "Enable polling mode");
7343182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7344182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7345182999Smav	    "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
7346182999Smav	    sizeof(sc->dev), sysctl_hdac_polling_interval, "I",
7347182999Smav	    "Controller/Jack Sense polling interval (1-1000 ms)");
7348182999Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
7349182999Smav	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
7350182999Smav	    "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
7351182999Smav	    sysctl_hdac_pindump, "I", "Dump pin states/data");
7352182999Smav#endif
7353182999Smav}
7354182999Smav
7355182999Smav/****************************************************************************
7356182999Smav * int hdac_suspend(device_t)
7357182999Smav *
7358182999Smav * Suspend and power down HDA bus and codecs.
7359182999Smav ****************************************************************************/
7360182999Smavstatic int
7361182999Smavhdac_suspend(device_t dev)
7362182999Smav{
7363182999Smav	struct hdac_softc *sc;
7364182999Smav	struct hdac_codec *codec;
7365182999Smav	struct hdac_devinfo *devinfo;
7366182999Smav	int codec_index, fg_index, i;
7367182999Smav
7368183097Smav	HDA_BOOTHVERBOSE(
7369182999Smav		device_printf(dev, "Suspend...\n");
7370162922Sariff	);
7371182999Smav
7372182999Smav	sc = device_get_softc(dev);
7373182999Smav	hdac_lock(sc);
7374182999Smav
7375183097Smav	HDA_BOOTHVERBOSE(
7376182999Smav		device_printf(dev, "Stop streams...\n");
7377162922Sariff	);
7378182999Smav	for (i = 0; i < sc->num_chans; i++) {
7379182999Smav		if (sc->chans[i].flags & HDAC_CHN_RUNNING) {
7380182999Smav			sc->chans[i].flags |= HDAC_CHN_SUSPEND;
7381182999Smav			hdac_channel_stop(sc, &sc->chans[i]);
7382182999Smav		}
7383182999Smav	}
7384162922Sariff
7385182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7386182999Smav		codec = sc->codecs[codec_index];
7387182999Smav		if (codec == NULL)
7388162922Sariff			continue;
7389182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7390182999Smav			devinfo = &codec->fgs[fg_index];
7391183097Smav			HDA_BOOTHVERBOSE(
7392182999Smav				device_printf(dev,
7393182999Smav				    "Power down FG"
7394182999Smav				    " cad=%d nid=%d to the D3 state...\n",
7395182999Smav				    codec->cad, devinfo->nid);
7396182999Smav			);
7397182999Smav			hdac_command(sc,
7398182999Smav			    HDA_CMD_SET_POWER_STATE(codec->cad,
7399182999Smav			    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7400182999Smav			    codec->cad);
7401162922Sariff		}
7402162922Sariff	}
7403162922Sariff
7404183097Smav	HDA_BOOTHVERBOSE(
7405182999Smav		device_printf(dev, "Reset controller...\n");
7406162922Sariff	);
7407182999Smav	callout_stop(&sc->poll_hda);
7408182999Smav	callout_stop(&sc->poll_hdac);
7409182999Smav	callout_stop(&sc->poll_jack);
7410182999Smav	hdac_reset(sc, 0);
7411182999Smav	hdac_unlock(sc);
7412182999Smav	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
7413182999Smav	callout_drain(&sc->poll_hda);
7414182999Smav	callout_drain(&sc->poll_hdac);
7415182999Smav	callout_drain(&sc->poll_jack);
7416162922Sariff
7417183097Smav	HDA_BOOTHVERBOSE(
7418182999Smav		device_printf(dev, "Suspend done\n");
7419162922Sariff	);
7420182999Smav
7421182999Smav	return (0);
7422182999Smav}
7423182999Smav
7424182999Smav/****************************************************************************
7425182999Smav * int hdac_resume(device_t)
7426182999Smav *
7427182999Smav * Powerup and restore HDA bus and codecs state.
7428182999Smav ****************************************************************************/
7429182999Smavstatic int
7430182999Smavhdac_resume(device_t dev)
7431182999Smav{
7432182999Smav	struct hdac_softc *sc;
7433182999Smav	struct hdac_codec *codec;
7434182999Smav	struct hdac_devinfo *devinfo;
7435182999Smav	int codec_index, fg_index, i;
7436182999Smav
7437183097Smav	HDA_BOOTHVERBOSE(
7438182999Smav		device_printf(dev, "Resume...\n");
7439162922Sariff	);
7440162922Sariff
7441182999Smav	sc = device_get_softc(dev);
7442182999Smav	hdac_lock(sc);
7443182999Smav
7444182999Smav	/* Quiesce everything */
7445183097Smav	HDA_BOOTHVERBOSE(
7446182999Smav		device_printf(dev, "Reset controller...\n");
7447162922Sariff	);
7448182999Smav	hdac_reset(sc, 1);
7449182999Smav
7450182999Smav	/* Initialize the CORB and RIRB */
7451182999Smav	hdac_corb_init(sc);
7452182999Smav	hdac_rirb_init(sc);
7453182999Smav
7454182999Smav	/* Start the corb and rirb engines */
7455183097Smav	HDA_BOOTHVERBOSE(
7456182999Smav		device_printf(dev, "Starting CORB Engine...\n");
7457162922Sariff	);
7458182999Smav	hdac_corb_start(sc);
7459183097Smav	HDA_BOOTHVERBOSE(
7460182999Smav		device_printf(dev, "Starting RIRB Engine...\n");
7461162922Sariff	);
7462182999Smav	hdac_rirb_start(sc);
7463163057Sariff
7464183097Smav	HDA_BOOTHVERBOSE(
7465182999Smav		device_printf(dev,
7466182999Smav		    "Enabling controller interrupt...\n");
7467162922Sariff	);
7468182999Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
7469182999Smav	    HDAC_GCTL_UNSOL);
7470182999Smav	if (sc->polling == 0) {
7471182999Smav		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
7472182999Smav		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
7473182999Smav	} else {
7474182999Smav		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
7475182999Smav	}
7476182999Smav	DELAY(1000);
7477162922Sariff
7478182999Smav	for (codec_index = 0; codec_index < HDAC_CODEC_MAX; codec_index++) {
7479182999Smav		codec = sc->codecs[codec_index];
7480182999Smav		if (codec == NULL)
7481182999Smav			continue;
7482182999Smav		for (fg_index = 0; fg_index < codec->num_fgs; fg_index++) {
7483182999Smav			devinfo = &codec->fgs[fg_index];
7484182999Smav			if (devinfo->node_type !=
7485182999Smav			    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
7486183097Smav				HDA_BOOTHVERBOSE(
7487182999Smav					device_printf(dev,
7488182999Smav					    "Power down unsupported non-audio FG"
7489182999Smav					    " cad=%d nid=%d to the D3 state...\n",
7490182999Smav					    codec->cad, devinfo->nid);
7491182999Smav				);
7492182999Smav				hdac_command(sc,
7493182999Smav				    HDA_CMD_SET_POWER_STATE(codec->cad,
7494182999Smav				    devinfo->nid, HDA_CMD_POWER_STATE_D3),
7495182999Smav				    codec->cad);
7496182999Smav				continue;
7497182999Smav			}
7498162922Sariff
7499183097Smav			HDA_BOOTHVERBOSE(
7500182999Smav				device_printf(dev,
7501182999Smav				    "Power up audio FG cad=%d nid=%d...\n",
7502182999Smav				    devinfo->codec->cad, devinfo->nid);
7503182999Smav			);
7504182999Smav			hdac_powerup(devinfo);
7505183097Smav			HDA_BOOTHVERBOSE(
7506182999Smav				device_printf(dev, "AFG commit...\n");
7507182999Smav		    	);
7508182999Smav			hdac_audio_commit(devinfo);
7509183097Smav		    	HDA_BOOTHVERBOSE(
7510182999Smav				device_printf(dev, "Ctls commit...\n");
7511182999Smav			);
7512182999Smav			hdac_audio_ctl_commit(devinfo);
7513183097Smav		    	HDA_BOOTHVERBOSE(
7514182999Smav				device_printf(dev, "HP switch init...\n");
7515182999Smav			);
7516182999Smav			hdac_hp_switch_init(devinfo);
7517182999Smav
7518182999Smav			hdac_unlock(sc);
7519182999Smav			for (i = 0; i < devinfo->function.audio.num_devs; i++) {
7520182999Smav				struct hdac_pcm_devinfo *pdevinfo =
7521182999Smav				    &devinfo->function.audio.devs[i];
7522183097Smav				HDA_BOOTHVERBOSE(
7523182999Smav					device_printf(pdevinfo->dev,
7524182999Smav					    "OSS mixer reinitialization...\n");
7525182999Smav				);
7526182999Smav				if (mixer_reinit(pdevinfo->dev) == -1)
7527182999Smav					device_printf(pdevinfo->dev,
7528182999Smav					    "unable to reinitialize the mixer\n");
7529182999Smav			}
7530182999Smav			hdac_lock(sc);
7531182999Smav		}
7532169277Sariff	}
7533169277Sariff
7534183097Smav	HDA_BOOTHVERBOSE(
7535182999Smav		device_printf(dev, "Start streams...\n");
7536163057Sariff	);
7537182999Smav	for (i = 0; i < sc->num_chans; i++) {
7538182999Smav		if (sc->chans[i].flags & HDAC_CHN_SUSPEND) {
7539182999Smav			sc->chans[i].flags &= ~HDAC_CHN_SUSPEND;
7540182999Smav			hdac_channel_start(sc, &sc->chans[i]);
7541182999Smav		}
7542182999Smav	}
7543162922Sariff
7544182999Smav	hdac_unlock(sc);
7545182999Smav
7546183097Smav	HDA_BOOTHVERBOSE(
7547182999Smav		device_printf(dev, "Resume done\n");
7548162922Sariff	);
7549164614Sariff
7550182999Smav	return (0);
7551162922Sariff}
7552162922Sariff/****************************************************************************
7553162922Sariff * int hdac_detach(device_t)
7554162922Sariff *
7555162922Sariff * Detach and free up resources utilized by the hdac device.
7556162922Sariff ****************************************************************************/
7557162922Sariffstatic int
7558162922Sariffhdac_detach(device_t dev)
7559162922Sariff{
7560182999Smav	struct hdac_softc *sc;
7561182999Smav	device_t *devlist = NULL;
7562182999Smav	int i, devcount;
7563162922Sariff
7564182999Smav	sc = device_get_softc(dev);
7565162922Sariff
7566182999Smav	device_get_children(dev, &devlist, &devcount);
7567182999Smav	for (i = 0; devlist != NULL && i < devcount; i++)
7568182999Smav		device_delete_child(dev, devlist[i]);
7569182999Smav	if (devlist != NULL)
7570182999Smav		free(devlist, M_TEMP);
7571162922Sariff
7572163057Sariff	hdac_release_resources(sc);
7573162922Sariff
7574162922Sariff	return (0);
7575162922Sariff}
7576162922Sariff
7577184095Smavstatic int
7578184095Smavhdac_print_child(device_t dev, device_t child)
7579184095Smav{
7580184095Smav	struct hdac_pcm_devinfo *pdevinfo =
7581184095Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(child);
7582184095Smav	int retval;
7583184095Smav
7584184095Smav	retval = bus_print_child_header(dev, child);
7585184095Smav	retval += printf(" at cad %d nid %d",
7586184095Smav	    pdevinfo->devinfo->codec->cad, pdevinfo->devinfo->nid);
7587184095Smav	retval += bus_print_child_footer(dev, child);
7588184095Smav
7589184095Smav	return (retval);
7590184095Smav}
7591184095Smav
7592162922Sariffstatic device_method_t hdac_methods[] = {
7593162922Sariff	/* device interface */
7594162922Sariff	DEVMETHOD(device_probe,		hdac_probe),
7595162922Sariff	DEVMETHOD(device_attach,	hdac_attach),
7596162922Sariff	DEVMETHOD(device_detach,	hdac_detach),
7597182999Smav	DEVMETHOD(device_suspend,	hdac_suspend),
7598182999Smav	DEVMETHOD(device_resume,	hdac_resume),
7599184095Smav	/* Bus interface */
7600184095Smav	DEVMETHOD(bus_print_child,	hdac_print_child),
7601162922Sariff	{ 0, 0 }
7602162922Sariff};
7603162922Sariff
7604162922Sariffstatic driver_t hdac_driver = {
7605182999Smav	"hdac",
7606162922Sariff	hdac_methods,
7607182999Smav	sizeof(struct hdac_softc),
7608162922Sariff};
7609162922Sariff
7610182999Smavstatic devclass_t hdac_devclass;
7611182999Smav
7612182999SmavDRIVER_MODULE(snd_hda, pci, hdac_driver, hdac_devclass, 0, 0);
7613162922SariffMODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
7614162922SariffMODULE_VERSION(snd_hda, 1);
7615182999Smav
7616182999Smavstatic int
7617182999Smavhdac_pcm_probe(device_t dev)
7618182999Smav{
7619182999Smav	struct hdac_pcm_devinfo *pdevinfo =
7620182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
7621182999Smav	char buf[128];
7622182999Smav
7623184095Smav	snprintf(buf, sizeof(buf), "HDA %s PCM #%d",
7624182999Smav	    hdac_codec_name(pdevinfo->devinfo->codec),
7625182999Smav	    pdevinfo->index);
7626182999Smav	device_set_desc_copy(dev, buf);
7627182999Smav	return (0);
7628182999Smav}
7629182999Smav
7630182999Smavstatic int
7631182999Smavhdac_pcm_attach(device_t dev)
7632182999Smav{
7633182999Smav	struct hdac_pcm_devinfo *pdevinfo =
7634182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
7635182999Smav	struct hdac_softc *sc = pdevinfo->devinfo->codec->sc;
7636182999Smav	char status[SND_STATUSLEN];
7637182999Smav	int i;
7638182999Smav
7639182999Smav	pdevinfo->chan_size = pcm_getbuffersize(dev,
7640182999Smav	    HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
7641182999Smav
7642182999Smav	HDA_BOOTVERBOSE(
7643182999Smav		device_printf(dev, "+--------------------------------------+\n");
7644182999Smav		device_printf(dev, "| DUMPING PCM Playback/Record Channels |\n");
7645182999Smav		device_printf(dev, "+--------------------------------------+\n");
7646182999Smav		hdac_dump_pcmchannels(pdevinfo);
7647182999Smav		device_printf(dev, "\n");
7648182999Smav		device_printf(dev, "+--------------------------------+\n");
7649182999Smav		device_printf(dev, "| DUMPING Playback/Record Pathes |\n");
7650182999Smav		device_printf(dev, "+--------------------------------+\n");
7651182999Smav		hdac_dump_dac(pdevinfo);
7652182999Smav		hdac_dump_adc(pdevinfo);
7653182999Smav		hdac_dump_mix(pdevinfo);
7654182999Smav		device_printf(dev, "\n");
7655182999Smav		device_printf(dev, "+-------------------------+\n");
7656182999Smav		device_printf(dev, "| DUMPING Volume Controls |\n");
7657182999Smav		device_printf(dev, "+-------------------------+\n");
7658182999Smav		hdac_dump_ctls(pdevinfo, "Master Volume", SOUND_MASK_VOLUME);
7659182999Smav		hdac_dump_ctls(pdevinfo, "PCM Volume", SOUND_MASK_PCM);
7660182999Smav		hdac_dump_ctls(pdevinfo, "CD Volume", SOUND_MASK_CD);
7661182999Smav		hdac_dump_ctls(pdevinfo, "Microphone Volume", SOUND_MASK_MIC);
7662182999Smav		hdac_dump_ctls(pdevinfo, "Microphone2 Volume", SOUND_MASK_MONITOR);
7663182999Smav		hdac_dump_ctls(pdevinfo, "Line-in Volume", SOUND_MASK_LINE);
7664182999Smav		hdac_dump_ctls(pdevinfo, "Speaker/Beep Volume", SOUND_MASK_SPEAKER);
7665182999Smav		hdac_dump_ctls(pdevinfo, "Recording Level", SOUND_MASK_RECLEV);
7666182999Smav		hdac_dump_ctls(pdevinfo, "Input Mix Level", SOUND_MASK_IMIX);
7667182999Smav		hdac_dump_ctls(pdevinfo, NULL, 0);
7668182999Smav		device_printf(dev, "\n");
7669182999Smav	);
7670182999Smav
7671182999Smav	if (resource_int_value(device_get_name(dev),
7672182999Smav	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
7673182999Smav		i &= HDA_BLK_ALIGN;
7674182999Smav		if (i < HDA_BLK_MIN)
7675182999Smav			i = HDA_BLK_MIN;
7676182999Smav		pdevinfo->chan_blkcnt = pdevinfo->chan_size / i;
7677182999Smav		i = 0;
7678182999Smav		while (pdevinfo->chan_blkcnt >> i)
7679182999Smav			i++;
7680182999Smav		pdevinfo->chan_blkcnt = 1 << (i - 1);
7681182999Smav		if (pdevinfo->chan_blkcnt < HDA_BDL_MIN)
7682182999Smav			pdevinfo->chan_blkcnt = HDA_BDL_MIN;
7683182999Smav		else if (pdevinfo->chan_blkcnt > HDA_BDL_MAX)
7684182999Smav			pdevinfo->chan_blkcnt = HDA_BDL_MAX;
7685182999Smav	} else
7686182999Smav		pdevinfo->chan_blkcnt = HDA_BDL_DEFAULT;
7687182999Smav
7688182999Smav	/*
7689182999Smav	 * We don't register interrupt handler with snd_setup_intr
7690182999Smav	 * in pcm device. Mark pcm device as MPSAFE manually.
7691182999Smav	 */
7692182999Smav	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
7693182999Smav
7694183097Smav	HDA_BOOTHVERBOSE(
7695182999Smav		device_printf(dev, "OSS mixer initialization...\n");
7696182999Smav	);
7697182999Smav	if (mixer_init(dev, &hdac_audio_ctl_ossmixer_class, pdevinfo) != 0)
7698182999Smav		device_printf(dev, "Can't register mixer\n");
7699182999Smav
7700183097Smav	HDA_BOOTHVERBOSE(
7701182999Smav		device_printf(dev, "Registering PCM channels...\n");
7702182999Smav	);
7703182999Smav	if (pcm_register(dev, pdevinfo, (pdevinfo->play >= 0)?1:0,
7704182999Smav	    (pdevinfo->rec >= 0)?1:0) != 0)
7705182999Smav		device_printf(dev, "Can't register PCM\n");
7706182999Smav
7707182999Smav	pdevinfo->registered++;
7708182999Smav
7709182999Smav	if (pdevinfo->play >= 0)
7710182999Smav		pcm_addchan(dev, PCMDIR_PLAY, &hdac_channel_class, pdevinfo);
7711182999Smav	if (pdevinfo->rec >= 0)
7712182999Smav		pcm_addchan(dev, PCMDIR_REC, &hdac_channel_class, pdevinfo);
7713182999Smav
7714184095Smav	snprintf(status, SND_STATUSLEN, "at cad %d nid %d on %s %s",
7715184095Smav	    pdevinfo->devinfo->codec->cad, pdevinfo->devinfo->nid,
7716184095Smav	    device_get_nameunit(sc->dev), PCM_KLDSTRING(snd_hda));
7717182999Smav	pcm_setstatus(dev, status);
7718182999Smav
7719182999Smav	return (0);
7720182999Smav}
7721182999Smav
7722182999Smavstatic int
7723182999Smavhdac_pcm_detach(device_t dev)
7724182999Smav{
7725182999Smav	struct hdac_pcm_devinfo *pdevinfo =
7726182999Smav	    (struct hdac_pcm_devinfo *)device_get_ivars(dev);
7727182999Smav	int err;
7728182999Smav
7729182999Smav	if (pdevinfo->registered > 0) {
7730182999Smav		err = pcm_unregister(dev);
7731182999Smav		if (err != 0)
7732182999Smav			return (err);
7733182999Smav	}
7734182999Smav
7735182999Smav	return (0);
7736182999Smav}
7737182999Smav
7738182999Smavstatic device_method_t hdac_pcm_methods[] = {
7739182999Smav	/* device interface */
7740182999Smav	DEVMETHOD(device_probe,		hdac_pcm_probe),
7741182999Smav	DEVMETHOD(device_attach,	hdac_pcm_attach),
7742182999Smav	DEVMETHOD(device_detach,	hdac_pcm_detach),
7743182999Smav	{ 0, 0 }
7744182999Smav};
7745182999Smav
7746182999Smavstatic driver_t hdac_pcm_driver = {
7747182999Smav	"pcm",
7748182999Smav	hdac_pcm_methods,
7749182999Smav	PCM_SOFTC_SIZE,
7750182999Smav};
7751182999Smav
7752182999SmavDRIVER_MODULE(snd_hda_pcm, hdac, hdac_pcm_driver, pcm_devclass, 0, 0);
7753182999Smav
7754