hdac.c revision 178155
1168404Spjd/*-
2168404Spjd * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
3168404Spjd * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
4168404Spjd * All rights reserved.
5168404Spjd *
6168404Spjd * Redistribution and use in source and binary forms, with or without
7168404Spjd * modification, are permitted provided that the following conditions
8168404Spjd * are met:
9168404Spjd * 1. Redistributions of source code must retain the above copyright
10168404Spjd *    notice, this list of conditions and the following disclaimer.
11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
12168404Spjd *    notice, this list of conditions and the following disclaimer in the
13168404Spjd *    documentation and/or other materials provided with the distribution.
14168404Spjd *
15168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23277826Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24268123Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25260835Sdelphij * SUCH DAMAGE.
26268085Sdelphij */
27168404Spjd
28168404Spjd/*
29168404Spjd * Intel High Definition Audio (Controller) driver for FreeBSD. Be advised
30168404Spjd * that this driver still in its early stage, and possible of rewrite are
31168404Spjd * pretty much guaranteed. There are supposedly several distinct parent/child
32168404Spjd * busses to make this "perfect", but as for now and for the sake of
33168404Spjd * simplicity, everything is gobble up within single source.
34168404Spjd *
35168404Spjd * List of subsys:
36168404Spjd *     1) HDA Controller support
37168404Spjd *     2) HDA Codecs support, which may include
38168404Spjd *        - HDA
39168404Spjd *        - Modem
40168404Spjd *        - HDMI
41168404Spjd *     3) Widget parser - the real magic of why this driver works on so
42168404Spjd *        many hardwares with minimal vendor specific quirk. The original
43168404Spjd *        parser was written using Ruby and can be found at
44168404Spjd *        http://people.freebsd.org/~ariff/HDA/parser.rb . This crude
45168404Spjd *        ruby parser take the verbose dmesg dump as its input. Refer to
46168404Spjd *        http://www.microsoft.com/whdc/device/audio/default.mspx for various
47168404Spjd *        interesting documents, especially UAA (Universal Audio Architecture).
48168404Spjd *     4) Possible vendor specific support.
49168404Spjd *        (snd_hda_intel, snd_hda_ati, etc..)
50168404Spjd *
51185029Spjd * Thanks to Ahmad Ubaidah Omar @ Defenxis Sdn. Bhd. for the
52185029Spjd * Compaq V3000 with Conexant HDA.
53168404Spjd *
54168404Spjd *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55168404Spjd *    *                                                                 *
56168404Spjd *    *        This driver is a collaborative effort made by:           *
57185029Spjd *    *                                                                 *
58168404Spjd *    *          Stephane E. Potvin <sepotvin@videotron.ca>             *
59168404Spjd *    *               Andrea Bittau <a.bittau@cs.ucl.ac.uk>             *
60168404Spjd *    *               Wesley Morgan <morganw@chemikals.org>             *
61168404Spjd *    *              Daniel Eischen <deischen@FreeBSD.org>              *
62251631Sdelphij *    *             Maxime Guillaud <bsd-ports@mguillaud.net>           *
63168404Spjd *    *              Ariff Abdullah <ariff@FreeBSD.org>                 *
64168404Spjd *    *                                                                 *
65168404Spjd *    *   ....and various people from freebsd-multimedia@FreeBSD.org    *
66251631Sdelphij *    *                                                                 *
67168404Spjd *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
68168404Spjd */
69168404Spjd
70168404Spjd#include <dev/sound/pcm/sound.h>
71168404Spjd#include <dev/pci/pcireg.h>
72168404Spjd#include <dev/pci/pcivar.h>
73168404Spjd
74168404Spjd#include <sys/ctype.h>
75168404Spjd#include <sys/taskqueue.h>
76168404Spjd
77168404Spjd#include <dev/sound/pci/hda/hdac_private.h>
78168404Spjd#include <dev/sound/pci/hda/hdac_reg.h>
79185029Spjd#include <dev/sound/pci/hda/hda_reg.h>
80168404Spjd#include <dev/sound/pci/hda/hdac.h>
81251631Sdelphij
82168404Spjd#include "mixer_if.h"
83168404Spjd
84168404Spjd#define HDA_DRV_TEST_REV	"20080412_0051"
85168404Spjd#define HDA_WIDGET_PARSER_REV	1
86168404Spjd
87168404SpjdSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 178155 2008-04-12 15:07:32Z ariff $");
88168404Spjd
89168404Spjd#define HDA_BOOTVERBOSE(stmt)	do {			\
90168404Spjd	if (bootverbose != 0 || snd_verbose > 3) {	\
91168404Spjd		stmt					\
92168404Spjd	}						\
93168404Spjd} while(0)
94168404Spjd
95168404Spjd#if 1
96168404Spjd#undef HDAC_INTR_EXTRA
97168404Spjd#define HDAC_INTR_EXTRA		1
98168404Spjd#endif
99168404Spjd
100168404Spjd#define hdac_lock(sc)		snd_mtxlock((sc)->lock)
101168404Spjd#define hdac_unlock(sc)		snd_mtxunlock((sc)->lock)
102168404Spjd#define hdac_lockassert(sc)	snd_mtxassert((sc)->lock)
103168404Spjd#define hdac_lockowned(sc)	mtx_owned((sc)->lock)
104168404Spjd
105168404Spjd#undef HDAC_MSI_ENABLED
106168404Spjd#if __FreeBSD_version >= 700026 ||					\
107168404Spjd    (__FreeBSD_version < 700000 && __FreeBSD_version >= 602106)
108268858Sdelphij#define HDAC_MSI_ENABLED	1
109168404Spjd#endif
110168404Spjd
111168404Spjd#define HDA_FLAG_MATCH(fl, v)	(((fl) & (v)) == (v))
112168404Spjd#define HDA_DEV_MATCH(fl, v)	((fl) == (v) || \
113185029Spjd				(fl) == 0xffffffff || \
114286570Smav				(((fl) & 0xffff0000) == 0xffff0000 && \
115185029Spjd				((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \
116185029Spjd				(((fl) & 0x0000ffff) == 0x0000ffff && \
117185029Spjd				((fl) & 0xffff0000) == ((v) & 0xffff0000)))
118185029Spjd#define HDA_MATCH_ALL		0xffffffff
119185029Spjd#define HDAC_INVALID		0xffffffff
120185029Spjd
121168404Spjd/* Default controller / jack sense poll: 250ms */
122168404Spjd#define HDAC_POLL_INTERVAL	max(hz >> 2, 1)
123168404Spjd
124168404Spjd/*
125251478Sdelphij * Make room for possible 4096 playback/record channels, in 100 years to come.
126168404Spjd */
127168404Spjd#define HDAC_TRIGGER_NONE	0x00000000
128168404Spjd#define HDAC_TRIGGER_PLAY	0x00000fff
129185029Spjd#define HDAC_TRIGGER_REC	0x00fff000
130219089Spjd#define HDAC_TRIGGER_UNSOL	0x80000000
131258632Savg
132168404Spjd#define HDA_MODEL_CONSTRUCT(vendor, model)	\
133168404Spjd		(((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff))
134168404Spjd
135168404Spjd/* Controller models */
136168404Spjd
137248572Ssmh/* Intel */
138219089Spjd#define INTEL_VENDORID		0x8086
139168404Spjd#define HDA_INTEL_82801F	HDA_MODEL_CONSTRUCT(INTEL, 0x2668)
140168404Spjd#define HDA_INTEL_63XXESB	HDA_MODEL_CONSTRUCT(INTEL, 0x269a)
141191902Skmacy#define HDA_INTEL_82801G	HDA_MODEL_CONSTRUCT(INTEL, 0x27d8)
142272483Ssmh#define HDA_INTEL_82801H	HDA_MODEL_CONSTRUCT(INTEL, 0x284b)
143191902Skmacy#define HDA_INTEL_82801I	HDA_MODEL_CONSTRUCT(INTEL, 0x293e)
144240133Smm#define HDA_INTEL_ALL		HDA_MODEL_CONSTRUCT(INTEL, 0xffff)
145240133Smm
146240133Smm/* Nvidia */
147240133Smm#define NVIDIA_VENDORID		0x10de
148240133Smm#define HDA_NVIDIA_MCP51	HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c)
149240133Smm#define HDA_NVIDIA_MCP55	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371)
150240133Smm#define HDA_NVIDIA_MCP61_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4)
151240133Smm#define HDA_NVIDIA_MCP61_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0)
152168404Spjd#define HDA_NVIDIA_MCP65_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a)
153168404Spjd#define HDA_NVIDIA_MCP65_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b)
154168404Spjd#define HDA_NVIDIA_MCP67_1	HDA_MODEL_CONSTRUCT(NVIDIA, 0x055c)
155168404Spjd#define HDA_NVIDIA_MCP67_2	HDA_MODEL_CONSTRUCT(NVIDIA, 0x055d)
156286625Smav#define HDA_NVIDIA_ALL		HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff)
157168404Spjd
158258632Savg/* ATI */
159258632Savg#define ATI_VENDORID		0x1002
160258632Savg#define HDA_ATI_SB450		HDA_MODEL_CONSTRUCT(ATI, 0x437b)
161258632Savg#define HDA_ATI_SB600		HDA_MODEL_CONSTRUCT(ATI, 0x4383)
162258632Savg#define HDA_ATI_ALL		HDA_MODEL_CONSTRUCT(ATI, 0xffff)
163258632Savg
164168404Spjd/* VIA */
165168404Spjd#define VIA_VENDORID		0x1106
166168404Spjd#define HDA_VIA_VT82XX		HDA_MODEL_CONSTRUCT(VIA, 0x3288)
167208373Smm#define HDA_VIA_ALL		HDA_MODEL_CONSTRUCT(VIA, 0xffff)
168208373Smm
169208373Smm/* SiS */
170208373Smm#define SIS_VENDORID		0x1039
171286625Smav#define HDA_SIS_966		HDA_MODEL_CONSTRUCT(SIS, 0x7502)
172208373Smm#define HDA_SIS_ALL		HDA_MODEL_CONSTRUCT(SIS, 0xffff)
173168404Spjd
174286625Smav/* OEM/subvendors */
175286625Smav
176286625Smav/* Intel */
177286625Smav#define INTEL_D101GGC_SUBVENDOR	HDA_MODEL_CONSTRUCT(INTEL, 0xd600)
178286625Smav
179286625Smav/* HP/Compaq */
180286625Smav#define HP_VENDORID		0x103c
181286625Smav#define HP_V3000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b5)
182286625Smav#define HP_NX7400_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a2)
183286625Smav#define HP_NX6310_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30aa)
184286625Smav#define HP_NX6325_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b0)
185286625Smav#define HP_XW4300_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3013)
186168404Spjd#define HP_3010_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3010)
187168404Spjd#define HP_DV5000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a5)
188168404Spjd#define HP_DC7700S_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x2801)
189168404Spjd#define HP_DC7700_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x2802)
190168404Spjd#define HP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0xffff)
191258632Savg/* What is wrong with XN 2563 anyway? (Got the picture ?) */
192258632Savg#define HP_NX6325_SUBVENDORX	0x103c30b0
193258632Savg
194258632Savg/* Dell */
195258632Savg#define DELL_VENDORID		0x1028
196208373Smm#define DELL_D820_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01cc)
197194043Skmacy#define DELL_V1500_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x0228)
198168404Spjd#define DELL_I1300_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01c9)
199168404Spjd#define DELL_XPSM1210_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01d7)
200185029Spjd#define DELL_OPLX745_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01da)
201185029Spjd#define DELL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0xffff)
202185029Spjd
203185029Spjd/* Clevo */
204185029Spjd#define CLEVO_VENDORID		0x1558
205185029Spjd#define CLEVO_D900T_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0x0900)
206185029Spjd#define CLEVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0xffff)
207275780Sdelphij
208208373Smm/* Acer */
209208373Smm#define ACER_VENDORID		0x1025
210208373Smm#define ACER_A5050_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x010f)
211242845Sdelphij#define ACER_A4520_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0127)
212269230Sdelphij#define ACER_A4710_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x012f)
213272483Ssmh#define ACER_3681WXM_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x0110)
214185029Spjd#define ACER_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0xffff)
215270759Ssmh
216275748Sdelphij/* Asus */
217270759Ssmh#define ASUS_VENDORID		0x1043
218270759Ssmh#define ASUS_A8X_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1153)
219270759Ssmh#define ASUS_U5F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
220270759Ssmh#define ASUS_W6F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
221270759Ssmh#define ASUS_A7M_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1323)
222270759Ssmh#define ASUS_F3JC_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1338)
223272483Ssmh#define ASUS_G2K_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1339)
224270759Ssmh#define ASUS_A7T_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x13c2)
225270759Ssmh#define ASUS_W2J_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1971)
226270759Ssmh#define ASUS_M5200_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
227270759Ssmh#define ASUS_P1AH2_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
228185029Spjd#define ASUS_M2NPVMX_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
229275780Sdelphij#define ASUS_M2V_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81e7)
230273026Sdelphij#define ASUS_P5BWD_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81ec)
231168473Spjd#define ASUS_M2N_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x8234)
232217367Smdf#define ASUS_A8NVMCSM_SUBVENDOR	HDA_MODEL_CONSTRUCT(NVIDIA, 0xcb84)
233168473Spjd#define ASUS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
234217367Smdf
235168473Spjd/* IBM / Lenovo */
236269230Sdelphij#define IBM_VENDORID		0x1014
237269230Sdelphij#define IBM_M52_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0x02f6)
238269230Sdelphij#define IBM_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0xffff)
239273026Sdelphij
240273026Sdelphij/* Lenovo */
241273026Sdelphij#define LENOVO_VENDORID		0x17aa
242273026Sdelphij#define LENOVO_3KN100_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x2066)
243270759Ssmh#define LENOVO_TCA55_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x1015)
244270759Ssmh#define LENOVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0xffff)
245270759Ssmh
246270759Ssmh/* Samsung */
247270759Ssmh#define SAMSUNG_VENDORID	0x144d
248270759Ssmh#define SAMSUNG_Q1_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027)
249270759Ssmh#define SAMSUNG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff)
250270759Ssmh
251168404Spjd/* Medion ? */
252270759Ssmh#define MEDION_VENDORID			0x161f
253270759Ssmh#define MEDION_MD95257_SUBVENDOR	HDA_MODEL_CONSTRUCT(MEDION, 0x203d)
254270759Ssmh#define MEDION_ALL_SUBVENDOR		HDA_MODEL_CONSTRUCT(MEDION, 0xffff)
255270759Ssmh
256270759Ssmh/* Apple Computer Inc. */
257270759Ssmh#define APPLE_VENDORID		0x106b
258270759Ssmh#define APPLE_MB3_SUBVENDOR	HDA_MODEL_CONSTRUCT(APPLE, 0x00a1)
259270759Ssmh
260270759Ssmh/*
261270759Ssmh * Apple Intel MacXXXX seems using Sigmatel codec/vendor id
262270759Ssmh * instead of their own, which is beyond my comprehension
263272483Ssmh * (see HDA_CODEC_STAC9221 below).
264270759Ssmh */
265272483Ssmh#define APPLE_INTEL_MAC		0x76808384
266270759Ssmh
267270759Ssmh/* LG Electronics */
268270759Ssmh#define LG_VENDORID		0x1854
269270759Ssmh#define LG_LW20_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0x0018)
270270759Ssmh#define LG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0xffff)
271270759Ssmh
272275748Sdelphij/* Fujitsu Siemens */
273275748Sdelphij#define FS_VENDORID		0x1734
274275748Sdelphij#define FS_PA1510_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10b8)
275275748Sdelphij#define FS_SI1848_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10cd)
276275748Sdelphij#define FS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0xffff)
277275748Sdelphij
278275748Sdelphij/* Fujitsu Limited */
279275748Sdelphij#define FL_VENDORID		0x10cf
280275748Sdelphij#define FL_S7020D_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0x1326)
281272483Ssmh#define FL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FL, 0xffff)
282270759Ssmh
283168404Spjd/* Toshiba */
284185029Spjd#define TOSHIBA_VENDORID	0x1179
285168404Spjd#define TOSHIBA_U200_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001)
286168404Spjd#define TOSHIBA_A135_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xff01)
287168404Spjd#define TOSHIBA_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff)
288168404Spjd
289168404Spjd/* Micro-Star International (MSI) */
290185029Spjd#define MSI_VENDORID		0x1462
291185029Spjd#define MSI_MS1034_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x0349)
292185029Spjd#define MSI_MS034A_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x034a)
293185029Spjd#define MSI_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0xffff)
294185029Spjd
295185029Spjd/* Giga-Byte Technology */
296185029Spjd#define GB_VENDORID		0x1458
297185029Spjd#define GB_G33S2H_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xa022)
298168404Spjd#define GP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(GB, 0xffff)
299168404Spjd
300168404Spjd/* Uniwill ? */
301168404Spjd#define UNIWILL_VENDORID	0x1584
302168404Spjd#define UNIWILL_9075_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9075)
303168404Spjd#define UNIWILL_9080_SUBVENDOR	HDA_MODEL_CONSTRUCT(UNIWILL, 0x9080)
304168404Spjd
305185029Spjd
306185029Spjd/* Misc constants.. */
307185029Spjd#define HDA_AMP_MUTE_DEFAULT	(0xffffffff)
308185029Spjd#define HDA_AMP_MUTE_NONE	(0)
309185029Spjd#define HDA_AMP_MUTE_LEFT	(1 << 0)
310185029Spjd#define HDA_AMP_MUTE_RIGHT	(1 << 1)
311185029Spjd#define HDA_AMP_MUTE_ALL	(HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT)
312185029Spjd
313168404Spjd#define HDA_AMP_LEFT_MUTED(v)	((v) & (HDA_AMP_MUTE_LEFT))
314168404Spjd#define HDA_AMP_RIGHT_MUTED(v)	(((v) & HDA_AMP_MUTE_RIGHT) >> 1)
315205264Skmacy
316205231Skmacy#define HDA_DAC_PATH	(1 << 0)
317205231Skmacy#define HDA_ADC_PATH	(1 << 1)
318205231Skmacy#define HDA_ADC_RECSEL	(1 << 2)
319205231Skmacy
320205231Skmacy#define HDA_DAC_LOCKED	(1 << 3)
321205231Skmacy#define HDA_ADC_LOCKED	(1 << 4)
322205231Skmacy
323205231Skmacy#define HDA_CTL_OUT	(1 << 0)
324205231Skmacy#define HDA_CTL_IN	(1 << 1)
325205231Skmacy#define HDA_CTL_BOTH	(HDA_CTL_IN | HDA_CTL_OUT)
326205231Skmacy
327205231Skmacy#define HDA_GPIO_MAX		8
328205231Skmacy/* 0 - 7 = GPIO , 8 = Flush */
329206796Spjd#define HDA_QUIRK_GPIO0		(1 << 0)
330205231Skmacy#define HDA_QUIRK_GPIO1		(1 << 1)
331168404Spjd#define HDA_QUIRK_GPIO2		(1 << 2)
332185029Spjd#define HDA_QUIRK_GPIO3		(1 << 3)
333185029Spjd#define HDA_QUIRK_GPIO4		(1 << 4)
334205231Skmacy#define HDA_QUIRK_GPIO5		(1 << 5)
335205264Skmacy#define HDA_QUIRK_GPIO6		(1 << 6)
336168404Spjd#define HDA_QUIRK_GPIO7		(1 << 7)
337168404Spjd#define HDA_QUIRK_GPIOFLUSH	(1 << 8)
338206796Spjd
339205231Skmacy/* 9 - 25 = anything else */
340185029Spjd#define HDA_QUIRK_SOFTPCMVOL	(1 << 9)
341168404Spjd#define HDA_QUIRK_FIXEDRATE	(1 << 10)
342168404Spjd#define HDA_QUIRK_FORCESTEREO	(1 << 11)
343168404Spjd#define HDA_QUIRK_EAPDINV	(1 << 12)
344168404Spjd#define HDA_QUIRK_DMAPOS	(1 << 13)
345168404Spjd
346185029Spjd/* 26 - 31 = vrefs */
347168404Spjd#define HDA_QUIRK_IVREF50	(1 << 26)
348168404Spjd#define HDA_QUIRK_IVREF80	(1 << 27)
349168404Spjd#define HDA_QUIRK_IVREF100	(1 << 28)
350168404Spjd#define HDA_QUIRK_OVREF50	(1 << 29)
351168404Spjd#define HDA_QUIRK_OVREF80	(1 << 30)
352168404Spjd#define HDA_QUIRK_OVREF100	(1 << 31)
353168404Spjd
354168404Spjd#define HDA_QUIRK_IVREF		(HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF80 | \
355168404Spjd							HDA_QUIRK_IVREF100)
356168404Spjd#define HDA_QUIRK_OVREF		(HDA_QUIRK_OVREF50 | HDA_QUIRK_OVREF80 | \
357168404Spjd							HDA_QUIRK_OVREF100)
358168404Spjd#define HDA_QUIRK_VREF		(HDA_QUIRK_IVREF | HDA_QUIRK_OVREF)
359168404Spjd
360168404Spjd#define SOUND_MASK_SKIP		(1 << 30)
361168404Spjd#define SOUND_MASK_DISABLE	(1 << 31)
362168404Spjd
363205231Skmacy#if __FreeBSD_version < 600000
364168404Spjd#define taskqueue_drain(...)
365205231Skmacy#endif
366168404Spjd
367251629Sdelphijstatic const struct {
368251629Sdelphij	char *key;
369251629Sdelphij	uint32_t value;
370251629Sdelphij} hdac_quirks_tab[] = {
371251629Sdelphij	{ "gpio0", HDA_QUIRK_GPIO0 },
372251629Sdelphij	{ "gpio1", HDA_QUIRK_GPIO1 },
373168404Spjd	{ "gpio2", HDA_QUIRK_GPIO2 },
374251629Sdelphij	{ "gpio3", HDA_QUIRK_GPIO3 },
375251629Sdelphij	{ "gpio4", HDA_QUIRK_GPIO4 },
376251629Sdelphij	{ "gpio5", HDA_QUIRK_GPIO5 },
377251629Sdelphij	{ "gpio6", HDA_QUIRK_GPIO6 },
378251629Sdelphij	{ "gpio7", HDA_QUIRK_GPIO7 },
379168404Spjd	{ "gpioflush", HDA_QUIRK_GPIOFLUSH },
380208373Smm	{ "softpcmvol", HDA_QUIRK_SOFTPCMVOL },
381208373Smm	{ "fixedrate", HDA_QUIRK_FIXEDRATE },
382208373Smm	{ "forcestereo", HDA_QUIRK_FORCESTEREO },
383168404Spjd	{ "eapdinv", HDA_QUIRK_EAPDINV },
384168404Spjd	{ "dmapos", HDA_QUIRK_DMAPOS },
385168404Spjd	{ "ivref50", HDA_QUIRK_IVREF50 },
386168404Spjd	{ "ivref80", HDA_QUIRK_IVREF80 },
387168404Spjd	{ "ivref100", HDA_QUIRK_IVREF100 },
388168404Spjd	{ "ovref50", HDA_QUIRK_OVREF50 },
389168404Spjd	{ "ovref80", HDA_QUIRK_OVREF80 },
390168404Spjd	{ "ovref100", HDA_QUIRK_OVREF100 },
391168404Spjd	{ "ivref", HDA_QUIRK_IVREF },
392168404Spjd	{ "ovref", HDA_QUIRK_OVREF },
393286574Smav	{ "vref", HDA_QUIRK_VREF },
394286574Smav};
395286574Smav#define HDAC_QUIRKS_TAB_LEN	\
396286574Smav		(sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0]))
397286574Smav
398286574Smav#define HDA_BDL_MIN	2
399286574Smav#define HDA_BDL_MAX	256
400286574Smav#define HDA_BDL_DEFAULT	HDA_BDL_MIN
401185029Spjd
402286574Smav#define HDA_BLK_MIN	HDAC_DMA_ALIGNMENT
403286574Smav#define HDA_BLK_ALIGN	(~(HDA_BLK_MIN - 1))
404286574Smav
405286574Smav#define HDA_BUFSZ_MIN		4096
406286574Smav#define HDA_BUFSZ_MAX		65536
407208373Smm#define HDA_BUFSZ_DEFAULT	16384
408286574Smav
409286574Smav#define HDA_PARSE_MAXDEPTH	10
410286574Smav
411286574Smav#define HDAC_UNSOLTAG_EVENT_HP		0x00
412286574Smav#define HDAC_UNSOLTAG_EVENT_TEST	0x01
413286574Smav
414286574SmavMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
415286574Smav
416286574Smavenum {
417286574Smav	HDA_PARSE_MIXER,
418286574Smav	HDA_PARSE_DIRECT
419286574Smav};
420286574Smav
421286574Smav/* Default */
422208373Smmstatic uint32_t hdac_fmt[] = {
423286574Smav	AFMT_STEREO | AFMT_S16_LE,
424286574Smav	0
425286574Smav};
426286574Smav
427286574Smavstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0};
428286574Smav
429286574Smavstatic const struct {
430286574Smav	uint32_t	model;
431286574Smav	char		*desc;
432286574Smav} hdac_devices[] = {
433286574Smav	{ HDA_INTEL_82801F,  "Intel 82801F" },
434286574Smav	{ HDA_INTEL_63XXESB, "Intel 631x/632xESB" },
435286574Smav	{ HDA_INTEL_82801G,  "Intel 82801G" },
436286574Smav	{ HDA_INTEL_82801H,  "Intel 82801H" },
437286574Smav	{ HDA_INTEL_82801I,  "Intel 82801I" },
438286574Smav	{ HDA_NVIDIA_MCP51,  "NVidia MCP51" },
439286574Smav	{ HDA_NVIDIA_MCP55,  "NVidia MCP55" },
440286574Smav	{ HDA_NVIDIA_MCP61_1, "NVidia MCP61" },
441286574Smav	{ HDA_NVIDIA_MCP61_2, "NVidia MCP61" },
442286574Smav	{ HDA_NVIDIA_MCP65_1, "NVidia MCP65" },
443286574Smav	{ HDA_NVIDIA_MCP65_2, "NVidia MCP65" },
444286574Smav	{ HDA_NVIDIA_MCP67_1, "NVidia MCP67" },
445286574Smav	{ HDA_NVIDIA_MCP67_2, "NVidia MCP67" },
446286574Smav	{ HDA_ATI_SB450,     "ATI SB450"    },
447286574Smav	{ HDA_ATI_SB600,     "ATI SB600"    },
448286574Smav	{ HDA_VIA_VT82XX,    "VIA VT8251/8237A" },
449286574Smav	{ HDA_SIS_966,       "SiS 966" },
450286574Smav	/* Unknown */
451286574Smav	{ HDA_INTEL_ALL,  "Intel (Unknown)"  },
452286574Smav	{ HDA_NVIDIA_ALL, "NVidia (Unknown)" },
453286574Smav	{ HDA_ATI_ALL,    "ATI (Unknown)"    },
454286574Smav	{ HDA_VIA_ALL,    "VIA (Unknown)"    },
455286574Smav	{ HDA_SIS_ALL,    "SiS (Unknown)"    },
456286574Smav};
457286574Smav#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0]))
458286574Smav
459286574Smavstatic const struct {
460286574Smav	uint16_t vendor;
461286574Smav	uint8_t reg;
462286574Smav	uint8_t mask;
463286574Smav	uint8_t enable;
464286574Smav} hdac_pcie_snoop[] = {
465286574Smav	{  INTEL_VENDORID, 0x00, 0x00, 0x00 },
466286574Smav	{    ATI_VENDORID, 0x42, 0xf8, 0x02 },
467286574Smav	{ NVIDIA_VENDORID, 0x4e, 0xf0, 0x0f },
468286574Smav};
469286574Smav#define HDAC_PCIESNOOP_LEN	\
470286574Smav			(sizeof(hdac_pcie_snoop) / sizeof(hdac_pcie_snoop[0]))
471286574Smav
472286574Smavstatic const struct {
473286574Smav	uint32_t	rate;
474286574Smav	int		valid;
475286574Smav	uint16_t	base;
476286574Smav	uint16_t	mul;
477286574Smav	uint16_t	div;
478286574Smav} hda_rate_tab[] = {
479286574Smav	{   8000, 1, 0x0000, 0x0000, 0x0500 },	/* (48000 * 1) / 6 */
480286574Smav	{   9600, 0, 0x0000, 0x0000, 0x0400 },	/* (48000 * 1) / 5 */
481286574Smav	{  12000, 0, 0x0000, 0x0000, 0x0300 },	/* (48000 * 1) / 4 */
482286574Smav	{  16000, 1, 0x0000, 0x0000, 0x0200 },	/* (48000 * 1) / 3 */
483286574Smav	{  18000, 0, 0x0000, 0x1000, 0x0700 },	/* (48000 * 3) / 8 */
484286574Smav	{  19200, 0, 0x0000, 0x0800, 0x0400 },	/* (48000 * 2) / 5 */
485286574Smav	{  24000, 0, 0x0000, 0x0000, 0x0100 },	/* (48000 * 1) / 2 */
486286574Smav	{  28800, 0, 0x0000, 0x1000, 0x0400 },	/* (48000 * 3) / 5 */
487286574Smav	{  32000, 1, 0x0000, 0x0800, 0x0200 },	/* (48000 * 2) / 3 */
488286574Smav	{  36000, 0, 0x0000, 0x1000, 0x0300 },	/* (48000 * 3) / 4 */
489286574Smav	{  38400, 0, 0x0000, 0x1800, 0x0400 },	/* (48000 * 4) / 5 */
490286574Smav	{  48000, 1, 0x0000, 0x0000, 0x0000 },	/* (48000 * 1) / 1 */
491286574Smav	{  64000, 0, 0x0000, 0x1800, 0x0200 },	/* (48000 * 4) / 3 */
492286574Smav	{  72000, 0, 0x0000, 0x1000, 0x0100 },	/* (48000 * 3) / 2 */
493286574Smav	{  96000, 1, 0x0000, 0x0800, 0x0000 },	/* (48000 * 2) / 1 */
494286574Smav	{ 144000, 0, 0x0000, 0x1000, 0x0000 },	/* (48000 * 3) / 1 */
495286574Smav	{ 192000, 1, 0x0000, 0x1800, 0x0000 },	/* (48000 * 4) / 1 */
496286574Smav	{   8820, 0, 0x4000, 0x0000, 0x0400 },	/* (44100 * 1) / 5 */
497286574Smav	{  11025, 1, 0x4000, 0x0000, 0x0300 },	/* (44100 * 1) / 4 */
498286574Smav	{  12600, 0, 0x4000, 0x0800, 0x0600 },	/* (44100 * 2) / 7 */
499286574Smav	{  14700, 0, 0x4000, 0x0000, 0x0200 },	/* (44100 * 1) / 3 */
500286574Smav	{  17640, 0, 0x4000, 0x0800, 0x0400 },	/* (44100 * 2) / 5 */
501286574Smav	{  18900, 0, 0x4000, 0x1000, 0x0600 },	/* (44100 * 3) / 7 */
502286574Smav	{  22050, 1, 0x4000, 0x0000, 0x0100 },	/* (44100 * 1) / 2 */
503286574Smav	{  25200, 0, 0x4000, 0x1800, 0x0600 },	/* (44100 * 4) / 7 */
504286574Smav	{  26460, 0, 0x4000, 0x1000, 0x0400 },	/* (44100 * 3) / 5 */
505286574Smav	{  29400, 0, 0x4000, 0x0800, 0x0200 },	/* (44100 * 2) / 3 */
506286574Smav	{  33075, 0, 0x4000, 0x1000, 0x0300 },	/* (44100 * 3) / 4 */
507286574Smav	{  35280, 0, 0x4000, 0x1800, 0x0400 },	/* (44100 * 4) / 5 */
508286574Smav	{  44100, 1, 0x4000, 0x0000, 0x0000 },	/* (44100 * 1) / 1 */
509286574Smav	{  58800, 0, 0x4000, 0x1800, 0x0200 },	/* (44100 * 4) / 3 */
510286574Smav	{  66150, 0, 0x4000, 0x1000, 0x0100 },	/* (44100 * 3) / 2 */
511286574Smav	{  88200, 1, 0x4000, 0x0800, 0x0000 },	/* (44100 * 2) / 1 */
512286574Smav	{ 132300, 0, 0x4000, 0x1000, 0x0000 },	/* (44100 * 3) / 1 */
513286574Smav	{ 176400, 1, 0x4000, 0x1800, 0x0000 },	/* (44100 * 4) / 1 */
514286574Smav};
515286574Smav#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
516286574Smav
517286574Smav/* All codecs you can eat... */
518286574Smav#define HDA_CODEC_CONSTRUCT(vendor, id) \
519286574Smav		(((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff))
520286574Smav
521286574Smav/* Realtek */
522286574Smav#define REALTEK_VENDORID	0x10ec
523286574Smav#define HDA_CODEC_ALC260	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
524185029Spjd#define HDA_CODEC_ALC262	HDA_CODEC_CONSTRUCT(REALTEK, 0x0262)
525185029Spjd#define HDA_CODEC_ALC268	HDA_CODEC_CONSTRUCT(REALTEK, 0x0268)
526185029Spjd#define HDA_CODEC_ALC660	HDA_CODEC_CONSTRUCT(REALTEK, 0x0660)
527185029Spjd#define HDA_CODEC_ALC861	HDA_CODEC_CONSTRUCT(REALTEK, 0x0861)
528208373Smm#define HDA_CODEC_ALC861VD	HDA_CODEC_CONSTRUCT(REALTEK, 0x0862)
529208373Smm#define HDA_CODEC_ALC880	HDA_CODEC_CONSTRUCT(REALTEK, 0x0880)
530185029Spjd#define HDA_CODEC_ALC882	HDA_CODEC_CONSTRUCT(REALTEK, 0x0882)
531185029Spjd#define HDA_CODEC_ALC883	HDA_CODEC_CONSTRUCT(REALTEK, 0x0883)
532185029Spjd#define HDA_CODEC_ALC885	HDA_CODEC_CONSTRUCT(REALTEK, 0x0885)
533185029Spjd#define HDA_CODEC_ALC888	HDA_CODEC_CONSTRUCT(REALTEK, 0x0888)
534185029Spjd#define HDA_CODEC_ALCXXXX	HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
535185029Spjd
536286570Smav/* Analog Devices */
537185029Spjd#define ANALOGDEVICES_VENDORID	0x11d4
538274172Savg#define HDA_CODEC_AD1981HD	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1981)
539185029Spjd#define HDA_CODEC_AD1983	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1983)
540185029Spjd#define HDA_CODEC_AD1984	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1984)
541185029Spjd#define HDA_CODEC_AD1986A	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1986)
542185029Spjd#define HDA_CODEC_AD1988	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x1988)
543251478Sdelphij#define HDA_CODEC_AD1988B	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0x198b)
544185029Spjd#define HDA_CODEC_ADXXXX	HDA_CODEC_CONSTRUCT(ANALOGDEVICES, 0xffff)
545251478Sdelphij
546251478Sdelphij/* CMedia */
547251478Sdelphij#define CMEDIA_VENDORID		0x434d
548205231Skmacy#define HDA_CODEC_CMI9880	HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980)
549205231Skmacy#define HDA_CODEC_CMIXXXX	HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff)
550205231Skmacy
551206796Spjd/* Sigmatel */
552205231Skmacy#define SIGMATEL_VENDORID	0x8384
553205231Skmacy#define HDA_CODEC_STAC9221	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
554205231Skmacy#define HDA_CODEC_STAC9221D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
555205231Skmacy#define HDA_CODEC_STAC9220	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
556205231Skmacy#define HDA_CODEC_STAC922XD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
557205231Skmacy#define HDA_CODEC_STAC9227	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
558205231Skmacy#define HDA_CODEC_STAC9271D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
559205231Skmacy#define HDA_CODEC_STAC9205	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x76a0)
560242845Sdelphij#define HDA_CODEC_STACXXXX	HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
561242845Sdelphij
562242845Sdelphij/*
563242845Sdelphij * Conexant
564275748Sdelphij *
565275748Sdelphij * Ok, the truth is, I don't have any idea at all whether
566275748Sdelphij * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only
567275780Sdelphij * place that tell me it is "Venice" is from its Windows driver INF.
568168404Spjd *
569168404Spjd *  Venice - CX?????
570168404Spjd * Waikiki - CX20551-22
571168404Spjd */
572168404Spjd#define CONEXANT_VENDORID	0x14f1
573168404Spjd#define HDA_CODEC_CXVENICE	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045)
574168404Spjd#define HDA_CODEC_CXWAIKIKI	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047)
575168404Spjd#define HDA_CODEC_CXXXXX	HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff)
576168404Spjd
577168404Spjd/* VIA */
578168404Spjd#define HDA_CODEC_VT1708_8	HDA_CODEC_CONSTRUCT(VIA, 0x1708)
579168404Spjd#define HDA_CODEC_VT1708_9	HDA_CODEC_CONSTRUCT(VIA, 0x1709)
580168404Spjd#define HDA_CODEC_VT1708_A	HDA_CODEC_CONSTRUCT(VIA, 0x170a)
581168404Spjd#define HDA_CODEC_VT1708_B	HDA_CODEC_CONSTRUCT(VIA, 0x170b)
582168404Spjd#define HDA_CODEC_VT1709_0	HDA_CODEC_CONSTRUCT(VIA, 0xe710)
583168404Spjd#define HDA_CODEC_VT1709_1	HDA_CODEC_CONSTRUCT(VIA, 0xe711)
584168404Spjd#define HDA_CODEC_VT1709_2	HDA_CODEC_CONSTRUCT(VIA, 0xe712)
585205231Skmacy#define HDA_CODEC_VT1709_3	HDA_CODEC_CONSTRUCT(VIA, 0xe713)
586168404Spjd#define HDA_CODEC_VT1709_4	HDA_CODEC_CONSTRUCT(VIA, 0xe714)
587205231Skmacy#define HDA_CODEC_VT1709_5	HDA_CODEC_CONSTRUCT(VIA, 0xe715)
588168404Spjd#define HDA_CODEC_VT1709_6	HDA_CODEC_CONSTRUCT(VIA, 0xe716)
589168404Spjd#define HDA_CODEC_VT1709_7	HDA_CODEC_CONSTRUCT(VIA, 0xe717)
590168404Spjd#define HDA_CODEC_VTXXXX	HDA_CODEC_CONSTRUCT(VIA, 0xffff)
591208373Smm
592208373Smm
593208373Smm/* Codecs */
594168404Spjdstatic const struct {
595168404Spjd	uint32_t id;
596168404Spjd	char *name;
597168404Spjd} hdac_codecs[] = {
598168404Spjd	{ HDA_CODEC_ALC260,    "Realtek ALC260" },
599168404Spjd	{ HDA_CODEC_ALC262,    "Realtek ALC262" },
600168404Spjd	{ HDA_CODEC_ALC268,    "Realtek ALC268" },
601168404Spjd	{ HDA_CODEC_ALC660,    "Realtek ALC660" },
602168404Spjd	{ HDA_CODEC_ALC861,    "Realtek ALC861" },
603185029Spjd	{ HDA_CODEC_ALC861VD,  "Realtek ALC861-VD" },
604185029Spjd	{ HDA_CODEC_ALC880,    "Realtek ALC880" },
605208373Smm	{ HDA_CODEC_ALC882,    "Realtek ALC882" },
606286574Smav	{ HDA_CODEC_ALC883,    "Realtek ALC883" },
607208373Smm	{ HDA_CODEC_ALC885,    "Realtek ALC885" },
608286574Smav	{ HDA_CODEC_ALC888,    "Realtek ALC888" },
609286574Smav	{ HDA_CODEC_AD1981HD,  "Analog Devices AD1981HD" },
610286574Smav	{ HDA_CODEC_AD1983,    "Analog Devices AD1983" },
611286574Smav	{ HDA_CODEC_AD1984,    "Analog Devices AD1984" },
612286574Smav	{ HDA_CODEC_AD1986A,   "Analog Devices AD1986A" },
613286574Smav	{ HDA_CODEC_AD1988,    "Analog Devices AD1988" },
614286574Smav	{ HDA_CODEC_AD1988B,   "Analog Devices AD1988B" },
615286574Smav	{ HDA_CODEC_CMI9880,   "CMedia CMI9880" },
616286574Smav	{ HDA_CODEC_STAC9221,  "Sigmatel STAC9221" },
617286574Smav	{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
618286574Smav	{ HDA_CODEC_STAC9220,  "Sigmatel STAC9220" },
619286574Smav	{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
620286574Smav	{ HDA_CODEC_STAC9227,  "Sigmatel STAC9227" },
621286574Smav	{ HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" },
622286574Smav	{ HDA_CODEC_STAC9205,  "Sigmatel STAC9205" },
623185029Spjd	{ HDA_CODEC_CXVENICE,  "Conexant Venice" },
624185029Spjd	{ HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" },
625185029Spjd	{ HDA_CODEC_VT1708_8,  "VIA VT1708_8" },
626185029Spjd	{ HDA_CODEC_VT1708_9,  "VIA VT1708_9" },
627208373Smm	{ HDA_CODEC_VT1708_A,  "VIA VT1708_A" },
628208373Smm	{ HDA_CODEC_VT1708_B,  "VIA VT1708_B" },
629185029Spjd	{ HDA_CODEC_VT1709_0,  "VIA VT1709_0" },
630185029Spjd	{ HDA_CODEC_VT1709_1,  "VIA VT1709_1" },
631185029Spjd	{ HDA_CODEC_VT1709_2,  "VIA VT1709_2" },
632185029Spjd	{ HDA_CODEC_VT1709_3,  "VIA VT1709_3" },
633185029Spjd	{ HDA_CODEC_VT1709_4,  "VIA VT1709_4" },
634185029Spjd	{ HDA_CODEC_VT1709_5,  "VIA VT1709_5" },
635286570Smav	{ HDA_CODEC_VT1709_6,  "VIA VT1709_6" },
636185029Spjd	{ HDA_CODEC_VT1709_7,  "VIA VT1709_7" },
637274172Savg	/* Unknown codec */
638185029Spjd	{ HDA_CODEC_ALCXXXX,   "Realtek (Unknown)" },
639185029Spjd	{ HDA_CODEC_ADXXXX,    "Analog Devices (Unknown)" },
640185029Spjd	{ HDA_CODEC_CMIXXXX,   "CMedia (Unknown)" },
641185029Spjd	{ HDA_CODEC_STACXXXX,  "Sigmatel (Unknown)" },
642251478Sdelphij	{ HDA_CODEC_CXXXXX,    "Conexant (Unknown)" },
643185029Spjd	{ HDA_CODEC_VTXXXX,    "VIA (Unknown)" },
644251478Sdelphij};
645251478Sdelphij#define HDAC_CODECS_LEN	(sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
646251478Sdelphij
647206796Spjdenum {
648206796Spjd	HDAC_HP_SWITCH_CTL,
649206796Spjd	HDAC_HP_SWITCH_CTRL,
650206796Spjd	HDAC_HP_SWITCH_DEBUG
651206796Spjd};
652206796Spjd
653206796Spjdstatic const struct {
654206796Spjd	uint32_t model;
655206796Spjd	uint32_t id;
656206796Spjd	int type;
657206796Spjd	int inverted;
658242845Sdelphij	int polling;
659242845Sdelphij	int execsense;
660242845Sdelphij	nid_t hpnid;
661242845Sdelphij	nid_t spkrnid[8];
662275748Sdelphij	nid_t eapdnid;
663275748Sdelphij} hdac_hp_switch[] = {
664275748Sdelphij	/* Specific OEM models */
665275780Sdelphij	{ HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL,
666275780Sdelphij	    0, 0, -1, 17, { 16, -1 }, 16 },
667168404Spjd	/* { HP_XW4300_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL,
668168404Spjd	    0, 0, -1, 21, { 16, 17, -1 }, -1 } */
669168404Spjd	/* { HP_3010_SUBVENDOR,  HDA_CODEC_ALC260, HDAC_HP_SWITCH_DEBUG,
670168404Spjd	    0, 1, 0, 16, { 15, 18, 19, 20, 21, -1 }, -1 }, */
671168404Spjd	{ HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
672251631Sdelphij	    0, 0, -1, 6, { 5, -1 }, 5 },
673168404Spjd	{ HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
674206796Spjd	    0, 0, -1, 6, { 5, -1 }, 5 },
675168404Spjd	{ HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
676168404Spjd	    0, 0, -1, 6, { 5, -1 }, 5 },
677168404Spjd	/* { HP_DC7700_SUBVENDOR, HDA_CODEC_ALC262, HDAC_HP_SWITCH_CTL,
678168404Spjd	    0, 0, -1, 21, { 22, 27, -1 }, -1 }, */
679168404Spjd	{ TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
680168404Spjd	    0, 0, -1, 6, { 5, -1 }, -1 },
681168404Spjd	{ TOSHIBA_A135_SUBVENDOR, HDA_CODEC_ALC861VD, HDAC_HP_SWITCH_CTL,
682168404Spjd	    0, 0, -1, 27, { 20, -1 }, -1 },
683168404Spjd	{ DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL,
684168404Spjd	    0, 0, -1, 13, { 14, -1 }, -1 },
685168404Spjd	{ DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL,
686168404Spjd	    0, 0, -1, 13, { 14, -1 }, -1 },
687168404Spjd	{ DELL_OPLX745_SUBVENDOR, HDA_CODEC_AD1983, HDAC_HP_SWITCH_CTL,
688168404Spjd	    0, 0, -1, 6, { 5, 7, -1 }, -1 },
689168404Spjd	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205, HDAC_HP_SWITCH_CTRL,
690168404Spjd	    0, 0, -1, 10, { 13, -1 }, -1 },
691168404Spjd	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, HDAC_HP_SWITCH_CTL,
692168404Spjd	    0, 0, -1, 21, { 20, 22, -1 }, -1 },
693168404Spjd	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL,
694168404Spjd	    0, 0, -1, 10, { 13, -1 }, -1 },
695168404Spjd	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL,
696168404Spjd	    1, 0, -1, 26, { 27, -1 }, -1 },
697168404Spjd	/* { LENOVO_TCA55_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL,
698168404Spjd	    0, 0, -1, 26, { 27, 28, 29, 30, -1 }, -1 }, */
699168404Spjd	{ LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL,
700168404Spjd	    0, 0, -1, 27, { 20, -1 }, -1 },
701168404Spjd	{ ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
702168404Spjd	    0, 0, -1, 20, { 21, -1 }, -1 },
703168404Spjd	{ ACER_3681WXM_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
704168404Spjd	    0, 0, -1, 20, { 21, -1 }, -1 },
705168404Spjd	{ ACER_A4520_SUBVENDOR, HDA_CODEC_ALC268, HDAC_HP_SWITCH_CTL,
706168404Spjd	    0, 0, -1, 20, { 21, -1 }, -1 },
707168404Spjd	{ ACER_A4710_SUBVENDOR, HDA_CODEC_ALC268, HDAC_HP_SWITCH_CTL,
708206796Spjd	    0, 0, -1, 20, { 21, -1 }, -1 },
709168404Spjd	{ UNIWILL_9080_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
710168404Spjd	    0, 0, -1, 20, { 21, -1 }, -1 },
711168404Spjd	{ MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
712168404Spjd	    0, 0, -1, 20, { 27, -1 }, -1 },
713185029Spjd	{ MSI_MS034A_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
714168404Spjd	    0, 0, -1, 20, { 27, -1 }, -1 },
715168404Spjd	{ FS_SI1848_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
716168404Spjd	    0, 0, -1, 20, { 21, -1 }, -1 },
717168404Spjd	{ FL_S7020D_SUBVENDOR, HDA_CODEC_ALC260, HDAC_HP_SWITCH_CTL,
718168404Spjd	    0, 0, -1, 20, { 16, -1 }, -1 },
719168404Spjd	/*
720168404Spjd	 * All models that at least come from the same vendor with
721168404Spjd	 * simmilar codec.
722168404Spjd	 */
723168404Spjd	{ HP_ALL_SUBVENDOR, HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL,
724168404Spjd	    0, 0, -1, 17, { 16, -1 }, 16 },
725168404Spjd	{ HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
726168404Spjd	    0, 0, -1, 6, { 5, -1 }, 5 },
727168404Spjd	{ TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
728275748Sdelphij	    0, 0, -1, 6, { 5, -1 }, -1 },
729275780Sdelphij	{ DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL,
730275748Sdelphij	    0, 0, -1, 13, { 14, -1 }, -1 },
731275748Sdelphij#if 0
732168404Spjd	{ LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL,
733251478Sdelphij	    1, 0, -1, 26, { 27, -1 }, -1 },
734251478Sdelphij	{ ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL,
735251478Sdelphij	    0, 0, -1, 20, { 21, -1 }, -1 },
736168404Spjd#endif
737168404Spjd};
738209962Smm#define HDAC_HP_SWITCH_LEN	\
739168404Spjd		(sizeof(hdac_hp_switch) / sizeof(hdac_hp_switch[0]))
740168404Spjd
741168404Spjdstatic const struct {
742168404Spjd	uint32_t model;
743168404Spjd	uint32_t id;
744168404Spjd	nid_t eapdnid;
745168404Spjd	int hp_switch;
746168404Spjd} hdac_eapd_switch[] = {
747168404Spjd	{ HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, 16, 1 },
748168404Spjd	{ HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
749168404Spjd	{ HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
750168404Spjd};
751168404Spjd#define HDAC_EAPD_SWITCH_LEN	\
752168404Spjd		(sizeof(hdac_eapd_switch) / sizeof(hdac_eapd_switch[0]))
753168404Spjd
754168404Spjd/****************************************************************************
755258632Savg * Function prototypes
756168404Spjd ****************************************************************************/
757168404Spjdstatic void	hdac_intr_handler(void *);
758168404Spjdstatic int	hdac_reset(struct hdac_softc *);
759168404Spjdstatic int	hdac_get_capabilities(struct hdac_softc *);
760286570Smavstatic void	hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
761286570Smavstatic int	hdac_dma_alloc(struct hdac_softc *,
762286570Smav					struct hdac_dma *, bus_size_t);
763286570Smavstatic void	hdac_dma_free(struct hdac_softc *, struct hdac_dma *);
764286570Smavstatic int	hdac_mem_alloc(struct hdac_softc *);
765286570Smavstatic void	hdac_mem_free(struct hdac_softc *);
766286570Smavstatic int	hdac_irq_alloc(struct hdac_softc *);
767286570Smavstatic void	hdac_irq_free(struct hdac_softc *);
768286570Smavstatic void	hdac_corb_init(struct hdac_softc *);
769286570Smavstatic void	hdac_rirb_init(struct hdac_softc *);
770286570Smavstatic void	hdac_corb_start(struct hdac_softc *);
771286570Smavstatic void	hdac_rirb_start(struct hdac_softc *);
772286570Smavstatic void	hdac_scan_codecs(struct hdac_softc *, int);
773286570Smavstatic int	hdac_probe_codec(struct hdac_codec *);
774286570Smavstatic struct	hdac_devinfo *hdac_probe_function(struct hdac_codec *, nid_t);
775286570Smavstatic void	hdac_add_child(struct hdac_softc *, struct hdac_devinfo *);
776286570Smav
777286570Smavstatic void	hdac_attach2(void *);
778286570Smav
779286570Smavstatic uint32_t	hdac_command_sendone_internal(struct hdac_softc *,
780286570Smav							uint32_t, int);
781286570Smavstatic void	hdac_command_send_internal(struct hdac_softc *,
782286570Smav					struct hdac_command_list *, int);
783286570Smav
784286570Smavstatic int	hdac_probe(device_t);
785286570Smavstatic int	hdac_attach(device_t);
786286570Smavstatic int	hdac_detach(device_t);
787286570Smavstatic void	hdac_widget_connection_select(struct hdac_widget *, uint8_t);
788286570Smavstatic void	hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
789286570Smav						uint32_t, int, int);
790286570Smavstatic struct	hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
791286570Smav							nid_t, int, int);
792168404Spjdstatic void	hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
793286570Smav				nid_t, nid_t, int, int, int, int, int, int);
794286570Smavstatic int	hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *);
795286570Smavstatic struct	hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
796286570Smav
797286570Smavstatic int	hdac_rirb_flush(struct hdac_softc *sc);
798286570Smavstatic int	hdac_unsolq_flush(struct hdac_softc *sc);
799219089Spjd
800286570Smav#define hdac_command(a1, a2, a3)	\
801168404Spjd		hdac_command_sendone_internal(a1, a2, a3)
802168404Spjd
803168404Spjd#define hdac_codec_id(d)						\
804286570Smav		((uint32_t)((d == NULL) ? 0x00000000 :			\
805168404Spjd		((((uint32_t)(d)->vendor_id & 0x0000ffff) << 16) |	\
806168404Spjd		((uint32_t)(d)->device_id & 0x0000ffff))))
807168404Spjd
808168404Spjdstatic char *
809168404Spjdhdac_codec_name(struct hdac_devinfo *devinfo)
810168404Spjd{
811168404Spjd	uint32_t id;
812168404Spjd	int i;
813168404Spjd
814168404Spjd	id = hdac_codec_id(devinfo);
815168404Spjd
816185029Spjd	for (i = 0; i < HDAC_CODECS_LEN; i++) {
817286570Smav		if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
818286570Smav			return (hdac_codecs[i].name);
819286570Smav	}
820286570Smav
821286570Smav	return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec");
822286570Smav}
823286570Smav
824286570Smavstatic char *
825286570Smavhdac_audio_ctl_ossmixer_mask2name(uint32_t devmask)
826286570Smav{
827286570Smav	static char *ossname[] = SOUND_DEVICE_NAMES;
828286570Smav	static char *unknown = "???";
829286570Smav	int i;
830286570Smav
831185029Spjd	for (i = SOUND_MIXER_NRDEVICES - 1; i >= 0; i--) {
832286570Smav		if (devmask & (1 << i))
833286570Smav			return (ossname[i]);
834286570Smav	}
835286570Smav	return (unknown);
836286570Smav}
837286570Smav
838286570Smavstatic void
839286570Smavhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
840286570Smav{
841286570Smav	static char *ossname[] = SOUND_DEVICE_NAMES;
842286570Smav	int i, first = 1;
843286570Smav
844286570Smav	bzero(buf, len);
845286570Smav	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
846286570Smav		if (mask & (1 << i)) {
847286570Smav			if (first == 0)
848286570Smav				strlcat(buf, ", ", len);
849286570Smav			strlcat(buf, ossname[i], len);
850286570Smav			first = 0;
851286570Smav		}
852286570Smav	}
853286570Smav}
854286570Smav
855286570Smavstatic struct hdac_audio_ctl *
856286570Smavhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
857168404Spjd{
858168404Spjd	if (devinfo == NULL ||
859275748Sdelphij	    devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO ||
860275748Sdelphij	    index == NULL || devinfo->function.audio.ctl == NULL ||
861275748Sdelphij	    devinfo->function.audio.ctlcnt < 1 ||
862275748Sdelphij	    *index < 0 || *index >= devinfo->function.audio.ctlcnt)
863275748Sdelphij		return (NULL);
864275748Sdelphij	return (&devinfo->function.audio.ctl[(*index)++]);
865275748Sdelphij}
866275748Sdelphij
867275748Sdelphijstatic struct hdac_audio_ctl *
868275748Sdelphijhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid,
869275748Sdelphij						int index, int cnt)
870275748Sdelphij{
871275748Sdelphij	struct hdac_audio_ctl *ctl, *retctl = NULL;
872275748Sdelphij	int i, at, atindex, found = 0;
873275748Sdelphij
874275748Sdelphij	if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
875275748Sdelphij		return (NULL);
876275748Sdelphij
877275748Sdelphij	at = cnt;
878275748Sdelphij	if (at == 0)
879168404Spjd		at = 1;
880168404Spjd	else if (at < 0)
881168404Spjd		at = -1;
882168404Spjd	atindex = index;
883168404Spjd	if (atindex < 0)
884185029Spjd		atindex = -1;
885185029Spjd
886168404Spjd	i = 0;
887275811Sdelphij	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
888275811Sdelphij		if (ctl->enable == 0 || ctl->widget == NULL)
889275811Sdelphij			continue;
890275811Sdelphij		if (!(ctl->widget->nid == nid && (atindex == -1 ||
891275811Sdelphij		    ctl->index == atindex)))
892275811Sdelphij			continue;
893286570Smav		found++;
894275811Sdelphij		if (found == cnt)
895286570Smav			return (ctl);
896275811Sdelphij		retctl = ctl;
897286570Smav	}
898286570Smav
899275811Sdelphij	return ((at == -1) ? retctl : NULL);
900275811Sdelphij}
901275811Sdelphij
902168404Spjdstatic void
903286570Smavhdac_hp_switch_handler(struct hdac_devinfo *devinfo)
904286570Smav{
905286570Smav	struct hdac_softc *sc;
906286570Smav	struct hdac_widget *w;
907286570Smav	struct hdac_audio_ctl *ctl;
908286570Smav	uint32_t val, id, res;
909286570Smav	int i = 0, j, timeout, forcemute;
910286570Smav	nid_t cad;
911286570Smav
912286570Smav	if (devinfo == NULL || devinfo->codec == NULL ||
913286570Smav	    devinfo->codec->sc == NULL)
914286570Smav		return;
915286570Smav
916286570Smav	sc = devinfo->codec->sc;
917286570Smav	cad = devinfo->codec->cad;
918286570Smav	id = hdac_codec_id(devinfo);
919168404Spjd	for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
920185029Spjd		if (HDA_DEV_MATCH(hdac_hp_switch[i].model,
921185029Spjd		    sc->pci_subvendor) &&
922185029Spjd		    hdac_hp_switch[i].id == id)
923286570Smav			break;
924286570Smav	}
925185029Spjd
926185029Spjd	if (i >= HDAC_HP_SWITCH_LEN)
927168404Spjd		return;
928168404Spjd
929168404Spjd	forcemute = 0;
930205253Skmacy	if (hdac_hp_switch[i].eapdnid != -1) {
931168404Spjd		w = hdac_widget_get(devinfo, hdac_hp_switch[i].eapdnid);
932168404Spjd		if (w != NULL && w->param.eapdbtl != HDAC_INVALID)
933168404Spjd			forcemute = (w->param.eapdbtl &
934168404Spjd			    HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1;
935168404Spjd	}
936168404Spjd
937168404Spjd	if (hdac_hp_switch[i].execsense != -1)
938168404Spjd		hdac_command(sc,
939168404Spjd		    HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid,
940168404Spjd		    hdac_hp_switch[i].execsense), cad);
941168404Spjd
942168404Spjd	timeout = 10000;
943205264Skmacy	do {
944168404Spjd		res = hdac_command(sc,
945168404Spjd		    HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid),
946168404Spjd		    cad);
947168404Spjd		if (hdac_hp_switch[i].execsense == -1 || res != 0x7fffffff)
948168404Spjd			break;
949168404Spjd		DELAY(10);
950168404Spjd	} while (--timeout != 0);
951168404Spjd
952219089Spjd	HDA_BOOTVERBOSE(
953219089Spjd		device_printf(sc->dev,
954168404Spjd		    "HDA_DEBUG: Pin sense: nid=%d timeout=%d res=0x%08x\n",
955168404Spjd		    hdac_hp_switch[i].hpnid, timeout, res);
956168404Spjd	);
957185029Spjd
958185029Spjd	res = HDA_CMD_GET_PIN_SENSE_PRESENCE_DETECT(res);
959185029Spjd	res ^= hdac_hp_switch[i].inverted;
960185029Spjd
961272707Savg	switch (hdac_hp_switch[i].type) {
962251478Sdelphij	case HDAC_HP_SWITCH_CTL:
963251478Sdelphij		ctl = hdac_audio_ctl_amp_get(devinfo,
964251478Sdelphij		    hdac_hp_switch[i].hpnid, 0, 1);
965251478Sdelphij		if (ctl != NULL) {
966251478Sdelphij			val = (res != 0 && forcemute == 0) ?
967251478Sdelphij			    HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL;
968208373Smm			if (val != ctl->muted) {
969208373Smm				ctl->muted = val;
970185029Spjd				hdac_audio_ctl_amp_set(ctl,
971286598Smav				    HDA_AMP_MUTE_DEFAULT, ctl->left,
972286598Smav				    ctl->right);
973286598Smav			}
974286598Smav		}
975286598Smav		for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
976286598Smav			ctl = hdac_audio_ctl_amp_get(devinfo,
977286598Smav			    hdac_hp_switch[i].spkrnid[j], 0, 1);
978286598Smav			if (ctl == NULL)
979286598Smav				continue;
980286598Smav			val = (res != 0 || forcemute == 1) ?
981185029Spjd			    HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE;
982185029Spjd			if (val == ctl->muted)
983185029Spjd				continue;
984251631Sdelphij			ctl->muted = val;
985185029Spjd			hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT,
986185029Spjd			    ctl->left, ctl->right);
987185029Spjd		}
988251478Sdelphij		break;
989185029Spjd	case HDAC_HP_SWITCH_CTRL:
990208373Smm		if (res != 0) {
991219089Spjd			/* HP in */
992208373Smm			w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
993208373Smm			if (w != NULL && w->type ==
994185029Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
995217367Smdf				if (forcemute == 0)
996205231Skmacy					val = w->wclass.pin.ctrl |
997217367Smdf					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
998205231Skmacy				else
999217367Smdf					val = w->wclass.pin.ctrl &
1000205231Skmacy					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1001217367Smdf				if (val != w->wclass.pin.ctrl) {
1002205231Skmacy					w->wclass.pin.ctrl = val;
1003217367Smdf					hdac_command(sc,
1004208373Smm					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
1005205231Skmacy					    w->nid, w->wclass.pin.ctrl), cad);
1006205231Skmacy				}
1007205231Skmacy			}
1008208373Smm			for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
1009208373Smm				w = hdac_widget_get(devinfo,
1010208373Smm				    hdac_hp_switch[i].spkrnid[j]);
1011208373Smm				if (w == NULL || w->type !=
1012205231Skmacy				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1013217367Smdf					continue;
1014205231Skmacy				val = w->wclass.pin.ctrl &
1015217367Smdf				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1016205231Skmacy				if (val == w->wclass.pin.ctrl)
1017217367Smdf					continue;
1018205231Skmacy				w->wclass.pin.ctrl = val;
1019205231Skmacy				hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL(
1020217367Smdf				    cad, w->nid, w->wclass.pin.ctrl), cad);
1021205231Skmacy			}
1022217367Smdf		} else {
1023205231Skmacy			/* HP out */
1024217367Smdf			w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
1025205231Skmacy			if (w != NULL && w->type ==
1026205231Skmacy			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
1027217367Smdf				val = w->wclass.pin.ctrl &
1028205231Skmacy				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1029217367Smdf				if (val != w->wclass.pin.ctrl) {
1030205231Skmacy					w->wclass.pin.ctrl = val;
1031205231Skmacy					hdac_command(sc,
1032217367Smdf					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
1033205231Skmacy					    w->nid, w->wclass.pin.ctrl), cad);
1034205231Skmacy				}
1035205231Skmacy			}
1036217367Smdf			for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
1037205231Skmacy				w = hdac_widget_get(devinfo,
1038217367Smdf				    hdac_hp_switch[i].spkrnid[j]);
1039205231Skmacy				if (w == NULL || w->type !=
1040217367Smdf				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1041205231Skmacy					continue;
1042205231Skmacy				if (forcemute == 0)
1043217367Smdf					val = w->wclass.pin.ctrl |
1044205231Skmacy					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1045217367Smdf				else
1046205231Skmacy					val = w->wclass.pin.ctrl &
1047205231Skmacy					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1048217367Smdf				if (val == w->wclass.pin.ctrl)
1049205231Skmacy					continue;
1050205231Skmacy				w->wclass.pin.ctrl = val;
1051205231Skmacy				hdac_command(sc, HDA_CMD_SET_PIN_WIDGET_CTRL(
1052217367Smdf				    cad, w->nid, w->wclass.pin.ctrl), cad);
1053205231Skmacy			}
1054205231Skmacy		}
1055185029Spjd		break;
1056185029Spjd	case HDAC_HP_SWITCH_DEBUG:
1057185029Spjd		if (hdac_hp_switch[i].execsense != -1)
1058286570Smav			hdac_command(sc,
1059185029Spjd			    HDA_CMD_SET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid,
1060185029Spjd			    hdac_hp_switch[i].execsense), cad);
1061185029Spjd		res = hdac_command(sc,
1062185029Spjd		    HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad);
1063185029Spjd		device_printf(sc->dev,
1064185029Spjd		    "[ 0] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n",
1065208373Smm		    hdac_hp_switch[i].hpnid, res);
1066286570Smav		for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
1067286570Smav			w = hdac_widget_get(devinfo,
1068185029Spjd			    hdac_hp_switch[i].spkrnid[j]);
1069286598Smav			if (w == NULL || w->type !=
1070286570Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1071185029Spjd				continue;
1072185029Spjd			if (hdac_hp_switch[i].execsense != -1)
1073185029Spjd				hdac_command(sc,
1074185029Spjd				    HDA_CMD_SET_PIN_SENSE(cad, w->nid,
1075185029Spjd				    hdac_hp_switch[i].execsense), cad);
1076185029Spjd			res = hdac_command(sc,
1077185029Spjd			    HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
1078185029Spjd			device_printf(sc->dev,
1079185029Spjd			    "[%2d] HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n",
1080185029Spjd			    j + 1, w->nid, res);
1081185029Spjd		}
1082251478Sdelphij		break;
1083251478Sdelphij	default:
1084251478Sdelphij		break;
1085268123Sdelphij	}
1086251478Sdelphij}
1087251478Sdelphij
1088185029Spjdstatic void
1089185029Spjdhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
1090185029Spjd{
1091185029Spjd	struct hdac_softc *sc;
1092185029Spjd	struct hdac_devinfo *devinfo = NULL;
1093185029Spjd	device_t *devlist = NULL;
1094185029Spjd	int devcount, i;
1095185029Spjd
1096185029Spjd	if (codec == NULL || codec->sc == NULL)
1097185029Spjd		return;
1098185029Spjd
1099185029Spjd	sc = codec->sc;
1100185029Spjd
1101185029Spjd	HDA_BOOTVERBOSE(
1102185029Spjd		device_printf(sc->dev, "HDA_DEBUG: Unsol Tag: 0x%08x\n", tag);
1103185029Spjd	);
1104185029Spjd
1105185029Spjd	device_get_children(sc->dev, &devlist, &devcount);
1106185029Spjd	for (i = 0; devlist != NULL && i < devcount; i++) {
1107275811Sdelphij		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
1108275811Sdelphij		if (devinfo != NULL && devinfo->node_type ==
1109275811Sdelphij		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
1110275811Sdelphij		    devinfo->codec != NULL &&
1111275811Sdelphij		    devinfo->codec->cad == codec->cad) {
1112275811Sdelphij			break;
1113286570Smav		} else
1114286570Smav			devinfo = NULL;
1115286570Smav	}
1116275811Sdelphij	if (devlist != NULL)
1117275811Sdelphij		free(devlist, M_TEMP);
1118185029Spjd
1119286570Smav	if (devinfo == NULL)
1120275811Sdelphij		return;
1121275811Sdelphij
1122251478Sdelphij	switch (tag) {
1123168404Spjd	case HDAC_UNSOLTAG_EVENT_HP:
1124209962Smm		hdac_hp_switch_handler(devinfo);
1125168404Spjd		break;
1126168404Spjd	case HDAC_UNSOLTAG_EVENT_TEST:
1127168404Spjd		device_printf(sc->dev, "Unsol Test!\n");
1128168404Spjd		break;
1129168404Spjd	default:
1130168404Spjd		break;
1131168404Spjd	}
1132168404Spjd}
1133168404Spjd
1134168404Spjdstatic int
1135209962Smmhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
1136168404Spjd{
1137168404Spjd	/* XXX to be removed */
1138168404Spjd#ifdef HDAC_INTR_EXTRA
1139168404Spjd	uint32_t res;
1140168404Spjd#endif
1141168404Spjd
1142286570Smav	if (!(ch->flags & HDAC_CHN_RUNNING))
1143168404Spjd		return (0);
1144168404Spjd
1145168404Spjd	/* XXX to be removed */
1146168404Spjd#ifdef HDAC_INTR_EXTRA
1147168404Spjd	res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS);
1148168404Spjd#endif
1149219089Spjd
1150219089Spjd	/* XXX to be removed */
1151219089Spjd#ifdef HDAC_INTR_EXTRA
1152219089Spjd	HDA_BOOTVERBOSE(
1153219089Spjd		if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE))
1154219089Spjd			device_printf(sc->dev,
1155219089Spjd			    "PCMDIR_%s intr triggered beyond stream boundary:"
1156219089Spjd			    "%08x\n",
1157168404Spjd			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
1158268075Sdelphij	);
1159168404Spjd#endif
1160268075Sdelphij
1161268075Sdelphij	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS,
1162168404Spjd	    HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS );
1163168404Spjd
1164275811Sdelphij	/* XXX to be removed */
1165168404Spjd#ifdef HDAC_INTR_EXTRA
1166168404Spjd	if (res & HDAC_SDSTS_BCIS) {
1167275811Sdelphij#endif
1168275811Sdelphij		return (1);
1169275811Sdelphij	/* XXX to be removed */
1170168404Spjd#ifdef HDAC_INTR_EXTRA
1171275811Sdelphij	}
1172168404Spjd#endif
1173168404Spjd
1174168404Spjd	return (0);
1175168404Spjd}
1176168404Spjd
1177168404Spjd/****************************************************************************
1178168404Spjd * void hdac_intr_handler(void *)
1179168404Spjd *
1180168404Spjd * Interrupt handler. Processes interrupts received from the hdac.
1181168404Spjd ****************************************************************************/
1182168404Spjdstatic void
1183168404Spjdhdac_intr_handler(void *context)
1184286570Smav{
1185168404Spjd	struct hdac_softc *sc;
1186168404Spjd	uint32_t intsts;
1187275811Sdelphij	uint8_t rirbsts;
1188168404Spjd	struct hdac_rirb *rirb_base;
1189275811Sdelphij	uint32_t trigger;
1190168404Spjd
1191275811Sdelphij	sc = (struct hdac_softc *)context;
1192168404Spjd
1193168404Spjd	hdac_lock(sc);
1194275811Sdelphij	if (sc->polling != 0) {
1195275811Sdelphij		hdac_unlock(sc);
1196275811Sdelphij		return;
1197286570Smav	}
1198286570Smav
1199286570Smav	/* Do we have anything to do? */
1200286570Smav	intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
1201286570Smav	if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) {
1202286570Smav		hdac_unlock(sc);
1203286570Smav		return;
1204286570Smav	}
1205275811Sdelphij
1206275811Sdelphij	trigger = 0;
1207275811Sdelphij
1208275811Sdelphij	/* Was this a controller interrupt? */
1209168404Spjd	if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) {
1210168404Spjd		rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
1211275811Sdelphij		rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1212275811Sdelphij		/* Get as many responses that we can */
1213275811Sdelphij		while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) {
1214168404Spjd			HDAC_WRITE_1(&sc->mem,
1215168404Spjd			    HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
1216168404Spjd			if (hdac_rirb_flush(sc) != 0)
1217168404Spjd				trigger |= HDAC_TRIGGER_UNSOL;
1218168404Spjd			rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
1219168404Spjd		}
1220168404Spjd		/* XXX to be removed */
1221168404Spjd		/* Clear interrupt and exit */
1222168404Spjd#ifdef HDAC_INTR_EXTRA
1223168404Spjd		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS);
1224168404Spjd#endif
1225168404Spjd	}
1226168404Spjd
1227168404Spjd	if (intsts & HDAC_INTSTS_SIS_MASK) {
1228168404Spjd		if ((intsts & (1 << sc->num_iss)) &&
1229168404Spjd		    hdac_stream_intr(sc, &sc->play) != 0)
1230168404Spjd			trigger |= HDAC_TRIGGER_PLAY;
1231275811Sdelphij		if ((intsts & (1 << 0)) &&
1232168404Spjd		    hdac_stream_intr(sc, &sc->rec) != 0)
1233275811Sdelphij			trigger |= HDAC_TRIGGER_REC;
1234275811Sdelphij		/* XXX to be removed */
1235168404Spjd#ifdef HDAC_INTR_EXTRA
1236168404Spjd		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts &
1237275811Sdelphij		    HDAC_INTSTS_SIS_MASK);
1238168404Spjd#endif
1239275811Sdelphij	}
1240275811Sdelphij
1241275811Sdelphij	hdac_unlock(sc);
1242275811Sdelphij
1243168404Spjd	if (trigger & HDAC_TRIGGER_PLAY)
1244275811Sdelphij		chn_intr(sc->play.c);
1245275811Sdelphij	if (trigger & HDAC_TRIGGER_REC)
1246275811Sdelphij		chn_intr(sc->rec.c);
1247168404Spjd	if (trigger & HDAC_TRIGGER_UNSOL)
1248168404Spjd		taskqueue_enqueue(taskqueue_thread, &sc->unsolq_task);
1249168404Spjd}
1250168404Spjd
1251168404Spjd/****************************************************************************
1252168404Spjd * int hdac_reset(hdac_softc *)
1253168404Spjd *
1254168404Spjd * Reset the hdac to a quiescent and known state.
1255168404Spjd ****************************************************************************/
1256168404Spjdstatic int
1257168404Spjdhdac_reset(struct hdac_softc *sc)
1258168404Spjd{
1259286570Smav	uint32_t gctl;
1260286570Smav	int count, i;
1261168404Spjd
1262168404Spjd	/*
1263168404Spjd	 * Stop all Streams DMA engine
1264168404Spjd	 */
1265168404Spjd	for (i = 0; i < sc->num_iss; i++)
1266168404Spjd		HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
1267168404Spjd	for (i = 0; i < sc->num_oss; i++)
1268168404Spjd		HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
1269168404Spjd	for (i = 0; i < sc->num_bss; i++)
1270168404Spjd		HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
1271168404Spjd
1272286570Smav	/*
1273286570Smav	 * Stop Control DMA engines.
1274168404Spjd	 */
1275168404Spjd	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
1276168404Spjd	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
1277168404Spjd
1278168404Spjd	/*
1279168404Spjd	 * Reset DMA position buffer.
1280168404Spjd	 */
1281168404Spjd	HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE, 0x0);
1282168404Spjd	HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, 0x0);
1283286570Smav
1284168404Spjd	/*
1285275811Sdelphij	 * Reset the controller. The reset must remain asserted for
1286168404Spjd	 * a minimum of 100us.
1287286570Smav	 */
1288286570Smav	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1289286570Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
1290286570Smav	count = 10000;
1291286570Smav	do {
1292185029Spjd		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1293168404Spjd		if (!(gctl & HDAC_GCTL_CRST))
1294168404Spjd			break;
1295168404Spjd		DELAY(10);
1296185029Spjd	} while	(--count);
1297185029Spjd	if (gctl & HDAC_GCTL_CRST) {
1298286570Smav		device_printf(sc->dev, "Unable to put hdac in reset\n");
1299286570Smav		return (ENXIO);
1300286570Smav	}
1301286570Smav	DELAY(100);
1302286570Smav	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1303286570Smav	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
1304286570Smav	count = 10000;
1305286570Smav	do {
1306286570Smav		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1307286570Smav		if (gctl & HDAC_GCTL_CRST)
1308286570Smav			break;
1309286570Smav		DELAY(10);
1310185029Spjd	} while (--count);
1311185029Spjd	if (!(gctl & HDAC_GCTL_CRST)) {
1312185029Spjd		device_printf(sc->dev, "Device stuck in reset\n");
1313185029Spjd		return (ENXIO);
1314185029Spjd	}
1315219089Spjd
1316208373Smm	/*
1317208373Smm	 * Wait for codecs to finish their own reset sequence. The delay here
1318185029Spjd	 * should be of 250us but for some reasons, on it's not enough on my
1319185029Spjd	 * computer. Let's use twice as much as necessary to make sure that
1320185029Spjd	 * it's reset properly.
1321168404Spjd	 */
1322168404Spjd	DELAY(1000);
1323168404Spjd
1324168404Spjd	return (0);
1325168404Spjd}
1326168404Spjd
1327286570Smav
1328168404Spjd/****************************************************************************
1329275811Sdelphij * int hdac_get_capabilities(struct hdac_softc *);
1330168404Spjd *
1331275811Sdelphij * Retreive the general capabilities of the hdac;
1332286570Smav *	Number of Input Streams
1333286570Smav *	Number of Output Streams
1334286570Smav *	Number of bidirectional Streams
1335286570Smav *	64bit ready
1336168404Spjd *	CORB and RIRB sizes
1337168404Spjd ****************************************************************************/
1338185029Spjdstatic int
1339185029Spjdhdac_get_capabilities(struct hdac_softc *sc)
1340286570Smav{
1341286570Smav	uint16_t gcap;
1342286570Smav	uint8_t corbsize, rirbsize;
1343286570Smav
1344286570Smav	gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
1345286570Smav	sc->num_iss = HDAC_GCAP_ISS(gcap);
1346286570Smav	sc->num_oss = HDAC_GCAP_OSS(gcap);
1347286570Smav	sc->num_bss = HDAC_GCAP_BSS(gcap);
1348286570Smav
1349286570Smav	sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK);
1350185029Spjd
1351185029Spjd	corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
1352185029Spjd	if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
1353185029Spjd	    HDAC_CORBSIZE_CORBSZCAP_256)
1354219089Spjd		sc->corb_size = 256;
1355208373Smm	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
1356185029Spjd	    HDAC_CORBSIZE_CORBSZCAP_16)
1357185029Spjd		sc->corb_size = 16;
1358168404Spjd	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
1359168404Spjd	    HDAC_CORBSIZE_CORBSZCAP_2)
1360168404Spjd		sc->corb_size = 2;
1361168404Spjd	else {
1362168404Spjd		device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
1363168404Spjd		    __func__, corbsize);
1364168404Spjd		return (ENXIO);
1365168404Spjd	}
1366168404Spjd
1367168404Spjd	rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
1368168404Spjd	if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
1369168404Spjd	    HDAC_RIRBSIZE_RIRBSZCAP_256)
1370168404Spjd		sc->rirb_size = 256;
1371168404Spjd	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
1372168404Spjd	    HDAC_RIRBSIZE_RIRBSZCAP_16)
1373168404Spjd		sc->rirb_size = 16;
1374168404Spjd	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
1375168404Spjd	    HDAC_RIRBSIZE_RIRBSZCAP_2)
1376168404Spjd		sc->rirb_size = 2;
1377168404Spjd	else {
1378168404Spjd		device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
1379168404Spjd		    __func__, rirbsize);
1380168404Spjd		return (ENXIO);
1381168404Spjd	}
1382168404Spjd
1383269230Sdelphij	return (0);
1384269230Sdelphij}
1385269230Sdelphij
1386168404Spjd
1387269230Sdelphij/****************************************************************************
1388168404Spjd * void hdac_dma_cb
1389168404Spjd *
1390168404Spjd * This function is called by bus_dmamap_load when the mapping has been
1391168404Spjd * established. We just record the physical address of the mapping into
1392168404Spjd * the struct hdac_dma passed in.
1393168404Spjd ****************************************************************************/
1394168404Spjdstatic void
1395168404Spjdhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
1396168404Spjd{
1397168404Spjd	struct hdac_dma *dma;
1398168404Spjd
1399286570Smav	if (error == 0) {
1400286570Smav		dma = (struct hdac_dma *)callback_arg;
1401286570Smav		dma->dma_paddr = segs[0].ds_addr;
1402286570Smav	}
1403286570Smav}
1404168404Spjd
1405185029Spjd
1406168404Spjd/****************************************************************************
1407168404Spjd * int hdac_dma_alloc
1408168404Spjd *
1409168404Spjd * This function allocate and setup a dma region (struct hdac_dma).
1410168404Spjd * It must be freed by a corresponding hdac_dma_free.
1411168404Spjd ****************************************************************************/
1412168404Spjdstatic int
1413168404Spjdhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
1414168404Spjd{
1415168404Spjd	bus_size_t roundsz;
1416168404Spjd	int result;
1417286570Smav	int lowaddr;
1418286570Smav
1419286570Smav	roundsz = roundup2(size, HDAC_DMA_ALIGNMENT);
1420286570Smav	lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR :
1421286570Smav	    BUS_SPACE_MAXADDR_32BIT;
1422286570Smav	bzero(dma, sizeof(*dma));
1423286570Smav
1424286570Smav	/*
1425286570Smav	 * Create a DMA tag
1426286570Smav	 */
1427286570Smav	result = bus_dma_tag_create(NULL,	/* parent */
1428286570Smav	    HDAC_DMA_ALIGNMENT,			/* alignment */
1429286570Smav	    0,					/* boundary */
1430286570Smav	    lowaddr,				/* lowaddr */
1431286570Smav	    BUS_SPACE_MAXADDR,			/* highaddr */
1432286570Smav	    NULL,				/* filtfunc */
1433286570Smav	    NULL,				/* fistfuncarg */
1434286570Smav	    roundsz, 				/* maxsize */
1435286570Smav	    1,					/* nsegments */
1436286570Smav	    roundsz, 				/* maxsegsz */
1437286570Smav	    0,					/* flags */
1438286570Smav	    NULL,				/* lockfunc */
1439286570Smav	    NULL,				/* lockfuncarg */
1440286570Smav	    &dma->dma_tag);			/* dmat */
1441286598Smav	if (result != 0) {
1442286570Smav		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
1443286570Smav		    __func__, result);
1444286570Smav		goto hdac_dma_alloc_fail;
1445286570Smav	}
1446286570Smav
1447286570Smav	/*
1448286570Smav	 * Allocate DMA memory
1449286570Smav	 */
1450286570Smav	result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
1451286570Smav	    BUS_DMA_NOWAIT | BUS_DMA_ZERO |
1452286570Smav	    ((sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0),
1453286570Smav	    &dma->dma_map);
1454286570Smav	if (result != 0) {
1455286570Smav		device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n",
1456286570Smav		    __func__, result);
1457286570Smav		goto hdac_dma_alloc_fail;
1458286570Smav	}
1459286570Smav
1460286570Smav	dma->dma_size = roundsz;
1461286570Smav
1462286570Smav	/*
1463286570Smav	 * Map the memory
1464286570Smav	 */
1465286570Smav	result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
1466286570Smav	    (void *)dma->dma_vaddr, roundsz, hdac_dma_cb, (void *)dma, 0);
1467286570Smav	if (result != 0 || dma->dma_paddr == 0) {
1468286570Smav		if (result == 0)
1469286570Smav			result = ENOMEM;
1470286570Smav		device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n",
1471286570Smav		    __func__, result);
1472286570Smav		goto hdac_dma_alloc_fail;
1473286570Smav	}
1474286570Smav
1475286570Smav	HDA_BOOTVERBOSE(
1476286570Smav		device_printf(sc->dev, "%s: size=%ju -> roundsz=%ju\n",
1477286570Smav		    __func__, (uintmax_t)size, (uintmax_t)roundsz);
1478286570Smav	);
1479286570Smav
1480286570Smav	return (0);
1481286570Smav
1482286570Smavhdac_dma_alloc_fail:
1483286570Smav	hdac_dma_free(sc, dma);
1484286570Smav
1485286598Smav	return (result);
1486286598Smav}
1487286598Smav
1488286598Smav
1489286598Smav/****************************************************************************
1490286598Smav * void hdac_dma_free(struct hdac_softc *, struct hdac_dma *)
1491286598Smav *
1492286598Smav * Free a struct dhac_dma that has been previously allocated via the
1493286598Smav * hdac_dma_alloc function.
1494286598Smav ****************************************************************************/
1495286598Smavstatic void
1496286598Smavhdac_dma_free(struct hdac_softc *sc, struct hdac_dma *dma)
1497286598Smav{
1498286598Smav	if (dma->dma_map != NULL) {
1499286570Smav#if 0
1500286570Smav		/* Flush caches */
1501286570Smav		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
1502286570Smav		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1503286570Smav#endif
1504286570Smav		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1505286570Smav	}
1506286570Smav	if (dma->dma_vaddr != NULL) {
1507168404Spjd		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1508168404Spjd		dma->dma_vaddr = NULL;
1509168404Spjd	}
1510168404Spjd	dma->dma_map = NULL;
1511168404Spjd	if (dma->dma_tag != NULL) {
1512168404Spjd		bus_dma_tag_destroy(dma->dma_tag);
1513168404Spjd		dma->dma_tag = NULL;
1514168404Spjd	}
1515168404Spjd	dma->dma_size = 0;
1516168404Spjd}
1517286570Smav
1518286570Smav/****************************************************************************
1519286570Smav * int hdac_mem_alloc(struct hdac_softc *)
1520168404Spjd *
1521168404Spjd * Allocate all the bus resources necessary to speak with the physical
1522168404Spjd * controller.
1523168404Spjd ****************************************************************************/
1524168404Spjdstatic int
1525286570Smavhdac_mem_alloc(struct hdac_softc *sc)
1526168404Spjd{
1527168404Spjd	struct hdac_mem *mem;
1528185029Spjd
1529185029Spjd	mem = &sc->mem;
1530185029Spjd	mem->mem_rid = PCIR_BAR(0);
1531185029Spjd	mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1532185029Spjd	    &mem->mem_rid, RF_ACTIVE);
1533185029Spjd	if (mem->mem_res == NULL) {
1534286570Smav		device_printf(sc->dev,
1535185029Spjd		    "%s: Unable to allocate memory resource\n", __func__);
1536185029Spjd		return (ENOMEM);
1537286570Smav	}
1538185029Spjd	mem->mem_tag = rman_get_bustag(mem->mem_res);
1539185029Spjd	mem->mem_handle = rman_get_bushandle(mem->mem_res);
1540185029Spjd
1541185029Spjd	return (0);
1542168404Spjd}
1543185029Spjd
1544168404Spjd/****************************************************************************
1545185029Spjd * void hdac_mem_free(struct hdac_softc *)
1546168404Spjd *
1547168404Spjd * Free up resources previously allocated by hdac_mem_alloc.
1548286570Smav ****************************************************************************/
1549168404Spjdstatic void
1550286570Smavhdac_mem_free(struct hdac_softc *sc)
1551168404Spjd{
1552168404Spjd	struct hdac_mem *mem;
1553168404Spjd
1554168404Spjd	mem = &sc->mem;
1555168404Spjd	if (mem->mem_res != NULL)
1556286570Smav		bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
1557240133Smm		    mem->mem_res);
1558240133Smm	mem->mem_res = NULL;
1559277300Ssmh}
1560168404Spjd
1561168404Spjd/****************************************************************************
1562240133Smm * int hdac_irq_alloc(struct hdac_softc *)
1563240133Smm *
1564240133Smm * Allocate and setup the resources necessary for interrupt handling.
1565240133Smm ****************************************************************************/
1566240133Smmstatic int
1567240133Smmhdac_irq_alloc(struct hdac_softc *sc)
1568240133Smm{
1569240133Smm	struct hdac_irq *irq;
1570240133Smm	int result;
1571240133Smm
1572240133Smm	irq = &sc->irq;
1573240133Smm	irq->irq_rid = 0x0;
1574240133Smm
1575240133Smm#ifdef HDAC_MSI_ENABLED
1576240133Smm	if ((sc->flags & HDAC_F_MSI) &&
1577240133Smm	    (result = pci_msi_count(sc->dev)) == 1 &&
1578240133Smm	    pci_alloc_msi(sc->dev, &result) == 0)
1579240133Smm		irq->irq_rid = 0x1;
1580240133Smm	else
1581240133Smm#endif
1582240133Smm		sc->flags &= ~HDAC_F_MSI;
1583240133Smm
1584240133Smm	irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1585240133Smm	    &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
1586240133Smm	if (irq->irq_res == NULL) {
1587240133Smm		device_printf(sc->dev, "%s: Unable to allocate irq\n",
1588240133Smm		    __func__);
1589240133Smm		goto hdac_irq_alloc_fail;
1590240133Smm	}
1591240133Smm	result = snd_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE,
1592240133Smm	    hdac_intr_handler, sc, &irq->irq_handle);
1593240133Smm	if (result != 0) {
1594240133Smm		device_printf(sc->dev,
1595240133Smm		    "%s: Unable to setup interrupt handler (%x)\n",
1596240133Smm		    __func__, result);
1597240133Smm		goto hdac_irq_alloc_fail;
1598240133Smm	}
1599240133Smm
1600240133Smm	return (0);
1601240133Smm
1602240133Smmhdac_irq_alloc_fail:
1603240133Smm	hdac_irq_free(sc);
1604240133Smm
1605240133Smm	return (ENXIO);
1606240133Smm}
1607286570Smav
1608286570Smav/****************************************************************************
1609286570Smav * void hdac_irq_free(struct hdac_softc *)
1610286570Smav *
1611286570Smav * Free up resources previously allocated by hdac_irq_alloc.
1612286570Smav ****************************************************************************/
1613286570Smavstatic void
1614286570Smavhdac_irq_free(struct hdac_softc *sc)
1615286570Smav{
1616286570Smav	struct hdac_irq *irq;
1617286570Smav
1618286570Smav	irq = &sc->irq;
1619286570Smav	if (irq->irq_res != NULL && irq->irq_handle != NULL)
1620286570Smav		bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
1621286570Smav	if (irq->irq_res != NULL)
1622286570Smav		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1623286570Smav		    irq->irq_res);
1624286570Smav#ifdef HDAC_MSI_ENABLED
1625286570Smav	if ((sc->flags & HDAC_F_MSI) && irq->irq_rid == 0x1)
1626286570Smav		pci_release_msi(sc->dev);
1627286570Smav#endif
1628286570Smav	irq->irq_handle = NULL;
1629286570Smav	irq->irq_res = NULL;
1630286570Smav	irq->irq_rid = 0x0;
1631286570Smav}
1632286570Smav
1633168404Spjd/****************************************************************************
1634168404Spjd * void hdac_corb_init(struct hdac_softc *)
1635168404Spjd *
1636185029Spjd * Initialize the corb registers for operations but do not start it up yet.
1637286570Smav * The CORB engine must not be running when this function is called.
1638185029Spjd ****************************************************************************/
1639286570Smavstatic void
1640185029Spjdhdac_corb_init(struct hdac_softc *sc)
1641185029Spjd{
1642185029Spjd	uint8_t corbsize;
1643168404Spjd	uint64_t corbpaddr;
1644286570Smav
1645168404Spjd	/* Setup the CORB size. */
1646168404Spjd	switch (sc->corb_size) {
1647168404Spjd	case 256:
1648168404Spjd		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
1649219089Spjd		break;
1650286570Smav	case 16:
1651219089Spjd		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
1652286570Smav		break;
1653286570Smav	case 2:
1654286570Smav		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
1655219089Spjd		break;
1656286570Smav	default:
1657219089Spjd		panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
1658286570Smav	}
1659240133Smm	HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
1660240133Smm
1661240133Smm	/* Setup the CORB Address in the hdac */
1662277300Ssmh	corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
1663168404Spjd	HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
1664168404Spjd	HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
1665168404Spjd
1666168404Spjd	/* Set the WP and RP */
1667168404Spjd	sc->corb_wp = 0;
1668219089Spjd	HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
1669219089Spjd	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
1670168404Spjd	/*
1671168404Spjd	 * The HDA specification indicates that the CORBRPRST bit will always
1672168404Spjd	 * read as zero. Unfortunately, it seems that at least the 82801G
1673219089Spjd	 * doesn't reset the bit to zero, which stalls the corb engine.
1674219089Spjd	 * manually reset the bit to zero before continuing.
1675219089Spjd	 */
1676168404Spjd	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
1677286570Smav
1678185029Spjd	/* Enable CORB error reporting */
1679219089Spjd#if 0
1680240133Smm	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
1681168404Spjd#endif
1682168404Spjd}
1683168404Spjd
1684275811Sdelphij/****************************************************************************
1685205231Skmacy * void hdac_rirb_init(struct hdac_softc *)
1686275811Sdelphij *
1687205231Skmacy * Initialize the rirb registers for operations but do not start it up yet.
1688286570Smav * The RIRB engine must not be running when this function is called.
1689206796Spjd ****************************************************************************/
1690205231Skmacystatic void
1691206796Spjdhdac_rirb_init(struct hdac_softc *sc)
1692205231Skmacy{
1693205231Skmacy	uint8_t rirbsize;
1694205231Skmacy	uint64_t rirbpaddr;
1695205231Skmacy
1696205231Skmacy	/* Setup the RIRB size. */
1697205231Skmacy	switch (sc->rirb_size) {
1698205231Skmacy	case 256:
1699205231Skmacy		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
1700205231Skmacy		break;
1701275811Sdelphij	case 16:
1702168404Spjd		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
1703286570Smav		break;
1704168404Spjd	case 2:
1705286570Smav		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
1706168404Spjd		break;
1707286570Smav	default:
1708286570Smav		panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
1709286570Smav	}
1710286570Smav	HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
1711286570Smav
1712286570Smav	/* Setup the RIRB Address in the hdac */
1713286570Smav	rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
1714286570Smav	HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
1715168404Spjd	HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
1716286570Smav
1717286570Smav	/* Setup the WP and RP */
1718286570Smav	sc->rirb_rp = 0;
1719286570Smav	HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
1720286570Smav
1721286570Smav	if (sc->polling == 0) {
1722286570Smav		/* Setup the interrupt threshold */
1723286570Smav		HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
1724286570Smav
1725286570Smav		/* Enable Overrun and response received reporting */
1726286570Smav#if 0
1727286570Smav		HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
1728286570Smav		    HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
1729286570Smav#else
1730168404Spjd		HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
1731185029Spjd#endif
1732286570Smav	}
1733168404Spjd
1734168404Spjd#if 0
1735168404Spjd	/*
1736168404Spjd	 * Make sure that the Host CPU cache doesn't contain any dirty
1737275811Sdelphij	 * cache lines that falls in the rirb. If I understood correctly, it
1738168404Spjd	 * should be sufficient to do this only once as the rirb is purely
1739168404Spjd	 * read-only from now on.
1740286570Smav	 */
1741168404Spjd	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
1742286570Smav	    BUS_DMASYNC_PREREAD);
1743168404Spjd#endif
1744168404Spjd}
1745168404Spjd
1746286570Smav/****************************************************************************
1747286570Smav * void hdac_corb_start(hdac_softc *)
1748286570Smav *
1749286570Smav * Startup the corb DMA engine
1750286570Smav ****************************************************************************/
1751168404Spjdstatic void
1752286570Smavhdac_corb_start(struct hdac_softc *sc)
1753205231Skmacy{
1754205231Skmacy	uint32_t corbctl;
1755185029Spjd
1756275811Sdelphij	corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
1757205231Skmacy	corbctl |= HDAC_CORBCTL_CORBRUN;
1758205231Skmacy	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
1759286570Smav}
1760275811Sdelphij
1761286570Smav/****************************************************************************
1762286570Smav * void hdac_rirb_start(hdac_softc *)
1763286570Smav *
1764206794Spjd * Startup the rirb DMA engine
1765168404Spjd ****************************************************************************/
1766168404Spjdstatic void
1767168404Spjdhdac_rirb_start(struct hdac_softc *sc)
1768168404Spjd{
1769168404Spjd	uint32_t rirbctl;
1770168404Spjd
1771168404Spjd	rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
1772168404Spjd	rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
1773168404Spjd	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
1774275811Sdelphij}
1775275811Sdelphij
1776168404Spjd
1777286570Smav/****************************************************************************
1778286570Smav * void hdac_scan_codecs(struct hdac_softc *, int)
1779286570Smav *
1780168404Spjd * Scan the bus for available codecs, starting with num.
1781286570Smav ****************************************************************************/
1782205231Skmacystatic void
1783205231Skmacyhdac_scan_codecs(struct hdac_softc *sc, int num)
1784168404Spjd{
1785286570Smav	struct hdac_codec *codec;
1786286570Smav	int i;
1787286570Smav	uint16_t statests;
1788286570Smav
1789286570Smav	if (num < 0)
1790286570Smav		num = 0;
1791286570Smav	if (num >= HDAC_CODEC_MAX)
1792286570Smav		num = HDAC_CODEC_MAX - 1;
1793286570Smav
1794286570Smav	statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
1795286570Smav	for (i = num; i < HDAC_CODEC_MAX; i++) {
1796286570Smav		if (HDAC_STATESTS_SDIWAKE(statests, i)) {
1797286570Smav			/* We have found a codec. */
1798286570Smav			codec = (struct hdac_codec *)malloc(sizeof(*codec),
1799286570Smav			    M_HDAC, M_ZERO | M_NOWAIT);
1800286570Smav			if (codec == NULL) {
1801286570Smav				device_printf(sc->dev,
1802168404Spjd				    "Unable to allocate memory for codec\n");
1803258632Savg				continue;
1804286570Smav			}
1805286570Smav			codec->commands = NULL;
1806286570Smav			codec->responses_received = 0;
1807168404Spjd			codec->verbs_sent = 0;
1808286570Smav			codec->sc = sc;
1809168404Spjd			codec->cad = i;
1810168404Spjd			sc->codecs[i] = codec;
1811168404Spjd			if (hdac_probe_codec(codec) != 0)
1812168404Spjd				break;
1813168404Spjd		}
1814168404Spjd	}
1815286570Smav	/* All codecs have been probed, now try to attach drivers to them */
1816205231Skmacy	/* bus_generic_attach(sc->dev); */
1817286570Smav}
1818168404Spjd
1819275811Sdelphij/****************************************************************************
1820205231Skmacy * void hdac_probe_codec(struct hdac_softc *, int)
1821168404Spjd *
1822205231Skmacy * Probe a the given codec_id for available function groups.
1823168404Spjd ****************************************************************************/
1824286570Smavstatic int
1825286570Smavhdac_probe_codec(struct hdac_codec *codec)
1826275811Sdelphij{
1827168404Spjd	struct hdac_softc *sc = codec->sc;
1828168404Spjd	struct hdac_devinfo *devinfo;
1829168404Spjd	uint32_t vendorid, revisionid, subnode;
1830219089Spjd	int startnode;
1831168404Spjd	int endnode;
1832286570Smav	int i;
1833168404Spjd	nid_t cad = codec->cad;
1834286570Smav
1835275811Sdelphij	HDA_BOOTVERBOSE(
1836168404Spjd		device_printf(sc->dev, "HDA_DEBUG: Probing codec: %d\n", cad);
1837185029Spjd	);
1838185029Spjd	vendorid = hdac_command(sc,
1839168404Spjd	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
1840168404Spjd	    cad);
1841205231Skmacy	revisionid = hdac_command(sc,
1842168404Spjd	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
1843286570Smav	    cad);
1844206796Spjd	subnode = hdac_command(sc,
1845286570Smav	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
1846168404Spjd	    cad);
1847286570Smav	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
1848286570Smav	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
1849286570Smav
1850286570Smav	HDA_BOOTVERBOSE(
1851286570Smav		device_printf(sc->dev, "HDA_DEBUG: \tstartnode=%d endnode=%d\n",
1852286570Smav		    startnode, endnode);
1853286570Smav	);
1854275811Sdelphij	for (i = startnode; i < endnode; i++) {
1855205231Skmacy		devinfo = hdac_probe_function(codec, i);
1856168404Spjd		if (devinfo != NULL) {
1857205231Skmacy			/* XXX Ignore other FG. */
1858168404Spjd			devinfo->vendor_id =
1859275811Sdelphij			    HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
1860168404Spjd			devinfo->device_id =
1861168404Spjd			    HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
1862168404Spjd			devinfo->revision_id =
1863286570Smav			    HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
1864286570Smav			devinfo->stepping_id =
1865275811Sdelphij			    HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
1866168404Spjd			HDA_BOOTVERBOSE(
1867185029Spjd				device_printf(sc->dev,
1868168404Spjd				    "HDA_DEBUG: \tFound AFG nid=%d "
1869168404Spjd				    "[startnode=%d endnode=%d]\n",
1870205231Skmacy				    devinfo->nid, startnode, endnode);
1871168404Spjd			);
1872168404Spjd			return (1);
1873168404Spjd		}
1874275811Sdelphij	}
1875275811Sdelphij
1876275811Sdelphij	HDA_BOOTVERBOSE(
1877168404Spjd		device_printf(sc->dev, "HDA_DEBUG: \tAFG not found\n");
1878286570Smav	);
1879286570Smav	return (0);
1880168404Spjd}
1881286570Smav
1882168404Spjdstatic struct hdac_devinfo *
1883168404Spjdhdac_probe_function(struct hdac_codec *codec, nid_t nid)
1884168404Spjd{
1885286570Smav	struct hdac_softc *sc = codec->sc;
1886286570Smav	struct hdac_devinfo *devinfo;
1887185029Spjd	uint32_t fctgrptype;
1888286570Smav	nid_t cad = codec->cad;
1889286570Smav
1890286570Smav	fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
1891286570Smav	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
1892286576Smav
1893286570Smav	/* XXX For now, ignore other FG. */
1894286570Smav	if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
1895286576Smav		return (NULL);
1896168404Spjd
1897168404Spjd	devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC,
1898185029Spjd	    M_NOWAIT | M_ZERO);
1899208373Smm	if (devinfo == NULL) {
1900185029Spjd		device_printf(sc->dev, "%s: Unable to allocate ivar\n",
1901208373Smm		    __func__);
1902208373Smm		return (NULL);
1903208373Smm	}
1904208373Smm
1905208373Smm	devinfo->nid = nid;
1906208373Smm	devinfo->node_type = fctgrptype;
1907286574Smav	devinfo->codec = codec;
1908286574Smav
1909286574Smav	hdac_add_child(sc, devinfo);
1910208373Smm
1911208373Smm	return (devinfo);
1912208373Smm}
1913208373Smm
1914208373Smmstatic void
1915208373Smmhdac_add_child(struct hdac_softc *sc, struct hdac_devinfo *devinfo)
1916208373Smm{
1917208373Smm	devinfo->dev = device_add_child(sc->dev, NULL, -1);
1918208373Smm	device_set_ivars(devinfo->dev, (void *)devinfo);
1919208373Smm	/* XXX - Print more information when booting verbose??? */
1920208373Smm}
1921286574Smav
1922286574Smavstatic void
1923286574Smavhdac_widget_connection_parse(struct hdac_widget *w)
1924185029Spjd{
1925185029Spjd	struct hdac_softc *sc = w->devinfo->codec->sc;
1926185029Spjd	uint32_t res;
1927185029Spjd	int i, j, max, ents, entnum;
1928208373Smm	nid_t cad = w->devinfo->codec->cad;
1929185029Spjd	nid_t nid = w->nid;
1930208373Smm	nid_t cnid, addcnid, prevcnid;
1931208373Smm
1932208373Smm	w->nconns = 0;
1933208373Smm
1934208373Smm	res = hdac_command(sc,
1935208373Smm	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad);
1936286574Smav
1937286574Smav	ents = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res);
1938286574Smav
1939208373Smm	if (ents < 1)
1940208373Smm		return;
1941208373Smm
1942208373Smm	entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4;
1943208373Smm	max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1;
1944208373Smm	prevcnid = 0;
1945208373Smm
1946208373Smm#define CONN_RMASK(e)		(1 << ((32 / (e)) - 1))
1947208373Smm#define CONN_NMASK(e)		(CONN_RMASK(e) - 1)
1948208373Smm#define CONN_RESVAL(r, e, n)	((r) >> ((32 / (e)) * (n)))
1949208373Smm#define CONN_RANGE(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_RMASK(e))
1950286574Smav#define CONN_CNID(r, e, n)	(CONN_RESVAL(r, e, n) & CONN_NMASK(e))
1951286574Smav
1952286574Smav	for (i = 0; i < ents; i += entnum) {
1953286574Smav		res = hdac_command(sc,
1954286574Smav		    HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad);
1955286574Smav		for (j = 0; j < entnum; j++) {
1956286574Smav			cnid = CONN_CNID(res, entnum, j);
1957185029Spjd			if (cnid == 0) {
1958185029Spjd				if (w->nconns < ents)
1959185029Spjd					device_printf(sc->dev,
1960185029Spjd					    "%s: nid=%d WARNING: zero cnid "
1961168404Spjd					    "entnum=%d j=%d index=%d "
1962286570Smav					    "entries=%d found=%d res=0x%08x\n",
1963168404Spjd					    __func__, nid, entnum, j, i,
1964168404Spjd					    ents, w->nconns, res);
1965168404Spjd				else
1966168404Spjd					goto getconns_out;
1967168404Spjd			}
1968286570Smav			if (cnid < w->devinfo->startnode ||
1969168404Spjd			    cnid >= w->devinfo->endnode) {
1970286570Smav				HDA_BOOTVERBOSE(
1971168404Spjd					device_printf(sc->dev,
1972228103Smm					    "%s: GHOST: nid=%d j=%d "
1973286570Smav					    "entnum=%d index=%d res=0x%08x\n",
1974185029Spjd					    __func__, nid, j, entnum, i, res);
1975168404Spjd				);
1976168404Spjd			}
1977168404Spjd			if (CONN_RANGE(res, entnum, j) == 0)
1978168404Spjd				addcnid = cnid;
1979168404Spjd			else if (prevcnid == 0 || prevcnid >= cnid) {
1980286570Smav				device_printf(sc->dev,
1981286570Smav				    "%s: WARNING: Invalid child range "
1982286570Smav				    "nid=%d index=%d j=%d entnum=%d "
1983286570Smav				    "prevcnid=%d cnid=%d res=0x%08x\n",
1984286570Smav				    __func__, nid, i, j, entnum, prevcnid,
1985286570Smav				    cnid, res);
1986286570Smav				addcnid = cnid;
1987286570Smav			} else
1988286570Smav				addcnid = prevcnid + 1;
1989168404Spjd			while (addcnid <= cnid) {
1990286570Smav				if (w->nconns > max) {
1991286570Smav					device_printf(sc->dev,
1992168404Spjd					    "%s: nid=%d: Adding %d: "
1993168404Spjd					    "Max connection reached! max=%d\n",
1994168404Spjd					    __func__, nid, addcnid, max + 1);
1995168404Spjd					goto getconns_out;
1996209962Smm				}
1997209962Smm				w->conns[w->nconns++] = addcnid++;
1998209962Smm			}
1999209962Smm			prevcnid = cnid;
2000209962Smm		}
2001209962Smm	}
2002209962Smm
2003209962Smmgetconns_out:
2004209962Smm	HDA_BOOTVERBOSE(
2005209962Smm		device_printf(sc->dev,
2006209962Smm		    "HDA_DEBUG: %s: nid=%d entries=%d found=%d\n",
2007209962Smm		    __func__, nid, ents, w->nconns);
2008209962Smm	);
2009209962Smm	return;
2010209962Smm}
2011209962Smm
2012209962Smmstatic uint32_t
2013209962Smmhdac_widget_pin_getconfig(struct hdac_widget *w)
2014209962Smm{
2015209962Smm	struct hdac_softc *sc;
2016209962Smm	uint32_t config, orig, id;
2017209962Smm	nid_t cad, nid;
2018209962Smm
2019209962Smm	sc = w->devinfo->codec->sc;
2020209962Smm	cad = w->devinfo->codec->cad;
2021209962Smm	nid = w->nid;
2022209962Smm	id = hdac_codec_id(w->devinfo);
2023209962Smm
2024286570Smav	config = hdac_command(sc,
2025286570Smav	    HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
2026286570Smav	    cad);
2027209962Smm	orig = config;
2028209962Smm
2029209962Smm	/*
2030209962Smm	 * XXX REWRITE!!!! Don't argue!
2031219089Spjd	 */
2032219089Spjd	if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) {
2033219089Spjd		switch (nid) {
2034219089Spjd		case 26:
2035286570Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2036219089Spjd			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2037219089Spjd			break;
2038286570Smav		case 27:
2039286570Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2040286570Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
2041219089Spjd			break;
2042219089Spjd		default:
2043219089Spjd			break;
2044219089Spjd		}
2045219089Spjd	} else if (id == HDA_CODEC_ALC880 &&
2046219089Spjd	    (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR ||
2047168404Spjd	    sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) {
2048168404Spjd		/*
2049168404Spjd		 * Super broken BIOS
2050168404Spjd		 */
2051168404Spjd		switch (nid) {
2052168404Spjd		case 20:
2053168404Spjd			break;
2054286570Smav		case 21:
2055286570Smav			break;
2056219089Spjd		case 22:
2057185029Spjd			break;
2058168404Spjd		case 23:
2059168404Spjd			break;
2060168404Spjd		case 24:	/* MIC1 */
2061168404Spjd			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2062286570Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2063286570Smav			break;
2064168404Spjd		case 25:	/* XXX MIC2 */
2065168404Spjd			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2066242845Sdelphij			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2067242845Sdelphij			break;
2068242845Sdelphij		case 26:	/* LINE1 */
2069242845Sdelphij			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2070242845Sdelphij			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2071242845Sdelphij			break;
2072242845Sdelphij		case 27:	/* XXX LINE2 */
2073286570Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2074242845Sdelphij			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2075242845Sdelphij			break;
2076242845Sdelphij		case 28:	/* CD */
2077286570Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2078168404Spjd			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
2079168404Spjd			break;
2080168404Spjd		case 30:
2081168404Spjd			break;
2082168404Spjd		case 31:
2083168404Spjd			break;
2084168404Spjd		default:
2085168404Spjd			break;
2086168404Spjd		}
2087168404Spjd	} else if (id == HDA_CODEC_ALC883 &&
2088185029Spjd	    (sc->pci_subvendor == MSI_MS034A_SUBVENDOR ||
2089185029Spjd	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor))) {
2090185029Spjd		switch (nid) {
2091168404Spjd		case 25:
2092219089Spjd			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2093185029Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2094219089Spjd			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2095168404Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2096168404Spjd			break;
2097219089Spjd		case 28:
2098219089Spjd			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2099185029Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2100286570Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2101219089Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2102219089Spjd			break;
2103168404Spjd		default:
2104286570Smav			break;
2105286570Smav		}
2106286570Smav	} else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor ==
2107168404Spjd	    HP_V3000_SUBVENDOR) {
2108208373Smm		switch (nid) {
2109168404Spjd		case 18:
2110168404Spjd			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2111168404Spjd			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2112286570Smav			break;
2113286570Smav		case 20:
2114168404Spjd			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2115168404Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2116168404Spjd			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2117274172Savg			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2118274172Savg			break;
2119274172Savg		case 21:
2120274172Savg			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2121274172Savg			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2122274172Savg			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2123274172Savg			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2124274172Savg			break;
2125274172Savg		default:
2126274172Savg			break;
2127274172Savg		}
2128274172Savg	} else if (id == HDA_CODEC_CXWAIKIKI && sc->pci_subvendor ==
2129274172Savg	    HP_DV5000_SUBVENDOR) {
2130274172Savg		switch (nid) {
2131274172Savg		case 20:
2132185029Spjd		case 21:
2133185029Spjd			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2134185029Spjd			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2135185029Spjd			break;
2136168404Spjd		default:
2137240133Smm			break;
2138185029Spjd		}
2139240133Smm	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2140240133Smm	    ASUS_W6F_SUBVENDOR) {
2141185029Spjd		switch (nid) {
2142274172Savg		case 11:
2143185029Spjd			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2144185029Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2145240133Smm			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
2146185029Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2147185029Spjd			break;
2148185029Spjd		case 15:
2149268858Sdelphij			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2150268858Sdelphij			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2151268858Sdelphij			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2152268858Sdelphij			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2153185029Spjd			break;
2154274172Savg		default:
2155274172Savg			break;
2156286570Smav		}
2157286570Smav	} else if (id == HDA_CODEC_ALC861 && sc->pci_subvendor ==
2158274172Savg	    UNIWILL_9075_SUBVENDOR) {
2159286570Smav		switch (nid) {
2160286570Smav		case 15:
2161286570Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2162286570Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2163286570Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2164286570Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2165286570Smav			break;
2166274172Savg		default:
2167286570Smav			break;
2168274172Savg		}
2169274172Savg	} else if (id == HDA_CODEC_AD1986A &&
2170274172Savg	    (sc->pci_subvendor == ASUS_M2NPVMX_SUBVENDOR ||
2171286570Smav	    sc->pci_subvendor == ASUS_A8NVMCSM_SUBVENDOR)) {
2172274172Savg		switch (nid) {
2173286570Smav		case 28:	/* LINE */
2174274172Savg			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2175286570Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
2176274172Savg			break;
2177274172Savg		case 29:	/* MIC */
2178274172Savg			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2179268858Sdelphij			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
2180168404Spjd			break;
2181168404Spjd		default:
2182168404Spjd			break;
2183168404Spjd		}
2184286570Smav	} else if (id == HDA_CODEC_ALC268 &&
2185286570Smav	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) {
2186168404Spjd		switch (nid) {
2187286570Smav		case 28:
2188168404Spjd			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2189168404Spjd			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2190240133Smm			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2191240133Smm			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2192277300Ssmh			break;
2193219089Spjd		default:
2194168404Spjd			break;
2195168404Spjd		}
2196240133Smm	}
2197286574Smav
2198168404Spjd	HDA_BOOTVERBOSE(
2199168404Spjd		if (config != orig)
2200240133Smm			device_printf(sc->dev,
2201286574Smav			    "HDA_DEBUG: Pin config nid=%u 0x%08x -> 0x%08x\n",
2202168404Spjd			    nid, orig, config);
2203168404Spjd	);
2204286570Smav
2205185029Spjd	return (config);
2206185029Spjd}
2207286570Smav
2208286570Smavstatic uint32_t
2209286570Smavhdac_widget_pin_getcaps(struct hdac_widget *w)
2210185029Spjd{
2211185029Spjd	struct hdac_softc *sc;
2212185029Spjd	uint32_t caps, orig, id;
2213168404Spjd	nid_t cad, nid;
2214168404Spjd
2215168404Spjd	sc = w->devinfo->codec->sc;
2216168404Spjd	cad = w->devinfo->codec->cad;
2217242845Sdelphij	nid = w->nid;
2218242845Sdelphij	id = hdac_codec_id(w->devinfo);
2219242845Sdelphij
2220242845Sdelphij	caps = hdac_command(sc,
2221242845Sdelphij	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
2222286570Smav	orig = caps;
2223286570Smav
2224242845Sdelphij	HDA_BOOTVERBOSE(
2225242845Sdelphij		if (caps != orig)
2226242845Sdelphij			device_printf(sc->dev,
2227286570Smav			    "HDA_DEBUG: Pin caps nid=%u 0x%08x -> 0x%08x\n",
2228286570Smav			    nid, orig, caps);
2229168404Spjd	);
2230168404Spjd
2231168404Spjd	return (caps);
2232268858Sdelphij}
2233168404Spjd
2234168404Spjdstatic void
2235168404Spjdhdac_widget_pin_parse(struct hdac_widget *w)
2236286570Smav{
2237286570Smav	struct hdac_softc *sc = w->devinfo->codec->sc;
2238168404Spjd	uint32_t config, pincap;
2239168404Spjd	char *devstr, *connstr;
2240219089Spjd	nid_t cad = w->devinfo->codec->cad;
2241168404Spjd	nid_t nid = w->nid;
2242168404Spjd
2243168404Spjd	config = hdac_widget_pin_getconfig(w);
2244168404Spjd	w->wclass.pin.config = config;
2245168404Spjd
2246168404Spjd	pincap = hdac_widget_pin_getcaps(w);
2247168404Spjd	w->wclass.pin.cap = pincap;
2248168404Spjd
2249168404Spjd	w->wclass.pin.ctrl = hdac_command(sc,
2250286598Smav	    HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) &
2251286598Smav	    ~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
2252286598Smav	    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
2253286598Smav	    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
2254286598Smav	    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
2255286598Smav
2256286598Smav	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
2257286598Smav		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
2258286598Smav	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
2259286598Smav		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
2260286598Smav	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
2261286598Smav		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
2262286598Smav	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
2263286598Smav		w->param.eapdbtl = hdac_command(sc,
2264286598Smav		    HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
2265286598Smav		w->param.eapdbtl &= 0x7;
2266286598Smav		w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
2267286598Smav	} else
2268286598Smav		w->param.eapdbtl = HDAC_INVALID;
2269286598Smav
2270286598Smav	switch (config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
2271286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
2272286598Smav		devstr = "line out";
2273286598Smav		break;
2274286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
2275286598Smav		devstr = "speaker";
2276286598Smav		break;
2277286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
2278286598Smav		devstr = "headphones out";
2279286598Smav		break;
2280286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
2281286598Smav		devstr = "CD";
2282286598Smav		break;
2283286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
2284286598Smav		devstr = "SPDIF out";
2285286598Smav		break;
2286286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
2287286598Smav		devstr = "digital (other) out";
2288286598Smav		break;
2289286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE:
2290286598Smav		devstr = "modem, line side";
2291286598Smav		break;
2292286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET:
2293286598Smav		devstr = "modem, handset side";
2294286598Smav		break;
2295286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
2296286598Smav		devstr = "line in";
2297286598Smav		break;
2298286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
2299286598Smav		devstr = "AUX";
2300286598Smav		break;
2301168404Spjd	case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
2302168404Spjd		devstr = "Mic in";
2303286570Smav		break;
2304286570Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY:
2305286570Smav		devstr = "telephony";
2306286570Smav		break;
2307286570Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
2308286570Smav		devstr = "SPDIF in";
2309168404Spjd		break;
2310286570Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
2311168404Spjd		devstr = "digital (other) in";
2312286570Smav		break;
2313286598Smav	case HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER:
2314286598Smav		devstr = "other";
2315286570Smav		break;
2316286598Smav	default:
2317286598Smav		devstr = "unknown";
2318219089Spjd		break;
2319286570Smav	}
2320286598Smav
2321286598Smav	switch (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) {
2322286598Smav	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK:
2323286598Smav		connstr = "jack";
2324286598Smav		break;
2325286598Smav	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE:
2326286598Smav		connstr = "none";
2327286570Smav		break;
2328286598Smav	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED:
2329286598Smav		connstr = "fixed";
2330286598Smav		break;
2331286598Smav	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH:
2332286598Smav		connstr = "jack / fixed";
2333286570Smav		break;
2334219089Spjd	default:
2335286598Smav		connstr = "unknown";
2336185029Spjd		break;
2337185029Spjd	}
2338286570Smav
2339219089Spjd	strlcat(w->name, ": ", sizeof(w->name));
2340168404Spjd	strlcat(w->name, devstr, sizeof(w->name));
2341168404Spjd	strlcat(w->name, " (", sizeof(w->name));
2342168404Spjd	strlcat(w->name, connstr, sizeof(w->name));
2343168404Spjd	strlcat(w->name, ")", sizeof(w->name));
2344286570Smav}
2345286570Smav
2346286570Smavstatic void
2347286570Smavhdac_widget_parse(struct hdac_widget *w)
2348286570Smav{
2349286570Smav	struct hdac_softc *sc = w->devinfo->codec->sc;
2350286570Smav	uint32_t wcap, cap;
2351286570Smav	char *typestr;
2352286570Smav	nid_t cad = w->devinfo->codec->cad;
2353286570Smav	nid_t nid = w->nid;
2354286570Smav
2355286570Smav	wcap = hdac_command(sc,
2356286570Smav	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
2357286570Smav	    cad);
2358286570Smav	w->param.widget_cap = wcap;
2359286570Smav	w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
2360286570Smav
2361286570Smav	switch (w->type) {
2362286570Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
2363286570Smav		typestr = "audio output";
2364286570Smav		break;
2365286570Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
2366286570Smav		typestr = "audio input";
2367286570Smav		break;
2368286570Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
2369286570Smav		typestr = "audio mixer";
2370286570Smav		break;
2371286570Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
2372219089Spjd		typestr = "audio selector";
2373168404Spjd		break;
2374168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
2375286570Smav		typestr = "pin";
2376286570Smav		break;
2377286570Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET:
2378286570Smav		typestr = "power widget";
2379286570Smav		break;
2380286570Smav	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET:
2381286570Smav		typestr = "volume widget";
2382168404Spjd		break;
2383168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
2384168404Spjd		typestr = "beep widget";
2385168404Spjd		break;
2386168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET:
2387168404Spjd		typestr = "vendor widget";
2388286570Smav		break;
2389168404Spjd	default:
2390168404Spjd		typestr = "unknown type";
2391168404Spjd		break;
2392168404Spjd	}
2393168404Spjd
2394168404Spjd	strlcpy(w->name, typestr, sizeof(w->name));
2395168404Spjd
2396168404Spjd	if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(wcap)) {
2397219089Spjd		hdac_command(sc,
2398219089Spjd		    HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0),
2399219089Spjd		    cad);
2400168404Spjd		DELAY(1000);
2401286570Smav	}
2402168404Spjd
2403219089Spjd	hdac_widget_connection_parse(w);
2404286570Smav
2405219089Spjd	if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
2406275811Sdelphij		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2407219089Spjd			w->param.outamp_cap =
2408168404Spjd			    hdac_command(sc,
2409168404Spjd			    HDA_CMD_GET_PARAMETER(cad, nid,
2410168404Spjd			    HDA_PARAM_OUTPUT_AMP_CAP), cad);
2411168404Spjd		else
2412168404Spjd			w->param.outamp_cap =
2413168404Spjd			    w->devinfo->function.audio.outamp_cap;
2414168404Spjd	} else
2415168404Spjd		w->param.outamp_cap = 0;
2416168404Spjd
2417168404Spjd	if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) {
2418286570Smav		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2419168404Spjd			w->param.inamp_cap =
2420168404Spjd			    hdac_command(sc,
2421168404Spjd			    HDA_CMD_GET_PARAMETER(cad, nid,
2422168404Spjd			    HDA_PARAM_INPUT_AMP_CAP), cad);
2423168404Spjd		else
2424219089Spjd			w->param.inamp_cap =
2425168404Spjd			    w->devinfo->function.audio.inamp_cap;
2426219089Spjd	} else
2427168404Spjd		w->param.inamp_cap = 0;
2428168404Spjd
2429168404Spjd	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
2430168404Spjd	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
2431248571Smm		if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) {
2432168404Spjd			cap = hdac_command(sc,
2433168404Spjd			    HDA_CMD_GET_PARAMETER(cad, nid,
2434168404Spjd			    HDA_PARAM_SUPP_STREAM_FORMATS), cad);
2435168404Spjd			w->param.supp_stream_formats = (cap != 0) ? cap :
2436248571Smm			    w->devinfo->function.audio.supp_stream_formats;
2437168404Spjd			cap = hdac_command(sc,
2438286570Smav			    HDA_CMD_GET_PARAMETER(cad, nid,
2439286570Smav			    HDA_PARAM_SUPP_PCM_SIZE_RATE), cad);
2440168404Spjd			w->param.supp_pcm_size_rate = (cap != 0) ? cap :
2441168404Spjd			    w->devinfo->function.audio.supp_pcm_size_rate;
2442168404Spjd		} else {
2443168404Spjd			w->param.supp_stream_formats =
2444168404Spjd			    w->devinfo->function.audio.supp_stream_formats;
2445219089Spjd			w->param.supp_pcm_size_rate =
2446286570Smav			    w->devinfo->function.audio.supp_pcm_size_rate;
2447219089Spjd		}
2448286570Smav	} else {
2449168404Spjd		w->param.supp_stream_formats = 0;
2450168404Spjd		w->param.supp_pcm_size_rate = 0;
2451168404Spjd	}
2452286570Smav
2453168404Spjd	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
2454168404Spjd		hdac_widget_pin_parse(w);
2455168404Spjd}
2456286570Smav
2457219089Spjdstatic struct hdac_widget *
2458275811Sdelphijhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid)
2459168404Spjd{
2460286570Smav	if (devinfo == NULL || devinfo->widget == NULL ||
2461286570Smav		    nid < devinfo->startnode || nid >= devinfo->endnode)
2462168404Spjd		return (NULL);
2463168404Spjd	return (&devinfo->widget[nid - devinfo->startnode]);
2464168404Spjd}
2465168404Spjd
2466286570Smavstatic __inline int
2467168404Spjdhda_poll_channel(struct hdac_chan *ch)
2468168404Spjd{
2469168404Spjd	uint32_t sz, delta;
2470168404Spjd	volatile uint32_t ptr;
2471168404Spjd
2472168404Spjd	if (!(ch->flags & HDAC_CHN_RUNNING))
2473242845Sdelphij		return (0);
2474242845Sdelphij
2475242845Sdelphij	sz = ch->blksz * ch->blkcnt;
2476242845Sdelphij	if (ch->dmapos != NULL)
2477242845Sdelphij		ptr = *(ch->dmapos);
2478242845Sdelphij	else
2479242845Sdelphij		ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem,
2480242845Sdelphij		    ch->off + HDAC_SDLPIB);
2481242845Sdelphij	ch->ptr = ptr;
2482242845Sdelphij	ptr %= sz;
2483242845Sdelphij	ptr &= ~(ch->blksz - 1);
2484242845Sdelphij	delta = (sz + ptr - ch->prevptr) % sz;
2485242845Sdelphij
2486242845Sdelphij	if (delta < ch->blksz)
2487242845Sdelphij		return (0);
2488242845Sdelphij
2489242845Sdelphij	ch->prevptr = ptr;
2490242845Sdelphij
2491242845Sdelphij	return (1);
2492242845Sdelphij}
2493242845Sdelphij
2494242845Sdelphij#define hda_chan_active(sc)	(((sc)->play.flags | (sc)->rec.flags) &	\
2495242845Sdelphij				 HDAC_CHN_RUNNING)
2496242845Sdelphij
2497242845Sdelphijstatic void
2498242845Sdelphijhda_poll_callback(void *arg)
2499242845Sdelphij{
2500242845Sdelphij	struct hdac_softc *sc = arg;
2501242845Sdelphij	uint32_t trigger;
2502242845Sdelphij
2503242845Sdelphij	if (sc == NULL)
2504242845Sdelphij		return;
2505242845Sdelphij
2506242845Sdelphij	hdac_lock(sc);
2507286570Smav	if (sc->polling == 0 || hda_chan_active(sc) == 0) {
2508242845Sdelphij		hdac_unlock(sc);
2509242845Sdelphij		return;
2510242845Sdelphij	}
2511242845Sdelphij
2512242845Sdelphij	trigger = 0;
2513242845Sdelphij	trigger |= (hda_poll_channel(&sc->play) != 0) ? HDAC_TRIGGER_PLAY : 0;
2514242845Sdelphij	trigger |= (hda_poll_channel(&sc->rec)) != 0 ? HDAC_TRIGGER_REC : 0;
2515168404Spjd
2516168404Spjd	/* XXX */
2517168404Spjd	callout_reset(&sc->poll_hda, 1/*sc->poll_ticks*/,
2518168404Spjd	    hda_poll_callback, sc);
2519168404Spjd
2520168404Spjd	hdac_unlock(sc);
2521168404Spjd
2522185029Spjd	if (trigger & HDAC_TRIGGER_PLAY)
2523185029Spjd		chn_intr(sc->play.c);
2524185029Spjd	if (trigger & HDAC_TRIGGER_REC)
2525185029Spjd		chn_intr(sc->rec.c);
2526168404Spjd}
2527168404Spjd
2528209962Smmstatic int
2529168404Spjdhdac_rirb_flush(struct hdac_softc *sc)
2530168404Spjd{
2531168404Spjd	struct hdac_rirb *rirb_base, *rirb;
2532168404Spjd	struct hdac_codec *codec;
2533205231Skmacy	struct hdac_command_list *commands;
2534275811Sdelphij	nid_t cad;
2535205231Skmacy	uint32_t resp;
2536205231Skmacy	uint8_t rirbwp;
2537168404Spjd	int ret;
2538168404Spjd
2539168404Spjd	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2540258632Savg	rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
2541258632Savg#if 0
2542205231Skmacy	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2543258632Savg	    BUS_DMASYNC_POSTREAD);
2544168404Spjd#endif
2545168404Spjd
2546168404Spjd	ret = 0;
2547168404Spjd
2548206796Spjd	while (sc->rirb_rp != rirbwp) {
2549275780Sdelphij		sc->rirb_rp++;
2550275780Sdelphij		sc->rirb_rp %= sc->rirb_size;
2551275780Sdelphij		rirb = &rirb_base[sc->rirb_rp];
2552275780Sdelphij		cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
2553275780Sdelphij		if (cad < 0 || cad >= HDAC_CODEC_MAX ||
2554275780Sdelphij		    sc->codecs[cad] == NULL)
2555275780Sdelphij			continue;
2556275780Sdelphij		resp = rirb->response;
2557275780Sdelphij		codec = sc->codecs[cad];
2558275780Sdelphij		commands = codec->commands;
2559275780Sdelphij		if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
2560275780Sdelphij			sc->unsolq[sc->unsolq_wp++] = (cad << 16) |
2561275780Sdelphij			    ((resp >> 26) & 0xffff);
2562275780Sdelphij			sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
2563275780Sdelphij		} else if (commands != NULL && commands->num_commands > 0 &&
2564275780Sdelphij		    codec->responses_received < commands->num_commands)
2565275780Sdelphij			commands->responses[codec->responses_received++] =
2566275780Sdelphij			    resp;
2567286570Smav		ret++;
2568286570Smav	}
2569286570Smav
2570286570Smav	return (ret);
2571286570Smav}
2572286570Smav
2573275780Sdelphijstatic int
2574286570Smavhdac_unsolq_flush(struct hdac_softc *sc)
2575275780Sdelphij{
2576286570Smav	nid_t cad;
2577275780Sdelphij	uint32_t tag;
2578275780Sdelphij	int ret = 0;
2579275780Sdelphij
2580275780Sdelphij	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
2581275780Sdelphij		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
2582275780Sdelphij		while (sc->unsolq_rp != sc->unsolq_wp) {
2583275780Sdelphij			cad = sc->unsolq[sc->unsolq_rp] >> 16;
2584275780Sdelphij			tag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
2585275780Sdelphij			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
2586275780Sdelphij			hdac_unsolicited_handler(sc->codecs[cad], tag);
2587275780Sdelphij			ret++;
2588275780Sdelphij		}
2589275780Sdelphij		sc->unsolq_st = HDAC_UNSOLQ_READY;
2590275780Sdelphij	}
2591275780Sdelphij
2592275780Sdelphij	return (ret);
2593205231Skmacy}
2594205231Skmacy
2595205231Skmacystatic void
2596205231Skmacyhdac_poll_callback(void *arg)
2597205231Skmacy{
2598205231Skmacy	struct hdac_softc *sc = arg;
2599205231Skmacy	if (sc == NULL)
2600205231Skmacy		return;
2601205231Skmacy
2602205231Skmacy	hdac_lock(sc);
2603205231Skmacy	if (sc->polling == 0 || sc->poll_ival == 0) {
2604205231Skmacy		hdac_unlock(sc);
2605205231Skmacy		return;
2606205231Skmacy	}
2607258632Savg	if (hdac_rirb_flush(sc) != 0)
2608206796Spjd		hdac_unsolq_flush(sc);
2609205231Skmacy	callout_reset(&sc->poll_hdac, sc->poll_ival, hdac_poll_callback, sc);
2610205231Skmacy	hdac_unlock(sc);
2611205231Skmacy}
2612205231Skmacy
2613206796Spjdstatic void
2614168404Spjdhdac_stream_stop(struct hdac_chan *ch)
2615286570Smav{
2616286570Smav	struct hdac_softc *sc = ch->devinfo->codec->sc;
2617286570Smav	uint32_t ctl;
2618286570Smav
2619286570Smav	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2620286570Smav	ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2621286570Smav	    HDAC_SDCTL_RUN);
2622286570Smav	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2623286570Smav
2624286570Smav	ch->flags &= ~HDAC_CHN_RUNNING;
2625286570Smav
2626286570Smav	if (sc->polling != 0) {
2627286570Smav		int pollticks;
2628205231Skmacy
2629205231Skmacy		if (hda_chan_active(sc) == 0) {
2630275811Sdelphij			callout_stop(&sc->poll_hda);
2631275811Sdelphij			sc->poll_ticks = 1;
2632286570Smav		} else {
2633286570Smav			if (sc->play.flags & HDAC_CHN_RUNNING)
2634286570Smav				ch = &sc->play;
2635286570Smav			else
2636168404Spjd				ch = &sc->rec;
2637275811Sdelphij			pollticks = ((uint64_t)hz * ch->blksz) /
2638275811Sdelphij			    ((uint64_t)sndbuf_getbps(ch->b) *
2639286570Smav			    sndbuf_getspd(ch->b));
2640286570Smav			pollticks >>= 2;
2641219089Spjd			if (pollticks > hz)
2642168404Spjd				pollticks = hz;
2643168404Spjd			if (pollticks < 1) {
2644168404Spjd				HDA_BOOTVERBOSE(
2645168404Spjd					device_printf(sc->dev,
2646275811Sdelphij					    "%s: pollticks=%d < 1 !\n",
2647275811Sdelphij					    __func__, pollticks);
2648168404Spjd				);
2649258632Savg				pollticks = 1;
2650258632Savg			}
2651275811Sdelphij			if (pollticks > sc->poll_ticks) {
2652258632Savg				HDA_BOOTVERBOSE(
2653258632Savg					device_printf(sc->dev,
2654258632Savg					    "%s: pollticks %d -> %d\n",
2655258632Savg					    __func__, sc->poll_ticks,
2656258632Savg					    pollticks);
2657258632Savg				);
2658258632Savg				sc->poll_ticks = pollticks;
2659258632Savg				callout_reset(&sc->poll_hda, 1,
2660258632Savg				    hda_poll_callback, sc);
2661258632Savg			}
2662258632Savg		}
2663258632Savg	} else {
2664275811Sdelphij		ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2665286570Smav		ctl &= ~(1 << (ch->off >> 5));
2666258632Savg		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2667258632Savg	}
2668286570Smav}
2669258632Savg
2670275811Sdelphijstatic void
2671258632Savghdac_stream_start(struct hdac_chan *ch)
2672258632Savg{
2673258632Savg	struct hdac_softc *sc = ch->devinfo->codec->sc;
2674258632Savg	uint32_t ctl;
2675258632Savg
2676275811Sdelphij	if (sc->polling != 0) {
2677168404Spjd		int pollticks;
2678168404Spjd
2679286570Smav		pollticks = ((uint64_t)hz * ch->blksz) /
2680286570Smav		    ((uint64_t)sndbuf_getbps(ch->b) * sndbuf_getspd(ch->b));
2681286570Smav		pollticks >>= 2;
2682286570Smav		if (pollticks > hz)
2683219089Spjd			pollticks = hz;
2684185029Spjd		if (pollticks < 1) {
2685185029Spjd			HDA_BOOTVERBOSE(
2686185029Spjd				device_printf(sc->dev,
2687286570Smav				    "%s: pollticks=%d < 1 !\n",
2688275811Sdelphij				    __func__, pollticks);
2689286570Smav			);
2690286570Smav			pollticks = 1;
2691275811Sdelphij		}
2692275811Sdelphij		if (hda_chan_active(sc) == 0 || pollticks < sc->poll_ticks) {
2693168404Spjd			HDA_BOOTVERBOSE(
2694168404Spjd				if (hda_chan_active(sc) == 0) {
2695168404Spjd					device_printf(sc->dev,
2696168404Spjd					    "%s: pollticks=%d\n",
2697286570Smav					    __func__, pollticks);
2698168404Spjd				} else {
2699168404Spjd					device_printf(sc->dev,
2700168404Spjd					    "%s: pollticks %d -> %d\n",
2701286570Smav					    __func__, sc->poll_ticks,
2702168404Spjd					    pollticks);
2703168404Spjd				}
2704168404Spjd			);
2705168404Spjd			sc->poll_ticks = pollticks;
2706219089Spjd			callout_reset(&sc->poll_hda, 1, hda_poll_callback,
2707168404Spjd			    sc);
2708219089Spjd		}
2709168404Spjd		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2710168404Spjd		ctl |= HDAC_SDCTL_RUN;
2711168404Spjd	} else {
2712168404Spjd		ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2713208373Smm		ctl |= 1 << (ch->off >> 5);
2714286570Smav		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2715208373Smm		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2716275811Sdelphij		ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2717208373Smm		    HDAC_SDCTL_RUN;
2718275811Sdelphij	}
2719208373Smm	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2720275811Sdelphij
2721208373Smm	ch->flags |= HDAC_CHN_RUNNING;
2722208373Smm}
2723208373Smm
2724275811Sdelphijstatic void
2725208373Smmhdac_stream_reset(struct hdac_chan *ch)
2726208373Smm{
2727208373Smm	struct hdac_softc *sc = ch->devinfo->codec->sc;
2728286570Smav	int timeout = 1000;
2729275811Sdelphij	int to = timeout;
2730275811Sdelphij	uint32_t ctl;
2731275811Sdelphij
2732275811Sdelphij	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2733275811Sdelphij	ctl |= HDAC_SDCTL_SRST;
2734185029Spjd	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2735168404Spjd	do {
2736168404Spjd		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2737168404Spjd		if (ctl & HDAC_SDCTL_SRST)
2738168404Spjd			break;
2739205231Skmacy		DELAY(10);
2740205231Skmacy	} while (--to);
2741205231Skmacy	if (!(ctl & HDAC_SDCTL_SRST)) {
2742206796Spjd		device_printf(sc->dev, "timeout in reset\n");
2743258632Savg	}
2744205231Skmacy	ctl &= ~HDAC_SDCTL_SRST;
2745205231Skmacy	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2746168404Spjd	to = timeout;
2747168404Spjd	do {
2748168404Spjd		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2749168404Spjd		if (!(ctl & HDAC_SDCTL_SRST))
2750168404Spjd			break;
2751286570Smav		DELAY(10);
2752205231Skmacy	} while (--to);
2753206796Spjd	if (ctl & HDAC_SDCTL_SRST)
2754206796Spjd		device_printf(sc->dev, "can't reset!\n");
2755258632Savg}
2756168404Spjd
2757205231Skmacystatic void
2758258632Savghdac_stream_setid(struct hdac_chan *ch)
2759205231Skmacy{
2760205231Skmacy	struct hdac_softc *sc = ch->devinfo->codec->sc;
2761205231Skmacy	uint32_t ctl;
2762205231Skmacy
2763205231Skmacy	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2);
2764206796Spjd	ctl &= ~HDAC_SDCTL2_STRM_MASK;
2765205231Skmacy	ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT;
2766205231Skmacy	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl);
2767205231Skmacy}
2768206796Spjd
2769168404Spjdstatic void
2770168404Spjdhdac_bdl_setup(struct hdac_chan *ch)
2771168404Spjd{
2772168404Spjd	struct hdac_softc *sc = ch->devinfo->codec->sc;
2773168404Spjd	struct hdac_bdle *bdle;
2774168404Spjd	uint64_t addr;
2775185029Spjd	uint32_t blksz, blkcnt;
2776258632Savg	int i;
2777258632Savg
2778258632Savg	addr = (uint64_t)sndbuf_getbufaddr(ch->b);
2779258632Savg	bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr;
2780185029Spjd
2781185029Spjd	if (sc->polling != 0) {
2782205231Skmacy		blksz = ch->blksz * ch->blkcnt;
2783205231Skmacy		blkcnt = 1;
2784168404Spjd	} else {
2785168404Spjd		blksz = ch->blksz;
2786168404Spjd		blkcnt = ch->blkcnt;
2787168404Spjd	}
2788168404Spjd
2789168404Spjd	for (i = 0; i < blkcnt; i++, bdle++) {
2790168404Spjd		bdle->addrl = (uint32_t)addr;
2791168404Spjd		bdle->addrh = (uint32_t)(addr >> 32);
2792209962Smm		bdle->len = blksz;
2793168404Spjd		bdle->ioc = 1 ^ sc->polling;
2794275811Sdelphij		addr += blksz;
2795219089Spjd	}
2796205231Skmacy
2797205231Skmacy	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt);
2798168404Spjd	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1);
2799168404Spjd	addr = ch->bdl_dma.dma_paddr;
2800258632Savg	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr);
2801205231Skmacy	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
2802205231Skmacy	if (ch->dmapos != NULL &&
2803258632Savg	    !(HDAC_READ_4(&sc->mem, HDAC_DPIBLBASE) & 0x00000001)) {
2804168404Spjd		addr = sc->pos_dma.dma_paddr;
2805168404Spjd		HDAC_WRITE_4(&sc->mem, HDAC_DPIBLBASE,
2806205231Skmacy		    ((uint32_t)addr & HDAC_DPLBASE_DPLBASE_MASK) | 0x00000001);
2807205231Skmacy		HDAC_WRITE_4(&sc->mem, HDAC_DPIBUBASE, (uint32_t)(addr >> 32));
2808205231Skmacy	}
2809205231Skmacy}
2810205231Skmacy
2811205231Skmacystatic int
2812205231Skmacyhdac_bdl_alloc(struct hdac_chan *ch)
2813206796Spjd{
2814205231Skmacy	struct hdac_softc *sc = ch->devinfo->codec->sc;
2815205231Skmacy	int rc;
2816205231Skmacy
2817205231Skmacy	rc = hdac_dma_alloc(sc, &ch->bdl_dma,
2818205231Skmacy	    sizeof(struct hdac_bdle) * HDA_BDL_MAX);
2819275811Sdelphij	if (rc) {
2820275811Sdelphij		device_printf(sc->dev, "can't alloc bdl\n");
2821286570Smav		return (rc);
2822275811Sdelphij	}
2823275811Sdelphij
2824185029Spjd	return (0);
2825219089Spjd}
2826219089Spjd
2827275811Sdelphijstatic void
2828219089Spjdhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid,
2829219089Spjd					int index, int lmute, int rmute,
2830275811Sdelphij					int left, int right, int dir)
2831219089Spjd{
2832219089Spjd	uint16_t v = 0;
2833219089Spjd
2834258632Savg	if (sc == NULL)
2835258632Savg		return;
2836258632Savg
2837258632Savg	if (left != right || lmute != rmute) {
2838258632Savg		v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
2839258632Savg		    (lmute << 7) | left;
2840258632Savg		hdac_command(sc,
2841258632Savg		    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2842275811Sdelphij		v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
2843258632Savg		    (rmute << 7) | right;
2844258632Savg	} else
2845258632Savg		v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
2846275811Sdelphij		    (lmute << 7) | left;
2847258632Savg
2848258632Savg	hdac_command(sc,
2849258632Savg	    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2850258632Savg}
2851168404Spjd
2852275811Sdelphijstatic void
2853286570Smavhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
2854286570Smav						int left, int right)
2855168404Spjd{
2856275811Sdelphij	struct hdac_softc *sc;
2857185029Spjd	nid_t nid, cad;
2858286570Smav	int lmute, rmute;
2859185029Spjd
2860185029Spjd	if (ctl == NULL || ctl->widget == NULL ||
2861185029Spjd	    ctl->widget->devinfo == NULL ||
2862185029Spjd	    ctl->widget->devinfo->codec == NULL ||
2863275811Sdelphij	    ctl->widget->devinfo->codec->sc == NULL)
2864286570Smav		return;
2865286570Smav
2866286570Smav	sc = ctl->widget->devinfo->codec->sc;
2867286570Smav	cad = ctl->widget->devinfo->codec->cad;
2868286570Smav	nid = ctl->widget->nid;
2869286570Smav
2870185029Spjd	if (mute == HDA_AMP_MUTE_DEFAULT) {
2871185029Spjd		lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
2872275811Sdelphij		rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
2873185029Spjd	} else {
2874275811Sdelphij		lmute = HDA_AMP_LEFT_MUTED(mute);
2875185029Spjd		rmute = HDA_AMP_RIGHT_MUTED(mute);
2876185029Spjd	}
2877275811Sdelphij
2878168404Spjd	if (ctl->dir & HDA_CTL_OUT)
2879168404Spjd		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2880219089Spjd		    lmute, rmute, left, right, 0);
2881219089Spjd	if (ctl->dir & HDA_CTL_IN)
2882219089Spjd		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2883219089Spjd		    lmute, rmute, left, right, 1);
2884219089Spjd	ctl->left = left;
2885219089Spjd	ctl->right = right;
2886275811Sdelphij}
2887219089Spjd
2888219089Spjdstatic void
2889219089Spjdhdac_widget_connection_select(struct hdac_widget *w, uint8_t index)
2890219089Spjd{
2891275811Sdelphij	if (w == NULL || w->nconns < 1 || index > (w->nconns - 1))
2892219089Spjd		return;
2893258632Savg	hdac_command(w->devinfo->codec->sc,
2894168404Spjd	    HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad,
2895258632Savg	    w->nid, index), w->devinfo->codec->cad);
2896258632Savg	w->selconn = index;
2897168404Spjd}
2898205231Skmacy
2899206796Spjd
2900258632Savg/****************************************************************************
2901206796Spjd * uint32_t hdac_command_sendone_internal
2902258632Savg *
2903205231Skmacy * Wrapper function that sends only one command to a given codec
2904206796Spjd ****************************************************************************/
2905205231Skmacystatic uint32_t
2906205231Skmacyhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad)
2907185029Spjd{
2908205231Skmacy	struct hdac_command_list cl;
2909205231Skmacy	uint32_t response = HDAC_INVALID;
2910258632Savg
2911205231Skmacy	if (!hdac_lockowned(sc))
2912185029Spjd		device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n");
2913185029Spjd	cl.num_commands = 1;
2914168404Spjd	cl.verbs = &verb;
2915168404Spjd	cl.responses = &response;
2916168404Spjd
2917168404Spjd	hdac_command_send_internal(sc, &cl, cad);
2918168404Spjd
2919168404Spjd	return (response);
2920168404Spjd}
2921168404Spjd
2922168404Spjd/****************************************************************************
2923168404Spjd * hdac_command_send_internal
2924168404Spjd *
2925168404Spjd * Send a command list to the codec via the corb. We queue as much verbs as
2926168404Spjd * we can and msleep on the codec. When the interrupt get the responses
2927208373Smm * back from the rirb, it will wake us up so we can queue the remaining verbs
2928168404Spjd * if any.
2929208373Smm ****************************************************************************/
2930208373Smmstatic void
2931208373Smmhdac_command_send_internal(struct hdac_softc *sc,
2932168404Spjd			struct hdac_command_list *commands, nid_t cad)
2933209275Smm{
2934209275Smm	struct hdac_codec *codec;
2935209275Smm	int corbrp;
2936208373Smm	uint32_t *corb;
2937208373Smm	int timeout;
2938208373Smm	int retry = 10;
2939209962Smm	struct hdac_rirb *rirb_base;
2940208373Smm
2941168404Spjd	if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL ||
2942168404Spjd	    commands->num_commands < 1)
2943208373Smm		return;
2944208373Smm
2945209962Smm	codec = sc->codecs[cad];
2946185029Spjd	codec->commands = commands;
2947185029Spjd	codec->responses_received = 0;
2948185029Spjd	codec->verbs_sent = 0;
2949208373Smm	corb = (uint32_t *)sc->corb_dma.dma_vaddr;
2950208373Smm	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2951208373Smm
2952168404Spjd	do {
2953208373Smm		if (codec->verbs_sent != commands->num_commands) {
2954208373Smm			/* Queue as many verbs as possible */
2955208373Smm			corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP);
2956208373Smm#if 0
2957209962Smm			bus_dmamap_sync(sc->corb_dma.dma_tag,
2958208373Smm			    sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
2959168404Spjd#endif
2960168404Spjd			while (codec->verbs_sent != commands->num_commands &&
2961208373Smm			    ((sc->corb_wp + 1) % sc->corb_size) != corbrp) {
2962208373Smm				sc->corb_wp++;
2963208373Smm				sc->corb_wp %= sc->corb_size;
2964209962Smm				corb[sc->corb_wp] =
2965208373Smm				    commands->verbs[codec->verbs_sent++];
2966208373Smm			}
2967168404Spjd
2968208373Smm			/* Send the verbs to the codecs */
2969208373Smm#if 0
2970208373Smm			bus_dmamap_sync(sc->corb_dma.dma_tag,
2971168404Spjd			    sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
2972208373Smm#endif
2973168404Spjd			HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
2974208373Smm		}
2975208373Smm
2976209962Smm		timeout = 1000;
2977208373Smm		while (hdac_rirb_flush(sc) == 0 && --timeout)
2978185029Spjd			DELAY(10);
2979208373Smm	} while ((codec->verbs_sent != commands->num_commands ||
2980208373Smm	    codec->responses_received != commands->num_commands) && --retry);
2981208373Smm
2982208373Smm	if (retry == 0)
2983208373Smm		device_printf(sc->dev,
2984209962Smm		    "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n",
2985168404Spjd		    __func__, commands->num_commands, codec->verbs_sent,
2986168404Spjd		    codec->responses_received);
2987168404Spjd
2988168404Spjd	codec->commands = NULL;
2989168404Spjd	codec->responses_received = 0;
2990168404Spjd	codec->verbs_sent = 0;
2991191903Skmacy
2992191903Skmacy	hdac_unsolq_flush(sc);
2993191903Skmacy}
2994191903Skmacy
2995191903Skmacy
2996206796Spjd/****************************************************************************
2997168404Spjd * Device Methods
2998191903Skmacy ****************************************************************************/
2999191903Skmacy
3000191903Skmacy/****************************************************************************
3001191903Skmacy * int hdac_probe(device_t)
3002191903Skmacy *
3003191903Skmacy * Probe for the presence of an hdac. If none is found, check for a generic
3004191903Skmacy * match using the subclass of the device.
3005219089Spjd ****************************************************************************/
3006168404Spjdstatic int
3007219089Spjdhdac_probe(device_t dev)
3008168404Spjd{
3009168404Spjd	int i, result;
3010268858Sdelphij	uint32_t model;
3011168404Spjd	uint16_t class, subclass;
3012168404Spjd	char desc[64];
3013168404Spjd
3014168404Spjd	model = (uint32_t)pci_get_device(dev) << 16;
3015168404Spjd	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
3016191903Skmacy	class = pci_get_class(dev);
3017191903Skmacy	subclass = pci_get_subclass(dev);
3018191903Skmacy
3019168404Spjd	bzero(desc, sizeof(desc));
3020168404Spjd	result = ENXIO;
3021168404Spjd	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
3022185029Spjd		if (hdac_devices[i].model == model) {
3023168404Spjd		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3024168404Spjd		    	result = BUS_PROBE_DEFAULT;
3025168404Spjd			break;
3026185029Spjd		}
3027168404Spjd		if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
3028209962Smm		    class == PCIC_MULTIMEDIA &&
3029209962Smm		    subclass == PCIS_MULTIMEDIA_HDA) {
3030286570Smav		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
3031228103Smm		    	result = BUS_PROBE_GENERIC;
3032209962Smm			break;
3033205231Skmacy		}
3034209962Smm	}
3035286570Smav	if (result == ENXIO && class == PCIC_MULTIMEDIA &&
3036185029Spjd	    subclass == PCIS_MULTIMEDIA_HDA) {
3037185029Spjd		strlcpy(desc, "Generic", sizeof(desc));
3038205231Skmacy	    	result = BUS_PROBE_GENERIC;
3039209962Smm	}
3040286570Smav	if (result != ENXIO) {
3041185029Spjd		strlcat(desc, " High Definition Audio Controller",
3042185029Spjd		    sizeof(desc));
3043205231Skmacy		device_set_desc_copy(dev, desc);
3044209962Smm	}
3045286570Smav
3046185029Spjd	return (result);
3047185029Spjd}
3048205231Skmacy
3049209962Smmstatic void *
3050286570Smavhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
3051185029Spjd					struct pcm_channel *c, int dir)
3052185029Spjd{
3053168404Spjd	struct hdac_devinfo *devinfo = data;
3054209962Smm	struct hdac_softc *sc = devinfo->codec->sc;
3055209962Smm	struct hdac_chan *ch;
3056168404Spjd
3057168404Spjd	hdac_lock(sc);
3058168404Spjd	if (dir == PCMDIR_PLAY) {
3059168404Spjd		ch = &sc->play;
3060185029Spjd		ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5;
3061168404Spjd		devinfo->function.audio.playcnt++;
3062168404Spjd	} else {
3063168404Spjd		ch = &sc->rec;
3064286625Smav		ch->off = devinfo->function.audio.reccnt << 5;
3065168404Spjd		devinfo->function.audio.reccnt++;
3066270759Ssmh	}
3067168404Spjd	if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
3068272483Ssmh		ch->caps.minspeed = ch->caps.maxspeed = 48000;
3069272483Ssmh		ch->pcmrates[0] = 48000;
3070168404Spjd		ch->pcmrates[1] = 0;
3071168404Spjd	}
3072168404Spjd	if (sc->pos_dma.dma_vaddr != NULL)
3073168404Spjd		ch->dmapos = (uint32_t *)(sc->pos_dma.dma_vaddr +
3074168404Spjd		    (sc->streamcnt * 8));
3075168404Spjd	else
3076168404Spjd		ch->dmapos = NULL;
3077168404Spjd	ch->sid = ++sc->streamcnt;
3078168404Spjd	ch->dir = dir;
3079168404Spjd	ch->b = b;
3080272483Ssmh	ch->c = c;
3081272483Ssmh	ch->devinfo = devinfo;
3082272483Ssmh	ch->blksz = sc->chan_size / sc->chan_blkcnt;
3083272483Ssmh	ch->blkcnt = sc->chan_blkcnt;
3084168404Spjd	hdac_unlock(sc);
3085168404Spjd
3086168404Spjd	if (hdac_bdl_alloc(ch) != 0) {
3087168404Spjd		ch->blkcnt = 0;
3088270759Ssmh		return (NULL);
3089270759Ssmh	}
3090270759Ssmh
3091168404Spjd	if (sndbuf_alloc(ch->b, sc->chan_dmat,
3092270759Ssmh	    (sc->flags & HDAC_F_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0,
3093168404Spjd	    sc->chan_size) != 0)
3094168404Spjd		return (NULL);
3095286625Smav
3096168404Spjd	return (ch);
3097286625Smav}
3098286625Smav
3099286625Smavstatic int
3100286625Smavhdac_channel_setformat(kobj_t obj, void *data, uint32_t format)
3101286625Smav{
3102286625Smav	struct hdac_chan *ch = data;
3103286625Smav	int i;
3104286625Smav
3105286625Smav	for (i = 0; ch->caps.fmtlist[i] != 0; i++) {
3106286625Smav		if (format == ch->caps.fmtlist[i]) {
3107286625Smav			ch->fmt = format;
3108286625Smav			return (0);
3109286625Smav		}
3110286625Smav	}
3111286625Smav
3112286625Smav	return (EINVAL);
3113286625Smav}
3114286625Smav
3115286625Smavstatic int
3116286625Smavhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed)
3117286625Smav{
3118286625Smav	struct hdac_chan *ch = data;
3119286625Smav	uint32_t spd = 0, threshold;
3120286625Smav	int i;
3121286625Smav
3122286625Smav	for (i = 0; ch->pcmrates[i] != 0; i++) {
3123286625Smav		spd = ch->pcmrates[i];
3124286625Smav		threshold = spd + ((ch->pcmrates[i + 1] != 0) ?
3125286625Smav		    ((ch->pcmrates[i + 1] - spd) >> 1) : 0);
3126286625Smav		if (speed < threshold)
3127286625Smav			break;
3128168404Spjd	}
3129286625Smav
3130286625Smav	if (spd == 0)	/* impossible */
3131286625Smav		ch->spd = 48000;
3132168404Spjd	else
3133168404Spjd		ch->spd = spd;
3134286625Smav
3135286625Smav	return (ch->spd);
3136286625Smav}
3137286625Smav
3138286625Smavstatic void
3139286625Smavhdac_stream_setup(struct hdac_chan *ch)
3140270759Ssmh{
3141168404Spjd	struct hdac_softc *sc = ch->devinfo->codec->sc;
3142191902Skmacy	struct hdac_widget *w;
3143212780Savg	int i, chn, totalchn;
3144212780Savg	nid_t cad = ch->devinfo->codec->cad;
3145191902Skmacy	uint16_t fmt;
3146286625Smav
3147286625Smav	fmt = 0;
3148286625Smav	if (ch->fmt & AFMT_S16_LE)
3149286625Smav		fmt |= ch->bit16 << 4;
3150270759Ssmh	else if (ch->fmt & AFMT_S32_LE)
3151191902Skmacy		fmt |= ch->bit32 << 4;
3152277300Ssmh	else
3153168404Spjd		fmt |= 1 << 4;
3154185029Spjd
3155185029Spjd	for (i = 0; i < HDA_RATE_TAB_LEN; i++) {
3156185029Spjd		if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) {
3157185029Spjd			fmt |= hda_rate_tab[i].base;
3158185029Spjd			fmt |= hda_rate_tab[i].mul;
3159185029Spjd			fmt |= hda_rate_tab[i].div;
3160286625Smav			break;
3161286625Smav		}
3162286625Smav	}
3163286625Smav
3164286625Smav	if (ch->fmt & AFMT_STEREO) {
3165185029Spjd		fmt |= 1;
3166185029Spjd		totalchn = 2;
3167168404Spjd	} else
3168185029Spjd		totalchn = 1;
3169168404Spjd
3170168404Spjd	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
3171168404Spjd
3172168404Spjd	chn = 0;
3173286625Smav	for (i = 0; ch->io[i] != -1; i++) {
3174286625Smav		w = hdac_widget_get(ch->devinfo, ch->io[i]);
3175286625Smav		if (w == NULL)
3176286625Smav			continue;
3177286625Smav		HDA_BOOTVERBOSE(
3178286625Smav			device_printf(sc->dev,
3179168404Spjd			    "HDA_DEBUG: PCMDIR_%s: Stream setup nid=%d "
3180286625Smav			    "fmt=0x%08x\n",
3181168404Spjd			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
3182272483Ssmh			    ch->io[i], fmt);
3183272483Ssmh		);
3184272483Ssmh		hdac_command(sc,
3185272483Ssmh		    HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
3186272483Ssmh		if (ch->dir == PCMDIR_REC)
3187272483Ssmh			hdac_command(sc,
3188286625Smav			    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
3189286625Smav			    (chn < totalchn) ? ((ch->sid << 4) | chn) : 0),
3190286625Smav			    cad);
3191286625Smav		else
3192286625Smav			hdac_command(sc,
3193286625Smav			    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
3194272483Ssmh			    ch->sid << 4), cad);
3195277300Ssmh		chn +=
3196272483Ssmh		    HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(w->param.widget_cap) ?
3197272483Ssmh		    2 : 1;
3198168404Spjd	}
3199168404Spjd}
3200168404Spjd
3201168404Spjdstatic int
3202168404Spjdhdac_channel_setfragments(kobj_t obj, void *data,
3203168404Spjd					uint32_t blksz, uint32_t blkcnt)
3204168404Spjd{
3205185029Spjd	struct hdac_chan *ch = data;
3206168404Spjd	struct hdac_softc *sc = ch->devinfo->codec->sc;
3207168404Spjd
3208286625Smav	blksz &= HDA_BLK_ALIGN;
3209286628Smav
3210286625Smav	if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN))
3211286625Smav		blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN;
3212286625Smav	if (blksz < HDA_BLK_MIN)
3213270861Ssmh		blksz = HDA_BLK_MIN;
3214281026Smav	if (blkcnt > HDA_BDL_MAX)
3215281026Smav		blkcnt = HDA_BDL_MAX;
3216281026Smav	if (blkcnt < HDA_BDL_MIN)
3217270861Ssmh		blkcnt = HDA_BDL_MIN;
3218281026Smav
3219272483Ssmh	while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) {
3220272483Ssmh		if ((blkcnt >> 1) >= HDA_BDL_MIN)
3221272483Ssmh			blkcnt >>= 1;
3222272483Ssmh		else if ((blksz >> 1) >= HDA_BLK_MIN)
3223272483Ssmh			blksz >>= 1;
3224272483Ssmh		else
3225272483Ssmh			break;
3226272483Ssmh	}
3227272483Ssmh
3228286625Smav	if ((sndbuf_getblksz(ch->b) != blksz ||
3229286625Smav	    sndbuf_getblkcnt(ch->b) != blkcnt) &&
3230286625Smav	    sndbuf_resize(ch->b, blkcnt, blksz) != 0)
3231286625Smav		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
3232286625Smav		    __func__, blksz, blkcnt);
3233286625Smav
3234286625Smav	ch->blksz = sndbuf_getblksz(ch->b);
3235286625Smav	ch->blkcnt = sndbuf_getblkcnt(ch->b);
3236281026Smav
3237281026Smav	return (1);
3238281026Smav}
3239281026Smav
3240281026Smavstatic int
3241286625Smavhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
3242286625Smav{
3243286625Smav	struct hdac_chan *ch = data;
3244286625Smav	struct hdac_softc *sc = ch->devinfo->codec->sc;
3245286625Smav
3246286625Smav	hdac_channel_setfragments(obj, data, blksz, sc->chan_blkcnt);
3247286625Smav
3248281109Smav	return (ch->blksz);
3249281026Smav}
3250272483Ssmh
3251286625Smavstatic void
3252168404Spjdhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
3253286625Smav{
3254272483Ssmh	struct hdac_devinfo *devinfo = ch->devinfo;
3255270759Ssmh	nid_t cad = devinfo->codec->cad;
3256286625Smav	int i;
3257286625Smav
3258286625Smav	hdac_stream_stop(ch);
3259286625Smav
3260168404Spjd	for (i = 0; ch->io[i] != -1; i++) {
3261168404Spjd		hdac_command(sc,
3262286625Smav		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
3263286625Smav		    0), cad);
3264286625Smav	}
3265286625Smav}
3266286625Smav
3267286625Smavstatic void
3268286625Smavhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch)
3269286625Smav{
3270286625Smav	ch->ptr = 0;
3271286625Smav	ch->prevptr = 0;
3272286625Smav	hdac_stream_stop(ch);
3273286625Smav	hdac_stream_reset(ch);
3274208454Spjd	hdac_bdl_setup(ch);
3275208454Spjd	hdac_stream_setid(ch);
3276272527Sdelphij	hdac_stream_setup(ch);
3277208454Spjd	hdac_stream_start(ch);
3278278040Ssmh}
3279286625Smav
3280168404Spjdstatic int
3281168404Spjdhdac_channel_trigger(kobj_t obj, void *data, int go)
3282168404Spjd{
3283168404Spjd	struct hdac_chan *ch = data;
3284168404Spjd	struct hdac_softc *sc = ch->devinfo->codec->sc;
3285272483Ssmh
3286168404Spjd	if (!PCMTRIG_COMMON(go))
3287185029Spjd		return (0);
3288185029Spjd
3289185029Spjd	hdac_lock(sc);
3290185029Spjd	switch (go) {
3291185029Spjd	case PCMTRIG_START:
3292185029Spjd		hdac_channel_start(sc, ch);
3293185029Spjd		break;
3294168404Spjd	case PCMTRIG_STOP:
3295168404Spjd	case PCMTRIG_ABORT:
3296168404Spjd		hdac_channel_stop(sc, ch);
3297168404Spjd		break;
3298168404Spjd	default:
3299168404Spjd		break;
3300168404Spjd	}
3301168404Spjd	hdac_unlock(sc);
3302168404Spjd
3303168404Spjd	return (0);
3304168404Spjd}
3305168404Spjd
3306168404Spjdstatic int
3307168404Spjdhdac_channel_getptr(kobj_t obj, void *data)
3308168404Spjd{
3309168404Spjd	struct hdac_chan *ch = data;
3310168404Spjd	struct hdac_softc *sc = ch->devinfo->codec->sc;
3311168404Spjd	uint32_t ptr;
3312168404Spjd
3313286570Smav	hdac_lock(sc);
3314286570Smav	if (sc->polling != 0)
3315272506Sdelphij		ptr = ch->ptr;
3316272483Ssmh	else if (ch->dmapos != NULL)
3317277300Ssmh		ptr = *(ch->dmapos);
3318286625Smav	else
3319286625Smav		ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB);
3320286625Smav	hdac_unlock(sc);
3321286625Smav
3322286625Smav	/*
3323272483Ssmh	 * Round to available space and force 128 bytes aligment.
3324286625Smav	 */
3325272483Ssmh	ptr %= ch->blksz * ch->blkcnt;
3326272483Ssmh	ptr &= HDA_BLK_ALIGN;
3327168404Spjd
3328168404Spjd	return (ptr);
3329168404Spjd}
3330168404Spjd
3331168404Spjdstatic struct pcmchan_caps *
3332168404Spjdhdac_channel_getcaps(kobj_t obj, void *data)
3333168404Spjd{
3334168404Spjd	return (&((struct hdac_chan *)data)->caps);
3335168404Spjd}
3336168404Spjd
3337168404Spjdstatic kobj_method_t hdac_channel_methods[] = {
3338168404Spjd	KOBJMETHOD(channel_init,		hdac_channel_init),
3339286625Smav	KOBJMETHOD(channel_setformat,		hdac_channel_setformat),
3340286625Smav	KOBJMETHOD(channel_setspeed,		hdac_channel_setspeed),
3341168404Spjd	KOBJMETHOD(channel_setblocksize,	hdac_channel_setblocksize),
3342286625Smav	KOBJMETHOD(channel_setfragments,	hdac_channel_setfragments),
3343286625Smav	KOBJMETHOD(channel_trigger,		hdac_channel_trigger),
3344168404Spjd	KOBJMETHOD(channel_getptr,		hdac_channel_getptr),
3345286625Smav	KOBJMETHOD(channel_getcaps,		hdac_channel_getcaps),
3346286625Smav	{ 0, 0 }
3347286625Smav};
3348286625SmavCHANNEL_DECLARE(hdac_channel);
3349219089Spjd
3350168404Spjdstatic void
3351286625Smavhdac_jack_poll_callback(void *arg)
3352286625Smav{
3353286625Smav	struct hdac_devinfo *devinfo = arg;
3354286625Smav	struct hdac_softc *sc;
3355286625Smav
3356286625Smav	if (devinfo == NULL || devinfo->codec == NULL ||
3357286625Smav	    devinfo->codec->sc == NULL)
3358286625Smav		return;
3359286625Smav	sc = devinfo->codec->sc;
3360286625Smav	hdac_lock(sc);
3361286625Smav	if (sc->poll_ival == 0) {
3362286625Smav		hdac_unlock(sc);
3363286625Smav		return;
3364286625Smav	}
3365286625Smav	hdac_hp_switch_handler(devinfo);
3366168404Spjd	callout_reset(&sc->poll_jack, sc->poll_ival,
3367286625Smav	    hdac_jack_poll_callback, devinfo);
3368286625Smav	hdac_unlock(sc);
3369286625Smav}
3370286625Smav
3371168404Spjdstatic int
3372168404Spjdhdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
3373209275Smm{
3374168404Spjd	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
3375168404Spjd	struct hdac_softc *sc = devinfo->codec->sc;
3376168404Spjd	struct hdac_widget *w, *cw;
3377168404Spjd	struct hdac_audio_ctl *ctl;
3378211762Savg	uint32_t mask, recmask, id;
3379211762Savg	int i, j, softpcmvol;
3380185029Spjd	nid_t cad;
3381185029Spjd
3382211762Savg	hdac_lock(sc);
3383168404Spjd
3384168404Spjd	mask = 0;
3385286574Smav	recmask = 0;
3386286574Smav
3387286574Smav	id = hdac_codec_id(devinfo);
3388286574Smav	cad = devinfo->codec->cad;
3389286574Smav	for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
3390286574Smav		if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model,
3391286574Smav		    sc->pci_subvendor) && hdac_hp_switch[i].id == id))
3392286574Smav			continue;
3393286574Smav		w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
3394286574Smav		if (w == NULL || w->enable == 0 || w->type !=
3395286574Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
3396286574Smav			continue;
3397286574Smav		if (hdac_hp_switch[i].polling != 0)
3398286574Smav			callout_reset(&sc->poll_jack, 1,
3399168404Spjd			    hdac_jack_poll_callback, devinfo);
3400168404Spjd		else if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap))
3401168404Spjd			hdac_command(sc,
3402168404Spjd			    HDA_CMD_SET_UNSOLICITED_RESPONSE(cad, w->nid,
3403168404Spjd			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE |
3404168404Spjd			    HDAC_UNSOLTAG_EVENT_HP), cad);
3405168404Spjd		else
3406168404Spjd			continue;
3407168404Spjd		hdac_hp_switch_handler(devinfo);
3408168404Spjd		HDA_BOOTVERBOSE(
3409168404Spjd			device_printf(sc->dev,
3410168404Spjd			    "HDA_DEBUG: Enabling headphone/speaker "
3411168404Spjd			    "audio routing switching:\n");
3412168404Spjd			device_printf(sc->dev,
3413168404Spjd			    "HDA_DEBUG: \tindex=%d nid=%d "
3414168404Spjd			    "pci_subvendor=0x%08x "
3415168404Spjd			    "codec=0x%08x [%s]\n",
3416168404Spjd			    i, w->nid, sc->pci_subvendor, id,
3417168404Spjd			    (hdac_hp_switch[i].polling != 0) ? "POLL" :
3418168404Spjd			    "UNSOL");
3419168404Spjd		);
3420168404Spjd		break;
3421208373Smm	}
3422168404Spjd	for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
3423185029Spjd		if (!(HDA_DEV_MATCH(hdac_eapd_switch[i].model,
3424185029Spjd		    sc->pci_subvendor) &&
3425185029Spjd		    hdac_eapd_switch[i].id == id))
3426168404Spjd			continue;
3427168404Spjd		w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
3428168404Spjd		if (w == NULL || w->enable == 0)
3429168404Spjd			break;
3430168404Spjd		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3431168404Spjd		    w->param.eapdbtl == HDAC_INVALID)
3432168404Spjd			break;
3433168404Spjd		mask |= SOUND_MASK_OGAIN;
3434168404Spjd		break;
3435168404Spjd	}
3436168404Spjd
3437168404Spjd	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3438209275Smm		w = hdac_widget_get(devinfo, i);
3439168404Spjd		if (w == NULL || w->enable == 0)
3440208373Smm			continue;
3441168404Spjd		mask |= w->ctlflags;
3442208373Smm		if (!(w->pflags & HDA_ADC_RECSEL))
3443208373Smm			continue;
3444168404Spjd		for (j = 0; j < w->nconns; j++) {
3445168404Spjd			cw = hdac_widget_get(devinfo, w->conns[j]);
3446209275Smm			if (cw == NULL || cw->enable == 0)
3447168404Spjd				continue;
3448208373Smm			recmask |= cw->ctlflags;
3449208373Smm		}
3450168404Spjd	}
3451168404Spjd
3452168404Spjd	if (!(mask & SOUND_MASK_PCM)) {
3453168404Spjd		softpcmvol = 1;
3454168404Spjd		mask |= SOUND_MASK_PCM;
3455168404Spjd	} else
3456168404Spjd		softpcmvol = (devinfo->function.audio.quirks &
3457168404Spjd		    HDA_QUIRK_SOFTPCMVOL) ? 1 : 0;
3458168404Spjd
3459168404Spjd	i = 0;
3460168404Spjd	ctl = NULL;
3461168404Spjd	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3462168404Spjd		if (ctl->widget == NULL || ctl->enable == 0)
3463168404Spjd			continue;
3464168404Spjd		if (!(ctl->ossmask & SOUND_MASK_PCM))
3465168404Spjd			continue;
3466168404Spjd		if (ctl->step > 0)
3467168404Spjd			break;
3468168404Spjd	}
3469272483Ssmh
3470168404Spjd	if (softpcmvol == 1 || ctl == NULL) {
3471168404Spjd		pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
3472168404Spjd		HDA_BOOTVERBOSE(
3473168404Spjd			device_printf(sc->dev,
3474168404Spjd			    "HDA_DEBUG: %s Soft PCM volume\n",
3475168404Spjd			    (softpcmvol == 1) ?
3476168404Spjd			    "Forcing" : "Enabling");
3477168404Spjd		);
3478168404Spjd		i = 0;
3479168404Spjd		/*
3480168404Spjd		 * XXX Temporary quirk for STAC9220, until the parser
3481168404Spjd		 *     become smarter.
3482168404Spjd		 */
3483168404Spjd		if (id == HDA_CODEC_STAC9220) {
3484168404Spjd			mask |= SOUND_MASK_VOLUME;
3485168404Spjd			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
3486185029Spjd			    NULL) {
3487168404Spjd				if (ctl->widget == NULL || ctl->enable == 0)
3488185029Spjd					continue;
3489185029Spjd				if (ctl->widget->nid == 11 && ctl->index == 0) {
3490185029Spjd					ctl->ossmask = SOUND_MASK_VOLUME;
3491168404Spjd					ctl->ossval = 100 | (100 << 8);
3492168404Spjd				} else
3493168404Spjd					ctl->ossmask &= ~SOUND_MASK_VOLUME;
3494168404Spjd			}
3495168404Spjd		} else if (id == HDA_CODEC_STAC9221) {
3496168404Spjd			mask |= SOUND_MASK_VOLUME;
3497168404Spjd			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
3498168404Spjd			    NULL) {
3499168404Spjd				if (ctl->widget == NULL)
3500168404Spjd					continue;
3501168404Spjd				if (ctl->widget->type ==
3502168404Spjd				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT &&
3503168404Spjd				    ctl->index == 0 && (ctl->widget->nid == 2 ||
3504168404Spjd				    ctl->widget->enable != 0)) {
3505168404Spjd					ctl->enable = 1;
3506168404Spjd					ctl->ossmask = SOUND_MASK_VOLUME;
3507168404Spjd					ctl->ossval = 100 | (100 << 8);
3508168404Spjd				} else if (ctl->enable == 0)
3509168404Spjd					continue;
3510168404Spjd				else
3511168404Spjd					ctl->ossmask &= ~SOUND_MASK_VOLUME;
3512168404Spjd			}
3513168404Spjd		} else {
3514168404Spjd			mix_setparentchild(m, SOUND_MIXER_VOLUME,
3515168404Spjd			    SOUND_MASK_PCM);
3516168404Spjd			if (!(mask & SOUND_MASK_VOLUME))
3517168404Spjd				mix_setrealdev(m, SOUND_MIXER_VOLUME,
3518168404Spjd				    SOUND_MIXER_NONE);
3519168404Spjd			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
3520168404Spjd			    NULL) {
3521168404Spjd				if (ctl->widget == NULL || ctl->enable == 0)
3522168404Spjd					continue;
3523286570Smav				if (!HDA_FLAG_MATCH(ctl->ossmask,
3524168404Spjd				    SOUND_MASK_VOLUME | SOUND_MASK_PCM))
3525286570Smav					continue;
3526168404Spjd				if (!(ctl->mute == 1 && ctl->step == 0))
3527168404Spjd					ctl->enable = 0;
3528168404Spjd			}
3529168404Spjd		}
3530168404Spjd	}
3531168404Spjd
3532168404Spjd	recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
3533185029Spjd	    SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_IGAIN |
3534168404Spjd	    SOUND_MASK_OGAIN);
3535168404Spjd	recmask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3536286574Smav	mask &= (1 << SOUND_MIXER_NRDEVICES) - 1;
3537168404Spjd
3538168404Spjd	mix_setrecdevs(m, recmask);
3539168404Spjd	mix_setdevs(m, mask);
3540286574Smav
3541168404Spjd	hdac_unlock(sc);
3542168404Spjd
3543168404Spjd	return (0);
3544168404Spjd}
3545168404Spjd
3546168404Spjdstatic int
3547168404Spjdhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
3548168404Spjd					unsigned left, unsigned right)
3549168404Spjd{
3550286570Smav	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
3551168404Spjd	struct hdac_softc *sc = devinfo->codec->sc;
3552168404Spjd	struct hdac_widget *w;
3553168404Spjd	struct hdac_audio_ctl *ctl;
3554168404Spjd	uint32_t id, mute;
3555168404Spjd	int lvol, rvol, mlvol, mrvol;
3556208373Smm	int i = 0;
3557185029Spjd
3558168404Spjd	hdac_lock(sc);
3559168404Spjd	if (dev == SOUND_MIXER_OGAIN) {
3560168404Spjd		uint32_t orig;
3561208373Smm		/*if (left != right || !(left == 0 || left == 1)) {
3562185029Spjd			hdac_unlock(sc);
3563168404Spjd			return (-1);
3564209962Smm		}*/
3565168404Spjd		id = hdac_codec_id(devinfo);
3566168404Spjd		for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
3567286574Smav			if (HDA_DEV_MATCH(hdac_eapd_switch[i].model,
3568168404Spjd			    sc->pci_subvendor) &&
3569168404Spjd			    hdac_eapd_switch[i].id == id)
3570168404Spjd				break;
3571286574Smav		}
3572168404Spjd		if (i >= HDAC_EAPD_SWITCH_LEN) {
3573168404Spjd			hdac_unlock(sc);
3574168404Spjd			return (-1);
3575168404Spjd		}
3576168404Spjd		w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
3577168404Spjd		if (w == NULL ||
3578168404Spjd		    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3579168404Spjd		    w->param.eapdbtl == HDAC_INVALID) {
3580168404Spjd			hdac_unlock(sc);
3581286570Smav			return (-1);
3582168404Spjd		}
3583168404Spjd		orig = w->param.eapdbtl;
3584286570Smav		if (left == 0)
3585286570Smav			w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3586286570Smav		else
3587286570Smav			w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3588286570Smav		if (orig != w->param.eapdbtl) {
3589168404Spjd			uint32_t val;
3590168404Spjd
3591168404Spjd			if (hdac_eapd_switch[i].hp_switch != 0)
3592168404Spjd				hdac_hp_switch_handler(devinfo);
3593168404Spjd			val = w->param.eapdbtl;
3594286570Smav			if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV)
3595168404Spjd				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3596168404Spjd			hdac_command(sc,
3597168404Spjd			    HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad,
3598205231Skmacy			    w->nid, val), devinfo->codec->cad);
3599168404Spjd		}
3600168404Spjd		hdac_unlock(sc);
3601168404Spjd		return (left | (left << 8));
3602168404Spjd	}
3603168404Spjd	if (dev == SOUND_MIXER_VOLUME)
3604168404Spjd		devinfo->function.audio.mvol = left | (right << 8);
3605168404Spjd
3606275811Sdelphij	mlvol = devinfo->function.audio.mvol & 0x7f;
3607168404Spjd	mrvol = (devinfo->function.audio.mvol >> 8) & 0x7f;
3608219089Spjd	lvol = 0;
3609219089Spjd	rvol = 0;
3610168404Spjd
3611286570Smav	i = 0;
3612168404Spjd	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3613286570Smav		if (ctl->widget == NULL || ctl->enable == 0 ||
3614168404Spjd		    !(ctl->ossmask & (1 << dev)))
3615168404Spjd			continue;
3616168404Spjd		switch (dev) {
3617168404Spjd		case SOUND_MIXER_VOLUME:
3618168404Spjd			lvol = ((ctl->ossval & 0x7f) * left) / 100;
3619168404Spjd			lvol = (lvol * ctl->step) / 100;
3620286570Smav			rvol = (((ctl->ossval >> 8) & 0x7f) * right) / 100;
3621286570Smav			rvol = (rvol * ctl->step) / 100;
3622275811Sdelphij			break;
3623275811Sdelphij		default:
3624168404Spjd			if (ctl->ossmask & SOUND_MASK_VOLUME) {
3625286570Smav				lvol = (left * mlvol) / 100;
3626219089Spjd				lvol = (lvol * ctl->step) / 100;
3627219089Spjd				rvol = (right * mrvol) / 100;
3628168404Spjd				rvol = (rvol * ctl->step) / 100;
3629168404Spjd			} else {
3630168404Spjd				lvol = (left * ctl->step) / 100;
3631168404Spjd				rvol = (right * ctl->step) / 100;
3632168404Spjd			}
3633168404Spjd			ctl->ossval = left | (right << 8);
3634168404Spjd			break;
3635168404Spjd		}
3636286570Smav		mute = 0;
3637286570Smav		if (ctl->step < 1) {
3638286570Smav			mute |= (left == 0) ? HDA_AMP_MUTE_LEFT :
3639286570Smav			    (ctl->muted & HDA_AMP_MUTE_LEFT);
3640168404Spjd			mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT :
3641275811Sdelphij			    (ctl->muted & HDA_AMP_MUTE_RIGHT);
3642168404Spjd		} else {
3643168404Spjd			mute |= (lvol == 0) ? HDA_AMP_MUTE_LEFT :
3644286570Smav			    (ctl->muted & HDA_AMP_MUTE_LEFT);
3645168404Spjd			mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT :
3646168404Spjd			    (ctl->muted & HDA_AMP_MUTE_RIGHT);
3647168404Spjd		}
3648168404Spjd		hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
3649168404Spjd	}
3650168404Spjd	hdac_unlock(sc);
3651168404Spjd
3652168404Spjd	return (left | (right << 8));
3653286570Smav}
3654168404Spjd
3655168404Spjdstatic int
3656168404Spjdhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
3657168404Spjd{
3658168404Spjd	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
3659286570Smav	struct hdac_widget *w, *cw;
3660275811Sdelphij	struct hdac_softc *sc = devinfo->codec->sc;
3661275811Sdelphij	uint32_t ret = src, target;
3662168404Spjd	int i, j;
3663168404Spjd
3664286570Smav	target = 0;
3665168404Spjd	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
3666168404Spjd		if (src & (1 << i)) {
3667168404Spjd			target = 1 << i;
3668168404Spjd			break;
3669168404Spjd		}
3670168404Spjd	}
3671168404Spjd
3672286570Smav	hdac_lock(sc);
3673168404Spjd
3674286570Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3675275811Sdelphij		w = hdac_widget_get(devinfo, i);
3676275811Sdelphij		if (w == NULL || w->enable == 0)
3677168404Spjd			continue;
3678168404Spjd		if (!(w->pflags & HDA_ADC_RECSEL))
3679275811Sdelphij			continue;
3680168404Spjd		for (j = 0; j < w->nconns; j++) {
3681168404Spjd			cw = hdac_widget_get(devinfo, w->conns[j]);
3682286570Smav			if (cw == NULL || cw->enable == 0)
3683275811Sdelphij				continue;
3684168404Spjd			if ((target == SOUND_MASK_VOLUME &&
3685168404Spjd			    cw->type !=
3686286570Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
3687168404Spjd			    (target != SOUND_MASK_VOLUME &&
3688168404Spjd			    cw->type ==
3689168404Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER))
3690168404Spjd				continue;
3691168404Spjd			if (cw->ctlflags & target) {
3692168404Spjd				if (!(w->pflags & HDA_ADC_LOCKED))
3693168404Spjd					hdac_widget_connection_select(w, j);
3694168404Spjd				ret = target;
3695168404Spjd				j += w->nconns;
3696286570Smav			}
3697286570Smav		}
3698286570Smav	}
3699168404Spjd
3700168404Spjd	hdac_unlock(sc);
3701286570Smav
3702286570Smav	return (ret);
3703168404Spjd}
3704168404Spjd
3705168404Spjdstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
3706168404Spjd	KOBJMETHOD(mixer_init,		hdac_audio_ctl_ossmixer_init),
3707168404Spjd	KOBJMETHOD(mixer_set,		hdac_audio_ctl_ossmixer_set),
3708168404Spjd	KOBJMETHOD(mixer_setrecsrc,	hdac_audio_ctl_ossmixer_setrecsrc),
3709168404Spjd	{ 0, 0 }
3710286570Smav};
3711168404SpjdMIXER_DECLARE(hdac_audio_ctl_ossmixer);
3712168404Spjd
3713168404Spjdstatic void
3714168404Spjdhdac_unsolq_task(void *context, int pending)
3715286570Smav{
3716168404Spjd	struct hdac_softc *sc;
3717168404Spjd
3718168404Spjd	sc = (struct hdac_softc *)context;
3719286570Smav
3720275811Sdelphij	hdac_lock(sc);
3721275811Sdelphij	hdac_unsolq_flush(sc);
3722168404Spjd	hdac_unlock(sc);
3723168404Spjd}
3724286570Smav
3725185029Spjd/****************************************************************************
3726185029Spjd * int hdac_attach(device_t)
3727185029Spjd *
3728185029Spjd * Attach the device into the kernel. Interrupts usually won't be enabled
3729286570Smav * when this function is called. Setup everything that doesn't require
3730275811Sdelphij * interrupts and defer probing of codecs until interrupts are enabled.
3731275811Sdelphij ****************************************************************************/
3732168404Spjdstatic int
3733168404Spjdhdac_attach(device_t dev)
3734168404Spjd{
3735168404Spjd	struct hdac_softc *sc;
3736168404Spjd	int result;
3737168404Spjd	int i;
3738168404Spjd	uint16_t vendor;
3739168404Spjd	uint8_t v;
3740168404Spjd
3741168404Spjd	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
3742219089Spjd	sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
3743219089Spjd	sc->dev = dev;
3744248571Smm	sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
3745168404Spjd	sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff;
3746168404Spjd	vendor = pci_get_vendor(dev);
3747185029Spjd
3748168404Spjd	if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) {
3749168404Spjd		/* Screw nx6325 - subdevice/subvendor swapped */
3750168404Spjd		sc->pci_subvendor = HP_NX6325_SUBVENDOR;
3751168404Spjd	}
3752168404Spjd
3753248571Smm	callout_init(&sc->poll_hda, CALLOUT_MPSAFE);
3754168404Spjd	callout_init(&sc->poll_hdac, CALLOUT_MPSAFE);
3755168404Spjd	callout_init(&sc->poll_jack, CALLOUT_MPSAFE);
3756168404Spjd
3757219089Spjd	TASK_INIT(&sc->unsolq_task, 0, hdac_unsolq_task, sc);
3758168404Spjd
3759168404Spjd	sc->poll_ticks = 1;
3760168404Spjd	sc->poll_ival = HDAC_POLL_INTERVAL;
3761168404Spjd	if (resource_int_value(device_get_name(dev),
3762168404Spjd	    device_get_unit(dev), "polling", &i) == 0 && i != 0)
3763168404Spjd		sc->polling = 1;
3764268075Sdelphij	else
3765168404Spjd		sc->polling = 0;
3766168404Spjd
3767268075Sdelphij	sc->chan_size = pcm_getbuffersize(dev,
3768168404Spjd	    HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
3769168404Spjd
3770168404Spjd	if (resource_int_value(device_get_name(dev),
3771168404Spjd	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
3772168404Spjd		i &= HDA_BLK_ALIGN;
3773168404Spjd		if (i < HDA_BLK_MIN)
3774168404Spjd			i = HDA_BLK_MIN;
3775168404Spjd		sc->chan_blkcnt = sc->chan_size / i;
3776168404Spjd		i = 0;
3777168404Spjd		while (sc->chan_blkcnt >> i)
3778168404Spjd			i++;
3779168404Spjd		sc->chan_blkcnt = 1 << (i - 1);
3780168404Spjd		if (sc->chan_blkcnt < HDA_BDL_MIN)
3781168404Spjd			sc->chan_blkcnt = HDA_BDL_MIN;
3782268075Sdelphij		else if (sc->chan_blkcnt > HDA_BDL_MAX)
3783268075Sdelphij			sc->chan_blkcnt = HDA_BDL_MAX;
3784268075Sdelphij	} else
3785268075Sdelphij		sc->chan_blkcnt = HDA_BDL_DEFAULT;
3786268075Sdelphij
3787268075Sdelphij	result = bus_dma_tag_create(NULL,	/* parent */
3788168404Spjd	    HDAC_DMA_ALIGNMENT,			/* alignment */
3789268075Sdelphij	    0,					/* boundary */
3790268075Sdelphij	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
3791168404Spjd	    BUS_SPACE_MAXADDR,			/* highaddr */
3792268075Sdelphij	    NULL,				/* filtfunc */
3793268075Sdelphij	    NULL,				/* fistfuncarg */
3794268075Sdelphij	    sc->chan_size, 			/* maxsize */
3795268075Sdelphij	    1,					/* nsegments */
3796268075Sdelphij	    sc->chan_size, 			/* maxsegsz */
3797268075Sdelphij	    0,					/* flags */
3798268075Sdelphij	    NULL,				/* lockfunc */
3799275811Sdelphij	    NULL,				/* lockfuncarg */
3800286570Smav	    &sc->chan_dmat);			/* dmat */
3801275811Sdelphij	if (result != 0) {
3802206796Spjd		device_printf(dev, "%s: bus_dma_tag_create failed (%x)\n",
3803168404Spjd		     __func__, result);
3804286570Smav		snd_mtxfree(sc->lock);
3805168404Spjd		free(sc, M_DEVBUF);
3806209101Smm		return (ENXIO);
3807236884Smm	}
3808236884Smm
3809185029Spjd
3810185029Spjd	sc->hdabus = NULL;
3811236884Smm	for (i = 0; i < HDAC_CODEC_MAX; i++)
3812185029Spjd		sc->codecs[i] = NULL;
3813185029Spjd
3814168404Spjd	pci_enable_busmaster(dev);
3815185029Spjd
3816240133Smm	if (vendor == INTEL_VENDORID) {
3817240133Smm		/* TCSEL -> TC0 */
3818277300Ssmh		v = pci_read_config(dev, 0x44, 1);
3819168404Spjd		pci_write_config(dev, 0x44, v & 0xf8, 1);
3820286570Smav		HDA_BOOTVERBOSE(
3821286570Smav			device_printf(dev, "TCSEL: 0x%02d -> 0x%02d\n", v,
3822219089Spjd			    pci_read_config(dev, 0x44, 1));
3823219089Spjd		);
3824219089Spjd	}
3825219089Spjd
3826219089Spjd#ifdef HDAC_MSI_ENABLED
3827219089Spjd	if (resource_int_value(device_get_name(dev),
3828219089Spjd	    device_get_unit(dev), "msi", &i) == 0 && i != 0 &&
3829219089Spjd	    pci_msi_count(dev) == 1)
3830219089Spjd		sc->flags |= HDAC_F_MSI;
3831168404Spjd	else
3832168404Spjd#endif
3833168404Spjd		sc->flags &= ~HDAC_F_MSI;
3834168404Spjd
3835242845Sdelphij#if defined(__i386__) || defined(__amd64__)
3836242845Sdelphij	sc->flags |= HDAC_F_DMA_NOCACHE;
3837168404Spjd
3838242845Sdelphij	if (resource_int_value(device_get_name(dev),
3839168404Spjd	    device_get_unit(dev), "snoop", &i) == 0 && i != 0) {
3840168404Spjd#else
3841168404Spjd	sc->flags &= ~HDAC_F_DMA_NOCACHE;
3842168404Spjd#endif
3843286570Smav		/*
3844275811Sdelphij		 * Try to enable PCIe snoop to avoid messing around with
3845168404Spjd		 * uncacheable DMA attribute. Since PCIe snoop register
3846219089Spjd		 * config is pretty much vendor specific, there are no
3847219089Spjd		 * general solutions on how to enable it, forcing us (even
3848286570Smav		 * Microsoft) to enable uncacheable or write combined DMA
3849275811Sdelphij		 * by default.
3850219089Spjd		 *
3851168404Spjd		 * http://msdn2.microsoft.com/en-us/library/ms790324.aspx
3852286570Smav		 */
3853286570Smav		for (i = 0; i < HDAC_PCIESNOOP_LEN; i++) {
3854168404Spjd			if (hdac_pcie_snoop[i].vendor != vendor)
3855168404Spjd				continue;
3856275811Sdelphij			sc->flags &= ~HDAC_F_DMA_NOCACHE;
3857286570Smav			if (hdac_pcie_snoop[i].reg == 0x00)
3858168404Spjd				break;
3859168404Spjd			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
3860168404Spjd			if ((v & hdac_pcie_snoop[i].enable) ==
3861286570Smav			    hdac_pcie_snoop[i].enable)
3862168404Spjd				break;
3863168404Spjd			v &= hdac_pcie_snoop[i].mask;
3864168404Spjd			v |= hdac_pcie_snoop[i].enable;
3865168404Spjd			pci_write_config(dev, hdac_pcie_snoop[i].reg, v, 1);
3866168404Spjd			v = pci_read_config(dev, hdac_pcie_snoop[i].reg, 1);
3867168404Spjd			if ((v & hdac_pcie_snoop[i].enable) !=
3868168404Spjd			    hdac_pcie_snoop[i].enable) {
3869286570Smav				HDA_BOOTVERBOSE(
3870168404Spjd					device_printf(dev,
3871286570Smav					    "WARNING: Failed to enable PCIe "
3872168404Spjd					    "snoop!\n");
3873168404Spjd				);
3874168404Spjd#if defined(__i386__) || defined(__amd64__)
3875168404Spjd				sc->flags |= HDAC_F_DMA_NOCACHE;
3876168404Spjd#endif
3877168404Spjd			}
3878168404Spjd			break;
3879168404Spjd		}
3880286570Smav#if defined(__i386__) || defined(__amd64__)
3881286570Smav	}
3882168404Spjd#endif
3883168404Spjd
3884168404Spjd	HDA_BOOTVERBOSE(
3885168404Spjd		device_printf(dev, "DMA Coherency: %s / vendor=0x%04x\n",
3886168404Spjd		    (sc->flags & HDAC_F_DMA_NOCACHE) ?
3887168404Spjd		    "Uncacheable" : "PCIe snoop", vendor);
3888168404Spjd	);
3889168404Spjd
3890168404Spjd	/* Allocate resources */
3891168404Spjd	result = hdac_mem_alloc(sc);
3892168404Spjd	if (result != 0)
3893168404Spjd		goto hdac_attach_fail;
3894168404Spjd	result = hdac_irq_alloc(sc);
3895168404Spjd	if (result != 0)
3896168404Spjd		goto hdac_attach_fail;
3897168404Spjd
3898168404Spjd	/* Get Capabilities */
3899168404Spjd	result = hdac_get_capabilities(sc);
3900168404Spjd	if (result != 0)
3901168404Spjd		goto hdac_attach_fail;
3902168404Spjd
3903168404Spjd	/* Allocate CORB and RIRB dma memory */
3904168404Spjd	result = hdac_dma_alloc(sc, &sc->corb_dma,
3905168404Spjd	    sc->corb_size * sizeof(uint32_t));
3906168404Spjd	if (result != 0)
3907168404Spjd		goto hdac_attach_fail;
3908168404Spjd	result = hdac_dma_alloc(sc, &sc->rirb_dma,
3909168404Spjd	    sc->rirb_size * sizeof(struct hdac_rirb));
3910168404Spjd	if (result != 0)
3911168404Spjd		goto hdac_attach_fail;
3912168404Spjd
3913168404Spjd	/* Quiesce everything */
3914168404Spjd	hdac_reset(sc);
3915168404Spjd
3916168404Spjd	/* Initialize the CORB and RIRB */
3917168404Spjd	hdac_corb_init(sc);
3918168404Spjd	hdac_rirb_init(sc);
3919168404Spjd
3920168404Spjd	/* Defer remaining of initialization until interrupts are enabled */
3921246666Smm	sc->intrhook.ich_func = hdac_attach2;
3922275811Sdelphij	sc->intrhook.ich_arg = (void *)sc;
3923275811Sdelphij	if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
3924168404Spjd		sc->intrhook.ich_func = NULL;
3925268075Sdelphij		hdac_attach2((void *)sc);
3926247187Smm	}
3927268075Sdelphij
3928185029Spjd	return (0);
3929228103Smm
3930168404Spjdhdac_attach_fail:
3931268075Sdelphij	hdac_irq_free(sc);
3932268075Sdelphij	hdac_dma_free(sc, &sc->rirb_dma);
3933268075Sdelphij	hdac_dma_free(sc, &sc->corb_dma);
3934168404Spjd	hdac_mem_free(sc);
3935268075Sdelphij	snd_mtxfree(sc->lock);
3936268075Sdelphij	free(sc, M_DEVBUF);
3937268075Sdelphij
3938268075Sdelphij	return (ENXIO);
3939268075Sdelphij}
3940268075Sdelphij
3941268075Sdelphijstatic void
3942168404Spjdhdac_audio_parse(struct hdac_devinfo *devinfo)
3943286570Smav{
3944268075Sdelphij	struct hdac_softc *sc = devinfo->codec->sc;
3945275811Sdelphij	struct hdac_widget *w;
3946168404Spjd	uint32_t res;
3947168404Spjd	int i;
3948168404Spjd	nid_t cad, nid;
3949275811Sdelphij
3950286570Smav	cad = devinfo->codec->cad;
3951168404Spjd	nid = devinfo->nid;
3952168404Spjd
3953168404Spjd	hdac_command(sc,
3954275811Sdelphij	    HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), cad);
3955168404Spjd
3956168404Spjd	DELAY(100);
3957168404Spjd
3958168404Spjd	res = hdac_command(sc,
3959168404Spjd	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
3960168404Spjd
3961168404Spjd	devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
3962168404Spjd	devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
3963168404Spjd	devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
3964168404Spjd
3965209962Smm	res = hdac_command(sc,
3966168404Spjd	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_GPIO_COUNT), cad);
3967168404Spjd	devinfo->function.audio.gpio = res;
3968286570Smav
3969286570Smav	HDA_BOOTVERBOSE(
3970168404Spjd		device_printf(sc->dev, "       Vendor: 0x%08x\n",
3971168404Spjd		    devinfo->vendor_id);
3972168404Spjd		device_printf(sc->dev, "       Device: 0x%08x\n",
3973168404Spjd		    devinfo->device_id);
3974168404Spjd		device_printf(sc->dev, "     Revision: 0x%08x\n",
3975168404Spjd		    devinfo->revision_id);
3976168404Spjd		device_printf(sc->dev, "     Stepping: 0x%08x\n",
3977168404Spjd		    devinfo->stepping_id);
3978286570Smav		device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
3979286570Smav		    sc->pci_subvendor);
3980168404Spjd		device_printf(sc->dev, "        Nodes: start=%d "
3981168404Spjd		    "endnode=%d total=%d\n",
3982168404Spjd		    devinfo->startnode, devinfo->endnode, devinfo->nodecnt);
3983168404Spjd		device_printf(sc->dev, "    CORB size: %d\n", sc->corb_size);
3984168404Spjd		device_printf(sc->dev, "    RIRB size: %d\n", sc->rirb_size);
3985168404Spjd		device_printf(sc->dev, "      Streams: ISS=%d OSS=%d BSS=%d\n",
3986168404Spjd		    sc->num_iss, sc->num_oss, sc->num_bss);
3987168404Spjd		device_printf(sc->dev, "         GPIO: 0x%08x\n",
3988286570Smav		    devinfo->function.audio.gpio);
3989168404Spjd		device_printf(sc->dev, "               NumGPIO=%d NumGPO=%d "
3990168404Spjd		    "NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
3991168404Spjd		    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
3992168404Spjd		    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
3993275811Sdelphij		    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
3994168404Spjd		    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
3995168404Spjd		    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
3996168404Spjd	);
3997219089Spjd
3998275811Sdelphij	res = hdac_command(sc,
3999286570Smav	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS),
4000275811Sdelphij	    cad);
4001168404Spjd	devinfo->function.audio.supp_stream_formats = res;
4002168404Spjd
4003168404Spjd	res = hdac_command(sc,
4004275811Sdelphij	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE),
4005275811Sdelphij	    cad);
4006275811Sdelphij	devinfo->function.audio.supp_pcm_size_rate = res;
4007275811Sdelphij
4008168404Spjd	res = hdac_command(sc,
4009168404Spjd	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP),
4010286570Smav	    cad);
4011286570Smav	devinfo->function.audio.outamp_cap = res;
4012168404Spjd
4013168404Spjd	res = hdac_command(sc,
4014168404Spjd	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP),
4015168404Spjd	    cad);
4016168404Spjd	devinfo->function.audio.inamp_cap = res;
4017168404Spjd
4018268075Sdelphij	if (devinfo->nodecnt > 0)
4019185029Spjd		devinfo->widget = (struct hdac_widget *)malloc(
4020247187Smm		    sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
4021208373Smm		    M_NOWAIT | M_ZERO);
4022258389Savg	else
4023286570Smav		devinfo->widget = NULL;
4024168404Spjd
4025168404Spjd	if (devinfo->widget == NULL) {
4026168404Spjd		device_printf(sc->dev, "unable to allocate widgets!\n");
4027268075Sdelphij		devinfo->endnode = devinfo->startnode;
4028168404Spjd		devinfo->nodecnt = 0;
4029168404Spjd		return;
4030168404Spjd	}
4031268075Sdelphij
4032268075Sdelphij	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4033268075Sdelphij		w = hdac_widget_get(devinfo, i);
4034268075Sdelphij		if (w == NULL)
4035268075Sdelphij			device_printf(sc->dev, "Ghost widget! nid=%d!\n", i);
4036268075Sdelphij		else {
4037168404Spjd			w->devinfo = devinfo;
4038168404Spjd			w->nid = i;
4039219089Spjd			w->enable = 1;
4040168404Spjd			w->selconn = -1;
4041168404Spjd			w->pflags = 0;
4042168404Spjd			w->ctlflags = 0;
4043275811Sdelphij			w->param.eapdbtl = HDAC_INVALID;
4044168404Spjd			hdac_widget_parse(w);
4045275811Sdelphij		}
4046168404Spjd	}
4047168404Spjd}
4048275811Sdelphij
4049168404Spjdstatic void
4050275811Sdelphijhdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
4051275811Sdelphij{
4052275811Sdelphij	struct hdac_softc *sc = devinfo->codec->sc;
4053275811Sdelphij	struct hdac_audio_ctl *ctls;
4054168404Spjd	struct hdac_widget *w, *cw;
4055275811Sdelphij	int i, j, cnt, max, ocap, icap;
4056168404Spjd	int mute, offset, step, size;
4057286570Smav
4058286570Smav	/* XXX This is redundant */
4059286570Smav	max = 0;
4060286570Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4061286570Smav		w = hdac_widget_get(devinfo, i);
4062286570Smav		if (w == NULL || w->enable == 0)
4063286570Smav			continue;
4064286570Smav		if (w->param.outamp_cap != 0)
4065286570Smav			max++;
4066286570Smav		if (w->param.inamp_cap != 0) {
4067286570Smav			switch (w->type) {
4068168404Spjd			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4069286570Smav			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4070286570Smav				for (j = 0; j < w->nconns; j++) {
4071168404Spjd					cw = hdac_widget_get(devinfo,
4072168404Spjd					    w->conns[j]);
4073275811Sdelphij					if (cw == NULL || cw->enable == 0)
4074275811Sdelphij						continue;
4075168404Spjd					max++;
4076168404Spjd				}
4077275811Sdelphij				break;
4078275811Sdelphij			default:
4079275811Sdelphij				max++;
4080275811Sdelphij				break;
4081185029Spjd			}
4082168404Spjd		}
4083168404Spjd	}
4084168404Spjd
4085168404Spjd	devinfo->function.audio.ctlcnt = max;
4086168404Spjd
4087286570Smav	if (max < 1)
4088286570Smav		return;
4089286570Smav
4090219089Spjd	ctls = (struct hdac_audio_ctl *)malloc(
4091219089Spjd	    sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT);
4092168404Spjd
4093168404Spjd	if (ctls == NULL) {
4094286570Smav		/* Blekh! */
4095219089Spjd		device_printf(sc->dev, "unable to allocate ctls!\n");
4096168404Spjd		devinfo->function.audio.ctlcnt = 0;
4097168404Spjd		return;
4098168404Spjd	}
4099168404Spjd
4100286570Smav	cnt = 0;
4101286570Smav	for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) {
4102275811Sdelphij		if (cnt >= max) {
4103168404Spjd			device_printf(sc->dev, "%s: Ctl overflow!\n",
4104286570Smav			    __func__);
4105286570Smav			break;
4106286570Smav		}
4107286570Smav		w = hdac_widget_get(devinfo, i);
4108286570Smav		if (w == NULL || w->enable == 0)
4109286570Smav			continue;
4110185029Spjd		ocap = w->param.outamp_cap;
4111185029Spjd		icap = w->param.inamp_cap;
4112185029Spjd		if (ocap != 0) {
4113185029Spjd			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap);
4114185029Spjd			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap);
4115185029Spjd			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap);
4116185029Spjd			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap);
4117185029Spjd			/*if (offset > step) {
4118268075Sdelphij				HDA_BOOTVERBOSE(
4119268075Sdelphij					device_printf(sc->dev,
4120168404Spjd					    "HDA_DEBUG: BUGGY outamp: nid=%d "
4121251629Sdelphij					    "[offset=%d > step=%d]\n",
4122251629Sdelphij					    w->nid, offset, step);
4123251629Sdelphij				);
4124251629Sdelphij				offset = step;
4125168404Spjd			}*/
4126219089Spjd			ctls[cnt].enable = 1;
4127268123Sdelphij			ctls[cnt].widget = w;
4128168404Spjd			ctls[cnt].mute = mute;
4129286570Smav			ctls[cnt].step = step;
4130286570Smav			ctls[cnt].size = size;
4131168404Spjd			ctls[cnt].offset = offset;
4132228392Spjd			ctls[cnt].left = offset;
4133228392Spjd			ctls[cnt].right = offset;
4134228392Spjd			ctls[cnt++].dir = HDA_CTL_OUT;
4135168404Spjd		}
4136208373Smm
4137185029Spjd		if (icap != 0) {
4138185029Spjd			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap);
4139185029Spjd			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap);
4140185029Spjd			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap);
4141185029Spjd			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap);
4142185029Spjd			/*if (offset > step) {
4143185029Spjd				HDA_BOOTVERBOSE(
4144208373Smm					device_printf(sc->dev,
4145185029Spjd					    "HDA_DEBUG: BUGGY inamp: nid=%d "
4146286570Smav					    "[offset=%d > step=%d]\n",
4147208373Smm					    w->nid, offset, step);
4148208373Smm				);
4149185029Spjd				offset = step;
4150185029Spjd			}*/
4151185029Spjd			switch (w->type) {
4152185029Spjd			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4153185029Spjd			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4154185029Spjd				for (j = 0; j < w->nconns; j++) {
4155185029Spjd					if (cnt >= max) {
4156185029Spjd						device_printf(sc->dev,
4157185029Spjd						    "%s: Ctl overflow!\n",
4158185029Spjd						    __func__);
4159185029Spjd						break;
4160185029Spjd					}
4161258389Savg					cw = hdac_widget_get(devinfo,
4162185029Spjd					    w->conns[j]);
4163247187Smm					if (cw == NULL || cw->enable == 0)
4164247187Smm						continue;
4165247187Smm					ctls[cnt].enable = 1;
4166247187Smm					ctls[cnt].widget = w;
4167185029Spjd					ctls[cnt].childwidget = cw;
4168185029Spjd					ctls[cnt].index = j;
4169185029Spjd					ctls[cnt].mute = mute;
4170251478Sdelphij					ctls[cnt].step = step;
4171251478Sdelphij					ctls[cnt].size = size;
4172185029Spjd					ctls[cnt].offset = offset;
4173258389Savg					ctls[cnt].left = offset;
4174251478Sdelphij					ctls[cnt].right = offset;
4175251478Sdelphij					ctls[cnt++].dir = HDA_CTL_IN;
4176251478Sdelphij				}
4177251478Sdelphij				break;
4178251478Sdelphij			default:
4179251478Sdelphij				if (cnt >= max) {
4180251478Sdelphij					device_printf(sc->dev,
4181251478Sdelphij					    "%s: Ctl overflow!\n",
4182258389Savg					    __func__);
4183258389Savg					break;
4184251478Sdelphij				}
4185251478Sdelphij				ctls[cnt].enable = 1;
4186251478Sdelphij				ctls[cnt].widget = w;
4187251478Sdelphij				ctls[cnt].mute = mute;
4188251478Sdelphij				ctls[cnt].step = step;
4189251478Sdelphij				ctls[cnt].size = size;
4190185029Spjd				ctls[cnt].offset = offset;
4191185029Spjd				ctls[cnt].left = offset;
4192258389Savg				ctls[cnt].right = offset;
4193185029Spjd				ctls[cnt++].dir = HDA_CTL_IN;
4194275811Sdelphij				break;
4195185029Spjd			}
4196185029Spjd		}
4197185029Spjd	}
4198185029Spjd
4199275811Sdelphij	devinfo->function.audio.ctl = ctls;
4200185029Spjd}
4201185029Spjd
4202185029Spjdstatic const struct {
4203185029Spjd	uint32_t model;
4204185029Spjd	uint32_t id;
4205185029Spjd	uint32_t set, unset;
4206185029Spjd} hdac_quirks[] = {
4207185029Spjd	/*
4208185029Spjd	 * XXX Force stereo quirk. Monoural recording / playback
4209185029Spjd	 *     on few codecs (especially ALC880) seems broken or
4210185029Spjd	 *     perhaps unsupported.
4211185029Spjd	 */
4212208373Smm	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
4213208373Smm	    HDA_QUIRK_FORCESTEREO | HDA_QUIRK_IVREF, 0 },
4214208373Smm	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
4215208373Smm	    HDA_QUIRK_GPIO0, 0 },
4216208373Smm	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
4217208373Smm	    HDA_QUIRK_GPIO0, 0 },
4218208373Smm	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
4219208373Smm	    HDA_QUIRK_GPIO0, 0 },
4220185029Spjd	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
4221185029Spjd	    HDA_QUIRK_GPIO0, 0 },
4222168404Spjd	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
4223185029Spjd	    HDA_QUIRK_GPIO0, 0 },
4224168404Spjd	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
4225275811Sdelphij	    HDA_QUIRK_GPIO0, 0 },
4226168404Spjd	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
4227168404Spjd	    HDA_QUIRK_EAPDINV, 0 },
4228275811Sdelphij	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
4229168404Spjd	    HDA_QUIRK_EAPDINV, 0 },
4230168404Spjd	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
4231168404Spjd	    HDA_QUIRK_OVREF, 0 },
4232168404Spjd	{ ASUS_W6F_SUBVENDOR, HDA_CODEC_ALC861,
4233168404Spjd	    HDA_QUIRK_OVREF, 0 },
4234168404Spjd	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
4235168404Spjd	    HDA_QUIRK_OVREF, 0 },
4236168404Spjd	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
4237168404Spjd	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },*/
4238286570Smav	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
4239286570Smav	    HDA_QUIRK_GPIO1, 0 },
4240286570Smav	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
4241219089Spjd	    HDA_QUIRK_EAPDINV, 0 },
4242219089Spjd	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
4243219089Spjd	    HDA_QUIRK_EAPDINV, 0 },
4244168404Spjd	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
4245168404Spjd	    HDA_QUIRK_GPIO0 | HDA_QUIRK_OVREF50, 0},
4246168404Spjd	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
4247168404Spjd	    HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 },
4248168404Spjd	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205,
4249251520Sdelphij	    HDA_QUIRK_GPIO0, 0 },
4250251520Sdelphij	{ HDA_MATCH_ALL, HDA_CODEC_AD1988,
4251251520Sdelphij	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4252251520Sdelphij	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
4253251520Sdelphij	    HDA_QUIRK_IVREF80, HDA_QUIRK_IVREF50 | HDA_QUIRK_IVREF100 },
4254251520Sdelphij	{ HDA_MATCH_ALL, HDA_CODEC_CXVENICE,
4255251520Sdelphij	    0, HDA_QUIRK_FORCESTEREO },
4256251520Sdelphij	{ HDA_MATCH_ALL, HDA_CODEC_STACXXXX,
4257251520Sdelphij	    HDA_QUIRK_SOFTPCMVOL, 0 }
4258268075Sdelphij};
4259268075Sdelphij#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
4260268075Sdelphij
4261251520Sdelphijstatic void
4262251520Sdelphijhdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
4263251520Sdelphij{
4264286570Smav	struct hdac_widget *w;
4265251520Sdelphij	struct hdac_audio_ctl *ctl;
4266275811Sdelphij	uint32_t id, subvendor;
4267251520Sdelphij	int i;
4268251520Sdelphij
4269251520Sdelphij	id = hdac_codec_id(devinfo);
4270251520Sdelphij	subvendor = devinfo->codec->sc->pci_subvendor;
4271251520Sdelphij
4272251520Sdelphij	/*
4273251520Sdelphij	 * Quirks
4274251520Sdelphij	 */
4275251520Sdelphij	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
4276251520Sdelphij		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) &&
4277251520Sdelphij		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
4278268858Sdelphij			continue;
4279268858Sdelphij		if (hdac_quirks[i].set != 0)
4280268858Sdelphij			devinfo->function.audio.quirks |=
4281268858Sdelphij			    hdac_quirks[i].set;
4282268858Sdelphij		if (hdac_quirks[i].unset != 0)
4283268858Sdelphij			devinfo->function.audio.quirks &=
4284268858Sdelphij			    ~(hdac_quirks[i].unset);
4285268858Sdelphij	}
4286268858Sdelphij
4287268858Sdelphij	switch (id) {
4288268858Sdelphij	case HDA_CODEC_ALC260:
4289168404Spjd		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4290268858Sdelphij			w = hdac_widget_get(devinfo, i);
4291268858Sdelphij			if (w == NULL || w->enable == 0)
4292168404Spjd				continue;
4293168404Spjd			if (w->type !=
4294168404Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
4295268858Sdelphij				continue;
4296268858Sdelphij			if (w->nid != 5)
4297205231Skmacy				w->enable = 0;
4298205231Skmacy		}
4299206796Spjd		if (subvendor == HP_XW4300_SUBVENDOR) {
4300219089Spjd			ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1);
4301168404Spjd			if (ctl != NULL && ctl->widget != NULL) {
4302168404Spjd				ctl->ossmask = SOUND_MASK_SPEAKER;
4303168404Spjd				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4304168404Spjd			}
4305168404Spjd			ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1);
4306168404Spjd			if (ctl != NULL && ctl->widget != NULL) {
4307219089Spjd				ctl->ossmask = SOUND_MASK_SPEAKER;
4308268858Sdelphij				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4309185029Spjd			}
4310185029Spjd		} else if (subvendor == HP_3010_SUBVENDOR) {
4311185029Spjd			ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1);
4312185029Spjd			if (ctl != NULL && ctl->widget != NULL) {
4313185029Spjd				ctl->ossmask = SOUND_MASK_SPEAKER;
4314185029Spjd				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4315219089Spjd			}
4316268858Sdelphij			ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1);
4317268858Sdelphij			if (ctl != NULL && ctl->widget != NULL) {
4318168404Spjd				ctl->ossmask = SOUND_MASK_SPEAKER;
4319168404Spjd				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4320168404Spjd			}
4321219089Spjd		}
4322219089Spjd		break;
4323168404Spjd	case HDA_CODEC_ALC262:
4324286570Smav		if (subvendor == HP_DC7700S_SUBVENDOR) {
4325286570Smav			ctl = hdac_audio_ctl_amp_get(devinfo, 21, 0, 1);
4326286570Smav			if (ctl != NULL && ctl->widget != NULL) {
4327286570Smav				ctl->ossmask = SOUND_MASK_PHONEOUT;
4328168404Spjd				ctl->widget->ctlflags |= SOUND_MASK_PHONEOUT;
4329268858Sdelphij			}
4330268858Sdelphij			ctl = hdac_audio_ctl_amp_get(devinfo, 22, 0, 1);
4331168404Spjd			if (ctl != NULL && ctl->widget != NULL) {
4332286570Smav				ctl->ossmask = SOUND_MASK_SPEAKER;
4333268858Sdelphij				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4334268858Sdelphij			}
4335268858Sdelphij		} else if (subvendor == HP_DC7700_SUBVENDOR) {
4336286570Smav			ctl = hdac_audio_ctl_amp_get(devinfo, 22, 0, 1);
4337275811Sdelphij			if (ctl != NULL && ctl->widget != NULL) {
4338268858Sdelphij				ctl->ossmask = SOUND_MASK_SPEAKER;
4339268858Sdelphij				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4340168404Spjd			}
4341168404Spjd			ctl = hdac_audio_ctl_amp_get(devinfo, 27, 0, 1);
4342268858Sdelphij			if (ctl != NULL && ctl->widget != NULL) {
4343268858Sdelphij				ctl->ossmask = SOUND_MASK_SPEAKER;
4344168404Spjd				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4345168404Spjd			}
4346168404Spjd		}
4347251629Sdelphij		break;
4348251629Sdelphij	case HDA_CODEC_ALC268:
4349168404Spjd		if (HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subvendor)) {
4350185029Spjd			w = hdac_widget_get(devinfo, 29);
4351168404Spjd			if (w != NULL) {
4352168404Spjd				w->enable = 1;
4353168404Spjd				w->type =
4354168404Spjd				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET;
4355286570Smav				w->param.widget_cap &=
4356168404Spjd				    ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
4357219089Spjd				w->param.widget_cap |=
4358219089Spjd				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
4359219089Spjd				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
4360219089Spjd				strlcpy(w->name, "beep widget", sizeof(w->name));
4361219089Spjd			}
4362219089Spjd		}
4363219089Spjd		break;
4364286570Smav	case HDA_CODEC_ALC861:
4365286570Smav		ctl = hdac_audio_ctl_amp_get(devinfo, 21, 2, 1);
4366286570Smav		if (ctl != NULL)
4367286570Smav			ctl->muted = HDA_AMP_MUTE_ALL;
4368286570Smav		break;
4369286570Smav	case HDA_CODEC_ALC880:
4370286570Smav		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4371286570Smav			w = hdac_widget_get(devinfo, i);
4372286570Smav			if (w == NULL || w->enable == 0)
4373286570Smav				continue;
4374286570Smav			if (w->type ==
4375286570Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
4376286570Smav			    w->nid != 9 && w->nid != 29) {
4377286570Smav					w->enable = 0;
4378185029Spjd			} else if (w->type !=
4379286570Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET &&
4380286570Smav			    w->nid == 29) {
4381168404Spjd				w->type =
4382286570Smav				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET;
4383286570Smav				w->param.widget_cap &=
4384286570Smav				    ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
4385286570Smav				w->param.widget_cap |=
4386168404Spjd				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
4387168404Spjd				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
4388286570Smav				strlcpy(w->name, "beep widget", sizeof(w->name));
4389286570Smav			}
4390286570Smav		}
4391286570Smav		break;
4392286570Smav	case HDA_CODEC_ALC883:
4393286570Smav		/*
4394286570Smav		 * nid: 24/25 = External (jack) or Internal (fixed) Mic.
4395286570Smav		 *              Clear vref cap for jack connectivity.
4396286570Smav		 */
4397286570Smav		w = hdac_widget_get(devinfo, 24);
4398286570Smav		if (w != NULL && w->enable != 0 && w->type ==
4399286570Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4400286570Smav		    (w->wclass.pin.config &
4401286570Smav		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4402286570Smav		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
4403286570Smav			w->wclass.pin.cap &= ~(
4404286570Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
4405286570Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
4406286570Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
4407286598Smav		w = hdac_widget_get(devinfo, 25);
4408286598Smav		if (w != NULL && w->enable != 0 && w->type ==
4409286598Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4410286598Smav		    (w->wclass.pin.config &
4411286598Smav		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4412286598Smav		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
4413286570Smav			w->wclass.pin.cap &= ~(
4414286598Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
4415286598Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
4416286598Smav			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
4417286598Smav		/*
4418286598Smav		 * nid: 26 = Line-in, leave it alone.
4419286570Smav		 */
4420286570Smav		break;
4421185029Spjd	case HDA_CODEC_AD1981HD:
4422185029Spjd		w = hdac_widget_get(devinfo, 11);
4423168404Spjd		if (w != NULL && w->enable != 0 && w->nconns > 3)
4424168404Spjd			w->selconn = 3;
4425168404Spjd		if (subvendor == IBM_M52_SUBVENDOR) {
4426286570Smav			ctl = hdac_audio_ctl_amp_get(devinfo, 7, 0, 1);
4427168404Spjd			if (ctl != NULL)
4428168404Spjd				ctl->ossmask = SOUND_MASK_SPEAKER;
4429168404Spjd		}
4430209962Smm		break;
4431286570Smav	case HDA_CODEC_AD1986A:
4432185029Spjd		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4433168404Spjd			w = hdac_widget_get(devinfo, i);
4434286570Smav			if (w == NULL || w->enable == 0)
4435168404Spjd				continue;
4436219089Spjd			if (w->type !=
4437219089Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
4438168404Spjd				continue;
4439168404Spjd			if (w->nid != 3)
4440286570Smav				w->enable = 0;
4441168404Spjd		}
4442168404Spjd		if (subvendor == ASUS_M2NPVMX_SUBVENDOR ||
4443219089Spjd		    subvendor == ASUS_A8NVMCSM_SUBVENDOR) {
4444168404Spjd			/* nid 28 is mic, nid 29 is line-in */
4445168404Spjd			w = hdac_widget_get(devinfo, 15);
4446286570Smav			if (w != NULL)
4447286570Smav				w->selconn = 2;
4448286570Smav			w = hdac_widget_get(devinfo, 16);
4449286570Smav			if (w != NULL)
4450286570Smav				w->selconn = 1;
4451286570Smav		} else if (subvendor == ASUS_A8X_SUBVENDOR) {
4452185029Spjd			/*
4453185029Spjd			 * This is just plain ridiculous.. There
4454168404Spjd			 * are several A8 series that share the same
4455242845Sdelphij			 * pci id but works differently (EAPD).
4456242845Sdelphij			 */
4457242845Sdelphij			w = hdac_widget_get(devinfo, 26);
4458242845Sdelphij			if (w != NULL && w->type ==
4459242845Sdelphij			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4460286570Smav			    (w->wclass.pin.config &
4461242845Sdelphij			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
4462242845Sdelphij			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
4463242845Sdelphij				devinfo->function.audio.quirks &=
4464242845Sdelphij				    ~HDA_QUIRK_EAPDINV;
4465286570Smav		}
4466168404Spjd		break;
4467240133Smm	case HDA_CODEC_AD1988:
4468240133Smm	case HDA_CODEC_AD1988B:
4469277300Ssmh		/*w = hdac_widget_get(devinfo, 12);
4470168404Spjd		if (w != NULL) {
4471168404Spjd			w->selconn = 1;
4472168404Spjd			w->pflags |= HDA_ADC_LOCKED;
4473286570Smav		}
4474168404Spjd		w = hdac_widget_get(devinfo, 13);
4475168404Spjd		if (w != NULL) {
4476286570Smav			w->selconn = 4;
4477275811Sdelphij			w->pflags |= HDA_ADC_LOCKED;
4478286570Smav		}
4479286570Smav		w = hdac_widget_get(devinfo, 14);
4480286570Smav		if (w != NULL) {
4481286570Smav			w->selconn = 2;
4482286570Smav			w->pflags |= HDA_ADC_LOCKED;
4483286570Smav		}*/
4484286570Smav		ctl = hdac_audio_ctl_amp_get(devinfo, 57, 0, 1);
4485168404Spjd		if (ctl != NULL) {
4486286570Smav			ctl->ossmask = SOUND_MASK_IGAIN;
4487286570Smav			ctl->widget->ctlflags |= SOUND_MASK_IGAIN;
4488168404Spjd		}
4489219089Spjd		ctl = hdac_audio_ctl_amp_get(devinfo, 58, 0, 1);
4490168404Spjd		if (ctl != NULL) {
4491168404Spjd			ctl->ossmask = SOUND_MASK_IGAIN;
4492219089Spjd			ctl->widget->ctlflags |= SOUND_MASK_IGAIN;
4493286570Smav		}
4494286570Smav		ctl = hdac_audio_ctl_amp_get(devinfo, 60, 0, 1);
4495286570Smav		if (ctl != NULL) {
4496168404Spjd			ctl->ossmask = SOUND_MASK_IGAIN;
4497286570Smav			ctl->widget->ctlflags |= SOUND_MASK_IGAIN;
4498286570Smav		}
4499286570Smav		ctl = hdac_audio_ctl_amp_get(devinfo, 32, 0, 1);
4500185029Spjd		if (ctl != NULL) {
4501219089Spjd			ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME;
4502168404Spjd			ctl->widget->ctlflags |= SOUND_MASK_MIC;
4503168404Spjd		}
4504168404Spjd		ctl = hdac_audio_ctl_amp_get(devinfo, 32, 4, 1);
4505168404Spjd		if (ctl != NULL) {
4506168404Spjd			ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME;
4507168404Spjd			ctl->widget->ctlflags |= SOUND_MASK_MIC;
4508168404Spjd		}
4509168404Spjd		ctl = hdac_audio_ctl_amp_get(devinfo, 32, 1, 1);
4510168404Spjd		if (ctl != NULL) {
4511185029Spjd			ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME;
4512185029Spjd			ctl->widget->ctlflags |= SOUND_MASK_LINE;
4513219089Spjd		}
4514286570Smav		ctl = hdac_audio_ctl_amp_get(devinfo, 32, 7, 1);
4515286570Smav		if (ctl != NULL) {
4516219089Spjd			ctl->ossmask = SOUND_MASK_SPEAKER | SOUND_MASK_VOLUME;
4517185029Spjd			ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
4518168404Spjd		}
4519168404Spjd		break;
4520168404Spjd	case HDA_CODEC_STAC9205:
4521168404Spjd		if (subvendor == DELL_V1500_SUBVENDOR) {
4522168404Spjd			w = hdac_widget_get(devinfo, 29);
4523168404Spjd			if (w != NULL)
4524185029Spjd				w->selconn = 1;
4525185029Spjd			w = hdac_widget_get(devinfo, 30);
4526219089Spjd			if (w != NULL)
4527286570Smav				w->selconn = 1;
4528219089Spjd		}
4529185029Spjd		break;
4530168404Spjd	case HDA_CODEC_STAC9221:
4531168404Spjd		/*
4532168404Spjd		 * Dell XPS M1210 need all DACs for each output jacks
4533168404Spjd		 */
4534168404Spjd		if (subvendor == DELL_XPSM1210_SUBVENDOR)
4535168404Spjd			break;
4536168404Spjd		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4537168404Spjd			w = hdac_widget_get(devinfo, i);
4538185029Spjd			if (w == NULL || w->enable == 0)
4539168404Spjd				continue;
4540286570Smav			if (w->type !=
4541286570Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
4542286570Smav				continue;
4543185029Spjd			if (w->nid != 2)
4544185029Spjd				w->enable = 0;
4545185029Spjd		}
4546185029Spjd		break;
4547185029Spjd	case HDA_CODEC_STAC9221D:
4548185029Spjd		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4549185029Spjd			w = hdac_widget_get(devinfo, i);
4550185029Spjd			if (w == NULL || w->enable == 0)
4551185029Spjd				continue;
4552286570Smav			if (w->type ==
4553185029Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
4554185029Spjd			    w->nid != 6)
4555185029Spjd				w->enable = 0;
4556185029Spjd
4557286570Smav		}
4558168404Spjd		break;
4559185029Spjd	case HDA_CODEC_STAC9227:
4560275811Sdelphij		w = hdac_widget_get(devinfo, 8);
4561168404Spjd		if (w != NULL)
4562168404Spjd			w->enable = 0;
4563258632Savg		w = hdac_widget_get(devinfo, 9);
4564258632Savg		if (w != NULL)
4565258632Savg			w->enable = 0;
4566258632Savg		break;
4567168404Spjd	case HDA_CODEC_CXWAIKIKI:
4568258632Savg		if (subvendor == HP_DV5000_SUBVENDOR) {
4569258632Savg			w = hdac_widget_get(devinfo, 27);
4570258632Savg			if (w != NULL)
4571258632Savg				w->enable = 0;
4572258632Savg		}
4573258632Savg		ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1);
4574258632Savg		if (ctl != NULL)
4575258632Savg			ctl->ossmask = SOUND_MASK_SKIP;
4576168404Spjd		ctl = hdac_audio_ctl_amp_get(devinfo, 25, 0, 1);
4577168404Spjd		if (ctl != NULL && ctl->childwidget != NULL &&
4578168404Spjd		    ctl->childwidget->enable != 0) {
4579168404Spjd			ctl->ossmask = SOUND_MASK_PCM | SOUND_MASK_VOLUME;
4580168404Spjd			ctl->childwidget->ctlflags |= SOUND_MASK_PCM;
4581168404Spjd		}
4582286570Smav		ctl = hdac_audio_ctl_amp_get(devinfo, 25, 1, 1);
4583168404Spjd		if (ctl != NULL && ctl->childwidget != NULL &&
4584219089Spjd		    ctl->childwidget->enable != 0) {
4585268075Sdelphij			ctl->ossmask = SOUND_MASK_LINE | SOUND_MASK_VOLUME;
4586260150Sdelphij			ctl->childwidget->ctlflags |= SOUND_MASK_LINE;
4587260150Sdelphij		}
4588260150Sdelphij		ctl = hdac_audio_ctl_amp_get(devinfo, 25, 2, 1);
4589260150Sdelphij		if (ctl != NULL && ctl->childwidget != NULL &&
4590260150Sdelphij		    ctl->childwidget->enable != 0) {
4591219089Spjd			ctl->ossmask = SOUND_MASK_MIC | SOUND_MASK_VOLUME;
4592219089Spjd			ctl->childwidget->ctlflags |= SOUND_MASK_MIC;
4593219089Spjd		}
4594219089Spjd		ctl = hdac_audio_ctl_amp_get(devinfo, 26, 0, 1);
4595168404Spjd		if (ctl != NULL) {
4596268075Sdelphij			ctl->ossmask = SOUND_MASK_SKIP;
4597268075Sdelphij			/* XXX mixer \=rec mic broken.. why?!? */
4598268075Sdelphij			/* ctl->widget->ctlflags |= SOUND_MASK_MIC; */
4599268075Sdelphij		}
4600168404Spjd		break;
4601168404Spjd	default:
4602168404Spjd		break;
4603168404Spjd	}
4604168404Spjd}
4605219089Spjd
4606219089Spjdstatic int
4607168404Spjdhdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo)
4608168404Spjd{
4609168404Spjd	int *dev = &devinfo->function.audio.ossidx;
4610286570Smav
4611168404Spjd	while (*dev < SOUND_MIXER_NRDEVICES) {
4612168404Spjd		switch (*dev) {
4613168404Spjd		case SOUND_MIXER_VOLUME:
4614168404Spjd		case SOUND_MIXER_BASS:
4615168404Spjd		case SOUND_MIXER_TREBLE:
4616219089Spjd		case SOUND_MIXER_PCM:
4617219089Spjd		case SOUND_MIXER_SPEAKER:
4618219089Spjd		case SOUND_MIXER_LINE:
4619219089Spjd		case SOUND_MIXER_MIC:
4620286570Smav		case SOUND_MIXER_CD:
4621286570Smav		case SOUND_MIXER_RECLEV:
4622219089Spjd		case SOUND_MIXER_IGAIN:
4623219089Spjd		case SOUND_MIXER_OGAIN:	/* reserved for EAPD switch */
4624219089Spjd			(*dev)++;
4625219089Spjd			break;
4626219089Spjd		default:
4627243524Smm			return (*dev)++;
4628243524Smm			break;
4629243524Smm		}
4630243524Smm	}
4631243524Smm
4632243524Smm	return (-1);
4633219089Spjd}
4634219089Spjd
4635286570Smavstatic int
4636286570Smavhdac_widget_find_dac_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4637219089Spjd{
4638219089Spjd	struct hdac_widget *w;
4639219089Spjd	int i, ret = 0;
4640168404Spjd
4641275811Sdelphij	if (depth > HDA_PARSE_MAXDEPTH)
4642185029Spjd		return (0);
4643286570Smav	w = hdac_widget_get(devinfo, nid);
4644185029Spjd	if (w == NULL || w->enable == 0)
4645168404Spjd		return (0);
4646168404Spjd	switch (w->type) {
4647275811Sdelphij	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
4648168404Spjd		w->pflags |= HDA_DAC_PATH;
4649168404Spjd		ret = 1;
4650286570Smav		break;
4651219089Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4652168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4653168404Spjd		for (i = 0; i < w->nconns; i++) {
4654168404Spjd			if (hdac_widget_find_dac_path(devinfo,
4655168404Spjd			    w->conns[i], depth + 1) != 0) {
4656168404Spjd				if (w->selconn == -1)
4657219089Spjd					w->selconn = i;
4658251478Sdelphij				ret = 1;
4659258632Savg				w->pflags |= HDA_DAC_PATH;
4660258632Savg			}
4661268123Sdelphij		}
4662168404Spjd		break;
4663168404Spjd	default:
4664168404Spjd		break;
4665185029Spjd	}
4666168404Spjd	return (ret);
4667185029Spjd}
4668219089Spjd
4669168404Spjdstatic int
4670286570Smavhdac_widget_find_adc_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4671286570Smav{
4672286570Smav	struct hdac_widget *w;
4673185029Spjd	int i, conndev, ret = 0;
4674275811Sdelphij
4675251478Sdelphij	if (depth > HDA_PARSE_MAXDEPTH)
4676275811Sdelphij		return (0);
4677168404Spjd	w = hdac_widget_get(devinfo, nid);
4678168404Spjd	if (w == NULL || w->enable == 0)
4679258632Savg		return (0);
4680168404Spjd	switch (w->type) {
4681168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
4682168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
4683168404Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4684219089Spjd		for (i = 0; i < w->nconns; i++) {
4685258632Savg			if (hdac_widget_find_adc_path(devinfo, w->conns[i],
4686258632Savg			    depth + 1) != 0) {
4687185029Spjd				if (w->selconn == -1)
4688168404Spjd					w->selconn = i;
4689168404Spjd				w->pflags |= HDA_ADC_PATH;
4690168404Spjd				ret = 1;
4691185029Spjd			}
4692258632Savg		}
4693185029Spjd		break;
4694185029Spjd	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
4695272483Ssmh		conndev = w->wclass.pin.config &
4696185029Spjd		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4697185029Spjd		if (HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
4698185029Spjd		    (conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_CD ||
4699272483Ssmh		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN ||
4700185029Spjd		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN)) {
4701272483Ssmh			w->pflags |= HDA_ADC_PATH;
4702185029Spjd			ret = 1;
4703258632Savg		}
4704272483Ssmh		break;
4705185029Spjd	/*case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
4706185029Spjd		if (w->pflags & HDA_DAC_PATH) {
4707185029Spjd			w->pflags |= HDA_ADC_PATH;
4708185029Spjd			ret = 1;
4709185029Spjd		}
4710185029Spjd		break;*/
4711185029Spjd	default:
4712185029Spjd		break;
4713185029Spjd	}
4714185029Spjd	return (ret);
4715185029Spjd}
4716185029Spjd
4717272483Ssmhstatic uint32_t
4718249195Smmhdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo,
4719185029Spjd				nid_t nid, nid_t pnid, int index, int depth)
4720185029Spjd{
4721185029Spjd	struct hdac_widget *w, *pw;
4722185029Spjd	struct hdac_audio_ctl *ctl;
4723185029Spjd	uint32_t fl = 0;
4724185029Spjd	int i, ossdev, conndev, strategy;
4725249195Smm
4726185029Spjd	if (depth > HDA_PARSE_MAXDEPTH)
4727185029Spjd		return (0);
4728185029Spjd
4729185029Spjd	w = hdac_widget_get(devinfo, nid);
4730185029Spjd	if (w == NULL || w->enable == 0)
4731185029Spjd		return (0);
4732168404Spjd
4733185029Spjd	pw = hdac_widget_get(devinfo, pnid);
4734168404Spjd	strategy = devinfo->function.audio.parsing_strategy;
4735185029Spjd
4736168404Spjd	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER
4737168404Spjd	    || w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) {
4738168404Spjd		for (i = 0; i < w->nconns; i++) {
4739168404Spjd			fl |= hdac_audio_ctl_outamp_build(devinfo, w->conns[i],
4740185029Spjd			    w->nid, i, depth + 1);
4741168404Spjd		}
4742185029Spjd		w->ctlflags |= fl;
4743209962Smm		return (fl);
4744185029Spjd	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT &&
4745272483Ssmh	    (w->pflags & HDA_DAC_PATH)) {
4746185029Spjd		i = 0;
4747272483Ssmh		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4748272483Ssmh			if (ctl->enable == 0 || ctl->widget == NULL)
4749185029Spjd				continue;
4750249195Smm			/* XXX This should be compressed! */
4751168404Spjd			if (((ctl->widget->nid == w->nid) ||
4752168404Spjd			    (ctl->widget->nid == pnid && ctl->index == index &&
4753209962Smm			    (ctl->dir & HDA_CTL_IN)) ||
4754209962Smm			    (ctl->widget->nid == pnid && pw != NULL &&
4755209962Smm			    pw->type ==
4756209962Smm			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4757209962Smm			    (pw->nconns < 2 || pw->selconn == index ||
4758209962Smm			    pw->selconn == -1) &&
4759209962Smm			    (ctl->dir & HDA_CTL_OUT)) ||
4760185029Spjd			    (strategy == HDA_PARSE_DIRECT &&
4761251631Sdelphij			    ctl->widget->nid == w->nid)) &&
4762185029Spjd			    !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
4763185029Spjd				/*if (pw != NULL && pw->selconn == -1)
4764258632Savg					pw->selconn = index;
4765258632Savg				fl |= SOUND_MASK_VOLUME;
4766185029Spjd				fl |= SOUND_MASK_PCM;
4767185029Spjd				ctl->ossmask |= SOUND_MASK_VOLUME;
4768185029Spjd				ctl->ossmask |= SOUND_MASK_PCM;
4769168404Spjd				ctl->ossdev = SOUND_MIXER_PCM;*/
4770168404Spjd				if (!(w->ctlflags & SOUND_MASK_PCM) ||
4771168404Spjd				    (pw != NULL &&
4772168404Spjd				    !(pw->ctlflags & SOUND_MASK_PCM))) {
4773168404Spjd					fl |= SOUND_MASK_VOLUME;
4774168404Spjd					fl |= SOUND_MASK_PCM;
4775209962Smm					ctl->ossmask |= SOUND_MASK_VOLUME;
4776209962Smm					ctl->ossmask |= SOUND_MASK_PCM;
4777209962Smm					ctl->ossdev = SOUND_MIXER_PCM;
4778185029Spjd					w->ctlflags |= SOUND_MASK_VOLUME;
4779185029Spjd					w->ctlflags |= SOUND_MASK_PCM;
4780185029Spjd					if (pw != NULL) {
4781185029Spjd						if (pw->selconn == -1)
4782185029Spjd							pw->selconn = index;
4783185029Spjd						pw->ctlflags |=
4784249195Smm						    SOUND_MASK_VOLUME;
4785168404Spjd						pw->ctlflags |=
4786185029Spjd						    SOUND_MASK_PCM;
4787168404Spjd					}
4788168404Spjd				}
4789168404Spjd			}
4790286626Smav		}
4791286626Smav		w->ctlflags |= fl;
4792286626Smav		return (fl);
4793286626Smav	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4794286626Smav	    HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
4795286626Smav	    (w->pflags & HDA_ADC_PATH)) {
4796286626Smav		conndev = w->wclass.pin.config &
4797286626Smav		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4798286626Smav		i = 0;
4799286626Smav		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4800286626Smav			if (ctl->enable == 0 || ctl->widget == NULL)
4801286626Smav				continue;
4802286626Smav			/* XXX This should be compressed! */
4803286626Smav			if (((ctl->widget->nid == pnid && ctl->index == index &&
4804286626Smav			    (ctl->dir & HDA_CTL_IN)) ||
4805286626Smav			    (ctl->widget->nid == pnid && pw != NULL &&
4806286626Smav			    pw->type ==
4807286626Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4808286626Smav			    (pw->nconns < 2 || pw->selconn == index ||
4809286626Smav			    pw->selconn == -1) &&
4810286626Smav			    (ctl->dir & HDA_CTL_OUT)) ||
4811286626Smav			    (strategy == HDA_PARSE_DIRECT &&
4812286626Smav			    ctl->widget->nid == w->nid)) &&
4813286626Smav			    !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
4814286626Smav				if (pw != NULL && pw->selconn == -1)
4815286626Smav					pw->selconn = index;
4816286626Smav				ossdev = 0;
4817286626Smav				switch (conndev) {
4818286626Smav				case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
4819286626Smav					ossdev = SOUND_MIXER_MIC;
4820286626Smav					break;
4821286626Smav				case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
4822286626Smav					ossdev = SOUND_MIXER_LINE;
4823286626Smav					break;
4824286626Smav				case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
4825286626Smav					ossdev = SOUND_MIXER_CD;
4826286626Smav					break;
4827286626Smav				default:
4828286626Smav					ossdev =
4829286626Smav					    hdac_audio_ctl_ossmixer_getnextdev(
4830286626Smav					    devinfo);
4831286626Smav					if (ossdev < 0)
4832168404Spjd						ossdev = 0;
4833168566Spjd					break;
4834168404Spjd				}
4835168404Spjd				if (strategy == HDA_PARSE_MIXER) {
4836168566Spjd					fl |= SOUND_MASK_VOLUME;
4837168404Spjd					ctl->ossmask |= SOUND_MASK_VOLUME;
4838168404Spjd				}
4839219089Spjd				fl |= 1 << ossdev;
4840286625Smav				ctl->ossmask |= 1 << ossdev;
4841286625Smav				ctl->ossdev = ossdev;
4842272483Ssmh			}
4843168404Spjd		}
4844241773Savg		w->ctlflags |= fl;
4845241773Savg		return (fl);
4846241773Savg	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
4847241773Savg		i = 0;
4848241773Savg		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4849241773Savg			if (ctl->enable == 0 || ctl->widget == NULL)
4850286623Smav				continue;
4851286623Smav			/* XXX This should be compressed! */
4852219089Spjd			if (((ctl->widget->nid == pnid && ctl->index == index &&
4853168404Spjd			    (ctl->dir & HDA_CTL_IN)) ||
4854168404Spjd			    (ctl->widget->nid == pnid && pw != NULL &&
4855168404Spjd			    pw->type ==
4856168404Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4857168404Spjd			    (pw->nconns < 2 || pw->selconn == index ||
4858168404Spjd			    pw->selconn == -1) &&
4859219089Spjd			    (ctl->dir & HDA_CTL_OUT)) ||
4860205231Skmacy			    (strategy == HDA_PARSE_DIRECT &&
4861168404Spjd			    ctl->widget->nid == w->nid)) &&
4862168404Spjd			    !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
4863168404Spjd				if (pw != NULL && pw->selconn == -1)
4864168404Spjd					pw->selconn = index;
4865168404Spjd				fl |= SOUND_MASK_VOLUME;
4866168404Spjd				fl |= SOUND_MASK_SPEAKER;
4867168404Spjd				ctl->ossmask |= SOUND_MASK_VOLUME;
4868168566Spjd				ctl->ossmask |= SOUND_MASK_SPEAKER;
4869219089Spjd				ctl->ossdev = SOUND_MIXER_SPEAKER;
4870277300Ssmh			}
4871192360Skmacy		}
4872192360Skmacy		w->ctlflags |= fl;
4873192360Skmacy		return (fl);
4874192360Skmacy	}
4875192360Skmacy	return (0);
4876192360Skmacy}
4877192360Skmacy
4878192360Skmacystatic uint32_t
4879277300Ssmhhdac_audio_ctl_inamp_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4880168566Spjd{
4881280822Smav	struct hdac_widget *w, *cw;
4882168566Spjd	struct hdac_audio_ctl *ctl;
4883280822Smav	uint32_t fl;
4884280822Smav	int i;
4885168404Spjd
4886168404Spjd	if (depth > HDA_PARSE_MAXDEPTH)
4887175633Spjd		return (0);
4888219089Spjd
4889168481Spjd	w = hdac_widget_get(devinfo, nid);
4890168404Spjd	if (w == NULL || w->enable == 0)
4891168404Spjd		return (0);
4892168566Spjd	/*if (!(w->pflags & HDA_ADC_PATH))
4893168404Spjd		return (0);
4894280822Smav	if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
4895168404Spjd	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4896280822Smav		return (0);*/
4897168404Spjd	i = 0;
4898168481Spjd	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4899219089Spjd		if (ctl->enable == 0 || ctl->widget == NULL)
4900168404Spjd			continue;
4901168404Spjd		if (ctl->widget->nid == nid) {
4902168404Spjd			ctl->ossmask |= SOUND_MASK_RECLEV;
4903185029Spjd			w->ctlflags |= SOUND_MASK_RECLEV;
4904185029Spjd			return (SOUND_MASK_RECLEV);
4905185029Spjd		}
4906185029Spjd	}
4907185029Spjd	for (i = 0; i < w->nconns; i++) {
4908185029Spjd		cw = hdac_widget_get(devinfo, w->conns[i]);
4909185029Spjd		if (cw == NULL || cw->enable == 0)
4910185029Spjd			continue;
4911185029Spjd		if (cw->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
4912185029Spjd			continue;
4913275780Sdelphij		fl = hdac_audio_ctl_inamp_build(devinfo, cw->nid, depth + 1);
4914275780Sdelphij		if (fl != 0) {
4915275780Sdelphij			cw->ctlflags |= fl;
4916275780Sdelphij			w->ctlflags |= fl;
4917275780Sdelphij			return (fl);
4918275780Sdelphij		}
4919208373Smm	}
4920208373Smm	return (0);
4921208373Smm}
4922208373Smm
4923208373Smmstatic int
4924208373Smmhdac_audio_ctl_recsel_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4925286625Smav{
4926286625Smav	struct hdac_widget *w, *cw;
4927286625Smav	int i, child = 0;
4928286625Smav
4929286625Smav	if (depth > HDA_PARSE_MAXDEPTH)
4930286625Smav		return (0);
4931208373Smm
4932208373Smm	w = hdac_widget_get(devinfo, nid);
4933208373Smm	if (w == NULL || w->enable == 0)
4934168404Spjd		return (0);
4935168404Spjd	/*if (!(w->pflags & HDA_ADC_PATH))
4936168404Spjd		return (0);
4937168404Spjd	if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
4938168404Spjd	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4939168404Spjd		return (0);*/
4940168473Spjd	/* XXX weak! */
4941168473Spjd	for (i = 0; i < w->nconns; i++) {
4942168473Spjd		cw = hdac_widget_get(devinfo, w->conns[i]);
4943168404Spjd		if (cw == NULL)
4944168404Spjd			continue;
4945168404Spjd		if (++child > 1) {
4946168404Spjd			w->pflags |= HDA_ADC_RECSEL;
4947168404Spjd			return (1);
4948185029Spjd		}
4949168404Spjd	}
4950168404Spjd	for (i = 0; i < w->nconns; i++) {
4951205231Skmacy		if (hdac_audio_ctl_recsel_build(devinfo,
4952205231Skmacy		    w->conns[i], depth + 1) != 0)
4953205231Skmacy			return (1);
4954205231Skmacy	}
4955205231Skmacy	return (0);
4956205231Skmacy}
4957205231Skmacy
4958205231Skmacystatic int
4959205231Skmacyhdac_audio_build_tree_strategy(struct hdac_devinfo *devinfo)
4960205231Skmacy{
4961205231Skmacy	struct hdac_widget *w, *cw;
4962205231Skmacy	int i, j, conndev, found_dac = 0;
4963205231Skmacy	int strategy;
4964206796Spjd
4965205231Skmacy	strategy = devinfo->function.audio.parsing_strategy;
4966286570Smav
4967286570Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4968205231Skmacy		w = hdac_widget_get(devinfo, i);
4969286570Smav		if (w == NULL || w->enable == 0)
4970286570Smav			continue;
4971205231Skmacy		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4972286570Smav			continue;
4973286570Smav		if (!HDA_PARAM_PIN_CAP_OUTPUT_CAP(w->wclass.pin.cap))
4974205231Skmacy			continue;
4975286570Smav		conndev = w->wclass.pin.config &
4976286570Smav		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4977205231Skmacy		if (!(conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
4978286570Smav		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
4979286570Smav		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT))
4980205231Skmacy			continue;
4981286570Smav		for (j = 0; j < w->nconns; j++) {
4982286570Smav			cw = hdac_widget_get(devinfo, w->conns[j]);
4983205231Skmacy			if (cw == NULL || cw->enable == 0)
4984168404Spjd				continue;
4985168404Spjd			if (strategy == HDA_PARSE_MIXER && !(cw->type ==
4986168404Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
4987168404Spjd			    cw->type ==
4988168404Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4989168404Spjd				continue;
4990168404Spjd			if (hdac_widget_find_dac_path(devinfo, cw->nid, 0)
4991168404Spjd			    != 0) {
4992168404Spjd				if (w->selconn == -1)
4993168404Spjd					w->selconn = j;
4994168404Spjd				w->pflags |= HDA_DAC_PATH;
4995168404Spjd				found_dac++;
4996168404Spjd			}
4997286574Smav		}
4998168404Spjd	}
4999168404Spjd
5000168404Spjd	return (found_dac);
5001168404Spjd}
5002168404Spjd
5003168404Spjdstatic void
5004168404Spjdhdac_audio_build_tree(struct hdac_devinfo *devinfo)
5005168566Spjd{
5006168404Spjd	struct hdac_widget *w;
5007168404Spjd	struct hdac_audio_ctl *ctl;
5008168404Spjd	int i, j, dacs, strategy;
5009168404Spjd
5010185029Spjd	/* Construct DAC path */
5011168566Spjd	strategy = HDA_PARSE_MIXER;
5012258632Savg	devinfo->function.audio.parsing_strategy = strategy;
5013258632Savg	HDA_BOOTVERBOSE(
5014258632Savg		device_printf(devinfo->codec->sc->dev,
5015258632Savg		    "HDA_DEBUG: HWiP: HDA Widget Parser - Revision %d\n",
5016258632Savg		    HDA_WIDGET_PARSER_REV);
5017258632Savg	);
5018258632Savg	dacs = hdac_audio_build_tree_strategy(devinfo);
5019258632Savg	if (dacs == 0) {
5020258632Savg		HDA_BOOTVERBOSE(
5021258632Savg			device_printf(devinfo->codec->sc->dev,
5022258632Savg			    "HDA_DEBUG: HWiP: 0 DAC path found! "
5023258632Savg			    "Retrying parser "
5024258632Savg			    "using HDA_PARSE_DIRECT strategy.\n");
5025258632Savg		);
5026185029Spjd		strategy = HDA_PARSE_DIRECT;
5027168566Spjd		devinfo->function.audio.parsing_strategy = strategy;
5028194043Skmacy		dacs = hdac_audio_build_tree_strategy(devinfo);
5029193953Skmacy	}
5030206796Spjd
5031193878Skmacy	HDA_BOOTVERBOSE(
5032193953Skmacy		device_printf(devinfo->codec->sc->dev,
5033196863Strasz		    "HDA_DEBUG: HWiP: Found %d DAC path using HDA_PARSE_%s "
5034196863Strasz		    "strategy.\n",
5035196863Strasz		    dacs, (strategy == HDA_PARSE_MIXER) ? "MIXER" : "DIRECT");
5036196863Strasz	);
5037219089Spjd
5038193878Skmacy	/* Construct ADC path */
5039206796Spjd	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5040193878Skmacy		w = hdac_widget_get(devinfo, i);
5041193953Skmacy		if (w == NULL || w->enable == 0)
5042196863Strasz			continue;
5043196941Strasz		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
5044196863Strasz			continue;
5045196863Strasz		(void)hdac_widget_find_adc_path(devinfo, w->nid, 0);
5046219089Spjd	}
5047193878Skmacy
5048206796Spjd	/* Output mixers */
5049175633Spjd	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5050168696Spjd		w = hdac_widget_get(devinfo, i);
5051168987Sbmah		if (w == NULL || w->enable == 0)
5052168987Sbmah			continue;
5053175633Spjd		if ((strategy == HDA_PARSE_MIXER &&
5054175633Spjd		    (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
5055173419Spjd		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
5056168987Sbmah		    && (w->pflags & HDA_DAC_PATH)) ||
5057185029Spjd		    (strategy == HDA_PARSE_DIRECT && (w->pflags &
5058173419Spjd		    (HDA_DAC_PATH | HDA_ADC_PATH)))) {
5059185029Spjd			w->ctlflags |= hdac_audio_ctl_outamp_build(devinfo,
5060168566Spjd			    w->nid, devinfo->startnode - 1, 0, 0);
5061168566Spjd		} else if (w->type ==
5062168404Spjd		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
5063168404Spjd			j = 0;
5064168404Spjd			while ((ctl = hdac_audio_ctl_each(devinfo, &j)) !=
5065168404Spjd			    NULL) {
5066168404Spjd				if (ctl->enable == 0 || ctl->widget == NULL)
5067205231Skmacy					continue;
5068206796Spjd				if (ctl->widget->nid != w->nid)
5069168404Spjd					continue;
5070168404Spjd				ctl->ossmask |= SOUND_MASK_VOLUME;
5071168404Spjd				ctl->ossmask |= SOUND_MASK_SPEAKER;
5072168404Spjd				ctl->ossdev = SOUND_MIXER_SPEAKER;
5073168404Spjd				w->ctlflags |= SOUND_MASK_VOLUME;
5074168404Spjd				w->ctlflags |= SOUND_MASK_SPEAKER;
5075168404Spjd			}
5076185029Spjd		}
5077168404Spjd	}
5078168404Spjd
5079168404Spjd	/* Input mixers (rec) */
5080168404Spjd	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5081168404Spjd		w = hdac_widget_get(devinfo, i);
5082168404Spjd		if (w == NULL || w->enable == 0)
5083168404Spjd			continue;
5084168404Spjd		if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
5085168404Spjd		    w->pflags & HDA_ADC_PATH))
5086168404Spjd			continue;
5087168404Spjd		hdac_audio_ctl_inamp_build(devinfo, w->nid, 0);
5088168404Spjd		hdac_audio_ctl_recsel_build(devinfo, w->nid, 0);
5089205231Skmacy	}
5090205231Skmacy}
5091205231Skmacy
5092205231Skmacy#define HDA_COMMIT_CONN	(1 << 0)
5093205231Skmacy#define HDA_COMMIT_CTRL	(1 << 1)
5094206795Spjd#define HDA_COMMIT_EAPD	(1 << 2)
5095168404Spjd#define HDA_COMMIT_GPIO	(1 << 3)
5096205231Skmacy#define HDA_COMMIT_MISC	(1 << 4)
5097205231Skmacy#define HDA_COMMIT_ALL	(HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \
5098205231Skmacy			HDA_COMMIT_EAPD | HDA_COMMIT_GPIO | HDA_COMMIT_MISC)
5099205231Skmacy
5100205231Skmacystatic void
5101206795Spjdhdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl)
5102205231Skmacy{
5103206796Spjd	struct hdac_softc *sc = devinfo->codec->sc;
5104168404Spjd	struct hdac_widget *w;
5105168404Spjd	nid_t cad;
5106286570Smav	int i;
5107209962Smm
5108168404Spjd	if (!(cfl & HDA_COMMIT_ALL))
5109168566Spjd		return;
5110168566Spjd
5111168404Spjd	cad = devinfo->codec->cad;
5112168404Spjd
5113185029Spjd	if ((cfl & HDA_COMMIT_MISC)) {
5114185029Spjd		if (sc->pci_subvendor == APPLE_INTEL_MAC)
5115185029Spjd			hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
5116185029Spjd			    0x7e7, 0), cad);
5117185029Spjd	}
5118185029Spjd
5119185029Spjd	if (cfl & HDA_COMMIT_GPIO) {
5120185029Spjd		uint32_t gdata, gmask, gdir;
5121185029Spjd		int commitgpio, numgpio;
5122185029Spjd
5123185029Spjd		gdata = 0;
5124185029Spjd		gmask = 0;
5125185029Spjd		gdir = 0;
5126185029Spjd		commitgpio = 0;
5127185029Spjd
5128185029Spjd		numgpio = HDA_PARAM_GPIO_COUNT_NUM_GPIO(
5129185029Spjd		    devinfo->function.audio.gpio);
5130185029Spjd
5131185029Spjd		if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
5132185029Spjd			commitgpio = (numgpio > 0) ? 1 : 0;
5133185029Spjd		else {
5134185029Spjd			for (i = 0; i < numgpio && i < HDA_GPIO_MAX; i++) {
5135185029Spjd				if (!(devinfo->function.audio.quirks &
5136185029Spjd				    (1 << i)))
5137185029Spjd					continue;
5138185029Spjd				if (commitgpio == 0) {
5139185029Spjd					commitgpio = 1;
5140185029Spjd					HDA_BOOTVERBOSE(
5141185029Spjd						gdata = hdac_command(sc,
5142185029Spjd						    HDA_CMD_GET_GPIO_DATA(cad,
5143185029Spjd						    devinfo->nid), cad);
5144185029Spjd						gmask = hdac_command(sc,
5145185029Spjd						    HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
5146185029Spjd						    devinfo->nid), cad);
5147185029Spjd						gdir = hdac_command(sc,
5148185029Spjd						    HDA_CMD_GET_GPIO_DIRECTION(cad,
5149185029Spjd						    devinfo->nid), cad);
5150185029Spjd						device_printf(sc->dev,
5151185029Spjd						    "GPIO init: data=0x%08x "
5152185029Spjd						    "mask=0x%08x dir=0x%08x\n",
5153185029Spjd						    gdata, gmask, gdir);
5154185029Spjd						gdata = 0;
5155185029Spjd						gmask = 0;
5156185029Spjd						gdir = 0;
5157185029Spjd					);
5158185029Spjd				}
5159185029Spjd				gdata |= 1 << i;
5160185029Spjd				gmask |= 1 << i;
5161185029Spjd				gdir |= 1 << i;
5162185029Spjd			}
5163185029Spjd		}
5164185029Spjd
5165185029Spjd		if (commitgpio != 0) {
5166185029Spjd			HDA_BOOTVERBOSE(
5167185029Spjd				device_printf(sc->dev,
5168185029Spjd				    "GPIO commit: data=0x%08x mask=0x%08x "
5169251478Sdelphij				    "dir=0x%08x\n",
5170251478Sdelphij				    gdata, gmask, gdir);
5171251478Sdelphij			);
5172251478Sdelphij			hdac_command(sc,
5173251478Sdelphij			    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
5174251478Sdelphij			    gmask), cad);
5175185029Spjd			hdac_command(sc,
5176185029Spjd			    HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
5177185029Spjd			    gdir), cad);
5178185029Spjd			hdac_command(sc,
5179185029Spjd			    HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
5180185029Spjd			    gdata), cad);
5181185029Spjd		}
5182185029Spjd	}
5183185029Spjd
5184185029Spjd	for (i = 0; i < devinfo->nodecnt; i++) {
5185185029Spjd		w = &devinfo->widget[i];
5186185029Spjd		if (w == NULL || w->enable == 0)
5187185029Spjd			continue;
5188185029Spjd		if (cfl & HDA_COMMIT_CONN) {
5189185029Spjd			if (w->selconn == -1)
5190185029Spjd				w->selconn = 0;
5191185029Spjd			if (w->nconns > 0)
5192185029Spjd				hdac_widget_connection_select(w, w->selconn);
5193185029Spjd		}
5194185029Spjd		if ((cfl & HDA_COMMIT_CTRL) &&
5195185029Spjd		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
5196185029Spjd		    	uint32_t pincap;
5197185029Spjd
5198185029Spjd			pincap = w->wclass.pin.cap;
5199185029Spjd
5200185029Spjd			if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) ==
5201185029Spjd			    (HDA_DAC_PATH | HDA_ADC_PATH))
5202185029Spjd				device_printf(sc->dev, "WARNING: node %d "
5203185029Spjd				    "participate both for DAC/ADC!\n", w->nid);
5204185029Spjd			if (w->pflags & HDA_DAC_PATH) {
5205185029Spjd				w->wclass.pin.ctrl &=
5206185029Spjd				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
5207185029Spjd				if ((w->wclass.pin.config &
5208185029Spjd				    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) !=
5209185029Spjd				    HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
5210185029Spjd					w->wclass.pin.ctrl &=
5211185029Spjd					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
5212185029Spjd				if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF100) &&
5213185029Spjd				    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5214185029Spjd					w->wclass.pin.ctrl |=
5215185029Spjd					    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5216185029Spjd					    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
5217185029Spjd				else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF80) &&
5218185029Spjd				    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5219185029Spjd					w->wclass.pin.ctrl |=
5220185029Spjd					    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5221185029Spjd					    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
5222185029Spjd				else if ((devinfo->function.audio.quirks & HDA_QUIRK_OVREF50) &&
5223185029Spjd				    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5224185029Spjd					w->wclass.pin.ctrl |=
5225185029Spjd					    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5226185029Spjd					    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
5227185029Spjd			} else if (w->pflags & HDA_ADC_PATH) {
5228185029Spjd				w->wclass.pin.ctrl &=
5229185029Spjd				    ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
5230185029Spjd				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE);
5231185029Spjd				if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF100) &&
5232185029Spjd				    HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5233185029Spjd					w->wclass.pin.ctrl |=
5234185029Spjd					    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5235185029Spjd					    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100);
5236185029Spjd				else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF80) &&
5237185029Spjd				    HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5238185029Spjd					w->wclass.pin.ctrl |=
5239251478Sdelphij					    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5240251478Sdelphij					    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80);
5241251478Sdelphij				else if ((devinfo->function.audio.quirks & HDA_QUIRK_IVREF50) &&
5242251478Sdelphij				    HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5243251478Sdelphij					w->wclass.pin.ctrl |=
5244185029Spjd					    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
5245185029Spjd					    HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50);
5246185029Spjd			} else
5247185029Spjd				w->wclass.pin.ctrl &= ~(
5248208373Smm				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
5249208373Smm				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
5250208373Smm				    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
5251208373Smm				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
5252208373Smm			hdac_command(sc,
5253208373Smm			    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
5254208373Smm			    w->wclass.pin.ctrl), cad);
5255208373Smm		}
5256208373Smm		if ((cfl & HDA_COMMIT_EAPD) &&
5257185029Spjd		    w->param.eapdbtl != HDAC_INVALID) {
5258185029Spjd		    	uint32_t val;
5259208373Smm
5260275811Sdelphij			val = w->param.eapdbtl;
5261208373Smm			if (devinfo->function.audio.quirks &
5262208373Smm			    HDA_QUIRK_EAPDINV)
5263208373Smm				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
5264208373Smm			hdac_command(sc,
5265208373Smm			    HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid,
5266208373Smm			    val), cad);
5267208373Smm
5268208373Smm		}
5269275811Sdelphij		DELAY(1000);
5270208373Smm	}
5271208373Smm}
5272208373Smm
5273286570Smavstatic void
5274208373Smmhdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
5275208373Smm{
5276208373Smm	struct hdac_softc *sc = devinfo->codec->sc;
5277275811Sdelphij	struct hdac_audio_ctl *ctl;
5278208373Smm	int i;
5279208373Smm
5280208373Smm	devinfo->function.audio.mvol = 100 | (100 << 8);
5281275811Sdelphij	i = 0;
5282208373Smm	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5283208373Smm		if (ctl->enable == 0 || ctl->widget == NULL) {
5284208373Smm			HDA_BOOTVERBOSE(
5285208373Smm				device_printf(sc->dev, "[%2d] Ctl nid=%d",
5286208373Smm				    i, (ctl->widget != NULL) ?
5287208373Smm				    ctl->widget->nid : -1);
5288208373Smm				if (ctl->childwidget != NULL)
5289208373Smm					printf(" childnid=%d",
5290251478Sdelphij					    ctl->childwidget->nid);
5291208373Smm				if (ctl->widget == NULL)
5292208373Smm					printf(" NULL WIDGET!");
5293208373Smm				printf(" DISABLED\n");
5294251478Sdelphij			);
5295251478Sdelphij			continue;
5296251478Sdelphij		}
5297251478Sdelphij		HDA_BOOTVERBOSE(
5298251478Sdelphij			if (ctl->ossmask == 0) {
5299251478Sdelphij				device_printf(sc->dev, "[%2d] Ctl nid=%d",
5300251478Sdelphij				    i, ctl->widget->nid);
5301251478Sdelphij				if (ctl->childwidget != NULL)
5302251478Sdelphij					printf(" childnid=%d",
5303251478Sdelphij					ctl->childwidget->nid);
5304251478Sdelphij				printf(" Bind to NONE\n");
5305208373Smm			}
5306208373Smm		);
5307251478Sdelphij		if (ctl->step > 0) {
5308208373Smm			ctl->ossval = (ctl->left * 100) / ctl->step;
5309208373Smm			ctl->ossval |= ((ctl->right * 100) / ctl->step) << 8;
5310208373Smm		} else
5311208373Smm			ctl->ossval = 0;
5312208373Smm		hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT,
5313208373Smm		    ctl->left, ctl->right);
5314208373Smm	}
5315208373Smm}
5316219089Spjd
5317208373Smmstatic int
5318208373Smmhdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
5319208373Smm{
5320208373Smm	struct hdac_chan *ch;
5321208373Smm	struct hdac_widget *w;
5322208373Smm	uint32_t cap, fmtcap, pcmcap, path;
5323208373Smm	int i, type, ret, max;
5324208373Smm
5325208373Smm	if (dir == PCMDIR_PLAY) {
5326208373Smm		type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT;
5327208373Smm		ch = &devinfo->codec->sc->play;
5328208373Smm		path = HDA_DAC_PATH;
5329219089Spjd	} else {
5330219089Spjd		type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT;
5331208373Smm		ch = &devinfo->codec->sc->rec;
5332208373Smm		path = HDA_ADC_PATH;
5333208373Smm	}
5334208373Smm
5335185029Spjd	ch->caps = hdac_caps;
5336185029Spjd	ch->caps.fmtlist = ch->fmtlist;
5337185029Spjd	ch->bit16 = 1;
5338185029Spjd	ch->bit32 = 0;
5339185029Spjd	ch->pcmrates[0] = 48000;
5340185029Spjd	ch->pcmrates[1] = 0;
5341185029Spjd
5342185029Spjd	ret = 0;
5343185029Spjd	fmtcap = devinfo->function.audio.supp_stream_formats;
5344185029Spjd	pcmcap = devinfo->function.audio.supp_pcm_size_rate;
5345185029Spjd	max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1;
5346185029Spjd
5347185029Spjd	for (i = devinfo->startnode; i < devinfo->endnode && ret < max; i++) {
5348185029Spjd		w = hdac_widget_get(devinfo, i);
5349185029Spjd		if (w == NULL || w->enable == 0 || w->type != type ||
5350185029Spjd		    !(w->pflags & path))
5351185029Spjd			continue;
5352185029Spjd		cap = w->param.widget_cap;
5353185029Spjd		/*if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(cap))
5354185029Spjd			continue;*/
5355185029Spjd		if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(cap))
5356185029Spjd			continue;
5357185029Spjd		cap = w->param.supp_stream_formats;
5358185029Spjd		/*if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) {
5359185029Spjd		}
5360185029Spjd		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
5361185029Spjd		}*/
5362185029Spjd		if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
5363185029Spjd			continue;
5364185029Spjd		if (ret == 0) {
5365185029Spjd			fmtcap = w->param.supp_stream_formats;
5366185029Spjd			pcmcap = w->param.supp_pcm_size_rate;
5367185029Spjd		} else {
5368185029Spjd			fmtcap &= w->param.supp_stream_formats;
5369185029Spjd			pcmcap &= w->param.supp_pcm_size_rate;
5370185029Spjd		}
5371185029Spjd		ch->io[ret++] = i;
5372185029Spjd	}
5373185029Spjd	ch->io[ret] = -1;
5374185029Spjd
5375185029Spjd	ch->supp_stream_formats = fmtcap;
5376185029Spjd	ch->supp_pcm_size_rate = pcmcap;
5377185029Spjd
5378185029Spjd	/*
5379185029Spjd	 *  8bit = 0
5380185029Spjd	 * 16bit = 1
5381185029Spjd	 * 20bit = 2
5382185029Spjd	 * 24bit = 3
5383185029Spjd	 * 32bit = 4
5384185029Spjd	 */
5385185029Spjd	if (ret > 0) {
5386185029Spjd		cap = pcmcap;
5387185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
5388185029Spjd			ch->bit16 = 1;
5389185029Spjd		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
5390185029Spjd			ch->bit16 = 0;
5391185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
5392185029Spjd			ch->bit32 = 4;
5393185029Spjd		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
5394185029Spjd			ch->bit32 = 3;
5395185029Spjd		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
5396185029Spjd			ch->bit32 = 2;
5397185029Spjd		i = 0;
5398185029Spjd		if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
5399185029Spjd			ch->fmtlist[i++] = AFMT_S16_LE;
5400185029Spjd		ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
5401185029Spjd		if (ch->bit32 > 0) {
5402185029Spjd			if (!(devinfo->function.audio.quirks &
5403185029Spjd			    HDA_QUIRK_FORCESTEREO))
5404185029Spjd				ch->fmtlist[i++] = AFMT_S32_LE;
5405185029Spjd			ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
5406185029Spjd		}
5407185029Spjd		ch->fmtlist[i] = 0;
5408185029Spjd		i = 0;
5409185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
5410185029Spjd			ch->pcmrates[i++] = 8000;
5411185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
5412185029Spjd			ch->pcmrates[i++] = 11025;
5413185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
5414185029Spjd			ch->pcmrates[i++] = 16000;
5415185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
5416185029Spjd			ch->pcmrates[i++] = 22050;
5417185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
5418185029Spjd			ch->pcmrates[i++] = 32000;
5419185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
5420185029Spjd			ch->pcmrates[i++] = 44100;
5421185029Spjd		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(cap)) */
5422185029Spjd		ch->pcmrates[i++] = 48000;
5423185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
5424185029Spjd			ch->pcmrates[i++] = 88200;
5425185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
5426185029Spjd			ch->pcmrates[i++] = 96000;
5427185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
5428185029Spjd			ch->pcmrates[i++] = 176400;
5429185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
5430275811Sdelphij			ch->pcmrates[i++] = 192000;
5431185029Spjd		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(cap)) */
5432268085Sdelphij		ch->pcmrates[i] = 0;
5433185029Spjd		if (i > 0) {
5434185029Spjd			ch->caps.minspeed = ch->pcmrates[0];
5435185029Spjd			ch->caps.maxspeed = ch->pcmrates[i - 1];
5436185029Spjd		}
5437185029Spjd	}
5438185029Spjd
5439185029Spjd	return (ret);
5440286570Smav}
5441185029Spjd
5442185029Spjdstatic void
5443185029Spjdhdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag)
5444185029Spjd{
5445185029Spjd	struct hdac_audio_ctl *ctl;
5446185029Spjd	struct hdac_softc *sc = devinfo->codec->sc;
5447185029Spjd	int i;
5448286570Smav	uint32_t fl = 0;
5449185029Spjd
5450185029Spjd
5451185029Spjd	if (flag == 0) {
5452185029Spjd		fl = SOUND_MASK_VOLUME | SOUND_MASK_PCM |
5453275811Sdelphij		    SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
5454275811Sdelphij		    SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN;
5455185029Spjd	}
5456275811Sdelphij
5457185029Spjd	i = 0;
5458185029Spjd	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5459185029Spjd		if (ctl->enable == 0 || ctl->widget == NULL ||
5460286570Smav		    ctl->widget->enable == 0 || (ctl->ossmask &
5461185029Spjd		    (SOUND_MASK_SKIP | SOUND_MASK_DISABLE)))
5462185029Spjd			continue;
5463185029Spjd		if ((flag == 0 && (ctl->ossmask & ~fl)) ||
5464185029Spjd		    (flag != 0 && (ctl->ossmask & flag))) {
5465185029Spjd			if (banner != NULL) {
5466185029Spjd				device_printf(sc->dev, "\n");
5467286570Smav				device_printf(sc->dev, "%s\n", banner);
5468286570Smav			}
5469286570Smav			goto hdac_ctl_dump_it_all;
5470286570Smav		}
5471286570Smav	}
5472286570Smav
5473286570Smav	return;
5474286570Smav
5475286570Smavhdac_ctl_dump_it_all:
5476286570Smav	i = 0;
5477185029Spjd	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5478185029Spjd		if (ctl->enable == 0 || ctl->widget == NULL ||
5479185029Spjd		    ctl->widget->enable == 0)
5480185029Spjd			continue;
5481286570Smav		if (!((flag == 0 && (ctl->ossmask & ~fl)) ||
5482286570Smav		    (flag != 0 && (ctl->ossmask & flag))))
5483286570Smav			continue;
5484286570Smav		if (flag == 0) {
5485286570Smav			device_printf(sc->dev, "\n");
5486275811Sdelphij			device_printf(sc->dev, "Unknown Ctl (OSS: %s)\n",
5487286598Smav			    hdac_audio_ctl_ossmixer_mask2name(ctl->ossmask));
5488286598Smav		}
5489286598Smav		device_printf(sc->dev, "   |\n");
5490286598Smav		device_printf(sc->dev, "   +-  nid: %2d index: %2d ",
5491185029Spjd		    ctl->widget->nid, ctl->index);
5492185029Spjd		if (ctl->childwidget != NULL)
5493185029Spjd			printf("(nid: %2d) ", ctl->childwidget->nid);
5494185029Spjd		else
5495185029Spjd			printf("          ");
5496275811Sdelphij		printf("mute: %d step: %3d size: %3d off: %3d dir=0x%x ossmask=0x%08x\n",
5497185029Spjd		    ctl->mute, ctl->step, ctl->size, ctl->offset, ctl->dir,
5498185029Spjd		    ctl->ossmask);
5499185029Spjd	}
5500185029Spjd}
5501185029Spjd
5502185029Spjdstatic void
5503286570Smavhdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap)
5504286570Smav{
5505286570Smav	uint32_t cap;
5506185029Spjd
5507268085Sdelphij	cap = fcap;
5508268085Sdelphij	if (cap != 0) {
5509185029Spjd		device_printf(sc->dev, "     Stream cap: 0x%08x\n", cap);
5510185029Spjd		device_printf(sc->dev, "         Format:");
5511185029Spjd		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
5512185029Spjd			printf(" AC3");
5513185029Spjd		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
5514185029Spjd			printf(" FLOAT32");
5515185029Spjd		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
5516185029Spjd			printf(" PCM");
5517185029Spjd		printf("\n");
5518185029Spjd	}
5519185029Spjd	cap = pcmcap;
5520185029Spjd	if (cap != 0) {
5521185029Spjd		device_printf(sc->dev, "        PCM cap: 0x%08x\n", cap);
5522185029Spjd		device_printf(sc->dev, "       PCM size:");
5523185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
5524185029Spjd			printf(" 8");
5525185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
5526185029Spjd			printf(" 16");
5527185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
5528185029Spjd			printf(" 20");
5529185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
5530185029Spjd			printf(" 24");
5531185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
5532185029Spjd			printf(" 32");
5533185029Spjd		printf("\n");
5534185029Spjd		device_printf(sc->dev, "       PCM rate:");
5535185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
5536185029Spjd			printf(" 8");
5537219089Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
5538185029Spjd			printf(" 11");
5539219089Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
5540219089Spjd			printf(" 16");
5541185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
5542185029Spjd			printf(" 22");
5543251478Sdelphij		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
5544251478Sdelphij			printf(" 32");
5545251478Sdelphij		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
5546251478Sdelphij			printf(" 44");
5547251478Sdelphij		printf(" 48");
5548251478Sdelphij		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
5549251478Sdelphij			printf(" 88");
5550185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
5551185029Spjd			printf(" 96");
5552185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
5553185029Spjd			printf(" 176");
5554185029Spjd		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
5555185029Spjd			printf(" 192");
5556185029Spjd		printf("\n");
5557185029Spjd	}
5558185029Spjd}
5559185029Spjd
5560185029Spjdstatic void
5561185029Spjdhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
5562185029Spjd{
5563185029Spjd	uint32_t pincap, wcap;
5564185029Spjd
5565185029Spjd	pincap = w->wclass.pin.cap;
5566185029Spjd	wcap = w->param.widget_cap;
5567185029Spjd
5568249195Smm	device_printf(sc->dev, "        Pin cap: 0x%08x\n", pincap);
5569185029Spjd	device_printf(sc->dev, "                ");
5570185029Spjd	if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap))
5571185029Spjd		printf(" ISC");
5572185029Spjd	if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap))
5573185029Spjd		printf(" TRQD");
5574185029Spjd	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap))
5575185029Spjd		printf(" PDC");
5576185029Spjd	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
5577185029Spjd		printf(" HP");
5578209962Smm	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
5579209962Smm		printf(" OUT");
5580209962Smm	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
5581209962Smm		printf(" IN");
5582209962Smm	if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap))
5583209962Smm		printf(" BAL");
5584185029Spjd	if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) {
5585185029Spjd		printf(" VREF[");
5586209962Smm		if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
5587185029Spjd			printf(" 50");
5588185029Spjd		if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
5589185029Spjd			printf(" 80");
5590185029Spjd		if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
5591185029Spjd			printf(" 100");
5592185029Spjd		if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap))
5593185029Spjd			printf(" GROUND");
5594185029Spjd		if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap))
5595185029Spjd			printf(" HIZ");
5596185029Spjd		printf(" ]");
5597185029Spjd	}
5598185029Spjd	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap))
5599185029Spjd		printf(" EAPD");
5600185029Spjd	if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(wcap))
5601185029Spjd		printf(" : UNSOL");
5602185029Spjd	printf("\n");
5603185029Spjd	device_printf(sc->dev, "     Pin config: 0x%08x\n",
5604185029Spjd	    w->wclass.pin.config);
5605247187Smm	device_printf(sc->dev, "    Pin control: 0x%08x", w->wclass.pin.ctrl);
5606205231Skmacy	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE)
5607185029Spjd		printf(" HP");
5608206796Spjd	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE)
5609206796Spjd		printf(" IN");
5610205231Skmacy	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
5611205231Skmacy		printf(" OUT");
5612205231Skmacy	printf("\n");
5613205231Skmacy}
5614206796Spjd
5615205231Skmacystatic void
5616205231Skmacyhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
5617205231Skmacy{
5618206796Spjd	device_printf(sc->dev, "     %s amp: 0x%08x\n", banner, cap);
5619205231Skmacy	device_printf(sc->dev, "                 "
5620205231Skmacy	    "mute=%d step=%d size=%d offset=%d\n",
5621205231Skmacy	    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap),
5622205231Skmacy	    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap),
5623205231Skmacy	    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap),
5624205231Skmacy	    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap));
5625205231Skmacy}
5626205231Skmacy
5627185029Spjdstatic void
5628185029Spjdhdac_dump_nodes(struct hdac_devinfo *devinfo)
5629185029Spjd{
5630185029Spjd	struct hdac_softc *sc = devinfo->codec->sc;
5631185029Spjd	struct hdac_widget *w, *cw;
5632185029Spjd	int i, j;
5633185029Spjd
5634185029Spjd	device_printf(sc->dev, "\n");
5635185029Spjd	device_printf(sc->dev, "Default Parameter\n");
5636185029Spjd	device_printf(sc->dev, "-----------------\n");
5637185029Spjd	hdac_dump_audio_formats(sc,
5638185029Spjd	    devinfo->function.audio.supp_stream_formats,
5639185029Spjd	    devinfo->function.audio.supp_pcm_size_rate);
5640185029Spjd	device_printf(sc->dev, "         IN amp: 0x%08x\n",
5641185029Spjd	    devinfo->function.audio.inamp_cap);
5642185029Spjd	device_printf(sc->dev, "        OUT amp: 0x%08x\n",
5643185029Spjd	    devinfo->function.audio.outamp_cap);
5644275811Sdelphij	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5645185029Spjd		w = hdac_widget_get(devinfo, i);
5646185029Spjd		if (w == NULL) {
5647185029Spjd			device_printf(sc->dev, "Ghost widget nid=%d\n", i);
5648286570Smav			continue;
5649185029Spjd		}
5650185029Spjd		device_printf(sc->dev, "\n");
5651185029Spjd		device_printf(sc->dev, "            nid: %d [%s]%s\n", w->nid,
5652185029Spjd		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap) ?
5653185029Spjd		    "DIGITAL" : "ANALOG",
5654185029Spjd		    (w->enable == 0) ? " [DISABLED]" : "");
5655185029Spjd		device_printf(sc->dev, "           name: %s\n", w->name);
5656185029Spjd		device_printf(sc->dev, "     widget_cap: 0x%08x\n",
5657185029Spjd		    w->param.widget_cap);
5658185029Spjd		device_printf(sc->dev, "    Parse flags: 0x%08x\n",
5659185029Spjd		    w->pflags);
5660185029Spjd		device_printf(sc->dev, "      Ctl flags: 0x%08x\n",
5661185029Spjd		    w->ctlflags);
5662185029Spjd		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
5663185029Spjd		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
5664185029Spjd			hdac_dump_audio_formats(sc,
5665185029Spjd			    w->param.supp_stream_formats,
5666185029Spjd			    w->param.supp_pcm_size_rate);
5667185029Spjd		} else if (w->type ==
5668185029Spjd		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5669185029Spjd			hdac_dump_pin(sc, w);
5670185029Spjd		if (w->param.eapdbtl != HDAC_INVALID)
5671286570Smav			device_printf(sc->dev, "           EAPD: 0x%08x\n",
5672275811Sdelphij			    w->param.eapdbtl);
5673275811Sdelphij		if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) &&
5674185029Spjd		    w->param.outamp_cap != 0)
5675275811Sdelphij			hdac_dump_amp(sc, w->param.outamp_cap, "Output");
5676185029Spjd		if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) &&
5677185029Spjd		    w->param.inamp_cap != 0)
5678185029Spjd			hdac_dump_amp(sc, w->param.inamp_cap, " Input");
5679185029Spjd		device_printf(sc->dev, "    connections: %d\n", w->nconns);
5680185029Spjd		for (j = 0; j < w->nconns; j++) {
5681286570Smav			cw = hdac_widget_get(devinfo, w->conns[j]);
5682185029Spjd			device_printf(sc->dev, "          |\n");
5683185029Spjd			device_printf(sc->dev, "          + <- nid=%d [%s]",
5684185029Spjd			    w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
5685185029Spjd			if (cw == NULL)
5686185029Spjd				printf(" [UNKNOWN]");
5687275811Sdelphij			else if (cw->enable == 0)
5688185029Spjd				printf(" [DISABLED]");
5689185029Spjd			if (w->nconns > 1 && w->selconn == j && w->type !=
5690185029Spjd			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
5691185029Spjd				printf(" (selected)");
5692275811Sdelphij			printf("\n");
5693185029Spjd		}
5694185029Spjd	}
5695185029Spjd
5696185029Spjd}
5697286570Smav
5698286570Smavstatic int
5699286570Smavhdac_dump_dac_internal(struct hdac_devinfo *devinfo, nid_t nid, int depth)
5700185029Spjd{
5701185029Spjd	struct hdac_widget *w, *cw;
5702185029Spjd	struct hdac_softc *sc = devinfo->codec->sc;
5703185029Spjd	int i;
5704185029Spjd
5705185029Spjd	if (depth > HDA_PARSE_MAXDEPTH)
5706185029Spjd		return (0);
5707185029Spjd
5708286570Smav	w = hdac_widget_get(devinfo, nid);
5709286570Smav	if (w == NULL || w->enable == 0 || !(w->pflags & HDA_DAC_PATH))
5710275811Sdelphij		return (0);
5711185029Spjd
5712185029Spjd	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
5713185029Spjd		device_printf(sc->dev, "\n");
5714185029Spjd		device_printf(sc->dev, "    nid=%d [%s]\n", w->nid, w->name);
5715185029Spjd		device_printf(sc->dev, "      ^\n");
5716275811Sdelphij		device_printf(sc->dev, "      |\n");
5717275811Sdelphij		device_printf(sc->dev, "      +-----<------+\n");
5718185029Spjd	} else {
5719286570Smav		device_printf(sc->dev, "                   ^\n");
5720286570Smav		device_printf(sc->dev, "                   |\n");
5721185029Spjd		device_printf(sc->dev, "               ");
5722185029Spjd		printf("  nid=%d [%s]\n", w->nid, w->name);
5723185029Spjd	}
5724185029Spjd
5725185029Spjd	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) {
5726275811Sdelphij		return (1);
5727185029Spjd	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
5728275811Sdelphij		for (i = 0; i < w->nconns; i++) {
5729185029Spjd			cw = hdac_widget_get(devinfo, w->conns[i]);
5730185029Spjd			if (cw == NULL || cw->enable == 0 || cw->type ==
5731286598Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5732185029Spjd				continue;
5733185029Spjd			if (hdac_dump_dac_internal(devinfo, cw->nid,
5734185029Spjd			    depth + 1) != 0)
5735286570Smav				return (1);
5736185029Spjd		}
5737185029Spjd	} else if ((w->type ==
5738185029Spjd	    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR ||
5739185029Spjd	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
5740185029Spjd	    w->selconn > -1 && w->selconn < w->nconns) {
5741275811Sdelphij		if (hdac_dump_dac_internal(devinfo, w->conns[w->selconn],
5742185029Spjd		    depth + 1) != 0)
5743251478Sdelphij			return (1);
5744251478Sdelphij	}
5745251478Sdelphij
5746251478Sdelphij	return (0);
5747251478Sdelphij}
5748185029Spjd
5749208373Smmstatic void
5750251478Sdelphijhdac_dump_dac(struct hdac_devinfo *devinfo)
5751251478Sdelphij{
5752185029Spjd	struct hdac_widget *w;
5753275811Sdelphij	struct hdac_softc *sc = devinfo->codec->sc;
5754185029Spjd	int i, printed = 0;
5755251478Sdelphij
5756251478Sdelphij	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5757185029Spjd		w = hdac_widget_get(devinfo, i);
5758251478Sdelphij		if (w == NULL || w->enable == 0)
5759251478Sdelphij			continue;
5760185029Spjd		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
5761185029Spjd		    !(w->pflags & HDA_DAC_PATH))
5762228103Smm			continue;
5763251478Sdelphij		if (printed == 0) {
5764185029Spjd			printed = 1;
5765185029Spjd			device_printf(sc->dev, "\n");
5766185029Spjd			device_printf(sc->dev, "Playback path:\n");
5767185029Spjd		}
5768251478Sdelphij		hdac_dump_dac_internal(devinfo, w->nid, 0);
5769251478Sdelphij	}
5770251478Sdelphij}
5771185029Spjd
5772251478Sdelphijstatic void
5773185029Spjdhdac_dump_adc(struct hdac_devinfo *devinfo)
5774286570Smav{
5775275811Sdelphij	struct hdac_widget *w, *cw;
5776286570Smav	struct hdac_softc *sc = devinfo->codec->sc;
5777185029Spjd	int i, j;
5778205231Skmacy	int printed = 0;
5779185029Spjd	char ossdevs[256];
5780251478Sdelphij
5781251478Sdelphij	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5782251478Sdelphij		w = hdac_widget_get(devinfo, i);
5783251478Sdelphij		if (w == NULL || w->enable == 0)
5784251478Sdelphij			continue;
5785251478Sdelphij		if (!(w->pflags & HDA_ADC_RECSEL))
5786185029Spjd			continue;
5787185029Spjd		if (printed == 0) {
5788286570Smav			printed = 1;
5789206796Spjd			device_printf(sc->dev, "\n");
5790251478Sdelphij			device_printf(sc->dev, "Recording sources:\n");
5791251478Sdelphij		}
5792185029Spjd		device_printf(sc->dev, "\n");
5793205231Skmacy		device_printf(sc->dev, "    nid=%d [%s]\n", w->nid, w->name);
5794185029Spjd		for (j = 0; j < w->nconns; j++) {
5795185029Spjd			cw = hdac_widget_get(devinfo, w->conns[j]);
5796185029Spjd			if (cw == NULL || cw->enable == 0)
5797185029Spjd				continue;
5798185029Spjd			hdac_audio_ctl_ossmixer_mask2allname(cw->ctlflags,
5799185029Spjd			    ossdevs, sizeof(ossdevs));
5800185029Spjd			device_printf(sc->dev, "      |\n");
5801185029Spjd			device_printf(sc->dev, "      + <- nid=%d [%s]",
5802275811Sdelphij			    cw->nid, cw->name);
5803185029Spjd			if (strlen(ossdevs) > 0) {
5804275811Sdelphij				printf(" [recsrc: %s]", ossdevs);
5805275811Sdelphij			}
5806205231Skmacy			printf("\n");
5807185029Spjd		}
5808272708Savg	}
5809251478Sdelphij}
5810251478Sdelphij
5811251478Sdelphijstatic void
5812275811Sdelphijhdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt)
5813251478Sdelphij{
5814251478Sdelphij	nid_t *nids;
5815251478Sdelphij
5816185029Spjd	if (pcnt > 0) {
5817275811Sdelphij		device_printf(sc->dev, "\n");
5818185029Spjd		device_printf(sc->dev, "   PCM Playback: %d\n", pcnt);
5819275811Sdelphij		hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
5820275811Sdelphij		    sc->play.supp_pcm_size_rate);
5821206796Spjd		device_printf(sc->dev, "            DAC:");
5822275811Sdelphij		for (nids = sc->play.io; *nids != -1; nids++)
5823251478Sdelphij			printf(" %d", *nids);
5824205231Skmacy		printf("\n");
5825185029Spjd	}
5826185029Spjd
5827185029Spjd	if (rcnt > 0) {
5828185029Spjd		device_printf(sc->dev, "\n");
5829185029Spjd		device_printf(sc->dev, "     PCM Record: %d\n", rcnt);
5830185029Spjd		hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
5831275811Sdelphij		    sc->rec.supp_pcm_size_rate);
5832185029Spjd		device_printf(sc->dev, "            ADC:");
5833185029Spjd		for (nids = sc->rec.io; *nids != -1; nids++)
5834185029Spjd			printf(" %d", *nids);
5835185029Spjd		printf("\n");
5836185029Spjd	}
5837205231Skmacy}
5838185029Spjd
5839185029Spjdstatic void
5840185029Spjdhdac_release_resources(struct hdac_softc *sc)
5841275811Sdelphij{
5842185029Spjd	struct hdac_devinfo *devinfo = NULL;
5843185029Spjd	device_t *devlist = NULL;
5844185029Spjd	int i, devcount;
5845185029Spjd
5846275811Sdelphij	if (sc == NULL)
5847185029Spjd		return;
5848185029Spjd
5849205231Skmacy	hdac_lock(sc);
5850185029Spjd	sc->polling = 0;
5851185029Spjd	sc->poll_ival = 0;
5852185029Spjd	callout_stop(&sc->poll_hda);
5853185029Spjd	callout_stop(&sc->poll_hdac);
5854185029Spjd	callout_stop(&sc->poll_jack);
5855185029Spjd	hdac_reset(sc);
5856185029Spjd	hdac_unlock(sc);
5857185029Spjd	taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
5858185029Spjd	callout_drain(&sc->poll_hda);
5859286570Smav	callout_drain(&sc->poll_hdac);
5860185029Spjd	callout_drain(&sc->poll_jack);
5861185029Spjd
5862185029Spjd	hdac_irq_free(sc);
5863185029Spjd
5864185029Spjd	device_get_children(sc->dev, &devlist, &devcount);
5865185029Spjd	for (i = 0; devlist != NULL && i < devcount; i++) {
5866185029Spjd		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
5867205231Skmacy		if (devinfo == NULL)
5868185029Spjd			continue;
5869185029Spjd		if (devinfo->widget != NULL)
5870185029Spjd			free(devinfo->widget, M_HDAC);
5871185029Spjd		if (devinfo->node_type ==
5872185029Spjd		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
5873286570Smav		    devinfo->function.audio.ctl != NULL)
5874275811Sdelphij			free(devinfo->function.audio.ctl, M_HDAC);
5875251478Sdelphij		free(devinfo, M_HDAC);
5876251478Sdelphij		device_delete_child(sc->dev, devlist[i]);
5877251478Sdelphij	}
5878286570Smav	if (devlist != NULL)
5879251478Sdelphij		free(devlist, M_TEMP);
5880251478Sdelphij
5881251478Sdelphij	for (i = 0; i < HDAC_CODEC_MAX; i++) {
5882251478Sdelphij		if (sc->codecs[i] != NULL)
5883286570Smav			free(sc->codecs[i], M_HDAC);
5884286570Smav		sc->codecs[i] = NULL;
5885286570Smav	}
5886251478Sdelphij
5887286598Smav	hdac_dma_free(sc, &sc->pos_dma);
5888286598Smav	hdac_dma_free(sc, &sc->rirb_dma);
5889286598Smav	hdac_dma_free(sc, &sc->corb_dma);
5890286598Smav	if (sc->play.blkcnt > 0)
5891286598Smav		hdac_dma_free(sc, &sc->play.bdl_dma);
5892286598Smav	if (sc->rec.blkcnt > 0)
5893286598Smav		hdac_dma_free(sc, &sc->rec.bdl_dma);
5894286598Smav	if (sc->chan_dmat != NULL) {
5895286598Smav		bus_dma_tag_destroy(sc->chan_dmat);
5896286598Smav		sc->chan_dmat = NULL;
5897286598Smav	}
5898286598Smav	hdac_mem_free(sc);
5899286598Smav	snd_mtxfree(sc->lock);
5900286598Smav	free(sc, M_DEVBUF);
5901286598Smav}
5902286598Smav
5903286598Smav/* This function surely going to make its way into upper level someday. */
5904286598Smavstatic void
5905286598Smavhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
5906286598Smav{
5907286598Smav	const char *res = NULL;
5908286598Smav	int i = 0, j, k, len, inv;
5909286598Smav
5910275811Sdelphij	if (on != NULL)
5911286570Smav		*on = 0;
5912185029Spjd	if (off != NULL)
5913286570Smav		*off = 0;
5914251478Sdelphij	if (sc == NULL)
5915185029Spjd		return;
5916185029Spjd	if (resource_string_value(device_get_name(sc->dev),
5917185029Spjd	    device_get_unit(sc->dev), "config", &res) != 0)
5918185029Spjd		return;
5919286570Smav	if (!(res != NULL && strlen(res) > 0))
5920286570Smav		return;
5921185029Spjd	HDA_BOOTVERBOSE(
5922185029Spjd		device_printf(sc->dev, "HDA_DEBUG: HDA Config:");
5923185029Spjd	);
5924251478Sdelphij	for (;;) {
5925251478Sdelphij		while (res[i] != '\0' &&
5926251478Sdelphij		    (res[i] == ',' || isspace(res[i]) != 0))
5927251478Sdelphij			i++;
5928251478Sdelphij		if (res[i] == '\0') {
5929251478Sdelphij			HDA_BOOTVERBOSE(
5930251478Sdelphij				printf("\n");
5931251478Sdelphij			);
5932251478Sdelphij			return;
5933251478Sdelphij		}
5934251478Sdelphij		j = i;
5935251478Sdelphij		while (res[j] != '\0' &&
5936286570Smav		    !(res[j] == ',' || isspace(res[j]) != 0))
5937286570Smav			j++;
5938286570Smav		len = j - i;
5939251478Sdelphij		if (len > 2 && strncmp(res + i, "no", 2) == 0)
5940251478Sdelphij			inv = 2;
5941251478Sdelphij		else
5942251478Sdelphij			inv = 0;
5943251478Sdelphij		for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) {
5944251478Sdelphij			if (strncmp(res + i + inv,
5945251478Sdelphij			    hdac_quirks_tab[k].key, len - inv) != 0)
5946251478Sdelphij				continue;
5947286570Smav			if (len - inv != strlen(hdac_quirks_tab[k].key))
5948286570Smav				break;
5949251478Sdelphij			HDA_BOOTVERBOSE(
5950251478Sdelphij				printf(" %s%s", (inv != 0) ? "no" : "",
5951251478Sdelphij				    hdac_quirks_tab[k].key);
5952251478Sdelphij			);
5953275811Sdelphij			if (inv == 0 && on != NULL)
5954275811Sdelphij				*on |= hdac_quirks_tab[k].value;
5955286570Smav			else if (inv != 0 && off != NULL)
5956275811Sdelphij				*off |= hdac_quirks_tab[k].value;
5957251478Sdelphij			break;
5958286570Smav		}
5959251478Sdelphij		i = j;
5960286570Smav	}
5961286570Smav}
5962286570Smav
5963251478Sdelphij#ifdef SND_DYNSYSCTL
5964251478Sdelphijstatic int
5965251478Sdelphijsysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
5966251478Sdelphij{
5967251478Sdelphij	struct hdac_softc *sc;
5968251478Sdelphij	struct hdac_devinfo *devinfo;
5969251478Sdelphij	device_t dev;
5970251478Sdelphij	uint32_t ctl;
5971251478Sdelphij	int err, val;
5972251478Sdelphij
5973251478Sdelphij	dev = oidp->oid_arg1;
5974251478Sdelphij	devinfo = pcm_getdevinfo(dev);
5975286570Smav	if (devinfo == NULL || devinfo->codec == NULL ||
5976286570Smav	    devinfo->codec->sc == NULL)
5977251478Sdelphij		return (EINVAL);
5978274172Savg	sc = devinfo->codec->sc;
5979274172Savg	hdac_lock(sc);
5980274172Savg	val = sc->polling;
5981274172Savg	hdac_unlock(sc);
5982274172Savg	err = sysctl_handle_int(oidp, &val, 0, req);
5983286570Smav
5984286570Smav	if (err != 0 || req->newptr == NULL)
5985274172Savg		return (err);
5986286598Smav	if (val < 0 || val > 1)
5987286598Smav		return (EINVAL);
5988286598Smav
5989286598Smav	hdac_lock(sc);
5990286598Smav	if (val != sc->polling) {
5991286598Smav		if (hda_chan_active(sc) != 0)
5992286598Smav			err = EBUSY;
5993251478Sdelphij		else if (val == 0) {
5994251478Sdelphij			callout_stop(&sc->poll_hdac);
5995251478Sdelphij			hdac_unlock(sc);
5996251478Sdelphij			callout_drain(&sc->poll_hdac);
5997185029Spjd			hdac_lock(sc);
5998185029Spjd			HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT,
5999185029Spjd			    sc->rirb_size / 2);
6000185029Spjd			ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
6001185029Spjd			ctl |= HDAC_RIRBCTL_RINTCTL;
6002185029Spjd			HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl);
6003185029Spjd			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
6004185029Spjd			    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
6005185029Spjd			sc->polling = 0;
6006251478Sdelphij			DELAY(1000);
6007286598Smav		} else {
6008185029Spjd			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 0);
6009185029Spjd			HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 0);
6010185029Spjd			ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
6011251478Sdelphij			ctl &= ~HDAC_RIRBCTL_RINTCTL;
6012251478Sdelphij			HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl);
6013251478Sdelphij			hdac_unlock(sc);
6014185029Spjd			taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
6015251478Sdelphij			hdac_lock(sc);
6016185029Spjd			callout_reset(&sc->poll_hdac, 1, hdac_poll_callback,
6017286570Smav			    sc);
6018185029Spjd			sc->polling = 1;
6019251478Sdelphij			DELAY(1000);
6020185029Spjd		}
6021251478Sdelphij	}
6022185029Spjd	hdac_unlock(sc);
6023251478Sdelphij
6024275096Sdelphij	return (err);
6025185029Spjd}
6026185029Spjd
6027185029Spjdstatic int
6028185029Spjdsysctl_hdac_polling_interval(SYSCTL_HANDLER_ARGS)
6029185029Spjd{
6030185029Spjd	struct hdac_softc *sc;
6031185029Spjd	struct hdac_devinfo *devinfo;
6032185029Spjd	device_t dev;
6033185029Spjd	int err, val;
6034185029Spjd
6035208373Smm	dev = oidp->oid_arg1;
6036185029Spjd	devinfo = pcm_getdevinfo(dev);
6037208373Smm	if (devinfo == NULL || devinfo->codec == NULL ||
6038208373Smm	    devinfo->codec->sc == NULL)
6039251478Sdelphij		return (EINVAL);
6040185029Spjd	sc = devinfo->codec->sc;
6041185029Spjd	hdac_lock(sc);
6042185029Spjd	val = ((uint64_t)sc->poll_ival * 1000) / hz;
6043251478Sdelphij	hdac_unlock(sc);
6044286570Smav	err = sysctl_handle_int(oidp, &val, 0, req);
6045251478Sdelphij
6046251478Sdelphij	if (err != 0 || req->newptr == NULL)
6047251478Sdelphij		return (err);
6048251478Sdelphij
6049251478Sdelphij	if (val < 1)
6050251478Sdelphij		val = 1;
6051251478Sdelphij	if (val > 5000)
6052251478Sdelphij		val = 5000;
6053251478Sdelphij	val = ((uint64_t)val * hz) / 1000;
6054251478Sdelphij	if (val < 1)
6055251478Sdelphij		val = 1;
6056251478Sdelphij	if (val > (hz * 5))
6057251478Sdelphij		val = hz * 5;
6058251478Sdelphij
6059251478Sdelphij	hdac_lock(sc);
6060251478Sdelphij	sc->poll_ival = val;
6061251478Sdelphij	hdac_unlock(sc);
6062286570Smav
6063251478Sdelphij	return (err);
6064251478Sdelphij}
6065268075Sdelphij
6066286570Smav#ifdef SND_DEBUG
6067286570Smavstatic int
6068251478Sdelphijsysctl_hdac_pindump(SYSCTL_HANDLER_ARGS)
6069286570Smav{
6070286570Smav	struct hdac_softc *sc;
6071286570Smav	struct hdac_devinfo *devinfo;
6072251478Sdelphij	struct hdac_widget *w;
6073251478Sdelphij	device_t dev;
6074251478Sdelphij	uint32_t res, pincap, timeout;
6075286570Smav	int i, err, val;
6076286570Smav	nid_t cad;
6077269086Sdelphij
6078251478Sdelphij	dev = oidp->oid_arg1;
6079251478Sdelphij	devinfo = pcm_getdevinfo(dev);
6080251478Sdelphij	if (devinfo == NULL || devinfo->codec == NULL ||
6081251478Sdelphij	    devinfo->codec->sc == NULL)
6082286570Smav		return (EINVAL);
6083251478Sdelphij	val = 0;
6084286570Smav	err = sysctl_handle_int(oidp, &val, 0, req);
6085251478Sdelphij	if (err != 0 || req->newptr == NULL || val == 0)
6086251478Sdelphij		return (err);
6087274628Savg	sc = devinfo->codec->sc;
6088274628Savg	cad = devinfo->codec->cad;
6089274628Savg	hdac_lock(sc);
6090274628Savg	device_printf(dev, "HDAC Dump AFG [nid=%d]:\n", devinfo->nid);
6091274628Savg	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6092251478Sdelphij		w = hdac_widget_get(devinfo, i);
6093251478Sdelphij		if (w == NULL || w->type !=
6094251478Sdelphij		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
6095251478Sdelphij			continue;
6096274628Savg		pincap = w->wclass.pin.cap;
6097274628Savg		if ((HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap) ||
6098274628Savg		    HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap)) &&
6099274628Savg		    HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap)) {
6100286570Smav			timeout = 10000;
6101251478Sdelphij			hdac_command(sc,
6102286570Smav			    HDA_CMD_SET_PIN_SENSE(cad, w->nid, 0), cad);
6103251478Sdelphij			do {
6104251478Sdelphij				res = hdac_command(sc,
6105251478Sdelphij				    HDA_CMD_GET_PIN_SENSE(cad, w->nid), cad);
6106251478Sdelphij				if (res != 0x7fffffff)
6107251478Sdelphij					break;
6108251478Sdelphij				DELAY(10);
6109251478Sdelphij			} while (--timeout != 0);
6110251478Sdelphij		} else {
6111251478Sdelphij			timeout = -1;
6112251478Sdelphij			res = hdac_command(sc, HDA_CMD_GET_PIN_SENSE(cad,
6113251478Sdelphij			    w->nid), cad);
6114251478Sdelphij		}
6115251478Sdelphij		device_printf(dev,
6116251478Sdelphij		    "PIN_SENSE: nid=%-3d timeout=%d res=0x%08x [%s]\n",
6117251478Sdelphij		    w->nid, timeout, res,
6118251478Sdelphij		    (w->enable == 0) ? "DISABLED" : "ENABLED");
6119251478Sdelphij	}
6120251478Sdelphij	device_printf(dev,
6121251478Sdelphij	    "NumGPIO=%d NumGPO=%d NumGPI=%d GPIWake=%d GPIUnsol=%d\n",
6122251478Sdelphij	    HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio),
6123251478Sdelphij	    HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio),
6124251478Sdelphij	    HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio),
6125251478Sdelphij	    HDA_PARAM_GPIO_COUNT_GPI_WAKE(devinfo->function.audio.gpio),
6126251478Sdelphij	    HDA_PARAM_GPIO_COUNT_GPI_UNSOL(devinfo->function.audio.gpio));
6127251478Sdelphij	if (HDA_PARAM_GPIO_COUNT_NUM_GPI(devinfo->function.audio.gpio) > 0) {
6128251478Sdelphij		device_printf(dev, " GPI:");
6129251478Sdelphij		res = hdac_command(sc,
6130251478Sdelphij		    HDA_CMD_GET_GPI_DATA(cad, devinfo->nid), cad);
6131251478Sdelphij		printf(" data=0x%08x", res);
6132251478Sdelphij		res = hdac_command(sc,
6133251478Sdelphij		    HDA_CMD_GET_GPI_WAKE_ENABLE_MASK(cad, devinfo->nid),
6134251478Sdelphij		    cad);
6135251478Sdelphij		printf(" wake=0x%08x", res);
6136251478Sdelphij		res = hdac_command(sc,
6137251478Sdelphij		    HDA_CMD_GET_GPI_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
6138251478Sdelphij		    cad);
6139251478Sdelphij		printf(" unsol=0x%08x", res);
6140251478Sdelphij		res = hdac_command(sc,
6141251478Sdelphij		    HDA_CMD_GET_GPI_STICKY_MASK(cad, devinfo->nid), cad);
6142251478Sdelphij		printf(" sticky=0x%08x\n", res);
6143251478Sdelphij	}
6144251478Sdelphij	if (HDA_PARAM_GPIO_COUNT_NUM_GPO(devinfo->function.audio.gpio) > 0) {
6145251478Sdelphij		device_printf(dev, " GPO:");
6146251478Sdelphij		res = hdac_command(sc,
6147286570Smav		    HDA_CMD_GET_GPO_DATA(cad, devinfo->nid), cad);
6148286570Smav		printf(" data=0x%08x\n", res);
6149286570Smav	}
6150251478Sdelphij	if (HDA_PARAM_GPIO_COUNT_NUM_GPIO(devinfo->function.audio.gpio) > 0) {
6151251478Sdelphij		device_printf(dev, "GPI0:");
6152251478Sdelphij		res = hdac_command(sc,
6153251478Sdelphij		    HDA_CMD_GET_GPIO_DATA(cad, devinfo->nid), cad);
6154251478Sdelphij		printf(" data=0x%08x", res);
6155251478Sdelphij		res = hdac_command(sc,
6156251478Sdelphij		    HDA_CMD_GET_GPIO_ENABLE_MASK(cad, devinfo->nid), cad);
6157251478Sdelphij		printf(" enable=0x%08x", res);
6158251478Sdelphij		res = hdac_command(sc,
6159251478Sdelphij		    HDA_CMD_GET_GPIO_DIRECTION(cad, devinfo->nid), cad);
6160251478Sdelphij		printf(" direction=0x%08x\n", res);
6161251478Sdelphij		res = hdac_command(sc,
6162251478Sdelphij		    HDA_CMD_GET_GPIO_WAKE_ENABLE_MASK(cad, devinfo->nid), cad);
6163251478Sdelphij		device_printf(dev, "      wake=0x%08x", res);
6164251478Sdelphij		res = hdac_command(sc,
6165251478Sdelphij		    HDA_CMD_GET_GPIO_UNSOLICITED_ENABLE_MASK(cad, devinfo->nid),
6166251478Sdelphij		    cad);
6167251478Sdelphij		printf("  unsol=0x%08x", res);
6168251478Sdelphij		res = hdac_command(sc,
6169251478Sdelphij		    HDA_CMD_GET_GPIO_STICKY_MASK(cad, devinfo->nid), cad);
6170251478Sdelphij		printf("    sticky=0x%08x\n", res);
6171251478Sdelphij	}
6172251478Sdelphij	hdac_unlock(sc);
6173251478Sdelphij	return (0);
6174251478Sdelphij}
6175251478Sdelphij#endif
6176251478Sdelphij#endif
6177251478Sdelphij
6178251478Sdelphijstatic void
6179251478Sdelphijhdac_attach2(void *arg)
6180251478Sdelphij{
6181251478Sdelphij	struct hdac_softc *sc;
6182251478Sdelphij	struct hdac_widget *w;
6183251478Sdelphij	struct hdac_audio_ctl *ctl;
6184251478Sdelphij	uint32_t quirks_on, quirks_off;
6185275811Sdelphij	int pcnt, rcnt, codec_index;
6186251478Sdelphij	int i;
6187286570Smav	char status[SND_STATUSLEN];
6188286570Smav	device_t *devlist = NULL;
6189251478Sdelphij	int devcount;
6190251478Sdelphij	struct hdac_devinfo *devinfo = NULL;
6191251478Sdelphij
6192251478Sdelphij	sc = (struct hdac_softc *)arg;
6193286570Smav
6194286570Smav	hdac_config_fetch(sc, &quirks_on, &quirks_off);
6195286570Smav
6196286570Smav	HDA_BOOTVERBOSE(
6197274172Savg		device_printf(sc->dev, "HDA_DEBUG: HDA Config: on=0x%08x off=0x%08x\n",
6198286570Smav		    quirks_on, quirks_off);
6199251478Sdelphij	);
6200251478Sdelphij
6201251478Sdelphij	if (resource_int_value(device_get_name(sc->dev),
6202251478Sdelphij	    device_get_unit(sc->dev), "codec_index", &codec_index) != 0) {
6203185029Spjd		switch (sc->pci_subvendor) {
6204185029Spjd		case GB_G33S2H_SUBVENDOR:
6205185029Spjd			codec_index = 2;
6206185029Spjd			break;
6207185029Spjd		default:
6208185029Spjd			codec_index = 0;
6209185029Spjd			break;
6210185029Spjd		}
6211185029Spjd	}
6212208373Smm
6213219089Spjd	hdac_lock(sc);
6214251478Sdelphij
6215185029Spjd	/* Remove ourselves from the config hooks */
6216185029Spjd	if (sc->intrhook.ich_func != NULL) {
6217185029Spjd		config_intrhook_disestablish(&sc->intrhook);
6218185029Spjd		sc->intrhook.ich_func = NULL;
6219185029Spjd	}
6220185029Spjd
6221185029Spjd	/* Start the corb and rirb engines */
6222185029Spjd	HDA_BOOTVERBOSE(
6223219089Spjd		device_printf(sc->dev, "HDA_DEBUG: Starting CORB Engine...\n");
6224185029Spjd	);
6225219089Spjd	hdac_corb_start(sc);
6226185029Spjd	HDA_BOOTVERBOSE(
6227185029Spjd		device_printf(sc->dev, "HDA_DEBUG: Starting RIRB Engine...\n");
6228185029Spjd	);
6229185029Spjd	hdac_rirb_start(sc);
6230185029Spjd
6231185029Spjd	HDA_BOOTVERBOSE(
6232185029Spjd		device_printf(sc->dev,
6233185029Spjd		    "HDA_DEBUG: Enabling controller interrupt...\n");
6234185029Spjd	);
6235185029Spjd	if (sc->polling == 0)
6236219089Spjd		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
6237185029Spjd		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
6238185029Spjd	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
6239185029Spjd	    HDAC_GCTL_UNSOL);
6240185029Spjd
6241185029Spjd	DELAY(1000);
6242185029Spjd
6243185029Spjd	HDA_BOOTVERBOSE(
6244185029Spjd		device_printf(sc->dev,
6245185029Spjd		    "HDA_DEBUG: Scanning HDA codecs [start index=%d] ...\n",
6246185029Spjd		    codec_index);
6247185029Spjd	);
6248185029Spjd	hdac_scan_codecs(sc, codec_index);
6249185029Spjd
6250185029Spjd	device_get_children(sc->dev, &devlist, &devcount);
6251185029Spjd	for (i = 0; devlist != NULL && i < devcount; i++) {
6252185029Spjd		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
6253185029Spjd		if (devinfo != NULL && devinfo->node_type ==
6254185029Spjd		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
6255219089Spjd			break;
6256219089Spjd		} else
6257219089Spjd			devinfo = NULL;
6258219089Spjd	}
6259219089Spjd	if (devlist != NULL)
6260219089Spjd		free(devlist, M_TEMP);
6261219089Spjd
6262219089Spjd	if (devinfo == NULL) {
6263219089Spjd		hdac_unlock(sc);
6264219089Spjd		device_printf(sc->dev, "Audio Function Group not found!\n");
6265185029Spjd		hdac_release_resources(sc);
6266185029Spjd		return;
6267185029Spjd	}
6268185029Spjd
6269185029Spjd	HDA_BOOTVERBOSE(
6270185029Spjd		device_printf(sc->dev,
6271185029Spjd		    "HDA_DEBUG: Parsing AFG nid=%d cad=%d\n",
6272185029Spjd		    devinfo->nid, devinfo->codec->cad);
6273185029Spjd	);
6274185029Spjd	hdac_audio_parse(devinfo);
6275251478Sdelphij	HDA_BOOTVERBOSE(
6276185029Spjd		device_printf(sc->dev, "HDA_DEBUG: Parsing Ctls...\n");
6277185029Spjd	);
6278185029Spjd	hdac_audio_ctl_parse(devinfo);
6279185029Spjd	HDA_BOOTVERBOSE(
6280185029Spjd		device_printf(sc->dev, "HDA_DEBUG: Parsing vendor patch...\n");
6281185029Spjd	);
6282185029Spjd	hdac_vendor_patch_parse(devinfo);
6283185029Spjd	if (quirks_on != 0)
6284185029Spjd		devinfo->function.audio.quirks |= quirks_on;
6285251478Sdelphij	if (quirks_off != 0)
6286208373Smm		devinfo->function.audio.quirks &= ~quirks_off;
6287208373Smm
6288208373Smm	/* XXX Disable all DIGITAL path. */
6289208373Smm	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
6290208373Smm		w = hdac_widget_get(devinfo, i);
6291185029Spjd		if (w == NULL)
6292185029Spjd			continue;
6293185029Spjd		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
6294185029Spjd			w->enable = 0;
6295185029Spjd			continue;
6296185029Spjd		}
6297185029Spjd		/* XXX Disable useless pin ? */
6298185029Spjd		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
6299185029Spjd		    (w->wclass.pin.config &
6300185029Spjd		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
6301185029Spjd		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
6302185029Spjd			w->enable = 0;
6303185029Spjd	}
6304185029Spjd	i = 0;
6305185029Spjd	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6306185029Spjd		if (ctl->widget == NULL)
6307185029Spjd			continue;
6308185029Spjd		if (ctl->ossmask & SOUND_MASK_DISABLE)
6309185029Spjd			ctl->enable = 0;
6310185029Spjd		w = ctl->widget;
6311185029Spjd		if (w->enable == 0 ||
6312185029Spjd		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6313185029Spjd			ctl->enable = 0;
6314185029Spjd		w = ctl->childwidget;
6315185029Spjd		if (w == NULL)
6316185029Spjd			continue;
6317185029Spjd		if (w->enable == 0 ||
6318185029Spjd		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
6319185029Spjd			ctl->enable = 0;
6320185029Spjd	}
6321219089Spjd
6322185029Spjd	HDA_BOOTVERBOSE(
6323185029Spjd		device_printf(sc->dev, "HDA_DEBUG: Building AFG tree...\n");
6324185029Spjd	);
6325185029Spjd	hdac_audio_build_tree(devinfo);
6326185029Spjd
6327255753Sgibbs	i = 0;
6328255753Sgibbs	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6329185029Spjd		if (ctl->ossmask & (SOUND_MASK_SKIP | SOUND_MASK_DISABLE))
6330185029Spjd			ctl->ossmask = 0;
6331185029Spjd	}
6332185029Spjd	HDA_BOOTVERBOSE(
6333185029Spjd		device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n");
6334185029Spjd	);
6335219089Spjd	hdac_audio_commit(devinfo, HDA_COMMIT_ALL);
6336219089Spjd	HDA_BOOTVERBOSE(
6337185029Spjd		device_printf(sc->dev, "HDA_DEBUG: Ctls commit...\n");
6338185029Spjd	);
6339208373Smm	hdac_audio_ctl_commit(devinfo);
6340185029Spjd
6341286570Smav	HDA_BOOTVERBOSE(
6342185029Spjd		device_printf(sc->dev, "HDA_DEBUG: PCMDIR_PLAY setup...\n");
6343185029Spjd	);
6344185029Spjd	pcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_PLAY);
6345185029Spjd	HDA_BOOTVERBOSE(
6346286570Smav		device_printf(sc->dev, "HDA_DEBUG: PCMDIR_REC setup...\n");
6347286570Smav	);
6348185029Spjd	rcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_REC);
6349219089Spjd
6350286598Smav	hdac_unlock(sc);
6351185029Spjd	HDA_BOOTVERBOSE(
6352185029Spjd		device_printf(sc->dev,
6353185029Spjd		    "HDA_DEBUG: OSS mixer initialization...\n");
6354185029Spjd	);
6355185029Spjd
6356185029Spjd	/*
6357185029Spjd	 * There is no point of return after this. If the driver failed,
6358185029Spjd	 * so be it. Let the detach procedure do all the cleanup.
6359185029Spjd	 */
6360185029Spjd	if (mixer_init(sc->dev, &hdac_audio_ctl_ossmixer_class, devinfo) != 0)
6361185029Spjd		device_printf(sc->dev, "Can't register mixer\n");
6362185029Spjd
6363185029Spjd	if (pcnt > 0)
6364185029Spjd		pcnt = 1;
6365185029Spjd	if (rcnt > 0)
6366185029Spjd		rcnt = 1;
6367185029Spjd
6368185029Spjd	HDA_BOOTVERBOSE(
6369185029Spjd		device_printf(sc->dev,
6370185029Spjd		    "HDA_DEBUG: Registering PCM channels...\n");
6371185029Spjd	);
6372185029Spjd	if (pcm_register(sc->dev, devinfo, pcnt, rcnt) != 0)
6373185029Spjd		device_printf(sc->dev, "Can't register PCM\n");
6374185029Spjd
6375185029Spjd	sc->registered++;
6376185029Spjd
6377185029Spjd	if ((devinfo->function.audio.quirks & HDA_QUIRK_DMAPOS) &&
6378185029Spjd	    hdac_dma_alloc(sc, &sc->pos_dma,
6379185029Spjd	    (sc->num_iss + sc->num_oss + sc->num_bss) * 8) != 0) {
6380185029Spjd		HDA_BOOTVERBOSE(
6381185029Spjd			device_printf(sc->dev,
6382185029Spjd			    "Failed to allocate DMA pos buffer (non-fatal)\n");
6383185029Spjd		);
6384185029Spjd	}
6385185029Spjd
6386185029Spjd	for (i = 0; i < pcnt; i++)
6387185029Spjd		pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo);
6388185029Spjd	for (i = 0; i < rcnt; i++)
6389185029Spjd		pcm_addchan(sc->dev, PCMDIR_REC, &hdac_channel_class, devinfo);
6390185029Spjd
6391185029Spjd#ifdef SND_DYNSYSCTL
6392185029Spjd	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
6393185029Spjd	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
6394286570Smav	    "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
6395286570Smav	    sysctl_hdac_polling, "I", "Enable polling mode");
6396286598Smav	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
6397185029Spjd	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
6398185029Spjd	    "polling_interval", CTLTYPE_INT | CTLFLAG_RW, sc->dev,
6399185029Spjd	    sizeof(sc->dev), sysctl_hdac_polling_interval, "I",
6400185029Spjd	    "Controller/Jack Sense polling interval (1-1000 ms)");
6401185029Spjd#ifdef SND_DEBUG
6402185029Spjd	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
6403185029Spjd	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
6404185029Spjd	    "pindump", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
6405185029Spjd	    sysctl_hdac_pindump, "I", "Dump pin states/data");
6406185029Spjd#endif
6407185029Spjd#endif
6408185029Spjd
6409185029Spjd	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]",
6410185029Spjd	    rman_get_start(sc->mem.mem_res), rman_get_start(sc->irq.irq_res),
6411185029Spjd	    PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV);
6412185029Spjd	pcm_setstatus(sc->dev, status);
6413185029Spjd	device_printf(sc->dev, "<HDA Codec: %s>\n", hdac_codec_name(devinfo));
6414185029Spjd	HDA_BOOTVERBOSE(
6415185029Spjd		device_printf(sc->dev, "<HDA Codec ID: 0x%08x>\n",
6416185029Spjd		    hdac_codec_id(devinfo));
6417185029Spjd	);
6418185029Spjd	device_printf(sc->dev, "<HDA Driver Revision: %s>\n",
6419185029Spjd	    HDA_DRV_TEST_REV);
6420185029Spjd
6421185029Spjd	HDA_BOOTVERBOSE(
6422185029Spjd		if (devinfo->function.audio.quirks != 0) {
6423185029Spjd			device_printf(sc->dev, "\n");
6424185029Spjd			device_printf(sc->dev, "HDA config/quirks:");
6425185029Spjd			for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
6426185029Spjd				if ((devinfo->function.audio.quirks &
6427185029Spjd				    hdac_quirks_tab[i].value) ==
6428185029Spjd				    hdac_quirks_tab[i].value)
6429185029Spjd					printf(" %s", hdac_quirks_tab[i].key);
6430185029Spjd			}
6431185029Spjd			printf("\n");
6432185029Spjd		}
6433185029Spjd		device_printf(sc->dev, "\n");
6434185029Spjd		device_printf(sc->dev, "+-------------------+\n");
6435185029Spjd		device_printf(sc->dev, "| DUMPING HDA NODES |\n");
6436185029Spjd		device_printf(sc->dev, "+-------------------+\n");
6437185029Spjd		hdac_dump_nodes(devinfo);
6438185029Spjd		device_printf(sc->dev, "\n");
6439185029Spjd		device_printf(sc->dev, "+------------------------+\n");
6440185029Spjd		device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
6441185029Spjd		device_printf(sc->dev, "+------------------------+\n");
6442185029Spjd		device_printf(sc->dev, "\n");
6443185029Spjd		i = 0;
6444209962Smm		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
6445185029Spjd			device_printf(sc->dev, "%3d: nid=%d", i,
6446185029Spjd			    (ctl->widget != NULL) ? ctl->widget->nid : -1);
6447185029Spjd			if (ctl->childwidget != NULL)
6448185029Spjd				printf(" cnid=%d", ctl->childwidget->nid);
6449185029Spjd			printf(" dir=0x%x index=%d "
6450185029Spjd			    "ossmask=0x%08x ossdev=%d%s\n",
6451185029Spjd			    ctl->dir, ctl->index,
6452185029Spjd			    ctl->ossmask, ctl->ossdev,
6453185029Spjd			    (ctl->enable == 0) ? " [DISABLED]" : "");
6454209962Smm		}
6455185029Spjd		device_printf(sc->dev, "\n");
6456185029Spjd		device_printf(sc->dev, "+-----------------------------------+\n");
6457185029Spjd		device_printf(sc->dev, "| DUMPING HDA AUDIO/VOLUME CONTROLS |\n");
6458185029Spjd		device_printf(sc->dev, "+-----------------------------------+\n");
6459185029Spjd		hdac_dump_ctls(devinfo, "Master Volume (OSS: vol)", SOUND_MASK_VOLUME);
6460185029Spjd		hdac_dump_ctls(devinfo, "PCM Volume (OSS: pcm)", SOUND_MASK_PCM);
6461185029Spjd		hdac_dump_ctls(devinfo, "CD Volume (OSS: cd)", SOUND_MASK_CD);
6462185029Spjd		hdac_dump_ctls(devinfo, "Microphone Volume (OSS: mic)", SOUND_MASK_MIC);
6463185029Spjd		hdac_dump_ctls(devinfo, "Line-in Volume (OSS: line)", SOUND_MASK_LINE);
6464		hdac_dump_ctls(devinfo, "Recording Level (OSS: rec)", SOUND_MASK_RECLEV);
6465		hdac_dump_ctls(devinfo, "Speaker/Beep (OSS: speaker)", SOUND_MASK_SPEAKER);
6466		hdac_dump_ctls(devinfo, NULL, 0);
6467		hdac_dump_dac(devinfo);
6468		hdac_dump_adc(devinfo);
6469		device_printf(sc->dev, "\n");
6470		device_printf(sc->dev, "+--------------------------------------+\n");
6471		device_printf(sc->dev, "| DUMPING PCM Playback/Record Channels |\n");
6472		device_printf(sc->dev, "+--------------------------------------+\n");
6473		hdac_dump_pcmchannels(sc, pcnt, rcnt);
6474	);
6475
6476	if (sc->polling != 0) {
6477		hdac_lock(sc);
6478		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
6479		hdac_unlock(sc);
6480	}
6481}
6482
6483/****************************************************************************
6484 * int hdac_detach(device_t)
6485 *
6486 * Detach and free up resources utilized by the hdac device.
6487 ****************************************************************************/
6488static int
6489hdac_detach(device_t dev)
6490{
6491	struct hdac_softc *sc = NULL;
6492	struct hdac_devinfo *devinfo = NULL;
6493	int err;
6494
6495	devinfo = (struct hdac_devinfo *)pcm_getdevinfo(dev);
6496	if (devinfo != NULL && devinfo->codec != NULL)
6497		sc = devinfo->codec->sc;
6498	if (sc == NULL)
6499		return (0);
6500
6501	if (sc->registered > 0) {
6502		err = pcm_unregister(dev);
6503		if (err != 0)
6504			return (err);
6505	}
6506
6507	hdac_release_resources(sc);
6508
6509	return (0);
6510}
6511
6512static device_method_t hdac_methods[] = {
6513	/* device interface */
6514	DEVMETHOD(device_probe,		hdac_probe),
6515	DEVMETHOD(device_attach,	hdac_attach),
6516	DEVMETHOD(device_detach,	hdac_detach),
6517	{ 0, 0 }
6518};
6519
6520static driver_t hdac_driver = {
6521	"pcm",
6522	hdac_methods,
6523	PCM_SOFTC_SIZE,
6524};
6525
6526DRIVER_MODULE(snd_hda, pci, hdac_driver, pcm_devclass, 0, 0);
6527MODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
6528MODULE_VERSION(snd_hda, 1);
6529