hdac.c revision 167702
1162922Sariff/*-
2162922Sariff * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
3162922Sariff * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
4162922Sariff * All rights reserved.
5162922Sariff *
6162922Sariff * Redistribution and use in source and binary forms, with or without
7162922Sariff * modification, are permitted provided that the following conditions
8162922Sariff * are met:
9162922Sariff * 1. Redistributions of source code must retain the above copyright
10162922Sariff *    notice, this list of conditions and the following disclaimer.
11162922Sariff * 2. Redistributions in binary form must reproduce the above copyright
12162922Sariff *    notice, this list of conditions and the following disclaimer in the
13162922Sariff *    documentation and/or other materials provided with the distribution.
14162922Sariff *
15162922Sariff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16162922Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17162922Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18162922Sariff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19162922Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20162922Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21162922Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22162922Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23162922Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24162922Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25162922Sariff * SUCH DAMAGE.
26162922Sariff */
27162922Sariff
28162922Sariff/*
29162922Sariff * Intel High Definition Audio (Controller) driver for FreeBSD. Be advised
30162922Sariff * that this driver still in its early stage, and possible of rewrite are
31162922Sariff * pretty much guaranteed. There are supposedly several distinct parent/child
32162922Sariff * busses to make this "perfect", but as for now and for the sake of
33162922Sariff * simplicity, everything is gobble up within single source.
34162922Sariff *
35162922Sariff * List of subsys:
36162922Sariff *     1) HDA Controller support
37162922Sariff *     2) HDA Codecs support, which may include
38162922Sariff *        - HDA
39162922Sariff *        - Modem
40162922Sariff *        - HDMI
41162922Sariff *     3) Widget parser - the real magic of why this driver works on so
42162922Sariff *        many hardwares with minimal vendor specific quirk. The original
43162922Sariff *        parser was written using Ruby and can be found at
44162922Sariff *        http://people.freebsd.org/~ariff/HDA/parser.rb . This crude
45162922Sariff *        ruby parser take the verbose dmesg dump as its input. Refer to
46162922Sariff *        http://www.microsoft.com/whdc/device/audio/default.mspx for various
47164614Sariff *        interesting documents, especially UAA (Universal Audio Architecture).
48162922Sariff *     4) Possible vendor specific support.
49162922Sariff *        (snd_hda_intel, snd_hda_ati, etc..)
50162922Sariff *
51162922Sariff * Thanks to Ahmad Ubaidah Omar @ Defenxis Sdn. Bhd. for the
52162922Sariff * Compaq V3000 with Conexant HDA.
53162922Sariff *
54162922Sariff *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
55162922Sariff *    *                                                                 *
56162922Sariff *    *        This driver is a collaborative effort made by:           *
57162922Sariff *    *                                                                 *
58162922Sariff *    *          Stephane E. Potvin <sepotvin@videotron.ca>             *
59162922Sariff *    *               Andrea Bittau <a.bittau@cs.ucl.ac.uk>             *
60162922Sariff *    *               Wesley Morgan <morganw@chemikals.org>             *
61162922Sariff *    *              Daniel Eischen <deischen@FreeBSD.org>              *
62162922Sariff *    *             Maxime Guillaud <bsd-ports@mguillaud.net>           *
63162922Sariff *    *              Ariff Abdullah <ariff@FreeBSD.org>                 *
64162922Sariff *    *                                                                 *
65162922Sariff *    *   ....and various people from freebsd-multimedia@FreeBSD.org    *
66162922Sariff *    *                                                                 *
67162922Sariff *    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
68162922Sariff */
69162922Sariff
70163057Sariff#include <sys/ctype.h>
71163057Sariff
72162922Sariff#include <dev/sound/pcm/sound.h>
73162922Sariff#include <dev/pci/pcireg.h>
74162922Sariff#include <dev/pci/pcivar.h>
75162922Sariff
76162922Sariff#include <dev/sound/pci/hda/hdac_private.h>
77162922Sariff#include <dev/sound/pci/hda/hdac_reg.h>
78162922Sariff#include <dev/sound/pci/hda/hda_reg.h>
79162922Sariff#include <dev/sound/pci/hda/hdac.h>
80162922Sariff
81162922Sariff#include "mixer_if.h"
82162922Sariff
83167648Sariff#define HDA_DRV_TEST_REV	"20070317_0042"
84162922Sariff#define HDA_WIDGET_PARSER_REV	1
85162922Sariff
86162922SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 167702 2007-03-19 16:06:26Z ariff $");
87162922Sariff
88162922Sariff#undef HDA_DEBUG_ENABLED
89162922Sariff#define HDA_DEBUG_ENABLED	1
90162922Sariff
91162922Sariff#ifdef HDA_DEBUG_ENABLED
92163057Sariff#define HDA_DEBUG(stmt)	do {	\
93163057Sariff	stmt			\
94162922Sariff} while(0)
95162922Sariff#else
96163057Sariff#define HDA_DEBUG(stmt)
97162922Sariff#endif
98162922Sariff
99163057Sariff#define HDA_BOOTVERBOSE(stmt)	do {	\
100162922Sariff	if (bootverbose) {			\
101162922Sariff		stmt				\
102162922Sariff	}					\
103162922Sariff} while(0)
104162922Sariff
105162965Sariff#if 1
106162922Sariff#undef HDAC_INTR_EXTRA
107162922Sariff#define HDAC_INTR_EXTRA		1
108162922Sariff#endif
109162922Sariff
110162965Sariff#define hdac_lock(sc)		snd_mtxlock((sc)->lock)
111162965Sariff#define hdac_unlock(sc)		snd_mtxunlock((sc)->lock)
112163057Sariff#define hdac_lockassert(sc)	snd_mtxassert((sc)->lock)
113163057Sariff#define hdac_lockowned(sc)	mtx_owned((sc)->lock)
114162922Sariff
115162965Sariff#define HDA_FLAG_MATCH(fl, v)	(((fl) & (v)) == (v))
116163257Sariff#define HDA_DEV_MATCH(fl, v)	((fl) == (v) || \
117163257Sariff				(fl) == 0xffffffff || \
118163257Sariff				(((fl) & 0xffff0000) == 0xffff0000 && \
119163257Sariff				((fl) & 0x0000ffff) == ((v) & 0x0000ffff)) || \
120163257Sariff				(((fl) & 0x0000ffff) == 0x0000ffff && \
121163257Sariff				((fl) & 0xffff0000) == ((v) & 0xffff0000)))
122162965Sariff#define HDA_MATCH_ALL		0xffffffff
123162965Sariff#define HDAC_INVALID		0xffffffff
124162965Sariff
125162922Sariff#define HDA_MODEL_CONSTRUCT(vendor, model)	\
126162922Sariff		(((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff))
127162922Sariff
128162922Sariff/* Controller models */
129162922Sariff
130162922Sariff/* Intel */
131162922Sariff#define INTEL_VENDORID		0x8086
132162922Sariff#define HDA_INTEL_82801F	HDA_MODEL_CONSTRUCT(INTEL, 0x2668)
133162922Sariff#define HDA_INTEL_82801G	HDA_MODEL_CONSTRUCT(INTEL, 0x27d8)
134163136Sariff#define HDA_INTEL_82801H	HDA_MODEL_CONSTRUCT(INTEL, 0x284b)
135163136Sariff#define HDA_INTEL_63XXESB	HDA_MODEL_CONSTRUCT(INTEL, 0x269a)
136162922Sariff#define HDA_INTEL_ALL		HDA_MODEL_CONSTRUCT(INTEL, 0xffff)
137162922Sariff
138162922Sariff/* Nvidia */
139162922Sariff#define NVIDIA_VENDORID		0x10de
140162922Sariff#define HDA_NVIDIA_MCP51	HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c)
141162922Sariff#define HDA_NVIDIA_MCP55	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371)
142163136Sariff#define HDA_NVIDIA_MCP61A	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03e4)
143163136Sariff#define HDA_NVIDIA_MCP61B	HDA_MODEL_CONSTRUCT(NVIDIA, 0x03f0)
144163136Sariff#define HDA_NVIDIA_MCP65A	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044a)
145163136Sariff#define HDA_NVIDIA_MCP65B	HDA_MODEL_CONSTRUCT(NVIDIA, 0x044b)
146162922Sariff#define HDA_NVIDIA_ALL		HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff)
147162922Sariff
148162922Sariff/* ATI */
149162922Sariff#define ATI_VENDORID		0x1002
150162922Sariff#define HDA_ATI_SB450		HDA_MODEL_CONSTRUCT(ATI, 0x437b)
151163136Sariff#define HDA_ATI_SB600		HDA_MODEL_CONSTRUCT(ATI, 0x4383)
152162922Sariff#define HDA_ATI_ALL		HDA_MODEL_CONSTRUCT(ATI, 0xffff)
153162922Sariff
154163136Sariff/* VIA */
155163136Sariff#define VIA_VENDORID		0x1106
156163136Sariff#define HDA_VIA_VT82XX		HDA_MODEL_CONSTRUCT(VIA, 0x3288)
157163136Sariff#define HDA_VIA_ALL		HDA_MODEL_CONSTRUCT(VIA, 0xffff)
158163136Sariff
159163136Sariff/* SiS */
160163136Sariff#define SIS_VENDORID		0x1039
161163136Sariff#define HDA_SIS_966		HDA_MODEL_CONSTRUCT(SIS, 0x7502)
162163136Sariff#define HDA_SIS_ALL		HDA_MODEL_CONSTRUCT(SIS, 0xffff)
163163136Sariff
164162922Sariff/* OEM/subvendors */
165162922Sariff
166165466Sariff/* Intel */
167165466Sariff#define INTEL_D101GGC_SUBVENDOR	HDA_MODEL_CONSTRUCT(INTEL, 0xd600)
168165466Sariff
169162922Sariff/* HP/Compaq */
170162922Sariff#define HP_VENDORID		0x103c
171162922Sariff#define HP_V3000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b5)
172162922Sariff#define HP_NX7400_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a2)
173162922Sariff#define HP_NX6310_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30aa)
174165281Sariff#define HP_NX6325_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b0)
175166294Sariff#define HP_XW4300_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x3013)
176162922Sariff#define HP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0xffff)
177165281Sariff/* What is wrong with XN 2563 anyway? (Got the picture ?) */
178165281Sariff#define HP_NX6325_SUBVENDORX	0x103c30b0
179162922Sariff
180162922Sariff/* Dell */
181162922Sariff#define DELL_VENDORID		0x1028
182162922Sariff#define DELL_D820_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01cc)
183162922Sariff#define DELL_I1300_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01c9)
184162922Sariff#define DELL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0xffff)
185162922Sariff
186162922Sariff/* Clevo */
187162922Sariff#define CLEVO_VENDORID		0x1558
188162922Sariff#define CLEVO_D900T_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0x0900)
189162922Sariff#define CLEVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0xffff)
190162922Sariff
191162922Sariff/* Acer */
192162922Sariff#define ACER_VENDORID		0x1025
193165992Sariff#define ACER_A5050_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0x010f)
194162922Sariff#define ACER_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0xffff)
195162922Sariff
196162965Sariff/* Asus */
197162965Sariff#define ASUS_VENDORID		0x1043
198162965Sariff#define ASUS_M5200_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
199163276Sariff#define ASUS_U5F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
200163432Sariff#define ASUS_A8JC_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1153)
201165103Sariff#define ASUS_P1AH2_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x81cb)
202165281Sariff#define ASUS_A7M_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1323)
203167623Sariff#define ASUS_A7T_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x13c2)
204167648Sariff#define ASUS_W6F_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1263)
205162965Sariff#define ASUS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
206162922Sariff
207163257Sariff/* IBM / Lenovo */
208163257Sariff#define IBM_VENDORID		0x1014
209163257Sariff#define IBM_M52_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0x02f6)
210163257Sariff#define IBM_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(IBM, 0xffff)
211162965Sariff
212164614Sariff/* Lenovo */
213164657Sariff#define LENOVO_VENDORID		0x17aa
214164657Sariff#define LENOVO_3KN100_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0x2066)
215164657Sariff#define LENOVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LENOVO, 0xffff)
216163257Sariff
217164657Sariff/* Samsung */
218164657Sariff#define SAMSUNG_VENDORID	0x144d
219164657Sariff#define SAMSUNG_Q1_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xc027)
220164657Sariff#define SAMSUNG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(SAMSUNG, 0xffff)
221164614Sariff
222164750Sariff/* Medion ? */
223164750Sariff#define MEDION_VENDORID			0x161f
224164750Sariff#define MEDION_MD95257_SUBVENDOR	HDA_MODEL_CONSTRUCT(MEDION, 0x203d)
225164750Sariff#define MEDION_ALL_SUBVENDOR		HDA_MODEL_CONSTRUCT(MEDION, 0xffff)
226164750Sariff
227164828Sariff/*
228164828Sariff * Apple Intel MacXXXX seems using Sigmatel codec/vendor id
229164828Sariff * instead of their own, which is beyond my comprehension
230164828Sariff * (see HDA_CODEC_STAC9221 below).
231164828Sariff */
232164828Sariff#define APPLE_INTEL_MAC		0x76808384
233164828Sariff
234165281Sariff/* LG Electronics */
235165281Sariff#define LG_VENDORID		0x1854
236165281Sariff#define LG_LW20_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0x0018)
237165281Sariff#define LG_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(LG, 0xffff)
238165281Sariff
239165351Sariff/* Fujitsu Siemens */
240165351Sariff#define FS_VENDORID		0x1734
241165351Sariff#define FS_PA1510_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0x10b8)
242165351Sariff#define FS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(FS, 0xffff)
243165351Sariff
244165770Sariff/* Toshiba */
245165770Sariff#define TOSHIBA_VENDORID	0x1179
246165770Sariff#define TOSHIBA_U200_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0x0001)
247165770Sariff#define TOSHIBA_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(TOSHIBA, 0xffff)
248165770Sariff
249165992Sariff/* Micro-Star International (MSI) */
250165992Sariff#define MSI_VENDORID		0x1462
251165992Sariff#define MSI_MS1034_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0x0349)
252165992Sariff#define MSI_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(MSI, 0xffff)
253165992Sariff
254162922Sariff/* Misc constants.. */
255162922Sariff#define HDA_AMP_MUTE_DEFAULT	(0xffffffff)
256162922Sariff#define HDA_AMP_MUTE_NONE	(0)
257162922Sariff#define HDA_AMP_MUTE_LEFT	(1 << 0)
258162922Sariff#define HDA_AMP_MUTE_RIGHT	(1 << 1)
259162922Sariff#define HDA_AMP_MUTE_ALL	(HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT)
260162922Sariff
261162922Sariff#define HDA_AMP_LEFT_MUTED(v)	((v) & (HDA_AMP_MUTE_LEFT))
262162922Sariff#define HDA_AMP_RIGHT_MUTED(v)	(((v) & HDA_AMP_MUTE_RIGHT) >> 1)
263162922Sariff
264162922Sariff#define HDA_DAC_PATH	(1 << 0)
265162922Sariff#define HDA_ADC_PATH	(1 << 1)
266162922Sariff#define HDA_ADC_RECSEL	(1 << 2)
267162922Sariff
268163057Sariff#define HDA_CTL_OUT	(1 << 0)
269163057Sariff#define HDA_CTL_IN	(1 << 1)
270162922Sariff#define HDA_CTL_BOTH	(HDA_CTL_IN | HDA_CTL_OUT)
271162922Sariff
272163057Sariff#define HDA_GPIO_MAX		15
273163057Sariff/* 0 - 14 = GPIO */
274163057Sariff#define HDA_QUIRK_GPIO0		(1 << 0)
275163057Sariff#define HDA_QUIRK_GPIO1		(1 << 1)
276163057Sariff#define HDA_QUIRK_GPIO2		(1 << 2)
277165039Sariff#define HDA_QUIRK_GPIOFLUSH	(1 << 15)
278165039Sariff#define HDA_QUIRK_SOFTPCMVOL	(1 << 16)
279165039Sariff#define HDA_QUIRK_FIXEDRATE	(1 << 17)
280165039Sariff#define HDA_QUIRK_FORCESTEREO	(1 << 18)
281165039Sariff#define HDA_QUIRK_EAPDINV	(1 << 19)
282165069Sariff#define HDA_QUIRK_VREF		(1 << 20)
283162922Sariff
284163057Sariffstatic const struct {
285163057Sariff	char *key;
286163057Sariff	uint32_t value;
287163057Sariff} hdac_quirks_tab[] = {
288163057Sariff	{ "gpio0", HDA_QUIRK_GPIO0 },
289163057Sariff	{ "gpio1", HDA_QUIRK_GPIO1 },
290163057Sariff	{ "gpio2", HDA_QUIRK_GPIO2 },
291165039Sariff	{ "gpioflush", HDA_QUIRK_GPIOFLUSH },
292163057Sariff	{ "softpcmvol", HDA_QUIRK_SOFTPCMVOL },
293163057Sariff	{ "fixedrate", HDA_QUIRK_FIXEDRATE },
294163136Sariff	{ "forcestereo", HDA_QUIRK_FORCESTEREO },
295163276Sariff	{ "eapdinv", HDA_QUIRK_EAPDINV },
296165069Sariff	{ "vref", HDA_QUIRK_VREF },
297163057Sariff};
298163057Sariff#define HDAC_QUIRKS_TAB_LEN	\
299163057Sariff		(sizeof(hdac_quirks_tab) / sizeof(hdac_quirks_tab[0]))
300163057Sariff
301162922Sariff#define HDA_BDL_MIN	2
302162922Sariff#define HDA_BDL_MAX	256
303162922Sariff#define HDA_BDL_DEFAULT	HDA_BDL_MIN
304162922Sariff
305167648Sariff#define HDA_BLK_MIN	128
306167648Sariff#define HDA_BLK_ALIGN	(~(HDA_BLK_MIN - 1))
307167648Sariff
308162922Sariff#define HDA_BUFSZ_MIN		4096
309162922Sariff#define HDA_BUFSZ_MAX		65536
310162922Sariff#define HDA_BUFSZ_DEFAULT	16384
311162922Sariff
312162922Sariff#define HDA_PARSE_MAXDEPTH	10
313162922Sariff
314162922Sariff#define HDAC_UNSOLTAG_EVENT_HP	0x00
315162922Sariff
316165239SariffMALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
317162922Sariff
318162922Sariffenum {
319162922Sariff	HDA_PARSE_MIXER,
320162922Sariff	HDA_PARSE_DIRECT
321162922Sariff};
322162922Sariff
323162922Sariff/* Default */
324162922Sariffstatic uint32_t hdac_fmt[] = {
325162922Sariff	AFMT_STEREO | AFMT_S16_LE,
326162922Sariff	0
327162922Sariff};
328162922Sariff
329162922Sariffstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0};
330162922Sariff
331162922Sariffstatic const struct {
332162922Sariff	uint32_t	model;
333162922Sariff	char		*desc;
334162922Sariff} hdac_devices[] = {
335162922Sariff	{ HDA_INTEL_82801F,  "Intel 82801F" },
336162922Sariff	{ HDA_INTEL_82801G,  "Intel 82801G" },
337163136Sariff	{ HDA_INTEL_82801H,  "Intel 82801H" },
338163136Sariff	{ HDA_INTEL_63XXESB, "Intel 631x/632xESB" },
339162922Sariff	{ HDA_NVIDIA_MCP51,  "NVidia MCP51" },
340162922Sariff	{ HDA_NVIDIA_MCP55,  "NVidia MCP55" },
341163136Sariff	{ HDA_NVIDIA_MCP61A, "NVidia MCP61A" },
342163136Sariff	{ HDA_NVIDIA_MCP61B, "NVidia MCP61B" },
343163136Sariff	{ HDA_NVIDIA_MCP65A, "NVidia MCP65A" },
344163136Sariff	{ HDA_NVIDIA_MCP65B, "NVidia MCP65B" },
345162922Sariff	{ HDA_ATI_SB450,     "ATI SB450"    },
346163136Sariff	{ HDA_ATI_SB600,     "ATI SB600"    },
347163136Sariff	{ HDA_VIA_VT82XX,    "VIA VT8251/8237A" },
348163136Sariff	{ HDA_SIS_966,       "SiS 966" },
349162922Sariff	/* Unknown */
350162922Sariff	{ HDA_INTEL_ALL,  "Intel (Unknown)"  },
351162922Sariff	{ HDA_NVIDIA_ALL, "NVidia (Unknown)" },
352162922Sariff	{ HDA_ATI_ALL,    "ATI (Unknown)"    },
353163136Sariff	{ HDA_VIA_ALL,    "VIA (Unknown)"    },
354163136Sariff	{ HDA_SIS_ALL,    "SiS (Unknown)"    },
355162922Sariff};
356162922Sariff#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0]))
357162922Sariff
358162922Sariffstatic const struct {
359162922Sariff	uint32_t	rate;
360162922Sariff	int		valid;
361162922Sariff	uint16_t	base;
362162922Sariff	uint16_t	mul;
363162922Sariff	uint16_t	div;
364162922Sariff} hda_rate_tab[] = {
365162922Sariff	{   8000, 1, 0x0000, 0x0000, 0x0500 },	/* (48000 * 1) / 6 */
366162922Sariff	{   9600, 0, 0x0000, 0x0000, 0x0400 },	/* (48000 * 1) / 5 */
367162922Sariff	{  12000, 0, 0x0000, 0x0000, 0x0300 },	/* (48000 * 1) / 4 */
368162922Sariff	{  16000, 1, 0x0000, 0x0000, 0x0200 },	/* (48000 * 1) / 3 */
369162922Sariff	{  18000, 0, 0x0000, 0x1000, 0x0700 },	/* (48000 * 3) / 8 */
370162922Sariff	{  19200, 0, 0x0000, 0x0800, 0x0400 },	/* (48000 * 2) / 5 */
371162922Sariff	{  24000, 0, 0x0000, 0x0000, 0x0100 },	/* (48000 * 1) / 2 */
372162922Sariff	{  28800, 0, 0x0000, 0x1000, 0x0400 },	/* (48000 * 3) / 5 */
373162922Sariff	{  32000, 1, 0x0000, 0x0800, 0x0200 },	/* (48000 * 2) / 3 */
374162922Sariff	{  36000, 0, 0x0000, 0x1000, 0x0300 },	/* (48000 * 3) / 4 */
375162922Sariff	{  38400, 0, 0x0000, 0x1800, 0x0400 },	/* (48000 * 4) / 5 */
376162922Sariff	{  48000, 1, 0x0000, 0x0000, 0x0000 },	/* (48000 * 1) / 1 */
377162922Sariff	{  64000, 0, 0x0000, 0x1800, 0x0200 },	/* (48000 * 4) / 3 */
378162922Sariff	{  72000, 0, 0x0000, 0x1000, 0x0100 },	/* (48000 * 3) / 2 */
379162922Sariff	{  96000, 1, 0x0000, 0x0800, 0x0000 },	/* (48000 * 2) / 1 */
380162922Sariff	{ 144000, 0, 0x0000, 0x1000, 0x0000 },	/* (48000 * 3) / 1 */
381162922Sariff	{ 192000, 1, 0x0000, 0x1800, 0x0000 },	/* (48000 * 4) / 1 */
382162922Sariff	{   8820, 0, 0x4000, 0x0000, 0x0400 },	/* (44100 * 1) / 5 */
383162922Sariff	{  11025, 1, 0x4000, 0x0000, 0x0300 },	/* (44100 * 1) / 4 */
384162922Sariff	{  12600, 0, 0x4000, 0x0800, 0x0600 },	/* (44100 * 2) / 7 */
385162922Sariff	{  14700, 0, 0x4000, 0x0000, 0x0200 },	/* (44100 * 1) / 3 */
386162922Sariff	{  17640, 0, 0x4000, 0x0800, 0x0400 },	/* (44100 * 2) / 5 */
387162922Sariff	{  18900, 0, 0x4000, 0x1000, 0x0600 },	/* (44100 * 3) / 7 */
388162922Sariff	{  22050, 1, 0x4000, 0x0000, 0x0100 },	/* (44100 * 1) / 2 */
389162922Sariff	{  25200, 0, 0x4000, 0x1800, 0x0600 },	/* (44100 * 4) / 7 */
390162922Sariff	{  26460, 0, 0x4000, 0x1000, 0x0400 },	/* (44100 * 3) / 5 */
391162922Sariff	{  29400, 0, 0x4000, 0x0800, 0x0200 },	/* (44100 * 2) / 3 */
392162922Sariff	{  33075, 0, 0x4000, 0x1000, 0x0300 },	/* (44100 * 3) / 4 */
393162922Sariff	{  35280, 0, 0x4000, 0x1800, 0x0400 },	/* (44100 * 4) / 5 */
394162922Sariff	{  44100, 1, 0x4000, 0x0000, 0x0000 },	/* (44100 * 1) / 1 */
395162922Sariff	{  58800, 0, 0x4000, 0x1800, 0x0200 },	/* (44100 * 4) / 3 */
396162922Sariff	{  66150, 0, 0x4000, 0x1000, 0x0100 },	/* (44100 * 3) / 2 */
397162922Sariff	{  88200, 1, 0x4000, 0x0800, 0x0000 },	/* (44100 * 2) / 1 */
398162922Sariff	{ 132300, 0, 0x4000, 0x1000, 0x0000 },	/* (44100 * 3) / 1 */
399162922Sariff	{ 176400, 1, 0x4000, 0x1800, 0x0000 },	/* (44100 * 4) / 1 */
400162922Sariff};
401162922Sariff#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
402162922Sariff
403162922Sariff/* All codecs you can eat... */
404162922Sariff#define HDA_CODEC_CONSTRUCT(vendor, id) \
405162922Sariff		(((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff))
406162922Sariff
407162922Sariff/* Realtek */
408162922Sariff#define REALTEK_VENDORID	0x10ec
409162922Sariff#define HDA_CODEC_ALC260	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
410162922Sariff#define HDA_CODEC_ALC861	HDA_CODEC_CONSTRUCT(REALTEK, 0x0861)
411162922Sariff#define HDA_CODEC_ALC880	HDA_CODEC_CONSTRUCT(REALTEK, 0x0880)
412163057Sariff#define HDA_CODEC_ALC882	HDA_CODEC_CONSTRUCT(REALTEK, 0x0882)
413163057Sariff#define HDA_CODEC_ALC883	HDA_CODEC_CONSTRUCT(REALTEK, 0x0883)
414165305Sariff#define HDA_CODEC_ALC888	HDA_CODEC_CONSTRUCT(REALTEK, 0x0888)
415162922Sariff#define HDA_CODEC_ALCXXXX	HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
416162922Sariff
417162922Sariff/* Analog Device */
418162922Sariff#define ANALOGDEVICE_VENDORID	0x11d4
419162922Sariff#define HDA_CODEC_AD1981HD	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1981)
420162922Sariff#define HDA_CODEC_AD1983	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1983)
421162922Sariff#define HDA_CODEC_AD1986A	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1986)
422162922Sariff#define HDA_CODEC_ADXXXX	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0xffff)
423162922Sariff
424162922Sariff/* CMedia */
425162922Sariff#define CMEDIA_VENDORID		0x434d
426162922Sariff#define HDA_CODEC_CMI9880	HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980)
427162922Sariff#define HDA_CODEC_CMIXXXX	HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff)
428162922Sariff
429162922Sariff/* Sigmatel */
430162922Sariff#define SIGMATEL_VENDORID	0x8384
431162922Sariff#define HDA_CODEC_STAC9221	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
432162922Sariff#define HDA_CODEC_STAC9221D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
433162922Sariff#define HDA_CODEC_STAC9220	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
434162922Sariff#define HDA_CODEC_STAC922XD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
435165305Sariff#define HDA_CODEC_STAC9227	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7618)
436166796Sariff#define HDA_CODEC_STAC9271D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7627)
437162922Sariff#define HDA_CODEC_STACXXXX	HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
438162922Sariff
439162922Sariff/*
440162922Sariff * Conexant
441162922Sariff *
442162922Sariff * Ok, the truth is, I don't have any idea at all whether
443162922Sariff * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only
444162922Sariff * place that tell me it is "Venice" is from its Windows driver INF.
445163057Sariff *
446163057Sariff *  Venice - CX?????
447163057Sariff * Waikiki - CX20551-22
448162922Sariff */
449162922Sariff#define CONEXANT_VENDORID	0x14f1
450162922Sariff#define HDA_CODEC_CXVENICE	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045)
451163057Sariff#define HDA_CODEC_CXWAIKIKI	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5047)
452162922Sariff#define HDA_CODEC_CXXXXX	HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff)
453162922Sariff
454162922Sariff
455162922Sariff/* Codecs */
456162922Sariffstatic const struct {
457162922Sariff	uint32_t id;
458162922Sariff	char *name;
459162922Sariff} hdac_codecs[] = {
460162922Sariff	{ HDA_CODEC_ALC260,    "Realtek ALC260" },
461162922Sariff	{ HDA_CODEC_ALC861,    "Realtek ALC861" },
462162922Sariff	{ HDA_CODEC_ALC880,    "Realtek ALC880" },
463162922Sariff	{ HDA_CODEC_ALC882,    "Realtek ALC882" },
464163057Sariff	{ HDA_CODEC_ALC883,    "Realtek ALC883" },
465165305Sariff	{ HDA_CODEC_ALC888,    "Realtek ALC888" },
466162922Sariff	{ HDA_CODEC_AD1981HD,  "Analog Device AD1981HD" },
467162922Sariff	{ HDA_CODEC_AD1983,    "Analog Device AD1983" },
468162922Sariff	{ HDA_CODEC_AD1986A,   "Analog Device AD1986A" },
469162922Sariff	{ HDA_CODEC_CMI9880,   "CMedia CMI9880" },
470162922Sariff	{ HDA_CODEC_STAC9221,  "Sigmatel STAC9221" },
471162922Sariff	{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
472162922Sariff	{ HDA_CODEC_STAC9220,  "Sigmatel STAC9220" },
473162922Sariff	{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
474165305Sariff	{ HDA_CODEC_STAC9227,  "Sigmatel STAC9227" },
475166796Sariff	{ HDA_CODEC_STAC9271D, "Sigmatel STAC9271D" },
476162922Sariff	{ HDA_CODEC_CXVENICE,  "Conexant Venice" },
477163057Sariff	{ HDA_CODEC_CXWAIKIKI, "Conexant Waikiki" },
478162922Sariff	/* Unknown codec */
479162922Sariff	{ HDA_CODEC_ALCXXXX,   "Realtek (Unknown)" },
480162922Sariff	{ HDA_CODEC_ADXXXX,    "Analog Device (Unknown)" },
481162922Sariff	{ HDA_CODEC_CMIXXXX,   "CMedia (Unknown)" },
482162922Sariff	{ HDA_CODEC_STACXXXX,  "Sigmatel (Unknown)" },
483162922Sariff	{ HDA_CODEC_CXXXXX,    "Conexant (Unknown)" },
484162922Sariff};
485162922Sariff#define HDAC_CODECS_LEN	(sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
486162922Sariff
487162922Sariffenum {
488162922Sariff	HDAC_HP_SWITCH_CTL,
489162922Sariff	HDAC_HP_SWITCH_CTRL
490162922Sariff};
491162922Sariff
492162922Sariffstatic const struct {
493162965Sariff	uint32_t model;
494162922Sariff	uint32_t id;
495162922Sariff	int type;
496165039Sariff	int inverted;
497162922Sariff	nid_t hpnid;
498162922Sariff	nid_t spkrnid[8];
499162922Sariff	nid_t eapdnid;
500162922Sariff} hdac_hp_switch[] = {
501162922Sariff	/* Specific OEM models */
502165039Sariff	{ HP_V3000_SUBVENDOR,  HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 0,
503162922Sariff	    17, { 16, -1 }, 16 },
504165039Sariff	{ HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0,
505162922Sariff	     6, {  5, -1 },  5 },
506165039Sariff	{ HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0,
507162922Sariff	     6, {  5, -1 },  5 },
508165281Sariff	{ HP_NX6325_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0,
509165281Sariff	     6, {  5, -1 },  5 },
510165770Sariff	{ TOSHIBA_U200_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0,
511165770Sariff	     6, {  5, -1 }, -1 },
512165039Sariff	{ DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0,
513162922Sariff	    13, { 14, -1 }, -1 },
514165039Sariff	{ DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0,
515162922Sariff	    13, { 14, -1 }, -1 },
516165039Sariff	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDAC_HP_SWITCH_CTRL, 0,
517164828Sariff	    10, { 13, -1 }, -1 },
518165039Sariff	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 1,
519165039Sariff	    26, { 27, -1 }, -1 },
520165281Sariff	{ LG_LW20_SUBVENDOR, HDA_CODEC_ALC880, HDAC_HP_SWITCH_CTL, 0,
521165281Sariff	    27, { 20, -1 }, -1 },
522165992Sariff	{ ACER_A5050_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0,
523165992Sariff	    20, { 21, -1 }, -1 },
524165992Sariff	{ MSI_MS1034_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0,
525165992Sariff	    20, { 27, -1 }, -1 },
526162922Sariff	/*
527162922Sariff	 * All models that at least come from the same vendor with
528162922Sariff	 * simmilar codec.
529162922Sariff	 */
530165039Sariff	{ HP_ALL_SUBVENDOR,  HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL, 0,
531162922Sariff	    17, { 16, -1 }, 16 },
532165039Sariff	{ HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0,
533162922Sariff	     6, {  5, -1 },  5 },
534165770Sariff	{ TOSHIBA_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL, 0,
535165770Sariff	     6, {  5, -1 },  -1 },
536165039Sariff	{ DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL, 0,
537162922Sariff	    13, { 14, -1 }, -1 },
538165039Sariff	{ LENOVO_ALL_SUBVENDOR, HDA_CODEC_AD1986A, HDAC_HP_SWITCH_CTL, 1,
539165039Sariff	    26, { 27, -1 }, -1 },
540166294Sariff#if 0
541165992Sariff	{ ACER_ALL_SUBVENDOR, HDA_CODEC_ALC883, HDAC_HP_SWITCH_CTL, 0,
542165992Sariff	    20, { 21, -1 }, -1 },
543166294Sariff#endif
544162922Sariff};
545162922Sariff#define HDAC_HP_SWITCH_LEN	\
546162922Sariff		(sizeof(hdac_hp_switch) / sizeof(hdac_hp_switch[0]))
547162922Sariff
548162922Sariffstatic const struct {
549162965Sariff	uint32_t model;
550162922Sariff	uint32_t id;
551162922Sariff	nid_t eapdnid;
552162922Sariff	int hp_switch;
553162922Sariff} hdac_eapd_switch[] = {
554162922Sariff	{ HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, 16, 1 },
555162922Sariff	{ HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
556162922Sariff	{ HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
557162922Sariff};
558162922Sariff#define HDAC_EAPD_SWITCH_LEN	\
559162922Sariff		(sizeof(hdac_eapd_switch) / sizeof(hdac_eapd_switch[0]))
560162922Sariff
561162922Sariff/****************************************************************************
562162922Sariff * Function prototypes
563162922Sariff ****************************************************************************/
564162922Sariffstatic void	hdac_intr_handler(void *);
565162922Sariffstatic int	hdac_reset(struct hdac_softc *);
566162922Sariffstatic int	hdac_get_capabilities(struct hdac_softc *);
567162922Sariffstatic void	hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
568162922Sariffstatic int	hdac_dma_alloc(struct hdac_softc *,
569162922Sariff					struct hdac_dma *, bus_size_t);
570162922Sariffstatic void	hdac_dma_free(struct hdac_dma *);
571162922Sariffstatic int	hdac_mem_alloc(struct hdac_softc *);
572162922Sariffstatic void	hdac_mem_free(struct hdac_softc *);
573162922Sariffstatic int	hdac_irq_alloc(struct hdac_softc *);
574162922Sariffstatic void	hdac_irq_free(struct hdac_softc *);
575162922Sariffstatic void	hdac_corb_init(struct hdac_softc *);
576162922Sariffstatic void	hdac_rirb_init(struct hdac_softc *);
577162922Sariffstatic void	hdac_corb_start(struct hdac_softc *);
578162922Sariffstatic void	hdac_rirb_start(struct hdac_softc *);
579162922Sariffstatic void	hdac_scan_codecs(struct hdac_softc *);
580162922Sariffstatic int	hdac_probe_codec(struct hdac_codec *);
581162922Sariffstatic struct	hdac_devinfo *hdac_probe_function(struct hdac_codec *, nid_t);
582162922Sariffstatic void	hdac_add_child(struct hdac_softc *, struct hdac_devinfo *);
583162922Sariff
584162922Sariffstatic void	hdac_attach2(void *);
585162922Sariff
586162922Sariffstatic uint32_t	hdac_command_sendone_internal(struct hdac_softc *,
587162922Sariff							uint32_t, int);
588162922Sariffstatic void	hdac_command_send_internal(struct hdac_softc *,
589162922Sariff					struct hdac_command_list *, int);
590162922Sariff
591162922Sariffstatic int	hdac_probe(device_t);
592162922Sariffstatic int	hdac_attach(device_t);
593162922Sariffstatic int	hdac_detach(device_t);
594162922Sariffstatic void	hdac_widget_connection_select(struct hdac_widget *, uint8_t);
595162922Sariffstatic void	hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
596162922Sariff						uint32_t, int, int);
597162922Sariffstatic struct	hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
598162922Sariff							nid_t, int, int);
599162922Sariffstatic void	hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
600162922Sariff				nid_t, nid_t, int, int, int, int, int, int);
601162922Sariffstatic int	hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *);
602162922Sariffstatic struct	hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
603162922Sariff
604164614Sariffstatic int	hdac_rirb_flush(struct hdac_softc *sc);
605164614Sariffstatic int	hdac_unsolq_flush(struct hdac_softc *sc);
606164614Sariff
607162922Sariff#define hdac_command(a1, a2, a3)	\
608162922Sariff		hdac_command_sendone_internal(a1, a2, a3)
609162922Sariff
610162922Sariff#define hdac_codec_id(d)						\
611162922Sariff		((uint32_t)((d == NULL) ? 0x00000000 :			\
612162922Sariff		((((uint32_t)(d)->vendor_id & 0x0000ffff) << 16) |	\
613162922Sariff		((uint32_t)(d)->device_id & 0x0000ffff))))
614162922Sariff
615162922Sariffstatic char *
616162922Sariffhdac_codec_name(struct hdac_devinfo *devinfo)
617162922Sariff{
618162922Sariff	uint32_t id;
619162922Sariff	int i;
620162922Sariff
621162922Sariff	id = hdac_codec_id(devinfo);
622162922Sariff
623162922Sariff	for (i = 0; i < HDAC_CODECS_LEN; i++) {
624163257Sariff		if (HDA_DEV_MATCH(hdac_codecs[i].id, id))
625162922Sariff			return (hdac_codecs[i].name);
626162922Sariff	}
627162922Sariff
628162922Sariff	return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec");
629162922Sariff}
630162922Sariff
631162922Sariffstatic char *
632162922Sariffhdac_audio_ctl_ossmixer_mask2name(uint32_t devmask)
633162922Sariff{
634162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
635162922Sariff	static char *unknown = "???";
636162922Sariff	int i;
637162922Sariff
638162922Sariff	for (i = SOUND_MIXER_NRDEVICES - 1; i >= 0; i--) {
639162922Sariff		if (devmask & (1 << i))
640162922Sariff			return (ossname[i]);
641162922Sariff	}
642162922Sariff	return (unknown);
643162922Sariff}
644162922Sariff
645162922Sariffstatic void
646162922Sariffhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
647162922Sariff{
648162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
649162922Sariff	int i, first = 1;
650162922Sariff
651162922Sariff	bzero(buf, len);
652162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
653162922Sariff		if (mask & (1 << i)) {
654162922Sariff			if (first == 0)
655162922Sariff				strlcat(buf, ", ", len);
656162922Sariff			strlcat(buf, ossname[i], len);
657162922Sariff			first = 0;
658162922Sariff		}
659162922Sariff	}
660162922Sariff}
661162922Sariff
662162922Sariffstatic struct hdac_audio_ctl *
663162922Sariffhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
664162922Sariff{
665162922Sariff	if (devinfo == NULL ||
666162922Sariff	    devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO ||
667162922Sariff	    index == NULL || devinfo->function.audio.ctl == NULL ||
668162922Sariff	    devinfo->function.audio.ctlcnt < 1 ||
669162922Sariff	    *index < 0 || *index >= devinfo->function.audio.ctlcnt)
670162922Sariff		return (NULL);
671162922Sariff	return (&devinfo->function.audio.ctl[(*index)++]);
672162922Sariff}
673162922Sariff
674162922Sariffstatic struct hdac_audio_ctl *
675162922Sariffhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid,
676162922Sariff						int index, int cnt)
677162922Sariff{
678162922Sariff	struct hdac_audio_ctl *ctl, *retctl = NULL;
679162922Sariff	int i, at, atindex, found = 0;
680162922Sariff
681162922Sariff	if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
682162922Sariff		return (NULL);
683162922Sariff
684162922Sariff	at = cnt;
685162922Sariff	if (at == 0)
686162922Sariff		at = 1;
687162922Sariff	else if (at < 0)
688162922Sariff		at = -1;
689162922Sariff	atindex = index;
690162922Sariff	if (atindex < 0)
691162922Sariff		atindex = -1;
692162922Sariff
693162922Sariff	i = 0;
694162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
695162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL)
696162922Sariff			continue;
697162922Sariff		if (!(ctl->widget->nid == nid && (atindex == -1 ||
698162922Sariff		    ctl->index == atindex)))
699162922Sariff			continue;
700162922Sariff		found++;
701162922Sariff		if (found == cnt)
702162922Sariff			return (ctl);
703162922Sariff		retctl = ctl;
704162922Sariff	}
705162922Sariff
706162922Sariff	return ((at == -1) ? retctl : NULL);
707162922Sariff}
708162922Sariff
709162922Sariffstatic void
710162922Sariffhdac_hp_switch_handler(struct hdac_devinfo *devinfo)
711162922Sariff{
712162922Sariff	struct hdac_softc *sc;
713162922Sariff	struct hdac_widget *w;
714162922Sariff	struct hdac_audio_ctl *ctl;
715162922Sariff	uint32_t id, res;
716162922Sariff	int i = 0, j, forcemute;
717162922Sariff	nid_t cad;
718162922Sariff
719162922Sariff	if (devinfo == NULL || devinfo->codec == NULL ||
720162922Sariff	    devinfo->codec->sc == NULL)
721162922Sariff		return;
722162922Sariff
723162922Sariff	sc = devinfo->codec->sc;
724162922Sariff	cad = devinfo->codec->cad;
725162922Sariff	id = hdac_codec_id(devinfo);
726162922Sariff	for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
727163257Sariff		if (HDA_DEV_MATCH(hdac_hp_switch[i].model,
728162965Sariff		    sc->pci_subvendor) &&
729162922Sariff		    hdac_hp_switch[i].id == id)
730162922Sariff			break;
731162922Sariff	}
732162922Sariff
733162922Sariff	if (i >= HDAC_HP_SWITCH_LEN)
734162922Sariff		return;
735162922Sariff
736162922Sariff	forcemute = 0;
737162922Sariff	if (hdac_hp_switch[i].eapdnid != -1) {
738162922Sariff		w = hdac_widget_get(devinfo, hdac_hp_switch[i].eapdnid);
739162965Sariff		if (w != NULL && w->param.eapdbtl != HDAC_INVALID)
740162922Sariff			forcemute = (w->param.eapdbtl &
741162922Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1;
742162922Sariff	}
743162922Sariff
744162922Sariff	res = hdac_command(sc,
745162922Sariff	    HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad);
746163057Sariff	HDA_BOOTVERBOSE(
747162922Sariff		device_printf(sc->dev,
748163057Sariff		    "HDA_DEBUG: Pin sense: nid=%d res=0x%08x\n",
749162922Sariff		    hdac_hp_switch[i].hpnid, res);
750162922Sariff	);
751162922Sariff	res >>= 31;
752165039Sariff	res ^= hdac_hp_switch[i].inverted;
753162922Sariff
754162922Sariff	switch (hdac_hp_switch[i].type) {
755162922Sariff	case HDAC_HP_SWITCH_CTL:
756162922Sariff		ctl = hdac_audio_ctl_amp_get(devinfo,
757162922Sariff		    hdac_hp_switch[i].hpnid, 0, 1);
758162922Sariff		if (ctl != NULL) {
759162922Sariff			ctl->muted = (res != 0 && forcemute == 0) ?
760162922Sariff			    HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL;
761162922Sariff			hdac_audio_ctl_amp_set(ctl,
762162922Sariff			    HDA_AMP_MUTE_DEFAULT, ctl->left,
763162922Sariff			    ctl->right);
764162922Sariff		}
765162922Sariff		for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
766162922Sariff			ctl = hdac_audio_ctl_amp_get(devinfo,
767162922Sariff			    hdac_hp_switch[i].spkrnid[j], 0, 1);
768162922Sariff			if (ctl != NULL) {
769162922Sariff				ctl->muted = (res != 0 || forcemute == 1) ?
770162922Sariff				    HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE;
771162922Sariff				hdac_audio_ctl_amp_set(ctl,
772162922Sariff				    HDA_AMP_MUTE_DEFAULT, ctl->left,
773162922Sariff				    ctl->right);
774162922Sariff			}
775162922Sariff		}
776162922Sariff		break;
777162922Sariff	case HDAC_HP_SWITCH_CTRL:
778162922Sariff		if (res != 0) {
779162922Sariff			/* HP in */
780162922Sariff			w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
781163057Sariff			if (w != NULL && w->type ==
782163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
783162922Sariff				if (forcemute == 0)
784162922Sariff					w->wclass.pin.ctrl |=
785162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
786162922Sariff				else
787162922Sariff					w->wclass.pin.ctrl &=
788162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
789162922Sariff				hdac_command(sc,
790162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
791162922Sariff				    w->wclass.pin.ctrl), cad);
792162922Sariff			}
793162922Sariff			for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
794162922Sariff				w = hdac_widget_get(devinfo,
795162922Sariff				    hdac_hp_switch[i].spkrnid[j]);
796163057Sariff				if (w != NULL && w->type ==
797163057Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
798162922Sariff					w->wclass.pin.ctrl &=
799162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
800162922Sariff					hdac_command(sc,
801162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
802162922Sariff					    w->nid,
803162922Sariff					    w->wclass.pin.ctrl), cad);
804162922Sariff				}
805162922Sariff			}
806162922Sariff		} else {
807162922Sariff			/* HP out */
808162922Sariff			w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
809163057Sariff			if (w != NULL && w->type ==
810163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
811162922Sariff				w->wclass.pin.ctrl &=
812162922Sariff				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
813162922Sariff				hdac_command(sc,
814162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
815162922Sariff				    w->wclass.pin.ctrl), cad);
816162922Sariff			}
817162922Sariff			for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
818162922Sariff				w = hdac_widget_get(devinfo,
819162922Sariff				    hdac_hp_switch[i].spkrnid[j]);
820163057Sariff				if (w != NULL && w->type ==
821163057Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
822162922Sariff					if (forcemute == 0)
823162922Sariff						w->wclass.pin.ctrl |=
824162922Sariff						    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
825162922Sariff					else
826162922Sariff						w->wclass.pin.ctrl &=
827162922Sariff						    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
828162922Sariff					hdac_command(sc,
829162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
830162922Sariff					    w->nid,
831162922Sariff					    w->wclass.pin.ctrl), cad);
832162922Sariff				}
833162922Sariff			}
834162922Sariff		}
835162922Sariff		break;
836162922Sariff	default:
837162922Sariff		break;
838162922Sariff	}
839162922Sariff}
840162922Sariff
841162922Sariffstatic void
842162922Sariffhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
843162922Sariff{
844162922Sariff	struct hdac_softc *sc;
845162922Sariff	struct hdac_devinfo *devinfo = NULL;
846162965Sariff	device_t *devlist = NULL;
847162922Sariff	int devcount, i;
848162922Sariff
849162922Sariff	if (codec == NULL || codec->sc == NULL)
850162922Sariff		return;
851162922Sariff
852162922Sariff	sc = codec->sc;
853162922Sariff
854163057Sariff	HDA_BOOTVERBOSE(
855163057Sariff		device_printf(sc->dev, "HDA_DEBUG: Unsol Tag: 0x%08x\n", tag);
856162922Sariff	);
857162922Sariff
858162922Sariff	device_get_children(sc->dev, &devlist, &devcount);
859162965Sariff	for (i = 0; devlist != NULL && i < devcount; i++) {
860162965Sariff		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
861162965Sariff		if (devinfo != NULL && devinfo->node_type ==
862162965Sariff		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
863162965Sariff		    devinfo->codec != NULL &&
864162965Sariff		    devinfo->codec->cad == codec->cad) {
865162965Sariff			break;
866162965Sariff		} else
867162965Sariff			devinfo = NULL;
868162922Sariff	}
869162965Sariff	if (devlist != NULL)
870162965Sariff		free(devlist, M_TEMP);
871162965Sariff
872162922Sariff	if (devinfo == NULL)
873162922Sariff		return;
874162922Sariff
875162922Sariff	switch (tag) {
876162922Sariff	case HDAC_UNSOLTAG_EVENT_HP:
877162922Sariff		hdac_hp_switch_handler(devinfo);
878162922Sariff		break;
879162922Sariff	default:
880162922Sariff		break;
881162922Sariff	}
882162922Sariff}
883162922Sariff
884164614Sariffstatic int
885162922Sariffhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
886162922Sariff{
887162922Sariff	/* XXX to be removed */
888162922Sariff#ifdef HDAC_INTR_EXTRA
889162922Sariff	uint32_t res;
890162922Sariff#endif
891162922Sariff
892162922Sariff	if (ch->blkcnt == 0)
893164614Sariff		return (0);
894162922Sariff
895162922Sariff	/* XXX to be removed */
896162922Sariff#ifdef HDAC_INTR_EXTRA
897162922Sariff	res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS);
898162922Sariff#endif
899162922Sariff
900162922Sariff	/* XXX to be removed */
901162922Sariff#ifdef HDAC_INTR_EXTRA
902163057Sariff	HDA_BOOTVERBOSE(
903163057Sariff		if (res & (HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE))
904163057Sariff			device_printf(sc->dev,
905163057Sariff			    "PCMDIR_%s intr triggered beyond stream boundary:"
906163057Sariff			    "%08x\n",
907163057Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
908163057Sariff	);
909162922Sariff#endif
910162922Sariff
911162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS,
912163057Sariff	    HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS );
913162922Sariff
914162922Sariff	/* XXX to be removed */
915162922Sariff#ifdef HDAC_INTR_EXTRA
916162922Sariff	if (res & HDAC_SDSTS_BCIS) {
917162922Sariff#endif
918164614Sariff		return (1);
919162922Sariff	/* XXX to be removed */
920162922Sariff#ifdef HDAC_INTR_EXTRA
921162922Sariff	}
922162922Sariff#endif
923164614Sariff
924164614Sariff	return (0);
925162922Sariff}
926162922Sariff
927162922Sariff/****************************************************************************
928162922Sariff * void hdac_intr_handler(void *)
929162922Sariff *
930162922Sariff * Interrupt handler. Processes interrupts received from the hdac.
931162922Sariff ****************************************************************************/
932162922Sariffstatic void
933162922Sariffhdac_intr_handler(void *context)
934162922Sariff{
935162922Sariff	struct hdac_softc *sc;
936162922Sariff	uint32_t intsts;
937162922Sariff	uint8_t rirbsts;
938164614Sariff	struct hdac_rirb *rirb_base;
939164614Sariff	uint32_t trigger = 0;
940162922Sariff
941162922Sariff	sc = (struct hdac_softc *)context;
942162922Sariff
943162922Sariff	hdac_lock(sc);
944164614Sariff	if (sc->polling != 0) {
945164614Sariff		hdac_unlock(sc);
946164614Sariff		return;
947164614Sariff	}
948162922Sariff	/* Do we have anything to do? */
949162922Sariff	intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
950163057Sariff	if (!HDA_FLAG_MATCH(intsts, HDAC_INTSTS_GIS)) {
951162922Sariff		hdac_unlock(sc);
952162922Sariff		return;
953162922Sariff	}
954162922Sariff
955162922Sariff	/* Was this a controller interrupt? */
956163057Sariff	if (HDA_FLAG_MATCH(intsts, HDAC_INTSTS_CIS)) {
957162922Sariff		rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
958162922Sariff		rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
959162922Sariff		/* Get as many responses that we can */
960163057Sariff		while (HDA_FLAG_MATCH(rirbsts, HDAC_RIRBSTS_RINTFL)) {
961164614Sariff			HDAC_WRITE_1(&sc->mem,
962164614Sariff			    HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
963164614Sariff			hdac_rirb_flush(sc);
964162922Sariff			rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
965162922Sariff		}
966162922Sariff		/* XXX to be removed */
967162922Sariff		/* Clear interrupt and exit */
968162922Sariff#ifdef HDAC_INTR_EXTRA
969162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS);
970162922Sariff#endif
971162922Sariff	}
972164614Sariff
973164614Sariff	hdac_unsolq_flush(sc);
974164614Sariff
975163057Sariff	if (intsts & HDAC_INTSTS_SIS_MASK) {
976164614Sariff		if ((intsts & (1 << sc->num_iss)) &&
977164614Sariff		    hdac_stream_intr(sc, &sc->play) != 0)
978164614Sariff			trigger |= 1;
979164614Sariff		if ((intsts & (1 << 0)) &&
980164614Sariff		    hdac_stream_intr(sc, &sc->rec) != 0)
981164614Sariff			trigger |= 2;
982162922Sariff		/* XXX to be removed */
983162922Sariff#ifdef HDAC_INTR_EXTRA
984164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts &
985164614Sariff		    HDAC_INTSTS_SIS_MASK);
986162922Sariff#endif
987162922Sariff	}
988162922Sariff
989164614Sariff	hdac_unlock(sc);
990162922Sariff
991164614Sariff	if (trigger & 1)
992164614Sariff		chn_intr(sc->play.c);
993164614Sariff	if (trigger & 2)
994164614Sariff		chn_intr(sc->rec.c);
995162922Sariff}
996162922Sariff
997162922Sariff/****************************************************************************
998163057Sariff * int hdac_reset(hdac_softc *)
999162922Sariff *
1000162922Sariff * Reset the hdac to a quiescent and known state.
1001162922Sariff ****************************************************************************/
1002162922Sariffstatic int
1003162922Sariffhdac_reset(struct hdac_softc *sc)
1004162922Sariff{
1005162922Sariff	uint32_t gctl;
1006162922Sariff	int count, i;
1007162922Sariff
1008162922Sariff	/*
1009162922Sariff	 * Stop all Streams DMA engine
1010162922Sariff	 */
1011162922Sariff	for (i = 0; i < sc->num_iss; i++)
1012162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
1013162922Sariff	for (i = 0; i < sc->num_oss; i++)
1014162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
1015162922Sariff	for (i = 0; i < sc->num_bss; i++)
1016162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
1017162922Sariff
1018162922Sariff	/*
1019162922Sariff	 * Stop Control DMA engines
1020162922Sariff	 */
1021162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
1022162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
1023162922Sariff
1024162922Sariff	/*
1025162922Sariff	 * Reset the controller. The reset must remain asserted for
1026162922Sariff	 * a minimum of 100us.
1027162922Sariff	 */
1028162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1029162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
1030162922Sariff	count = 10000;
1031162922Sariff	do {
1032162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1033162922Sariff		if (!(gctl & HDAC_GCTL_CRST))
1034162922Sariff			break;
1035162922Sariff		DELAY(10);
1036162922Sariff	} while	(--count);
1037162922Sariff	if (gctl & HDAC_GCTL_CRST) {
1038162922Sariff		device_printf(sc->dev, "Unable to put hdac in reset\n");
1039162922Sariff		return (ENXIO);
1040162922Sariff	}
1041162922Sariff	DELAY(100);
1042162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1043162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
1044162922Sariff	count = 10000;
1045162922Sariff	do {
1046162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
1047163057Sariff		if (gctl & HDAC_GCTL_CRST)
1048162922Sariff			break;
1049162922Sariff		DELAY(10);
1050162922Sariff	} while (--count);
1051162922Sariff	if (!(gctl & HDAC_GCTL_CRST)) {
1052162922Sariff		device_printf(sc->dev, "Device stuck in reset\n");
1053162922Sariff		return (ENXIO);
1054162922Sariff	}
1055162922Sariff
1056162922Sariff	/*
1057162922Sariff	 * Wait for codecs to finish their own reset sequence. The delay here
1058162922Sariff	 * should be of 250us but for some reasons, on it's not enough on my
1059162922Sariff	 * computer. Let's use twice as much as necessary to make sure that
1060162922Sariff	 * it's reset properly.
1061162922Sariff	 */
1062162922Sariff	DELAY(1000);
1063162922Sariff
1064162922Sariff	return (0);
1065162922Sariff}
1066162922Sariff
1067162922Sariff
1068162922Sariff/****************************************************************************
1069162922Sariff * int hdac_get_capabilities(struct hdac_softc *);
1070162922Sariff *
1071162922Sariff * Retreive the general capabilities of the hdac;
1072162922Sariff *	Number of Input Streams
1073162922Sariff *	Number of Output Streams
1074162922Sariff *	Number of bidirectional Streams
1075162922Sariff *	64bit ready
1076162922Sariff *	CORB and RIRB sizes
1077162922Sariff ****************************************************************************/
1078162922Sariffstatic int
1079162922Sariffhdac_get_capabilities(struct hdac_softc *sc)
1080162922Sariff{
1081162922Sariff	uint16_t gcap;
1082162922Sariff	uint8_t corbsize, rirbsize;
1083162922Sariff
1084162922Sariff	gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
1085162922Sariff	sc->num_iss = HDAC_GCAP_ISS(gcap);
1086162922Sariff	sc->num_oss = HDAC_GCAP_OSS(gcap);
1087162922Sariff	sc->num_bss = HDAC_GCAP_BSS(gcap);
1088162922Sariff
1089163057Sariff	sc->support_64bit = HDA_FLAG_MATCH(gcap, HDAC_GCAP_64OK);
1090162922Sariff
1091162922Sariff	corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
1092162922Sariff	if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
1093162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_256)
1094162922Sariff		sc->corb_size = 256;
1095162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
1096162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_16)
1097162922Sariff		sc->corb_size = 16;
1098162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
1099162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_2)
1100162922Sariff		sc->corb_size = 2;
1101162922Sariff	else {
1102162922Sariff		device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
1103162922Sariff		    __func__, corbsize);
1104162922Sariff		return (ENXIO);
1105162922Sariff	}
1106162922Sariff
1107162922Sariff	rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
1108162922Sariff	if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
1109162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_256)
1110162922Sariff		sc->rirb_size = 256;
1111162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
1112162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_16)
1113162922Sariff		sc->rirb_size = 16;
1114162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
1115162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_2)
1116162922Sariff		sc->rirb_size = 2;
1117162922Sariff	else {
1118162922Sariff		device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
1119162922Sariff		    __func__, rirbsize);
1120162922Sariff		return (ENXIO);
1121162922Sariff	}
1122162922Sariff
1123162922Sariff	return (0);
1124162922Sariff}
1125162922Sariff
1126162922Sariff
1127162922Sariff/****************************************************************************
1128162922Sariff * void hdac_dma_cb
1129162922Sariff *
1130162922Sariff * This function is called by bus_dmamap_load when the mapping has been
1131162922Sariff * established. We just record the physical address of the mapping into
1132162922Sariff * the struct hdac_dma passed in.
1133162922Sariff ****************************************************************************/
1134162922Sariffstatic void
1135162922Sariffhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
1136162922Sariff{
1137162922Sariff	struct hdac_dma *dma;
1138162922Sariff
1139162922Sariff	if (error == 0) {
1140162922Sariff		dma = (struct hdac_dma *)callback_arg;
1141162922Sariff		dma->dma_paddr = segs[0].ds_addr;
1142162922Sariff	}
1143162922Sariff}
1144162922Sariff
1145162922Sariffstatic void
1146162922Sariffhdac_dma_nocache(void *ptr)
1147162922Sariff{
1148167609Sariff#if 0
1149162956Sariff#if defined(__i386__) || defined(__amd64__)
1150162922Sariff	pt_entry_t *pte;
1151162922Sariff	vm_offset_t va;
1152162922Sariff
1153162922Sariff	va = (vm_offset_t)ptr;
1154162922Sariff	pte = vtopte(va);
1155162922Sariff	if (pte)  {
1156162922Sariff		*pte |= PG_N;
1157162922Sariff		invltlb();
1158162922Sariff	}
1159162956Sariff#endif
1160167609Sariff#endif
1161162922Sariff}
1162162922Sariff
1163162922Sariff/****************************************************************************
1164162922Sariff * int hdac_dma_alloc
1165162922Sariff *
1166162922Sariff * This function allocate and setup a dma region (struct hdac_dma).
1167162922Sariff * It must be freed by a corresponding hdac_dma_free.
1168162922Sariff ****************************************************************************/
1169162922Sariffstatic int
1170162922Sariffhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
1171162922Sariff{
1172162922Sariff	int result;
1173162922Sariff	int lowaddr;
1174162922Sariff
1175162922Sariff	lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR :
1176162922Sariff	    BUS_SPACE_MAXADDR_32BIT;
1177162922Sariff	bzero(dma, sizeof(*dma));
1178162922Sariff
1179162922Sariff	/*
1180162922Sariff	 * Create a DMA tag
1181162922Sariff	 */
1182162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
1183162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
1184162922Sariff	    0,					/* boundary */
1185162922Sariff	    lowaddr,				/* lowaddr */
1186162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
1187162922Sariff	    NULL,				/* filtfunc */
1188162922Sariff	    NULL,				/* fistfuncarg */
1189162922Sariff	    size, 				/* maxsize */
1190162922Sariff	    1,					/* nsegments */
1191162922Sariff	    size, 				/* maxsegsz */
1192162922Sariff	    0,					/* flags */
1193162922Sariff	    NULL,				/* lockfunc */
1194162922Sariff	    NULL,				/* lockfuncarg */
1195162922Sariff	    &dma->dma_tag);			/* dmat */
1196162922Sariff	if (result != 0) {
1197162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
1198162922Sariff		    __func__, result);
1199162922Sariff		goto fail;
1200162922Sariff	}
1201162922Sariff
1202162922Sariff	/*
1203162922Sariff	 * Allocate DMA memory
1204162922Sariff	 */
1205162965Sariff	result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
1206162922Sariff	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
1207162922Sariff	if (result != 0) {
1208162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n",
1209162922Sariff		    __func__, result);
1210162922Sariff		goto fail;
1211162922Sariff	}
1212162922Sariff
1213162922Sariff	/*
1214162922Sariff	 * Map the memory
1215162922Sariff	 */
1216162922Sariff	result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
1217162922Sariff	    (void *)dma->dma_vaddr, size, hdac_dma_cb, (void *)dma,
1218162922Sariff	    BUS_DMA_NOWAIT);
1219162922Sariff	if (result != 0 || dma->dma_paddr == 0) {
1220162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n",
1221162922Sariff		    __func__, result);
1222162922Sariff		goto fail;
1223162922Sariff	}
1224162922Sariff	bzero((void *)dma->dma_vaddr, size);
1225162922Sariff	hdac_dma_nocache(dma->dma_vaddr);
1226162922Sariff
1227162922Sariff	return (0);
1228162922Sarifffail:
1229162922Sariff	if (dma->dma_map != NULL)
1230162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1231162922Sariff	if (dma->dma_tag != NULL)
1232162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1233162922Sariff	return (result);
1234162922Sariff}
1235162922Sariff
1236162922Sariff
1237162922Sariff/****************************************************************************
1238162922Sariff * void hdac_dma_free(struct hdac_dma *)
1239162922Sariff *
1240162922Sariff * Free a struct dhac_dma that has been previously allocated via the
1241162922Sariff * hdac_dma_alloc function.
1242162922Sariff ****************************************************************************/
1243162922Sariffstatic void
1244162922Sariffhdac_dma_free(struct hdac_dma *dma)
1245162922Sariff{
1246162922Sariff	if (dma->dma_tag != NULL) {
1247162922Sariff		/* Flush caches */
1248162922Sariff		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
1249162922Sariff		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1250162922Sariff		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1251162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1252162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1253162922Sariff	}
1254162922Sariff}
1255162922Sariff
1256162922Sariff/****************************************************************************
1257162922Sariff * int hdac_mem_alloc(struct hdac_softc *)
1258162922Sariff *
1259162922Sariff * Allocate all the bus resources necessary to speak with the physical
1260162922Sariff * controller.
1261162922Sariff ****************************************************************************/
1262162922Sariffstatic int
1263162922Sariffhdac_mem_alloc(struct hdac_softc *sc)
1264162922Sariff{
1265162922Sariff	struct hdac_mem *mem;
1266162922Sariff
1267162922Sariff	mem = &sc->mem;
1268162922Sariff	mem->mem_rid = PCIR_BAR(0);
1269162922Sariff	mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1270162922Sariff	    &mem->mem_rid, RF_ACTIVE);
1271162922Sariff	if (mem->mem_res == NULL) {
1272162922Sariff		device_printf(sc->dev,
1273162922Sariff		    "%s: Unable to allocate memory resource\n", __func__);
1274162922Sariff		return (ENOMEM);
1275162922Sariff	}
1276162922Sariff	mem->mem_tag = rman_get_bustag(mem->mem_res);
1277162922Sariff	mem->mem_handle = rman_get_bushandle(mem->mem_res);
1278162922Sariff
1279162922Sariff	return (0);
1280162922Sariff}
1281162922Sariff
1282162922Sariff/****************************************************************************
1283162922Sariff * void hdac_mem_free(struct hdac_softc *)
1284162922Sariff *
1285162922Sariff * Free up resources previously allocated by hdac_mem_alloc.
1286162922Sariff ****************************************************************************/
1287162922Sariffstatic void
1288162922Sariffhdac_mem_free(struct hdac_softc *sc)
1289162922Sariff{
1290162922Sariff	struct hdac_mem *mem;
1291162922Sariff
1292162922Sariff	mem = &sc->mem;
1293162922Sariff	if (mem->mem_res != NULL)
1294162922Sariff		bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
1295162922Sariff		    mem->mem_res);
1296164614Sariff	mem->mem_res = NULL;
1297162922Sariff}
1298162922Sariff
1299162922Sariff/****************************************************************************
1300162922Sariff * int hdac_irq_alloc(struct hdac_softc *)
1301162922Sariff *
1302162922Sariff * Allocate and setup the resources necessary for interrupt handling.
1303162922Sariff ****************************************************************************/
1304162922Sariffstatic int
1305162922Sariffhdac_irq_alloc(struct hdac_softc *sc)
1306162922Sariff{
1307162922Sariff	struct hdac_irq *irq;
1308162922Sariff	int result;
1309162922Sariff
1310162922Sariff	irq = &sc->irq;
1311162922Sariff	irq->irq_rid = 0x0;
1312162922Sariff	irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1313162922Sariff	    &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
1314162922Sariff	if (irq->irq_res == NULL) {
1315162922Sariff		device_printf(sc->dev, "%s: Unable to allocate irq\n",
1316162922Sariff		    __func__);
1317162922Sariff		goto fail;
1318162922Sariff	}
1319162922Sariff	result = snd_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE,
1320164614Sariff	    hdac_intr_handler, sc, &irq->irq_handle);
1321162922Sariff	if (result != 0) {
1322162922Sariff		device_printf(sc->dev,
1323162922Sariff		    "%s: Unable to setup interrupt handler (%x)\n",
1324162922Sariff		    __func__, result);
1325162922Sariff		goto fail;
1326162922Sariff	}
1327162922Sariff
1328162922Sariff	return (0);
1329162922Sariff
1330162922Sarifffail:
1331164614Sariff	hdac_irq_free(sc);
1332164614Sariff
1333162922Sariff	return (ENXIO);
1334162922Sariff}
1335162922Sariff
1336162922Sariff/****************************************************************************
1337162922Sariff * void hdac_irq_free(struct hdac_softc *)
1338162922Sariff *
1339162922Sariff * Free up resources previously allocated by hdac_irq_alloc.
1340162922Sariff ****************************************************************************/
1341162922Sariffstatic void
1342162922Sariffhdac_irq_free(struct hdac_softc *sc)
1343162922Sariff{
1344162922Sariff	struct hdac_irq *irq;
1345162922Sariff
1346162922Sariff	irq = &sc->irq;
1347164614Sariff	if (irq->irq_res != NULL && irq->irq_handle != NULL)
1348162922Sariff		bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
1349162922Sariff	if (irq->irq_res != NULL)
1350162922Sariff		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1351162922Sariff		    irq->irq_res);
1352164614Sariff	irq->irq_handle = NULL;
1353164614Sariff	irq->irq_res = NULL;
1354162922Sariff}
1355162922Sariff
1356162922Sariff/****************************************************************************
1357162922Sariff * void hdac_corb_init(struct hdac_softc *)
1358162922Sariff *
1359162922Sariff * Initialize the corb registers for operations but do not start it up yet.
1360162922Sariff * The CORB engine must not be running when this function is called.
1361162922Sariff ****************************************************************************/
1362162922Sariffstatic void
1363162922Sariffhdac_corb_init(struct hdac_softc *sc)
1364162922Sariff{
1365162922Sariff	uint8_t corbsize;
1366162922Sariff	uint64_t corbpaddr;
1367162922Sariff
1368162922Sariff	/* Setup the CORB size. */
1369162922Sariff	switch (sc->corb_size) {
1370162922Sariff	case 256:
1371162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
1372162922Sariff		break;
1373162922Sariff	case 16:
1374162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
1375162922Sariff		break;
1376162922Sariff	case 2:
1377162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
1378162922Sariff		break;
1379162922Sariff	default:
1380162922Sariff		panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
1381162922Sariff	}
1382162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
1383162922Sariff
1384162922Sariff	/* Setup the CORB Address in the hdac */
1385162922Sariff	corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
1386162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
1387162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
1388162922Sariff
1389162922Sariff	/* Set the WP and RP */
1390162922Sariff	sc->corb_wp = 0;
1391162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
1392162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
1393162922Sariff	/*
1394162922Sariff	 * The HDA specification indicates that the CORBRPRST bit will always
1395162922Sariff	 * read as zero. Unfortunately, it seems that at least the 82801G
1396162922Sariff	 * doesn't reset the bit to zero, which stalls the corb engine.
1397162922Sariff	 * manually reset the bit to zero before continuing.
1398162922Sariff	 */
1399162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
1400162922Sariff
1401162922Sariff	/* Enable CORB error reporting */
1402162922Sariff#if 0
1403162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
1404162922Sariff#endif
1405162922Sariff}
1406162922Sariff
1407162922Sariff/****************************************************************************
1408162922Sariff * void hdac_rirb_init(struct hdac_softc *)
1409162922Sariff *
1410162922Sariff * Initialize the rirb registers for operations but do not start it up yet.
1411162922Sariff * The RIRB engine must not be running when this function is called.
1412162922Sariff ****************************************************************************/
1413162922Sariffstatic void
1414162922Sariffhdac_rirb_init(struct hdac_softc *sc)
1415162922Sariff{
1416162922Sariff	uint8_t rirbsize;
1417162922Sariff	uint64_t rirbpaddr;
1418162922Sariff
1419162922Sariff	/* Setup the RIRB size. */
1420162922Sariff	switch (sc->rirb_size) {
1421162922Sariff	case 256:
1422162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
1423162922Sariff		break;
1424162922Sariff	case 16:
1425162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
1426162922Sariff		break;
1427162922Sariff	case 2:
1428162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
1429162922Sariff		break;
1430162922Sariff	default:
1431162922Sariff		panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
1432162922Sariff	}
1433162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
1434162922Sariff
1435162922Sariff	/* Setup the RIRB Address in the hdac */
1436162922Sariff	rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
1437162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
1438162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
1439162922Sariff
1440162922Sariff	/* Setup the WP and RP */
1441162922Sariff	sc->rirb_rp = 0;
1442162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
1443162922Sariff
1444164614Sariff	if (sc->polling == 0) {
1445164614Sariff		/* Setup the interrupt threshold */
1446164614Sariff		HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
1447162922Sariff
1448164614Sariff		/* Enable Overrun and response received reporting */
1449162922Sariff#if 0
1450164614Sariff		HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
1451164614Sariff		    HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
1452162922Sariff#else
1453164614Sariff		HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
1454162922Sariff#endif
1455164614Sariff	}
1456162922Sariff
1457162922Sariff	/*
1458162922Sariff	 * Make sure that the Host CPU cache doesn't contain any dirty
1459162922Sariff	 * cache lines that falls in the rirb. If I understood correctly, it
1460162922Sariff	 * should be sufficient to do this only once as the rirb is purely
1461162922Sariff	 * read-only from now on.
1462162922Sariff	 */
1463162922Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
1464162922Sariff	    BUS_DMASYNC_PREREAD);
1465162922Sariff}
1466162922Sariff
1467162922Sariff/****************************************************************************
1468162922Sariff * void hdac_corb_start(hdac_softc *)
1469162922Sariff *
1470162922Sariff * Startup the corb DMA engine
1471162922Sariff ****************************************************************************/
1472162922Sariffstatic void
1473162922Sariffhdac_corb_start(struct hdac_softc *sc)
1474162922Sariff{
1475162922Sariff	uint32_t corbctl;
1476162922Sariff
1477162922Sariff	corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
1478162922Sariff	corbctl |= HDAC_CORBCTL_CORBRUN;
1479162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
1480162922Sariff}
1481162922Sariff
1482162922Sariff/****************************************************************************
1483162922Sariff * void hdac_rirb_start(hdac_softc *)
1484162922Sariff *
1485162922Sariff * Startup the rirb DMA engine
1486162922Sariff ****************************************************************************/
1487162922Sariffstatic void
1488162922Sariffhdac_rirb_start(struct hdac_softc *sc)
1489162922Sariff{
1490162922Sariff	uint32_t rirbctl;
1491162922Sariff
1492162922Sariff	rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
1493162922Sariff	rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
1494162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
1495162922Sariff}
1496162922Sariff
1497162922Sariff
1498162922Sariff/****************************************************************************
1499162922Sariff * void hdac_scan_codecs(struct hdac_softc *)
1500162922Sariff *
1501162922Sariff * Scan the bus for available codecs.
1502162922Sariff ****************************************************************************/
1503162922Sariffstatic void
1504162922Sariffhdac_scan_codecs(struct hdac_softc *sc)
1505162922Sariff{
1506162922Sariff	struct hdac_codec *codec;
1507162922Sariff	int i;
1508162922Sariff	uint16_t statests;
1509162922Sariff
1510162922Sariff	statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
1511162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++) {
1512162922Sariff		if (HDAC_STATESTS_SDIWAKE(statests, i)) {
1513162922Sariff			/* We have found a codec. */
1514162922Sariff			hdac_unlock(sc);
1515162922Sariff			codec = (struct hdac_codec *)malloc(sizeof(*codec),
1516162922Sariff			    M_HDAC, M_ZERO | M_NOWAIT);
1517162922Sariff			hdac_lock(sc);
1518162922Sariff			if (codec == NULL) {
1519162922Sariff				device_printf(sc->dev,
1520162922Sariff				    "Unable to allocate memory for codec\n");
1521162922Sariff				continue;
1522162922Sariff			}
1523164614Sariff			codec->commands = NULL;
1524164614Sariff			codec->responses_received = 0;
1525162922Sariff			codec->verbs_sent = 0;
1526162922Sariff			codec->sc = sc;
1527162922Sariff			codec->cad = i;
1528162922Sariff			sc->codecs[i] = codec;
1529162922Sariff			if (hdac_probe_codec(codec) != 0)
1530162922Sariff				break;
1531162922Sariff		}
1532162922Sariff	}
1533162922Sariff	/* All codecs have been probed, now try to attach drivers to them */
1534163057Sariff	/* bus_generic_attach(sc->dev); */
1535162922Sariff}
1536162922Sariff
1537162922Sariff/****************************************************************************
1538162922Sariff * void hdac_probe_codec(struct hdac_softc *, int)
1539162922Sariff *
1540162922Sariff * Probe a the given codec_id for available function groups.
1541162922Sariff ****************************************************************************/
1542162922Sariffstatic int
1543162922Sariffhdac_probe_codec(struct hdac_codec *codec)
1544162922Sariff{
1545162922Sariff	struct hdac_softc *sc = codec->sc;
1546162922Sariff	struct hdac_devinfo *devinfo;
1547162922Sariff	uint32_t vendorid, revisionid, subnode;
1548162922Sariff	int startnode;
1549162922Sariff	int endnode;
1550162922Sariff	int i;
1551162922Sariff	nid_t cad = codec->cad;
1552162922Sariff
1553163057Sariff	HDA_BOOTVERBOSE(
1554163057Sariff		device_printf(sc->dev, "HDA_DEBUG: Probing codec: %d\n", cad);
1555162922Sariff	);
1556162922Sariff	vendorid = hdac_command(sc,
1557162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
1558162922Sariff	    cad);
1559162922Sariff	revisionid = hdac_command(sc,
1560162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
1561162922Sariff	    cad);
1562162922Sariff	subnode = hdac_command(sc,
1563162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
1564162922Sariff	    cad);
1565162922Sariff	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
1566162922Sariff	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
1567162922Sariff
1568163057Sariff	HDA_BOOTVERBOSE(
1569163057Sariff		device_printf(sc->dev, "HDA_DEBUG: \tstartnode=%d endnode=%d\n",
1570163057Sariff		    startnode, endnode);
1571162922Sariff	);
1572162922Sariff	for (i = startnode; i < endnode; i++) {
1573162922Sariff		devinfo = hdac_probe_function(codec, i);
1574162922Sariff		if (devinfo != NULL) {
1575162922Sariff			/* XXX Ignore other FG. */
1576162922Sariff			devinfo->vendor_id =
1577162922Sariff			    HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
1578162922Sariff			devinfo->device_id =
1579162922Sariff			    HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
1580162922Sariff			devinfo->revision_id =
1581162922Sariff			    HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
1582162922Sariff			devinfo->stepping_id =
1583162922Sariff			    HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
1584163057Sariff			HDA_BOOTVERBOSE(
1585162922Sariff				device_printf(sc->dev,
1586163057Sariff				    "HDA_DEBUG: \tFound AFG nid=%d "
1587162922Sariff				    "[startnode=%d endnode=%d]\n",
1588163057Sariff				    devinfo->nid, startnode, endnode);
1589162922Sariff			);
1590162922Sariff			return (1);
1591162922Sariff		}
1592162922Sariff	}
1593162922Sariff
1594163057Sariff	HDA_BOOTVERBOSE(
1595163057Sariff		device_printf(sc->dev, "HDA_DEBUG: \tAFG not found\n");
1596162922Sariff	);
1597162922Sariff	return (0);
1598162922Sariff}
1599162922Sariff
1600162922Sariffstatic struct hdac_devinfo *
1601162922Sariffhdac_probe_function(struct hdac_codec *codec, nid_t nid)
1602162922Sariff{
1603162922Sariff	struct hdac_softc *sc = codec->sc;
1604162922Sariff	struct hdac_devinfo *devinfo;
1605162922Sariff	uint32_t fctgrptype;
1606162922Sariff	nid_t cad = codec->cad;
1607162922Sariff
1608162965Sariff	fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
1609162965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
1610162922Sariff
1611162922Sariff	/* XXX For now, ignore other FG. */
1612162965Sariff	if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
1613162922Sariff		return (NULL);
1614162922Sariff
1615162922Sariff	hdac_unlock(sc);
1616162922Sariff	devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC,
1617162922Sariff	    M_NOWAIT | M_ZERO);
1618162922Sariff	hdac_lock(sc);
1619162922Sariff	if (devinfo == NULL) {
1620162922Sariff		device_printf(sc->dev, "%s: Unable to allocate ivar\n",
1621162922Sariff		    __func__);
1622162922Sariff		return (NULL);
1623162922Sariff	}
1624162922Sariff
1625162922Sariff	devinfo->nid = nid;
1626162965Sariff	devinfo->node_type = fctgrptype;
1627162922Sariff	devinfo->codec = codec;
1628162922Sariff
1629162922Sariff	hdac_add_child(sc, devinfo);
1630162922Sariff
1631162922Sariff	return (devinfo);
1632162922Sariff}
1633162922Sariff
1634162922Sariffstatic void
1635162922Sariffhdac_add_child(struct hdac_softc *sc, struct hdac_devinfo *devinfo)
1636162922Sariff{
1637162922Sariff	devinfo->dev = device_add_child(sc->dev, NULL, -1);
1638162922Sariff	device_set_ivars(devinfo->dev, (void *)devinfo);
1639162922Sariff	/* XXX - Print more information when booting verbose??? */
1640162922Sariff}
1641162922Sariff
1642162922Sariffstatic void
1643162922Sariffhdac_widget_connection_parse(struct hdac_widget *w)
1644162922Sariff{
1645162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1646162922Sariff	uint32_t res;
1647162922Sariff	int i, j, max, found, entnum, cnid;
1648162922Sariff	nid_t cad = w->devinfo->codec->cad;
1649162922Sariff	nid_t nid = w->nid;
1650162922Sariff
1651162922Sariff	res = hdac_command(sc,
1652162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad);
1653162922Sariff
1654162922Sariff	w->nconns = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res);
1655162922Sariff
1656162922Sariff	if (w->nconns < 1)
1657162922Sariff		return;
1658162922Sariff
1659162922Sariff	entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4;
1660162922Sariff	res = 0;
1661162922Sariff	i = 0;
1662162922Sariff	found = 0;
1663162922Sariff	max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1;
1664162922Sariff
1665162922Sariff	while (i < w->nconns) {
1666162922Sariff		res = hdac_command(sc,
1667162922Sariff		    HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad);
1668162922Sariff		for (j = 0; j < entnum; j++) {
1669162922Sariff			cnid = res;
1670162922Sariff			cnid >>= (32 / entnum) * j;
1671162922Sariff			cnid &= (1 << (32 / entnum)) - 1;
1672162922Sariff			if (cnid == 0)
1673162922Sariff				continue;
1674162922Sariff			if (found > max) {
1675162922Sariff				device_printf(sc->dev,
1676162922Sariff				    "node %d: Adding %d: "
1677162922Sariff				    "Max connection reached!\n",
1678162922Sariff				    nid, cnid);
1679162922Sariff				continue;
1680162922Sariff			}
1681162922Sariff			w->conns[found++] = cnid;
1682162922Sariff		}
1683162922Sariff		i += entnum;
1684162922Sariff	}
1685162922Sariff
1686163057Sariff	HDA_BOOTVERBOSE(
1687162922Sariff		if (w->nconns != found) {
1688162922Sariff			device_printf(sc->dev,
1689163057Sariff			    "HDA_DEBUG: nid=%d WARNING!!! Connection "
1690162922Sariff			    "length=%d != found=%d\n",
1691162922Sariff			    nid, w->nconns, found);
1692162922Sariff		}
1693162922Sariff	);
1694162922Sariff}
1695162922Sariff
1696162922Sariffstatic uint32_t
1697162922Sariffhdac_widget_pin_getconfig(struct hdac_widget *w)
1698162922Sariff{
1699162922Sariff	struct hdac_softc *sc;
1700166965Sariff	uint32_t config, orig, id;
1701162922Sariff	nid_t cad, nid;
1702162922Sariff
1703162922Sariff	sc = w->devinfo->codec->sc;
1704162922Sariff	cad = w->devinfo->codec->cad;
1705162922Sariff	nid = w->nid;
1706162922Sariff	id = hdac_codec_id(w->devinfo);
1707162922Sariff
1708162922Sariff	config = hdac_command(sc,
1709162922Sariff	    HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
1710162922Sariff	    cad);
1711166965Sariff	orig = config;
1712166965Sariff
1713162965Sariff	/*
1714162965Sariff	 * XXX REWRITE!!!! Don't argue!
1715162965Sariff	 */
1716165281Sariff	if (id == HDA_CODEC_ALC880 && sc->pci_subvendor == LG_LW20_SUBVENDOR) {
1717165281Sariff		switch (nid) {
1718165281Sariff		case 26:
1719165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1720165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1721165281Sariff			break;
1722165281Sariff		case 27:
1723165281Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1724165281Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
1725165281Sariff			break;
1726167610Sariff		default:
1727167610Sariff			break;
1728165281Sariff		}
1729165281Sariff	} else if (id == HDA_CODEC_ALC880 &&
1730162965Sariff	    (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR ||
1731162965Sariff	    sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) {
1732162922Sariff		/*
1733162965Sariff		 * Super broken BIOS
1734162922Sariff		 */
1735162922Sariff		switch (nid) {
1736162922Sariff		case 20:
1737162922Sariff			break;
1738162922Sariff		case 21:
1739162922Sariff			break;
1740162922Sariff		case 22:
1741162922Sariff			break;
1742162922Sariff		case 23:
1743162922Sariff			break;
1744162922Sariff		case 24:	/* MIC1 */
1745162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1746162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
1747162922Sariff			break;
1748162922Sariff		case 25:	/* XXX MIC2 */
1749162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1750162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
1751162922Sariff			break;
1752162922Sariff		case 26:	/* LINE1 */
1753162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1754162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1755162922Sariff			break;
1756162922Sariff		case 27:	/* XXX LINE2 */
1757162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1758162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1759162922Sariff			break;
1760162922Sariff		case 28:	/* CD */
1761162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1762162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
1763162922Sariff			break;
1764162922Sariff		case 30:
1765162922Sariff			break;
1766162922Sariff		case 31:
1767162922Sariff			break;
1768162922Sariff		default:
1769162922Sariff			break;
1770162922Sariff		}
1771166965Sariff	} else if (id == HDA_CODEC_ALC883 &&
1772166965Sariff	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, sc->pci_subvendor)) {
1773166965Sariff		switch (nid) {
1774166965Sariff		case 25:
1775166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
1776166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
1777166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
1778166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
1779166965Sariff			break;
1780166965Sariff		default:
1781166965Sariff			break;
1782166965Sariff		}
1783166965Sariff	} else if (id == HDA_CODEC_CXVENICE && sc->pci_subvendor ==
1784166965Sariff	    HP_V3000_SUBVENDOR) {
1785166965Sariff		switch (nid) {
1786166965Sariff		case 18:
1787166965Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
1788166965Sariff			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
1789166965Sariff			break;
1790166965Sariff		case 20:
1791166965Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
1792166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
1793166965Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
1794166965Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
1795166965Sariff			break;
1796167454Sariff		case 21:
1797167454Sariff			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
1798167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
1799167454Sariff			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
1800167454Sariff			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
1801167454Sariff			break;
1802166965Sariff		default:
1803166965Sariff			break;
1804166965Sariff		}
1805162922Sariff	}
1806162922Sariff
1807166965Sariff	HDA_BOOTVERBOSE(
1808166965Sariff		if (config != orig)
1809166965Sariff			device_printf(sc->dev,
1810166965Sariff			    "HDA_DEBUG: Pin config nid=%u 0x%08x -> 0x%08x\n",
1811166965Sariff			    nid, orig, config);
1812166965Sariff	);
1813166965Sariff
1814162922Sariff	return (config);
1815162922Sariff}
1816162922Sariff
1817166965Sariffstatic uint32_t
1818166965Sariffhdac_widget_pin_getcaps(struct hdac_widget *w)
1819166965Sariff{
1820166965Sariff	struct hdac_softc *sc;
1821166965Sariff	uint32_t caps, orig, id;
1822166965Sariff	nid_t cad, nid;
1823166965Sariff
1824166965Sariff	sc = w->devinfo->codec->sc;
1825166965Sariff	cad = w->devinfo->codec->cad;
1826166965Sariff	nid = w->nid;
1827166965Sariff	id = hdac_codec_id(w->devinfo);
1828166965Sariff
1829166965Sariff	caps = hdac_command(sc,
1830166965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
1831166965Sariff	orig = caps;
1832166965Sariff
1833166965Sariff	HDA_BOOTVERBOSE(
1834166965Sariff		if (caps != orig)
1835166965Sariff			device_printf(sc->dev,
1836166965Sariff			    "HDA_DEBUG: Pin caps nid=%u 0x%08x -> 0x%08x\n",
1837166965Sariff			    nid, orig, caps);
1838166965Sariff	);
1839166965Sariff
1840166965Sariff	return (caps);
1841166965Sariff}
1842166965Sariff
1843162922Sariffstatic void
1844162922Sariffhdac_widget_pin_parse(struct hdac_widget *w)
1845162922Sariff{
1846162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1847162922Sariff	uint32_t config, pincap;
1848162922Sariff	char *devstr, *connstr;
1849162922Sariff	nid_t cad = w->devinfo->codec->cad;
1850162922Sariff	nid_t nid = w->nid;
1851162922Sariff
1852162922Sariff	config = hdac_widget_pin_getconfig(w);
1853162922Sariff	w->wclass.pin.config = config;
1854162922Sariff
1855166965Sariff	pincap = hdac_widget_pin_getcaps(w);
1856162922Sariff	w->wclass.pin.cap = pincap;
1857162922Sariff
1858162922Sariff	w->wclass.pin.ctrl = hdac_command(sc,
1859164614Sariff	    HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) &
1860164614Sariff	    ~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
1861164614Sariff	    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
1862164614Sariff	    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE);
1863162922Sariff
1864162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
1865162922Sariff		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
1866162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
1867162922Sariff		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1868162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
1869162922Sariff		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
1870162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
1871162922Sariff		w->param.eapdbtl = hdac_command(sc,
1872162922Sariff		    HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
1873162922Sariff		w->param.eapdbtl &= 0x7;
1874162922Sariff		w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
1875162922Sariff	} else
1876162965Sariff		w->param.eapdbtl = HDAC_INVALID;
1877162922Sariff
1878162922Sariff	switch (config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
1879162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
1880162922Sariff		devstr = "line out";
1881162922Sariff		break;
1882162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
1883162922Sariff		devstr = "speaker";
1884162922Sariff		break;
1885162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
1886162922Sariff		devstr = "headphones out";
1887162922Sariff		break;
1888162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
1889162922Sariff		devstr = "CD";
1890162922Sariff		break;
1891162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
1892162922Sariff		devstr = "SPDIF out";
1893162922Sariff		break;
1894162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
1895162922Sariff		devstr = "digital (other) out";
1896162922Sariff		break;
1897162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE:
1898162922Sariff		devstr = "modem, line side";
1899162922Sariff		break;
1900162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET:
1901162922Sariff		devstr = "modem, handset side";
1902162922Sariff		break;
1903162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
1904162922Sariff		devstr = "line in";
1905162922Sariff		break;
1906162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
1907162922Sariff		devstr = "AUX";
1908162922Sariff		break;
1909162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
1910162922Sariff		devstr = "Mic in";
1911162922Sariff		break;
1912162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY:
1913162922Sariff		devstr = "telephony";
1914162922Sariff		break;
1915162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
1916162922Sariff		devstr = "SPDIF in";
1917162922Sariff		break;
1918162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
1919162922Sariff		devstr = "digital (other) in";
1920162922Sariff		break;
1921162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER:
1922162922Sariff		devstr = "other";
1923162922Sariff		break;
1924162922Sariff	default:
1925162922Sariff		devstr = "unknown";
1926162922Sariff		break;
1927162922Sariff	}
1928162922Sariff
1929162922Sariff	switch (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) {
1930162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK:
1931162922Sariff		connstr = "jack";
1932162922Sariff		break;
1933162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE:
1934162922Sariff		connstr = "none";
1935162922Sariff		break;
1936162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED:
1937162922Sariff		connstr = "fixed";
1938162922Sariff		break;
1939162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH:
1940162922Sariff		connstr = "jack / fixed";
1941162922Sariff		break;
1942162922Sariff	default:
1943162922Sariff		connstr = "unknown";
1944162922Sariff		break;
1945162922Sariff	}
1946162922Sariff
1947162922Sariff	strlcat(w->name, ": ", sizeof(w->name));
1948162922Sariff	strlcat(w->name, devstr, sizeof(w->name));
1949162922Sariff	strlcat(w->name, " (", sizeof(w->name));
1950162922Sariff	strlcat(w->name, connstr, sizeof(w->name));
1951162922Sariff	strlcat(w->name, ")", sizeof(w->name));
1952162922Sariff}
1953162922Sariff
1954162922Sariffstatic void
1955162922Sariffhdac_widget_parse(struct hdac_widget *w)
1956162922Sariff{
1957162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1958162922Sariff	uint32_t wcap, cap;
1959162922Sariff	char *typestr;
1960162922Sariff	nid_t cad = w->devinfo->codec->cad;
1961162922Sariff	nid_t nid = w->nid;
1962162922Sariff
1963162922Sariff	wcap = hdac_command(sc,
1964162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
1965162922Sariff	    cad);
1966162922Sariff	w->param.widget_cap = wcap;
1967162922Sariff	w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
1968162922Sariff
1969162922Sariff	switch (w->type) {
1970162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
1971162922Sariff		typestr = "audio output";
1972162922Sariff		break;
1973162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
1974162922Sariff		typestr = "audio input";
1975162922Sariff		break;
1976162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
1977162922Sariff		typestr = "audio mixer";
1978162922Sariff		break;
1979162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
1980162922Sariff		typestr = "audio selector";
1981162922Sariff		break;
1982162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
1983162922Sariff		typestr = "pin";
1984162922Sariff		break;
1985162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET:
1986162922Sariff		typestr = "power widget";
1987162922Sariff		break;
1988162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET:
1989162922Sariff		typestr = "volume widget";
1990162922Sariff		break;
1991162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
1992162922Sariff		typestr = "beep widget";
1993162922Sariff		break;
1994162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET:
1995162922Sariff		typestr = "vendor widget";
1996162922Sariff		break;
1997162922Sariff	default:
1998162922Sariff		typestr = "unknown type";
1999162922Sariff		break;
2000162922Sariff	}
2001162922Sariff
2002162922Sariff	strlcpy(w->name, typestr, sizeof(w->name));
2003162922Sariff
2004162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(wcap)) {
2005162922Sariff		hdac_command(sc,
2006162922Sariff		    HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0),
2007162922Sariff		    cad);
2008162922Sariff		DELAY(1000);
2009162922Sariff	}
2010162922Sariff
2011162922Sariff	hdac_widget_connection_parse(w);
2012162922Sariff
2013162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
2014162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2015162922Sariff			w->param.outamp_cap =
2016162922Sariff			    hdac_command(sc,
2017162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2018162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP), cad);
2019162922Sariff		else
2020162922Sariff			w->param.outamp_cap =
2021162922Sariff			    w->devinfo->function.audio.outamp_cap;
2022162922Sariff	} else
2023162922Sariff		w->param.outamp_cap = 0;
2024162922Sariff
2025162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) {
2026162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
2027162922Sariff			w->param.inamp_cap =
2028162922Sariff			    hdac_command(sc,
2029162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2030162922Sariff			    HDA_PARAM_INPUT_AMP_CAP), cad);
2031162922Sariff		else
2032162922Sariff			w->param.inamp_cap =
2033162922Sariff			    w->devinfo->function.audio.inamp_cap;
2034162922Sariff	} else
2035162922Sariff		w->param.inamp_cap = 0;
2036162922Sariff
2037162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
2038162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
2039162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) {
2040162922Sariff			cap = hdac_command(sc,
2041162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2042162922Sariff			    HDA_PARAM_SUPP_STREAM_FORMATS), cad);
2043162922Sariff			w->param.supp_stream_formats = (cap != 0) ? cap :
2044162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2045162922Sariff			cap = hdac_command(sc,
2046162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
2047162922Sariff			    HDA_PARAM_SUPP_PCM_SIZE_RATE), cad);
2048162922Sariff			w->param.supp_pcm_size_rate = (cap != 0) ? cap :
2049162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2050162922Sariff		} else {
2051162922Sariff			w->param.supp_stream_formats =
2052162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
2053162922Sariff			w->param.supp_pcm_size_rate =
2054162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
2055162922Sariff		}
2056162922Sariff	} else {
2057162922Sariff		w->param.supp_stream_formats = 0;
2058162922Sariff		w->param.supp_pcm_size_rate = 0;
2059162922Sariff	}
2060162922Sariff
2061162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
2062162922Sariff		hdac_widget_pin_parse(w);
2063162922Sariff}
2064162922Sariff
2065162922Sariffstatic struct hdac_widget *
2066162922Sariffhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid)
2067162922Sariff{
2068162922Sariff	if (devinfo == NULL || devinfo->widget == NULL ||
2069162922Sariff		    nid < devinfo->startnode || nid >= devinfo->endnode)
2070162922Sariff		return (NULL);
2071162922Sariff	return (&devinfo->widget[nid - devinfo->startnode]);
2072162922Sariff}
2073162922Sariff
2074164614Sariffstatic __inline int
2075164614Sariffhda_poll_channel(struct hdac_chan *ch)
2076164614Sariff{
2077164614Sariff	uint32_t sz, delta;
2078164614Sariff	volatile uint32_t ptr;
2079164614Sariff
2080164614Sariff	if (ch->active == 0)
2081164614Sariff		return (0);
2082164614Sariff
2083164614Sariff	sz = ch->blksz * ch->blkcnt;
2084164614Sariff	ptr = HDAC_READ_4(&ch->devinfo->codec->sc->mem, ch->off + HDAC_SDLPIB);
2085164614Sariff	ch->ptr = ptr;
2086164614Sariff	ptr %= sz;
2087164614Sariff	ptr &= ~(ch->blksz - 1);
2088164614Sariff	delta = (sz + ptr - ch->prevptr) % sz;
2089164614Sariff
2090164614Sariff	if (delta < ch->blksz)
2091164614Sariff		return (0);
2092164614Sariff
2093164614Sariff	ch->prevptr = ptr;
2094164614Sariff
2095164614Sariff	return (1);
2096164614Sariff}
2097164614Sariff
2098164614Sariff#define hda_chan_active(sc)	((sc)->play.active + (sc)->rec.active)
2099164614Sariff
2100162922Sariffstatic void
2101164614Sariffhda_poll_callback(void *arg)
2102164614Sariff{
2103164614Sariff	struct hdac_softc *sc = arg;
2104164614Sariff	uint32_t trigger = 0;
2105164614Sariff
2106164614Sariff	if (sc == NULL)
2107164614Sariff		return;
2108164614Sariff
2109164614Sariff	hdac_lock(sc);
2110164614Sariff	if (sc->polling == 0 || hda_chan_active(sc) == 0) {
2111164614Sariff		hdac_unlock(sc);
2112164614Sariff		return;
2113164614Sariff	}
2114164614Sariff
2115164614Sariff	trigger |= (hda_poll_channel(&sc->play) != 0) ? 1 : 0;
2116164614Sariff	trigger |= (hda_poll_channel(&sc->rec) != 0) ? 2 : 0;
2117164614Sariff
2118164614Sariff	/* XXX */
2119164614Sariff	callout_reset(&sc->poll_hda, 1/*sc->poll_ticks*/,
2120164614Sariff	    hda_poll_callback, sc);
2121164614Sariff
2122164614Sariff	hdac_unlock(sc);
2123164614Sariff
2124164614Sariff	if (trigger & 1)
2125164614Sariff		chn_intr(sc->play.c);
2126164614Sariff	if (trigger & 2)
2127164614Sariff		chn_intr(sc->rec.c);
2128164614Sariff}
2129164614Sariff
2130164614Sariffstatic int
2131164614Sariffhdac_rirb_flush(struct hdac_softc *sc)
2132164614Sariff{
2133164614Sariff	struct hdac_rirb *rirb_base, *rirb;
2134164614Sariff	struct hdac_codec *codec;
2135164614Sariff	struct hdac_command_list *commands;
2136164614Sariff	nid_t cad;
2137164614Sariff	uint32_t resp;
2138164614Sariff	uint8_t rirbwp;
2139164614Sariff	int ret = 0;
2140164614Sariff
2141164614Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2142164614Sariff	rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
2143164614Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2144164614Sariff	    BUS_DMASYNC_POSTREAD);
2145164614Sariff
2146164614Sariff	while (sc->rirb_rp != rirbwp) {
2147164614Sariff		sc->rirb_rp++;
2148164614Sariff		sc->rirb_rp %= sc->rirb_size;
2149164614Sariff		rirb = &rirb_base[sc->rirb_rp];
2150164614Sariff		cad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
2151164614Sariff		if (cad < 0 || cad >= HDAC_CODEC_MAX ||
2152164614Sariff		    sc->codecs[cad] == NULL)
2153164614Sariff			continue;
2154164614Sariff		resp = rirb->response;
2155164614Sariff		codec = sc->codecs[cad];
2156164614Sariff		commands = codec->commands;
2157164614Sariff		if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
2158164614Sariff			sc->unsolq[sc->unsolq_wp++] = (cad << 16) |
2159164614Sariff			    ((resp >> 26) & 0xffff);
2160164614Sariff			sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
2161164614Sariff		} else if (commands != NULL && commands->num_commands > 0 &&
2162164614Sariff		    codec->responses_received < commands->num_commands)
2163164614Sariff			commands->responses[codec->responses_received++] =
2164164614Sariff			    resp;
2165164614Sariff		ret++;
2166164614Sariff	}
2167164614Sariff
2168164614Sariff	return (ret);
2169164614Sariff}
2170164614Sariff
2171164614Sariffstatic int
2172164614Sariffhdac_unsolq_flush(struct hdac_softc *sc)
2173164614Sariff{
2174164614Sariff	nid_t cad;
2175164614Sariff	uint32_t tag;
2176164614Sariff	int ret = 0;
2177164614Sariff
2178164614Sariff	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
2179164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
2180164614Sariff		while (sc->unsolq_rp != sc->unsolq_wp) {
2181164614Sariff			cad = sc->unsolq[sc->unsolq_rp] >> 16;
2182164614Sariff			tag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
2183164614Sariff			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
2184164614Sariff			hdac_unsolicited_handler(sc->codecs[cad], tag);
2185164614Sariff			ret++;
2186164614Sariff		}
2187164614Sariff		sc->unsolq_st = HDAC_UNSOLQ_READY;
2188164614Sariff	}
2189164614Sariff
2190164614Sariff	return (ret);
2191164614Sariff}
2192164614Sariff
2193164614Sariffstatic void
2194164614Sariffhdac_poll_callback(void *arg)
2195164614Sariff{
2196164614Sariff	struct hdac_softc *sc = arg;
2197164614Sariff	if (sc == NULL)
2198164614Sariff		return;
2199166796Sariff
2200164614Sariff	hdac_lock(sc);
2201164614Sariff	if (sc->polling == 0) {
2202164614Sariff		hdac_unlock(sc);
2203164614Sariff		return;
2204164614Sariff	}
2205164614Sariff	hdac_rirb_flush(sc);
2206164614Sariff	hdac_unsolq_flush(sc);
2207164614Sariff	callout_reset(&sc->poll_hdac, max(hz >> 2, 1),
2208164614Sariff	    hdac_poll_callback, sc);
2209164614Sariff	hdac_unlock(sc);
2210164614Sariff}
2211164614Sariff
2212164614Sariffstatic void
2213162922Sariffhdac_stream_stop(struct hdac_chan *ch)
2214162922Sariff{
2215162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2216162922Sariff	uint32_t ctl;
2217162922Sariff
2218162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2219162922Sariff	ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2220162922Sariff	    HDAC_SDCTL_RUN);
2221162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2222162922Sariff
2223164614Sariff	ch->active = 0;
2224164614Sariff
2225164614Sariff	if (sc->polling != 0) {
2226164614Sariff		int pollticks;
2227164614Sariff
2228164614Sariff		if (hda_chan_active(sc) == 0) {
2229164614Sariff			callout_stop(&sc->poll_hda);
2230164614Sariff			sc->poll_ticks = 1;
2231164614Sariff		} else {
2232164614Sariff			if (sc->play.active != 0)
2233164614Sariff				ch = &sc->play;
2234164614Sariff			else
2235164614Sariff				ch = &sc->rec;
2236164614Sariff			pollticks = ((uint64_t)hz * ch->blksz) /
2237164614Sariff			    ((uint64_t)sndbuf_getbps(ch->b) *
2238164614Sariff			    sndbuf_getspd(ch->b));
2239164614Sariff			pollticks >>= 2;
2240164614Sariff			if (pollticks > hz)
2241164614Sariff				pollticks = hz;
2242164614Sariff			if (pollticks < 1) {
2243164614Sariff				HDA_BOOTVERBOSE(
2244164614Sariff					device_printf(sc->dev,
2245164614Sariff					    "%s: pollticks=%d < 1 !\n",
2246164614Sariff					    __func__, pollticks);
2247164614Sariff				);
2248164614Sariff				pollticks = 1;
2249164614Sariff			}
2250164614Sariff			if (pollticks > sc->poll_ticks) {
2251164614Sariff				HDA_BOOTVERBOSE(
2252164614Sariff					device_printf(sc->dev,
2253164614Sariff					    "%s: pollticks %d -> %d\n",
2254164614Sariff					    __func__, sc->poll_ticks,
2255164614Sariff					    pollticks);
2256164614Sariff				);
2257164614Sariff				sc->poll_ticks = pollticks;
2258164614Sariff				callout_reset(&sc->poll_hda, 1,
2259164614Sariff				    hda_poll_callback, sc);
2260164614Sariff			}
2261164614Sariff		}
2262164614Sariff	} else {
2263164614Sariff		ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2264164614Sariff		ctl &= ~(1 << (ch->off >> 5));
2265164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2266164614Sariff	}
2267162922Sariff}
2268162922Sariff
2269162922Sariffstatic void
2270162922Sariffhdac_stream_start(struct hdac_chan *ch)
2271162922Sariff{
2272162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2273162922Sariff	uint32_t ctl;
2274162922Sariff
2275164614Sariff	if (sc->polling != 0) {
2276164614Sariff		int pollticks;
2277162922Sariff
2278164614Sariff		pollticks = ((uint64_t)hz * ch->blksz) /
2279164614Sariff		    ((uint64_t)sndbuf_getbps(ch->b) * sndbuf_getspd(ch->b));
2280164614Sariff		pollticks >>= 2;
2281164614Sariff		if (pollticks > hz)
2282164614Sariff			pollticks = hz;
2283164614Sariff		if (pollticks < 1) {
2284164614Sariff			HDA_BOOTVERBOSE(
2285164614Sariff				device_printf(sc->dev,
2286164614Sariff				    "%s: pollticks=%d < 1 !\n",
2287164614Sariff				    __func__, pollticks);
2288164614Sariff			);
2289164614Sariff			pollticks = 1;
2290164614Sariff		}
2291164614Sariff		if (hda_chan_active(sc) == 0 || pollticks < sc->poll_ticks) {
2292164614Sariff			HDA_BOOTVERBOSE(
2293164614Sariff				if (hda_chan_active(sc) == 0) {
2294164614Sariff					device_printf(sc->dev,
2295164614Sariff					    "%s: pollticks=%d\n",
2296164614Sariff					    __func__, pollticks);
2297164614Sariff				} else {
2298164614Sariff					device_printf(sc->dev,
2299164614Sariff					    "%s: pollticks %d -> %d\n",
2300164614Sariff					    __func__, sc->poll_ticks,
2301164614Sariff					    pollticks);
2302164614Sariff				}
2303164614Sariff			);
2304164614Sariff			sc->poll_ticks = pollticks;
2305164614Sariff			callout_reset(&sc->poll_hda, 1, hda_poll_callback,
2306164614Sariff			    sc);
2307164614Sariff		}
2308164614Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2309164614Sariff		ctl |= HDAC_SDCTL_RUN;
2310164614Sariff	} else {
2311164614Sariff		ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
2312164614Sariff		ctl |= 1 << (ch->off >> 5);
2313164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
2314164614Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2315164614Sariff		ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
2316164614Sariff		    HDAC_SDCTL_RUN;
2317164614Sariff	}
2318162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2319164614Sariff
2320164614Sariff	ch->active = 1;
2321162922Sariff}
2322162922Sariff
2323162922Sariffstatic void
2324162922Sariffhdac_stream_reset(struct hdac_chan *ch)
2325162922Sariff{
2326162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2327162922Sariff	int timeout = 1000;
2328162922Sariff	int to = timeout;
2329162922Sariff	uint32_t ctl;
2330162922Sariff
2331162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2332162922Sariff	ctl |= HDAC_SDCTL_SRST;
2333162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2334162922Sariff	do {
2335162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2336162922Sariff		if (ctl & HDAC_SDCTL_SRST)
2337162922Sariff			break;
2338162922Sariff		DELAY(10);
2339162922Sariff	} while (--to);
2340162922Sariff	if (!(ctl & HDAC_SDCTL_SRST)) {
2341162922Sariff		device_printf(sc->dev, "timeout in reset\n");
2342162922Sariff	}
2343162922Sariff	ctl &= ~HDAC_SDCTL_SRST;
2344162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
2345162922Sariff	to = timeout;
2346162922Sariff	do {
2347162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
2348162922Sariff		if (!(ctl & HDAC_SDCTL_SRST))
2349162922Sariff			break;
2350162922Sariff		DELAY(10);
2351162922Sariff	} while (--to);
2352163057Sariff	if (ctl & HDAC_SDCTL_SRST)
2353162922Sariff		device_printf(sc->dev, "can't reset!\n");
2354162922Sariff}
2355162922Sariff
2356162922Sariffstatic void
2357162922Sariffhdac_stream_setid(struct hdac_chan *ch)
2358162922Sariff{
2359162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2360162922Sariff	uint32_t ctl;
2361162922Sariff
2362162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2);
2363162922Sariff	ctl &= ~HDAC_SDCTL2_STRM_MASK;
2364162922Sariff	ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT;
2365162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl);
2366162922Sariff}
2367162922Sariff
2368162922Sariffstatic void
2369162922Sariffhdac_bdl_setup(struct hdac_chan *ch)
2370162922Sariff{
2371162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2372164614Sariff	struct hdac_bdle *bdle;
2373162922Sariff	uint64_t addr;
2374164614Sariff	uint32_t blksz, blkcnt;
2375162922Sariff	int i;
2376162922Sariff
2377162922Sariff	addr = (uint64_t)sndbuf_getbufaddr(ch->b);
2378164614Sariff	bdle = (struct hdac_bdle *)ch->bdl_dma.dma_vaddr;
2379162922Sariff
2380164614Sariff	if (sc->polling != 0) {
2381164614Sariff		blksz = ch->blksz * ch->blkcnt;
2382164614Sariff		blkcnt = 1;
2383164614Sariff	} else {
2384164614Sariff		blksz = ch->blksz;
2385164614Sariff		blkcnt = ch->blkcnt;
2386164614Sariff	}
2387164614Sariff
2388164614Sariff	for (i = 0; i < blkcnt; i++, bdle++) {
2389162922Sariff		bdle->addrl = (uint32_t)addr;
2390162922Sariff		bdle->addrh = (uint32_t)(addr >> 32);
2391164614Sariff		bdle->len = blksz;
2392164614Sariff		bdle->ioc = 1 ^ sc->polling;
2393164614Sariff		addr += blksz;
2394162922Sariff	}
2395162922Sariff
2396164614Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, blksz * blkcnt);
2397164614Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blkcnt - 1);
2398162922Sariff	addr = ch->bdl_dma.dma_paddr;
2399162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr);
2400162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
2401162922Sariff}
2402162922Sariff
2403162922Sariffstatic int
2404162922Sariffhdac_bdl_alloc(struct hdac_chan *ch)
2405162922Sariff{
2406162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2407162922Sariff	int rc;
2408162922Sariff
2409162922Sariff	rc = hdac_dma_alloc(sc, &ch->bdl_dma,
2410162922Sariff	    sizeof(struct hdac_bdle) * HDA_BDL_MAX);
2411162922Sariff	if (rc) {
2412162922Sariff		device_printf(sc->dev, "can't alloc bdl\n");
2413162922Sariff		return (rc);
2414162922Sariff	}
2415162922Sariff	hdac_dma_nocache(ch->bdl_dma.dma_vaddr);
2416162922Sariff
2417162922Sariff	return (0);
2418162922Sariff}
2419162922Sariff
2420162922Sariffstatic void
2421162922Sariffhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid,
2422162922Sariff					int index, int lmute, int rmute,
2423162922Sariff					int left, int right, int dir)
2424162922Sariff{
2425162922Sariff	uint16_t v = 0;
2426162922Sariff
2427162922Sariff	if (sc == NULL)
2428162922Sariff		return;
2429162922Sariff
2430162922Sariff	if (left != right || lmute != rmute) {
2431162922Sariff		v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
2432162922Sariff		    (lmute << 7) | left;
2433162922Sariff		hdac_command(sc,
2434164614Sariff		    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2435162922Sariff		v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
2436162922Sariff		    (rmute << 7) | right;
2437162922Sariff	} else
2438162922Sariff		v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
2439162922Sariff		    (lmute << 7) | left;
2440162922Sariff
2441162922Sariff	hdac_command(sc,
2442162922Sariff	    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
2443162922Sariff}
2444162922Sariff
2445162922Sariffstatic void
2446162922Sariffhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
2447162922Sariff						int left, int right)
2448162922Sariff{
2449162922Sariff	struct hdac_softc *sc;
2450162922Sariff	nid_t nid, cad;
2451162922Sariff	int lmute, rmute;
2452162922Sariff
2453162922Sariff	if (ctl == NULL || ctl->widget == NULL ||
2454162922Sariff	    ctl->widget->devinfo == NULL ||
2455162922Sariff	    ctl->widget->devinfo->codec == NULL ||
2456162922Sariff	    ctl->widget->devinfo->codec->sc == NULL)
2457162922Sariff		return;
2458162922Sariff
2459162922Sariff	sc = ctl->widget->devinfo->codec->sc;
2460162922Sariff	cad = ctl->widget->devinfo->codec->cad;
2461162922Sariff	nid = ctl->widget->nid;
2462162922Sariff
2463162922Sariff	if (mute == HDA_AMP_MUTE_DEFAULT) {
2464162922Sariff		lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
2465162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
2466162922Sariff	} else {
2467162922Sariff		lmute = HDA_AMP_LEFT_MUTED(mute);
2468162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(mute);
2469162922Sariff	}
2470162922Sariff
2471162922Sariff	if (ctl->dir & HDA_CTL_OUT)
2472162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2473162922Sariff		    lmute, rmute, left, right, 0);
2474162922Sariff	if (ctl->dir & HDA_CTL_IN)
2475162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2476162922Sariff		    lmute, rmute, left, right, 1);
2477162922Sariff	ctl->left = left;
2478162922Sariff	ctl->right = right;
2479162922Sariff}
2480162922Sariff
2481162922Sariffstatic void
2482162922Sariffhdac_widget_connection_select(struct hdac_widget *w, uint8_t index)
2483162922Sariff{
2484162922Sariff	if (w == NULL || w->nconns < 1 || index > (w->nconns - 1))
2485162922Sariff		return;
2486162922Sariff	hdac_command(w->devinfo->codec->sc,
2487162922Sariff	    HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad,
2488162922Sariff	    w->nid, index), w->devinfo->codec->cad);
2489162922Sariff	w->selconn = index;
2490162922Sariff}
2491162922Sariff
2492162922Sariff
2493162922Sariff/****************************************************************************
2494162922Sariff * uint32_t hdac_command_sendone_internal
2495162922Sariff *
2496162922Sariff * Wrapper function that sends only one command to a given codec
2497162922Sariff ****************************************************************************/
2498162922Sariffstatic uint32_t
2499162922Sariffhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad)
2500162922Sariff{
2501162922Sariff	struct hdac_command_list cl;
2502162965Sariff	uint32_t response = HDAC_INVALID;
2503162922Sariff
2504163057Sariff	if (!hdac_lockowned(sc))
2505162922Sariff		device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n");
2506162922Sariff	cl.num_commands = 1;
2507162922Sariff	cl.verbs = &verb;
2508162922Sariff	cl.responses = &response;
2509162922Sariff
2510162922Sariff	hdac_command_send_internal(sc, &cl, cad);
2511162922Sariff
2512162922Sariff	return (response);
2513162922Sariff}
2514162922Sariff
2515162922Sariff/****************************************************************************
2516162922Sariff * hdac_command_send_internal
2517162922Sariff *
2518162922Sariff * Send a command list to the codec via the corb. We queue as much verbs as
2519162922Sariff * we can and msleep on the codec. When the interrupt get the responses
2520162922Sariff * back from the rirb, it will wake us up so we can queue the remaining verbs
2521162922Sariff * if any.
2522162922Sariff ****************************************************************************/
2523162922Sariffstatic void
2524162922Sariffhdac_command_send_internal(struct hdac_softc *sc,
2525162922Sariff			struct hdac_command_list *commands, nid_t cad)
2526162922Sariff{
2527162922Sariff	struct hdac_codec *codec;
2528162922Sariff	int corbrp;
2529162922Sariff	uint32_t *corb;
2530162922Sariff	int timeout;
2531162922Sariff	int retry = 10;
2532164614Sariff	struct hdac_rirb *rirb_base;
2533162922Sariff
2534164614Sariff	if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL ||
2535164614Sariff	    commands->num_commands < 1)
2536162922Sariff		return;
2537162922Sariff
2538162922Sariff	codec = sc->codecs[cad];
2539162922Sariff	codec->commands = commands;
2540162922Sariff	codec->responses_received = 0;
2541162922Sariff	codec->verbs_sent = 0;
2542162922Sariff	corb = (uint32_t *)sc->corb_dma.dma_vaddr;
2543162922Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2544162922Sariff
2545162922Sariff	do {
2546162922Sariff		if (codec->verbs_sent != commands->num_commands) {
2547162922Sariff			/* Queue as many verbs as possible */
2548162922Sariff			corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP);
2549162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
2550162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
2551162922Sariff			while (codec->verbs_sent != commands->num_commands &&
2552162922Sariff			    ((sc->corb_wp + 1) % sc->corb_size) != corbrp) {
2553162922Sariff				sc->corb_wp++;
2554162922Sariff				sc->corb_wp %= sc->corb_size;
2555162922Sariff				corb[sc->corb_wp] =
2556162922Sariff				    commands->verbs[codec->verbs_sent++];
2557162922Sariff			}
2558162922Sariff
2559162922Sariff			/* Send the verbs to the codecs */
2560162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
2561162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
2562162922Sariff			HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
2563162922Sariff		}
2564162922Sariff
2565162922Sariff		timeout = 1000;
2566164614Sariff		while (hdac_rirb_flush(sc) == 0 && --timeout)
2567162922Sariff			DELAY(10);
2568162922Sariff	} while ((codec->verbs_sent != commands->num_commands ||
2569164614Sariff	    codec->responses_received != commands->num_commands) && --retry);
2570162922Sariff
2571162922Sariff	if (retry == 0)
2572162922Sariff		device_printf(sc->dev,
2573164614Sariff		    "%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n",
2574164614Sariff		    __func__, commands->num_commands, codec->verbs_sent,
2575164614Sariff		    codec->responses_received);
2576162922Sariff
2577164614Sariff	codec->commands = NULL;
2578164614Sariff	codec->responses_received = 0;
2579162922Sariff	codec->verbs_sent = 0;
2580162922Sariff
2581164614Sariff	hdac_unsolq_flush(sc);
2582162922Sariff}
2583162922Sariff
2584162922Sariff
2585162922Sariff/****************************************************************************
2586162922Sariff * Device Methods
2587162922Sariff ****************************************************************************/
2588162922Sariff
2589162922Sariff/****************************************************************************
2590162922Sariff * int hdac_probe(device_t)
2591162922Sariff *
2592162922Sariff * Probe for the presence of an hdac. If none is found, check for a generic
2593162922Sariff * match using the subclass of the device.
2594162922Sariff ****************************************************************************/
2595162922Sariffstatic int
2596162922Sariffhdac_probe(device_t dev)
2597162922Sariff{
2598162922Sariff	int i, result;
2599163257Sariff	uint32_t model;
2600163257Sariff	uint16_t class, subclass;
2601162922Sariff	char desc[64];
2602162922Sariff
2603162922Sariff	model = (uint32_t)pci_get_device(dev) << 16;
2604162922Sariff	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
2605162922Sariff	class = pci_get_class(dev);
2606162922Sariff	subclass = pci_get_subclass(dev);
2607162922Sariff
2608162922Sariff	bzero(desc, sizeof(desc));
2609162922Sariff	result = ENXIO;
2610162922Sariff	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
2611162922Sariff		if (hdac_devices[i].model == model) {
2612162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
2613162922Sariff		    	result = BUS_PROBE_DEFAULT;
2614162922Sariff			break;
2615162922Sariff		}
2616163257Sariff		if (HDA_DEV_MATCH(hdac_devices[i].model, model) &&
2617162922Sariff		    class == PCIC_MULTIMEDIA &&
2618162922Sariff		    subclass == PCIS_MULTIMEDIA_HDA) {
2619162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
2620162922Sariff		    	result = BUS_PROBE_GENERIC;
2621162922Sariff			break;
2622162922Sariff		}
2623162922Sariff	}
2624162922Sariff	if (result == ENXIO && class == PCIC_MULTIMEDIA &&
2625162922Sariff	    subclass == PCIS_MULTIMEDIA_HDA) {
2626162922Sariff		strlcpy(desc, "Generic", sizeof(desc));
2627162922Sariff	    	result = BUS_PROBE_GENERIC;
2628162922Sariff	}
2629162922Sariff	if (result != ENXIO) {
2630162922Sariff		strlcat(desc, " High Definition Audio Controller",
2631162922Sariff		    sizeof(desc));
2632162922Sariff		device_set_desc_copy(dev, desc);
2633162922Sariff	}
2634162922Sariff
2635162922Sariff	return (result);
2636162922Sariff}
2637162922Sariff
2638162922Sariffstatic void *
2639162922Sariffhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
2640162922Sariff					struct pcm_channel *c, int dir)
2641162922Sariff{
2642162922Sariff	struct hdac_devinfo *devinfo = data;
2643162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2644162922Sariff	struct hdac_chan *ch;
2645162922Sariff
2646162922Sariff	hdac_lock(sc);
2647162922Sariff	if (dir == PCMDIR_PLAY) {
2648162922Sariff		ch = &sc->play;
2649162922Sariff		ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5;
2650162922Sariff		ch->dir = PCMDIR_PLAY;
2651162922Sariff		ch->sid = ++sc->streamcnt;
2652162922Sariff		devinfo->function.audio.playcnt++;
2653162922Sariff	} else {
2654162922Sariff		ch = &sc->rec;
2655162922Sariff		ch->off = devinfo->function.audio.reccnt << 5;
2656162922Sariff		ch->dir = PCMDIR_REC;
2657162922Sariff		ch->sid = ++sc->streamcnt;
2658162922Sariff		devinfo->function.audio.reccnt++;
2659162922Sariff	}
2660162922Sariff	if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
2661162922Sariff		ch->caps.minspeed = ch->caps.maxspeed = 48000;
2662162922Sariff		ch->pcmrates[0] = 48000;
2663162922Sariff		ch->pcmrates[1] = 0;
2664162922Sariff	}
2665162922Sariff	ch->b = b;
2666162922Sariff	ch->c = c;
2667162922Sariff	ch->devinfo = devinfo;
2668162922Sariff	ch->blksz = sc->chan_size / sc->chan_blkcnt;
2669162922Sariff	ch->blkcnt = sc->chan_blkcnt;
2670162922Sariff	hdac_unlock(sc);
2671162922Sariff
2672162922Sariff	if (hdac_bdl_alloc(ch) != 0) {
2673162922Sariff		ch->blkcnt = 0;
2674162922Sariff		return (NULL);
2675162922Sariff	}
2676162922Sariff
2677162922Sariff	if (sndbuf_alloc(ch->b, sc->chan_dmat, sc->chan_size) != 0)
2678162922Sariff		return (NULL);
2679162922Sariff
2680162922Sariff	hdac_dma_nocache(ch->b->buf);
2681162922Sariff
2682162922Sariff	return (ch);
2683162922Sariff}
2684162922Sariff
2685162922Sariffstatic int
2686162922Sariffhdac_channel_setformat(kobj_t obj, void *data, uint32_t format)
2687162922Sariff{
2688162922Sariff	struct hdac_chan *ch = data;
2689162922Sariff	int i;
2690162922Sariff
2691162922Sariff	for (i = 0; ch->caps.fmtlist[i] != 0; i++) {
2692162922Sariff		if (format == ch->caps.fmtlist[i]) {
2693162922Sariff			ch->fmt = format;
2694162922Sariff			return (0);
2695162922Sariff		}
2696162922Sariff	}
2697162922Sariff
2698162922Sariff	return (EINVAL);
2699162922Sariff}
2700162922Sariff
2701162922Sariffstatic int
2702162922Sariffhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed)
2703162922Sariff{
2704162922Sariff	struct hdac_chan *ch = data;
2705164614Sariff	uint32_t spd = 0, threshold;
2706162922Sariff	int i;
2707162922Sariff
2708162922Sariff	for (i = 0; ch->pcmrates[i] != 0; i++) {
2709162922Sariff		spd = ch->pcmrates[i];
2710164614Sariff		threshold = spd + ((ch->pcmrates[i + 1] != 0) ?
2711164614Sariff		    ((ch->pcmrates[i + 1] - spd) >> 1) : 0);
2712164614Sariff		if (speed < threshold)
2713162922Sariff			break;
2714162922Sariff	}
2715162922Sariff
2716164614Sariff	if (spd == 0)	/* impossible */
2717162922Sariff		ch->spd = 48000;
2718162922Sariff	else
2719162922Sariff		ch->spd = spd;
2720162922Sariff
2721162922Sariff	return (ch->spd);
2722162922Sariff}
2723162922Sariff
2724162922Sariffstatic void
2725162922Sariffhdac_stream_setup(struct hdac_chan *ch)
2726162922Sariff{
2727162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2728162922Sariff	int i;
2729162922Sariff	nid_t cad = ch->devinfo->codec->cad;
2730162922Sariff	uint16_t fmt;
2731162922Sariff
2732162922Sariff	fmt = 0;
2733162922Sariff	if (ch->fmt & AFMT_S16_LE)
2734162922Sariff		fmt |= ch->bit16 << 4;
2735162922Sariff	else if (ch->fmt & AFMT_S32_LE)
2736162922Sariff		fmt |= ch->bit32 << 4;
2737162922Sariff	else
2738162922Sariff		fmt |= 1 << 4;
2739162922Sariff
2740162922Sariff	for (i = 0; i < HDA_RATE_TAB_LEN; i++) {
2741162922Sariff		if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) {
2742162922Sariff			fmt |= hda_rate_tab[i].base;
2743162922Sariff			fmt |= hda_rate_tab[i].mul;
2744162922Sariff			fmt |= hda_rate_tab[i].div;
2745162922Sariff			break;
2746162922Sariff		}
2747162922Sariff	}
2748162922Sariff
2749162922Sariff	if (ch->fmt & AFMT_STEREO)
2750162922Sariff		fmt |= 1;
2751162922Sariff
2752162922Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
2753162922Sariff
2754162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
2755163057Sariff		HDA_BOOTVERBOSE(
2756162922Sariff			device_printf(sc->dev,
2757163057Sariff			    "HDA_DEBUG: PCMDIR_%s: Stream setup nid=%d "
2758163057Sariff			    "fmt=0x%08x\n",
2759162922Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
2760162922Sariff			    ch->io[i], fmt);
2761162922Sariff		);
2762162922Sariff		hdac_command(sc,
2763162922Sariff		    HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
2764162922Sariff		hdac_command(sc,
2765162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
2766162922Sariff		    ch->sid << 4), cad);
2767162922Sariff	}
2768162922Sariff}
2769162922Sariff
2770162922Sariffstatic int
2771167648Sariffhdac_channel_setfragments(kobj_t obj, void *data,
2772167648Sariff					uint32_t blksz, uint32_t blkcnt)
2773162922Sariff{
2774162922Sariff	struct hdac_chan *ch = data;
2775164614Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2776162922Sariff
2777167648Sariff	blksz &= HDA_BLK_ALIGN;
2778162922Sariff
2779167648Sariff	if (blksz > (sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN))
2780167648Sariff		blksz = sndbuf_getmaxsize(ch->b) / HDA_BDL_MIN;
2781167648Sariff	if (blksz < HDA_BLK_MIN)
2782167648Sariff		blksz = HDA_BLK_MIN;
2783167648Sariff	if (blkcnt > HDA_BDL_MAX)
2784167648Sariff		blkcnt = HDA_BDL_MAX;
2785167648Sariff	if (blkcnt < HDA_BDL_MIN)
2786167648Sariff		blkcnt = HDA_BDL_MIN;
2787164614Sariff
2788167648Sariff	while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->b)) {
2789167648Sariff		if ((blkcnt >> 1) >= HDA_BDL_MIN)
2790167648Sariff			blkcnt >>= 1;
2791167648Sariff		else if ((blksz >> 1) >= HDA_BLK_MIN)
2792167648Sariff			blksz >>= 1;
2793167648Sariff		else
2794167648Sariff			break;
2795167648Sariff	}
2796167648Sariff
2797164614Sariff	if ((sndbuf_getblksz(ch->b) != blksz ||
2798167648Sariff	    sndbuf_getblkcnt(ch->b) != blkcnt) &&
2799167648Sariff	    sndbuf_resize(ch->b, blkcnt, blksz) != 0)
2800164614Sariff		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
2801167648Sariff		    __func__, blksz, blkcnt);
2802164614Sariff
2803164614Sariff	ch->blksz = sndbuf_getblksz(ch->b);
2804167648Sariff	ch->blkcnt = sndbuf_getblkcnt(ch->b);
2805164614Sariff
2806167648Sariff	return (1);
2807167648Sariff}
2808167648Sariff
2809167648Sariffstatic int
2810167648Sariffhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blksz)
2811167648Sariff{
2812167648Sariff	struct hdac_chan *ch = data;
2813167648Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2814167648Sariff
2815167648Sariff	hdac_channel_setfragments(obj, data, blksz, sc->chan_blkcnt);
2816167648Sariff
2817162922Sariff	return (ch->blksz);
2818162922Sariff}
2819162922Sariff
2820162922Sariffstatic void
2821162922Sariffhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
2822162922Sariff{
2823162922Sariff	struct hdac_devinfo *devinfo = ch->devinfo;
2824162922Sariff	nid_t cad = devinfo->codec->cad;
2825162922Sariff	int i;
2826162922Sariff
2827162922Sariff	hdac_stream_stop(ch);
2828162922Sariff
2829162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
2830162922Sariff		hdac_command(sc,
2831162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
2832162922Sariff		    0), cad);
2833162922Sariff	}
2834162922Sariff}
2835162922Sariff
2836162922Sariffstatic void
2837162922Sariffhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch)
2838162922Sariff{
2839162922Sariff	ch->ptr = 0;
2840162922Sariff	ch->prevptr = 0;
2841162922Sariff	hdac_stream_stop(ch);
2842162922Sariff	hdac_stream_reset(ch);
2843162922Sariff	hdac_bdl_setup(ch);
2844162922Sariff	hdac_stream_setid(ch);
2845162922Sariff	hdac_stream_setup(ch);
2846162922Sariff	hdac_stream_start(ch);
2847162922Sariff}
2848162922Sariff
2849162922Sariffstatic int
2850162922Sariffhdac_channel_trigger(kobj_t obj, void *data, int go)
2851162922Sariff{
2852162922Sariff	struct hdac_chan *ch = data;
2853162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2854162922Sariff
2855162922Sariff	hdac_lock(sc);
2856162922Sariff	switch (go) {
2857162922Sariff	case PCMTRIG_START:
2858162922Sariff		hdac_channel_start(sc, ch);
2859162922Sariff		break;
2860162922Sariff	case PCMTRIG_STOP:
2861162922Sariff	case PCMTRIG_ABORT:
2862162922Sariff		hdac_channel_stop(sc, ch);
2863162922Sariff		break;
2864167610Sariff	default:
2865167610Sariff		break;
2866162922Sariff	}
2867162922Sariff	hdac_unlock(sc);
2868162922Sariff
2869162922Sariff	return (0);
2870162922Sariff}
2871162922Sariff
2872162922Sariffstatic int
2873162922Sariffhdac_channel_getptr(kobj_t obj, void *data)
2874162922Sariff{
2875162922Sariff	struct hdac_chan *ch = data;
2876162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2877162922Sariff	uint32_t ptr;
2878162922Sariff
2879162922Sariff	hdac_lock(sc);
2880164614Sariff	if (sc->polling != 0)
2881164614Sariff		ptr = ch->ptr;
2882164614Sariff	else
2883164614Sariff		ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB);
2884162922Sariff	hdac_unlock(sc);
2885162922Sariff
2886164614Sariff	/*
2887164614Sariff	 * Round to available space and force 128 bytes aligment.
2888164614Sariff	 */
2889164614Sariff	ptr %= ch->blksz * ch->blkcnt;
2890167648Sariff	ptr &= HDA_BLK_ALIGN;
2891162922Sariff
2892162922Sariff	return (ptr);
2893162922Sariff}
2894162922Sariff
2895162922Sariffstatic struct pcmchan_caps *
2896162922Sariffhdac_channel_getcaps(kobj_t obj, void *data)
2897162922Sariff{
2898162922Sariff	return (&((struct hdac_chan *)data)->caps);
2899162922Sariff}
2900162922Sariff
2901162922Sariffstatic kobj_method_t hdac_channel_methods[] = {
2902162922Sariff	KOBJMETHOD(channel_init,		hdac_channel_init),
2903162922Sariff	KOBJMETHOD(channel_setformat,		hdac_channel_setformat),
2904162922Sariff	KOBJMETHOD(channel_setspeed,		hdac_channel_setspeed),
2905162922Sariff	KOBJMETHOD(channel_setblocksize,	hdac_channel_setblocksize),
2906167648Sariff	KOBJMETHOD(channel_setfragments,	hdac_channel_setfragments),
2907162922Sariff	KOBJMETHOD(channel_trigger,		hdac_channel_trigger),
2908162922Sariff	KOBJMETHOD(channel_getptr,		hdac_channel_getptr),
2909162922Sariff	KOBJMETHOD(channel_getcaps,		hdac_channel_getcaps),
2910162922Sariff	{ 0, 0 }
2911162922Sariff};
2912162922SariffCHANNEL_DECLARE(hdac_channel);
2913162922Sariff
2914162922Sariffstatic int
2915162922Sariffhdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
2916162922Sariff{
2917162922Sariff	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
2918162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2919162922Sariff	struct hdac_widget *w, *cw;
2920162922Sariff	struct hdac_audio_ctl *ctl;
2921162922Sariff	uint32_t mask, recmask, id;
2922162922Sariff	int i, j, softpcmvol;
2923162922Sariff	nid_t cad;
2924162922Sariff
2925162922Sariff	hdac_lock(sc);
2926162922Sariff
2927162922Sariff	mask = 0;
2928162922Sariff	recmask = 0;
2929162922Sariff
2930162922Sariff	id = hdac_codec_id(devinfo);
2931162922Sariff	cad = devinfo->codec->cad;
2932162922Sariff	for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
2933163257Sariff		if (!(HDA_DEV_MATCH(hdac_hp_switch[i].model,
2934162965Sariff		    sc->pci_subvendor) &&
2935162922Sariff		    hdac_hp_switch[i].id == id))
2936162922Sariff			continue;
2937162922Sariff		w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
2938162922Sariff		if (w != NULL && w->enable != 0
2939162922Sariff		    && w->type ==
2940162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
2941162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
2942162922Sariff			hdac_command(sc,
2943162922Sariff			    HDA_CMD_SET_UNSOLICITED_RESPONSE(cad,
2944162922Sariff			    w->nid,
2945162922Sariff			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE|
2946162922Sariff			    HDAC_UNSOLTAG_EVENT_HP), cad);
2947162922Sariff			hdac_hp_switch_handler(devinfo);
2948163057Sariff			HDA_BOOTVERBOSE(
2949163057Sariff				device_printf(sc->dev,
2950163057Sariff				    "HDA_DEBUG: Enabling headphone/speaker "
2951163057Sariff				    "audio routing switching:\n");
2952163057Sariff				device_printf(sc->dev,
2953163057Sariff				    "HDA_DEBUG: \tindex=%d nid=%d "
2954163057Sariff				    "pci_subvendor=0x%08x "
2955163057Sariff				    "codec=0x%08x\n",
2956163057Sariff				    i, w->nid, sc->pci_subvendor, id);
2957163057Sariff			);
2958162922Sariff		}
2959162922Sariff		break;
2960162922Sariff	}
2961162922Sariff	for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
2962163257Sariff		if (!(HDA_DEV_MATCH(hdac_eapd_switch[i].model,
2963162965Sariff		    sc->pci_subvendor) &&
2964162965Sariff		    hdac_eapd_switch[i].id == id))
2965162922Sariff			continue;
2966162922Sariff		w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
2967162922Sariff		if (w == NULL || w->enable == 0)
2968162922Sariff			break;
2969162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
2970162965Sariff		    w->param.eapdbtl == HDAC_INVALID)
2971162922Sariff			break;
2972162922Sariff		mask |= SOUND_MASK_OGAIN;
2973162922Sariff		break;
2974162922Sariff	}
2975162922Sariff
2976162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
2977162922Sariff		w = hdac_widget_get(devinfo, i);
2978162922Sariff		if (w == NULL || w->enable == 0)
2979162922Sariff			continue;
2980162922Sariff		mask |= w->ctlflags;
2981162922Sariff		if (!(w->pflags & HDA_ADC_RECSEL))
2982162922Sariff			continue;
2983162922Sariff		for (j = 0; j < w->nconns; j++) {
2984162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
2985162922Sariff			if (cw == NULL || cw->enable == 0)
2986162922Sariff				continue;
2987162922Sariff			recmask |= cw->ctlflags;
2988162922Sariff		}
2989162922Sariff	}
2990162922Sariff
2991162922Sariff	if (!(mask & SOUND_MASK_PCM)) {
2992162922Sariff		softpcmvol = 1;
2993162922Sariff		mask |= SOUND_MASK_PCM;
2994163057Sariff	} else
2995163057Sariff		softpcmvol = (devinfo->function.audio.quirks &
2996163057Sariff		    HDA_QUIRK_SOFTPCMVOL) ? 1 : 0;
2997162922Sariff
2998162922Sariff	i = 0;
2999162922Sariff	ctl = NULL;
3000162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3001162922Sariff		if (ctl->widget == NULL || ctl->enable == 0)
3002162922Sariff			continue;
3003162922Sariff		if (!(ctl->ossmask & SOUND_MASK_PCM))
3004162922Sariff			continue;
3005162922Sariff		if (ctl->step > 0)
3006162922Sariff			break;
3007162922Sariff	}
3008162922Sariff
3009162922Sariff	if (softpcmvol == 1 || ctl == NULL) {
3010162922Sariff		struct snddev_info *d = NULL;
3011162922Sariff		d = device_get_softc(sc->dev);
3012162922Sariff		if (d != NULL) {
3013162922Sariff			d->flags |= SD_F_SOFTPCMVOL;
3014163057Sariff			HDA_BOOTVERBOSE(
3015162922Sariff				device_printf(sc->dev,
3016163057Sariff				    "HDA_DEBUG: %s Soft PCM volume\n",
3017162922Sariff				    (softpcmvol == 1) ?
3018162922Sariff				    "Forcing" : "Enabling");
3019162922Sariff			);
3020162922Sariff		}
3021162922Sariff		i = 0;
3022162922Sariff		/*
3023162922Sariff		 * XXX Temporary quirk for STAC9220, until the parser
3024162922Sariff		 *     become smarter.
3025162922Sariff		 */
3026162922Sariff		if (id == HDA_CODEC_STAC9220) {
3027162922Sariff			mask |= SOUND_MASK_VOLUME;
3028162922Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
3029162922Sariff			    NULL) {
3030162922Sariff				if (ctl->widget == NULL || ctl->enable == 0)
3031162922Sariff					continue;
3032162922Sariff				if (ctl->widget->nid == 11 && ctl->index == 0) {
3033162922Sariff					ctl->ossmask = SOUND_MASK_VOLUME;
3034162922Sariff					ctl->ossval = 100 | (100 << 8);
3035162922Sariff				} else
3036162922Sariff					ctl->ossmask &= ~SOUND_MASK_VOLUME;
3037162922Sariff			}
3038165992Sariff		} else if (id == HDA_CODEC_STAC9221) {
3039165992Sariff			mask |= SOUND_MASK_VOLUME;
3040165992Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
3041165992Sariff			    NULL) {
3042165992Sariff				if (ctl->widget == NULL)
3043165992Sariff					continue;
3044165992Sariff				if (ctl->widget->nid == 2 && ctl->index == 0) {
3045165992Sariff					ctl->enable = 1;
3046165992Sariff					ctl->ossmask = SOUND_MASK_VOLUME;
3047165992Sariff					ctl->ossval = 100 | (100 << 8);
3048165992Sariff				} else if (ctl->enable == 0)
3049165992Sariff					continue;
3050165992Sariff				else
3051165992Sariff					ctl->ossmask &= ~SOUND_MASK_VOLUME;
3052165992Sariff			}
3053162922Sariff		} else {
3054162922Sariff			mix_setparentchild(m, SOUND_MIXER_VOLUME,
3055162922Sariff			    SOUND_MASK_PCM);
3056162922Sariff			if (!(mask & SOUND_MASK_VOLUME))
3057162922Sariff				mix_setrealdev(m, SOUND_MIXER_VOLUME,
3058162922Sariff				    SOUND_MIXER_NONE);
3059162922Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
3060162922Sariff			    NULL) {
3061162922Sariff				if (ctl->widget == NULL || ctl->enable == 0)
3062162922Sariff					continue;
3063163057Sariff				if (!HDA_FLAG_MATCH(ctl->ossmask,
3064163057Sariff				    SOUND_MASK_VOLUME | SOUND_MASK_PCM))
3065162922Sariff					continue;
3066162922Sariff				if (!(ctl->mute == 1 && ctl->step == 0))
3067162922Sariff					ctl->enable = 0;
3068162922Sariff			}
3069162922Sariff		}
3070162922Sariff	}
3071162922Sariff
3072162922Sariff	recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER);
3073162922Sariff
3074162922Sariff	mix_setrecdevs(m, recmask);
3075162922Sariff	mix_setdevs(m, mask);
3076162922Sariff
3077162922Sariff	hdac_unlock(sc);
3078162922Sariff
3079162922Sariff	return (0);
3080162922Sariff}
3081162922Sariff
3082162922Sariffstatic int
3083162922Sariffhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
3084162922Sariff					unsigned left, unsigned right)
3085162922Sariff{
3086162922Sariff	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
3087162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3088162922Sariff	struct hdac_widget *w;
3089162922Sariff	struct hdac_audio_ctl *ctl;
3090162922Sariff	uint32_t id, mute;
3091162922Sariff	int lvol, rvol, mlvol, mrvol;
3092162922Sariff	int i = 0;
3093162922Sariff
3094162922Sariff	hdac_lock(sc);
3095162922Sariff	if (dev == SOUND_MIXER_OGAIN) {
3096163257Sariff		uint32_t orig;
3097162922Sariff		/*if (left != right || !(left == 0 || left == 1)) {
3098162922Sariff			hdac_unlock(sc);
3099162922Sariff			return (-1);
3100162922Sariff		}*/
3101162922Sariff		id = hdac_codec_id(devinfo);
3102162922Sariff		for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
3103163257Sariff			if (HDA_DEV_MATCH(hdac_eapd_switch[i].model,
3104162965Sariff			    sc->pci_subvendor) &&
3105162922Sariff			    hdac_eapd_switch[i].id == id)
3106162922Sariff				break;
3107162922Sariff		}
3108162922Sariff		if (i >= HDAC_EAPD_SWITCH_LEN) {
3109162922Sariff			hdac_unlock(sc);
3110162922Sariff			return (-1);
3111162922Sariff		}
3112162922Sariff		w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
3113162922Sariff		if (w == NULL ||
3114162922Sariff		    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
3115162965Sariff		    w->param.eapdbtl == HDAC_INVALID) {
3116162922Sariff			hdac_unlock(sc);
3117162922Sariff			return (-1);
3118162922Sariff		}
3119163257Sariff		orig = w->param.eapdbtl;
3120163432Sariff		if (left == 0)
3121162922Sariff			w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3122162922Sariff		else
3123162922Sariff			w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3124163257Sariff		if (orig != w->param.eapdbtl) {
3125163432Sariff			uint32_t val;
3126163432Sariff
3127163257Sariff			if (hdac_eapd_switch[i].hp_switch != 0)
3128163257Sariff				hdac_hp_switch_handler(devinfo);
3129163432Sariff			val = w->param.eapdbtl;
3130163432Sariff			if (devinfo->function.audio.quirks & HDA_QUIRK_EAPDINV)
3131163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
3132163257Sariff			hdac_command(sc,
3133163257Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad,
3134163432Sariff			    w->nid, val), devinfo->codec->cad);
3135163257Sariff		}
3136162922Sariff		hdac_unlock(sc);
3137162922Sariff		return (left | (left << 8));
3138162922Sariff	}
3139162922Sariff	if (dev == SOUND_MIXER_VOLUME)
3140162922Sariff		devinfo->function.audio.mvol = left | (right << 8);
3141162922Sariff
3142162922Sariff	mlvol = devinfo->function.audio.mvol & 0x7f;
3143162922Sariff	mrvol = (devinfo->function.audio.mvol >> 8) & 0x7f;
3144162922Sariff	lvol = 0;
3145162922Sariff	rvol = 0;
3146162922Sariff
3147162922Sariff	i = 0;
3148162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3149162922Sariff		if (ctl->widget == NULL || ctl->enable == 0 ||
3150162922Sariff		    !(ctl->ossmask & (1 << dev)))
3151162922Sariff			continue;
3152162922Sariff		switch (dev) {
3153162922Sariff		case SOUND_MIXER_VOLUME:
3154162922Sariff			lvol = ((ctl->ossval & 0x7f) * left) / 100;
3155162922Sariff			lvol = (lvol * ctl->step) / 100;
3156162922Sariff			rvol = (((ctl->ossval >> 8) & 0x7f) * right) / 100;
3157162922Sariff			rvol = (rvol * ctl->step) / 100;
3158162922Sariff			break;
3159162922Sariff		default:
3160162922Sariff			if (ctl->ossmask & SOUND_MASK_VOLUME) {
3161162922Sariff				lvol = (left * mlvol) / 100;
3162162922Sariff				lvol = (lvol * ctl->step) / 100;
3163162922Sariff				rvol = (right * mrvol) / 100;
3164162922Sariff				rvol = (rvol * ctl->step) / 100;
3165162922Sariff			} else {
3166162922Sariff				lvol = (left * ctl->step) / 100;
3167162922Sariff				rvol = (right * ctl->step) / 100;
3168162922Sariff			}
3169162922Sariff			ctl->ossval = left | (right << 8);
3170162922Sariff			break;
3171162922Sariff		}
3172162922Sariff		mute = 0;
3173162922Sariff		if (ctl->step < 1) {
3174162922Sariff			mute |= (left == 0) ? HDA_AMP_MUTE_LEFT :
3175162922Sariff			    (ctl->muted & HDA_AMP_MUTE_LEFT);
3176162922Sariff			mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT :
3177162922Sariff			    (ctl->muted & HDA_AMP_MUTE_RIGHT);
3178162922Sariff		} else {
3179162922Sariff			mute |= (lvol == 0) ? HDA_AMP_MUTE_LEFT :
3180162922Sariff			    (ctl->muted & HDA_AMP_MUTE_LEFT);
3181162922Sariff			mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT :
3182162922Sariff			    (ctl->muted & HDA_AMP_MUTE_RIGHT);
3183162922Sariff		}
3184162922Sariff		hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
3185162922Sariff	}
3186162922Sariff	hdac_unlock(sc);
3187162922Sariff
3188162922Sariff	return (left | (right << 8));
3189162922Sariff}
3190162922Sariff
3191162922Sariffstatic int
3192162922Sariffhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
3193162922Sariff{
3194162922Sariff	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
3195162922Sariff	struct hdac_widget *w, *cw;
3196162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3197162922Sariff	uint32_t ret = src, target;
3198162922Sariff	int i, j;
3199162922Sariff
3200162922Sariff	target = 0;
3201162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
3202162922Sariff		if (src & (1 << i)) {
3203162922Sariff			target = 1 << i;
3204162922Sariff			break;
3205162922Sariff		}
3206162922Sariff	}
3207162922Sariff
3208162922Sariff	hdac_lock(sc);
3209162922Sariff
3210162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3211162922Sariff		w = hdac_widget_get(devinfo, i);
3212162965Sariff		if (w == NULL || w->enable == 0)
3213162922Sariff			continue;
3214162922Sariff		if (!(w->pflags & HDA_ADC_RECSEL))
3215162922Sariff			continue;
3216162922Sariff		for (j = 0; j < w->nconns; j++) {
3217162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
3218162922Sariff			if (cw == NULL || cw->enable == 0)
3219162922Sariff				continue;
3220162922Sariff			if ((target == SOUND_MASK_VOLUME &&
3221162922Sariff			    cw->type !=
3222162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
3223162922Sariff			    (target != SOUND_MASK_VOLUME &&
3224162922Sariff			    cw->type ==
3225162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER))
3226162922Sariff				continue;
3227162922Sariff			if (cw->ctlflags & target) {
3228162922Sariff				hdac_widget_connection_select(w, j);
3229162922Sariff				ret = target;
3230162922Sariff				j += w->nconns;
3231162922Sariff			}
3232162922Sariff		}
3233162922Sariff	}
3234162922Sariff
3235162922Sariff	hdac_unlock(sc);
3236162922Sariff
3237162922Sariff	return (ret);
3238162922Sariff}
3239162922Sariff
3240162922Sariffstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
3241162922Sariff	KOBJMETHOD(mixer_init,		hdac_audio_ctl_ossmixer_init),
3242162922Sariff	KOBJMETHOD(mixer_set,		hdac_audio_ctl_ossmixer_set),
3243162922Sariff	KOBJMETHOD(mixer_setrecsrc,	hdac_audio_ctl_ossmixer_setrecsrc),
3244162922Sariff	{ 0, 0 }
3245162922Sariff};
3246162922SariffMIXER_DECLARE(hdac_audio_ctl_ossmixer);
3247162922Sariff
3248162922Sariff/****************************************************************************
3249162922Sariff * int hdac_attach(device_t)
3250162922Sariff *
3251162922Sariff * Attach the device into the kernel. Interrupts usually won't be enabled
3252162922Sariff * when this function is called. Setup everything that doesn't require
3253162922Sariff * interrupts and defer probing of codecs until interrupts are enabled.
3254162922Sariff ****************************************************************************/
3255162922Sariffstatic int
3256162922Sariffhdac_attach(device_t dev)
3257162922Sariff{
3258162922Sariff	struct hdac_softc *sc;
3259162922Sariff	int result;
3260162922Sariff	int i = 0;
3261162922Sariff
3262162922Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO);
3263162922Sariff	if (sc == NULL) {
3264162922Sariff		device_printf(dev, "cannot allocate softc\n");
3265162922Sariff		return (ENOMEM);
3266162922Sariff	}
3267163057Sariff
3268163057Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
3269162922Sariff	sc->dev = dev;
3270163257Sariff	sc->pci_subvendor = (uint32_t)pci_get_subdevice(sc->dev) << 16;
3271163257Sariff	sc->pci_subvendor |= (uint32_t)pci_get_subvendor(sc->dev) & 0x0000ffff;
3272162922Sariff
3273165281Sariff	if (sc->pci_subvendor == HP_NX6325_SUBVENDORX) {
3274165281Sariff		/* Screw nx6325 - subdevice/subvendor swapped */
3275165281Sariff		sc->pci_subvendor = HP_NX6325_SUBVENDOR;
3276165281Sariff	}
3277165281Sariff
3278164614Sariff	callout_init(&sc->poll_hda, CALLOUT_MPSAFE);
3279164614Sariff	callout_init(&sc->poll_hdac, CALLOUT_MPSAFE);
3280164614Sariff
3281164614Sariff	sc->poll_ticks = 1;
3282164614Sariff	if (resource_int_value(device_get_name(sc->dev),
3283164614Sariff	    device_get_unit(sc->dev), "polling", &i) == 0 && i != 0)
3284164614Sariff		sc->polling = 1;
3285164614Sariff	else
3286164614Sariff		sc->polling = 0;
3287164614Sariff
3288162922Sariff	sc->chan_size = pcm_getbuffersize(dev,
3289164614Sariff	    HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_MAX);
3290164614Sariff
3291162922Sariff	if (resource_int_value(device_get_name(sc->dev),
3292164614Sariff	    device_get_unit(sc->dev), "blocksize", &i) == 0 && i > 0) {
3293167648Sariff		i &= HDA_BLK_ALIGN;
3294167648Sariff		if (i < HDA_BLK_MIN)
3295167648Sariff			i = HDA_BLK_MIN;
3296162922Sariff		sc->chan_blkcnt = sc->chan_size / i;
3297162922Sariff		i = 0;
3298162922Sariff		while (sc->chan_blkcnt >> i)
3299162922Sariff			i++;
3300162922Sariff		sc->chan_blkcnt = 1 << (i - 1);
3301162922Sariff		if (sc->chan_blkcnt < HDA_BDL_MIN)
3302162922Sariff			sc->chan_blkcnt = HDA_BDL_MIN;
3303162922Sariff		else if (sc->chan_blkcnt > HDA_BDL_MAX)
3304162922Sariff			sc->chan_blkcnt = HDA_BDL_MAX;
3305162922Sariff	} else
3306162922Sariff		sc->chan_blkcnt = HDA_BDL_DEFAULT;
3307162922Sariff
3308162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
3309162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
3310162922Sariff	    0,					/* boundary */
3311162922Sariff	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
3312162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
3313162922Sariff	    NULL,				/* filtfunc */
3314162922Sariff	    NULL,				/* fistfuncarg */
3315165281Sariff	    sc->chan_size, 			/* maxsize */
3316162922Sariff	    1,					/* nsegments */
3317165281Sariff	    sc->chan_size, 			/* maxsegsz */
3318162922Sariff	    0,					/* flags */
3319162922Sariff	    NULL,				/* lockfunc */
3320162922Sariff	    NULL,				/* lockfuncarg */
3321162922Sariff	    &sc->chan_dmat);			/* dmat */
3322162922Sariff	if (result != 0) {
3323162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
3324162922Sariff		     __func__, result);
3325163057Sariff		snd_mtxfree(sc->lock);
3326162922Sariff		free(sc, M_DEVBUF);
3327162922Sariff		return (ENXIO);
3328162922Sariff	}
3329162922Sariff
3330162922Sariff
3331162922Sariff	sc->hdabus = NULL;
3332162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++)
3333162922Sariff		sc->codecs[i] = NULL;
3334162922Sariff
3335162922Sariff	pci_enable_busmaster(dev);
3336162922Sariff
3337162922Sariff	/* Allocate resources */
3338162922Sariff	result = hdac_mem_alloc(sc);
3339162922Sariff	if (result != 0)
3340163057Sariff		goto hdac_attach_fail;
3341162922Sariff	result = hdac_irq_alloc(sc);
3342162922Sariff	if (result != 0)
3343163057Sariff		goto hdac_attach_fail;
3344162922Sariff
3345162922Sariff	/* Get Capabilities */
3346162922Sariff	result = hdac_get_capabilities(sc);
3347162922Sariff	if (result != 0)
3348163057Sariff		goto hdac_attach_fail;
3349162922Sariff
3350162922Sariff	/* Allocate CORB and RIRB dma memory */
3351162922Sariff	result = hdac_dma_alloc(sc, &sc->corb_dma,
3352162922Sariff	    sc->corb_size * sizeof(uint32_t));
3353162922Sariff	if (result != 0)
3354163057Sariff		goto hdac_attach_fail;
3355162922Sariff	result = hdac_dma_alloc(sc, &sc->rirb_dma,
3356162922Sariff	    sc->rirb_size * sizeof(struct hdac_rirb));
3357162922Sariff	if (result != 0)
3358163057Sariff		goto hdac_attach_fail;
3359162922Sariff
3360162922Sariff	/* Quiesce everything */
3361162922Sariff	hdac_reset(sc);
3362162922Sariff
3363162922Sariff	/* Disable PCI-Express QOS */
3364162922Sariff	pci_write_config(sc->dev, 0x44,
3365162922Sariff	    pci_read_config(sc->dev, 0x44, 1) & 0xf8, 1);
3366162922Sariff
3367162922Sariff	/* Initialize the CORB and RIRB */
3368162922Sariff	hdac_corb_init(sc);
3369162922Sariff	hdac_rirb_init(sc);
3370162922Sariff
3371162922Sariff	/* Defer remaining of initialization until interrupts are enabled */
3372162922Sariff	sc->intrhook.ich_func = hdac_attach2;
3373162922Sariff	sc->intrhook.ich_arg = (void *)sc;
3374162922Sariff	if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
3375162922Sariff		sc->intrhook.ich_func = NULL;
3376162922Sariff		hdac_attach2((void *)sc);
3377162922Sariff	}
3378162922Sariff
3379163057Sariff	return (0);
3380162922Sariff
3381163057Sariffhdac_attach_fail:
3382162922Sariff	hdac_dma_free(&sc->rirb_dma);
3383162922Sariff	hdac_dma_free(&sc->corb_dma);
3384162922Sariff	hdac_irq_free(sc);
3385162922Sariff	hdac_mem_free(sc);
3386162922Sariff	snd_mtxfree(sc->lock);
3387163057Sariff	free(sc, M_DEVBUF);
3388162922Sariff
3389163057Sariff	return (ENXIO);
3390162922Sariff}
3391162922Sariff
3392162922Sariffstatic void
3393162922Sariffhdac_audio_parse(struct hdac_devinfo *devinfo)
3394162922Sariff{
3395162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3396162922Sariff	struct hdac_widget *w;
3397162922Sariff	uint32_t res;
3398162922Sariff	int i;
3399162922Sariff	nid_t cad, nid;
3400162922Sariff
3401162922Sariff	cad = devinfo->codec->cad;
3402162922Sariff	nid = devinfo->nid;
3403162922Sariff
3404162922Sariff	hdac_command(sc,
3405162922Sariff	    HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), cad);
3406162922Sariff
3407162922Sariff	DELAY(100);
3408162922Sariff
3409162922Sariff	res = hdac_command(sc,
3410162922Sariff	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
3411162922Sariff
3412162922Sariff	devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
3413162922Sariff	devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
3414162922Sariff	devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
3415162922Sariff
3416163057Sariff	HDA_BOOTVERBOSE(
3417162922Sariff		device_printf(sc->dev, "       Vendor: 0x%08x\n",
3418162922Sariff		    devinfo->vendor_id);
3419162922Sariff		device_printf(sc->dev, "       Device: 0x%08x\n",
3420162922Sariff		    devinfo->device_id);
3421162922Sariff		device_printf(sc->dev, "     Revision: 0x%08x\n",
3422162922Sariff		    devinfo->revision_id);
3423162922Sariff		device_printf(sc->dev, "     Stepping: 0x%08x\n",
3424162922Sariff		    devinfo->stepping_id);
3425162922Sariff		device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
3426162922Sariff		    sc->pci_subvendor);
3427162922Sariff		device_printf(sc->dev, "        Nodes: start=%d "
3428162922Sariff		    "endnode=%d total=%d\n",
3429162922Sariff		    devinfo->startnode, devinfo->endnode, devinfo->nodecnt);
3430162922Sariff	);
3431162922Sariff
3432162922Sariff	res = hdac_command(sc,
3433162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS),
3434162922Sariff	    cad);
3435162922Sariff	devinfo->function.audio.supp_stream_formats = res;
3436162922Sariff
3437162922Sariff	res = hdac_command(sc,
3438162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE),
3439162922Sariff	    cad);
3440162922Sariff	devinfo->function.audio.supp_pcm_size_rate = res;
3441162922Sariff
3442162922Sariff	res = hdac_command(sc,
3443162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP),
3444162922Sariff	    cad);
3445162922Sariff	devinfo->function.audio.outamp_cap = res;
3446162922Sariff
3447162922Sariff	res = hdac_command(sc,
3448162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP),
3449162922Sariff	    cad);
3450162922Sariff	devinfo->function.audio.inamp_cap = res;
3451162922Sariff
3452162922Sariff	if (devinfo->nodecnt > 0) {
3453162922Sariff		hdac_unlock(sc);
3454162922Sariff		devinfo->widget = (struct hdac_widget *)malloc(
3455162922Sariff		    sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
3456162922Sariff		    M_NOWAIT | M_ZERO);
3457162922Sariff		hdac_lock(sc);
3458162922Sariff	} else
3459162922Sariff		devinfo->widget = NULL;
3460162922Sariff
3461162922Sariff	if (devinfo->widget == NULL) {
3462162922Sariff		device_printf(sc->dev, "unable to allocate widgets!\n");
3463162922Sariff		devinfo->endnode = devinfo->startnode;
3464162922Sariff		devinfo->nodecnt = 0;
3465162922Sariff		return;
3466162922Sariff	}
3467162922Sariff
3468162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3469162922Sariff		w = hdac_widget_get(devinfo, i);
3470162922Sariff		if (w == NULL)
3471162922Sariff			device_printf(sc->dev, "Ghost widget! nid=%d!\n", i);
3472162922Sariff		else {
3473162922Sariff			w->devinfo = devinfo;
3474162922Sariff			w->nid = i;
3475162922Sariff			w->enable = 1;
3476162922Sariff			w->selconn = -1;
3477162922Sariff			w->pflags = 0;
3478162922Sariff			w->ctlflags = 0;
3479162965Sariff			w->param.eapdbtl = HDAC_INVALID;
3480162922Sariff			hdac_widget_parse(w);
3481162922Sariff		}
3482162922Sariff	}
3483162922Sariff}
3484162922Sariff
3485162922Sariffstatic void
3486162922Sariffhdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
3487162922Sariff{
3488162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3489162922Sariff	struct hdac_audio_ctl *ctls;
3490162922Sariff	struct hdac_widget *w, *cw;
3491162922Sariff	int i, j, cnt, max, ocap, icap;
3492163057Sariff	int mute, offset, step, size;
3493162922Sariff
3494162922Sariff	/* XXX This is redundant */
3495162922Sariff	max = 0;
3496162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3497162922Sariff		w = hdac_widget_get(devinfo, i);
3498162922Sariff		if (w == NULL || w->enable == 0)
3499162922Sariff			continue;
3500162922Sariff		if (w->param.outamp_cap != 0)
3501162922Sariff			max++;
3502162922Sariff		if (w->param.inamp_cap != 0) {
3503162922Sariff			switch (w->type) {
3504162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3505162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3506162922Sariff				for (j = 0; j < w->nconns; j++) {
3507162922Sariff					cw = hdac_widget_get(devinfo,
3508162922Sariff					    w->conns[j]);
3509162922Sariff					if (cw == NULL || cw->enable == 0)
3510162922Sariff						continue;
3511162922Sariff					max++;
3512162922Sariff				}
3513162922Sariff				break;
3514162922Sariff			default:
3515162922Sariff				max++;
3516162922Sariff				break;
3517162922Sariff			}
3518162922Sariff		}
3519162922Sariff	}
3520162922Sariff
3521162922Sariff	devinfo->function.audio.ctlcnt = max;
3522162922Sariff
3523162922Sariff	if (max < 1)
3524162922Sariff		return;
3525162922Sariff
3526162922Sariff	hdac_unlock(sc);
3527162922Sariff	ctls = (struct hdac_audio_ctl *)malloc(
3528162922Sariff	    sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT);
3529162922Sariff	hdac_lock(sc);
3530162922Sariff
3531162922Sariff	if (ctls == NULL) {
3532162922Sariff		/* Blekh! */
3533162922Sariff		device_printf(sc->dev, "unable to allocate ctls!\n");
3534162922Sariff		devinfo->function.audio.ctlcnt = 0;
3535162922Sariff		return;
3536162922Sariff	}
3537162922Sariff
3538162922Sariff	cnt = 0;
3539162922Sariff	for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) {
3540162922Sariff		if (cnt >= max) {
3541162922Sariff			device_printf(sc->dev, "%s: Ctl overflow!\n",
3542162922Sariff			    __func__);
3543162922Sariff			break;
3544162922Sariff		}
3545162922Sariff		w = hdac_widget_get(devinfo, i);
3546162922Sariff		if (w == NULL || w->enable == 0)
3547162922Sariff			continue;
3548162922Sariff		ocap = w->param.outamp_cap;
3549162922Sariff		icap = w->param.inamp_cap;
3550162922Sariff		if (ocap != 0) {
3551163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap);
3552163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap);
3553163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap);
3554163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap);
3555163057Sariff			/*if (offset > step) {
3556163057Sariff				HDA_BOOTVERBOSE(
3557163057Sariff					device_printf(sc->dev,
3558163057Sariff					    "HDA_DEBUG: BUGGY outamp: nid=%d "
3559163057Sariff					    "[offset=%d > step=%d]\n",
3560163057Sariff					    w->nid, offset, step);
3561163057Sariff				);
3562163057Sariff				offset = step;
3563163057Sariff			}*/
3564162922Sariff			ctls[cnt].enable = 1;
3565162922Sariff			ctls[cnt].widget = w;
3566163057Sariff			ctls[cnt].mute = mute;
3567163057Sariff			ctls[cnt].step = step;
3568163057Sariff			ctls[cnt].size = size;
3569163057Sariff			ctls[cnt].offset = offset;
3570163057Sariff			ctls[cnt].left = offset;
3571163057Sariff			ctls[cnt].right = offset;
3572162922Sariff			ctls[cnt++].dir = HDA_CTL_OUT;
3573162922Sariff		}
3574162922Sariff
3575162922Sariff		if (icap != 0) {
3576163057Sariff			mute = HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(icap);
3577163057Sariff			step = HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(icap);
3578163057Sariff			size = HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(icap);
3579163057Sariff			offset = HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(icap);
3580163057Sariff			/*if (offset > step) {
3581163057Sariff				HDA_BOOTVERBOSE(
3582163057Sariff					device_printf(sc->dev,
3583163057Sariff					    "HDA_DEBUG: BUGGY inamp: nid=%d "
3584163057Sariff					    "[offset=%d > step=%d]\n",
3585163057Sariff					    w->nid, offset, step);
3586163057Sariff				);
3587163057Sariff				offset = step;
3588163057Sariff			}*/
3589162922Sariff			switch (w->type) {
3590162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3591162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3592162922Sariff				for (j = 0; j < w->nconns; j++) {
3593162922Sariff					if (cnt >= max) {
3594162922Sariff						device_printf(sc->dev,
3595162922Sariff						    "%s: Ctl overflow!\n",
3596162922Sariff						    __func__);
3597162922Sariff						break;
3598162922Sariff					}
3599162922Sariff					cw = hdac_widget_get(devinfo,
3600162922Sariff					    w->conns[j]);
3601162922Sariff					if (cw == NULL || cw->enable == 0)
3602162922Sariff						continue;
3603162922Sariff					ctls[cnt].enable = 1;
3604162922Sariff					ctls[cnt].widget = w;
3605162922Sariff					ctls[cnt].childwidget = cw;
3606162922Sariff					ctls[cnt].index = j;
3607163057Sariff					ctls[cnt].mute = mute;
3608163057Sariff					ctls[cnt].step = step;
3609163057Sariff					ctls[cnt].size = size;
3610163057Sariff					ctls[cnt].offset = offset;
3611163057Sariff					ctls[cnt].left = offset;
3612163057Sariff					ctls[cnt].right = offset;
3613162922Sariff					ctls[cnt++].dir = HDA_CTL_IN;
3614162922Sariff				}
3615162922Sariff				break;
3616162922Sariff			default:
3617162922Sariff				if (cnt >= max) {
3618162922Sariff					device_printf(sc->dev,
3619162922Sariff					    "%s: Ctl overflow!\n",
3620162922Sariff					    __func__);
3621162922Sariff					break;
3622162922Sariff				}
3623162922Sariff				ctls[cnt].enable = 1;
3624162922Sariff				ctls[cnt].widget = w;
3625163057Sariff				ctls[cnt].mute = mute;
3626163057Sariff				ctls[cnt].step = step;
3627163057Sariff				ctls[cnt].size = size;
3628163057Sariff				ctls[cnt].offset = offset;
3629163057Sariff				ctls[cnt].left = offset;
3630163057Sariff				ctls[cnt].right = offset;
3631162922Sariff				ctls[cnt++].dir = HDA_CTL_IN;
3632162922Sariff				break;
3633162922Sariff			}
3634162922Sariff		}
3635162922Sariff	}
3636162922Sariff
3637162922Sariff	devinfo->function.audio.ctl = ctls;
3638162922Sariff}
3639162922Sariff
3640162965Sariffstatic const struct {
3641162965Sariff	uint32_t model;
3642162965Sariff	uint32_t id;
3643162965Sariff	uint32_t set, unset;
3644162965Sariff} hdac_quirks[] = {
3645163057Sariff	/*
3646163057Sariff	 * XXX Force stereo quirk. Monoural recording / playback
3647163057Sariff	 *     on few codecs (especially ALC880) seems broken or
3648163057Sariff	 *     perhaps unsupported.
3649163057Sariff	 */
3650163057Sariff	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
3651165069Sariff	    HDA_QUIRK_FORCESTEREO | HDA_QUIRK_VREF, 0 },
3652162965Sariff	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
3653165039Sariff	    HDA_QUIRK_GPIO0, 0 },
3654162965Sariff	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
3655165039Sariff	    HDA_QUIRK_GPIO0, 0 },
3656165281Sariff	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
3657165281Sariff	    HDA_QUIRK_GPIO0, 0 },
3658167623Sariff	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
3659167623Sariff	    HDA_QUIRK_GPIO0, 0 },
3660163276Sariff	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
3661163276Sariff	    HDA_QUIRK_EAPDINV, 0 },
3662163432Sariff	{ ASUS_A8JC_SUBVENDOR, HDA_CODEC_AD1986A,
3663163432Sariff	    HDA_QUIRK_EAPDINV, 0 },
3664165281Sariff	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
3665165281Sariff	    HDA_QUIRK_GPIO1, 0 },
3666164657Sariff	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
3667164614Sariff	    HDA_QUIRK_EAPDINV, 0 },
3668164657Sariff	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
3669164657Sariff	    HDA_QUIRK_EAPDINV, 0 },
3670165039Sariff	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
3671165039Sariff	    HDA_QUIRK_GPIO0 | HDA_QUIRK_GPIO1, 0 },
3672162965Sariff	{ HDA_MATCH_ALL, HDA_CODEC_CXVENICE,
3673162965Sariff	    0, HDA_QUIRK_FORCESTEREO },
3674162965Sariff	{ HDA_MATCH_ALL, HDA_CODEC_STACXXXX,
3675162965Sariff	    HDA_QUIRK_SOFTPCMVOL, 0 }
3676162965Sariff};
3677162965Sariff#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
3678162965Sariff
3679162922Sariffstatic void
3680162922Sariffhdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
3681162922Sariff{
3682162922Sariff	struct hdac_widget *w;
3683165466Sariff	struct hdac_audio_ctl *ctl;
3684162965Sariff	uint32_t id, subvendor;
3685162922Sariff	int i;
3686162922Sariff
3687163057Sariff	id = hdac_codec_id(devinfo);
3688163057Sariff	subvendor = devinfo->codec->sc->pci_subvendor;
3689163057Sariff
3690162922Sariff	/*
3691163057Sariff	 * Quirks
3692162922Sariff	 */
3693163057Sariff	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
3694163257Sariff		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subvendor) &&
3695163257Sariff		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
3696163057Sariff			continue;
3697163057Sariff		if (hdac_quirks[i].set != 0)
3698163057Sariff			devinfo->function.audio.quirks |=
3699163057Sariff			    hdac_quirks[i].set;
3700163057Sariff		if (hdac_quirks[i].unset != 0)
3701163057Sariff			devinfo->function.audio.quirks &=
3702163057Sariff			    ~(hdac_quirks[i].unset);
3703163057Sariff	}
3704163057Sariff
3705162922Sariff	switch (id) {
3706162922Sariff	case HDA_CODEC_ALC260:
3707162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3708162922Sariff			w = hdac_widget_get(devinfo, i);
3709162922Sariff			if (w == NULL || w->enable == 0)
3710162922Sariff				continue;
3711162922Sariff			if (w->type !=
3712162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
3713162922Sariff				continue;
3714162922Sariff			if (w->nid != 5)
3715162922Sariff				w->enable = 0;
3716162922Sariff		}
3717166294Sariff		if (subvendor == HP_XW4300_SUBVENDOR) {
3718166294Sariff			ctl = hdac_audio_ctl_amp_get(devinfo, 16, 0, 1);
3719166294Sariff			if (ctl != NULL && ctl->widget != NULL) {
3720166294Sariff				ctl->ossmask = SOUND_MASK_SPEAKER;
3721166294Sariff				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
3722166294Sariff			}
3723166294Sariff			ctl = hdac_audio_ctl_amp_get(devinfo, 17, 0, 1);
3724166294Sariff			if (ctl != NULL && ctl->widget != NULL) {
3725166294Sariff				ctl->ossmask = SOUND_MASK_SPEAKER;
3726166294Sariff				ctl->widget->ctlflags |= SOUND_MASK_SPEAKER;
3727166294Sariff			}
3728166294Sariff		}
3729162922Sariff		break;
3730165103Sariff	case HDA_CODEC_ALC861:
3731165466Sariff		ctl = hdac_audio_ctl_amp_get(devinfo, 28, 1, 1);
3732165466Sariff		if (ctl != NULL)
3733165466Sariff			ctl->muted = HDA_AMP_MUTE_ALL;
3734165103Sariff		break;
3735162922Sariff	case HDA_CODEC_ALC880:
3736162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3737162922Sariff			w = hdac_widget_get(devinfo, i);
3738162922Sariff			if (w == NULL || w->enable == 0)
3739162922Sariff				continue;
3740162922Sariff			if (w->type ==
3741162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
3742162922Sariff			    w->nid != 9 && w->nid != 29) {
3743162922Sariff					w->enable = 0;
3744162922Sariff			} else if (w->type !=
3745162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET &&
3746162922Sariff			    w->nid == 29) {
3747163057Sariff				w->type =
3748163057Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET;
3749163057Sariff				w->param.widget_cap &=
3750163057Sariff				    ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
3751162922Sariff				w->param.widget_cap |=
3752162922Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
3753162922Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
3754162922Sariff				strlcpy(w->name, "beep widget", sizeof(w->name));
3755162922Sariff			}
3756162922Sariff		}
3757162922Sariff		break;
3758166965Sariff	case HDA_CODEC_ALC883:
3759166965Sariff		/*
3760166965Sariff		 * nid: 24/25 = External (jack) or Internal (fixed) Mic.
3761166965Sariff		 *              Clear vref cap for jack connectivity.
3762166965Sariff		 */
3763166965Sariff		w = hdac_widget_get(devinfo, 24);
3764166965Sariff		if (w != NULL && w->enable != 0 && w->type ==
3765166965Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
3766166965Sariff		    (w->wclass.pin.config &
3767166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
3768166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
3769166965Sariff			w->wclass.pin.cap &= ~(
3770166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
3771166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
3772166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
3773166965Sariff		w = hdac_widget_get(devinfo, 25);
3774166965Sariff		if (w != NULL && w->enable != 0 && w->type ==
3775166965Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
3776166965Sariff		    (w->wclass.pin.config &
3777166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
3778166965Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK)
3779166965Sariff			w->wclass.pin.cap &= ~(
3780166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_100_MASK |
3781166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_80_MASK |
3782166965Sariff			    HDA_PARAM_PIN_CAP_VREF_CTRL_50_MASK);
3783166965Sariff		/*
3784166965Sariff		 * nid: 26 = Line-in, leave it alone.
3785166965Sariff		 */
3786166965Sariff		break;
3787163257Sariff	case HDA_CODEC_AD1981HD:
3788163257Sariff		w = hdac_widget_get(devinfo, 11);
3789163257Sariff		if (w != NULL && w->enable != 0 && w->nconns > 3)
3790163257Sariff			w->selconn = 3;
3791163257Sariff		if (subvendor == IBM_M52_SUBVENDOR) {
3792163257Sariff			ctl = hdac_audio_ctl_amp_get(devinfo, 7, 0, 1);
3793163257Sariff			if (ctl != NULL)
3794163257Sariff				ctl->ossmask = SOUND_MASK_SPEAKER;
3795163257Sariff		}
3796163257Sariff		break;
3797162922Sariff	case HDA_CODEC_AD1986A:
3798162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3799162922Sariff			w = hdac_widget_get(devinfo, i);
3800162922Sariff			if (w == NULL || w->enable == 0)
3801162922Sariff				continue;
3802162922Sariff			if (w->type !=
3803162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
3804162922Sariff				continue;
3805162922Sariff			if (w->nid != 3)
3806162922Sariff				w->enable = 0;
3807162922Sariff		}
3808162922Sariff		break;
3809162922Sariff	case HDA_CODEC_STAC9221:
3810162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3811162922Sariff			w = hdac_widget_get(devinfo, i);
3812162922Sariff			if (w == NULL || w->enable == 0)
3813162922Sariff				continue;
3814162922Sariff			if (w->type !=
3815162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
3816162922Sariff				continue;
3817162922Sariff			if (w->nid != 2)
3818162922Sariff				w->enable = 0;
3819162922Sariff		}
3820162922Sariff		break;
3821162922Sariff	case HDA_CODEC_STAC9221D:
3822162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3823162922Sariff			w = hdac_widget_get(devinfo, i);
3824162922Sariff			if (w == NULL || w->enable == 0)
3825162922Sariff				continue;
3826162922Sariff			if (w->type ==
3827162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
3828162922Sariff			    w->nid != 6)
3829162922Sariff				w->enable = 0;
3830162922Sariff
3831162922Sariff		}
3832162922Sariff		break;
3833162922Sariff	default:
3834162922Sariff		break;
3835162922Sariff	}
3836162922Sariff}
3837162922Sariff
3838162922Sariffstatic int
3839162922Sariffhdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo)
3840162922Sariff{
3841162922Sariff	int *dev = &devinfo->function.audio.ossidx;
3842162922Sariff
3843162922Sariff	while (*dev < SOUND_MIXER_NRDEVICES) {
3844162922Sariff		switch (*dev) {
3845162922Sariff		case SOUND_MIXER_VOLUME:
3846162922Sariff		case SOUND_MIXER_BASS:
3847162922Sariff		case SOUND_MIXER_TREBLE:
3848162922Sariff		case SOUND_MIXER_PCM:
3849162922Sariff		case SOUND_MIXER_SPEAKER:
3850162922Sariff		case SOUND_MIXER_LINE:
3851162922Sariff		case SOUND_MIXER_MIC:
3852162922Sariff		case SOUND_MIXER_CD:
3853162922Sariff		case SOUND_MIXER_RECLEV:
3854162922Sariff		case SOUND_MIXER_OGAIN:	/* reserved for EAPD switch */
3855162922Sariff			(*dev)++;
3856162922Sariff			break;
3857162922Sariff		default:
3858162922Sariff			return (*dev)++;
3859162922Sariff			break;
3860162922Sariff		}
3861162922Sariff	}
3862162922Sariff
3863162922Sariff	return (-1);
3864162922Sariff}
3865162922Sariff
3866162922Sariffstatic int
3867162922Sariffhdac_widget_find_dac_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
3868162922Sariff{
3869162922Sariff	struct hdac_widget *w;
3870162922Sariff	int i, ret = 0;
3871162922Sariff
3872162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3873162922Sariff		return (0);
3874162922Sariff	w = hdac_widget_get(devinfo, nid);
3875162922Sariff	if (w == NULL || w->enable == 0)
3876162922Sariff		return (0);
3877162922Sariff	switch (w->type) {
3878162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
3879162922Sariff		w->pflags |= HDA_DAC_PATH;
3880162922Sariff		ret = 1;
3881162922Sariff		break;
3882162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3883162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3884162922Sariff		for (i = 0; i < w->nconns; i++) {
3885162922Sariff			if (hdac_widget_find_dac_path(devinfo,
3886162922Sariff			    w->conns[i], depth + 1) != 0) {
3887162922Sariff				if (w->selconn == -1)
3888162922Sariff					w->selconn = i;
3889162922Sariff				ret = 1;
3890162922Sariff				w->pflags |= HDA_DAC_PATH;
3891162922Sariff			}
3892162922Sariff		}
3893162922Sariff		break;
3894162922Sariff	default:
3895162922Sariff		break;
3896162922Sariff	}
3897162922Sariff	return (ret);
3898162922Sariff}
3899162922Sariff
3900162922Sariffstatic int
3901162922Sariffhdac_widget_find_adc_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
3902162922Sariff{
3903162922Sariff	struct hdac_widget *w;
3904162922Sariff	int i, conndev, ret = 0;
3905162922Sariff
3906162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3907162922Sariff		return (0);
3908162922Sariff	w = hdac_widget_get(devinfo, nid);
3909162922Sariff	if (w == NULL || w->enable == 0)
3910162922Sariff		return (0);
3911162922Sariff	switch (w->type) {
3912162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
3913162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3914162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3915162922Sariff		for (i = 0; i < w->nconns; i++) {
3916162922Sariff			if (hdac_widget_find_adc_path(devinfo, w->conns[i],
3917162922Sariff			    depth + 1) != 0) {
3918162922Sariff				if (w->selconn == -1)
3919162922Sariff					w->selconn = i;
3920162922Sariff				w->pflags |= HDA_ADC_PATH;
3921162922Sariff				ret = 1;
3922162922Sariff			}
3923162922Sariff		}
3924162922Sariff		break;
3925162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
3926162922Sariff		conndev = w->wclass.pin.config &
3927162922Sariff		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
3928162922Sariff		if (HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
3929162922Sariff		    (conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_CD ||
3930162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN ||
3931162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN)) {
3932162922Sariff			w->pflags |= HDA_ADC_PATH;
3933162922Sariff			ret = 1;
3934162922Sariff		}
3935162922Sariff		break;
3936162922Sariff	/*case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3937162922Sariff		if (w->pflags & HDA_DAC_PATH) {
3938162922Sariff			w->pflags |= HDA_ADC_PATH;
3939162922Sariff			ret = 1;
3940162922Sariff		}
3941162922Sariff		break;*/
3942162922Sariff	default:
3943162922Sariff		break;
3944162922Sariff	}
3945162922Sariff	return (ret);
3946162922Sariff}
3947162922Sariff
3948162922Sariffstatic uint32_t
3949162922Sariffhdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo,
3950162922Sariff				nid_t nid, nid_t pnid, int index, int depth)
3951162922Sariff{
3952162922Sariff	struct hdac_widget *w, *pw;
3953162922Sariff	struct hdac_audio_ctl *ctl;
3954162922Sariff	uint32_t fl = 0;
3955162922Sariff	int i, ossdev, conndev, strategy;
3956162922Sariff
3957162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3958162922Sariff		return (0);
3959162922Sariff
3960162922Sariff	w = hdac_widget_get(devinfo, nid);
3961162922Sariff	if (w == NULL || w->enable == 0)
3962162922Sariff		return (0);
3963162922Sariff
3964162922Sariff	pw = hdac_widget_get(devinfo, pnid);
3965162922Sariff	strategy = devinfo->function.audio.parsing_strategy;
3966162922Sariff
3967162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER
3968162922Sariff	    || w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) {
3969162922Sariff		for (i = 0; i < w->nconns; i++) {
3970162922Sariff			fl |= hdac_audio_ctl_outamp_build(devinfo, w->conns[i],
3971162922Sariff			    w->nid, i, depth + 1);
3972162922Sariff		}
3973162922Sariff		w->ctlflags |= fl;
3974162922Sariff		return (fl);
3975162922Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT &&
3976162922Sariff	    (w->pflags & HDA_DAC_PATH)) {
3977162922Sariff		i = 0;
3978162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3979162922Sariff			if (ctl->enable == 0 || ctl->widget == NULL)
3980162922Sariff				continue;
3981163057Sariff			/* XXX This should be compressed! */
3982162922Sariff			if ((ctl->widget->nid == w->nid) ||
3983162922Sariff			    (ctl->widget->nid == pnid && ctl->index == index &&
3984162922Sariff			    (ctl->dir & HDA_CTL_IN)) ||
3985162922Sariff			    (ctl->widget->nid == pnid && pw != NULL &&
3986162922Sariff			    pw->type ==
3987162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
3988162922Sariff			    (pw->nconns < 2 || pw->selconn == index ||
3989162922Sariff			    pw->selconn == -1) &&
3990162922Sariff			    (ctl->dir & HDA_CTL_OUT)) ||
3991162922Sariff			    (strategy == HDA_PARSE_DIRECT &&
3992162922Sariff			    ctl->widget->nid == w->nid)) {
3993163057Sariff				/*if (pw != NULL && pw->selconn == -1)
3994162922Sariff					pw->selconn = index;
3995162922Sariff				fl |= SOUND_MASK_VOLUME;
3996162922Sariff				fl |= SOUND_MASK_PCM;
3997162922Sariff				ctl->ossmask |= SOUND_MASK_VOLUME;
3998162922Sariff				ctl->ossmask |= SOUND_MASK_PCM;
3999163057Sariff				ctl->ossdev = SOUND_MIXER_PCM;*/
4000163057Sariff				if (!(w->ctlflags & SOUND_MASK_PCM) ||
4001163057Sariff				    (pw != NULL &&
4002163057Sariff				    !(pw->ctlflags & SOUND_MASK_PCM))) {
4003163057Sariff					fl |= SOUND_MASK_VOLUME;
4004163057Sariff					fl |= SOUND_MASK_PCM;
4005163057Sariff					ctl->ossmask |= SOUND_MASK_VOLUME;
4006163057Sariff					ctl->ossmask |= SOUND_MASK_PCM;
4007163057Sariff					ctl->ossdev = SOUND_MIXER_PCM;
4008163057Sariff					w->ctlflags |= SOUND_MASK_VOLUME;
4009163057Sariff					w->ctlflags |= SOUND_MASK_PCM;
4010163057Sariff					if (pw != NULL) {
4011163057Sariff						if (pw->selconn == -1)
4012163057Sariff							pw->selconn = index;
4013163057Sariff						pw->ctlflags |=
4014163057Sariff						    SOUND_MASK_VOLUME;
4015163057Sariff						pw->ctlflags |=
4016163057Sariff						    SOUND_MASK_PCM;
4017163057Sariff					}
4018163057Sariff				}
4019162922Sariff			}
4020162922Sariff		}
4021162922Sariff		w->ctlflags |= fl;
4022162922Sariff		return (fl);
4023164614Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4024164614Sariff	    HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
4025162922Sariff	    (w->pflags & HDA_ADC_PATH)) {
4026162922Sariff		conndev = w->wclass.pin.config &
4027162922Sariff		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4028162922Sariff		i = 0;
4029162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4030162922Sariff			if (ctl->enable == 0 || ctl->widget == NULL)
4031162922Sariff				continue;
4032163057Sariff			/* XXX This should be compressed! */
4033162922Sariff			if (((ctl->widget->nid == pnid && ctl->index == index &&
4034162922Sariff			    (ctl->dir & HDA_CTL_IN)) ||
4035162922Sariff			    (ctl->widget->nid == pnid && pw != NULL &&
4036162922Sariff			    pw->type ==
4037162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4038162922Sariff			    (pw->nconns < 2 || pw->selconn == index ||
4039162922Sariff			    pw->selconn == -1) &&
4040162922Sariff			    (ctl->dir & HDA_CTL_OUT)) ||
4041162922Sariff			    (strategy == HDA_PARSE_DIRECT &&
4042162922Sariff			    ctl->widget->nid == w->nid)) &&
4043163057Sariff			    !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
4044162922Sariff				if (pw != NULL && pw->selconn == -1)
4045162922Sariff					pw->selconn = index;
4046162922Sariff				ossdev = 0;
4047162922Sariff				switch (conndev) {
4048162922Sariff				case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
4049162922Sariff					ossdev = SOUND_MIXER_MIC;
4050162922Sariff					break;
4051162922Sariff				case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
4052162922Sariff					ossdev = SOUND_MIXER_LINE;
4053162922Sariff					break;
4054162922Sariff				case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
4055162922Sariff					ossdev = SOUND_MIXER_CD;
4056162922Sariff					break;
4057162922Sariff				default:
4058162922Sariff					ossdev =
4059162922Sariff					    hdac_audio_ctl_ossmixer_getnextdev(
4060162922Sariff					    devinfo);
4061162922Sariff					if (ossdev < 0)
4062162922Sariff						ossdev = 0;
4063162922Sariff					break;
4064162922Sariff				}
4065162922Sariff				if (strategy == HDA_PARSE_MIXER) {
4066162922Sariff					fl |= SOUND_MASK_VOLUME;
4067162922Sariff					ctl->ossmask |= SOUND_MASK_VOLUME;
4068162922Sariff				}
4069162922Sariff				fl |= 1 << ossdev;
4070162922Sariff				ctl->ossmask |= 1 << ossdev;
4071162922Sariff				ctl->ossdev = ossdev;
4072162922Sariff			}
4073162922Sariff		}
4074162922Sariff		w->ctlflags |= fl;
4075162922Sariff		return (fl);
4076162922Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
4077162922Sariff		i = 0;
4078162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4079162922Sariff			if (ctl->enable == 0 || ctl->widget == NULL)
4080162922Sariff				continue;
4081163057Sariff			/* XXX This should be compressed! */
4082162922Sariff			if (((ctl->widget->nid == pnid && ctl->index == index &&
4083162922Sariff			    (ctl->dir & HDA_CTL_IN)) ||
4084162922Sariff			    (ctl->widget->nid == pnid && pw != NULL &&
4085162922Sariff			    pw->type ==
4086162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
4087162922Sariff			    (pw->nconns < 2 || pw->selconn == index ||
4088162922Sariff			    pw->selconn == -1) &&
4089162922Sariff			    (ctl->dir & HDA_CTL_OUT)) ||
4090162922Sariff			    (strategy == HDA_PARSE_DIRECT &&
4091162922Sariff			    ctl->widget->nid == w->nid)) &&
4092163057Sariff			    !(ctl->ossmask & ~SOUND_MASK_VOLUME)) {
4093162922Sariff				if (pw != NULL && pw->selconn == -1)
4094162922Sariff					pw->selconn = index;
4095162922Sariff				fl |= SOUND_MASK_VOLUME;
4096162922Sariff				fl |= SOUND_MASK_SPEAKER;
4097162922Sariff				ctl->ossmask |= SOUND_MASK_VOLUME;
4098162922Sariff				ctl->ossmask |= SOUND_MASK_SPEAKER;
4099162922Sariff				ctl->ossdev = SOUND_MIXER_SPEAKER;
4100162922Sariff			}
4101162922Sariff		}
4102162922Sariff		w->ctlflags |= fl;
4103162922Sariff		return (fl);
4104162922Sariff	}
4105162922Sariff	return (0);
4106162922Sariff}
4107162922Sariff
4108162922Sariffstatic uint32_t
4109162922Sariffhdac_audio_ctl_inamp_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4110162922Sariff{
4111162922Sariff	struct hdac_widget *w, *cw;
4112162922Sariff	struct hdac_audio_ctl *ctl;
4113162922Sariff	uint32_t fl;
4114162922Sariff	int i;
4115162922Sariff
4116162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
4117162922Sariff		return (0);
4118162922Sariff
4119162922Sariff	w = hdac_widget_get(devinfo, nid);
4120162922Sariff	if (w == NULL || w->enable == 0)
4121162922Sariff		return (0);
4122162922Sariff	/*if (!(w->pflags & HDA_ADC_PATH))
4123162922Sariff		return (0);
4124162922Sariff	if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
4125162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4126162922Sariff		return (0);*/
4127162922Sariff	i = 0;
4128162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4129162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL)
4130162922Sariff			continue;
4131162922Sariff		if (ctl->widget->nid == nid) {
4132162922Sariff			ctl->ossmask |= SOUND_MASK_RECLEV;
4133162922Sariff			w->ctlflags |= SOUND_MASK_RECLEV;
4134162922Sariff			return (SOUND_MASK_RECLEV);
4135162922Sariff		}
4136162922Sariff	}
4137162922Sariff	for (i = 0; i < w->nconns; i++) {
4138162922Sariff		cw = hdac_widget_get(devinfo, w->conns[i]);
4139162922Sariff		if (cw == NULL || cw->enable == 0)
4140162922Sariff			continue;
4141162922Sariff		if (cw->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
4142162922Sariff			continue;
4143162922Sariff		fl = hdac_audio_ctl_inamp_build(devinfo, cw->nid, depth + 1);
4144162922Sariff		if (fl != 0) {
4145162922Sariff			cw->ctlflags |= fl;
4146162922Sariff			w->ctlflags |= fl;
4147162922Sariff			return (fl);
4148162922Sariff		}
4149162922Sariff	}
4150162922Sariff	return (0);
4151162922Sariff}
4152162922Sariff
4153162922Sariffstatic int
4154162922Sariffhdac_audio_ctl_recsel_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4155162922Sariff{
4156162922Sariff	struct hdac_widget *w, *cw;
4157162922Sariff	int i, child = 0;
4158162922Sariff
4159162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
4160162922Sariff		return (0);
4161162922Sariff
4162162922Sariff	w = hdac_widget_get(devinfo, nid);
4163162922Sariff	if (w == NULL || w->enable == 0)
4164162922Sariff		return (0);
4165162922Sariff	/*if (!(w->pflags & HDA_ADC_PATH))
4166162922Sariff		return (0);
4167162922Sariff	if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
4168162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4169162922Sariff		return (0);*/
4170162922Sariff	/* XXX weak! */
4171162922Sariff	for (i = 0; i < w->nconns; i++) {
4172162922Sariff		cw = hdac_widget_get(devinfo, w->conns[i]);
4173162922Sariff		if (cw == NULL)
4174162922Sariff			continue;
4175162922Sariff		if (++child > 1) {
4176162922Sariff			w->pflags |= HDA_ADC_RECSEL;
4177162922Sariff			return (1);
4178162922Sariff		}
4179162922Sariff	}
4180162922Sariff	for (i = 0; i < w->nconns; i++) {
4181162922Sariff		if (hdac_audio_ctl_recsel_build(devinfo,
4182162922Sariff		    w->conns[i], depth + 1) != 0)
4183162922Sariff			return (1);
4184162922Sariff	}
4185162922Sariff	return (0);
4186162922Sariff}
4187162922Sariff
4188162922Sariffstatic int
4189162922Sariffhdac_audio_build_tree_strategy(struct hdac_devinfo *devinfo)
4190162922Sariff{
4191162922Sariff	struct hdac_widget *w, *cw;
4192162922Sariff	int i, j, conndev, found_dac = 0;
4193162922Sariff	int strategy;
4194162922Sariff
4195162922Sariff	strategy = devinfo->function.audio.parsing_strategy;
4196162922Sariff
4197162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4198162922Sariff		w = hdac_widget_get(devinfo, i);
4199162922Sariff		if (w == NULL || w->enable == 0)
4200162922Sariff			continue;
4201162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4202162922Sariff			continue;
4203162922Sariff		if (!HDA_PARAM_PIN_CAP_OUTPUT_CAP(w->wclass.pin.cap))
4204162922Sariff			continue;
4205162922Sariff		conndev = w->wclass.pin.config &
4206162922Sariff		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
4207162922Sariff		if (!(conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
4208162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
4209162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT))
4210162922Sariff			continue;
4211162922Sariff		for (j = 0; j < w->nconns; j++) {
4212162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
4213162922Sariff			if (cw == NULL || cw->enable == 0)
4214162922Sariff				continue;
4215162922Sariff			if (strategy == HDA_PARSE_MIXER && !(cw->type ==
4216162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
4217162922Sariff			    cw->type ==
4218162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
4219162922Sariff				continue;
4220162922Sariff			if (hdac_widget_find_dac_path(devinfo, cw->nid, 0)
4221162922Sariff			    != 0) {
4222162922Sariff				if (w->selconn == -1)
4223162922Sariff					w->selconn = j;
4224162922Sariff				w->pflags |= HDA_DAC_PATH;
4225162922Sariff				found_dac++;
4226162922Sariff			}
4227162922Sariff		}
4228162922Sariff	}
4229162922Sariff
4230162922Sariff	return (found_dac);
4231162922Sariff}
4232162922Sariff
4233162922Sariffstatic void
4234162922Sariffhdac_audio_build_tree(struct hdac_devinfo *devinfo)
4235162922Sariff{
4236162922Sariff	struct hdac_widget *w;
4237162922Sariff	struct hdac_audio_ctl *ctl;
4238162922Sariff	int i, j, dacs, strategy;
4239162922Sariff
4240162922Sariff	/* Construct DAC path */
4241162922Sariff	strategy = HDA_PARSE_MIXER;
4242162922Sariff	devinfo->function.audio.parsing_strategy = strategy;
4243163057Sariff	HDA_BOOTVERBOSE(
4244162922Sariff		device_printf(devinfo->codec->sc->dev,
4245163057Sariff		    "HDA_DEBUG: HWiP: HDA Widget Parser - Revision %d\n",
4246162922Sariff		    HDA_WIDGET_PARSER_REV);
4247162922Sariff	);
4248162922Sariff	dacs = hdac_audio_build_tree_strategy(devinfo);
4249162922Sariff	if (dacs == 0) {
4250163057Sariff		HDA_BOOTVERBOSE(
4251162922Sariff			device_printf(devinfo->codec->sc->dev,
4252163057Sariff			    "HDA_DEBUG: HWiP: 0 DAC path found! "
4253163057Sariff			    "Retrying parser "
4254162922Sariff			    "using HDA_PARSE_DIRECT strategy.\n");
4255162922Sariff		);
4256162922Sariff		strategy = HDA_PARSE_DIRECT;
4257162922Sariff		devinfo->function.audio.parsing_strategy = strategy;
4258162922Sariff		dacs = hdac_audio_build_tree_strategy(devinfo);
4259162922Sariff	}
4260162922Sariff
4261163057Sariff	HDA_BOOTVERBOSE(
4262162922Sariff		device_printf(devinfo->codec->sc->dev,
4263163057Sariff		    "HDA_DEBUG: HWiP: Found %d DAC path using HDA_PARSE_%s "
4264163057Sariff		    "strategy.\n",
4265162922Sariff		    dacs, (strategy == HDA_PARSE_MIXER) ? "MIXER" : "DIRECT");
4266162922Sariff	);
4267162922Sariff
4268162922Sariff	/* Construct ADC path */
4269162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4270162922Sariff		w = hdac_widget_get(devinfo, i);
4271162922Sariff		if (w == NULL || w->enable == 0)
4272162922Sariff			continue;
4273162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
4274162922Sariff			continue;
4275162922Sariff		(void)hdac_widget_find_adc_path(devinfo, w->nid, 0);
4276162922Sariff	}
4277162922Sariff
4278162922Sariff	/* Output mixers */
4279162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4280162922Sariff		w = hdac_widget_get(devinfo, i);
4281162922Sariff		if (w == NULL || w->enable == 0)
4282162922Sariff			continue;
4283162922Sariff		if ((strategy == HDA_PARSE_MIXER &&
4284162922Sariff		    (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
4285162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
4286162922Sariff		    && (w->pflags & HDA_DAC_PATH)) ||
4287162922Sariff		    (strategy == HDA_PARSE_DIRECT && (w->pflags &
4288162922Sariff		    (HDA_DAC_PATH | HDA_ADC_PATH)))) {
4289162922Sariff			w->ctlflags |= hdac_audio_ctl_outamp_build(devinfo,
4290162922Sariff			    w->nid, devinfo->startnode - 1, 0, 0);
4291162922Sariff		} else if (w->type ==
4292162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
4293162922Sariff			j = 0;
4294162922Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &j)) !=
4295162922Sariff			    NULL) {
4296162922Sariff				if (ctl->enable == 0 || ctl->widget == NULL)
4297162922Sariff					continue;
4298162922Sariff				if (ctl->widget->nid != w->nid)
4299162922Sariff					continue;
4300162922Sariff				ctl->ossmask |= SOUND_MASK_VOLUME;
4301162922Sariff				ctl->ossmask |= SOUND_MASK_SPEAKER;
4302162922Sariff				ctl->ossdev = SOUND_MIXER_SPEAKER;
4303162922Sariff				w->ctlflags |= SOUND_MASK_VOLUME;
4304162922Sariff				w->ctlflags |= SOUND_MASK_SPEAKER;
4305162922Sariff			}
4306162922Sariff		}
4307162922Sariff	}
4308162922Sariff
4309162922Sariff	/* Input mixers (rec) */
4310162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4311162922Sariff		w = hdac_widget_get(devinfo, i);
4312162922Sariff		if (w == NULL || w->enable == 0)
4313162922Sariff			continue;
4314162922Sariff		if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
4315162922Sariff		    w->pflags & HDA_ADC_PATH))
4316162922Sariff			continue;
4317162922Sariff		hdac_audio_ctl_inamp_build(devinfo, w->nid, 0);
4318162922Sariff		hdac_audio_ctl_recsel_build(devinfo, w->nid, 0);
4319162922Sariff	}
4320162922Sariff}
4321162922Sariff
4322162922Sariff#define HDA_COMMIT_CONN	(1 << 0)
4323162922Sariff#define HDA_COMMIT_CTRL	(1 << 1)
4324162922Sariff#define HDA_COMMIT_EAPD	(1 << 2)
4325162922Sariff#define HDA_COMMIT_GPIO	(1 << 3)
4326162922Sariff#define HDA_COMMIT_ALL	(HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \
4327162922Sariff				HDA_COMMIT_EAPD | HDA_COMMIT_GPIO)
4328162922Sariff
4329162922Sariffstatic void
4330162922Sariffhdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl)
4331162922Sariff{
4332162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4333162922Sariff	struct hdac_widget *w;
4334164750Sariff	nid_t cad;
4335164750Sariff	int i;
4336162922Sariff
4337162922Sariff	if (!(cfl & HDA_COMMIT_ALL))
4338162922Sariff		return;
4339162922Sariff
4340162922Sariff	cad = devinfo->codec->cad;
4341162922Sariff
4342163057Sariff	if (cfl & HDA_COMMIT_GPIO) {
4343165039Sariff		uint32_t gdata, gmask, gdir;
4344165039Sariff		int commitgpio = 0;
4345164828Sariff
4346165039Sariff		gdata = 0;
4347165039Sariff		gmask = 0;
4348165039Sariff		gdir = 0;
4349166796Sariff
4350165039Sariff		if (sc->pci_subvendor == APPLE_INTEL_MAC)
4351164828Sariff			hdac_command(sc, HDA_CMD_12BIT(cad, devinfo->nid,
4352164828Sariff			    0x7e7, 0), cad);
4353165039Sariff
4354165039Sariff		if (devinfo->function.audio.quirks & HDA_QUIRK_GPIOFLUSH)
4355165039Sariff			commitgpio = 1;
4356165039Sariff		else {
4357165039Sariff			for (i = 0; i < HDA_GPIO_MAX; i++) {
4358165039Sariff				if (!(devinfo->function.audio.quirks &
4359165039Sariff				    (1 << i)))
4360165039Sariff					continue;
4361165039Sariff				if (commitgpio == 0) {
4362165039Sariff					commitgpio = 1;
4363165039Sariff					gdata = hdac_command(sc,
4364165039Sariff					    HDA_CMD_GET_GPIO_DATA(cad,
4365165039Sariff					    devinfo->nid), cad);
4366165039Sariff					gmask = hdac_command(sc,
4367165039Sariff					    HDA_CMD_GET_GPIO_ENABLE_MASK(cad,
4368165039Sariff					    devinfo->nid), cad);
4369165039Sariff					gdir = hdac_command(sc,
4370165039Sariff					    HDA_CMD_GET_GPIO_DIRECTION(cad,
4371165039Sariff					    devinfo->nid), cad);
4372165039Sariff					HDA_BOOTVERBOSE(
4373165039Sariff						device_printf(sc->dev,
4374165039Sariff						    "GPIO init: data=0x%08x "
4375165039Sariff						    "mask=0x%08x dir=0x%08x\n",
4376165039Sariff						    gdata, gmask, gdir);
4377165039Sariff					);
4378165039Sariff				}
4379165039Sariff				gdata |= 1 << i;
4380165039Sariff				gmask |= 1 << i;
4381165039Sariff				gdir |= 1 << i;
4382165039Sariff			}
4383165039Sariff		}
4384165039Sariff
4385165039Sariff		if (commitgpio != 0) {
4386165039Sariff			HDA_BOOTVERBOSE(
4387165039Sariff				device_printf(sc->dev,
4388165039Sariff				    "GPIO commit: data=0x%08x mask=0x%08x "
4389165039Sariff				    "dir=0x%08x\n",
4390165039Sariff				    gdata, gmask, gdir);
4391165039Sariff			);
4392162922Sariff			hdac_command(sc,
4393164828Sariff			    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, devinfo->nid,
4394164828Sariff			    gmask), cad);
4395164828Sariff			hdac_command(sc,
4396164828Sariff			    HDA_CMD_SET_GPIO_DIRECTION(cad, devinfo->nid,
4397164828Sariff			    gdir), cad);
4398164828Sariff			hdac_command(sc,
4399164828Sariff			    HDA_CMD_SET_GPIO_DATA(cad, devinfo->nid,
4400164828Sariff			    gdata), cad);
4401162922Sariff		}
4402162922Sariff	}
4403162922Sariff
4404162922Sariff	for (i = 0; i < devinfo->nodecnt; i++) {
4405162922Sariff		w = &devinfo->widget[i];
4406162922Sariff		if (w == NULL || w->enable == 0)
4407162922Sariff			continue;
4408162922Sariff		if (cfl & HDA_COMMIT_CONN) {
4409162922Sariff			if (w->selconn == -1)
4410162922Sariff				w->selconn = 0;
4411162922Sariff			if (w->nconns > 0)
4412162922Sariff				hdac_widget_connection_select(w, w->selconn);
4413162922Sariff		}
4414162922Sariff		if ((cfl & HDA_COMMIT_CTRL) &&
4415162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
4416162922Sariff			if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) ==
4417162922Sariff			    (HDA_DAC_PATH | HDA_ADC_PATH))
4418162922Sariff				device_printf(sc->dev, "WARNING: node %d "
4419162922Sariff				    "participate both for DAC/ADC!\n", w->nid);
4420162922Sariff			if (w->pflags & HDA_DAC_PATH) {
4421162922Sariff				w->wclass.pin.ctrl &=
4422162922Sariff				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
4423162922Sariff				if ((w->wclass.pin.config &
4424162922Sariff				    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) !=
4425162922Sariff				    HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
4426162922Sariff					w->wclass.pin.ctrl &=
4427162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
4428162922Sariff			} else if (w->pflags & HDA_ADC_PATH) {
4429162922Sariff				w->wclass.pin.ctrl &=
4430162922Sariff				    ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
4431162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE);
4432165069Sariff				if (w->devinfo->function.audio.quirks & HDA_QUIRK_VREF) {
4433165069Sariff					uint32_t pincap = w->wclass.pin.cap;
4434165069Sariff					if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
4435165069Sariff						w->wclass.pin.ctrl |=
4436165069Sariff						    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
4437165069Sariff							HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_100
4438165069Sariff						    );
4439165069Sariff					else if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
4440165069Sariff						w->wclass.pin.ctrl |=
4441165069Sariff						    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
4442165069Sariff							HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_80
4443165069Sariff						    );
4444165069Sariff					else if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
4445165069Sariff						w->wclass.pin.ctrl |=
4446165069Sariff						    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE(
4447165069Sariff							HDA_CMD_PIN_WIDGET_CTRL_VREF_ENABLE_50
4448165069Sariff						    );
4449165069Sariff				}
4450162922Sariff			} else
4451162922Sariff				w->wclass.pin.ctrl &= ~(
4452162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
4453162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
4454165069Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE |
4455165069Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_VREF_ENABLE_MASK);
4456162922Sariff			hdac_command(sc,
4457162922Sariff			    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
4458162922Sariff			    w->wclass.pin.ctrl), cad);
4459162922Sariff		}
4460162922Sariff		if ((cfl & HDA_COMMIT_EAPD) &&
4461163276Sariff		    w->param.eapdbtl != HDAC_INVALID) {
4462163432Sariff		    	uint32_t val;
4463163432Sariff
4464163432Sariff			val = w->param.eapdbtl;
4465163276Sariff			if (devinfo->function.audio.quirks &
4466163432Sariff			    HDA_QUIRK_EAPDINV)
4467163432Sariff				val ^= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
4468162922Sariff			hdac_command(sc,
4469162922Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid,
4470163432Sariff			    val), cad);
4471162922Sariff
4472163276Sariff		}
4473162922Sariff		DELAY(1000);
4474162922Sariff	}
4475162922Sariff}
4476162922Sariff
4477162922Sariffstatic void
4478162922Sariffhdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
4479162922Sariff{
4480162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4481162922Sariff	struct hdac_audio_ctl *ctl;
4482162922Sariff	int i;
4483162922Sariff
4484162922Sariff	devinfo->function.audio.mvol = 100 | (100 << 8);
4485162922Sariff	i = 0;
4486162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4487162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL) {
4488163057Sariff			HDA_BOOTVERBOSE(
4489162922Sariff				device_printf(sc->dev, "[%2d] Ctl nid=%d",
4490162922Sariff				    i, (ctl->widget != NULL) ?
4491162922Sariff				    ctl->widget->nid : -1);
4492162922Sariff				if (ctl->childwidget != NULL)
4493162922Sariff					printf(" childnid=%d",
4494162922Sariff					    ctl->childwidget->nid);
4495162922Sariff				if (ctl->widget == NULL)
4496162922Sariff					printf(" NULL WIDGET!");
4497162922Sariff				printf(" DISABLED\n");
4498162922Sariff			);
4499162922Sariff			continue;
4500162922Sariff		}
4501163057Sariff		HDA_BOOTVERBOSE(
4502162922Sariff			if (ctl->ossmask == 0) {
4503162922Sariff				device_printf(sc->dev, "[%2d] Ctl nid=%d",
4504162922Sariff				    i, ctl->widget->nid);
4505162922Sariff				if (ctl->childwidget != NULL)
4506162922Sariff					printf(" childnid=%d",
4507162922Sariff					ctl->childwidget->nid);
4508162922Sariff				printf(" Bind to NONE\n");
4509166294Sariff			}
4510162922Sariff		);
4511162922Sariff		if (ctl->step > 0) {
4512162922Sariff			ctl->ossval = (ctl->left * 100) / ctl->step;
4513162922Sariff			ctl->ossval |= ((ctl->right * 100) / ctl->step) << 8;
4514162922Sariff		} else
4515162922Sariff			ctl->ossval = 0;
4516162922Sariff		hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT,
4517162922Sariff		    ctl->left, ctl->right);
4518162922Sariff	}
4519162922Sariff}
4520162922Sariff
4521162922Sariffstatic int
4522162922Sariffhdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
4523162922Sariff{
4524162922Sariff	struct hdac_chan *ch;
4525162922Sariff	struct hdac_widget *w;
4526162922Sariff	uint32_t cap, fmtcap, pcmcap, path;
4527162922Sariff	int i, type, ret, max;
4528162922Sariff
4529162922Sariff	if (dir == PCMDIR_PLAY) {
4530162922Sariff		type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT;
4531162922Sariff		ch = &devinfo->codec->sc->play;
4532162922Sariff		path = HDA_DAC_PATH;
4533162922Sariff	} else {
4534162922Sariff		type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT;
4535162922Sariff		ch = &devinfo->codec->sc->rec;
4536162922Sariff		path = HDA_ADC_PATH;
4537162922Sariff	}
4538162922Sariff
4539162922Sariff	ch->caps = hdac_caps;
4540162922Sariff	ch->caps.fmtlist = ch->fmtlist;
4541162922Sariff	ch->bit16 = 1;
4542162922Sariff	ch->bit32 = 0;
4543162922Sariff	ch->pcmrates[0] = 48000;
4544162922Sariff	ch->pcmrates[1] = 0;
4545162922Sariff
4546162922Sariff	ret = 0;
4547162922Sariff	fmtcap = devinfo->function.audio.supp_stream_formats;
4548162922Sariff	pcmcap = devinfo->function.audio.supp_pcm_size_rate;
4549162922Sariff	max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1;
4550162922Sariff
4551162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode && ret < max; i++) {
4552162922Sariff		w = hdac_widget_get(devinfo, i);
4553162922Sariff		if (w == NULL || w->enable == 0 || w->type != type ||
4554163057Sariff		    !(w->pflags & path))
4555162922Sariff			continue;
4556162922Sariff		cap = w->param.widget_cap;
4557162922Sariff		/*if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(cap))
4558162922Sariff			continue;*/
4559162922Sariff		if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(cap))
4560162922Sariff			continue;
4561162922Sariff		cap = w->param.supp_stream_formats;
4562162922Sariff		/*if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) {
4563162922Sariff		}
4564162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
4565162922Sariff		}*/
4566162922Sariff		if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
4567162922Sariff			continue;
4568164614Sariff		if (ret == 0) {
4569164614Sariff			fmtcap = w->param.supp_stream_formats;
4570164614Sariff			pcmcap = w->param.supp_pcm_size_rate;
4571164614Sariff		} else {
4572164614Sariff			fmtcap &= w->param.supp_stream_formats;
4573164614Sariff			pcmcap &= w->param.supp_pcm_size_rate;
4574164614Sariff		}
4575162922Sariff		ch->io[ret++] = i;
4576162922Sariff	}
4577162922Sariff	ch->io[ret] = -1;
4578162922Sariff
4579162922Sariff	ch->supp_stream_formats = fmtcap;
4580162922Sariff	ch->supp_pcm_size_rate = pcmcap;
4581162922Sariff
4582162922Sariff	/*
4583162922Sariff	 *  8bit = 0
4584162922Sariff	 * 16bit = 1
4585162922Sariff	 * 20bit = 2
4586162922Sariff	 * 24bit = 3
4587162922Sariff	 * 32bit = 4
4588162922Sariff	 */
4589162922Sariff	if (ret > 0) {
4590162922Sariff		cap = pcmcap;
4591162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
4592162922Sariff			ch->bit16 = 1;
4593162922Sariff		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
4594162922Sariff			ch->bit16 = 0;
4595162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
4596162922Sariff			ch->bit32 = 4;
4597162922Sariff		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
4598162922Sariff			ch->bit32 = 3;
4599162922Sariff		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
4600162922Sariff			ch->bit32 = 2;
4601162922Sariff		i = 0;
4602162922Sariff		if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
4603162922Sariff			ch->fmtlist[i++] = AFMT_S16_LE;
4604162922Sariff		ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
4605162922Sariff		if (ch->bit32 > 0) {
4606162922Sariff			if (!(devinfo->function.audio.quirks &
4607162922Sariff			    HDA_QUIRK_FORCESTEREO))
4608162922Sariff				ch->fmtlist[i++] = AFMT_S32_LE;
4609162922Sariff			ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
4610162922Sariff		}
4611162922Sariff		ch->fmtlist[i] = 0;
4612162922Sariff		i = 0;
4613162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
4614162922Sariff			ch->pcmrates[i++] = 8000;
4615162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
4616162922Sariff			ch->pcmrates[i++] = 11025;
4617162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
4618162922Sariff			ch->pcmrates[i++] = 16000;
4619162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
4620162922Sariff			ch->pcmrates[i++] = 22050;
4621162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
4622162922Sariff			ch->pcmrates[i++] = 32000;
4623162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
4624162922Sariff			ch->pcmrates[i++] = 44100;
4625162922Sariff		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(cap)) */
4626162922Sariff		ch->pcmrates[i++] = 48000;
4627162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
4628162922Sariff			ch->pcmrates[i++] = 88200;
4629162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
4630162922Sariff			ch->pcmrates[i++] = 96000;
4631162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
4632162922Sariff			ch->pcmrates[i++] = 176400;
4633162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
4634162922Sariff			ch->pcmrates[i++] = 192000;
4635162922Sariff		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(cap)) */
4636162922Sariff		ch->pcmrates[i] = 0;
4637162922Sariff		if (i > 0) {
4638162922Sariff			ch->caps.minspeed = ch->pcmrates[0];
4639162922Sariff			ch->caps.maxspeed = ch->pcmrates[i - 1];
4640162922Sariff		}
4641162922Sariff	}
4642162922Sariff
4643162922Sariff	return (ret);
4644162922Sariff}
4645162922Sariff
4646162922Sariffstatic void
4647162922Sariffhdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag)
4648162922Sariff{
4649162922Sariff	struct hdac_audio_ctl *ctl;
4650162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4651162922Sariff	int i;
4652162922Sariff	uint32_t fl = 0;
4653162922Sariff
4654162922Sariff
4655162922Sariff	if (flag == 0) {
4656162922Sariff		fl = SOUND_MASK_VOLUME | SOUND_MASK_PCM |
4657162922Sariff		    SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
4658162922Sariff		    SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN;
4659162922Sariff	}
4660162922Sariff
4661162922Sariff	i = 0;
4662162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4663162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL ||
4664162922Sariff		    ctl->widget->enable == 0)
4665162922Sariff			continue;
4666162922Sariff		if ((flag == 0 && (ctl->ossmask & ~fl)) ||
4667162922Sariff		    (flag != 0 && (ctl->ossmask & flag))) {
4668162922Sariff			if (banner != NULL) {
4669162922Sariff				device_printf(sc->dev, "\n");
4670162922Sariff				device_printf(sc->dev, "%s\n", banner);
4671162922Sariff			}
4672162922Sariff			goto hdac_ctl_dump_it_all;
4673162922Sariff		}
4674162922Sariff	}
4675162922Sariff
4676162922Sariff	return;
4677162922Sariff
4678162922Sariffhdac_ctl_dump_it_all:
4679162922Sariff	i = 0;
4680162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4681162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL ||
4682162922Sariff		    ctl->widget->enable == 0)
4683162922Sariff			continue;
4684162922Sariff		if (!((flag == 0 && (ctl->ossmask & ~fl)) ||
4685162922Sariff		    (flag != 0 && (ctl->ossmask & flag))))
4686162922Sariff			continue;
4687162922Sariff		if (flag == 0) {
4688162922Sariff			device_printf(sc->dev, "\n");
4689162922Sariff			device_printf(sc->dev, "Unknown Ctl (OSS: %s)\n",
4690162922Sariff			    hdac_audio_ctl_ossmixer_mask2name(ctl->ossmask));
4691162922Sariff		}
4692162922Sariff		device_printf(sc->dev, "   |\n");
4693162922Sariff		device_printf(sc->dev, "   +-  nid: %2d index: %2d ",
4694162922Sariff		    ctl->widget->nid, ctl->index);
4695162922Sariff		if (ctl->childwidget != NULL)
4696162922Sariff			printf("(nid: %2d) ", ctl->childwidget->nid);
4697162922Sariff		else
4698162922Sariff			printf("          ");
4699162922Sariff		printf("mute: %d step: %3d size: %3d off: %3d dir=0x%x ossmask=0x%08x\n",
4700162922Sariff		    ctl->mute, ctl->step, ctl->size, ctl->offset, ctl->dir,
4701162922Sariff		    ctl->ossmask);
4702162922Sariff	}
4703162922Sariff}
4704162922Sariff
4705162922Sariffstatic void
4706162922Sariffhdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap)
4707162922Sariff{
4708162922Sariff	uint32_t cap;
4709162922Sariff
4710162922Sariff	cap = fcap;
4711162922Sariff	if (cap != 0) {
4712162922Sariff		device_printf(sc->dev, "     Stream cap: 0x%08x\n", cap);
4713162922Sariff		device_printf(sc->dev, "         Format:");
4714162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
4715162922Sariff			printf(" AC3");
4716162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
4717162922Sariff			printf(" FLOAT32");
4718162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
4719162922Sariff			printf(" PCM");
4720162922Sariff		printf("\n");
4721162922Sariff	}
4722162922Sariff	cap = pcmcap;
4723162922Sariff	if (cap != 0) {
4724162922Sariff		device_printf(sc->dev, "        PCM cap: 0x%08x\n", cap);
4725162922Sariff		device_printf(sc->dev, "       PCM size:");
4726162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
4727162922Sariff			printf(" 8");
4728162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
4729162922Sariff			printf(" 16");
4730162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
4731162922Sariff			printf(" 20");
4732162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
4733162922Sariff			printf(" 24");
4734162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
4735162922Sariff			printf(" 32");
4736162922Sariff		printf("\n");
4737162922Sariff		device_printf(sc->dev, "       PCM rate:");
4738162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
4739162922Sariff			printf(" 8");
4740162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
4741162922Sariff			printf(" 11");
4742162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
4743162922Sariff			printf(" 16");
4744162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
4745162922Sariff			printf(" 22");
4746162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
4747162922Sariff			printf(" 32");
4748162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
4749162922Sariff			printf(" 44");
4750162922Sariff		printf(" 48");
4751162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
4752162922Sariff			printf(" 88");
4753162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
4754162922Sariff			printf(" 96");
4755162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
4756162922Sariff			printf(" 176");
4757162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
4758162922Sariff			printf(" 192");
4759162922Sariff		printf("\n");
4760162922Sariff	}
4761162922Sariff}
4762162922Sariff
4763162922Sariffstatic void
4764162922Sariffhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
4765162922Sariff{
4766162922Sariff	uint32_t pincap, wcap;
4767162922Sariff
4768162922Sariff	pincap = w->wclass.pin.cap;
4769162922Sariff	wcap = w->param.widget_cap;
4770162922Sariff
4771162922Sariff	device_printf(sc->dev, "        Pin cap: 0x%08x\n", pincap);
4772162922Sariff	device_printf(sc->dev, "                ");
4773162922Sariff	if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap))
4774162922Sariff		printf(" ISC");
4775162922Sariff	if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap))
4776162922Sariff		printf(" TRQD");
4777162922Sariff	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap))
4778162922Sariff		printf(" PDC");
4779162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
4780162922Sariff		printf(" HP");
4781162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
4782162922Sariff		printf(" OUT");
4783162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
4784162922Sariff		printf(" IN");
4785162922Sariff	if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap))
4786162922Sariff		printf(" BAL");
4787165069Sariff	if (HDA_PARAM_PIN_CAP_VREF_CTRL(pincap)) {
4788165069Sariff		printf(" VREF[");
4789165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_50(pincap))
4790165069Sariff			printf(" 50");
4791165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_80(pincap))
4792165069Sariff			printf(" 80");
4793165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_100(pincap))
4794165069Sariff			printf(" 100");
4795165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_GROUND(pincap))
4796165069Sariff			printf(" GROUND");
4797165069Sariff		if (HDA_PARAM_PIN_CAP_VREF_CTRL_HIZ(pincap))
4798165069Sariff			printf(" HIZ");
4799165069Sariff		printf(" ]");
4800165069Sariff	}
4801162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap))
4802162922Sariff		printf(" EAPD");
4803162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(wcap))
4804162922Sariff		printf(" : UNSOL");
4805162922Sariff	printf("\n");
4806162922Sariff	device_printf(sc->dev, "     Pin config: 0x%08x\n",
4807162922Sariff	    w->wclass.pin.config);
4808162922Sariff	device_printf(sc->dev, "    Pin control: 0x%08x", w->wclass.pin.ctrl);
4809162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE)
4810162922Sariff		printf(" HP");
4811162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE)
4812162922Sariff		printf(" IN");
4813162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
4814162922Sariff		printf(" OUT");
4815162922Sariff	printf("\n");
4816162922Sariff}
4817162922Sariff
4818162922Sariffstatic void
4819162922Sariffhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
4820162922Sariff{
4821163057Sariff	device_printf(sc->dev, "     %s amp: 0x%08x\n", banner, cap);
4822162922Sariff	device_printf(sc->dev, "                 "
4823162922Sariff	    "mute=%d step=%d size=%d offset=%d\n",
4824162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap),
4825162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap),
4826162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap),
4827162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap));
4828162922Sariff}
4829162922Sariff
4830162922Sariffstatic void
4831162922Sariffhdac_dump_nodes(struct hdac_devinfo *devinfo)
4832162922Sariff{
4833162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4834162922Sariff	struct hdac_widget *w, *cw;
4835162922Sariff	int i, j;
4836162922Sariff
4837162922Sariff	device_printf(sc->dev, "\n");
4838162922Sariff	device_printf(sc->dev, "Default Parameter\n");
4839162922Sariff	device_printf(sc->dev, "-----------------\n");
4840162922Sariff	hdac_dump_audio_formats(sc,
4841162922Sariff	    devinfo->function.audio.supp_stream_formats,
4842162922Sariff	    devinfo->function.audio.supp_pcm_size_rate);
4843162922Sariff	device_printf(sc->dev, "         IN amp: 0x%08x\n",
4844162922Sariff	    devinfo->function.audio.inamp_cap);
4845162922Sariff	device_printf(sc->dev, "        OUT amp: 0x%08x\n",
4846162922Sariff	    devinfo->function.audio.outamp_cap);
4847162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4848162922Sariff		w = hdac_widget_get(devinfo, i);
4849162922Sariff		if (w == NULL) {
4850162922Sariff			device_printf(sc->dev, "Ghost widget nid=%d\n", i);
4851162922Sariff			continue;
4852162922Sariff		}
4853162922Sariff		device_printf(sc->dev, "\n");
4854162922Sariff		device_printf(sc->dev, "            nid: %d [%s]%s\n", w->nid,
4855162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap) ?
4856162922Sariff		    "DIGITAL" : "ANALOG",
4857162922Sariff		    (w->enable == 0) ? " [DISABLED]" : "");
4858162922Sariff		device_printf(sc->dev, "           name: %s\n", w->name);
4859162922Sariff		device_printf(sc->dev, "     widget_cap: 0x%08x\n",
4860162922Sariff		    w->param.widget_cap);
4861162922Sariff		device_printf(sc->dev, "    Parse flags: 0x%08x\n",
4862162922Sariff		    w->pflags);
4863162922Sariff		device_printf(sc->dev, "      Ctl flags: 0x%08x\n",
4864162922Sariff		    w->ctlflags);
4865162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
4866162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
4867162922Sariff			hdac_dump_audio_formats(sc,
4868162922Sariff			    w->param.supp_stream_formats,
4869162922Sariff			    w->param.supp_pcm_size_rate);
4870162922Sariff		} else if (w->type ==
4871162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4872162922Sariff			hdac_dump_pin(sc, w);
4873162965Sariff		if (w->param.eapdbtl != HDAC_INVALID)
4874162922Sariff			device_printf(sc->dev, "           EAPD: 0x%08x\n",
4875162922Sariff			    w->param.eapdbtl);
4876163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap) &&
4877163057Sariff		    w->param.outamp_cap != 0)
4878162922Sariff			hdac_dump_amp(sc, w->param.outamp_cap, "Output");
4879163057Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap) &&
4880163057Sariff		    w->param.inamp_cap != 0)
4881162922Sariff			hdac_dump_amp(sc, w->param.inamp_cap, " Input");
4882162922Sariff		device_printf(sc->dev, "    connections: %d\n", w->nconns);
4883162922Sariff		for (j = 0; j < w->nconns; j++) {
4884162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
4885162922Sariff			device_printf(sc->dev, "          |\n");
4886162922Sariff			device_printf(sc->dev, "          + <- nid=%d [%s]",
4887162922Sariff			    w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
4888162922Sariff			if (cw == NULL)
4889162922Sariff				printf(" [UNKNOWN]");
4890162922Sariff			else if (cw->enable == 0)
4891162922Sariff				printf(" [DISABLED]");
4892162922Sariff			if (w->nconns > 1 && w->selconn == j && w->type !=
4893162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
4894162922Sariff				printf(" (selected)");
4895162922Sariff			printf("\n");
4896162922Sariff		}
4897162922Sariff	}
4898162922Sariff
4899162922Sariff}
4900162922Sariff
4901163057Sariffstatic int
4902163057Sariffhdac_dump_dac_internal(struct hdac_devinfo *devinfo, nid_t nid, int depth)
4903163057Sariff{
4904163057Sariff	struct hdac_widget *w, *cw;
4905163057Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4906163057Sariff	int i;
4907163057Sariff
4908163057Sariff	if (depth > HDA_PARSE_MAXDEPTH)
4909163057Sariff		return (0);
4910163057Sariff
4911163057Sariff	w = hdac_widget_get(devinfo, nid);
4912163057Sariff	if (w == NULL || w->enable == 0 || !(w->pflags & HDA_DAC_PATH))
4913163057Sariff		return (0);
4914163057Sariff
4915163057Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
4916163057Sariff		device_printf(sc->dev, "\n");
4917163057Sariff		device_printf(sc->dev, "    nid=%d [%s]\n", w->nid, w->name);
4918163057Sariff		device_printf(sc->dev, "      ^\n");
4919163057Sariff		device_printf(sc->dev, "      |\n");
4920163057Sariff		device_printf(sc->dev, "      +-----<------+\n");
4921163057Sariff	} else {
4922163057Sariff		device_printf(sc->dev, "                   ^\n");
4923163057Sariff		device_printf(sc->dev, "                   |\n");
4924163057Sariff		device_printf(sc->dev, "               ");
4925163057Sariff		printf("  nid=%d [%s]\n", w->nid, w->name);
4926163057Sariff	}
4927163057Sariff
4928163057Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT) {
4929163057Sariff		return (1);
4930163057Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) {
4931163057Sariff		for (i = 0; i < w->nconns; i++) {
4932163057Sariff			cw = hdac_widget_get(devinfo, w->conns[i]);
4933163057Sariff			if (cw == NULL || cw->enable == 0 || cw->type ==
4934163057Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4935163057Sariff				continue;
4936163057Sariff			if (hdac_dump_dac_internal(devinfo, cw->nid,
4937163057Sariff			    depth + 1) != 0)
4938163057Sariff				return (1);
4939163057Sariff		}
4940163057Sariff	} else if ((w->type ==
4941163057Sariff	    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR ||
4942163057Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) &&
4943163057Sariff	    w->selconn > -1 && w->selconn < w->nconns) {
4944163057Sariff		if (hdac_dump_dac_internal(devinfo, w->conns[w->selconn],
4945163057Sariff		    depth + 1) != 0)
4946163057Sariff			return (1);
4947163057Sariff	}
4948163057Sariff
4949163057Sariff	return (0);
4950163057Sariff}
4951163057Sariff
4952162922Sariffstatic void
4953162922Sariffhdac_dump_dac(struct hdac_devinfo *devinfo)
4954162922Sariff{
4955163057Sariff	struct hdac_widget *w;
4956163057Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4957163057Sariff	int i, printed = 0;
4958163057Sariff
4959163057Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4960163057Sariff		w = hdac_widget_get(devinfo, i);
4961163057Sariff		if (w == NULL || w->enable == 0)
4962163057Sariff			continue;
4963163057Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
4964163057Sariff		    !(w->pflags & HDA_DAC_PATH))
4965163057Sariff			continue;
4966163057Sariff		if (printed == 0) {
4967163057Sariff			printed = 1;
4968163057Sariff			device_printf(sc->dev, "\n");
4969163057Sariff			device_printf(sc->dev, "Playback path:\n");
4970163057Sariff		}
4971163057Sariff		hdac_dump_dac_internal(devinfo, w->nid, 0);
4972163057Sariff	}
4973162922Sariff}
4974162922Sariff
4975162922Sariffstatic void
4976162922Sariffhdac_dump_adc(struct hdac_devinfo *devinfo)
4977162922Sariff{
4978162922Sariff	struct hdac_widget *w, *cw;
4979162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4980162922Sariff	int i, j;
4981162922Sariff	int printed = 0;
4982162922Sariff	char ossdevs[256];
4983162922Sariff
4984162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4985162922Sariff		w = hdac_widget_get(devinfo, i);
4986162922Sariff		if (w == NULL || w->enable == 0)
4987162922Sariff			continue;
4988162922Sariff		if (!(w->pflags & HDA_ADC_RECSEL))
4989162922Sariff			continue;
4990162922Sariff		if (printed == 0) {
4991162922Sariff			printed = 1;
4992162922Sariff			device_printf(sc->dev, "\n");
4993162922Sariff			device_printf(sc->dev, "Recording sources:\n");
4994162922Sariff		}
4995162922Sariff		device_printf(sc->dev, "\n");
4996162922Sariff		device_printf(sc->dev, "    nid=%d [%s]\n", w->nid, w->name);
4997162922Sariff		for (j = 0; j < w->nconns; j++) {
4998162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
4999162922Sariff			if (cw == NULL || cw->enable == 0)
5000162922Sariff				continue;
5001162922Sariff			hdac_audio_ctl_ossmixer_mask2allname(cw->ctlflags,
5002162922Sariff			    ossdevs, sizeof(ossdevs));
5003162922Sariff			device_printf(sc->dev, "      |\n");
5004162922Sariff			device_printf(sc->dev, "      + <- nid=%d [%s]",
5005162922Sariff			    cw->nid, cw->name);
5006162922Sariff			if (strlen(ossdevs) > 0) {
5007162922Sariff				printf(" [recsrc: %s]", ossdevs);
5008162922Sariff			}
5009162922Sariff			printf("\n");
5010162922Sariff		}
5011162922Sariff	}
5012162922Sariff}
5013162922Sariff
5014162922Sariffstatic void
5015162922Sariffhdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt)
5016162922Sariff{
5017162922Sariff	nid_t *nids;
5018162922Sariff
5019162922Sariff	if (pcnt > 0) {
5020162922Sariff		device_printf(sc->dev, "\n");
5021162922Sariff		device_printf(sc->dev, "   PCM Playback: %d\n", pcnt);
5022162922Sariff		hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
5023162922Sariff		    sc->play.supp_pcm_size_rate);
5024162922Sariff		device_printf(sc->dev, "            DAC:");
5025162922Sariff		for (nids = sc->play.io; *nids != -1; nids++)
5026162922Sariff			printf(" %d", *nids);
5027162922Sariff		printf("\n");
5028162922Sariff	}
5029162922Sariff
5030162922Sariff	if (rcnt > 0) {
5031162922Sariff		device_printf(sc->dev, "\n");
5032162922Sariff		device_printf(sc->dev, "     PCM Record: %d\n", rcnt);
5033162922Sariff		hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
5034162922Sariff		    sc->rec.supp_pcm_size_rate);
5035162922Sariff		device_printf(sc->dev, "            ADC:");
5036162922Sariff		for (nids = sc->rec.io; *nids != -1; nids++)
5037162922Sariff			printf(" %d", *nids);
5038162922Sariff		printf("\n");
5039162922Sariff	}
5040162922Sariff}
5041162922Sariff
5042162922Sariffstatic void
5043163057Sariffhdac_release_resources(struct hdac_softc *sc)
5044163057Sariff{
5045163057Sariff	struct hdac_devinfo *devinfo = NULL;
5046163057Sariff	device_t *devlist = NULL;
5047163057Sariff	int i, devcount;
5048163057Sariff
5049163057Sariff	if (sc == NULL)
5050163057Sariff		return;
5051163057Sariff
5052163057Sariff	hdac_lock(sc);
5053164614Sariff	if (sc->polling != 0)
5054164614Sariff		callout_stop(&sc->poll_hdac);
5055163057Sariff	hdac_reset(sc);
5056163057Sariff	hdac_unlock(sc);
5057163057Sariff	snd_mtxfree(sc->lock);
5058163057Sariff
5059163057Sariff	device_get_children(sc->dev, &devlist, &devcount);
5060163057Sariff	for (i = 0; devlist != NULL && i < devcount; i++) {
5061163057Sariff		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
5062163057Sariff		if (devinfo == NULL)
5063163057Sariff			continue;
5064163057Sariff		if (devinfo->widget != NULL)
5065163057Sariff			free(devinfo->widget, M_HDAC);
5066163057Sariff		if (devinfo->node_type ==
5067163057Sariff		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
5068163057Sariff		    devinfo->function.audio.ctl != NULL)
5069163057Sariff			free(devinfo->function.audio.ctl, M_HDAC);
5070163057Sariff		free(devinfo, M_HDAC);
5071163057Sariff		device_delete_child(sc->dev, devlist[i]);
5072163057Sariff	}
5073163057Sariff	if (devlist != NULL)
5074163057Sariff		free(devlist, M_TEMP);
5075163057Sariff
5076163057Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++) {
5077163057Sariff		if (sc->codecs[i] != NULL)
5078163057Sariff			free(sc->codecs[i], M_HDAC);
5079163057Sariff		sc->codecs[i] = NULL;
5080163057Sariff	}
5081163057Sariff
5082163057Sariff	hdac_dma_free(&sc->rirb_dma);
5083163057Sariff	hdac_dma_free(&sc->corb_dma);
5084163057Sariff	if (sc->play.blkcnt > 0)
5085163057Sariff		hdac_dma_free(&sc->play.bdl_dma);
5086163057Sariff	if (sc->rec.blkcnt > 0)
5087163057Sariff		hdac_dma_free(&sc->rec.bdl_dma);
5088167702Sariff	if (sc->chan_dmat != NULL) {
5089167702Sariff		bus_dma_tag_destroy(sc->chan_dmat);
5090167702Sariff		sc->chan_dmat = NULL;
5091167702Sariff	}
5092163057Sariff	hdac_irq_free(sc);
5093163057Sariff	hdac_mem_free(sc);
5094163057Sariff	free(sc, M_DEVBUF);
5095163057Sariff}
5096163057Sariff
5097163057Sariff/* This function surely going to make its way into upper level someday. */
5098163057Sariffstatic void
5099163057Sariffhdac_config_fetch(struct hdac_softc *sc, uint32_t *on, uint32_t *off)
5100163057Sariff{
5101163057Sariff	const char *res = NULL;
5102163057Sariff	int i = 0, j, k, len, inv;
5103163057Sariff
5104163057Sariff	if (on != NULL)
5105163057Sariff		*on = 0;
5106163057Sariff	if (off != NULL)
5107163057Sariff		*off = 0;
5108163057Sariff	if (sc == NULL)
5109163057Sariff		return;
5110163057Sariff	if (resource_string_value(device_get_name(sc->dev),
5111163057Sariff	    device_get_unit(sc->dev), "config", &res) != 0)
5112163057Sariff		return;
5113163057Sariff	if (!(res != NULL && strlen(res) > 0))
5114163057Sariff		return;
5115163057Sariff	HDA_BOOTVERBOSE(
5116163057Sariff		device_printf(sc->dev, "HDA_DEBUG: HDA Config:");
5117163057Sariff	);
5118163057Sariff	for (;;) {
5119163057Sariff		while (res[i] != '\0' &&
5120163057Sariff		    (res[i] == ',' || isspace(res[i]) != 0))
5121163057Sariff			i++;
5122163057Sariff		if (res[i] == '\0') {
5123163057Sariff			HDA_BOOTVERBOSE(
5124163057Sariff				printf("\n");
5125163057Sariff			);
5126163057Sariff			return;
5127163057Sariff		}
5128163057Sariff		j = i;
5129163057Sariff		while (res[j] != '\0' &&
5130163057Sariff		    !(res[j] == ',' || isspace(res[j]) != 0))
5131163057Sariff			j++;
5132163057Sariff		len = j - i;
5133163057Sariff		if (len > 2 && strncmp(res + i, "no", 2) == 0)
5134163057Sariff			inv = 2;
5135163057Sariff		else
5136163057Sariff			inv = 0;
5137163057Sariff		for (k = 0; len > inv && k < HDAC_QUIRKS_TAB_LEN; k++) {
5138163057Sariff			if (strncmp(res + i + inv,
5139163057Sariff			    hdac_quirks_tab[k].key, len - inv) != 0)
5140163057Sariff				continue;
5141163057Sariff			if (len - inv != strlen(hdac_quirks_tab[k].key))
5142163057Sariff				break;
5143163057Sariff			HDA_BOOTVERBOSE(
5144163057Sariff				printf(" %s%s", (inv != 0) ? "no" : "",
5145163057Sariff				    hdac_quirks_tab[k].key);
5146163057Sariff			);
5147163057Sariff			if (inv == 0 && on != NULL)
5148163057Sariff				*on |= hdac_quirks_tab[k].value;
5149163057Sariff			else if (inv != 0 && off != NULL)
5150163057Sariff				*off |= hdac_quirks_tab[k].value;
5151163057Sariff			break;
5152163057Sariff		}
5153163057Sariff		i = j;
5154163057Sariff	}
5155163057Sariff}
5156163057Sariff
5157164614Sariff#ifdef SND_DYNSYSCTL
5158164614Sariffstatic int
5159164614Sariffsysctl_hdac_polling(SYSCTL_HANDLER_ARGS)
5160164614Sariff{
5161164614Sariff	struct hdac_softc *sc;
5162164614Sariff	struct hdac_devinfo *devinfo;
5163164614Sariff	device_t dev;
5164164614Sariff	uint32_t ctl;
5165164614Sariff	int err, val;
5166164614Sariff
5167164614Sariff	dev = oidp->oid_arg1;
5168164614Sariff	devinfo = pcm_getdevinfo(dev);
5169164614Sariff	if (devinfo == NULL || devinfo->codec == NULL ||
5170164614Sariff	    devinfo->codec->sc == NULL)
5171164614Sariff		return (EINVAL);
5172164614Sariff	sc = devinfo->codec->sc;
5173164614Sariff	hdac_lock(sc);
5174164614Sariff	val = sc->polling;
5175164614Sariff	hdac_unlock(sc);
5176164614Sariff	err = sysctl_handle_int(oidp, &val, sizeof(val), req);
5177164614Sariff
5178164614Sariff	if (err || req->newptr == NULL)
5179164614Sariff		return (err);
5180164614Sariff	if (val < 0 || val > 1)
5181164614Sariff		return (EINVAL);
5182164614Sariff
5183164614Sariff	hdac_lock(sc);
5184164614Sariff	if (val != sc->polling) {
5185164614Sariff		if (hda_chan_active(sc) != 0)
5186164614Sariff			err = EBUSY;
5187164614Sariff		else if (val == 0) {
5188164614Sariff			callout_stop(&sc->poll_hdac);
5189164614Sariff			HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT,
5190164614Sariff			    sc->rirb_size / 2);
5191164614Sariff			ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
5192164614Sariff			ctl |= HDAC_RIRBCTL_RINTCTL;
5193164614Sariff			HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl);
5194164614Sariff			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
5195164614Sariff			    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
5196164614Sariff			sc->polling = 0;
5197164614Sariff			DELAY(1000);
5198164614Sariff		} else {
5199164614Sariff			HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, 0);
5200164614Sariff			HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, 0);
5201164614Sariff			ctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
5202164614Sariff			ctl &= ~HDAC_RIRBCTL_RINTCTL;
5203164614Sariff			HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, ctl);
5204164614Sariff			callout_reset(&sc->poll_hdac, 1, hdac_poll_callback,
5205164614Sariff			    sc);
5206164614Sariff			sc->polling = 1;
5207164614Sariff			DELAY(1000);
5208164614Sariff		}
5209164614Sariff	}
5210164614Sariff	hdac_unlock(sc);
5211164614Sariff
5212164614Sariff	return (err);
5213164614Sariff}
5214164614Sariff#endif
5215164614Sariff
5216163057Sariffstatic void
5217162922Sariffhdac_attach2(void *arg)
5218162922Sariff{
5219162922Sariff	struct hdac_softc *sc;
5220162922Sariff	struct hdac_widget *w;
5221162922Sariff	struct hdac_audio_ctl *ctl;
5222163057Sariff	uint32_t quirks_on, quirks_off;
5223162922Sariff	int pcnt, rcnt;
5224162922Sariff	int i;
5225162922Sariff	char status[SND_STATUSLEN];
5226162965Sariff	device_t *devlist = NULL;
5227162922Sariff	int devcount;
5228162922Sariff	struct hdac_devinfo *devinfo = NULL;
5229162922Sariff
5230162922Sariff	sc = (struct hdac_softc *)arg;
5231162922Sariff
5232163057Sariff	hdac_config_fetch(sc, &quirks_on, &quirks_off);
5233162922Sariff
5234163057Sariff	HDA_BOOTVERBOSE(
5235163057Sariff		device_printf(sc->dev, "HDA_DEBUG: HDA Config: on=0x%08x off=0x%08x\n",
5236163057Sariff		    quirks_on, quirks_off);
5237163057Sariff	);
5238163057Sariff
5239162922Sariff	hdac_lock(sc);
5240162922Sariff
5241162922Sariff	/* Remove ourselves from the config hooks */
5242162922Sariff	if (sc->intrhook.ich_func != NULL) {
5243162922Sariff		config_intrhook_disestablish(&sc->intrhook);
5244162922Sariff		sc->intrhook.ich_func = NULL;
5245162922Sariff	}
5246162922Sariff
5247162922Sariff	/* Start the corb and rirb engines */
5248163057Sariff	HDA_BOOTVERBOSE(
5249162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Starting CORB Engine...\n");
5250162922Sariff	);
5251162922Sariff	hdac_corb_start(sc);
5252163057Sariff	HDA_BOOTVERBOSE(
5253162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Starting RIRB Engine...\n");
5254162922Sariff	);
5255162922Sariff	hdac_rirb_start(sc);
5256162922Sariff
5257163057Sariff	HDA_BOOTVERBOSE(
5258162922Sariff		device_printf(sc->dev,
5259162922Sariff		    "HDA_DEBUG: Enabling controller interrupt...\n");
5260162922Sariff	);
5261164614Sariff	if (sc->polling == 0)
5262164614Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTCTL,
5263164614Sariff		    HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
5264163057Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, HDAC_READ_4(&sc->mem, HDAC_GCTL) |
5265163057Sariff	    HDAC_GCTL_UNSOL);
5266162922Sariff
5267162922Sariff	DELAY(1000);
5268162922Sariff
5269163057Sariff	HDA_BOOTVERBOSE(
5270162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Scanning HDA codecs...\n");
5271162922Sariff	);
5272162922Sariff	hdac_scan_codecs(sc);
5273162922Sariff
5274162922Sariff	device_get_children(sc->dev, &devlist, &devcount);
5275162965Sariff	for (i = 0; devlist != NULL && i < devcount; i++) {
5276162965Sariff		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
5277162965Sariff		if (devinfo != NULL && devinfo->node_type ==
5278162965Sariff		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
5279162965Sariff			break;
5280162965Sariff		} else
5281162965Sariff			devinfo = NULL;
5282162922Sariff	}
5283162965Sariff	if (devlist != NULL)
5284162965Sariff		free(devlist, M_TEMP);
5285162922Sariff
5286162922Sariff	if (devinfo == NULL) {
5287162922Sariff		hdac_unlock(sc);
5288162922Sariff		device_printf(sc->dev, "Audio Function Group not found!\n");
5289163057Sariff		hdac_release_resources(sc);
5290162922Sariff		return;
5291162922Sariff	}
5292162922Sariff
5293163057Sariff	HDA_BOOTVERBOSE(
5294162922Sariff		device_printf(sc->dev,
5295162922Sariff		    "HDA_DEBUG: Parsing AFG nid=%d cad=%d\n",
5296162922Sariff		    devinfo->nid, devinfo->codec->cad);
5297162922Sariff	);
5298162922Sariff	hdac_audio_parse(devinfo);
5299163057Sariff	HDA_BOOTVERBOSE(
5300162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Parsing Ctls...\n");
5301162922Sariff	);
5302162922Sariff	hdac_audio_ctl_parse(devinfo);
5303163057Sariff	HDA_BOOTVERBOSE(
5304162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Parsing vendor patch...\n");
5305162922Sariff	);
5306162922Sariff	hdac_vendor_patch_parse(devinfo);
5307163057Sariff	if (quirks_on != 0)
5308163057Sariff		devinfo->function.audio.quirks |= quirks_on;
5309163057Sariff	if (quirks_off != 0)
5310163057Sariff		devinfo->function.audio.quirks &= ~quirks_off;
5311162922Sariff
5312162922Sariff	/* XXX Disable all DIGITAL path. */
5313162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5314162922Sariff		w = hdac_widget_get(devinfo, i);
5315162922Sariff		if (w == NULL)
5316162922Sariff			continue;
5317162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
5318162922Sariff			w->enable = 0;
5319162922Sariff			continue;
5320162922Sariff		}
5321162922Sariff		/* XXX Disable useless pin ? */
5322162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
5323162922Sariff		    (w->wclass.pin.config &
5324162922Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
5325162922Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
5326162922Sariff			w->enable = 0;
5327162922Sariff	}
5328162922Sariff	i = 0;
5329162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5330162922Sariff		if (ctl->widget == NULL)
5331162922Sariff			continue;
5332162922Sariff		w = ctl->widget;
5333162922Sariff		if (w->enable == 0)
5334162922Sariff			ctl->enable = 0;
5335162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
5336162922Sariff			ctl->enable = 0;
5337162922Sariff		w = ctl->childwidget;
5338162922Sariff		if (w == NULL)
5339162922Sariff			continue;
5340162922Sariff		if (w->enable == 0 ||
5341162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
5342162922Sariff			ctl->enable = 0;
5343162922Sariff	}
5344162922Sariff
5345163057Sariff	HDA_BOOTVERBOSE(
5346162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Building AFG tree...\n");
5347162922Sariff	);
5348162922Sariff	hdac_audio_build_tree(devinfo);
5349162922Sariff
5350163057Sariff	HDA_BOOTVERBOSE(
5351162922Sariff		device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n");
5352162922Sariff	);
5353162922Sariff	hdac_audio_commit(devinfo, HDA_COMMIT_ALL);
5354163057Sariff	HDA_BOOTVERBOSE(
5355162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Ctls commit...\n");
5356162922Sariff	);
5357162922Sariff	hdac_audio_ctl_commit(devinfo);
5358162922Sariff
5359163057Sariff	HDA_BOOTVERBOSE(
5360162922Sariff		device_printf(sc->dev, "HDA_DEBUG: PCMDIR_PLAY setup...\n");
5361162922Sariff	);
5362162922Sariff	pcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_PLAY);
5363163057Sariff	HDA_BOOTVERBOSE(
5364162922Sariff		device_printf(sc->dev, "HDA_DEBUG: PCMDIR_REC setup...\n");
5365162922Sariff	);
5366162922Sariff	rcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_REC);
5367162922Sariff
5368162922Sariff	hdac_unlock(sc);
5369163057Sariff	HDA_BOOTVERBOSE(
5370162922Sariff		device_printf(sc->dev,
5371162922Sariff		    "HDA_DEBUG: OSS mixer initialization...\n");
5372162922Sariff	);
5373163057Sariff
5374163057Sariff	/*
5375163057Sariff	 * There is no point of return after this. If the driver failed,
5376163057Sariff	 * so be it. Let the detach procedure do all the cleanup.
5377163057Sariff	 */
5378163057Sariff	if (mixer_init(sc->dev, &hdac_audio_ctl_ossmixer_class, devinfo) != 0)
5379162922Sariff		device_printf(sc->dev, "Can't register mixer\n");
5380162922Sariff
5381162922Sariff	if (pcnt > 0)
5382162922Sariff		pcnt = 1;
5383162922Sariff	if (rcnt > 0)
5384162922Sariff		rcnt = 1;
5385162922Sariff
5386163057Sariff	HDA_BOOTVERBOSE(
5387162922Sariff		device_printf(sc->dev,
5388162922Sariff		    "HDA_DEBUG: Registering PCM channels...\n");
5389162922Sariff	);
5390163057Sariff	if (pcm_register(sc->dev, devinfo, pcnt, rcnt) != 0)
5391162922Sariff		device_printf(sc->dev, "Can't register PCM\n");
5392162922Sariff
5393162922Sariff	sc->registered++;
5394162922Sariff
5395162922Sariff	for (i = 0; i < pcnt; i++)
5396162922Sariff		pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo);
5397162922Sariff	for (i = 0; i < rcnt; i++)
5398162922Sariff		pcm_addchan(sc->dev, PCMDIR_REC, &hdac_channel_class, devinfo);
5399162922Sariff
5400164614Sariff#ifdef SND_DYNSYSCTL
5401164614Sariff	SYSCTL_ADD_PROC(device_get_sysctl_ctx(sc->dev),
5402164614Sariff	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO,
5403164614Sariff	    "polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
5404164614Sariff	    sysctl_hdac_polling, "I", "Enable polling mode");
5405164614Sariff#endif
5406164614Sariff
5407162922Sariff	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]",
5408164614Sariff	    rman_get_start(sc->mem.mem_res), rman_get_start(sc->irq.irq_res),
5409164614Sariff	    PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV);
5410162922Sariff	pcm_setstatus(sc->dev, status);
5411162922Sariff	device_printf(sc->dev, "<HDA Codec: %s>\n", hdac_codec_name(devinfo));
5412163057Sariff	HDA_BOOTVERBOSE(
5413163057Sariff		device_printf(sc->dev, "<HDA Codec ID: 0x%08x>\n",
5414163057Sariff		    hdac_codec_id(devinfo));
5415163057Sariff	);
5416164614Sariff	device_printf(sc->dev, "<HDA Driver Revision: %s>\n",
5417164614Sariff	    HDA_DRV_TEST_REV);
5418162922Sariff
5419163057Sariff	HDA_BOOTVERBOSE(
5420162922Sariff		if (devinfo->function.audio.quirks != 0) {
5421162922Sariff			device_printf(sc->dev, "\n");
5422163057Sariff			device_printf(sc->dev, "HDA config/quirks:");
5423163057Sariff			for (i = 0; i < HDAC_QUIRKS_TAB_LEN; i++) {
5424163057Sariff				if (devinfo->function.audio.quirks &
5425163057Sariff				    hdac_quirks_tab[i].value)
5426163057Sariff					printf(" %s", hdac_quirks_tab[i].key);
5427163057Sariff			}
5428162922Sariff			printf("\n");
5429162922Sariff		}
5430162922Sariff		device_printf(sc->dev, "\n");
5431162922Sariff		device_printf(sc->dev, "+-------------------+\n");
5432162922Sariff		device_printf(sc->dev, "| DUMPING HDA NODES |\n");
5433162922Sariff		device_printf(sc->dev, "+-------------------+\n");
5434162922Sariff		hdac_dump_nodes(devinfo);
5435162922Sariff		device_printf(sc->dev, "\n");
5436162922Sariff		device_printf(sc->dev, "+------------------------+\n");
5437162922Sariff		device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
5438162922Sariff		device_printf(sc->dev, "+------------------------+\n");
5439162922Sariff		device_printf(sc->dev, "\n");
5440162922Sariff		i = 0;
5441162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
5442162922Sariff			device_printf(sc->dev, "%3d: nid=%d", i,
5443162922Sariff			    (ctl->widget != NULL) ? ctl->widget->nid : -1);
5444162922Sariff			if (ctl->childwidget != NULL)
5445162922Sariff				printf(" cnid=%d", ctl->childwidget->nid);
5446162922Sariff			printf(" dir=0x%x index=%d "
5447162922Sariff			    "ossmask=0x%08x ossdev=%d%s\n",
5448162922Sariff			    ctl->dir, ctl->index,
5449162922Sariff			    ctl->ossmask, ctl->ossdev,
5450162922Sariff			    (ctl->enable == 0) ? " [DISABLED]" : "");
5451162922Sariff		}
5452162922Sariff		device_printf(sc->dev, "\n");
5453162922Sariff		device_printf(sc->dev, "+-----------------------------------+\n");
5454162922Sariff		device_printf(sc->dev, "| DUMPING HDA AUDIO/VOLUME CONTROLS |\n");
5455162922Sariff		device_printf(sc->dev, "+-----------------------------------+\n");
5456162922Sariff		hdac_dump_ctls(devinfo, "Master Volume (OSS: vol)", SOUND_MASK_VOLUME);
5457162922Sariff		hdac_dump_ctls(devinfo, "PCM Volume (OSS: pcm)", SOUND_MASK_PCM);
5458162922Sariff		hdac_dump_ctls(devinfo, "CD Volume (OSS: cd)", SOUND_MASK_CD);
5459162922Sariff		hdac_dump_ctls(devinfo, "Microphone Volume (OSS: mic)", SOUND_MASK_MIC);
5460162922Sariff		hdac_dump_ctls(devinfo, "Line-in Volume (OSS: line)", SOUND_MASK_LINE);
5461162922Sariff		hdac_dump_ctls(devinfo, "Recording Level (OSS: rec)", SOUND_MASK_RECLEV);
5462162922Sariff		hdac_dump_ctls(devinfo, "Speaker/Beep (OSS: speaker)", SOUND_MASK_SPEAKER);
5463162922Sariff		hdac_dump_ctls(devinfo, NULL, 0);
5464162922Sariff		hdac_dump_dac(devinfo);
5465162922Sariff		hdac_dump_adc(devinfo);
5466162922Sariff		device_printf(sc->dev, "\n");
5467162922Sariff		device_printf(sc->dev, "+--------------------------------------+\n");
5468162922Sariff		device_printf(sc->dev, "| DUMPING PCM Playback/Record Channels |\n");
5469162922Sariff		device_printf(sc->dev, "+--------------------------------------+\n");
5470162922Sariff		hdac_dump_pcmchannels(sc, pcnt, rcnt);
5471162922Sariff	);
5472164614Sariff
5473164614Sariff	if (sc->polling != 0) {
5474164614Sariff		hdac_lock(sc);
5475164614Sariff		callout_reset(&sc->poll_hdac, 1, hdac_poll_callback, sc);
5476164614Sariff		hdac_unlock(sc);
5477164614Sariff	}
5478162922Sariff}
5479162922Sariff
5480162922Sariff/****************************************************************************
5481162922Sariff * int hdac_detach(device_t)
5482162922Sariff *
5483162922Sariff * Detach and free up resources utilized by the hdac device.
5484162922Sariff ****************************************************************************/
5485162922Sariffstatic int
5486162922Sariffhdac_detach(device_t dev)
5487162922Sariff{
5488162922Sariff	struct hdac_softc *sc = NULL;
5489162922Sariff	struct hdac_devinfo *devinfo = NULL;
5490163057Sariff	int err;
5491162922Sariff
5492162922Sariff	devinfo = (struct hdac_devinfo *)pcm_getdevinfo(dev);
5493162922Sariff	if (devinfo != NULL && devinfo->codec != NULL)
5494162922Sariff		sc = devinfo->codec->sc;
5495162922Sariff	if (sc == NULL)
5496163057Sariff		return (0);
5497162922Sariff
5498162922Sariff	if (sc->registered > 0) {
5499163057Sariff		err = pcm_unregister(dev);
5500163057Sariff		if (err != 0)
5501163057Sariff			return (err);
5502162922Sariff	}
5503162922Sariff
5504163057Sariff	hdac_release_resources(sc);
5505162922Sariff
5506162922Sariff	return (0);
5507162922Sariff}
5508162922Sariff
5509162922Sariffstatic device_method_t hdac_methods[] = {
5510162922Sariff	/* device interface */
5511162922Sariff	DEVMETHOD(device_probe,		hdac_probe),
5512162922Sariff	DEVMETHOD(device_attach,	hdac_attach),
5513162922Sariff	DEVMETHOD(device_detach,	hdac_detach),
5514162922Sariff	{ 0, 0 }
5515162922Sariff};
5516162922Sariff
5517162922Sariffstatic driver_t hdac_driver = {
5518162922Sariff	"pcm",
5519162922Sariff	hdac_methods,
5520162922Sariff	PCM_SOFTC_SIZE,
5521162922Sariff};
5522162922Sariff
5523162922SariffDRIVER_MODULE(snd_hda, pci, hdac_driver, pcm_devclass, 0, 0);
5524162922SariffMODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
5525162922SariffMODULE_VERSION(snd_hda, 1);
5526