hdac.c revision 162965
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
47162922Sariff *        interesting documents, especiall 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
70162922Sariff#include <dev/sound/pcm/sound.h>
71162922Sariff#include <dev/pci/pcireg.h>
72162922Sariff#include <dev/pci/pcivar.h>
73162922Sariff
74162922Sariff#include <dev/sound/pci/hda/hdac_private.h>
75162922Sariff#include <dev/sound/pci/hda/hdac_reg.h>
76162922Sariff#include <dev/sound/pci/hda/hda_reg.h>
77162922Sariff#include <dev/sound/pci/hda/hdac.h>
78162922Sariff
79162922Sariff#include "mixer_if.h"
80162922Sariff
81162965Sariff#define HDA_DRV_TEST_REV	"20061003_0029"
82162922Sariff#define HDA_WIDGET_PARSER_REV	1
83162922Sariff
84162922SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdac.c 162965 2006-10-02 16:30:04Z ariff $");
85162922Sariff
86162922Sariff#undef HDA_DEBUG_ENABLED
87162922Sariff#define HDA_DEBUG_ENABLED	1
88162922Sariff
89162922Sariff#ifdef HDA_DEBUG_ENABLED
90162922Sariff#define HDA_DEBUG_MSG(stmt)	do {	\
91162922Sariff	if (bootverbose) {		\
92162922Sariff		stmt			\
93162922Sariff	}				\
94162922Sariff} while(0)
95162922Sariff#else
96162922Sariff#define HDA_DEBUG_MSG(stmt)
97162922Sariff#endif
98162922Sariff
99162922Sariff#define HDA_BOOTVERBOSE_MSG(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)
112162922Sariff
113162965Sariff#define HDA_FLAG_MATCH(fl, v)	(((fl) & (v)) == (v))
114162965Sariff#define HDA_MATCH_ALL		0xffffffff
115162965Sariff#define HDAC_INVALID		0xffffffff
116162965Sariff
117162922Sariff#define HDA_MODEL_CONSTRUCT(vendor, model)	\
118162922Sariff		(((uint32_t)(model) << 16) | ((vendor##_VENDORID) & 0xffff))
119162922Sariff
120162922Sariff/* Controller models */
121162922Sariff
122162922Sariff/* Intel */
123162922Sariff#define INTEL_VENDORID		0x8086
124162922Sariff#define HDA_INTEL_82801F	HDA_MODEL_CONSTRUCT(INTEL, 0x2668)
125162922Sariff#define HDA_INTEL_82801G	HDA_MODEL_CONSTRUCT(INTEL, 0x27d8)
126162922Sariff#define HDA_INTEL_ALL		HDA_MODEL_CONSTRUCT(INTEL, 0xffff)
127162922Sariff
128162922Sariff/* Nvidia */
129162922Sariff#define NVIDIA_VENDORID		0x10de
130162922Sariff#define HDA_NVIDIA_MCP51	HDA_MODEL_CONSTRUCT(NVIDIA, 0x026c)
131162922Sariff#define HDA_NVIDIA_MCP55	HDA_MODEL_CONSTRUCT(NVIDIA, 0x0371)
132162922Sariff#define HDA_NVIDIA_ALL		HDA_MODEL_CONSTRUCT(NVIDIA, 0xffff)
133162922Sariff
134162922Sariff/* ATI */
135162922Sariff#define ATI_VENDORID		0x1002
136162922Sariff#define HDA_ATI_SB450		HDA_MODEL_CONSTRUCT(ATI, 0x437b)
137162922Sariff#define HDA_ATI_ALL		HDA_MODEL_CONSTRUCT(ATI, 0xffff)
138162922Sariff
139162922Sariff/* OEM/subvendors */
140162922Sariff
141162922Sariff/* HP/Compaq */
142162922Sariff#define HP_VENDORID		0x103c
143162922Sariff#define HP_V3000_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30b5)
144162922Sariff#define HP_NX7400_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30a2)
145162922Sariff#define HP_NX6310_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0x30aa)
146162922Sariff#define HP_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(HP, 0xffff)
147162922Sariff
148162922Sariff/* Dell */
149162922Sariff#define DELL_VENDORID		0x1028
150162922Sariff#define DELL_D820_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01cc)
151162922Sariff#define DELL_I1300_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0x01c9)
152162922Sariff#define DELL_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(DELL, 0xffff)
153162922Sariff
154162922Sariff/* Clevo */
155162922Sariff#define CLEVO_VENDORID		0x1558
156162922Sariff#define CLEVO_D900T_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0x0900)
157162922Sariff#define CLEVO_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(CLEVO, 0xffff)
158162922Sariff
159162922Sariff/* Acer */
160162922Sariff#define ACER_VENDORID		0x1025
161162922Sariff#define ACER_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ACER, 0xffff)
162162922Sariff
163162965Sariff/* Asus */
164162965Sariff#define ASUS_VENDORID		0x1043
165162965Sariff#define ASUS_M5200_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0x1993)
166162965Sariff#define ASUS_ALL_SUBVENDOR	HDA_MODEL_CONSTRUCT(ASUS, 0xffff)
167162922Sariff
168162965Sariff
169162922Sariff/* Misc constants.. */
170162922Sariff#define HDA_AMP_MUTE_DEFAULT	(0xffffffff)
171162922Sariff#define HDA_AMP_MUTE_NONE	(0)
172162922Sariff#define HDA_AMP_MUTE_LEFT	(1 << 0)
173162922Sariff#define HDA_AMP_MUTE_RIGHT	(1 << 1)
174162922Sariff#define HDA_AMP_MUTE_ALL	(HDA_AMP_MUTE_LEFT | HDA_AMP_MUTE_RIGHT)
175162922Sariff
176162922Sariff#define HDA_AMP_LEFT_MUTED(v)	((v) & (HDA_AMP_MUTE_LEFT))
177162922Sariff#define HDA_AMP_RIGHT_MUTED(v)	(((v) & HDA_AMP_MUTE_RIGHT) >> 1)
178162922Sariff
179162922Sariff#define HDA_DAC_PATH	(1 << 0)
180162922Sariff#define HDA_ADC_PATH	(1 << 1)
181162922Sariff#define HDA_ADC_RECSEL	(1 << 2)
182162922Sariff
183162922Sariff#define HDA_CTL_OUT	0x1
184162922Sariff#define HDA_CTL_IN	0x2
185162922Sariff#define HDA_CTL_BOTH	(HDA_CTL_IN | HDA_CTL_OUT)
186162922Sariff
187162922Sariff#define HDA_QUIRK_GPIO1		(1 << 0)
188162922Sariff#define HDA_QUIRK_GPIO2		(1 << 1)
189162922Sariff#define HDA_QUIRK_SOFTPCMVOL	(1 << 2)
190162922Sariff#define HDA_QUIRK_FIXEDRATE	(1 << 3)
191162922Sariff#define HDA_QUIRK_FORCESTEREO	(1 << 4)
192162922Sariff
193162922Sariff#define HDA_BDL_MIN	2
194162922Sariff#define HDA_BDL_MAX	256
195162922Sariff#define HDA_BDL_DEFAULT	HDA_BDL_MIN
196162922Sariff
197162922Sariff#define HDA_BUFSZ_MIN		4096
198162922Sariff#define HDA_BUFSZ_MAX		65536
199162922Sariff#define HDA_BUFSZ_DEFAULT	16384
200162922Sariff
201162922Sariff#define HDA_PARSE_MAXDEPTH	10
202162922Sariff
203162922Sariff#define HDAC_UNSOLTAG_EVENT_HP	0x00
204162922Sariff
205162922Sariffstatic MALLOC_DEFINE(M_HDAC, "hdac", "High Definition Audio Controller");
206162922Sariff
207162922Sariffenum {
208162922Sariff	HDA_PARSE_MIXER,
209162922Sariff	HDA_PARSE_DIRECT
210162922Sariff};
211162922Sariff
212162922Sariff/* Default */
213162922Sariffstatic uint32_t hdac_fmt[] = {
214162922Sariff	AFMT_STEREO | AFMT_S16_LE,
215162922Sariff	0
216162922Sariff};
217162922Sariff
218162922Sariffstatic struct pcmchan_caps hdac_caps = {48000, 48000, hdac_fmt, 0};
219162922Sariff
220162922Sariffstatic const struct {
221162922Sariff	uint32_t	model;
222162922Sariff	char		*desc;
223162922Sariff} hdac_devices[] = {
224162922Sariff	{ HDA_INTEL_82801F,  "Intel 82801F" },
225162922Sariff	{ HDA_INTEL_82801G,  "Intel 82801G" },
226162922Sariff	{ HDA_NVIDIA_MCP51,  "NVidia MCP51" },
227162922Sariff	{ HDA_NVIDIA_MCP55,  "NVidia MCP55" },
228162922Sariff	{ HDA_ATI_SB450,     "ATI SB450"    },
229162922Sariff	/* Unknown */
230162922Sariff	{ HDA_INTEL_ALL,  "Intel (Unknown)"  },
231162922Sariff	{ HDA_NVIDIA_ALL, "NVidia (Unknown)" },
232162922Sariff	{ HDA_ATI_ALL,    "ATI (Unknown)"    },
233162922Sariff};
234162922Sariff#define HDAC_DEVICES_LEN (sizeof(hdac_devices) / sizeof(hdac_devices[0]))
235162922Sariff
236162922Sariffstatic const struct {
237162922Sariff	uint32_t	rate;
238162922Sariff	int		valid;
239162922Sariff	uint16_t	base;
240162922Sariff	uint16_t	mul;
241162922Sariff	uint16_t	div;
242162922Sariff} hda_rate_tab[] = {
243162922Sariff	{   8000, 1, 0x0000, 0x0000, 0x0500 },	/* (48000 * 1) / 6 */
244162922Sariff	{   9600, 0, 0x0000, 0x0000, 0x0400 },	/* (48000 * 1) / 5 */
245162922Sariff	{  12000, 0, 0x0000, 0x0000, 0x0300 },	/* (48000 * 1) / 4 */
246162922Sariff	{  16000, 1, 0x0000, 0x0000, 0x0200 },	/* (48000 * 1) / 3 */
247162922Sariff	{  18000, 0, 0x0000, 0x1000, 0x0700 },	/* (48000 * 3) / 8 */
248162922Sariff	{  19200, 0, 0x0000, 0x0800, 0x0400 },	/* (48000 * 2) / 5 */
249162922Sariff	{  24000, 0, 0x0000, 0x0000, 0x0100 },	/* (48000 * 1) / 2 */
250162922Sariff	{  28800, 0, 0x0000, 0x1000, 0x0400 },	/* (48000 * 3) / 5 */
251162922Sariff	{  32000, 1, 0x0000, 0x0800, 0x0200 },	/* (48000 * 2) / 3 */
252162922Sariff	{  36000, 0, 0x0000, 0x1000, 0x0300 },	/* (48000 * 3) / 4 */
253162922Sariff	{  38400, 0, 0x0000, 0x1800, 0x0400 },	/* (48000 * 4) / 5 */
254162922Sariff	{  48000, 1, 0x0000, 0x0000, 0x0000 },	/* (48000 * 1) / 1 */
255162922Sariff	{  64000, 0, 0x0000, 0x1800, 0x0200 },	/* (48000 * 4) / 3 */
256162922Sariff	{  72000, 0, 0x0000, 0x1000, 0x0100 },	/* (48000 * 3) / 2 */
257162922Sariff	{  96000, 1, 0x0000, 0x0800, 0x0000 },	/* (48000 * 2) / 1 */
258162922Sariff	{ 144000, 0, 0x0000, 0x1000, 0x0000 },	/* (48000 * 3) / 1 */
259162922Sariff	{ 192000, 1, 0x0000, 0x1800, 0x0000 },	/* (48000 * 4) / 1 */
260162922Sariff	{   8820, 0, 0x4000, 0x0000, 0x0400 },	/* (44100 * 1) / 5 */
261162922Sariff	{  11025, 1, 0x4000, 0x0000, 0x0300 },	/* (44100 * 1) / 4 */
262162922Sariff	{  12600, 0, 0x4000, 0x0800, 0x0600 },	/* (44100 * 2) / 7 */
263162922Sariff	{  14700, 0, 0x4000, 0x0000, 0x0200 },	/* (44100 * 1) / 3 */
264162922Sariff	{  17640, 0, 0x4000, 0x0800, 0x0400 },	/* (44100 * 2) / 5 */
265162922Sariff	{  18900, 0, 0x4000, 0x1000, 0x0600 },	/* (44100 * 3) / 7 */
266162922Sariff	{  22050, 1, 0x4000, 0x0000, 0x0100 },	/* (44100 * 1) / 2 */
267162922Sariff	{  25200, 0, 0x4000, 0x1800, 0x0600 },	/* (44100 * 4) / 7 */
268162922Sariff	{  26460, 0, 0x4000, 0x1000, 0x0400 },	/* (44100 * 3) / 5 */
269162922Sariff	{  29400, 0, 0x4000, 0x0800, 0x0200 },	/* (44100 * 2) / 3 */
270162922Sariff	{  33075, 0, 0x4000, 0x1000, 0x0300 },	/* (44100 * 3) / 4 */
271162922Sariff	{  35280, 0, 0x4000, 0x1800, 0x0400 },	/* (44100 * 4) / 5 */
272162922Sariff	{  44100, 1, 0x4000, 0x0000, 0x0000 },	/* (44100 * 1) / 1 */
273162922Sariff	{  58800, 0, 0x4000, 0x1800, 0x0200 },	/* (44100 * 4) / 3 */
274162922Sariff	{  66150, 0, 0x4000, 0x1000, 0x0100 },	/* (44100 * 3) / 2 */
275162922Sariff	{  88200, 1, 0x4000, 0x0800, 0x0000 },	/* (44100 * 2) / 1 */
276162922Sariff	{ 132300, 0, 0x4000, 0x1000, 0x0000 },	/* (44100 * 3) / 1 */
277162922Sariff	{ 176400, 1, 0x4000, 0x1800, 0x0000 },	/* (44100 * 4) / 1 */
278162922Sariff};
279162922Sariff#define HDA_RATE_TAB_LEN (sizeof(hda_rate_tab) / sizeof(hda_rate_tab[0]))
280162922Sariff
281162922Sariff/* All codecs you can eat... */
282162922Sariff#define HDA_CODEC_CONSTRUCT(vendor, id) \
283162922Sariff		(((uint32_t)(vendor##_VENDORID) << 16) | ((id) & 0xffff))
284162922Sariff
285162922Sariff/* Realtek */
286162922Sariff#define REALTEK_VENDORID	0x10ec
287162922Sariff#define HDA_CODEC_ALC260	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
288162922Sariff#define HDA_CODEC_ALC861	HDA_CODEC_CONSTRUCT(REALTEK, 0x0861)
289162922Sariff#define HDA_CODEC_ALC880	HDA_CODEC_CONSTRUCT(REALTEK, 0x0880)
290162922Sariff#define HDA_CODEC_ALC882	HDA_CODEC_CONSTRUCT(REALTEK, 0x0260)
291162922Sariff#define HDA_CODEC_ALCXXXX	HDA_CODEC_CONSTRUCT(REALTEK, 0xffff)
292162922Sariff
293162922Sariff/* Analog Device */
294162922Sariff#define ANALOGDEVICE_VENDORID	0x11d4
295162922Sariff#define HDA_CODEC_AD1981HD	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1981)
296162922Sariff#define HDA_CODEC_AD1983	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1983)
297162922Sariff#define HDA_CODEC_AD1986A	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0x1986)
298162922Sariff#define HDA_CODEC_ADXXXX	HDA_CODEC_CONSTRUCT(ANALOGDEVICE, 0xffff)
299162922Sariff
300162922Sariff/* CMedia */
301162922Sariff#define CMEDIA_VENDORID		0x434d
302162922Sariff#define HDA_CODEC_CMI9880	HDA_CODEC_CONSTRUCT(CMEDIA, 0x4980)
303162922Sariff#define HDA_CODEC_CMIXXXX	HDA_CODEC_CONSTRUCT(CMEDIA, 0xffff)
304162922Sariff
305162922Sariff/* Sigmatel */
306162922Sariff#define SIGMATEL_VENDORID	0x8384
307162922Sariff#define HDA_CODEC_STAC9221	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7680)
308162922Sariff#define HDA_CODEC_STAC9221D	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7683)
309162922Sariff#define HDA_CODEC_STAC9220	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7690)
310162922Sariff#define HDA_CODEC_STAC922XD	HDA_CODEC_CONSTRUCT(SIGMATEL, 0x7681)
311162922Sariff#define HDA_CODEC_STACXXXX	HDA_CODEC_CONSTRUCT(SIGMATEL, 0xffff)
312162922Sariff
313162922Sariff/*
314162922Sariff * Conexant
315162922Sariff *
316162922Sariff * Ok, the truth is, I don't have any idea at all whether
317162922Sariff * it is "Venice" or "Waikiki" or other unnamed CXyadayada. The only
318162922Sariff * place that tell me it is "Venice" is from its Windows driver INF.
319162922Sariff */
320162922Sariff#define CONEXANT_VENDORID	0x14f1
321162922Sariff#define HDA_CODEC_CXVENICE	HDA_CODEC_CONSTRUCT(CONEXANT, 0x5045)
322162922Sariff#define HDA_CODEC_CXXXXX	HDA_CODEC_CONSTRUCT(CONEXANT, 0xffff)
323162922Sariff
324162922Sariff
325162922Sariff/* Codecs */
326162922Sariffstatic const struct {
327162922Sariff	uint32_t id;
328162922Sariff	char *name;
329162922Sariff} hdac_codecs[] = {
330162922Sariff	{ HDA_CODEC_ALC260,    "Realtek ALC260" },
331162922Sariff	{ HDA_CODEC_ALC861,    "Realtek ALC861" },
332162922Sariff	{ HDA_CODEC_ALC880,    "Realtek ALC880" },
333162922Sariff	{ HDA_CODEC_ALC882,    "Realtek ALC882" },
334162922Sariff	{ HDA_CODEC_AD1981HD,  "Analog Device AD1981HD" },
335162922Sariff	{ HDA_CODEC_AD1983,    "Analog Device AD1983" },
336162922Sariff	{ HDA_CODEC_AD1986A,   "Analog Device AD1986A" },
337162922Sariff	{ HDA_CODEC_CMI9880,   "CMedia CMI9880" },
338162922Sariff	{ HDA_CODEC_STAC9221,  "Sigmatel STAC9221" },
339162922Sariff	{ HDA_CODEC_STAC9221D, "Sigmatel STAC9221D" },
340162922Sariff	{ HDA_CODEC_STAC9220,  "Sigmatel STAC9220" },
341162922Sariff	{ HDA_CODEC_STAC922XD, "Sigmatel STAC9220D/9223D" },
342162922Sariff	{ HDA_CODEC_CXVENICE,  "Conexant Venice" },
343162922Sariff	/* Unknown codec */
344162922Sariff	{ HDA_CODEC_ALCXXXX,   "Realtek (Unknown)" },
345162922Sariff	{ HDA_CODEC_ADXXXX,    "Analog Device (Unknown)" },
346162922Sariff	{ HDA_CODEC_CMIXXXX,   "CMedia (Unknown)" },
347162922Sariff	{ HDA_CODEC_STACXXXX,  "Sigmatel (Unknown)" },
348162922Sariff	{ HDA_CODEC_CXXXXX,    "Conexant (Unknown)" },
349162922Sariff};
350162922Sariff#define HDAC_CODECS_LEN	(sizeof(hdac_codecs) / sizeof(hdac_codecs[0]))
351162922Sariff
352162922Sariffenum {
353162922Sariff	HDAC_HP_SWITCH_CTL,
354162922Sariff	HDAC_HP_SWITCH_CTRL
355162922Sariff};
356162922Sariff
357162922Sariffstatic const struct {
358162965Sariff	uint32_t model;
359162922Sariff	uint32_t id;
360162922Sariff	int type;
361162922Sariff	nid_t hpnid;
362162922Sariff	nid_t spkrnid[8];
363162922Sariff	nid_t eapdnid;
364162922Sariff} hdac_hp_switch[] = {
365162922Sariff	/* Specific OEM models */
366162922Sariff	{ HP_V3000_SUBVENDOR,  HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL,
367162922Sariff	    17, { 16, -1 }, 16 },
368162922Sariff	{ HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
369162922Sariff	     6, {  5, -1 },  5 },
370162922Sariff	{ HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
371162922Sariff	     6, {  5, -1 },  5 },
372162922Sariff	{ DELL_D820_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL,
373162922Sariff	    13, { 14, -1 }, -1 },
374162922Sariff	{ DELL_I1300_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL,
375162922Sariff	    13, { 14, -1 }, -1 },
376162922Sariff	/*
377162922Sariff	 * All models that at least come from the same vendor with
378162922Sariff	 * simmilar codec.
379162922Sariff	 */
380162922Sariff	{ HP_ALL_SUBVENDOR,  HDA_CODEC_CXVENICE, HDAC_HP_SWITCH_CTL,
381162922Sariff	    17, { 16, -1 }, 16 },
382162922Sariff	{ HP_ALL_SUBVENDOR, HDA_CODEC_AD1981HD, HDAC_HP_SWITCH_CTL,
383162922Sariff	     6, {  5, -1 },  5 },
384162922Sariff	{ DELL_ALL_SUBVENDOR, HDA_CODEC_STAC9220, HDAC_HP_SWITCH_CTRL,
385162922Sariff	    13, { 14, -1 }, -1 },
386162922Sariff};
387162922Sariff#define HDAC_HP_SWITCH_LEN	\
388162922Sariff		(sizeof(hdac_hp_switch) / sizeof(hdac_hp_switch[0]))
389162922Sariff
390162922Sariffstatic const struct {
391162965Sariff	uint32_t model;
392162922Sariff	uint32_t id;
393162922Sariff	nid_t eapdnid;
394162922Sariff	int hp_switch;
395162922Sariff} hdac_eapd_switch[] = {
396162922Sariff	{ HP_V3000_SUBVENDOR, HDA_CODEC_CXVENICE, 16, 1 },
397162922Sariff	{ HP_NX7400_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
398162922Sariff	{ HP_NX6310_SUBVENDOR, HDA_CODEC_AD1981HD, 5, 1 },
399162922Sariff};
400162922Sariff#define HDAC_EAPD_SWITCH_LEN	\
401162922Sariff		(sizeof(hdac_eapd_switch) / sizeof(hdac_eapd_switch[0]))
402162922Sariff
403162922Sariff/****************************************************************************
404162922Sariff * Function prototypes
405162922Sariff ****************************************************************************/
406162922Sariffstatic void	hdac_intr_handler(void *);
407162922Sariffstatic int	hdac_reset(struct hdac_softc *);
408162922Sariffstatic int	hdac_get_capabilities(struct hdac_softc *);
409162922Sariffstatic void	hdac_dma_cb(void *, bus_dma_segment_t *, int, int);
410162922Sariffstatic int	hdac_dma_alloc(struct hdac_softc *,
411162922Sariff					struct hdac_dma *, bus_size_t);
412162922Sariffstatic void	hdac_dma_free(struct hdac_dma *);
413162922Sariffstatic int	hdac_mem_alloc(struct hdac_softc *);
414162922Sariffstatic void	hdac_mem_free(struct hdac_softc *);
415162922Sariffstatic int	hdac_irq_alloc(struct hdac_softc *);
416162922Sariffstatic void	hdac_irq_free(struct hdac_softc *);
417162922Sariffstatic void	hdac_corb_init(struct hdac_softc *);
418162922Sariffstatic void	hdac_rirb_init(struct hdac_softc *);
419162922Sariffstatic void	hdac_corb_start(struct hdac_softc *);
420162922Sariffstatic void	hdac_rirb_start(struct hdac_softc *);
421162922Sariffstatic void	hdac_scan_codecs(struct hdac_softc *);
422162922Sariffstatic int	hdac_probe_codec(struct hdac_codec *);
423162922Sariffstatic struct	hdac_devinfo *hdac_probe_function(struct hdac_codec *, nid_t);
424162922Sariffstatic void	hdac_add_child(struct hdac_softc *, struct hdac_devinfo *);
425162922Sariff
426162922Sariffstatic void	hdac_attach2(void *);
427162922Sariff
428162922Sariffstatic uint32_t	hdac_command_sendone_internal(struct hdac_softc *,
429162922Sariff							uint32_t, int);
430162922Sariffstatic void	hdac_command_send_internal(struct hdac_softc *,
431162922Sariff					struct hdac_command_list *, int);
432162922Sariff
433162922Sariffstatic int	hdac_probe(device_t);
434162922Sariffstatic int	hdac_attach(device_t);
435162922Sariffstatic int	hdac_detach(device_t);
436162922Sariffstatic void	hdac_widget_connection_select(struct hdac_widget *, uint8_t);
437162922Sariffstatic void	hdac_audio_ctl_amp_set(struct hdac_audio_ctl *,
438162922Sariff						uint32_t, int, int);
439162922Sariffstatic struct	hdac_audio_ctl *hdac_audio_ctl_amp_get(struct hdac_devinfo *,
440162922Sariff							nid_t, int, int);
441162922Sariffstatic void	hdac_audio_ctl_amp_set_internal(struct hdac_softc *,
442162922Sariff				nid_t, nid_t, int, int, int, int, int, int);
443162922Sariffstatic int	hdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *);
444162922Sariffstatic struct	hdac_widget *hdac_widget_get(struct hdac_devinfo *, nid_t);
445162922Sariff
446162922Sariff#define hdac_command(a1, a2, a3)	\
447162922Sariff		hdac_command_sendone_internal(a1, a2, a3)
448162922Sariff
449162922Sariff#define hdac_codec_id(d)						\
450162922Sariff		((uint32_t)((d == NULL) ? 0x00000000 :			\
451162922Sariff		((((uint32_t)(d)->vendor_id & 0x0000ffff) << 16) |	\
452162922Sariff		((uint32_t)(d)->device_id & 0x0000ffff))))
453162922Sariff
454162922Sariffstatic char *
455162922Sariffhdac_codec_name(struct hdac_devinfo *devinfo)
456162922Sariff{
457162922Sariff	uint32_t id;
458162922Sariff	int i;
459162922Sariff
460162922Sariff	id = hdac_codec_id(devinfo);
461162922Sariff
462162922Sariff	for (i = 0; i < HDAC_CODECS_LEN; i++) {
463162965Sariff		if (HDA_FLAG_MATCH(hdac_codecs[i].id, id))
464162922Sariff			return (hdac_codecs[i].name);
465162922Sariff	}
466162922Sariff
467162922Sariff	return ((id == 0x00000000) ? "NULL Codec" : "Unknown Codec");
468162922Sariff}
469162922Sariff
470162922Sariffstatic char *
471162922Sariffhdac_audio_ctl_ossmixer_mask2name(uint32_t devmask)
472162922Sariff{
473162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
474162922Sariff	static char *unknown = "???";
475162922Sariff	int i;
476162922Sariff
477162922Sariff	for (i = SOUND_MIXER_NRDEVICES - 1; i >= 0; i--) {
478162922Sariff		if (devmask & (1 << i))
479162922Sariff			return (ossname[i]);
480162922Sariff	}
481162922Sariff	return (unknown);
482162922Sariff}
483162922Sariff
484162922Sariffstatic void
485162922Sariffhdac_audio_ctl_ossmixer_mask2allname(uint32_t mask, char *buf, size_t len)
486162922Sariff{
487162922Sariff	static char *ossname[] = SOUND_DEVICE_NAMES;
488162922Sariff	int i, first = 1;
489162922Sariff
490162922Sariff	bzero(buf, len);
491162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
492162922Sariff		if (mask & (1 << i)) {
493162922Sariff			if (first == 0)
494162922Sariff				strlcat(buf, ", ", len);
495162922Sariff			strlcat(buf, ossname[i], len);
496162922Sariff			first = 0;
497162922Sariff		}
498162922Sariff	}
499162922Sariff}
500162922Sariff
501162922Sariffstatic struct hdac_audio_ctl *
502162922Sariffhdac_audio_ctl_each(struct hdac_devinfo *devinfo, int *index)
503162922Sariff{
504162922Sariff	if (devinfo == NULL ||
505162922Sariff	    devinfo->node_type != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO ||
506162922Sariff	    index == NULL || devinfo->function.audio.ctl == NULL ||
507162922Sariff	    devinfo->function.audio.ctlcnt < 1 ||
508162922Sariff	    *index < 0 || *index >= devinfo->function.audio.ctlcnt)
509162922Sariff		return (NULL);
510162922Sariff	return (&devinfo->function.audio.ctl[(*index)++]);
511162922Sariff}
512162922Sariff
513162922Sariffstatic struct hdac_audio_ctl *
514162922Sariffhdac_audio_ctl_amp_get(struct hdac_devinfo *devinfo, nid_t nid,
515162922Sariff						int index, int cnt)
516162922Sariff{
517162922Sariff	struct hdac_audio_ctl *ctl, *retctl = NULL;
518162922Sariff	int i, at, atindex, found = 0;
519162922Sariff
520162922Sariff	if (devinfo == NULL || devinfo->function.audio.ctl == NULL)
521162922Sariff		return (NULL);
522162922Sariff
523162922Sariff	at = cnt;
524162922Sariff	if (at == 0)
525162922Sariff		at = 1;
526162922Sariff	else if (at < 0)
527162922Sariff		at = -1;
528162922Sariff	atindex = index;
529162922Sariff	if (atindex < 0)
530162922Sariff		atindex = -1;
531162922Sariff
532162922Sariff	i = 0;
533162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
534162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL)
535162922Sariff			continue;
536162922Sariff		if (!(ctl->widget->nid == nid && (atindex == -1 ||
537162922Sariff		    ctl->index == atindex)))
538162922Sariff			continue;
539162922Sariff		found++;
540162922Sariff		if (found == cnt)
541162922Sariff			return (ctl);
542162922Sariff		retctl = ctl;
543162922Sariff	}
544162922Sariff
545162922Sariff	return ((at == -1) ? retctl : NULL);
546162922Sariff}
547162922Sariff
548162922Sariffstatic void
549162922Sariffhdac_hp_switch_handler(struct hdac_devinfo *devinfo)
550162922Sariff{
551162922Sariff	struct hdac_softc *sc;
552162922Sariff	struct hdac_widget *w;
553162922Sariff	struct hdac_audio_ctl *ctl;
554162922Sariff	uint32_t id, res;
555162922Sariff	int i = 0, j, forcemute;
556162922Sariff	nid_t cad;
557162922Sariff
558162922Sariff	if (devinfo == NULL || devinfo->codec == NULL ||
559162922Sariff	    devinfo->codec->sc == NULL)
560162922Sariff		return;
561162922Sariff
562162922Sariff	sc = devinfo->codec->sc;
563162922Sariff	cad = devinfo->codec->cad;
564162922Sariff	id = hdac_codec_id(devinfo);
565162922Sariff	for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
566162965Sariff		if (HDA_FLAG_MATCH(hdac_hp_switch[i].model,
567162965Sariff		    sc->pci_subvendor) &&
568162922Sariff		    hdac_hp_switch[i].id == id)
569162922Sariff			break;
570162922Sariff	}
571162922Sariff
572162922Sariff	if (i >= HDAC_HP_SWITCH_LEN)
573162922Sariff		return;
574162922Sariff
575162922Sariff	forcemute = 0;
576162922Sariff	if (hdac_hp_switch[i].eapdnid != -1) {
577162922Sariff		w = hdac_widget_get(devinfo, hdac_hp_switch[i].eapdnid);
578162965Sariff		if (w != NULL && w->param.eapdbtl != HDAC_INVALID)
579162922Sariff			forcemute = (w->param.eapdbtl &
580162922Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD) ? 0 : 1;
581162922Sariff	}
582162922Sariff
583162922Sariff	res = hdac_command(sc,
584162922Sariff	    HDA_CMD_GET_PIN_SENSE(cad, hdac_hp_switch[i].hpnid), cad);
585162922Sariff	HDA_BOOTVERBOSE_MSG(
586162922Sariff		device_printf(sc->dev,
587162922Sariff		    "Pin sense: nid=%d res=0x%08x\n",
588162922Sariff		    hdac_hp_switch[i].hpnid, res);
589162922Sariff	);
590162922Sariff	res >>= 31;
591162922Sariff
592162922Sariff	switch (hdac_hp_switch[i].type) {
593162922Sariff	case HDAC_HP_SWITCH_CTL:
594162922Sariff		ctl = hdac_audio_ctl_amp_get(devinfo,
595162922Sariff		    hdac_hp_switch[i].hpnid, 0, 1);
596162922Sariff		if (ctl != NULL) {
597162922Sariff			ctl->muted = (res != 0 && forcemute == 0) ?
598162922Sariff			    HDA_AMP_MUTE_NONE : HDA_AMP_MUTE_ALL;
599162922Sariff			hdac_audio_ctl_amp_set(ctl,
600162922Sariff			    HDA_AMP_MUTE_DEFAULT, ctl->left,
601162922Sariff			    ctl->right);
602162922Sariff		}
603162922Sariff		for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
604162922Sariff			ctl = hdac_audio_ctl_amp_get(devinfo,
605162922Sariff			    hdac_hp_switch[i].spkrnid[j], 0, 1);
606162922Sariff			if (ctl != NULL) {
607162922Sariff				ctl->muted = (res != 0 || forcemute == 1) ?
608162922Sariff				    HDA_AMP_MUTE_ALL : HDA_AMP_MUTE_NONE;
609162922Sariff				hdac_audio_ctl_amp_set(ctl,
610162922Sariff				    HDA_AMP_MUTE_DEFAULT, ctl->left,
611162922Sariff				    ctl->right);
612162922Sariff			}
613162922Sariff		}
614162922Sariff		break;
615162922Sariff	case HDAC_HP_SWITCH_CTRL:
616162922Sariff		if (res != 0) {
617162922Sariff			/* HP in */
618162922Sariff			w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
619162922Sariff			if (w != NULL) {
620162922Sariff				if (forcemute == 0)
621162922Sariff					w->wclass.pin.ctrl |=
622162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
623162922Sariff				else
624162922Sariff					w->wclass.pin.ctrl &=
625162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
626162922Sariff				hdac_command(sc,
627162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
628162922Sariff				    w->wclass.pin.ctrl), cad);
629162922Sariff			}
630162922Sariff			for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
631162922Sariff				w = hdac_widget_get(devinfo,
632162922Sariff				    hdac_hp_switch[i].spkrnid[j]);
633162922Sariff				if (w != NULL) {
634162922Sariff					w->wclass.pin.ctrl &=
635162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
636162922Sariff					hdac_command(sc,
637162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
638162922Sariff					    w->nid,
639162922Sariff					    w->wclass.pin.ctrl), cad);
640162922Sariff				}
641162922Sariff			}
642162922Sariff		} else {
643162922Sariff			/* HP out */
644162922Sariff			w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
645162922Sariff			if (w != NULL) {
646162922Sariff				w->wclass.pin.ctrl &=
647162922Sariff				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
648162922Sariff				hdac_command(sc,
649162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
650162922Sariff				    w->wclass.pin.ctrl), cad);
651162922Sariff			}
652162922Sariff			for (j = 0; hdac_hp_switch[i].spkrnid[j] != -1; j++) {
653162922Sariff				w = hdac_widget_get(devinfo,
654162922Sariff				    hdac_hp_switch[i].spkrnid[j]);
655162922Sariff				if (w != NULL) {
656162922Sariff					if (forcemute == 0)
657162922Sariff						w->wclass.pin.ctrl |=
658162922Sariff						    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
659162922Sariff					else
660162922Sariff						w->wclass.pin.ctrl &=
661162922Sariff						    ~HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
662162922Sariff					hdac_command(sc,
663162922Sariff					    HDA_CMD_SET_PIN_WIDGET_CTRL(cad,
664162922Sariff					    w->nid,
665162922Sariff					    w->wclass.pin.ctrl), cad);
666162922Sariff				}
667162922Sariff			}
668162922Sariff		}
669162922Sariff		break;
670162922Sariff	default:
671162922Sariff		break;
672162922Sariff	}
673162922Sariff}
674162922Sariff
675162922Sariffstatic void
676162922Sariffhdac_unsolicited_handler(struct hdac_codec *codec, uint32_t tag)
677162922Sariff{
678162922Sariff	struct hdac_softc *sc;
679162922Sariff	struct hdac_devinfo *devinfo = NULL;
680162965Sariff	device_t *devlist = NULL;
681162922Sariff	int devcount, i;
682162922Sariff
683162922Sariff	if (codec == NULL || codec->sc == NULL)
684162922Sariff		return;
685162922Sariff
686162922Sariff	sc = codec->sc;
687162922Sariff
688162922Sariff	HDA_BOOTVERBOSE_MSG(
689162922Sariff		device_printf(sc->dev, "Unsol Tag: 0x%08x\n", tag);
690162922Sariff	);
691162922Sariff
692162922Sariff	device_get_children(sc->dev, &devlist, &devcount);
693162965Sariff	for (i = 0; devlist != NULL && i < devcount; i++) {
694162965Sariff		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
695162965Sariff		if (devinfo != NULL && devinfo->node_type ==
696162965Sariff		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
697162965Sariff		    devinfo->codec != NULL &&
698162965Sariff		    devinfo->codec->cad == codec->cad) {
699162965Sariff			break;
700162965Sariff		} else
701162965Sariff			devinfo = NULL;
702162922Sariff	}
703162965Sariff	if (devlist != NULL)
704162965Sariff		free(devlist, M_TEMP);
705162965Sariff
706162922Sariff	if (devinfo == NULL)
707162922Sariff		return;
708162922Sariff
709162922Sariff	switch (tag) {
710162922Sariff	case HDAC_UNSOLTAG_EVENT_HP:
711162922Sariff		hdac_hp_switch_handler(devinfo);
712162922Sariff		break;
713162922Sariff	default:
714162922Sariff		break;
715162922Sariff	}
716162922Sariff}
717162922Sariff
718162922Sariffstatic void
719162922Sariffhdac_stream_intr(struct hdac_softc *sc, struct hdac_chan *ch)
720162922Sariff{
721162922Sariff	/* XXX to be removed */
722162922Sariff#ifdef HDAC_INTR_EXTRA
723162922Sariff	uint32_t res;
724162922Sariff#endif
725162922Sariff
726162922Sariff	if (ch->blkcnt == 0)
727162922Sariff		return;
728162922Sariff
729162922Sariff	/* XXX to be removed */
730162922Sariff#ifdef HDAC_INTR_EXTRA
731162922Sariff	res = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDSTS);
732162922Sariff#endif
733162922Sariff
734162922Sariff	/* XXX to be removed */
735162922Sariff#ifdef HDAC_INTR_EXTRA
736162922Sariff	if ((res & HDAC_SDSTS_DESE) || (res & HDAC_SDSTS_FIFOE))
737162922Sariff		device_printf(sc->dev,
738162922Sariff		    "PCMDIR_%s intr triggered beyond stream boundary: %08x\n",
739162922Sariff		    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC", res);
740162922Sariff#endif
741162922Sariff
742162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDSTS,
743162922Sariff		     HDAC_SDSTS_DESE | HDAC_SDSTS_FIFOE | HDAC_SDSTS_BCIS );
744162922Sariff
745162922Sariff	/* XXX to be removed */
746162922Sariff#ifdef HDAC_INTR_EXTRA
747162922Sariff	if (res & HDAC_SDSTS_BCIS) {
748162922Sariff#endif
749162922Sariff		ch->prevptr = ch->ptr;
750162922Sariff		ch->ptr += sndbuf_getblksz(ch->b);
751162922Sariff		ch->ptr %= sndbuf_getsize(ch->b);
752162922Sariff		hdac_unlock(sc);
753162922Sariff		chn_intr(ch->c);
754162922Sariff		hdac_lock(sc);
755162922Sariff	/* XXX to be removed */
756162922Sariff#ifdef HDAC_INTR_EXTRA
757162922Sariff	}
758162922Sariff#endif
759162922Sariff}
760162922Sariff
761162922Sariff/****************************************************************************
762162922Sariff * void hdac_intr_handler(void *)
763162922Sariff *
764162922Sariff * Interrupt handler. Processes interrupts received from the hdac.
765162922Sariff ****************************************************************************/
766162922Sariffstatic void
767162922Sariffhdac_intr_handler(void *context)
768162922Sariff{
769162922Sariff	struct hdac_softc *sc;
770162922Sariff	uint32_t intsts;
771162922Sariff	uint8_t rirbsts;
772162922Sariff	uint8_t rirbwp;
773162922Sariff	struct hdac_rirb *rirb_base, *rirb;
774162922Sariff	nid_t ucad;
775162922Sariff	uint32_t utag;
776162922Sariff
777162922Sariff	sc = (struct hdac_softc *)context;
778162922Sariff
779162922Sariff	hdac_lock(sc);
780162922Sariff	/* Do we have anything to do? */
781162922Sariff	intsts = HDAC_READ_4(&sc->mem, HDAC_INTSTS);
782162922Sariff	if ((intsts & HDAC_INTSTS_GIS) != HDAC_INTSTS_GIS) {
783162922Sariff		hdac_unlock(sc);
784162922Sariff		return;
785162922Sariff	}
786162922Sariff
787162922Sariff	/* Was this a controller interrupt? */
788162922Sariff	if ((intsts & HDAC_INTSTS_CIS) == HDAC_INTSTS_CIS) {
789162922Sariff		rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
790162922Sariff		rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
791162922Sariff		/* Get as many responses that we can */
792162922Sariff		while ((rirbsts & HDAC_RIRBSTS_RINTFL) == HDAC_RIRBSTS_RINTFL) {
793162922Sariff			HDAC_WRITE_1(&sc->mem, HDAC_RIRBSTS, HDAC_RIRBSTS_RINTFL);
794162922Sariff			rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
795162922Sariff			bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
796162922Sariff			    BUS_DMASYNC_POSTREAD);
797162922Sariff			while (sc->rirb_rp != rirbwp) {
798162922Sariff				sc->rirb_rp++;
799162922Sariff				sc->rirb_rp %= sc->rirb_size;
800162922Sariff				rirb = &rirb_base[sc->rirb_rp];
801162922Sariff				if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
802162922Sariff					ucad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
803162922Sariff					utag = rirb->response >> 26;
804162922Sariff					if (ucad > -1 && ucad < HDAC_CODEC_MAX &&
805162922Sariff					    sc->codecs[ucad] != NULL) {
806162922Sariff						sc->unsolq[sc->unsolq_wp++] =
807162922Sariff						    (ucad << 16) |
808162922Sariff						    (utag & 0xffff);
809162922Sariff						sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
810162922Sariff					}
811162922Sariff				}
812162922Sariff			}
813162922Sariff			rirbsts = HDAC_READ_1(&sc->mem, HDAC_RIRBSTS);
814162922Sariff		}
815162922Sariff		/* XXX to be removed */
816162922Sariff		/* Clear interrupt and exit */
817162922Sariff#ifdef HDAC_INTR_EXTRA
818162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, HDAC_INTSTS_CIS);
819162922Sariff#endif
820162922Sariff	}
821162922Sariff	if ((intsts & HDAC_INTSTS_SIS_MASK)) {
822162922Sariff		if (intsts & (1 << sc->num_iss))
823162922Sariff			hdac_stream_intr(sc, &sc->play);
824162922Sariff		if (intsts & (1 << 0))
825162922Sariff			hdac_stream_intr(sc, &sc->rec);
826162922Sariff		/* XXX to be removed */
827162922Sariff#ifdef HDAC_INTR_EXTRA
828162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_INTSTS, intsts & HDAC_INTSTS_SIS_MASK);
829162922Sariff#endif
830162922Sariff	}
831162922Sariff
832162922Sariff	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
833162922Sariff		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
834162922Sariff		while (sc->unsolq_rp != sc->unsolq_wp) {
835162922Sariff			ucad = sc->unsolq[sc->unsolq_rp] >> 16;
836162922Sariff			utag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
837162922Sariff			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
838162922Sariff			hdac_unsolicited_handler(sc->codecs[ucad], utag);
839162922Sariff		}
840162922Sariff		sc->unsolq_st = HDAC_UNSOLQ_READY;
841162922Sariff	}
842162922Sariff
843162922Sariff	hdac_unlock(sc);
844162922Sariff}
845162922Sariff
846162922Sariff/****************************************************************************
847162922Sariff * int had_reset(hdac_softc *)
848162922Sariff *
849162922Sariff * Reset the hdac to a quiescent and known state.
850162922Sariff ****************************************************************************/
851162922Sariffstatic int
852162922Sariffhdac_reset(struct hdac_softc *sc)
853162922Sariff{
854162922Sariff	uint32_t gctl;
855162922Sariff	int count, i;
856162922Sariff
857162922Sariff	/*
858162922Sariff	 * Stop all Streams DMA engine
859162922Sariff	 */
860162922Sariff	for (i = 0; i < sc->num_iss; i++)
861162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_ISDCTL(sc, i), 0x0);
862162922Sariff	for (i = 0; i < sc->num_oss; i++)
863162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_OSDCTL(sc, i), 0x0);
864162922Sariff	for (i = 0; i < sc->num_bss; i++)
865162922Sariff		HDAC_WRITE_4(&sc->mem, HDAC_BSDCTL(sc, i), 0x0);
866162922Sariff
867162922Sariff	/*
868162922Sariff	 * Stop Control DMA engines
869162922Sariff	 */
870162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, 0x0);
871162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, 0x0);
872162922Sariff
873162922Sariff	/*
874162922Sariff	 * Reset the controller. The reset must remain asserted for
875162922Sariff	 * a minimum of 100us.
876162922Sariff	 */
877162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
878162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl & ~HDAC_GCTL_CRST);
879162922Sariff	count = 10000;
880162922Sariff	do {
881162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
882162922Sariff		if (!(gctl & HDAC_GCTL_CRST))
883162922Sariff			break;
884162922Sariff		DELAY(10);
885162922Sariff	} while	(--count);
886162922Sariff	if (gctl & HDAC_GCTL_CRST) {
887162922Sariff		device_printf(sc->dev, "Unable to put hdac in reset\n");
888162922Sariff		return (ENXIO);
889162922Sariff	}
890162922Sariff	DELAY(100);
891162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
892162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_CRST);
893162922Sariff	count = 10000;
894162922Sariff	do {
895162922Sariff		gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
896162922Sariff		if ((gctl & HDAC_GCTL_CRST))
897162922Sariff			break;
898162922Sariff		DELAY(10);
899162922Sariff	} while (--count);
900162922Sariff	if (!(gctl & HDAC_GCTL_CRST)) {
901162922Sariff		device_printf(sc->dev, "Device stuck in reset\n");
902162922Sariff		return (ENXIO);
903162922Sariff	}
904162922Sariff
905162922Sariff	/*
906162922Sariff	 * Enable unsolicited interrupt.
907162922Sariff	 */
908162922Sariff	gctl = HDAC_READ_4(&sc->mem, HDAC_GCTL);
909162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_GCTL, gctl | HDAC_GCTL_UNSOL);
910162922Sariff
911162922Sariff	/*
912162922Sariff	 * Wait for codecs to finish their own reset sequence. The delay here
913162922Sariff	 * should be of 250us but for some reasons, on it's not enough on my
914162922Sariff	 * computer. Let's use twice as much as necessary to make sure that
915162922Sariff	 * it's reset properly.
916162922Sariff	 */
917162922Sariff	DELAY(1000);
918162922Sariff
919162922Sariff	return (0);
920162922Sariff}
921162922Sariff
922162922Sariff
923162922Sariff/****************************************************************************
924162922Sariff * int hdac_get_capabilities(struct hdac_softc *);
925162922Sariff *
926162922Sariff * Retreive the general capabilities of the hdac;
927162922Sariff *	Number of Input Streams
928162922Sariff *	Number of Output Streams
929162922Sariff *	Number of bidirectional Streams
930162922Sariff *	64bit ready
931162922Sariff *	CORB and RIRB sizes
932162922Sariff ****************************************************************************/
933162922Sariffstatic int
934162922Sariffhdac_get_capabilities(struct hdac_softc *sc)
935162922Sariff{
936162922Sariff	uint16_t gcap;
937162922Sariff	uint8_t corbsize, rirbsize;
938162922Sariff
939162922Sariff	gcap = HDAC_READ_2(&sc->mem, HDAC_GCAP);
940162922Sariff	sc->num_iss = HDAC_GCAP_ISS(gcap);
941162922Sariff	sc->num_oss = HDAC_GCAP_OSS(gcap);
942162922Sariff	sc->num_bss = HDAC_GCAP_BSS(gcap);
943162922Sariff
944162922Sariff	sc->support_64bit = (gcap & HDAC_GCAP_64OK) == HDAC_GCAP_64OK;
945162922Sariff
946162922Sariff	corbsize = HDAC_READ_1(&sc->mem, HDAC_CORBSIZE);
947162922Sariff	if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_256) ==
948162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_256)
949162922Sariff		sc->corb_size = 256;
950162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_16) ==
951162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_16)
952162922Sariff		sc->corb_size = 16;
953162922Sariff	else if ((corbsize & HDAC_CORBSIZE_CORBSZCAP_2) ==
954162922Sariff	    HDAC_CORBSIZE_CORBSZCAP_2)
955162922Sariff		sc->corb_size = 2;
956162922Sariff	else {
957162922Sariff		device_printf(sc->dev, "%s: Invalid corb size (%x)\n",
958162922Sariff		    __func__, corbsize);
959162922Sariff		return (ENXIO);
960162922Sariff	}
961162922Sariff
962162922Sariff	rirbsize = HDAC_READ_1(&sc->mem, HDAC_RIRBSIZE);
963162922Sariff	if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_256) ==
964162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_256)
965162922Sariff		sc->rirb_size = 256;
966162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_16) ==
967162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_16)
968162922Sariff		sc->rirb_size = 16;
969162922Sariff	else if ((rirbsize & HDAC_RIRBSIZE_RIRBSZCAP_2) ==
970162922Sariff	    HDAC_RIRBSIZE_RIRBSZCAP_2)
971162922Sariff		sc->rirb_size = 2;
972162922Sariff	else {
973162922Sariff		device_printf(sc->dev, "%s: Invalid rirb size (%x)\n",
974162922Sariff		    __func__, rirbsize);
975162922Sariff		return (ENXIO);
976162922Sariff	}
977162922Sariff
978162922Sariff	return (0);
979162922Sariff}
980162922Sariff
981162922Sariff
982162922Sariff/****************************************************************************
983162922Sariff * void hdac_dma_cb
984162922Sariff *
985162922Sariff * This function is called by bus_dmamap_load when the mapping has been
986162922Sariff * established. We just record the physical address of the mapping into
987162922Sariff * the struct hdac_dma passed in.
988162922Sariff ****************************************************************************/
989162922Sariffstatic void
990162922Sariffhdac_dma_cb(void *callback_arg, bus_dma_segment_t *segs, int nseg, int error)
991162922Sariff{
992162922Sariff	struct hdac_dma *dma;
993162922Sariff
994162922Sariff	if (error == 0) {
995162922Sariff		dma = (struct hdac_dma *)callback_arg;
996162922Sariff		dma->dma_paddr = segs[0].ds_addr;
997162922Sariff	}
998162922Sariff}
999162922Sariff
1000162922Sariffstatic void
1001162922Sariffhdac_dma_nocache(void *ptr)
1002162922Sariff{
1003162956Sariff#if defined(__i386__) || defined(__amd64__)
1004162922Sariff	pt_entry_t *pte;
1005162922Sariff	vm_offset_t va;
1006162922Sariff
1007162922Sariff	va = (vm_offset_t)ptr;
1008162922Sariff	pte = vtopte(va);
1009162922Sariff	if (pte)  {
1010162922Sariff		*pte |= PG_N;
1011162922Sariff		invltlb();
1012162922Sariff	}
1013162956Sariff#endif
1014162922Sariff}
1015162922Sariff
1016162922Sariff/****************************************************************************
1017162922Sariff * int hdac_dma_alloc
1018162922Sariff *
1019162922Sariff * This function allocate and setup a dma region (struct hdac_dma).
1020162922Sariff * It must be freed by a corresponding hdac_dma_free.
1021162922Sariff ****************************************************************************/
1022162922Sariffstatic int
1023162922Sariffhdac_dma_alloc(struct hdac_softc *sc, struct hdac_dma *dma, bus_size_t size)
1024162922Sariff{
1025162922Sariff	int result;
1026162922Sariff	int lowaddr;
1027162922Sariff
1028162922Sariff	lowaddr = (sc->support_64bit) ? BUS_SPACE_MAXADDR :
1029162922Sariff	    BUS_SPACE_MAXADDR_32BIT;
1030162922Sariff	bzero(dma, sizeof(*dma));
1031162922Sariff
1032162922Sariff	/*
1033162922Sariff	 * Create a DMA tag
1034162922Sariff	 */
1035162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
1036162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
1037162922Sariff	    0,					/* boundary */
1038162922Sariff	    lowaddr,				/* lowaddr */
1039162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
1040162922Sariff	    NULL,				/* filtfunc */
1041162922Sariff	    NULL,				/* fistfuncarg */
1042162922Sariff	    size, 				/* maxsize */
1043162922Sariff	    1,					/* nsegments */
1044162922Sariff	    size, 				/* maxsegsz */
1045162922Sariff	    0,					/* flags */
1046162922Sariff	    NULL,				/* lockfunc */
1047162922Sariff	    NULL,				/* lockfuncarg */
1048162922Sariff	    &dma->dma_tag);			/* dmat */
1049162922Sariff	if (result != 0) {
1050162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
1051162922Sariff		    __func__, result);
1052162922Sariff		goto fail;
1053162922Sariff	}
1054162922Sariff
1055162922Sariff	/*
1056162922Sariff	 * Allocate DMA memory
1057162922Sariff	 */
1058162965Sariff	result = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr,
1059162922Sariff	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map);
1060162922Sariff	if (result != 0) {
1061162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_alloc failed (%x)\n",
1062162922Sariff		    __func__, result);
1063162922Sariff		goto fail;
1064162922Sariff	}
1065162922Sariff
1066162922Sariff	/*
1067162922Sariff	 * Map the memory
1068162922Sariff	 */
1069162922Sariff	result = bus_dmamap_load(dma->dma_tag, dma->dma_map,
1070162922Sariff	    (void *)dma->dma_vaddr, size, hdac_dma_cb, (void *)dma,
1071162922Sariff	    BUS_DMA_NOWAIT);
1072162922Sariff	if (result != 0 || dma->dma_paddr == 0) {
1073162922Sariff		device_printf(sc->dev, "%s: bus_dmamem_load failed (%x)\n",
1074162922Sariff		    __func__, result);
1075162922Sariff		goto fail;
1076162922Sariff	}
1077162922Sariff	bzero((void *)dma->dma_vaddr, size);
1078162922Sariff	hdac_dma_nocache(dma->dma_vaddr);
1079162922Sariff
1080162922Sariff	return (0);
1081162922Sarifffail:
1082162922Sariff	if (dma->dma_map != NULL)
1083162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1084162922Sariff	if (dma->dma_tag != NULL)
1085162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1086162922Sariff	return (result);
1087162922Sariff}
1088162922Sariff
1089162922Sariff
1090162922Sariff/****************************************************************************
1091162922Sariff * void hdac_dma_free(struct hdac_dma *)
1092162922Sariff *
1093162922Sariff * Free a struct dhac_dma that has been previously allocated via the
1094162922Sariff * hdac_dma_alloc function.
1095162922Sariff ****************************************************************************/
1096162922Sariffstatic void
1097162922Sariffhdac_dma_free(struct hdac_dma *dma)
1098162922Sariff{
1099162922Sariff	if (dma->dma_tag != NULL) {
1100162922Sariff		/* Flush caches */
1101162922Sariff		bus_dmamap_sync(dma->dma_tag, dma->dma_map,
1102162922Sariff		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1103162922Sariff		bus_dmamap_unload(dma->dma_tag, dma->dma_map);
1104162922Sariff		bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map);
1105162922Sariff		bus_dma_tag_destroy(dma->dma_tag);
1106162922Sariff	}
1107162922Sariff}
1108162922Sariff
1109162922Sariff/****************************************************************************
1110162922Sariff * int hdac_mem_alloc(struct hdac_softc *)
1111162922Sariff *
1112162922Sariff * Allocate all the bus resources necessary to speak with the physical
1113162922Sariff * controller.
1114162922Sariff ****************************************************************************/
1115162922Sariffstatic int
1116162922Sariffhdac_mem_alloc(struct hdac_softc *sc)
1117162922Sariff{
1118162922Sariff	struct hdac_mem *mem;
1119162922Sariff
1120162922Sariff	mem = &sc->mem;
1121162922Sariff	mem->mem_rid = PCIR_BAR(0);
1122162922Sariff	mem->mem_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1123162922Sariff	    &mem->mem_rid, RF_ACTIVE);
1124162922Sariff	if (mem->mem_res == NULL) {
1125162922Sariff		device_printf(sc->dev,
1126162922Sariff		    "%s: Unable to allocate memory resource\n", __func__);
1127162922Sariff		return (ENOMEM);
1128162922Sariff	}
1129162922Sariff	mem->mem_tag = rman_get_bustag(mem->mem_res);
1130162922Sariff	mem->mem_handle = rman_get_bushandle(mem->mem_res);
1131162922Sariff
1132162922Sariff	return (0);
1133162922Sariff}
1134162922Sariff
1135162922Sariff/****************************************************************************
1136162922Sariff * void hdac_mem_free(struct hdac_softc *)
1137162922Sariff *
1138162922Sariff * Free up resources previously allocated by hdac_mem_alloc.
1139162922Sariff ****************************************************************************/
1140162922Sariffstatic void
1141162922Sariffhdac_mem_free(struct hdac_softc *sc)
1142162922Sariff{
1143162922Sariff	struct hdac_mem *mem;
1144162922Sariff
1145162922Sariff	mem = &sc->mem;
1146162922Sariff	if (mem->mem_res != NULL)
1147162922Sariff		bus_release_resource(sc->dev, SYS_RES_MEMORY, mem->mem_rid,
1148162922Sariff		    mem->mem_res);
1149162922Sariff}
1150162922Sariff
1151162922Sariff/****************************************************************************
1152162922Sariff * int hdac_irq_alloc(struct hdac_softc *)
1153162922Sariff *
1154162922Sariff * Allocate and setup the resources necessary for interrupt handling.
1155162922Sariff ****************************************************************************/
1156162922Sariffstatic int
1157162922Sariffhdac_irq_alloc(struct hdac_softc *sc)
1158162922Sariff{
1159162922Sariff	struct hdac_irq *irq;
1160162922Sariff	int result;
1161162922Sariff
1162162922Sariff	irq = &sc->irq;
1163162922Sariff	irq->irq_rid = 0x0;
1164162922Sariff	irq->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1165162922Sariff	    &irq->irq_rid, RF_SHAREABLE | RF_ACTIVE);
1166162922Sariff	if (irq->irq_res == NULL) {
1167162922Sariff		device_printf(sc->dev, "%s: Unable to allocate irq\n",
1168162922Sariff		    __func__);
1169162922Sariff		goto fail;
1170162922Sariff	}
1171162922Sariff	result = snd_setup_intr(sc->dev, irq->irq_res, INTR_MPSAFE,
1172162922Sariff		hdac_intr_handler, sc, &irq->irq_handle);
1173162922Sariff	if (result != 0) {
1174162922Sariff		device_printf(sc->dev,
1175162922Sariff		    "%s: Unable to setup interrupt handler (%x)\n",
1176162922Sariff		    __func__, result);
1177162922Sariff		goto fail;
1178162922Sariff	}
1179162922Sariff
1180162922Sariff	return (0);
1181162922Sariff
1182162922Sarifffail:
1183162922Sariff	if (irq->irq_res != NULL)
1184162922Sariff		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1185162922Sariff		    irq->irq_res);
1186162922Sariff	return (ENXIO);
1187162922Sariff}
1188162922Sariff
1189162922Sariff/****************************************************************************
1190162922Sariff * void hdac_irq_free(struct hdac_softc *)
1191162922Sariff *
1192162922Sariff * Free up resources previously allocated by hdac_irq_alloc.
1193162922Sariff ****************************************************************************/
1194162922Sariffstatic void
1195162922Sariffhdac_irq_free(struct hdac_softc *sc)
1196162922Sariff{
1197162922Sariff	struct hdac_irq *irq;
1198162922Sariff
1199162922Sariff	irq = &sc->irq;
1200162922Sariff	if (irq->irq_handle != NULL)
1201162922Sariff		bus_teardown_intr(sc->dev, irq->irq_res, irq->irq_handle);
1202162922Sariff	if (irq->irq_res != NULL)
1203162922Sariff		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->irq_rid,
1204162922Sariff		    irq->irq_res);
1205162922Sariff}
1206162922Sariff
1207162922Sariff/****************************************************************************
1208162922Sariff * void hdac_corb_init(struct hdac_softc *)
1209162922Sariff *
1210162922Sariff * Initialize the corb registers for operations but do not start it up yet.
1211162922Sariff * The CORB engine must not be running when this function is called.
1212162922Sariff ****************************************************************************/
1213162922Sariffstatic void
1214162922Sariffhdac_corb_init(struct hdac_softc *sc)
1215162922Sariff{
1216162922Sariff	uint8_t corbsize;
1217162922Sariff	uint64_t corbpaddr;
1218162922Sariff
1219162922Sariff	/* Setup the CORB size. */
1220162922Sariff	switch (sc->corb_size) {
1221162922Sariff	case 256:
1222162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_256);
1223162922Sariff		break;
1224162922Sariff	case 16:
1225162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_16);
1226162922Sariff		break;
1227162922Sariff	case 2:
1228162922Sariff		corbsize = HDAC_CORBSIZE_CORBSIZE(HDAC_CORBSIZE_CORBSIZE_2);
1229162922Sariff		break;
1230162922Sariff	default:
1231162922Sariff		panic("%s: Invalid CORB size (%x)\n", __func__, sc->corb_size);
1232162922Sariff	}
1233162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBSIZE, corbsize);
1234162922Sariff
1235162922Sariff	/* Setup the CORB Address in the hdac */
1236162922Sariff	corbpaddr = (uint64_t)sc->corb_dma.dma_paddr;
1237162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBLBASE, (uint32_t)corbpaddr);
1238162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_CORBUBASE, (uint32_t)(corbpaddr >> 32));
1239162922Sariff
1240162922Sariff	/* Set the WP and RP */
1241162922Sariff	sc->corb_wp = 0;
1242162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
1243162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, HDAC_CORBRP_CORBRPRST);
1244162922Sariff	/*
1245162922Sariff	 * The HDA specification indicates that the CORBRPRST bit will always
1246162922Sariff	 * read as zero. Unfortunately, it seems that at least the 82801G
1247162922Sariff	 * doesn't reset the bit to zero, which stalls the corb engine.
1248162922Sariff	 * manually reset the bit to zero before continuing.
1249162922Sariff	 */
1250162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_CORBRP, 0x0);
1251162922Sariff
1252162922Sariff	/* Enable CORB error reporting */
1253162922Sariff#if 0
1254162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, HDAC_CORBCTL_CMEIE);
1255162922Sariff#endif
1256162922Sariff}
1257162922Sariff
1258162922Sariff/****************************************************************************
1259162922Sariff * void hdac_rirb_init(struct hdac_softc *)
1260162922Sariff *
1261162922Sariff * Initialize the rirb registers for operations but do not start it up yet.
1262162922Sariff * The RIRB engine must not be running when this function is called.
1263162922Sariff ****************************************************************************/
1264162922Sariffstatic void
1265162922Sariffhdac_rirb_init(struct hdac_softc *sc)
1266162922Sariff{
1267162922Sariff	uint8_t rirbsize;
1268162922Sariff	uint64_t rirbpaddr;
1269162922Sariff
1270162922Sariff	/* Setup the RIRB size. */
1271162922Sariff	switch (sc->rirb_size) {
1272162922Sariff	case 256:
1273162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_256);
1274162922Sariff		break;
1275162922Sariff	case 16:
1276162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_16);
1277162922Sariff		break;
1278162922Sariff	case 2:
1279162922Sariff		rirbsize = HDAC_RIRBSIZE_RIRBSIZE(HDAC_RIRBSIZE_RIRBSIZE_2);
1280162922Sariff		break;
1281162922Sariff	default:
1282162922Sariff		panic("%s: Invalid RIRB size (%x)\n", __func__, sc->rirb_size);
1283162922Sariff	}
1284162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBSIZE, rirbsize);
1285162922Sariff
1286162922Sariff	/* Setup the RIRB Address in the hdac */
1287162922Sariff	rirbpaddr = (uint64_t)sc->rirb_dma.dma_paddr;
1288162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBLBASE, (uint32_t)rirbpaddr);
1289162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_RIRBUBASE, (uint32_t)(rirbpaddr >> 32));
1290162922Sariff
1291162922Sariff	/* Setup the WP and RP */
1292162922Sariff	sc->rirb_rp = 0;
1293162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_RIRBWP, HDAC_RIRBWP_RIRBWPRST);
1294162922Sariff
1295162922Sariff	/* Setup the interrupt threshold */
1296162922Sariff	HDAC_WRITE_2(&sc->mem, HDAC_RINTCNT, sc->rirb_size / 2);
1297162922Sariff
1298162922Sariff	/* Enable Overrun and response received reporting */
1299162922Sariff#if 0
1300162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL,
1301162922Sariff	    HDAC_RIRBCTL_RIRBOIC | HDAC_RIRBCTL_RINTCTL);
1302162922Sariff#else
1303162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, HDAC_RIRBCTL_RINTCTL);
1304162922Sariff#endif
1305162922Sariff
1306162922Sariff	/*
1307162922Sariff	 * Make sure that the Host CPU cache doesn't contain any dirty
1308162922Sariff	 * cache lines that falls in the rirb. If I understood correctly, it
1309162922Sariff	 * should be sufficient to do this only once as the rirb is purely
1310162922Sariff	 * read-only from now on.
1311162922Sariff	 */
1312162922Sariff	bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
1313162922Sariff	    BUS_DMASYNC_PREREAD);
1314162922Sariff}
1315162922Sariff
1316162922Sariff/****************************************************************************
1317162922Sariff * void hdac_corb_start(hdac_softc *)
1318162922Sariff *
1319162922Sariff * Startup the corb DMA engine
1320162922Sariff ****************************************************************************/
1321162922Sariffstatic void
1322162922Sariffhdac_corb_start(struct hdac_softc *sc)
1323162922Sariff{
1324162922Sariff	uint32_t corbctl;
1325162922Sariff
1326162922Sariff	corbctl = HDAC_READ_1(&sc->mem, HDAC_CORBCTL);
1327162922Sariff	corbctl |= HDAC_CORBCTL_CORBRUN;
1328162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_CORBCTL, corbctl);
1329162922Sariff}
1330162922Sariff
1331162922Sariff/****************************************************************************
1332162922Sariff * void hdac_rirb_start(hdac_softc *)
1333162922Sariff *
1334162922Sariff * Startup the rirb DMA engine
1335162922Sariff ****************************************************************************/
1336162922Sariffstatic void
1337162922Sariffhdac_rirb_start(struct hdac_softc *sc)
1338162922Sariff{
1339162922Sariff	uint32_t rirbctl;
1340162922Sariff
1341162922Sariff	rirbctl = HDAC_READ_1(&sc->mem, HDAC_RIRBCTL);
1342162922Sariff	rirbctl |= HDAC_RIRBCTL_RIRBDMAEN;
1343162922Sariff	HDAC_WRITE_1(&sc->mem, HDAC_RIRBCTL, rirbctl);
1344162922Sariff}
1345162922Sariff
1346162922Sariff
1347162922Sariff/****************************************************************************
1348162922Sariff * void hdac_scan_codecs(struct hdac_softc *)
1349162922Sariff *
1350162922Sariff * Scan the bus for available codecs.
1351162922Sariff ****************************************************************************/
1352162922Sariffstatic void
1353162922Sariffhdac_scan_codecs(struct hdac_softc *sc)
1354162922Sariff{
1355162922Sariff	struct hdac_codec *codec;
1356162922Sariff	int i;
1357162922Sariff	uint16_t statests;
1358162922Sariff
1359162922Sariff	SLIST_INIT(&sc->codec_list);
1360162922Sariff
1361162922Sariff	statests = HDAC_READ_2(&sc->mem, HDAC_STATESTS);
1362162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++) {
1363162922Sariff		if (HDAC_STATESTS_SDIWAKE(statests, i)) {
1364162922Sariff			/* We have found a codec. */
1365162922Sariff			hdac_unlock(sc);
1366162922Sariff			codec = (struct hdac_codec *)malloc(sizeof(*codec),
1367162922Sariff			    M_HDAC, M_ZERO | M_NOWAIT);
1368162922Sariff			hdac_lock(sc);
1369162922Sariff			if (codec == NULL) {
1370162922Sariff				device_printf(sc->dev,
1371162922Sariff				    "Unable to allocate memory for codec\n");
1372162922Sariff				continue;
1373162922Sariff			}
1374162922Sariff			codec->verbs_sent = 0;
1375162922Sariff			codec->sc = sc;
1376162922Sariff			codec->cad = i;
1377162922Sariff			sc->codecs[i] = codec;
1378162922Sariff			SLIST_INSERT_HEAD(&sc->codec_list, codec, next_codec);
1379162922Sariff			if (hdac_probe_codec(codec) != 0)
1380162922Sariff				break;
1381162922Sariff		}
1382162922Sariff	}
1383162922Sariff	/* All codecs have been probed, now try to attach drivers to them */
1384162922Sariff	bus_generic_attach(sc->dev);
1385162922Sariff}
1386162922Sariff
1387162922Sariff/****************************************************************************
1388162922Sariff * void hdac_probe_codec(struct hdac_softc *, int)
1389162922Sariff *
1390162922Sariff * Probe a the given codec_id for available function groups.
1391162922Sariff ****************************************************************************/
1392162922Sariffstatic int
1393162922Sariffhdac_probe_codec(struct hdac_codec *codec)
1394162922Sariff{
1395162922Sariff	struct hdac_softc *sc = codec->sc;
1396162922Sariff	struct hdac_devinfo *devinfo;
1397162922Sariff	uint32_t vendorid, revisionid, subnode;
1398162922Sariff	int startnode;
1399162922Sariff	int endnode;
1400162922Sariff	int i;
1401162922Sariff	nid_t cad = codec->cad;
1402162922Sariff
1403162922Sariff	HDA_DEBUG_MSG(
1404162922Sariff		device_printf(sc->dev, "%s: Probing codec: %d\n",
1405162922Sariff		    __func__, cad);
1406162922Sariff	);
1407162922Sariff	vendorid = hdac_command(sc,
1408162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_VENDOR_ID),
1409162922Sariff	    cad);
1410162922Sariff	revisionid = hdac_command(sc,
1411162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_REVISION_ID),
1412162922Sariff	    cad);
1413162922Sariff	subnode = hdac_command(sc,
1414162922Sariff	    HDA_CMD_GET_PARAMETER(cad, 0x0, HDA_PARAM_SUB_NODE_COUNT),
1415162922Sariff	    cad);
1416162922Sariff	startnode = HDA_PARAM_SUB_NODE_COUNT_START(subnode);
1417162922Sariff	endnode = startnode + HDA_PARAM_SUB_NODE_COUNT_TOTAL(subnode);
1418162922Sariff
1419162922Sariff	HDA_DEBUG_MSG(
1420162922Sariff		device_printf(sc->dev, "%s: \tstartnode=%d endnode=%d\n",
1421162922Sariff		    __func__, startnode, endnode);
1422162922Sariff	);
1423162922Sariff	for (i = startnode; i < endnode; i++) {
1424162922Sariff		devinfo = hdac_probe_function(codec, i);
1425162922Sariff		if (devinfo != NULL) {
1426162922Sariff			/* XXX Ignore other FG. */
1427162922Sariff			devinfo->vendor_id =
1428162922Sariff			    HDA_PARAM_VENDOR_ID_VENDOR_ID(vendorid);
1429162922Sariff			devinfo->device_id =
1430162922Sariff			    HDA_PARAM_VENDOR_ID_DEVICE_ID(vendorid);
1431162922Sariff			devinfo->revision_id =
1432162922Sariff			    HDA_PARAM_REVISION_ID_REVISION_ID(revisionid);
1433162922Sariff			devinfo->stepping_id =
1434162922Sariff			    HDA_PARAM_REVISION_ID_STEPPING_ID(revisionid);
1435162922Sariff			HDA_DEBUG_MSG(
1436162922Sariff				device_printf(sc->dev,
1437162922Sariff				    "%s: \tFound AFG nid=%d "
1438162922Sariff				    "[startnode=%d endnode=%d]\n",
1439162922Sariff				    __func__, devinfo->nid,
1440162922Sariff				    startnode, endnode);
1441162922Sariff			);
1442162922Sariff			return (1);
1443162922Sariff		}
1444162922Sariff	}
1445162922Sariff
1446162922Sariff	HDA_DEBUG_MSG(
1447162922Sariff		device_printf(sc->dev, "%s: \tAFG not found\n",
1448162922Sariff		    __func__);
1449162922Sariff	);
1450162922Sariff	return (0);
1451162922Sariff}
1452162922Sariff
1453162922Sariffstatic struct hdac_devinfo *
1454162922Sariffhdac_probe_function(struct hdac_codec *codec, nid_t nid)
1455162922Sariff{
1456162922Sariff	struct hdac_softc *sc = codec->sc;
1457162922Sariff	struct hdac_devinfo *devinfo;
1458162922Sariff	uint32_t fctgrptype;
1459162922Sariff	nid_t cad = codec->cad;
1460162922Sariff
1461162965Sariff	fctgrptype = HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE(hdac_command(sc,
1462162965Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_FCT_GRP_TYPE), cad));
1463162922Sariff
1464162922Sariff	/* XXX For now, ignore other FG. */
1465162965Sariff	if (fctgrptype != HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO)
1466162922Sariff		return (NULL);
1467162922Sariff
1468162922Sariff	hdac_unlock(sc);
1469162922Sariff	devinfo = (struct hdac_devinfo *)malloc(sizeof(*devinfo), M_HDAC,
1470162922Sariff	    M_NOWAIT | M_ZERO);
1471162922Sariff	hdac_lock(sc);
1472162922Sariff	if (devinfo == NULL) {
1473162922Sariff		device_printf(sc->dev, "%s: Unable to allocate ivar\n",
1474162922Sariff		    __func__);
1475162922Sariff		return (NULL);
1476162922Sariff	}
1477162922Sariff
1478162922Sariff	devinfo->nid = nid;
1479162965Sariff	devinfo->node_type = fctgrptype;
1480162922Sariff	devinfo->codec = codec;
1481162922Sariff
1482162922Sariff	hdac_add_child(sc, devinfo);
1483162922Sariff
1484162922Sariff	return (devinfo);
1485162922Sariff}
1486162922Sariff
1487162922Sariffstatic void
1488162922Sariffhdac_add_child(struct hdac_softc *sc, struct hdac_devinfo *devinfo)
1489162922Sariff{
1490162922Sariff	devinfo->dev = device_add_child(sc->dev, NULL, -1);
1491162922Sariff	device_set_ivars(devinfo->dev, (void *)devinfo);
1492162922Sariff	/* XXX - Print more information when booting verbose??? */
1493162922Sariff}
1494162922Sariff
1495162922Sariffstatic void
1496162922Sariffhdac_widget_connection_parse(struct hdac_widget *w)
1497162922Sariff{
1498162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1499162922Sariff	uint32_t res;
1500162922Sariff	int i, j, max, found, entnum, cnid;
1501162922Sariff	nid_t cad = w->devinfo->codec->cad;
1502162922Sariff	nid_t nid = w->nid;
1503162922Sariff
1504162922Sariff	res = hdac_command(sc,
1505162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_CONN_LIST_LENGTH), cad);
1506162922Sariff
1507162922Sariff	w->nconns = HDA_PARAM_CONN_LIST_LENGTH_LIST_LENGTH(res);
1508162922Sariff
1509162922Sariff	if (w->nconns < 1)
1510162922Sariff		return;
1511162922Sariff
1512162922Sariff	entnum = HDA_PARAM_CONN_LIST_LENGTH_LONG_FORM(res) ? 2 : 4;
1513162922Sariff	res = 0;
1514162922Sariff	i = 0;
1515162922Sariff	found = 0;
1516162922Sariff	max = (sizeof(w->conns) / sizeof(w->conns[0])) - 1;
1517162922Sariff
1518162922Sariff	while (i < w->nconns) {
1519162922Sariff		res = hdac_command(sc,
1520162922Sariff		    HDA_CMD_GET_CONN_LIST_ENTRY(cad, nid, i), cad);
1521162922Sariff		for (j = 0; j < entnum; j++) {
1522162922Sariff			cnid = res;
1523162922Sariff			cnid >>= (32 / entnum) * j;
1524162922Sariff			cnid &= (1 << (32 / entnum)) - 1;
1525162922Sariff			if (cnid == 0)
1526162922Sariff				continue;
1527162922Sariff			if (found > max) {
1528162922Sariff				device_printf(sc->dev,
1529162922Sariff				    "node %d: Adding %d: "
1530162922Sariff				    "Max connection reached!\n",
1531162922Sariff				    nid, cnid);
1532162922Sariff				continue;
1533162922Sariff			}
1534162922Sariff			w->conns[found++] = cnid;
1535162922Sariff		}
1536162922Sariff		i += entnum;
1537162922Sariff	}
1538162922Sariff
1539162922Sariff	HDA_BOOTVERBOSE_MSG(
1540162922Sariff		if (w->nconns != found) {
1541162922Sariff			device_printf(sc->dev,
1542162922Sariff			    "node %d: WARNING!!! Connection "
1543162922Sariff			    "length=%d != found=%d\n",
1544162922Sariff			    nid, w->nconns, found);
1545162922Sariff		}
1546162922Sariff	);
1547162922Sariff}
1548162922Sariff
1549162922Sariffstatic uint32_t
1550162922Sariffhdac_widget_pin_getconfig(struct hdac_widget *w)
1551162922Sariff{
1552162922Sariff	struct hdac_softc *sc;
1553162922Sariff	uint32_t config, id;
1554162922Sariff	nid_t cad, nid;
1555162922Sariff
1556162922Sariff	sc = w->devinfo->codec->sc;
1557162922Sariff	cad = w->devinfo->codec->cad;
1558162922Sariff	nid = w->nid;
1559162922Sariff	id = hdac_codec_id(w->devinfo);
1560162922Sariff
1561162922Sariff	config = hdac_command(sc,
1562162922Sariff	    HDA_CMD_GET_CONFIGURATION_DEFAULT(cad, nid),
1563162922Sariff	    cad);
1564162965Sariff	/*
1565162965Sariff	 * XXX REWRITE!!!! Don't argue!
1566162965Sariff	 */
1567162922Sariff	if (id == HDA_CODEC_ALC880 &&
1568162965Sariff	    (sc->pci_subvendor == CLEVO_D900T_SUBVENDOR ||
1569162965Sariff	    sc->pci_subvendor == ASUS_M5200_SUBVENDOR)) {
1570162922Sariff		/*
1571162965Sariff		 * Super broken BIOS
1572162922Sariff		 */
1573162922Sariff		switch (nid) {
1574162922Sariff		case 20:
1575162922Sariff			break;
1576162922Sariff		case 21:
1577162922Sariff			break;
1578162922Sariff		case 22:
1579162922Sariff			break;
1580162922Sariff		case 23:
1581162922Sariff			break;
1582162922Sariff		case 24:	/* MIC1 */
1583162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1584162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
1585162922Sariff			break;
1586162922Sariff		case 25:	/* XXX MIC2 */
1587162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1588162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
1589162922Sariff			break;
1590162922Sariff		case 26:	/* LINE1 */
1591162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1592162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1593162922Sariff			break;
1594162922Sariff		case 27:	/* XXX LINE2 */
1595162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1596162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1597162922Sariff			break;
1598162922Sariff		case 28:	/* CD */
1599162922Sariff			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1600162922Sariff			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
1601162922Sariff			break;
1602162922Sariff		case 30:
1603162922Sariff			break;
1604162922Sariff		case 31:
1605162922Sariff			break;
1606162922Sariff		default:
1607162922Sariff			break;
1608162922Sariff		}
1609162922Sariff	}
1610162922Sariff
1611162922Sariff	return (config);
1612162922Sariff}
1613162922Sariff
1614162922Sariffstatic void
1615162922Sariffhdac_widget_pin_parse(struct hdac_widget *w)
1616162922Sariff{
1617162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1618162922Sariff	uint32_t config, pincap;
1619162922Sariff	char *devstr, *connstr;
1620162922Sariff	nid_t cad = w->devinfo->codec->cad;
1621162922Sariff	nid_t nid = w->nid;
1622162922Sariff
1623162922Sariff	config = hdac_widget_pin_getconfig(w);
1624162922Sariff	w->wclass.pin.config = config;
1625162922Sariff
1626162922Sariff	pincap = hdac_command(sc,
1627162922Sariff		HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_PIN_CAP), cad);
1628162922Sariff	w->wclass.pin.cap = pincap;
1629162922Sariff
1630162922Sariff	w->wclass.pin.ctrl = hdac_command(sc,
1631162922Sariff		HDA_CMD_GET_PIN_WIDGET_CTRL(cad, nid), cad) &
1632162922Sariff		~(HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
1633162922Sariff		HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
1634162922Sariff		HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE);
1635162922Sariff
1636162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
1637162922Sariff		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
1638162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
1639162922Sariff		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE;
1640162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
1641162922Sariff		w->wclass.pin.ctrl |= HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
1642162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap)) {
1643162922Sariff		w->param.eapdbtl = hdac_command(sc,
1644162922Sariff		    HDA_CMD_GET_EAPD_BTL_ENABLE(cad, nid), cad);
1645162922Sariff		w->param.eapdbtl &= 0x7;
1646162922Sariff		w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
1647162922Sariff	} else
1648162965Sariff		w->param.eapdbtl = HDAC_INVALID;
1649162922Sariff
1650162922Sariff	switch (config & HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) {
1651162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT:
1652162922Sariff		devstr = "line out";
1653162922Sariff		break;
1654162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER:
1655162922Sariff		devstr = "speaker";
1656162922Sariff		break;
1657162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT:
1658162922Sariff		devstr = "headphones out";
1659162922Sariff		break;
1660162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
1661162922Sariff		devstr = "CD";
1662162922Sariff		break;
1663162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_OUT:
1664162922Sariff		devstr = "SPDIF out";
1665162922Sariff		break;
1666162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_OUT:
1667162922Sariff		devstr = "digital (other) out";
1668162922Sariff		break;
1669162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_LINE:
1670162922Sariff		devstr = "modem, line side";
1671162922Sariff		break;
1672162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_MODEM_HANDSET:
1673162922Sariff		devstr = "modem, handset side";
1674162922Sariff		break;
1675162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
1676162922Sariff		devstr = "line in";
1677162922Sariff		break;
1678162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_AUX:
1679162922Sariff		devstr = "AUX";
1680162922Sariff		break;
1681162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
1682162922Sariff		devstr = "Mic in";
1683162922Sariff		break;
1684162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_TELEPHONY:
1685162922Sariff		devstr = "telephony";
1686162922Sariff		break;
1687162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_SPDIF_IN:
1688162922Sariff		devstr = "SPDIF in";
1689162922Sariff		break;
1690162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_DIGITAL_OTHER_IN:
1691162922Sariff		devstr = "digital (other) in";
1692162922Sariff		break;
1693162922Sariff	case HDA_CONFIG_DEFAULTCONF_DEVICE_OTHER:
1694162922Sariff		devstr = "other";
1695162922Sariff		break;
1696162922Sariff	default:
1697162922Sariff		devstr = "unknown";
1698162922Sariff		break;
1699162922Sariff	}
1700162922Sariff
1701162922Sariff	switch (config & HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) {
1702162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK:
1703162922Sariff		connstr = "jack";
1704162922Sariff		break;
1705162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE:
1706162922Sariff		connstr = "none";
1707162922Sariff		break;
1708162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED:
1709162922Sariff		connstr = "fixed";
1710162922Sariff		break;
1711162922Sariff	case HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_BOTH:
1712162922Sariff		connstr = "jack / fixed";
1713162922Sariff		break;
1714162922Sariff	default:
1715162922Sariff		connstr = "unknown";
1716162922Sariff		break;
1717162922Sariff	}
1718162922Sariff
1719162922Sariff	strlcat(w->name, ": ", sizeof(w->name));
1720162922Sariff	strlcat(w->name, devstr, sizeof(w->name));
1721162922Sariff	strlcat(w->name, " (", sizeof(w->name));
1722162922Sariff	strlcat(w->name, connstr, sizeof(w->name));
1723162922Sariff	strlcat(w->name, ")", sizeof(w->name));
1724162922Sariff}
1725162922Sariff
1726162922Sariffstatic void
1727162922Sariffhdac_widget_parse(struct hdac_widget *w)
1728162922Sariff{
1729162922Sariff	struct hdac_softc *sc = w->devinfo->codec->sc;
1730162922Sariff	uint32_t wcap, cap;
1731162922Sariff	char *typestr;
1732162922Sariff	nid_t cad = w->devinfo->codec->cad;
1733162922Sariff	nid_t nid = w->nid;
1734162922Sariff
1735162922Sariff	wcap = hdac_command(sc,
1736162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_AUDIO_WIDGET_CAP),
1737162922Sariff	    cad);
1738162922Sariff	w->param.widget_cap = wcap;
1739162922Sariff	w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE(wcap);
1740162922Sariff
1741162922Sariff	switch (w->type) {
1742162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
1743162922Sariff		typestr = "audio output";
1744162922Sariff		break;
1745162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
1746162922Sariff		typestr = "audio input";
1747162922Sariff		break;
1748162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
1749162922Sariff		typestr = "audio mixer";
1750162922Sariff		break;
1751162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
1752162922Sariff		typestr = "audio selector";
1753162922Sariff		break;
1754162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
1755162922Sariff		typestr = "pin";
1756162922Sariff		break;
1757162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_POWER_WIDGET:
1758162922Sariff		typestr = "power widget";
1759162922Sariff		break;
1760162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VOLUME_WIDGET:
1761162922Sariff		typestr = "volume widget";
1762162922Sariff		break;
1763162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET:
1764162922Sariff		typestr = "beep widget";
1765162922Sariff		break;
1766162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_VENDOR_WIDGET:
1767162922Sariff		typestr = "vendor widget";
1768162922Sariff		break;
1769162922Sariff	default:
1770162922Sariff		typestr = "unknown type";
1771162922Sariff		break;
1772162922Sariff	}
1773162922Sariff
1774162922Sariff	strlcpy(w->name, typestr, sizeof(w->name));
1775162922Sariff
1776162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_POWER_CTRL(wcap)) {
1777162922Sariff		hdac_command(sc,
1778162922Sariff		    HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0),
1779162922Sariff		    cad);
1780162922Sariff		DELAY(1000);
1781162922Sariff	}
1782162922Sariff
1783162922Sariff	hdac_widget_connection_parse(w);
1784162922Sariff
1785162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(wcap)) {
1786162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
1787162922Sariff			w->param.outamp_cap =
1788162922Sariff			    hdac_command(sc,
1789162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
1790162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP), cad);
1791162922Sariff		else
1792162922Sariff			w->param.outamp_cap =
1793162922Sariff			    w->devinfo->function.audio.outamp_cap;
1794162922Sariff	} else
1795162922Sariff		w->param.outamp_cap = 0;
1796162922Sariff
1797162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(wcap)) {
1798162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_AMP_OVR(wcap))
1799162922Sariff			w->param.inamp_cap =
1800162922Sariff			    hdac_command(sc,
1801162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
1802162922Sariff			    HDA_PARAM_INPUT_AMP_CAP), cad);
1803162922Sariff		else
1804162922Sariff			w->param.inamp_cap =
1805162922Sariff			    w->devinfo->function.audio.inamp_cap;
1806162922Sariff	} else
1807162922Sariff		w->param.inamp_cap = 0;
1808162922Sariff
1809162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
1810162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
1811162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_FORMAT_OVR(wcap)) {
1812162922Sariff			cap = hdac_command(sc,
1813162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
1814162922Sariff			    HDA_PARAM_SUPP_STREAM_FORMATS), cad);
1815162922Sariff			w->param.supp_stream_formats = (cap != 0) ? cap :
1816162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
1817162922Sariff			cap = hdac_command(sc,
1818162922Sariff			    HDA_CMD_GET_PARAMETER(cad, nid,
1819162922Sariff			    HDA_PARAM_SUPP_PCM_SIZE_RATE), cad);
1820162922Sariff			w->param.supp_pcm_size_rate = (cap != 0) ? cap :
1821162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
1822162922Sariff		} else {
1823162922Sariff			w->param.supp_stream_formats =
1824162922Sariff			    w->devinfo->function.audio.supp_stream_formats;
1825162922Sariff			w->param.supp_pcm_size_rate =
1826162922Sariff			    w->devinfo->function.audio.supp_pcm_size_rate;
1827162922Sariff		}
1828162922Sariff	} else {
1829162922Sariff		w->param.supp_stream_formats = 0;
1830162922Sariff		w->param.supp_pcm_size_rate = 0;
1831162922Sariff	}
1832162922Sariff
1833162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
1834162922Sariff		hdac_widget_pin_parse(w);
1835162922Sariff}
1836162922Sariff
1837162922Sariffstatic struct hdac_widget *
1838162922Sariffhdac_widget_get(struct hdac_devinfo *devinfo, nid_t nid)
1839162922Sariff{
1840162922Sariff	if (devinfo == NULL || devinfo->widget == NULL ||
1841162922Sariff		    nid < devinfo->startnode || nid >= devinfo->endnode)
1842162922Sariff		return (NULL);
1843162922Sariff	return (&devinfo->widget[nid - devinfo->startnode]);
1844162922Sariff}
1845162922Sariff
1846162922Sariffstatic void
1847162922Sariffhdac_stream_stop(struct hdac_chan *ch)
1848162922Sariff{
1849162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
1850162922Sariff	uint32_t ctl;
1851162922Sariff
1852162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
1853162922Sariff	ctl &= ~(HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
1854162922Sariff	    HDAC_SDCTL_RUN);
1855162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
1856162922Sariff
1857162922Sariff	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
1858162922Sariff	ctl &= ~(1 << (ch->off >> 5));
1859162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
1860162922Sariff}
1861162922Sariff
1862162922Sariffstatic void
1863162922Sariffhdac_stream_start(struct hdac_chan *ch)
1864162922Sariff{
1865162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
1866162922Sariff	uint32_t ctl;
1867162922Sariff
1868162922Sariff	ctl = HDAC_READ_4(&sc->mem, HDAC_INTCTL);
1869162922Sariff	ctl |= 1 << (ch->off >> 5);
1870162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, ctl);
1871162922Sariff
1872162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
1873162922Sariff	ctl |= HDAC_SDCTL_IOCE | HDAC_SDCTL_FEIE | HDAC_SDCTL_DEIE |
1874162922Sariff	    HDAC_SDCTL_RUN;
1875162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
1876162922Sariff}
1877162922Sariff
1878162922Sariffstatic void
1879162922Sariffhdac_stream_reset(struct hdac_chan *ch)
1880162922Sariff{
1881162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
1882162922Sariff	int timeout = 1000;
1883162922Sariff	int to = timeout;
1884162922Sariff	uint32_t ctl;
1885162922Sariff
1886162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
1887162922Sariff	ctl |= HDAC_SDCTL_SRST;
1888162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
1889162922Sariff	do {
1890162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
1891162922Sariff		if (ctl & HDAC_SDCTL_SRST)
1892162922Sariff			break;
1893162922Sariff		DELAY(10);
1894162922Sariff	} while (--to);
1895162922Sariff	if (!(ctl & HDAC_SDCTL_SRST)) {
1896162922Sariff		device_printf(sc->dev, "timeout in reset\n");
1897162922Sariff	}
1898162922Sariff	ctl &= ~HDAC_SDCTL_SRST;
1899162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL0, ctl);
1900162922Sariff	to = timeout;
1901162922Sariff	do {
1902162922Sariff		ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL0);
1903162922Sariff		if (!(ctl & HDAC_SDCTL_SRST))
1904162922Sariff			break;
1905162922Sariff		DELAY(10);
1906162922Sariff	} while (--to);
1907162922Sariff	if ((ctl & HDAC_SDCTL_SRST))
1908162922Sariff		device_printf(sc->dev, "can't reset!\n");
1909162922Sariff}
1910162922Sariff
1911162922Sariffstatic void
1912162922Sariffhdac_stream_setid(struct hdac_chan *ch)
1913162922Sariff{
1914162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
1915162922Sariff	uint32_t ctl;
1916162922Sariff
1917162922Sariff	ctl = HDAC_READ_1(&sc->mem, ch->off + HDAC_SDCTL2);
1918162922Sariff	ctl &= ~HDAC_SDCTL2_STRM_MASK;
1919162922Sariff	ctl |= ch->sid << HDAC_SDCTL2_STRM_SHIFT;
1920162922Sariff	HDAC_WRITE_1(&sc->mem, ch->off + HDAC_SDCTL2, ctl);
1921162922Sariff}
1922162922Sariff
1923162922Sariffstatic void
1924162922Sariffhdac_bdl_setup(struct hdac_chan *ch)
1925162922Sariff{
1926162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
1927162922Sariff	uint64_t addr;
1928162922Sariff	int blks, size, blocksize;
1929162922Sariff	struct hdac_bdle *bdle;
1930162922Sariff	int i;
1931162922Sariff
1932162922Sariff	addr = (uint64_t)sndbuf_getbufaddr(ch->b);
1933162922Sariff	size = sndbuf_getsize(ch->b);
1934162922Sariff	blocksize = sndbuf_getblksz(ch->b);
1935162922Sariff	blks = size / blocksize;
1936162922Sariff	bdle = (struct hdac_bdle*)ch->bdl_dma.dma_vaddr;
1937162922Sariff
1938162922Sariff	for (i = 0; i < blks; i++, bdle++) {
1939162922Sariff		bdle->addrl = (uint32_t)addr;
1940162922Sariff		bdle->addrh = (uint32_t)(addr >> 32);
1941162922Sariff		bdle->len = blocksize;
1942162922Sariff		bdle->ioc = 1;
1943162922Sariff
1944162922Sariff		addr += blocksize;
1945162922Sariff	}
1946162922Sariff
1947162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDCBL, size);
1948162922Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDLVI, blks - 1);
1949162922Sariff	addr = ch->bdl_dma.dma_paddr;
1950162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPL, (uint32_t)addr);
1951162922Sariff	HDAC_WRITE_4(&sc->mem, ch->off + HDAC_SDBDPU, (uint32_t)(addr >> 32));
1952162922Sariff}
1953162922Sariff
1954162922Sariffstatic int
1955162922Sariffhdac_bdl_alloc(struct hdac_chan *ch)
1956162922Sariff{
1957162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
1958162922Sariff	int rc;
1959162922Sariff
1960162922Sariff	rc = hdac_dma_alloc(sc, &ch->bdl_dma,
1961162922Sariff	    sizeof(struct hdac_bdle) * HDA_BDL_MAX);
1962162922Sariff	if (rc) {
1963162922Sariff		device_printf(sc->dev, "can't alloc bdl\n");
1964162922Sariff		return (rc);
1965162922Sariff	}
1966162922Sariff	hdac_dma_nocache(ch->bdl_dma.dma_vaddr);
1967162922Sariff
1968162922Sariff	return (0);
1969162922Sariff}
1970162922Sariff
1971162922Sariffstatic void
1972162922Sariffhdac_audio_ctl_amp_set_internal(struct hdac_softc *sc, nid_t cad, nid_t nid,
1973162922Sariff					int index, int lmute, int rmute,
1974162922Sariff					int left, int right, int dir)
1975162922Sariff{
1976162922Sariff	uint16_t v = 0;
1977162922Sariff
1978162922Sariff	if (sc == NULL)
1979162922Sariff		return;
1980162922Sariff
1981162922Sariff	if (left != right || lmute != rmute) {
1982162922Sariff		v = (1 << (15 - dir)) | (1 << 13) | (index << 8) |
1983162922Sariff		    (lmute << 7) | left;
1984162922Sariff		hdac_command(sc,
1985162922Sariff			HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
1986162922Sariff		v = (1 << (15 - dir)) | (1 << 12) | (index << 8) |
1987162922Sariff		    (rmute << 7) | right;
1988162922Sariff	} else
1989162922Sariff		v = (1 << (15 - dir)) | (3 << 12) | (index << 8) |
1990162922Sariff		    (lmute << 7) | left;
1991162922Sariff
1992162922Sariff	hdac_command(sc,
1993162922Sariff	    HDA_CMD_SET_AMP_GAIN_MUTE(cad, nid, v), cad);
1994162922Sariff}
1995162922Sariff
1996162922Sariffstatic void
1997162922Sariffhdac_audio_ctl_amp_set(struct hdac_audio_ctl *ctl, uint32_t mute,
1998162922Sariff						int left, int right)
1999162922Sariff{
2000162922Sariff	struct hdac_softc *sc;
2001162922Sariff	nid_t nid, cad;
2002162922Sariff	int lmute, rmute;
2003162922Sariff
2004162922Sariff	if (ctl == NULL || ctl->widget == NULL ||
2005162922Sariff	    ctl->widget->devinfo == NULL ||
2006162922Sariff	    ctl->widget->devinfo->codec == NULL ||
2007162922Sariff	    ctl->widget->devinfo->codec->sc == NULL)
2008162922Sariff		return;
2009162922Sariff
2010162922Sariff	sc = ctl->widget->devinfo->codec->sc;
2011162922Sariff	cad = ctl->widget->devinfo->codec->cad;
2012162922Sariff	nid = ctl->widget->nid;
2013162922Sariff
2014162922Sariff	if (mute == HDA_AMP_MUTE_DEFAULT) {
2015162922Sariff		lmute = HDA_AMP_LEFT_MUTED(ctl->muted);
2016162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(ctl->muted);
2017162922Sariff	} else {
2018162922Sariff		lmute = HDA_AMP_LEFT_MUTED(mute);
2019162922Sariff		rmute = HDA_AMP_RIGHT_MUTED(mute);
2020162922Sariff	}
2021162922Sariff
2022162922Sariff	if (ctl->dir & HDA_CTL_OUT)
2023162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2024162922Sariff		    lmute, rmute, left, right, 0);
2025162922Sariff	if (ctl->dir & HDA_CTL_IN)
2026162922Sariff		hdac_audio_ctl_amp_set_internal(sc, cad, nid, ctl->index,
2027162922Sariff		    lmute, rmute, left, right, 1);
2028162922Sariff	ctl->left = left;
2029162922Sariff	ctl->right = right;
2030162922Sariff}
2031162922Sariff
2032162922Sariffstatic void
2033162922Sariffhdac_widget_connection_select(struct hdac_widget *w, uint8_t index)
2034162922Sariff{
2035162922Sariff	if (w == NULL || w->nconns < 1 || index > (w->nconns - 1))
2036162922Sariff		return;
2037162922Sariff	hdac_command(w->devinfo->codec->sc,
2038162922Sariff	    HDA_CMD_SET_CONNECTION_SELECT_CONTROL(w->devinfo->codec->cad,
2039162922Sariff	    w->nid, index), w->devinfo->codec->cad);
2040162922Sariff	w->selconn = index;
2041162922Sariff}
2042162922Sariff
2043162922Sariff
2044162922Sariff/****************************************************************************
2045162922Sariff * uint32_t hdac_command_sendone_internal
2046162922Sariff *
2047162922Sariff * Wrapper function that sends only one command to a given codec
2048162922Sariff ****************************************************************************/
2049162922Sariffstatic uint32_t
2050162922Sariffhdac_command_sendone_internal(struct hdac_softc *sc, uint32_t verb, nid_t cad)
2051162922Sariff{
2052162922Sariff	struct hdac_command_list cl;
2053162965Sariff	uint32_t response = HDAC_INVALID;
2054162922Sariff
2055162922Sariff	if (!mtx_owned(sc->lock))
2056162922Sariff		device_printf(sc->dev, "WARNING!!!! mtx not owned!!!!\n");
2057162922Sariff	cl.num_commands = 1;
2058162922Sariff	cl.verbs = &verb;
2059162922Sariff	cl.responses = &response;
2060162922Sariff
2061162922Sariff	hdac_command_send_internal(sc, &cl, cad);
2062162922Sariff
2063162922Sariff	return (response);
2064162922Sariff}
2065162922Sariff
2066162922Sariff/****************************************************************************
2067162922Sariff * hdac_command_send_internal
2068162922Sariff *
2069162922Sariff * Send a command list to the codec via the corb. We queue as much verbs as
2070162922Sariff * we can and msleep on the codec. When the interrupt get the responses
2071162922Sariff * back from the rirb, it will wake us up so we can queue the remaining verbs
2072162922Sariff * if any.
2073162922Sariff ****************************************************************************/
2074162922Sariffstatic void
2075162922Sariffhdac_command_send_internal(struct hdac_softc *sc,
2076162922Sariff			struct hdac_command_list *commands, nid_t cad)
2077162922Sariff{
2078162922Sariff	struct hdac_codec *codec;
2079162922Sariff	int corbrp;
2080162922Sariff	uint32_t *corb;
2081162922Sariff	uint8_t rirbwp;
2082162922Sariff	int timeout;
2083162922Sariff	int retry = 10;
2084162922Sariff	struct hdac_rirb *rirb_base, *rirb;
2085162922Sariff	nid_t ucad;
2086162922Sariff	uint32_t utag;
2087162922Sariff
2088162922Sariff	if (sc == NULL || sc->codecs[cad] == NULL || commands == NULL)
2089162922Sariff		return;
2090162922Sariff
2091162922Sariff	codec = sc->codecs[cad];
2092162922Sariff	codec->commands = commands;
2093162922Sariff	codec->responses_received = 0;
2094162922Sariff	codec->verbs_sent = 0;
2095162922Sariff	corb = (uint32_t *)sc->corb_dma.dma_vaddr;
2096162922Sariff	rirb_base = (struct hdac_rirb *)sc->rirb_dma.dma_vaddr;
2097162922Sariff
2098162922Sariff	do {
2099162922Sariff		if (codec->verbs_sent != commands->num_commands) {
2100162922Sariff			/* Queue as many verbs as possible */
2101162922Sariff			corbrp = HDAC_READ_2(&sc->mem, HDAC_CORBRP);
2102162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
2103162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_PREWRITE);
2104162922Sariff			while (codec->verbs_sent != commands->num_commands &&
2105162922Sariff			    ((sc->corb_wp + 1) % sc->corb_size) != corbrp) {
2106162922Sariff				sc->corb_wp++;
2107162922Sariff				sc->corb_wp %= sc->corb_size;
2108162922Sariff				corb[sc->corb_wp] =
2109162922Sariff				    commands->verbs[codec->verbs_sent++];
2110162922Sariff			}
2111162922Sariff
2112162922Sariff			/* Send the verbs to the codecs */
2113162922Sariff			bus_dmamap_sync(sc->corb_dma.dma_tag,
2114162922Sariff			    sc->corb_dma.dma_map, BUS_DMASYNC_POSTWRITE);
2115162922Sariff			HDAC_WRITE_2(&sc->mem, HDAC_CORBWP, sc->corb_wp);
2116162922Sariff		}
2117162922Sariff
2118162922Sariff		timeout = 1000;
2119162922Sariff		do {
2120162922Sariff			rirbwp = HDAC_READ_1(&sc->mem, HDAC_RIRBWP);
2121162922Sariff			bus_dmamap_sync(sc->rirb_dma.dma_tag, sc->rirb_dma.dma_map,
2122162922Sariff			    BUS_DMASYNC_POSTREAD);
2123162922Sariff			if (sc->rirb_rp != rirbwp) {
2124162922Sariff				do {
2125162922Sariff					sc->rirb_rp++;
2126162922Sariff					sc->rirb_rp %= sc->rirb_size;
2127162922Sariff					rirb = &rirb_base[sc->rirb_rp];
2128162922Sariff					if (rirb->response_ex & HDAC_RIRB_RESPONSE_EX_UNSOLICITED) {
2129162922Sariff						ucad = HDAC_RIRB_RESPONSE_EX_SDATA_IN(rirb->response_ex);
2130162922Sariff						utag = rirb->response >> 26;
2131162922Sariff						if (ucad > -1 && ucad < HDAC_CODEC_MAX &&
2132162922Sariff						    sc->codecs[ucad] != NULL) {
2133162922Sariff							sc->unsolq[sc->unsolq_wp++] =
2134162922Sariff							    (ucad << 16) |
2135162922Sariff							    (utag & 0xffff);
2136162922Sariff							sc->unsolq_wp %= HDAC_UNSOLQ_MAX;
2137162922Sariff						}
2138162922Sariff					} else if (codec->responses_received < commands->num_commands)
2139162922Sariff						codec->commands->responses[codec->responses_received++] =
2140162922Sariff						    rirb->response;
2141162922Sariff				} while (sc->rirb_rp != rirbwp);
2142162922Sariff				break;
2143162922Sariff			}
2144162922Sariff			DELAY(10);
2145162922Sariff		} while (--timeout);
2146162922Sariff	} while ((codec->verbs_sent != commands->num_commands ||
2147162922Sariff	    	codec->responses_received != commands->num_commands) &&
2148162922Sariff		--retry);
2149162922Sariff
2150162922Sariff	if (retry == 0)
2151162922Sariff		device_printf(sc->dev,
2152162922Sariff			"%s: TIMEOUT numcmd=%d, sent=%d, received=%d\n",
2153162922Sariff			__func__, commands->num_commands,
2154162922Sariff			codec->verbs_sent, codec->responses_received);
2155162922Sariff
2156162922Sariff	codec->verbs_sent = 0;
2157162922Sariff
2158162922Sariff	if (sc->unsolq_st == HDAC_UNSOLQ_READY) {
2159162922Sariff		sc->unsolq_st = HDAC_UNSOLQ_BUSY;
2160162922Sariff		while (sc->unsolq_rp != sc->unsolq_wp) {
2161162922Sariff			ucad = sc->unsolq[sc->unsolq_rp] >> 16;
2162162922Sariff			utag = sc->unsolq[sc->unsolq_rp++] & 0xffff;
2163162922Sariff			sc->unsolq_rp %= HDAC_UNSOLQ_MAX;
2164162922Sariff			hdac_unsolicited_handler(sc->codecs[ucad], utag);
2165162922Sariff		}
2166162922Sariff		sc->unsolq_st = HDAC_UNSOLQ_READY;
2167162922Sariff	}
2168162922Sariff}
2169162922Sariff
2170162922Sariff
2171162922Sariff/****************************************************************************
2172162922Sariff * Device Methods
2173162922Sariff ****************************************************************************/
2174162922Sariff
2175162922Sariff/****************************************************************************
2176162922Sariff * int hdac_probe(device_t)
2177162922Sariff *
2178162922Sariff * Probe for the presence of an hdac. If none is found, check for a generic
2179162922Sariff * match using the subclass of the device.
2180162922Sariff ****************************************************************************/
2181162922Sariffstatic int
2182162922Sariffhdac_probe(device_t dev)
2183162922Sariff{
2184162922Sariff	int i, result;
2185162922Sariff	uint32_t model, class, subclass;
2186162922Sariff	char desc[64];
2187162922Sariff
2188162922Sariff	model = (uint32_t)pci_get_device(dev) << 16;
2189162922Sariff	model |= (uint32_t)pci_get_vendor(dev) & 0x0000ffff;
2190162922Sariff	class = pci_get_class(dev);
2191162922Sariff	subclass = pci_get_subclass(dev);
2192162922Sariff
2193162922Sariff	bzero(desc, sizeof(desc));
2194162922Sariff	result = ENXIO;
2195162922Sariff	for (i = 0; i < HDAC_DEVICES_LEN; i++) {
2196162922Sariff		if (hdac_devices[i].model == model) {
2197162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
2198162922Sariff		    	result = BUS_PROBE_DEFAULT;
2199162922Sariff			break;
2200162922Sariff		}
2201162965Sariff		if (HDA_FLAG_MATCH(hdac_devices[i].model, model) &&
2202162922Sariff		    class == PCIC_MULTIMEDIA &&
2203162922Sariff		    subclass == PCIS_MULTIMEDIA_HDA) {
2204162922Sariff		    	strlcpy(desc, hdac_devices[i].desc, sizeof(desc));
2205162922Sariff		    	result = BUS_PROBE_GENERIC;
2206162922Sariff			break;
2207162922Sariff		}
2208162922Sariff	}
2209162922Sariff	if (result == ENXIO && class == PCIC_MULTIMEDIA &&
2210162922Sariff	    subclass == PCIS_MULTIMEDIA_HDA) {
2211162922Sariff		strlcpy(desc, "Generic", sizeof(desc));
2212162922Sariff	    	result = BUS_PROBE_GENERIC;
2213162922Sariff	}
2214162922Sariff	if (result != ENXIO) {
2215162922Sariff		strlcat(desc, " High Definition Audio Controller",
2216162922Sariff		    sizeof(desc));
2217162922Sariff		device_set_desc_copy(dev, desc);
2218162922Sariff	}
2219162922Sariff
2220162922Sariff	return (result);
2221162922Sariff}
2222162922Sariff
2223162922Sariffstatic void *
2224162922Sariffhdac_channel_init(kobj_t obj, void *data, struct snd_dbuf *b,
2225162922Sariff					struct pcm_channel *c, int dir)
2226162922Sariff{
2227162922Sariff	struct hdac_devinfo *devinfo = data;
2228162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2229162922Sariff	struct hdac_chan *ch;
2230162922Sariff
2231162922Sariff	hdac_lock(sc);
2232162922Sariff	if (dir == PCMDIR_PLAY) {
2233162922Sariff		ch = &sc->play;
2234162922Sariff		ch->off = (sc->num_iss + devinfo->function.audio.playcnt) << 5;
2235162922Sariff		ch->dir = PCMDIR_PLAY;
2236162922Sariff		ch->sid = ++sc->streamcnt;
2237162922Sariff		devinfo->function.audio.playcnt++;
2238162922Sariff	} else {
2239162922Sariff		ch = &sc->rec;
2240162922Sariff		ch->off = devinfo->function.audio.reccnt << 5;
2241162922Sariff		ch->dir = PCMDIR_REC;
2242162922Sariff		ch->sid = ++sc->streamcnt;
2243162922Sariff		devinfo->function.audio.reccnt++;
2244162922Sariff	}
2245162922Sariff	if (devinfo->function.audio.quirks & HDA_QUIRK_FIXEDRATE) {
2246162922Sariff		ch->caps.minspeed = ch->caps.maxspeed = 48000;
2247162922Sariff		ch->pcmrates[0] = 48000;
2248162922Sariff		ch->pcmrates[1] = 0;
2249162922Sariff	}
2250162922Sariff	ch->b = b;
2251162922Sariff	ch->c = c;
2252162922Sariff	ch->devinfo = devinfo;
2253162922Sariff	ch->blksz = sc->chan_size / sc->chan_blkcnt;
2254162922Sariff	ch->blkcnt = sc->chan_blkcnt;
2255162922Sariff	hdac_unlock(sc);
2256162922Sariff
2257162922Sariff	if (hdac_bdl_alloc(ch) != 0) {
2258162922Sariff		ch->blkcnt = 0;
2259162922Sariff		return (NULL);
2260162922Sariff	}
2261162922Sariff
2262162922Sariff	if (sndbuf_alloc(ch->b, sc->chan_dmat, sc->chan_size) != 0)
2263162922Sariff		return (NULL);
2264162922Sariff
2265162922Sariff	hdac_dma_nocache(ch->b->buf);
2266162922Sariff
2267162922Sariff	return (ch);
2268162922Sariff}
2269162922Sariff
2270162922Sariffstatic int
2271162922Sariffhdac_channel_setformat(kobj_t obj, void *data, uint32_t format)
2272162922Sariff{
2273162922Sariff	struct hdac_chan *ch = data;
2274162922Sariff	int i;
2275162922Sariff
2276162922Sariff	for (i = 0; ch->caps.fmtlist[i] != 0; i++) {
2277162922Sariff		if (format == ch->caps.fmtlist[i]) {
2278162922Sariff			ch->fmt = format;
2279162922Sariff			return (0);
2280162922Sariff		}
2281162922Sariff	}
2282162922Sariff
2283162922Sariff	return (EINVAL);
2284162922Sariff}
2285162922Sariff
2286162922Sariffstatic int
2287162922Sariffhdac_channel_setspeed(kobj_t obj, void *data, uint32_t speed)
2288162922Sariff{
2289162922Sariff	struct hdac_chan *ch = data;
2290162922Sariff	uint32_t spd = 0;
2291162922Sariff	int i;
2292162922Sariff
2293162922Sariff	for (i = 0; ch->pcmrates[i] != 0; i++) {
2294162922Sariff		spd = ch->pcmrates[i];
2295162922Sariff		if (spd >= speed)
2296162922Sariff			break;
2297162922Sariff	}
2298162922Sariff
2299162922Sariff	if (spd == 0)
2300162922Sariff		ch->spd = 48000;
2301162922Sariff	else
2302162922Sariff		ch->spd = spd;
2303162922Sariff
2304162922Sariff	return (ch->spd);
2305162922Sariff}
2306162922Sariff
2307162922Sariffstatic void
2308162922Sariffhdac_stream_setup(struct hdac_chan *ch)
2309162922Sariff{
2310162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2311162922Sariff	int i;
2312162922Sariff	nid_t cad = ch->devinfo->codec->cad;
2313162922Sariff	uint16_t fmt;
2314162922Sariff
2315162922Sariff	/*
2316162922Sariff	 *  8bit = 0
2317162922Sariff	 * 16bit = 1
2318162922Sariff	 * 20bit = 2
2319162922Sariff	 * 24bit = 3
2320162922Sariff	 * 32bit = 4
2321162922Sariff	 */
2322162922Sariff	fmt = 0;
2323162922Sariff	if (ch->fmt & AFMT_S16_LE)
2324162922Sariff		fmt |= ch->bit16 << 4;
2325162922Sariff	else if (ch->fmt & AFMT_S32_LE)
2326162922Sariff		fmt |= ch->bit32 << 4;
2327162922Sariff	else
2328162922Sariff		fmt |= 1 << 4;
2329162922Sariff
2330162922Sariff	for (i = 0; i < HDA_RATE_TAB_LEN; i++) {
2331162922Sariff		if (hda_rate_tab[i].valid && ch->spd == hda_rate_tab[i].rate) {
2332162922Sariff			fmt |= hda_rate_tab[i].base;
2333162922Sariff			fmt |= hda_rate_tab[i].mul;
2334162922Sariff			fmt |= hda_rate_tab[i].div;
2335162922Sariff			break;
2336162922Sariff		}
2337162922Sariff	}
2338162922Sariff
2339162922Sariff	if (ch->fmt & AFMT_STEREO)
2340162922Sariff		fmt |= 1;
2341162922Sariff
2342162922Sariff	HDAC_WRITE_2(&sc->mem, ch->off + HDAC_SDFMT, fmt);
2343162922Sariff
2344162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
2345162922Sariff		HDA_BOOTVERBOSE_MSG(
2346162922Sariff			device_printf(sc->dev,
2347162922Sariff			    "PCMDIR_%s: Stream setup nid=%d fmt=0x%08x\n",
2348162922Sariff			    (ch->dir == PCMDIR_PLAY) ? "PLAY" : "REC",
2349162922Sariff			    ch->io[i], fmt);
2350162922Sariff		);
2351162922Sariff		hdac_command(sc,
2352162922Sariff		    HDA_CMD_SET_CONV_FMT(cad, ch->io[i], fmt), cad);
2353162922Sariff		hdac_command(sc,
2354162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
2355162922Sariff		    ch->sid << 4), cad);
2356162922Sariff	}
2357162922Sariff}
2358162922Sariff
2359162922Sariffstatic int
2360162922Sariffhdac_channel_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
2361162922Sariff{
2362162922Sariff	struct hdac_chan *ch = data;
2363162922Sariff
2364162922Sariff	sndbuf_resize(ch->b, ch->blkcnt, ch->blksz);
2365162922Sariff
2366162922Sariff	return (ch->blksz);
2367162922Sariff}
2368162922Sariff
2369162922Sariffstatic void
2370162922Sariffhdac_channel_stop(struct hdac_softc *sc, struct hdac_chan *ch)
2371162922Sariff{
2372162922Sariff	struct hdac_devinfo *devinfo = ch->devinfo;
2373162922Sariff	nid_t cad = devinfo->codec->cad;
2374162922Sariff	int i;
2375162922Sariff
2376162922Sariff	hdac_stream_stop(ch);
2377162922Sariff
2378162922Sariff	for (i = 0; ch->io[i] != -1; i++) {
2379162922Sariff		hdac_command(sc,
2380162922Sariff		    HDA_CMD_SET_CONV_STREAM_CHAN(cad, ch->io[i],
2381162922Sariff		    0), cad);
2382162922Sariff	}
2383162922Sariff}
2384162922Sariff
2385162922Sariffstatic void
2386162922Sariffhdac_channel_start(struct hdac_softc *sc, struct hdac_chan *ch)
2387162922Sariff{
2388162922Sariff	ch->ptr = 0;
2389162922Sariff	ch->prevptr = 0;
2390162922Sariff	hdac_stream_stop(ch);
2391162922Sariff	hdac_stream_reset(ch);
2392162922Sariff	hdac_bdl_setup(ch);
2393162922Sariff	hdac_stream_setid(ch);
2394162922Sariff	hdac_stream_setup(ch);
2395162922Sariff	hdac_stream_start(ch);
2396162922Sariff}
2397162922Sariff
2398162922Sariffstatic int
2399162922Sariffhdac_channel_trigger(kobj_t obj, void *data, int go)
2400162922Sariff{
2401162922Sariff	struct hdac_chan *ch = data;
2402162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2403162922Sariff
2404162922Sariff	hdac_lock(sc);
2405162922Sariff	switch (go) {
2406162922Sariff	case PCMTRIG_START:
2407162922Sariff		hdac_channel_start(sc, ch);
2408162922Sariff		break;
2409162922Sariff	case PCMTRIG_STOP:
2410162922Sariff	case PCMTRIG_ABORT:
2411162922Sariff		hdac_channel_stop(sc, ch);
2412162922Sariff		break;
2413162922Sariff	}
2414162922Sariff	hdac_unlock(sc);
2415162922Sariff
2416162922Sariff	return (0);
2417162922Sariff}
2418162922Sariff
2419162922Sariffstatic int
2420162922Sariffhdac_channel_getptr(kobj_t obj, void *data)
2421162922Sariff{
2422162922Sariff	struct hdac_chan *ch = data;
2423162922Sariff	struct hdac_softc *sc = ch->devinfo->codec->sc;
2424162922Sariff	int sz, delta;
2425162922Sariff	uint32_t ptr;
2426162922Sariff
2427162922Sariff	hdac_lock(sc);
2428162922Sariff	ptr = HDAC_READ_4(&sc->mem, ch->off + HDAC_SDLPIB);
2429162922Sariff	hdac_unlock(sc);
2430162922Sariff
2431162922Sariff	sz = sndbuf_getsize(ch->b);
2432162922Sariff	ptr %= sz;
2433162922Sariff
2434162922Sariff	if (ch->dir == PCMDIR_REC) {
2435162922Sariff		delta = ptr % sndbuf_getblksz(ch->b);
2436162922Sariff		if (delta != 0) {
2437162922Sariff			ptr -= delta;
2438162922Sariff			if (ptr < delta)
2439162922Sariff				ptr = sz - delta;
2440162922Sariff			else
2441162922Sariff				ptr -= delta;
2442162922Sariff		}
2443162922Sariff	}
2444162922Sariff
2445162922Sariff	return (ptr);
2446162922Sariff}
2447162922Sariff
2448162922Sariffstatic struct pcmchan_caps *
2449162922Sariffhdac_channel_getcaps(kobj_t obj, void *data)
2450162922Sariff{
2451162922Sariff	return (&((struct hdac_chan *)data)->caps);
2452162922Sariff}
2453162922Sariff
2454162922Sariffstatic kobj_method_t hdac_channel_methods[] = {
2455162922Sariff	KOBJMETHOD(channel_init,		hdac_channel_init),
2456162922Sariff	KOBJMETHOD(channel_setformat,		hdac_channel_setformat),
2457162922Sariff	KOBJMETHOD(channel_setspeed,		hdac_channel_setspeed),
2458162922Sariff	KOBJMETHOD(channel_setblocksize,	hdac_channel_setblocksize),
2459162922Sariff	KOBJMETHOD(channel_trigger,		hdac_channel_trigger),
2460162922Sariff	KOBJMETHOD(channel_getptr,		hdac_channel_getptr),
2461162922Sariff	KOBJMETHOD(channel_getcaps,		hdac_channel_getcaps),
2462162922Sariff	{ 0, 0 }
2463162922Sariff};
2464162922SariffCHANNEL_DECLARE(hdac_channel);
2465162922Sariff
2466162922Sariffstatic int
2467162922Sariffhdac_audio_ctl_ossmixer_init(struct snd_mixer *m)
2468162922Sariff{
2469162922Sariff	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
2470162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2471162922Sariff	struct hdac_widget *w, *cw;
2472162922Sariff	struct hdac_audio_ctl *ctl;
2473162922Sariff	uint32_t mask, recmask, id;
2474162922Sariff	int i, j, softpcmvol;
2475162922Sariff	nid_t cad;
2476162922Sariff
2477162922Sariff	if (resource_int_value(device_get_name(sc->dev),
2478162922Sariff	    device_get_unit(sc->dev), "softpcmvol", &softpcmvol) == 0)
2479162922Sariff		softpcmvol = (softpcmvol != 0) ? 1 : 0;
2480162922Sariff	else
2481162922Sariff		softpcmvol = (devinfo->function.audio.quirks &
2482162922Sariff		    HDA_QUIRK_SOFTPCMVOL) ?
2483162922Sariff		    1 : 0;
2484162922Sariff
2485162922Sariff	hdac_lock(sc);
2486162922Sariff
2487162922Sariff	mask = 0;
2488162922Sariff	recmask = 0;
2489162922Sariff
2490162922Sariff	id = hdac_codec_id(devinfo);
2491162922Sariff	cad = devinfo->codec->cad;
2492162922Sariff	for (i = 0; i < HDAC_HP_SWITCH_LEN; i++) {
2493162965Sariff		if (!(HDA_FLAG_MATCH(hdac_hp_switch[i].model,
2494162965Sariff		    sc->pci_subvendor) &&
2495162922Sariff		    hdac_hp_switch[i].id == id))
2496162922Sariff			continue;
2497162922Sariff		w = hdac_widget_get(devinfo, hdac_hp_switch[i].hpnid);
2498162922Sariff		if (w != NULL && w->enable != 0
2499162922Sariff		    && w->type ==
2500162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
2501162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(w->param.widget_cap)) {
2502162922Sariff			hdac_command(sc,
2503162922Sariff			    HDA_CMD_SET_UNSOLICITED_RESPONSE(cad,
2504162922Sariff			    w->nid,
2505162922Sariff			    HDA_CMD_SET_UNSOLICITED_RESPONSE_ENABLE|
2506162922Sariff			    HDAC_UNSOLTAG_EVENT_HP), cad);
2507162922Sariff			hdac_hp_switch_handler(devinfo);
2508162922Sariff		}
2509162922Sariff		break;
2510162922Sariff	}
2511162922Sariff	for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
2512162965Sariff		if (!(HDA_FLAG_MATCH(hdac_eapd_switch[i].model,
2513162965Sariff		    sc->pci_subvendor) &&
2514162965Sariff		    hdac_eapd_switch[i].id == id))
2515162922Sariff			continue;
2516162922Sariff		w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
2517162922Sariff		if (w == NULL || w->enable == 0)
2518162922Sariff			break;
2519162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
2520162965Sariff		    w->param.eapdbtl == HDAC_INVALID)
2521162922Sariff			break;
2522162922Sariff		mask |= SOUND_MASK_OGAIN;
2523162922Sariff		break;
2524162922Sariff	}
2525162922Sariff
2526162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
2527162922Sariff		w = hdac_widget_get(devinfo, i);
2528162922Sariff		if (w == NULL || w->enable == 0)
2529162922Sariff			continue;
2530162922Sariff		mask |= w->ctlflags;
2531162922Sariff		if (!(w->pflags & HDA_ADC_RECSEL))
2532162922Sariff			continue;
2533162922Sariff		for (j = 0; j < w->nconns; j++) {
2534162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
2535162922Sariff			if (cw == NULL || cw->enable == 0)
2536162922Sariff				continue;
2537162922Sariff			recmask |= cw->ctlflags;
2538162922Sariff		}
2539162922Sariff	}
2540162922Sariff
2541162922Sariff	if (!(mask & SOUND_MASK_PCM)) {
2542162922Sariff		softpcmvol = 1;
2543162922Sariff		mask |= SOUND_MASK_PCM;
2544162922Sariff	}
2545162922Sariff
2546162922Sariff	i = 0;
2547162922Sariff	ctl = NULL;
2548162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
2549162922Sariff		if (ctl->widget == NULL || ctl->enable == 0)
2550162922Sariff			continue;
2551162922Sariff		if (!(ctl->ossmask & SOUND_MASK_PCM))
2552162922Sariff			continue;
2553162922Sariff		if (ctl->step > 0)
2554162922Sariff			break;
2555162922Sariff	}
2556162922Sariff
2557162922Sariff	if (softpcmvol == 1 || ctl == NULL) {
2558162922Sariff		struct snddev_info *d = NULL;
2559162922Sariff		d = device_get_softc(sc->dev);
2560162922Sariff		if (d != NULL) {
2561162922Sariff			d->flags |= SD_F_SOFTPCMVOL;
2562162922Sariff			HDA_BOOTVERBOSE_MSG(
2563162922Sariff				device_printf(sc->dev,
2564162922Sariff				    "%s Soft PCM volume\n",
2565162922Sariff				    (softpcmvol == 1) ?
2566162922Sariff				    "Forcing" : "Enabling");
2567162922Sariff			);
2568162922Sariff		}
2569162922Sariff		i = 0;
2570162922Sariff		/*
2571162922Sariff		 * XXX Temporary quirk for STAC9220, until the parser
2572162922Sariff		 *     become smarter.
2573162922Sariff		 */
2574162922Sariff		if (id == HDA_CODEC_STAC9220) {
2575162922Sariff			mask |= SOUND_MASK_VOLUME;
2576162922Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
2577162922Sariff			    NULL) {
2578162922Sariff				if (ctl->widget == NULL || ctl->enable == 0)
2579162922Sariff					continue;
2580162922Sariff				if (ctl->widget->nid == 11 && ctl->index == 0) {
2581162922Sariff					ctl->ossmask = SOUND_MASK_VOLUME;
2582162922Sariff					ctl->ossval = 100 | (100 << 8);
2583162922Sariff				} else
2584162922Sariff					ctl->ossmask &= ~SOUND_MASK_VOLUME;
2585162922Sariff			}
2586162922Sariff		} else {
2587162922Sariff			mix_setparentchild(m, SOUND_MIXER_VOLUME,
2588162922Sariff			    SOUND_MASK_PCM);
2589162922Sariff			if (!(mask & SOUND_MASK_VOLUME))
2590162922Sariff				mix_setrealdev(m, SOUND_MIXER_VOLUME,
2591162922Sariff				    SOUND_MIXER_NONE);
2592162922Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &i)) !=
2593162922Sariff			    NULL) {
2594162922Sariff				if (ctl->widget == NULL || ctl->enable == 0)
2595162922Sariff					continue;
2596162922Sariff				if ((ctl->ossmask & (SOUND_MASK_VOLUME |
2597162922Sariff				    SOUND_MASK_PCM)) != (SOUND_MASK_VOLUME |
2598162922Sariff				    SOUND_MASK_PCM))
2599162922Sariff					continue;
2600162922Sariff				if (!(ctl->mute == 1 && ctl->step == 0))
2601162922Sariff					ctl->enable = 0;
2602162922Sariff			}
2603162922Sariff		}
2604162922Sariff	}
2605162922Sariff
2606162922Sariff	recmask &= ~(SOUND_MASK_PCM | SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER);
2607162922Sariff
2608162922Sariff	mix_setrecdevs(m, recmask);
2609162922Sariff	mix_setdevs(m, mask);
2610162922Sariff
2611162922Sariff	hdac_unlock(sc);
2612162922Sariff
2613162922Sariff	return (0);
2614162922Sariff}
2615162922Sariff
2616162922Sariffstatic int
2617162922Sariffhdac_audio_ctl_ossmixer_set(struct snd_mixer *m, unsigned dev,
2618162922Sariff					unsigned left, unsigned right)
2619162922Sariff{
2620162922Sariff	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
2621162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2622162922Sariff	struct hdac_widget *w;
2623162922Sariff	struct hdac_audio_ctl *ctl;
2624162922Sariff	uint32_t id, mute;
2625162922Sariff	int lvol, rvol, mlvol, mrvol;
2626162922Sariff	int i = 0;
2627162922Sariff
2628162922Sariff	hdac_lock(sc);
2629162922Sariff	if (dev == SOUND_MIXER_OGAIN) {
2630162922Sariff		/*if (left != right || !(left == 0 || left == 1)) {
2631162922Sariff			hdac_unlock(sc);
2632162922Sariff			return (-1);
2633162922Sariff		}*/
2634162922Sariff		id = hdac_codec_id(devinfo);
2635162922Sariff		for (i = 0; i < HDAC_EAPD_SWITCH_LEN; i++) {
2636162965Sariff			if (HDA_FLAG_MATCH(hdac_eapd_switch[i].model,
2637162965Sariff			    sc->pci_subvendor) &&
2638162922Sariff			    hdac_eapd_switch[i].id == id)
2639162922Sariff				break;
2640162922Sariff		}
2641162922Sariff		if (i >= HDAC_EAPD_SWITCH_LEN) {
2642162922Sariff			hdac_unlock(sc);
2643162922Sariff			return (-1);
2644162922Sariff		}
2645162922Sariff		w = hdac_widget_get(devinfo, hdac_eapd_switch[i].eapdnid);
2646162922Sariff		if (w == NULL ||
2647162922Sariff		    w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX ||
2648162965Sariff		    w->param.eapdbtl == HDAC_INVALID) {
2649162922Sariff			hdac_unlock(sc);
2650162922Sariff			return (-1);
2651162922Sariff		}
2652162922Sariff		if (left == 0)
2653162922Sariff			w->param.eapdbtl &= ~HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
2654162922Sariff		else
2655162922Sariff			w->param.eapdbtl |= HDA_CMD_SET_EAPD_BTL_ENABLE_EAPD;
2656162922Sariff		if (hdac_eapd_switch[i].hp_switch != 0)
2657162922Sariff			hdac_hp_switch_handler(devinfo);
2658162922Sariff		hdac_command(sc,
2659162922Sariff		    HDA_CMD_SET_EAPD_BTL_ENABLE(devinfo->codec->cad, w->nid,
2660162922Sariff		    w->param.eapdbtl), devinfo->codec->cad);
2661162922Sariff		hdac_unlock(sc);
2662162922Sariff		return (left | (left << 8));
2663162922Sariff	}
2664162922Sariff	if (dev == SOUND_MIXER_VOLUME)
2665162922Sariff		devinfo->function.audio.mvol = left | (right << 8);
2666162922Sariff
2667162922Sariff	mlvol = devinfo->function.audio.mvol & 0x7f;
2668162922Sariff	mrvol = (devinfo->function.audio.mvol >> 8) & 0x7f;
2669162922Sariff	lvol = 0;
2670162922Sariff	rvol = 0;
2671162922Sariff
2672162922Sariff	i = 0;
2673162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
2674162922Sariff		if (ctl->widget == NULL || ctl->enable == 0 ||
2675162922Sariff		    !(ctl->ossmask & (1 << dev)))
2676162922Sariff			continue;
2677162922Sariff		switch (dev) {
2678162922Sariff		case SOUND_MIXER_VOLUME:
2679162922Sariff			lvol = ((ctl->ossval & 0x7f) * left) / 100;
2680162922Sariff			lvol = (lvol * ctl->step) / 100;
2681162922Sariff			rvol = (((ctl->ossval >> 8) & 0x7f) * right) / 100;
2682162922Sariff			rvol = (rvol * ctl->step) / 100;
2683162922Sariff			break;
2684162922Sariff		default:
2685162922Sariff			if (ctl->ossmask & SOUND_MASK_VOLUME) {
2686162922Sariff				lvol = (left * mlvol) / 100;
2687162922Sariff				lvol = (lvol * ctl->step) / 100;
2688162922Sariff				rvol = (right * mrvol) / 100;
2689162922Sariff				rvol = (rvol * ctl->step) / 100;
2690162922Sariff			} else {
2691162922Sariff				lvol = (left * ctl->step) / 100;
2692162922Sariff				rvol = (right * ctl->step) / 100;
2693162922Sariff			}
2694162922Sariff			ctl->ossval = left | (right << 8);
2695162922Sariff			break;
2696162922Sariff		}
2697162922Sariff		mute = 0;
2698162922Sariff		if (ctl->step < 1) {
2699162922Sariff			mute |= (left == 0) ? HDA_AMP_MUTE_LEFT :
2700162922Sariff			    (ctl->muted & HDA_AMP_MUTE_LEFT);
2701162922Sariff			mute |= (right == 0) ? HDA_AMP_MUTE_RIGHT :
2702162922Sariff			    (ctl->muted & HDA_AMP_MUTE_RIGHT);
2703162922Sariff		} else {
2704162922Sariff			mute |= (lvol == 0) ? HDA_AMP_MUTE_LEFT :
2705162922Sariff			    (ctl->muted & HDA_AMP_MUTE_LEFT);
2706162922Sariff			mute |= (rvol == 0) ? HDA_AMP_MUTE_RIGHT :
2707162922Sariff			    (ctl->muted & HDA_AMP_MUTE_RIGHT);
2708162922Sariff		}
2709162922Sariff		hdac_audio_ctl_amp_set(ctl, mute, lvol, rvol);
2710162922Sariff	}
2711162922Sariff	hdac_unlock(sc);
2712162922Sariff
2713162922Sariff	return (left | (right << 8));
2714162922Sariff}
2715162922Sariff
2716162922Sariffstatic int
2717162922Sariffhdac_audio_ctl_ossmixer_setrecsrc(struct snd_mixer *m, uint32_t src)
2718162922Sariff{
2719162922Sariff	struct hdac_devinfo *devinfo = mix_getdevinfo(m);
2720162922Sariff	struct hdac_widget *w, *cw;
2721162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2722162922Sariff	uint32_t ret = src, target;
2723162922Sariff	int i, j;
2724162922Sariff
2725162922Sariff	target = 0;
2726162922Sariff	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
2727162922Sariff		if (src & (1 << i)) {
2728162922Sariff			target = 1 << i;
2729162922Sariff			break;
2730162922Sariff		}
2731162922Sariff	}
2732162922Sariff
2733162922Sariff	hdac_lock(sc);
2734162922Sariff
2735162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
2736162922Sariff		w = hdac_widget_get(devinfo, i);
2737162965Sariff		if (w == NULL || w->enable == 0)
2738162922Sariff			continue;
2739162922Sariff		if (!(w->pflags & HDA_ADC_RECSEL))
2740162922Sariff			continue;
2741162922Sariff		for (j = 0; j < w->nconns; j++) {
2742162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
2743162922Sariff			if (cw == NULL || cw->enable == 0)
2744162922Sariff				continue;
2745162922Sariff			if ((target == SOUND_MASK_VOLUME &&
2746162922Sariff			    cw->type !=
2747162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER) ||
2748162922Sariff			    (target != SOUND_MASK_VOLUME &&
2749162922Sariff			    cw->type ==
2750162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER))
2751162922Sariff				continue;
2752162922Sariff			if (cw->ctlflags & target) {
2753162922Sariff				hdac_widget_connection_select(w, j);
2754162922Sariff				ret = target;
2755162922Sariff				j += w->nconns;
2756162922Sariff			}
2757162922Sariff		}
2758162922Sariff	}
2759162922Sariff
2760162922Sariff	hdac_unlock(sc);
2761162922Sariff
2762162922Sariff	return (ret);
2763162922Sariff}
2764162922Sariff
2765162922Sariffstatic kobj_method_t hdac_audio_ctl_ossmixer_methods[] = {
2766162922Sariff	KOBJMETHOD(mixer_init,		hdac_audio_ctl_ossmixer_init),
2767162922Sariff	KOBJMETHOD(mixer_set,		hdac_audio_ctl_ossmixer_set),
2768162922Sariff	KOBJMETHOD(mixer_setrecsrc,	hdac_audio_ctl_ossmixer_setrecsrc),
2769162922Sariff	{ 0, 0 }
2770162922Sariff};
2771162922SariffMIXER_DECLARE(hdac_audio_ctl_ossmixer);
2772162922Sariff
2773162922Sariff/****************************************************************************
2774162922Sariff * int hdac_attach(device_t)
2775162922Sariff *
2776162922Sariff * Attach the device into the kernel. Interrupts usually won't be enabled
2777162922Sariff * when this function is called. Setup everything that doesn't require
2778162922Sariff * interrupts and defer probing of codecs until interrupts are enabled.
2779162922Sariff ****************************************************************************/
2780162922Sariffstatic int
2781162922Sariffhdac_attach(device_t dev)
2782162922Sariff{
2783162922Sariff	struct hdac_softc *sc;
2784162922Sariff	int result;
2785162922Sariff	int i = 0;
2786162922Sariff
2787162922Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO);
2788162922Sariff	if (sc == NULL) {
2789162922Sariff		device_printf(dev, "cannot allocate softc\n");
2790162922Sariff		return (ENOMEM);
2791162922Sariff	}
2792162922Sariff	sc->dev = dev;
2793162922Sariff	sc->pci_subvendor = pci_get_subdevice(sc->dev) << 16;
2794162922Sariff	sc->pci_subvendor |= pci_get_subvendor(sc->dev);
2795162922Sariff
2796162922Sariff	sc->chan_size = pcm_getbuffersize(dev,
2797162922Sariff	    HDA_BUFSZ_MIN, HDA_BUFSZ_DEFAULT, HDA_BUFSZ_DEFAULT);
2798162922Sariff	if (resource_int_value(device_get_name(sc->dev),
2799162922Sariff	    device_get_unit(sc->dev), "blocksize", &i) == 0 &&
2800162922Sariff	    i > 0) {
2801162922Sariff		sc->chan_blkcnt = sc->chan_size / i;
2802162922Sariff		i = 0;
2803162922Sariff		while (sc->chan_blkcnt >> i)
2804162922Sariff			i++;
2805162922Sariff		sc->chan_blkcnt = 1 << (i - 1);
2806162922Sariff		if (sc->chan_blkcnt < HDA_BDL_MIN)
2807162922Sariff			sc->chan_blkcnt = HDA_BDL_MIN;
2808162922Sariff		else if (sc->chan_blkcnt > HDA_BDL_MAX)
2809162922Sariff			sc->chan_blkcnt = HDA_BDL_MAX;
2810162922Sariff	} else
2811162922Sariff		sc->chan_blkcnt = HDA_BDL_DEFAULT;
2812162922Sariff
2813162922Sariff	result = bus_dma_tag_create(NULL,	/* parent */
2814162922Sariff	    HDAC_DMA_ALIGNMENT,			/* alignment */
2815162922Sariff	    0,					/* boundary */
2816162922Sariff	    BUS_SPACE_MAXADDR_32BIT,		/* lowaddr */
2817162922Sariff	    BUS_SPACE_MAXADDR,			/* highaddr */
2818162922Sariff	    NULL,				/* filtfunc */
2819162922Sariff	    NULL,				/* fistfuncarg */
2820162922Sariff	    sc->chan_size, 				/* maxsize */
2821162922Sariff	    1,					/* nsegments */
2822162922Sariff	    sc->chan_size, 				/* maxsegsz */
2823162922Sariff	    0,					/* flags */
2824162922Sariff	    NULL,				/* lockfunc */
2825162922Sariff	    NULL,				/* lockfuncarg */
2826162922Sariff	    &sc->chan_dmat);			/* dmat */
2827162922Sariff	if (result != 0) {
2828162922Sariff		device_printf(sc->dev, "%s: bus_dma_tag_create failed (%x)\n",
2829162922Sariff		     __func__, result);
2830162922Sariff		free(sc, M_DEVBUF);
2831162922Sariff		return (ENXIO);
2832162922Sariff	}
2833162922Sariff
2834162922Sariff
2835162922Sariff	sc->hdabus = NULL;
2836162922Sariff	for (i = 0; i < HDAC_CODEC_MAX; i++)
2837162922Sariff		sc->codecs[i] = NULL;
2838162922Sariff
2839162922Sariff	pci_enable_busmaster(dev);
2840162922Sariff
2841162922Sariff	/* Initialize driver mutex */
2842162922Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), HDAC_MTX_NAME);
2843162922Sariff
2844162922Sariff	/* Allocate resources */
2845162922Sariff	result = hdac_mem_alloc(sc);
2846162922Sariff	if (result != 0)
2847162922Sariff		goto fail;
2848162922Sariff	result = hdac_irq_alloc(sc);
2849162922Sariff	if (result != 0)
2850162922Sariff		goto fail;
2851162922Sariff
2852162922Sariff	/* Get Capabilities */
2853162922Sariff	result = hdac_get_capabilities(sc);
2854162922Sariff	if (result != 0)
2855162922Sariff		goto fail;
2856162922Sariff
2857162922Sariff	/* Allocate CORB and RIRB dma memory */
2858162922Sariff	result = hdac_dma_alloc(sc, &sc->corb_dma,
2859162922Sariff	    sc->corb_size * sizeof(uint32_t));
2860162922Sariff	if (result != 0)
2861162922Sariff		goto fail;
2862162922Sariff	result = hdac_dma_alloc(sc, &sc->rirb_dma,
2863162922Sariff	    sc->rirb_size * sizeof(struct hdac_rirb));
2864162922Sariff	if (result != 0)
2865162922Sariff		goto fail;
2866162922Sariff
2867162922Sariff	/* Quiesce everything */
2868162922Sariff	hdac_reset(sc);
2869162922Sariff
2870162922Sariff	/* Disable PCI-Express QOS */
2871162922Sariff	pci_write_config(sc->dev, 0x44,
2872162922Sariff	    pci_read_config(sc->dev, 0x44, 1) & 0xf8, 1);
2873162922Sariff
2874162922Sariff	/* Initialize the CORB and RIRB */
2875162922Sariff	hdac_corb_init(sc);
2876162922Sariff	hdac_rirb_init(sc);
2877162922Sariff
2878162922Sariff	/* Defer remaining of initialization until interrupts are enabled */
2879162922Sariff	sc->intrhook.ich_func = hdac_attach2;
2880162922Sariff	sc->intrhook.ich_arg = (void *)sc;
2881162922Sariff	if (cold == 0 || config_intrhook_establish(&sc->intrhook) != 0) {
2882162922Sariff		sc->intrhook.ich_func = NULL;
2883162922Sariff		hdac_attach2((void *)sc);
2884162922Sariff	}
2885162922Sariff
2886162922Sariff	return(0);
2887162922Sariff
2888162922Sarifffail:
2889162922Sariff	hdac_dma_free(&sc->rirb_dma);
2890162922Sariff	hdac_dma_free(&sc->corb_dma);
2891162922Sariff	hdac_irq_free(sc);
2892162922Sariff	hdac_mem_free(sc);
2893162922Sariff	snd_mtxfree(sc->lock);
2894162922Sariff
2895162922Sariff	return(ENXIO);
2896162922Sariff}
2897162922Sariff
2898162922Sariffstatic void
2899162922Sariffhdac_audio_parse(struct hdac_devinfo *devinfo)
2900162922Sariff{
2901162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2902162922Sariff	struct hdac_widget *w;
2903162922Sariff	uint32_t res;
2904162922Sariff	int i;
2905162922Sariff	nid_t cad, nid;
2906162922Sariff
2907162922Sariff	cad = devinfo->codec->cad;
2908162922Sariff	nid = devinfo->nid;
2909162922Sariff
2910162922Sariff	hdac_command(sc,
2911162922Sariff	    HDA_CMD_SET_POWER_STATE(cad, nid, HDA_CMD_POWER_STATE_D0), cad);
2912162922Sariff
2913162922Sariff	DELAY(100);
2914162922Sariff
2915162922Sariff	res = hdac_command(sc,
2916162922Sariff	    HDA_CMD_GET_PARAMETER(cad , nid, HDA_PARAM_SUB_NODE_COUNT), cad);
2917162922Sariff
2918162922Sariff	devinfo->nodecnt = HDA_PARAM_SUB_NODE_COUNT_TOTAL(res);
2919162922Sariff	devinfo->startnode = HDA_PARAM_SUB_NODE_COUNT_START(res);
2920162922Sariff	devinfo->endnode = devinfo->startnode + devinfo->nodecnt;
2921162922Sariff
2922162922Sariff	HDA_BOOTVERBOSE_MSG(
2923162922Sariff		device_printf(sc->dev, "       Vendor: 0x%08x\n",
2924162922Sariff		    devinfo->vendor_id);
2925162922Sariff		device_printf(sc->dev, "       Device: 0x%08x\n",
2926162922Sariff		    devinfo->device_id);
2927162922Sariff		device_printf(sc->dev, "     Revision: 0x%08x\n",
2928162922Sariff		    devinfo->revision_id);
2929162922Sariff		device_printf(sc->dev, "     Stepping: 0x%08x\n",
2930162922Sariff		    devinfo->stepping_id);
2931162922Sariff		device_printf(sc->dev, "PCI Subvendor: 0x%08x\n",
2932162922Sariff		    sc->pci_subvendor);
2933162922Sariff		device_printf(sc->dev, "        Nodes: start=%d "
2934162922Sariff		    "endnode=%d total=%d\n",
2935162922Sariff		    devinfo->startnode, devinfo->endnode, devinfo->nodecnt);
2936162922Sariff	);
2937162922Sariff
2938162922Sariff	res = hdac_command(sc,
2939162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_STREAM_FORMATS),
2940162922Sariff	    cad);
2941162922Sariff	devinfo->function.audio.supp_stream_formats = res;
2942162922Sariff
2943162922Sariff	res = hdac_command(sc,
2944162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_SUPP_PCM_SIZE_RATE),
2945162922Sariff	    cad);
2946162922Sariff	devinfo->function.audio.supp_pcm_size_rate = res;
2947162922Sariff
2948162922Sariff	res = hdac_command(sc,
2949162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_OUTPUT_AMP_CAP),
2950162922Sariff	    cad);
2951162922Sariff	devinfo->function.audio.outamp_cap = res;
2952162922Sariff
2953162922Sariff	res = hdac_command(sc,
2954162922Sariff	    HDA_CMD_GET_PARAMETER(cad, nid, HDA_PARAM_INPUT_AMP_CAP),
2955162922Sariff	    cad);
2956162922Sariff	devinfo->function.audio.inamp_cap = res;
2957162922Sariff
2958162922Sariff	if (devinfo->nodecnt > 0) {
2959162922Sariff		hdac_unlock(sc);
2960162922Sariff		devinfo->widget = (struct hdac_widget *)malloc(
2961162922Sariff		    sizeof(*(devinfo->widget)) * devinfo->nodecnt, M_HDAC,
2962162922Sariff		    M_NOWAIT | M_ZERO);
2963162922Sariff		hdac_lock(sc);
2964162922Sariff	} else
2965162922Sariff		devinfo->widget = NULL;
2966162922Sariff
2967162922Sariff	if (devinfo->widget == NULL) {
2968162922Sariff		device_printf(sc->dev, "unable to allocate widgets!\n");
2969162922Sariff		devinfo->endnode = devinfo->startnode;
2970162922Sariff		devinfo->nodecnt = 0;
2971162922Sariff		return;
2972162922Sariff	}
2973162922Sariff
2974162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
2975162922Sariff		w = hdac_widget_get(devinfo, i);
2976162922Sariff		if (w == NULL)
2977162922Sariff			device_printf(sc->dev, "Ghost widget! nid=%d!\n", i);
2978162922Sariff		else {
2979162922Sariff			w->devinfo = devinfo;
2980162922Sariff			w->nid = i;
2981162922Sariff			w->enable = 1;
2982162922Sariff			w->selconn = -1;
2983162922Sariff			w->pflags = 0;
2984162922Sariff			w->ctlflags = 0;
2985162965Sariff			w->param.eapdbtl = HDAC_INVALID;
2986162922Sariff			hdac_widget_parse(w);
2987162922Sariff		}
2988162922Sariff	}
2989162922Sariff}
2990162922Sariff
2991162922Sariffstatic void
2992162922Sariffhdac_audio_ctl_parse(struct hdac_devinfo *devinfo)
2993162922Sariff{
2994162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
2995162922Sariff	struct hdac_audio_ctl *ctls;
2996162922Sariff	struct hdac_widget *w, *cw;
2997162922Sariff	int i, j, cnt, max, ocap, icap;
2998162922Sariff
2999162922Sariff	/* XXX This is redundant */
3000162922Sariff	max = 0;
3001162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3002162922Sariff		w = hdac_widget_get(devinfo, i);
3003162922Sariff		if (w == NULL || w->enable == 0)
3004162922Sariff			continue;
3005162922Sariff		if (w->param.outamp_cap != 0)
3006162922Sariff			max++;
3007162922Sariff		if (w->param.inamp_cap != 0) {
3008162922Sariff			switch (w->type) {
3009162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3010162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3011162922Sariff				for (j = 0; j < w->nconns; j++) {
3012162922Sariff					cw = hdac_widget_get(devinfo,
3013162922Sariff					    w->conns[j]);
3014162922Sariff					if (cw == NULL || cw->enable == 0)
3015162922Sariff						continue;
3016162922Sariff					max++;
3017162922Sariff				}
3018162922Sariff				break;
3019162922Sariff			default:
3020162922Sariff				max++;
3021162922Sariff				break;
3022162922Sariff			}
3023162922Sariff		}
3024162922Sariff	}
3025162922Sariff
3026162922Sariff	devinfo->function.audio.ctlcnt = max;
3027162922Sariff
3028162922Sariff	if (max < 1)
3029162922Sariff		return;
3030162922Sariff
3031162922Sariff	hdac_unlock(sc);
3032162922Sariff	ctls = (struct hdac_audio_ctl *)malloc(
3033162922Sariff	    sizeof(*ctls) * max, M_HDAC, M_ZERO | M_NOWAIT);
3034162922Sariff	hdac_lock(sc);
3035162922Sariff
3036162922Sariff	if (ctls == NULL) {
3037162922Sariff		/* Blekh! */
3038162922Sariff		device_printf(sc->dev, "unable to allocate ctls!\n");
3039162922Sariff		devinfo->function.audio.ctlcnt = 0;
3040162922Sariff		return;
3041162922Sariff	}
3042162922Sariff
3043162922Sariff	cnt = 0;
3044162922Sariff	for (i = devinfo->startnode; cnt < max && i < devinfo->endnode; i++) {
3045162922Sariff		if (cnt >= max) {
3046162922Sariff			device_printf(sc->dev, "%s: Ctl overflow!\n",
3047162922Sariff			    __func__);
3048162922Sariff			break;
3049162922Sariff		}
3050162922Sariff		w = hdac_widget_get(devinfo, i);
3051162922Sariff		if (w == NULL || w->enable == 0)
3052162922Sariff			continue;
3053162922Sariff		ocap = w->param.outamp_cap;
3054162922Sariff		icap = w->param.inamp_cap;
3055162922Sariff		if (ocap != 0) {
3056162922Sariff			ctls[cnt].enable = 1;
3057162922Sariff			ctls[cnt].widget = w;
3058162922Sariff			ctls[cnt].mute =
3059162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(ocap);
3060162922Sariff			ctls[cnt].step =
3061162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(ocap);
3062162922Sariff			ctls[cnt].size =
3063162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(ocap);
3064162922Sariff			ctls[cnt].offset =
3065162922Sariff			    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(ocap);
3066162922Sariff			ctls[cnt].left = ctls[cnt].offset;
3067162922Sariff			ctls[cnt].right = ctls[cnt].offset;
3068162922Sariff			ctls[cnt++].dir = HDA_CTL_OUT;
3069162922Sariff		}
3070162922Sariff
3071162922Sariff		if (icap != 0) {
3072162922Sariff			switch (w->type) {
3073162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3074162922Sariff			case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3075162922Sariff				for (j = 0; j < w->nconns; j++) {
3076162922Sariff					if (cnt >= max) {
3077162922Sariff						device_printf(sc->dev,
3078162922Sariff						    "%s: Ctl overflow!\n",
3079162922Sariff						    __func__);
3080162922Sariff						break;
3081162922Sariff					}
3082162922Sariff					cw = hdac_widget_get(devinfo,
3083162922Sariff					    w->conns[j]);
3084162922Sariff					if (cw == NULL || cw->enable == 0)
3085162922Sariff						continue;
3086162922Sariff					ctls[cnt].enable = 1;
3087162922Sariff					ctls[cnt].widget = w;
3088162922Sariff					ctls[cnt].childwidget = cw;
3089162922Sariff					ctls[cnt].index = j;
3090162922Sariff					ctls[cnt].mute =
3091162922Sariff					    HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP(icap);
3092162922Sariff					ctls[cnt].step =
3093162922Sariff					    HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS(icap);
3094162922Sariff					ctls[cnt].size =
3095162922Sariff					    HDA_PARAM_INPUT_AMP_CAP_STEPSIZE(icap);
3096162922Sariff					ctls[cnt].offset =
3097162922Sariff					    HDA_PARAM_INPUT_AMP_CAP_OFFSET(icap);
3098162922Sariff					ctls[cnt].left = ctls[cnt].offset;
3099162922Sariff					ctls[cnt].right = ctls[cnt].offset;
3100162922Sariff					ctls[cnt++].dir = HDA_CTL_IN;
3101162922Sariff				}
3102162922Sariff				break;
3103162922Sariff			default:
3104162922Sariff				if (cnt >= max) {
3105162922Sariff					device_printf(sc->dev,
3106162922Sariff					    "%s: Ctl overflow!\n",
3107162922Sariff					    __func__);
3108162922Sariff					break;
3109162922Sariff				}
3110162922Sariff				ctls[cnt].enable = 1;
3111162922Sariff				ctls[cnt].widget = w;
3112162922Sariff				ctls[cnt].mute =
3113162922Sariff				    HDA_PARAM_INPUT_AMP_CAP_MUTE_CAP(icap);
3114162922Sariff				ctls[cnt].step =
3115162922Sariff				    HDA_PARAM_INPUT_AMP_CAP_NUMSTEPS(icap);
3116162922Sariff				ctls[cnt].size =
3117162922Sariff				    HDA_PARAM_INPUT_AMP_CAP_STEPSIZE(icap);
3118162922Sariff				ctls[cnt].offset =
3119162922Sariff				    HDA_PARAM_INPUT_AMP_CAP_OFFSET(icap);
3120162922Sariff				ctls[cnt].left = ctls[cnt].offset;
3121162922Sariff				ctls[cnt].right = ctls[cnt].offset;
3122162922Sariff				ctls[cnt++].dir = HDA_CTL_IN;
3123162922Sariff				break;
3124162922Sariff			}
3125162922Sariff		}
3126162922Sariff	}
3127162922Sariff
3128162922Sariff	devinfo->function.audio.ctl = ctls;
3129162922Sariff}
3130162922Sariff
3131162965Sariffstatic const struct {
3132162965Sariff	uint32_t model;
3133162965Sariff	uint32_t id;
3134162965Sariff	uint32_t set, unset;
3135162965Sariff} hdac_quirks[] = {
3136162965Sariff	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
3137162965Sariff	    HDA_QUIRK_GPIO1, 0 },
3138162965Sariff	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
3139162965Sariff	    HDA_QUIRK_GPIO1, 0 },
3140162965Sariff	{ HDA_MATCH_ALL, HDA_CODEC_CXVENICE,
3141162965Sariff	    0, HDA_QUIRK_FORCESTEREO },
3142162965Sariff	{ HDA_MATCH_ALL, HDA_CODEC_STACXXXX,
3143162965Sariff	    HDA_QUIRK_SOFTPCMVOL, 0 }
3144162965Sariff};
3145162965Sariff#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
3146162965Sariff
3147162922Sariffstatic void
3148162922Sariffhdac_vendor_patch_parse(struct hdac_devinfo *devinfo)
3149162922Sariff{
3150162922Sariff	struct hdac_widget *w;
3151162965Sariff	uint32_t id, subvendor;
3152162922Sariff	int i;
3153162922Sariff
3154162922Sariff	/*
3155162922Sariff	 * XXX Fixed rate quirk. Other than 48000
3156162922Sariff	 *     sounds pretty much like train wreck.
3157162922Sariff	 */
3158162922Sariff	devinfo->function.audio.quirks |= HDA_QUIRK_FIXEDRATE;
3159162922Sariff	/*
3160162922Sariff	 * XXX Force stereo quirk. Monoural recording / playback
3161162922Sariff	 *     on few codecs (especially ALC880) seems broken or
3162162922Sariff	 *     or perhaps unsupported.
3163162922Sariff	 */
3164162922Sariff	devinfo->function.audio.quirks |= HDA_QUIRK_FORCESTEREO;
3165162922Sariff	id = hdac_codec_id(devinfo);
3166162965Sariff	subvendor = devinfo->codec->sc->pci_subvendor;
3167162922Sariff	switch (id) {
3168162922Sariff	case HDA_CODEC_ALC260:
3169162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3170162922Sariff			w = hdac_widget_get(devinfo, i);
3171162922Sariff			if (w == NULL || w->enable == 0)
3172162922Sariff				continue;
3173162922Sariff			if (w->type !=
3174162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
3175162922Sariff				continue;
3176162922Sariff			if (w->nid != 5)
3177162922Sariff				w->enable = 0;
3178162922Sariff		}
3179162922Sariff		break;
3180162922Sariff	case HDA_CODEC_ALC880:
3181162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3182162922Sariff			w = hdac_widget_get(devinfo, i);
3183162922Sariff			if (w == NULL || w->enable == 0)
3184162922Sariff				continue;
3185162922Sariff			if (w->type ==
3186162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
3187162922Sariff			    w->nid != 9 && w->nid != 29) {
3188162922Sariff					w->enable = 0;
3189162922Sariff			} else if (w->type !=
3190162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET &&
3191162922Sariff			    w->nid == 29) {
3192162922Sariff				w->type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET;
3193162922Sariff				w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
3194162922Sariff				w->param.widget_cap |=
3195162922Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
3196162922Sariff				    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
3197162922Sariff				strlcpy(w->name, "beep widget", sizeof(w->name));
3198162922Sariff			}
3199162922Sariff		}
3200162922Sariff		break;
3201162922Sariff	case HDA_CODEC_AD1986A:
3202162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3203162922Sariff			w = hdac_widget_get(devinfo, i);
3204162922Sariff			if (w == NULL || w->enable == 0)
3205162922Sariff				continue;
3206162922Sariff			if (w->type !=
3207162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
3208162922Sariff				continue;
3209162922Sariff			if (w->nid != 3)
3210162922Sariff				w->enable = 0;
3211162922Sariff		}
3212162922Sariff		break;
3213162922Sariff	case HDA_CODEC_STAC9221:
3214162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3215162922Sariff			w = hdac_widget_get(devinfo, i);
3216162922Sariff			if (w == NULL || w->enable == 0)
3217162922Sariff				continue;
3218162922Sariff			if (w->type !=
3219162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT)
3220162922Sariff				continue;
3221162922Sariff			if (w->nid != 2)
3222162922Sariff				w->enable = 0;
3223162922Sariff		}
3224162922Sariff		break;
3225162922Sariff	case HDA_CODEC_STAC9221D:
3226162922Sariff		for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3227162922Sariff			w = hdac_widget_get(devinfo, i);
3228162922Sariff			if (w == NULL || w->enable == 0)
3229162922Sariff				continue;
3230162922Sariff			if (w->type ==
3231162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
3232162922Sariff			    w->nid != 6)
3233162922Sariff				w->enable = 0;
3234162922Sariff
3235162922Sariff		}
3236162922Sariff		break;
3237162922Sariff	default:
3238162922Sariff		break;
3239162922Sariff	}
3240162965Sariff
3241162965Sariff	/*
3242162965Sariff	 * Quirks
3243162965Sariff	 */
3244162965Sariff	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
3245162965Sariff		if (!(HDA_FLAG_MATCH(hdac_quirks[i].model, subvendor) &&
3246162965Sariff		    HDA_FLAG_MATCH(hdac_quirks[i].id, id)))
3247162965Sariff			continue;
3248162965Sariff		if (hdac_quirks[i].set != 0)
3249162965Sariff			devinfo->function.audio.quirks |=
3250162965Sariff			    hdac_quirks[i].set;
3251162965Sariff		if (hdac_quirks[i].unset != 0)
3252162965Sariff			devinfo->function.audio.quirks &=
3253162965Sariff			    ~(hdac_quirks[i].unset);
3254162965Sariff		break;
3255162922Sariff	}
3256162922Sariff}
3257162922Sariff
3258162922Sariffstatic int
3259162922Sariffhdac_audio_ctl_ossmixer_getnextdev(struct hdac_devinfo *devinfo)
3260162922Sariff{
3261162922Sariff	int *dev = &devinfo->function.audio.ossidx;
3262162922Sariff
3263162922Sariff	while (*dev < SOUND_MIXER_NRDEVICES) {
3264162922Sariff		switch (*dev) {
3265162922Sariff		case SOUND_MIXER_VOLUME:
3266162922Sariff		case SOUND_MIXER_BASS:
3267162922Sariff		case SOUND_MIXER_TREBLE:
3268162922Sariff		case SOUND_MIXER_PCM:
3269162922Sariff		case SOUND_MIXER_SPEAKER:
3270162922Sariff		case SOUND_MIXER_LINE:
3271162922Sariff		case SOUND_MIXER_MIC:
3272162922Sariff		case SOUND_MIXER_CD:
3273162922Sariff		case SOUND_MIXER_RECLEV:
3274162922Sariff		case SOUND_MIXER_OGAIN:	/* reserved for EAPD switch */
3275162922Sariff			(*dev)++;
3276162922Sariff			break;
3277162922Sariff		default:
3278162922Sariff			return (*dev)++;
3279162922Sariff			break;
3280162922Sariff		}
3281162922Sariff	}
3282162922Sariff
3283162922Sariff	return (-1);
3284162922Sariff}
3285162922Sariff
3286162922Sariffstatic int
3287162922Sariffhdac_widget_find_dac_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
3288162922Sariff{
3289162922Sariff	struct hdac_widget *w;
3290162922Sariff	int i, ret = 0;
3291162922Sariff
3292162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3293162922Sariff		return (0);
3294162922Sariff	w = hdac_widget_get(devinfo, nid);
3295162922Sariff	if (w == NULL || w->enable == 0)
3296162922Sariff		return (0);
3297162922Sariff	switch (w->type) {
3298162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT:
3299162922Sariff		w->pflags |= HDA_DAC_PATH;
3300162922Sariff		ret = 1;
3301162922Sariff		break;
3302162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3303162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3304162922Sariff		for (i = 0; i < w->nconns; i++) {
3305162922Sariff			if (hdac_widget_find_dac_path(devinfo,
3306162922Sariff			    w->conns[i], depth + 1) != 0) {
3307162922Sariff				if (w->selconn == -1)
3308162922Sariff					w->selconn = i;
3309162922Sariff				ret = 1;
3310162922Sariff				w->pflags |= HDA_DAC_PATH;
3311162922Sariff			}
3312162922Sariff		}
3313162922Sariff		break;
3314162922Sariff	default:
3315162922Sariff		break;
3316162922Sariff	}
3317162922Sariff	return (ret);
3318162922Sariff}
3319162922Sariff
3320162922Sariffstatic int
3321162922Sariffhdac_widget_find_adc_path(struct hdac_devinfo *devinfo, nid_t nid, int depth)
3322162922Sariff{
3323162922Sariff	struct hdac_widget *w;
3324162922Sariff	int i, conndev, ret = 0;
3325162922Sariff
3326162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3327162922Sariff		return (0);
3328162922Sariff	w = hdac_widget_get(devinfo, nid);
3329162922Sariff	if (w == NULL || w->enable == 0)
3330162922Sariff		return (0);
3331162922Sariff	switch (w->type) {
3332162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT:
3333162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR:
3334162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3335162922Sariff		for (i = 0; i < w->nconns; i++) {
3336162922Sariff			if (hdac_widget_find_adc_path(devinfo, w->conns[i],
3337162922Sariff			    depth + 1) != 0) {
3338162922Sariff				if (w->selconn == -1)
3339162922Sariff					w->selconn = i;
3340162922Sariff				w->pflags |= HDA_ADC_PATH;
3341162922Sariff				ret = 1;
3342162922Sariff			}
3343162922Sariff		}
3344162922Sariff		break;
3345162922Sariff	case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX:
3346162922Sariff		conndev = w->wclass.pin.config &
3347162922Sariff		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
3348162922Sariff		if (HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
3349162922Sariff		    (conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_CD ||
3350162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN ||
3351162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN)) {
3352162922Sariff			w->pflags |= HDA_ADC_PATH;
3353162922Sariff			ret = 1;
3354162922Sariff		}
3355162922Sariff		break;
3356162922Sariff	/*case HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER:
3357162922Sariff		if (w->pflags & HDA_DAC_PATH) {
3358162922Sariff			w->pflags |= HDA_ADC_PATH;
3359162922Sariff			ret = 1;
3360162922Sariff		}
3361162922Sariff		break;*/
3362162922Sariff	default:
3363162922Sariff		break;
3364162922Sariff	}
3365162922Sariff	return (ret);
3366162922Sariff}
3367162922Sariff
3368162922Sariffstatic uint32_t
3369162922Sariffhdac_audio_ctl_outamp_build(struct hdac_devinfo *devinfo,
3370162922Sariff				nid_t nid, nid_t pnid, int index, int depth)
3371162922Sariff{
3372162922Sariff	struct hdac_widget *w, *pw;
3373162922Sariff	struct hdac_audio_ctl *ctl;
3374162922Sariff	uint32_t fl = 0;
3375162922Sariff	int i, ossdev, conndev, strategy;
3376162922Sariff
3377162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3378162922Sariff		return (0);
3379162922Sariff
3380162922Sariff	w = hdac_widget_get(devinfo, nid);
3381162922Sariff	if (w == NULL || w->enable == 0)
3382162922Sariff		return (0);
3383162922Sariff
3384162922Sariff	pw = hdac_widget_get(devinfo, pnid);
3385162922Sariff	strategy = devinfo->function.audio.parsing_strategy;
3386162922Sariff
3387162922Sariff	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER
3388162922Sariff	    || w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR) {
3389162922Sariff		for (i = 0; i < w->nconns; i++) {
3390162922Sariff			fl |= hdac_audio_ctl_outamp_build(devinfo, w->conns[i],
3391162922Sariff			    w->nid, i, depth + 1);
3392162922Sariff		}
3393162922Sariff		w->ctlflags |= fl;
3394162922Sariff		return (fl);
3395162922Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT &&
3396162922Sariff	    (w->pflags & HDA_DAC_PATH)) {
3397162922Sariff		i = 0;
3398162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3399162922Sariff			if (ctl->enable == 0 || ctl->widget == NULL)
3400162922Sariff				continue;
3401162922Sariff			if ((ctl->widget->nid == w->nid) ||
3402162922Sariff			    (ctl->widget->nid == pnid && ctl->index == index &&
3403162922Sariff			    (ctl->dir & HDA_CTL_IN)) ||
3404162922Sariff			    (ctl->widget->nid == pnid && pw != NULL &&
3405162922Sariff			    pw->type ==
3406162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
3407162922Sariff			    (pw->nconns < 2 || pw->selconn == index ||
3408162922Sariff			    pw->selconn == -1) &&
3409162922Sariff			    (ctl->dir & HDA_CTL_OUT)) ||
3410162922Sariff			    (strategy == HDA_PARSE_DIRECT &&
3411162922Sariff			    ctl->widget->nid == w->nid)) {
3412162922Sariff				if (pw != NULL && pw->selconn == -1)
3413162922Sariff					pw->selconn = index;
3414162922Sariff				fl |= SOUND_MASK_VOLUME;
3415162922Sariff				fl |= SOUND_MASK_PCM;
3416162922Sariff				ctl->ossmask |= SOUND_MASK_VOLUME;
3417162922Sariff				ctl->ossmask |= SOUND_MASK_PCM;
3418162922Sariff				ctl->ossdev = SOUND_MIXER_PCM;
3419162922Sariff			}
3420162922Sariff		}
3421162922Sariff		w->ctlflags |= fl;
3422162922Sariff		return (fl);
3423162922Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX
3424162922Sariff	    && HDA_PARAM_PIN_CAP_INPUT_CAP(w->wclass.pin.cap) &&
3425162922Sariff	    (w->pflags & HDA_ADC_PATH)) {
3426162922Sariff		conndev = w->wclass.pin.config &
3427162922Sariff		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
3428162922Sariff		i = 0;
3429162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3430162922Sariff			if (ctl->enable == 0 || ctl->widget == NULL)
3431162922Sariff				continue;
3432162922Sariff			if (((ctl->widget->nid == pnid && ctl->index == index &&
3433162922Sariff			    (ctl->dir & HDA_CTL_IN)) ||
3434162922Sariff			    (ctl->widget->nid == pnid && pw != NULL &&
3435162922Sariff			    pw->type ==
3436162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
3437162922Sariff			    (pw->nconns < 2 || pw->selconn == index ||
3438162922Sariff			    pw->selconn == -1) &&
3439162922Sariff			    (ctl->dir & HDA_CTL_OUT)) ||
3440162922Sariff			    (strategy == HDA_PARSE_DIRECT &&
3441162922Sariff			    ctl->widget->nid == w->nid)) &&
3442162922Sariff			    (ctl->ossmask & ~SOUND_MASK_VOLUME) == 0) {
3443162922Sariff				if (pw != NULL && pw->selconn == -1)
3444162922Sariff					pw->selconn = index;
3445162922Sariff				ossdev = 0;
3446162922Sariff				switch (conndev) {
3447162922Sariff				case HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN:
3448162922Sariff					ossdev = SOUND_MIXER_MIC;
3449162922Sariff					break;
3450162922Sariff				case HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN:
3451162922Sariff					ossdev = SOUND_MIXER_LINE;
3452162922Sariff					break;
3453162922Sariff				case HDA_CONFIG_DEFAULTCONF_DEVICE_CD:
3454162922Sariff					ossdev = SOUND_MIXER_CD;
3455162922Sariff					break;
3456162922Sariff				default:
3457162922Sariff					ossdev =
3458162922Sariff					    hdac_audio_ctl_ossmixer_getnextdev(
3459162922Sariff					    devinfo);
3460162922Sariff					if (ossdev < 0)
3461162922Sariff						ossdev = 0;
3462162922Sariff					break;
3463162922Sariff				}
3464162922Sariff				if (strategy == HDA_PARSE_MIXER) {
3465162922Sariff					fl |= SOUND_MASK_VOLUME;
3466162922Sariff					ctl->ossmask |= SOUND_MASK_VOLUME;
3467162922Sariff				}
3468162922Sariff				fl |= 1 << ossdev;
3469162922Sariff				ctl->ossmask |= 1 << ossdev;
3470162922Sariff				ctl->ossdev = ossdev;
3471162922Sariff			}
3472162922Sariff		}
3473162922Sariff		w->ctlflags |= fl;
3474162922Sariff		return (fl);
3475162922Sariff	} else if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
3476162922Sariff		i = 0;
3477162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3478162922Sariff			if (ctl->enable == 0 || ctl->widget == NULL)
3479162922Sariff				continue;
3480162922Sariff			if (((ctl->widget->nid == pnid && ctl->index == index &&
3481162922Sariff			    (ctl->dir & HDA_CTL_IN)) ||
3482162922Sariff			    (ctl->widget->nid == pnid && pw != NULL &&
3483162922Sariff			    pw->type ==
3484162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR &&
3485162922Sariff			    (pw->nconns < 2 || pw->selconn == index ||
3486162922Sariff			    pw->selconn == -1) &&
3487162922Sariff			    (ctl->dir & HDA_CTL_OUT)) ||
3488162922Sariff			    (strategy == HDA_PARSE_DIRECT &&
3489162922Sariff			    ctl->widget->nid == w->nid)) &&
3490162922Sariff			    (ctl->ossmask & ~SOUND_MASK_VOLUME) == 0) {
3491162922Sariff				if (pw != NULL && pw->selconn == -1)
3492162922Sariff					pw->selconn = index;
3493162922Sariff				fl |= SOUND_MASK_VOLUME;
3494162922Sariff				fl |= SOUND_MASK_SPEAKER;
3495162922Sariff				ctl->ossmask |= SOUND_MASK_VOLUME;
3496162922Sariff				ctl->ossmask |= SOUND_MASK_SPEAKER;
3497162922Sariff				ctl->ossdev = SOUND_MIXER_SPEAKER;
3498162922Sariff			}
3499162922Sariff		}
3500162922Sariff		w->ctlflags |= fl;
3501162922Sariff		return (fl);
3502162922Sariff	}
3503162922Sariff	return (0);
3504162922Sariff}
3505162922Sariff
3506162922Sariffstatic uint32_t
3507162922Sariffhdac_audio_ctl_inamp_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
3508162922Sariff{
3509162922Sariff	struct hdac_widget *w, *cw;
3510162922Sariff	struct hdac_audio_ctl *ctl;
3511162922Sariff	uint32_t fl;
3512162922Sariff	int i;
3513162922Sariff
3514162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3515162922Sariff		return (0);
3516162922Sariff
3517162922Sariff	w = hdac_widget_get(devinfo, nid);
3518162922Sariff	if (w == NULL || w->enable == 0)
3519162922Sariff		return (0);
3520162922Sariff	/*if (!(w->pflags & HDA_ADC_PATH))
3521162922Sariff		return (0);
3522162922Sariff	if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
3523162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
3524162922Sariff		return (0);*/
3525162922Sariff	i = 0;
3526162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3527162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL)
3528162922Sariff			continue;
3529162922Sariff		if (ctl->widget->nid == nid) {
3530162922Sariff			ctl->ossmask |= SOUND_MASK_RECLEV;
3531162922Sariff			w->ctlflags |= SOUND_MASK_RECLEV;
3532162922Sariff			return (SOUND_MASK_RECLEV);
3533162922Sariff		}
3534162922Sariff	}
3535162922Sariff	for (i = 0; i < w->nconns; i++) {
3536162922Sariff		cw = hdac_widget_get(devinfo, w->conns[i]);
3537162922Sariff		if (cw == NULL || cw->enable == 0)
3538162922Sariff			continue;
3539162922Sariff		if (cw->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
3540162922Sariff			continue;
3541162922Sariff		fl = hdac_audio_ctl_inamp_build(devinfo, cw->nid, depth + 1);
3542162922Sariff		if (fl != 0) {
3543162922Sariff			cw->ctlflags |= fl;
3544162922Sariff			w->ctlflags |= fl;
3545162922Sariff			return (fl);
3546162922Sariff		}
3547162922Sariff	}
3548162922Sariff	return (0);
3549162922Sariff}
3550162922Sariff
3551162922Sariffstatic int
3552162922Sariffhdac_audio_ctl_recsel_build(struct hdac_devinfo *devinfo, nid_t nid, int depth)
3553162922Sariff{
3554162922Sariff	struct hdac_widget *w, *cw;
3555162922Sariff	int i, child = 0;
3556162922Sariff
3557162922Sariff	if (depth > HDA_PARSE_MAXDEPTH)
3558162922Sariff		return (0);
3559162922Sariff
3560162922Sariff	w = hdac_widget_get(devinfo, nid);
3561162922Sariff	if (w == NULL || w->enable == 0)
3562162922Sariff		return (0);
3563162922Sariff	/*if (!(w->pflags & HDA_ADC_PATH))
3564162922Sariff		return (0);
3565162922Sariff	if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT ||
3566162922Sariff	    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
3567162922Sariff		return (0);*/
3568162922Sariff	/* XXX weak! */
3569162922Sariff	for (i = 0; i < w->nconns; i++) {
3570162922Sariff		cw = hdac_widget_get(devinfo, w->conns[i]);
3571162922Sariff		if (cw == NULL)
3572162922Sariff			continue;
3573162922Sariff		if (++child > 1) {
3574162922Sariff			w->pflags |= HDA_ADC_RECSEL;
3575162922Sariff			return (1);
3576162922Sariff		}
3577162922Sariff	}
3578162922Sariff	for (i = 0; i < w->nconns; i++) {
3579162922Sariff		if (hdac_audio_ctl_recsel_build(devinfo,
3580162922Sariff		    w->conns[i], depth + 1) != 0)
3581162922Sariff			return (1);
3582162922Sariff	}
3583162922Sariff	return (0);
3584162922Sariff}
3585162922Sariff
3586162922Sariffstatic int
3587162922Sariffhdac_audio_build_tree_strategy(struct hdac_devinfo *devinfo)
3588162922Sariff{
3589162922Sariff	struct hdac_widget *w, *cw;
3590162922Sariff	int i, j, conndev, found_dac = 0;
3591162922Sariff	int strategy;
3592162922Sariff
3593162922Sariff	strategy = devinfo->function.audio.parsing_strategy;
3594162922Sariff
3595162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3596162922Sariff		w = hdac_widget_get(devinfo, i);
3597162922Sariff		if (w == NULL || w->enable == 0)
3598162922Sariff			continue;
3599162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
3600162922Sariff			continue;
3601162922Sariff		if (!HDA_PARAM_PIN_CAP_OUTPUT_CAP(w->wclass.pin.cap))
3602162922Sariff			continue;
3603162922Sariff		conndev = w->wclass.pin.config &
3604162922Sariff		    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
3605162922Sariff		if (!(conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT ||
3606162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_SPEAKER ||
3607162922Sariff		    conndev == HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT))
3608162922Sariff			continue;
3609162922Sariff		for (j = 0; j < w->nconns; j++) {
3610162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
3611162922Sariff			if (cw == NULL || cw->enable == 0)
3612162922Sariff				continue;
3613162922Sariff			if (strategy == HDA_PARSE_MIXER && !(cw->type ==
3614162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
3615162922Sariff			    cw->type ==
3616162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR))
3617162922Sariff				continue;
3618162922Sariff			if (hdac_widget_find_dac_path(devinfo, cw->nid, 0)
3619162922Sariff			    != 0) {
3620162922Sariff				if (w->selconn == -1)
3621162922Sariff					w->selconn = j;
3622162922Sariff				w->pflags |= HDA_DAC_PATH;
3623162922Sariff				found_dac++;
3624162922Sariff			}
3625162922Sariff		}
3626162922Sariff	}
3627162922Sariff
3628162922Sariff	return (found_dac);
3629162922Sariff}
3630162922Sariff
3631162922Sariffstatic void
3632162922Sariffhdac_audio_build_tree(struct hdac_devinfo *devinfo)
3633162922Sariff{
3634162922Sariff	struct hdac_widget *w;
3635162922Sariff	struct hdac_audio_ctl *ctl;
3636162922Sariff	int i, j, dacs, strategy;
3637162922Sariff
3638162922Sariff	/* Construct DAC path */
3639162922Sariff	strategy = HDA_PARSE_MIXER;
3640162922Sariff	devinfo->function.audio.parsing_strategy = strategy;
3641162922Sariff	HDA_BOOTVERBOSE_MSG(
3642162922Sariff		device_printf(devinfo->codec->sc->dev,
3643162922Sariff		    "HWiP: HDA Widget Parser - Revision %d\n",
3644162922Sariff		    HDA_WIDGET_PARSER_REV);
3645162922Sariff	);
3646162922Sariff	dacs = hdac_audio_build_tree_strategy(devinfo);
3647162922Sariff	if (dacs == 0) {
3648162922Sariff		HDA_BOOTVERBOSE_MSG(
3649162922Sariff			device_printf(devinfo->codec->sc->dev,
3650162922Sariff			    "HWiP: 0 DAC found! Retrying parser "
3651162922Sariff			    "using HDA_PARSE_DIRECT strategy.\n");
3652162922Sariff		);
3653162922Sariff		strategy = HDA_PARSE_DIRECT;
3654162922Sariff		devinfo->function.audio.parsing_strategy = strategy;
3655162922Sariff		dacs = hdac_audio_build_tree_strategy(devinfo);
3656162922Sariff	}
3657162922Sariff
3658162922Sariff	HDA_BOOTVERBOSE_MSG(
3659162922Sariff		device_printf(devinfo->codec->sc->dev,
3660162922Sariff		    "HWiP: Found %d DAC(s) using HDA_PARSE_%s strategy.\n",
3661162922Sariff		    dacs, (strategy == HDA_PARSE_MIXER) ? "MIXER" : "DIRECT");
3662162922Sariff	);
3663162922Sariff
3664162922Sariff	/* Construct ADC path */
3665162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3666162922Sariff		w = hdac_widget_get(devinfo, i);
3667162922Sariff		if (w == NULL || w->enable == 0)
3668162922Sariff			continue;
3669162922Sariff		if (w->type != HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT)
3670162922Sariff			continue;
3671162922Sariff		(void)hdac_widget_find_adc_path(devinfo, w->nid, 0);
3672162922Sariff	}
3673162922Sariff
3674162922Sariff	/* Output mixers */
3675162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3676162922Sariff		w = hdac_widget_get(devinfo, i);
3677162922Sariff		if (w == NULL || w->enable == 0)
3678162922Sariff			continue;
3679162922Sariff		if ((strategy == HDA_PARSE_MIXER &&
3680162922Sariff		    (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER ||
3681162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_SELECTOR)
3682162922Sariff		    && (w->pflags & HDA_DAC_PATH)) ||
3683162922Sariff		    (strategy == HDA_PARSE_DIRECT && (w->pflags &
3684162922Sariff		    (HDA_DAC_PATH | HDA_ADC_PATH)))) {
3685162922Sariff			w->ctlflags |= hdac_audio_ctl_outamp_build(devinfo,
3686162922Sariff			    w->nid, devinfo->startnode - 1, 0, 0);
3687162922Sariff		} else if (w->type ==
3688162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET) {
3689162922Sariff			j = 0;
3690162922Sariff			while ((ctl = hdac_audio_ctl_each(devinfo, &j)) !=
3691162922Sariff			    NULL) {
3692162922Sariff				if (ctl->enable == 0 || ctl->widget == NULL)
3693162922Sariff					continue;
3694162922Sariff				if (ctl->widget->nid != w->nid)
3695162922Sariff					continue;
3696162922Sariff				ctl->ossmask |= SOUND_MASK_VOLUME;
3697162922Sariff				ctl->ossmask |= SOUND_MASK_SPEAKER;
3698162922Sariff				ctl->ossdev = SOUND_MIXER_SPEAKER;
3699162922Sariff				w->ctlflags |= SOUND_MASK_VOLUME;
3700162922Sariff				w->ctlflags |= SOUND_MASK_SPEAKER;
3701162922Sariff			}
3702162922Sariff		}
3703162922Sariff	}
3704162922Sariff
3705162922Sariff	/* Input mixers (rec) */
3706162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
3707162922Sariff		w = hdac_widget_get(devinfo, i);
3708162922Sariff		if (w == NULL || w->enable == 0)
3709162922Sariff			continue;
3710162922Sariff		if (!(w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT &&
3711162922Sariff		    w->pflags & HDA_ADC_PATH))
3712162922Sariff			continue;
3713162922Sariff		hdac_audio_ctl_inamp_build(devinfo, w->nid, 0);
3714162922Sariff		hdac_audio_ctl_recsel_build(devinfo, w->nid, 0);
3715162922Sariff	}
3716162922Sariff}
3717162922Sariff
3718162922Sariff#define HDA_COMMIT_CONN	(1 << 0)
3719162922Sariff#define HDA_COMMIT_CTRL	(1 << 1)
3720162922Sariff#define HDA_COMMIT_EAPD	(1 << 2)
3721162922Sariff#define HDA_COMMIT_GPIO	(1 << 3)
3722162922Sariff#define HDA_COMMIT_ALL	(HDA_COMMIT_CONN | HDA_COMMIT_CTRL | \
3723162922Sariff				HDA_COMMIT_EAPD | HDA_COMMIT_GPIO)
3724162922Sariff
3725162922Sariffstatic void
3726162922Sariffhdac_audio_commit(struct hdac_devinfo *devinfo, uint32_t cfl)
3727162922Sariff{
3728162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3729162922Sariff	struct hdac_widget *w;
3730162922Sariff	nid_t cad;
3731162922Sariff	int i;
3732162922Sariff
3733162922Sariff	if (!(cfl & HDA_COMMIT_ALL))
3734162922Sariff		return;
3735162922Sariff
3736162922Sariff	cad = devinfo->codec->cad;
3737162922Sariff
3738162922Sariff	if ((cfl & HDA_COMMIT_GPIO)) {
3739162922Sariff		if (devinfo->function.audio.quirks & HDA_QUIRK_GPIO1) {
3740162922Sariff			hdac_command(sc,
3741162922Sariff			    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, 0x01,
3742162922Sariff			    0x01), cad);
3743162922Sariff			hdac_command(sc,
3744162922Sariff			    HDA_CMD_SET_GPIO_DIRECTION(cad, 0x01,
3745162922Sariff			    0x01), cad);
3746162922Sariff			hdac_command(sc,
3747162922Sariff			    HDA_CMD_SET_GPIO_DATA(cad, 0x01,
3748162922Sariff			    0x01), cad);
3749162922Sariff		}
3750162922Sariff		if (devinfo->function.audio.quirks & HDA_QUIRK_GPIO2) {
3751162922Sariff			hdac_command(sc,
3752162922Sariff			    HDA_CMD_SET_GPIO_ENABLE_MASK(cad, 0x01,
3753162922Sariff			    0x02), cad);
3754162922Sariff			hdac_command(sc,
3755162922Sariff			    HDA_CMD_SET_GPIO_DIRECTION(cad, 0x01,
3756162922Sariff			    0x02), cad);
3757162922Sariff			hdac_command(sc,
3758162922Sariff			    HDA_CMD_SET_GPIO_DATA(cad, 0x01,
3759162922Sariff			    0x02), cad);
3760162922Sariff		}
3761162922Sariff	}
3762162922Sariff
3763162922Sariff	for (i = 0; i < devinfo->nodecnt; i++) {
3764162922Sariff		w = &devinfo->widget[i];
3765162922Sariff		if (w == NULL || w->enable == 0)
3766162922Sariff			continue;
3767162922Sariff		if (cfl & HDA_COMMIT_CONN) {
3768162922Sariff			if (w->selconn == -1)
3769162922Sariff				w->selconn = 0;
3770162922Sariff			if (w->nconns > 0)
3771162922Sariff				hdac_widget_connection_select(w, w->selconn);
3772162922Sariff		}
3773162922Sariff		if ((cfl & HDA_COMMIT_CTRL) &&
3774162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX) {
3775162922Sariff			if ((w->pflags & (HDA_DAC_PATH | HDA_ADC_PATH)) ==
3776162922Sariff			    (HDA_DAC_PATH | HDA_ADC_PATH))
3777162922Sariff				device_printf(sc->dev, "WARNING: node %d "
3778162922Sariff				    "participate both for DAC/ADC!\n", w->nid);
3779162922Sariff			if (w->pflags & HDA_DAC_PATH) {
3780162922Sariff				w->wclass.pin.ctrl &=
3781162922Sariff				    ~HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE;
3782162922Sariff				if ((w->wclass.pin.config &
3783162922Sariff				    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) !=
3784162922Sariff				    HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT)
3785162922Sariff					w->wclass.pin.ctrl &=
3786162922Sariff					    ~HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE;
3787162922Sariff			} else if (w->pflags & HDA_ADC_PATH) {
3788162922Sariff				w->wclass.pin.ctrl &=
3789162922Sariff				    ~(HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
3790162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE);
3791162922Sariff			} else
3792162922Sariff				w->wclass.pin.ctrl &= ~(
3793162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE |
3794162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE |
3795162922Sariff				    HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE);
3796162922Sariff			hdac_command(sc,
3797162922Sariff			    HDA_CMD_SET_PIN_WIDGET_CTRL(cad, w->nid,
3798162922Sariff			    w->wclass.pin.ctrl), cad);
3799162922Sariff		}
3800162922Sariff		if ((cfl & HDA_COMMIT_EAPD) &&
3801162965Sariff		    w->param.eapdbtl != HDAC_INVALID)
3802162922Sariff			hdac_command(sc,
3803162922Sariff			    HDA_CMD_SET_EAPD_BTL_ENABLE(cad, w->nid,
3804162922Sariff			    w->param.eapdbtl), cad);
3805162922Sariff
3806162922Sariff		DELAY(1000);
3807162922Sariff	}
3808162922Sariff}
3809162922Sariff
3810162922Sariffstatic void
3811162922Sariffhdac_audio_ctl_commit(struct hdac_devinfo *devinfo)
3812162922Sariff{
3813162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3814162922Sariff	struct hdac_audio_ctl *ctl;
3815162922Sariff	int i;
3816162922Sariff
3817162922Sariff	devinfo->function.audio.mvol = 100 | (100 << 8);
3818162922Sariff	i = 0;
3819162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3820162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL) {
3821162922Sariff			HDA_BOOTVERBOSE_MSG(
3822162922Sariff				device_printf(sc->dev, "[%2d] Ctl nid=%d",
3823162922Sariff				    i, (ctl->widget != NULL) ?
3824162922Sariff				    ctl->widget->nid : -1);
3825162922Sariff				if (ctl->childwidget != NULL)
3826162922Sariff					printf(" childnid=%d",
3827162922Sariff					    ctl->childwidget->nid);
3828162922Sariff				if (ctl->widget == NULL)
3829162922Sariff					printf(" NULL WIDGET!");
3830162922Sariff				printf(" DISABLED\n");
3831162922Sariff			);
3832162922Sariff			continue;
3833162922Sariff		}
3834162922Sariff		HDA_BOOTVERBOSE_MSG(
3835162922Sariff			if (ctl->ossmask == 0) {
3836162922Sariff				device_printf(sc->dev, "[%2d] Ctl nid=%d",
3837162922Sariff				    i, ctl->widget->nid);
3838162922Sariff				if (ctl->childwidget != NULL)
3839162922Sariff					printf(" childnid=%d",
3840162922Sariff					ctl->childwidget->nid);
3841162922Sariff				printf(" Bind to NONE\n");
3842162922Sariff		}
3843162922Sariff		);
3844162922Sariff		if (ctl->step > 0) {
3845162922Sariff			ctl->ossval = (ctl->left * 100) / ctl->step;
3846162922Sariff			ctl->ossval |= ((ctl->right * 100) / ctl->step) << 8;
3847162922Sariff		} else
3848162922Sariff			ctl->ossval = 0;
3849162922Sariff		hdac_audio_ctl_amp_set(ctl, HDA_AMP_MUTE_DEFAULT,
3850162922Sariff		    ctl->left, ctl->right);
3851162922Sariff	}
3852162922Sariff}
3853162922Sariff
3854162922Sariffstatic int
3855162922Sariffhdac_pcmchannel_setup(struct hdac_devinfo *devinfo, int dir)
3856162922Sariff{
3857162922Sariff	struct hdac_chan *ch;
3858162922Sariff	struct hdac_widget *w;
3859162922Sariff	uint32_t cap, fmtcap, pcmcap, path;
3860162922Sariff	int i, type, ret, max;
3861162922Sariff
3862162922Sariff	if (dir == PCMDIR_PLAY) {
3863162922Sariff		type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT;
3864162922Sariff		ch = &devinfo->codec->sc->play;
3865162922Sariff		path = HDA_DAC_PATH;
3866162922Sariff	} else {
3867162922Sariff		type = HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT;
3868162922Sariff		ch = &devinfo->codec->sc->rec;
3869162922Sariff		path = HDA_ADC_PATH;
3870162922Sariff	}
3871162922Sariff
3872162922Sariff	ch->caps = hdac_caps;
3873162922Sariff	ch->caps.fmtlist = ch->fmtlist;
3874162922Sariff	ch->bit16 = 1;
3875162922Sariff	ch->bit32 = 0;
3876162922Sariff	ch->pcmrates[0] = 48000;
3877162922Sariff	ch->pcmrates[1] = 0;
3878162922Sariff
3879162922Sariff	ret = 0;
3880162922Sariff	fmtcap = devinfo->function.audio.supp_stream_formats;
3881162922Sariff	pcmcap = devinfo->function.audio.supp_pcm_size_rate;
3882162922Sariff	max = (sizeof(ch->io) / sizeof(ch->io[0])) - 1;
3883162922Sariff
3884162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode && ret < max; i++) {
3885162922Sariff		w = hdac_widget_get(devinfo, i);
3886162922Sariff		if (w == NULL || w->enable == 0 || w->type != type ||
3887162922Sariff		    (w->pflags & path) == 0)
3888162922Sariff			continue;
3889162922Sariff		cap = w->param.widget_cap;
3890162922Sariff		/*if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(cap))
3891162922Sariff			continue;*/
3892162922Sariff		if (!HDA_PARAM_AUDIO_WIDGET_CAP_STEREO(cap))
3893162922Sariff			continue;
3894162922Sariff		cap = w->param.supp_stream_formats;
3895162922Sariff		/*if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap)) {
3896162922Sariff		}
3897162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap)) {
3898162922Sariff		}*/
3899162922Sariff		if (!HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
3900162922Sariff			continue;
3901162922Sariff		ch->io[ret++] = i;
3902162922Sariff		fmtcap &= w->param.supp_stream_formats;
3903162922Sariff		pcmcap &= w->param.supp_pcm_size_rate;
3904162922Sariff	}
3905162922Sariff	ch->io[ret] = -1;
3906162922Sariff
3907162922Sariff	ch->supp_stream_formats = fmtcap;
3908162922Sariff	ch->supp_pcm_size_rate = pcmcap;
3909162922Sariff
3910162922Sariff	/*
3911162922Sariff	 *  8bit = 0
3912162922Sariff	 * 16bit = 1
3913162922Sariff	 * 20bit = 2
3914162922Sariff	 * 24bit = 3
3915162922Sariff	 * 32bit = 4
3916162922Sariff	 */
3917162922Sariff	if (ret > 0) {
3918162922Sariff		cap = pcmcap;
3919162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
3920162922Sariff			ch->bit16 = 1;
3921162922Sariff		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
3922162922Sariff			ch->bit16 = 0;
3923162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
3924162922Sariff			ch->bit32 = 4;
3925162922Sariff		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
3926162922Sariff			ch->bit32 = 3;
3927162922Sariff		else if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
3928162922Sariff			ch->bit32 = 2;
3929162922Sariff		i = 0;
3930162922Sariff		if (!(devinfo->function.audio.quirks & HDA_QUIRK_FORCESTEREO))
3931162922Sariff			ch->fmtlist[i++] = AFMT_S16_LE;
3932162922Sariff		ch->fmtlist[i++] = AFMT_S16_LE | AFMT_STEREO;
3933162922Sariff		if (ch->bit32 > 0) {
3934162922Sariff			if (!(devinfo->function.audio.quirks &
3935162922Sariff			    HDA_QUIRK_FORCESTEREO))
3936162922Sariff				ch->fmtlist[i++] = AFMT_S32_LE;
3937162922Sariff			ch->fmtlist[i++] = AFMT_S32_LE | AFMT_STEREO;
3938162922Sariff		}
3939162922Sariff		ch->fmtlist[i] = 0;
3940162922Sariff		i = 0;
3941162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
3942162922Sariff			ch->pcmrates[i++] = 8000;
3943162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
3944162922Sariff			ch->pcmrates[i++] = 11025;
3945162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
3946162922Sariff			ch->pcmrates[i++] = 16000;
3947162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
3948162922Sariff			ch->pcmrates[i++] = 22050;
3949162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
3950162922Sariff			ch->pcmrates[i++] = 32000;
3951162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
3952162922Sariff			ch->pcmrates[i++] = 44100;
3953162922Sariff		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_48KHZ(cap)) */
3954162922Sariff		ch->pcmrates[i++] = 48000;
3955162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
3956162922Sariff			ch->pcmrates[i++] = 88200;
3957162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
3958162922Sariff			ch->pcmrates[i++] = 96000;
3959162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
3960162922Sariff			ch->pcmrates[i++] = 176400;
3961162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
3962162922Sariff			ch->pcmrates[i++] = 192000;
3963162922Sariff		/* if (HDA_PARAM_SUPP_PCM_SIZE_RATE_384KHZ(cap)) */
3964162922Sariff		ch->pcmrates[i] = 0;
3965162922Sariff		if (i > 0) {
3966162922Sariff			ch->caps.minspeed = ch->pcmrates[0];
3967162922Sariff			ch->caps.maxspeed = ch->pcmrates[i - 1];
3968162922Sariff		}
3969162922Sariff	}
3970162922Sariff
3971162922Sariff	return (ret);
3972162922Sariff}
3973162922Sariff
3974162922Sariffstatic void
3975162922Sariffhdac_dump_ctls(struct hdac_devinfo *devinfo, const char *banner, uint32_t flag)
3976162922Sariff{
3977162922Sariff	struct hdac_audio_ctl *ctl;
3978162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
3979162922Sariff	int i;
3980162922Sariff	uint32_t fl = 0;
3981162922Sariff
3982162922Sariff
3983162922Sariff	if (flag == 0) {
3984162922Sariff		fl = SOUND_MASK_VOLUME | SOUND_MASK_PCM |
3985162922Sariff		    SOUND_MASK_CD | SOUND_MASK_LINE | SOUND_MASK_RECLEV |
3986162922Sariff		    SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_OGAIN;
3987162922Sariff	}
3988162922Sariff
3989162922Sariff	i = 0;
3990162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
3991162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL ||
3992162922Sariff		    ctl->widget->enable == 0)
3993162922Sariff			continue;
3994162922Sariff		if ((flag == 0 && (ctl->ossmask & ~fl)) ||
3995162922Sariff		    (flag != 0 && (ctl->ossmask & flag))) {
3996162922Sariff			if (banner != NULL) {
3997162922Sariff				device_printf(sc->dev, "\n");
3998162922Sariff				device_printf(sc->dev, "%s\n", banner);
3999162922Sariff			}
4000162922Sariff			goto hdac_ctl_dump_it_all;
4001162922Sariff		}
4002162922Sariff	}
4003162922Sariff
4004162922Sariff	return;
4005162922Sariff
4006162922Sariffhdac_ctl_dump_it_all:
4007162922Sariff	i = 0;
4008162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4009162922Sariff		if (ctl->enable == 0 || ctl->widget == NULL ||
4010162922Sariff		    ctl->widget->enable == 0)
4011162922Sariff			continue;
4012162922Sariff		if (!((flag == 0 && (ctl->ossmask & ~fl)) ||
4013162922Sariff		    (flag != 0 && (ctl->ossmask & flag))))
4014162922Sariff			continue;
4015162922Sariff		if (flag == 0) {
4016162922Sariff			device_printf(sc->dev, "\n");
4017162922Sariff			device_printf(sc->dev, "Unknown Ctl (OSS: %s)\n",
4018162922Sariff			    hdac_audio_ctl_ossmixer_mask2name(ctl->ossmask));
4019162922Sariff		}
4020162922Sariff		device_printf(sc->dev, "   |\n");
4021162922Sariff		device_printf(sc->dev, "   +-  nid: %2d index: %2d ",
4022162922Sariff		    ctl->widget->nid, ctl->index);
4023162922Sariff		if (ctl->childwidget != NULL)
4024162922Sariff			printf("(nid: %2d) ", ctl->childwidget->nid);
4025162922Sariff		else
4026162922Sariff			printf("          ");
4027162922Sariff		printf("mute: %d step: %3d size: %3d off: %3d dir=0x%x ossmask=0x%08x\n",
4028162922Sariff		    ctl->mute, ctl->step, ctl->size, ctl->offset, ctl->dir,
4029162922Sariff		    ctl->ossmask);
4030162922Sariff	}
4031162922Sariff}
4032162922Sariff
4033162922Sariffstatic void
4034162922Sariffhdac_dump_audio_formats(struct hdac_softc *sc, uint32_t fcap, uint32_t pcmcap)
4035162922Sariff{
4036162922Sariff	uint32_t cap;
4037162922Sariff
4038162922Sariff	cap = fcap;
4039162922Sariff	if (cap != 0) {
4040162922Sariff		device_printf(sc->dev, "     Stream cap: 0x%08x\n", cap);
4041162922Sariff		device_printf(sc->dev, "         Format:");
4042162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_AC3(cap))
4043162922Sariff			printf(" AC3");
4044162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_FLOAT32(cap))
4045162922Sariff			printf(" FLOAT32");
4046162922Sariff		if (HDA_PARAM_SUPP_STREAM_FORMATS_PCM(cap))
4047162922Sariff			printf(" PCM");
4048162922Sariff		printf("\n");
4049162922Sariff	}
4050162922Sariff	cap = pcmcap;
4051162922Sariff	if (cap != 0) {
4052162922Sariff		device_printf(sc->dev, "        PCM cap: 0x%08x\n", cap);
4053162922Sariff		device_printf(sc->dev, "       PCM size:");
4054162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8BIT(cap))
4055162922Sariff			printf(" 8");
4056162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16BIT(cap))
4057162922Sariff			printf(" 16");
4058162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_20BIT(cap))
4059162922Sariff			printf(" 20");
4060162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_24BIT(cap))
4061162922Sariff			printf(" 24");
4062162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32BIT(cap))
4063162922Sariff			printf(" 32");
4064162922Sariff		printf("\n");
4065162922Sariff		device_printf(sc->dev, "       PCM rate:");
4066162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_8KHZ(cap))
4067162922Sariff			printf(" 8");
4068162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_11KHZ(cap))
4069162922Sariff			printf(" 11");
4070162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_16KHZ(cap))
4071162922Sariff			printf(" 16");
4072162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_22KHZ(cap))
4073162922Sariff			printf(" 22");
4074162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_32KHZ(cap))
4075162922Sariff			printf(" 32");
4076162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_44KHZ(cap))
4077162922Sariff			printf(" 44");
4078162922Sariff		printf(" 48");
4079162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_88KHZ(cap))
4080162922Sariff			printf(" 88");
4081162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_96KHZ(cap))
4082162922Sariff			printf(" 96");
4083162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_176KHZ(cap))
4084162922Sariff			printf(" 176");
4085162922Sariff		if (HDA_PARAM_SUPP_PCM_SIZE_RATE_192KHZ(cap))
4086162922Sariff			printf(" 192");
4087162922Sariff		printf("\n");
4088162922Sariff	}
4089162922Sariff}
4090162922Sariff
4091162922Sariffstatic void
4092162922Sariffhdac_dump_pin(struct hdac_softc *sc, struct hdac_widget *w)
4093162922Sariff{
4094162922Sariff	uint32_t pincap, wcap;
4095162922Sariff
4096162922Sariff	pincap = w->wclass.pin.cap;
4097162922Sariff	wcap = w->param.widget_cap;
4098162922Sariff
4099162922Sariff	device_printf(sc->dev, "        Pin cap: 0x%08x\n", pincap);
4100162922Sariff	device_printf(sc->dev, "                ");
4101162922Sariff	if (HDA_PARAM_PIN_CAP_IMP_SENSE_CAP(pincap))
4102162922Sariff		printf(" ISC");
4103162922Sariff	if (HDA_PARAM_PIN_CAP_TRIGGER_REQD(pincap))
4104162922Sariff		printf(" TRQD");
4105162922Sariff	if (HDA_PARAM_PIN_CAP_PRESENCE_DETECT_CAP(pincap))
4106162922Sariff		printf(" PDC");
4107162922Sariff	if (HDA_PARAM_PIN_CAP_HEADPHONE_CAP(pincap))
4108162922Sariff		printf(" HP");
4109162922Sariff	if (HDA_PARAM_PIN_CAP_OUTPUT_CAP(pincap))
4110162922Sariff		printf(" OUT");
4111162922Sariff	if (HDA_PARAM_PIN_CAP_INPUT_CAP(pincap))
4112162922Sariff		printf(" IN");
4113162922Sariff	if (HDA_PARAM_PIN_CAP_BALANCED_IO_PINS(pincap))
4114162922Sariff		printf(" BAL");
4115162922Sariff	if (HDA_PARAM_PIN_CAP_EAPD_CAP(pincap))
4116162922Sariff		printf(" EAPD");
4117162922Sariff	if (HDA_PARAM_AUDIO_WIDGET_CAP_UNSOL_CAP(wcap))
4118162922Sariff		printf(" : UNSOL");
4119162922Sariff	printf("\n");
4120162922Sariff	device_printf(sc->dev, "     Pin config: 0x%08x\n",
4121162922Sariff	    w->wclass.pin.config);
4122162922Sariff	device_printf(sc->dev, "    Pin control: 0x%08x", w->wclass.pin.ctrl);
4123162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_HPHN_ENABLE)
4124162922Sariff		printf(" HP");
4125162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_IN_ENABLE)
4126162922Sariff		printf(" IN");
4127162922Sariff	if (w->wclass.pin.ctrl & HDA_CMD_SET_PIN_WIDGET_CTRL_OUT_ENABLE)
4128162922Sariff		printf(" OUT");
4129162922Sariff	printf("\n");
4130162922Sariff}
4131162922Sariff
4132162922Sariffstatic void
4133162922Sariffhdac_dump_amp(struct hdac_softc *sc, uint32_t cap, char *banner)
4134162922Sariff{
4135162922Sariff	device_printf(sc->dev, "     %s amp: 0x%0x\n", banner, cap);
4136162922Sariff	device_printf(sc->dev, "                 "
4137162922Sariff	    "mute=%d step=%d size=%d offset=%d\n",
4138162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_MUTE_CAP(cap),
4139162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS(cap),
4140162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE(cap),
4141162922Sariff	    HDA_PARAM_OUTPUT_AMP_CAP_OFFSET(cap));
4142162922Sariff}
4143162922Sariff
4144162922Sariffstatic void
4145162922Sariffhdac_dump_nodes(struct hdac_devinfo *devinfo)
4146162922Sariff{
4147162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4148162922Sariff	struct hdac_widget *w, *cw;
4149162922Sariff	int i, j;
4150162922Sariff
4151162922Sariff	device_printf(sc->dev, "\n");
4152162922Sariff	device_printf(sc->dev, "Default Parameter\n");
4153162922Sariff	device_printf(sc->dev, "-----------------\n");
4154162922Sariff	hdac_dump_audio_formats(sc,
4155162922Sariff	    devinfo->function.audio.supp_stream_formats,
4156162922Sariff	    devinfo->function.audio.supp_pcm_size_rate);
4157162922Sariff	device_printf(sc->dev, "         IN amp: 0x%08x\n",
4158162922Sariff	    devinfo->function.audio.inamp_cap);
4159162922Sariff	device_printf(sc->dev, "        OUT amp: 0x%08x\n",
4160162922Sariff	    devinfo->function.audio.outamp_cap);
4161162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4162162922Sariff		w = hdac_widget_get(devinfo, i);
4163162922Sariff		if (w == NULL) {
4164162922Sariff			device_printf(sc->dev, "Ghost widget nid=%d\n", i);
4165162922Sariff			continue;
4166162922Sariff		}
4167162922Sariff		device_printf(sc->dev, "\n");
4168162922Sariff		device_printf(sc->dev, "            nid: %d [%s]%s\n", w->nid,
4169162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap) ?
4170162922Sariff		    "DIGITAL" : "ANALOG",
4171162922Sariff		    (w->enable == 0) ? " [DISABLED]" : "");
4172162922Sariff		device_printf(sc->dev, "           name: %s\n", w->name);
4173162922Sariff		device_printf(sc->dev, "     widget_cap: 0x%08x\n",
4174162922Sariff		    w->param.widget_cap);
4175162922Sariff		device_printf(sc->dev, "    Parse flags: 0x%08x\n",
4176162922Sariff		    w->pflags);
4177162922Sariff		device_printf(sc->dev, "      Ctl flags: 0x%08x\n",
4178162922Sariff		    w->ctlflags);
4179162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_OUTPUT ||
4180162922Sariff		    w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_INPUT) {
4181162922Sariff			hdac_dump_audio_formats(sc,
4182162922Sariff			    w->param.supp_stream_formats,
4183162922Sariff			    w->param.supp_pcm_size_rate);
4184162922Sariff		} else if (w->type ==
4185162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
4186162922Sariff			hdac_dump_pin(sc, w);
4187162965Sariff		if (w->param.eapdbtl != HDAC_INVALID)
4188162922Sariff			device_printf(sc->dev, "           EAPD: 0x%08x\n",
4189162922Sariff			    w->param.eapdbtl);
4190162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_OUT_AMP(w->param.widget_cap))
4191162922Sariff			hdac_dump_amp(sc, w->param.outamp_cap, "Output");
4192162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_IN_AMP(w->param.widget_cap))
4193162922Sariff			hdac_dump_amp(sc, w->param.inamp_cap, " Input");
4194162922Sariff		device_printf(sc->dev, "    connections: %d\n", w->nconns);
4195162922Sariff		for (j = 0; j < w->nconns; j++) {
4196162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
4197162922Sariff			device_printf(sc->dev, "          |\n");
4198162922Sariff			device_printf(sc->dev, "          + <- nid=%d [%s]",
4199162922Sariff			    w->conns[j], (cw == NULL) ? "GHOST!" : cw->name);
4200162922Sariff			if (cw == NULL)
4201162922Sariff				printf(" [UNKNOWN]");
4202162922Sariff			else if (cw->enable == 0)
4203162922Sariff				printf(" [DISABLED]");
4204162922Sariff			if (w->nconns > 1 && w->selconn == j && w->type !=
4205162922Sariff			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_AUDIO_MIXER)
4206162922Sariff				printf(" (selected)");
4207162922Sariff			printf("\n");
4208162922Sariff		}
4209162922Sariff	}
4210162922Sariff
4211162922Sariff}
4212162922Sariff
4213162922Sariffstatic void
4214162922Sariffhdac_dump_dac(struct hdac_devinfo *devinfo)
4215162922Sariff{
4216162922Sariff	/* XXX TODO */
4217162922Sariff}
4218162922Sariff
4219162922Sariffstatic void
4220162922Sariffhdac_dump_adc(struct hdac_devinfo *devinfo)
4221162922Sariff{
4222162922Sariff	struct hdac_widget *w, *cw;
4223162922Sariff	struct hdac_softc *sc = devinfo->codec->sc;
4224162922Sariff	int i, j;
4225162922Sariff	int printed = 0;
4226162922Sariff	char ossdevs[256];
4227162922Sariff
4228162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4229162922Sariff		w = hdac_widget_get(devinfo, i);
4230162922Sariff		if (w == NULL || w->enable == 0)
4231162922Sariff			continue;
4232162922Sariff		if (!(w->pflags & HDA_ADC_RECSEL))
4233162922Sariff			continue;
4234162922Sariff		if (printed == 0) {
4235162922Sariff			printed = 1;
4236162922Sariff			device_printf(sc->dev, "\n");
4237162922Sariff			device_printf(sc->dev, "Recording sources:\n");
4238162922Sariff		}
4239162922Sariff		device_printf(sc->dev, "\n");
4240162922Sariff		device_printf(sc->dev, "    nid=%d [%s]\n", w->nid, w->name);
4241162922Sariff		for (j = 0; j < w->nconns; j++) {
4242162922Sariff			cw = hdac_widget_get(devinfo, w->conns[j]);
4243162922Sariff			if (cw == NULL || cw->enable == 0)
4244162922Sariff				continue;
4245162922Sariff			hdac_audio_ctl_ossmixer_mask2allname(cw->ctlflags,
4246162922Sariff			    ossdevs, sizeof(ossdevs));
4247162922Sariff			device_printf(sc->dev, "      |\n");
4248162922Sariff			device_printf(sc->dev, "      + <- nid=%d [%s]",
4249162922Sariff			    cw->nid, cw->name);
4250162922Sariff			if (strlen(ossdevs) > 0) {
4251162922Sariff				printf(" [recsrc: %s]", ossdevs);
4252162922Sariff			}
4253162922Sariff			printf("\n");
4254162922Sariff		}
4255162922Sariff	}
4256162922Sariff}
4257162922Sariff
4258162922Sariffstatic void
4259162922Sariffhdac_dump_pcmchannels(struct hdac_softc *sc, int pcnt, int rcnt)
4260162922Sariff{
4261162922Sariff	nid_t *nids;
4262162922Sariff
4263162922Sariff	if (pcnt > 0) {
4264162922Sariff		device_printf(sc->dev, "\n");
4265162922Sariff		device_printf(sc->dev, "   PCM Playback: %d\n", pcnt);
4266162922Sariff		hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
4267162922Sariff		    sc->play.supp_pcm_size_rate);
4268162922Sariff		device_printf(sc->dev, "            DAC:");
4269162922Sariff		for (nids = sc->play.io; *nids != -1; nids++)
4270162922Sariff			printf(" %d", *nids);
4271162922Sariff		printf("\n");
4272162922Sariff	}
4273162922Sariff
4274162922Sariff	if (rcnt > 0) {
4275162922Sariff		device_printf(sc->dev, "\n");
4276162922Sariff		device_printf(sc->dev, "     PCM Record: %d\n", rcnt);
4277162922Sariff		hdac_dump_audio_formats(sc, sc->play.supp_stream_formats,
4278162922Sariff		    sc->rec.supp_pcm_size_rate);
4279162922Sariff		device_printf(sc->dev, "            ADC:");
4280162922Sariff		for (nids = sc->rec.io; *nids != -1; nids++)
4281162922Sariff			printf(" %d", *nids);
4282162922Sariff		printf("\n");
4283162922Sariff	}
4284162922Sariff}
4285162922Sariff
4286162922Sariffstatic void
4287162922Sariffhdac_attach2(void *arg)
4288162922Sariff{
4289162922Sariff	struct hdac_softc *sc;
4290162922Sariff	struct hdac_widget *w;
4291162922Sariff	struct hdac_audio_ctl *ctl;
4292162922Sariff	int pcnt, rcnt;
4293162922Sariff	int i;
4294162922Sariff	char status[SND_STATUSLEN];
4295162965Sariff	device_t *devlist = NULL;
4296162922Sariff	int devcount;
4297162922Sariff	struct hdac_devinfo *devinfo = NULL;
4298162922Sariff
4299162922Sariff	sc = (struct hdac_softc *)arg;
4300162922Sariff
4301162922Sariff
4302162922Sariff	hdac_lock(sc);
4303162922Sariff
4304162922Sariff	/* Remove ourselves from the config hooks */
4305162922Sariff	if (sc->intrhook.ich_func != NULL) {
4306162922Sariff		config_intrhook_disestablish(&sc->intrhook);
4307162922Sariff		sc->intrhook.ich_func = NULL;
4308162922Sariff	}
4309162922Sariff
4310162922Sariff	/* Start the corb and rirb engines */
4311162922Sariff	HDA_DEBUG_MSG(
4312162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Starting CORB Engine...\n");
4313162922Sariff	);
4314162922Sariff	hdac_corb_start(sc);
4315162922Sariff	HDA_DEBUG_MSG(
4316162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Starting RIRB Engine...\n");
4317162922Sariff	);
4318162922Sariff	hdac_rirb_start(sc);
4319162922Sariff
4320162922Sariff	HDA_DEBUG_MSG(
4321162922Sariff		device_printf(sc->dev,
4322162922Sariff		    "HDA_DEBUG: Enabling controller interrupt...\n");
4323162922Sariff	);
4324162922Sariff	HDAC_WRITE_4(&sc->mem, HDAC_INTCTL, HDAC_INTCTL_CIE | HDAC_INTCTL_GIE);
4325162922Sariff
4326162922Sariff	DELAY(1000);
4327162922Sariff
4328162922Sariff	HDA_DEBUG_MSG(
4329162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Scanning HDA codecs...\n");
4330162922Sariff	);
4331162922Sariff	hdac_scan_codecs(sc);
4332162922Sariff
4333162922Sariff	device_get_children(sc->dev, &devlist, &devcount);
4334162965Sariff	for (i = 0; devlist != NULL && i < devcount; i++) {
4335162965Sariff		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
4336162965Sariff		if (devinfo != NULL && devinfo->node_type ==
4337162965Sariff		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO) {
4338162965Sariff			break;
4339162965Sariff		} else
4340162965Sariff			devinfo = NULL;
4341162922Sariff	}
4342162965Sariff	if (devlist != NULL)
4343162965Sariff		free(devlist, M_TEMP);
4344162922Sariff
4345162922Sariff	if (devinfo == NULL) {
4346162922Sariff		hdac_unlock(sc);
4347162922Sariff		device_printf(sc->dev, "Audio Function Group not found!\n");
4348162922Sariff		return;
4349162922Sariff	}
4350162922Sariff
4351162922Sariff	HDA_DEBUG_MSG(
4352162922Sariff		device_printf(sc->dev,
4353162922Sariff		    "HDA_DEBUG: Parsing AFG nid=%d cad=%d\n",
4354162922Sariff		    devinfo->nid, devinfo->codec->cad);
4355162922Sariff	);
4356162922Sariff	hdac_audio_parse(devinfo);
4357162922Sariff	HDA_DEBUG_MSG(
4358162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Parsing Ctls...\n");
4359162922Sariff	);
4360162922Sariff	hdac_audio_ctl_parse(devinfo);
4361162922Sariff	HDA_DEBUG_MSG(
4362162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Parsing vendor patch...\n");
4363162922Sariff	);
4364162922Sariff	hdac_vendor_patch_parse(devinfo);
4365162922Sariff
4366162922Sariff	/* XXX Disable all DIGITAL path. */
4367162922Sariff	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
4368162922Sariff		w = hdac_widget_get(devinfo, i);
4369162922Sariff		if (w == NULL)
4370162922Sariff			continue;
4371162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap)) {
4372162922Sariff			w->enable = 0;
4373162922Sariff			continue;
4374162922Sariff		}
4375162922Sariff		/* XXX Disable useless pin ? */
4376162922Sariff		if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
4377162922Sariff		    (w->wclass.pin.config &
4378162922Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) ==
4379162922Sariff		    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
4380162922Sariff			w->enable = 0;
4381162922Sariff	}
4382162922Sariff	i = 0;
4383162922Sariff	while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4384162922Sariff		if (ctl->widget == NULL)
4385162922Sariff			continue;
4386162922Sariff		w = ctl->widget;
4387162922Sariff		if (w->enable == 0)
4388162922Sariff			ctl->enable = 0;
4389162922Sariff		if (HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
4390162922Sariff			ctl->enable = 0;
4391162922Sariff		w = ctl->childwidget;
4392162922Sariff		if (w == NULL)
4393162922Sariff			continue;
4394162922Sariff		if (w->enable == 0 ||
4395162922Sariff		    HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL(w->param.widget_cap))
4396162922Sariff			ctl->enable = 0;
4397162922Sariff	}
4398162922Sariff
4399162922Sariff	HDA_DEBUG_MSG(
4400162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Building AFG tree...\n");
4401162922Sariff	);
4402162922Sariff	hdac_audio_build_tree(devinfo);
4403162922Sariff
4404162922Sariff	HDA_DEBUG_MSG(
4405162922Sariff		device_printf(sc->dev, "HDA_DEBUG: AFG commit...\n");
4406162922Sariff	);
4407162922Sariff	hdac_audio_commit(devinfo, HDA_COMMIT_ALL);
4408162922Sariff	HDA_DEBUG_MSG(
4409162922Sariff		device_printf(sc->dev, "HDA_DEBUG: Ctls commit...\n");
4410162922Sariff	);
4411162922Sariff	hdac_audio_ctl_commit(devinfo);
4412162922Sariff
4413162922Sariff	HDA_DEBUG_MSG(
4414162922Sariff		device_printf(sc->dev, "HDA_DEBUG: PCMDIR_PLAY setup...\n");
4415162922Sariff	);
4416162922Sariff	pcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_PLAY);
4417162922Sariff	HDA_DEBUG_MSG(
4418162922Sariff		device_printf(sc->dev, "HDA_DEBUG: PCMDIR_REC setup...\n");
4419162922Sariff	);
4420162922Sariff	rcnt = hdac_pcmchannel_setup(devinfo, PCMDIR_REC);
4421162922Sariff
4422162922Sariff	hdac_unlock(sc);
4423162922Sariff	HDA_DEBUG_MSG(
4424162922Sariff		device_printf(sc->dev,
4425162922Sariff		    "HDA_DEBUG: OSS mixer initialization...\n");
4426162922Sariff	);
4427162922Sariff	if (mixer_init(sc->dev, &hdac_audio_ctl_ossmixer_class, devinfo)) {
4428162922Sariff		device_printf(sc->dev, "Can't register mixer\n");
4429162922Sariff	}
4430162922Sariff
4431162922Sariff	if (pcnt > 0)
4432162922Sariff		pcnt = 1;
4433162922Sariff	if (rcnt > 0)
4434162922Sariff		rcnt = 1;
4435162922Sariff
4436162922Sariff	HDA_DEBUG_MSG(
4437162922Sariff		device_printf(sc->dev,
4438162922Sariff		    "HDA_DEBUG: Registering PCM channels...\n");
4439162922Sariff	);
4440162922Sariff	if (pcm_register(sc->dev, devinfo, pcnt, rcnt)) {
4441162922Sariff		device_printf(sc->dev, "Can't register PCM\n");
4442162922Sariff	}
4443162922Sariff
4444162922Sariff	sc->registered++;
4445162922Sariff
4446162922Sariff	for (i = 0; i < pcnt; i++)
4447162922Sariff		pcm_addchan(sc->dev, PCMDIR_PLAY, &hdac_channel_class, devinfo);
4448162922Sariff	for (i = 0; i < rcnt; i++)
4449162922Sariff		pcm_addchan(sc->dev, PCMDIR_REC, &hdac_channel_class, devinfo);
4450162922Sariff
4451162922Sariff	snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s [%s]",
4452162922Sariff			rman_get_start(sc->mem.mem_res),
4453162922Sariff			rman_get_start(sc->irq.irq_res),
4454162922Sariff			PCM_KLDSTRING(snd_hda), HDA_DRV_TEST_REV);
4455162922Sariff	pcm_setstatus(sc->dev, status);
4456162922Sariff	device_printf(sc->dev, "<HDA Codec: %s>\n", hdac_codec_name(devinfo));
4457162922Sariff	device_printf(sc->dev, "<HDA Driver Revision: %s>\n", HDA_DRV_TEST_REV);
4458162922Sariff
4459162922Sariff	HDA_BOOTVERBOSE_MSG(
4460162922Sariff		if (devinfo->function.audio.quirks != 0) {
4461162922Sariff			device_printf(sc->dev, "\n");
4462162922Sariff			device_printf(sc->dev, "HDA quirks:");
4463162922Sariff			if (devinfo->function.audio.quirks &
4464162922Sariff			    HDA_QUIRK_GPIO1)
4465162922Sariff				printf(" GPIO1");
4466162922Sariff			if (devinfo->function.audio.quirks &
4467162922Sariff			    HDA_QUIRK_GPIO2)
4468162922Sariff				printf(" GPIO2");
4469162922Sariff			if (devinfo->function.audio.quirks &
4470162922Sariff			    HDA_QUIRK_SOFTPCMVOL)
4471162922Sariff				printf(" SOFTPCMVOL");
4472162922Sariff			if (devinfo->function.audio.quirks &
4473162922Sariff			    HDA_QUIRK_FIXEDRATE)
4474162922Sariff				printf(" FIXEDRATE");
4475162922Sariff			if (devinfo->function.audio.quirks &
4476162922Sariff			    HDA_QUIRK_FORCESTEREO)
4477162922Sariff				printf(" FORCESTEREO");
4478162922Sariff			printf("\n");
4479162922Sariff		}
4480162922Sariff		device_printf(sc->dev, "\n");
4481162922Sariff		device_printf(sc->dev, "+-------------------+\n");
4482162922Sariff		device_printf(sc->dev, "| DUMPING HDA NODES |\n");
4483162922Sariff		device_printf(sc->dev, "+-------------------+\n");
4484162922Sariff		hdac_dump_nodes(devinfo);
4485162922Sariff		device_printf(sc->dev, "\n");
4486162922Sariff		device_printf(sc->dev, "+------------------------+\n");
4487162922Sariff		device_printf(sc->dev, "| DUMPING HDA AMPLIFIERS |\n");
4488162922Sariff		device_printf(sc->dev, "+------------------------+\n");
4489162922Sariff		device_printf(sc->dev, "\n");
4490162922Sariff		i = 0;
4491162922Sariff		while ((ctl = hdac_audio_ctl_each(devinfo, &i)) != NULL) {
4492162922Sariff			device_printf(sc->dev, "%3d: nid=%d", i,
4493162922Sariff			    (ctl->widget != NULL) ? ctl->widget->nid : -1);
4494162922Sariff			if (ctl->childwidget != NULL)
4495162922Sariff				printf(" cnid=%d", ctl->childwidget->nid);
4496162922Sariff			printf(" dir=0x%x index=%d "
4497162922Sariff			    "ossmask=0x%08x ossdev=%d%s\n",
4498162922Sariff			    ctl->dir, ctl->index,
4499162922Sariff			    ctl->ossmask, ctl->ossdev,
4500162922Sariff			    (ctl->enable == 0) ? " [DISABLED]" : "");
4501162922Sariff		}
4502162922Sariff		device_printf(sc->dev, "\n");
4503162922Sariff		device_printf(sc->dev, "+-----------------------------------+\n");
4504162922Sariff		device_printf(sc->dev, "| DUMPING HDA AUDIO/VOLUME CONTROLS |\n");
4505162922Sariff		device_printf(sc->dev, "+-----------------------------------+\n");
4506162922Sariff		hdac_dump_ctls(devinfo, "Master Volume (OSS: vol)", SOUND_MASK_VOLUME);
4507162922Sariff		hdac_dump_ctls(devinfo, "PCM Volume (OSS: pcm)", SOUND_MASK_PCM);
4508162922Sariff		hdac_dump_ctls(devinfo, "CD Volume (OSS: cd)", SOUND_MASK_CD);
4509162922Sariff		hdac_dump_ctls(devinfo, "Microphone Volume (OSS: mic)", SOUND_MASK_MIC);
4510162922Sariff		hdac_dump_ctls(devinfo, "Line-in Volume (OSS: line)", SOUND_MASK_LINE);
4511162922Sariff		hdac_dump_ctls(devinfo, "Recording Level (OSS: rec)", SOUND_MASK_RECLEV);
4512162922Sariff		hdac_dump_ctls(devinfo, "Speaker/Beep (OSS: speaker)", SOUND_MASK_SPEAKER);
4513162922Sariff		hdac_dump_ctls(devinfo, NULL, 0);
4514162922Sariff		hdac_dump_dac(devinfo);
4515162922Sariff		hdac_dump_adc(devinfo);
4516162922Sariff		device_printf(sc->dev, "\n");
4517162922Sariff		device_printf(sc->dev, "+--------------------------------------+\n");
4518162922Sariff		device_printf(sc->dev, "| DUMPING PCM Playback/Record Channels |\n");
4519162922Sariff		device_printf(sc->dev, "+--------------------------------------+\n");
4520162922Sariff		hdac_dump_pcmchannels(sc, pcnt, rcnt);
4521162922Sariff	);
4522162922Sariff}
4523162922Sariff
4524162922Sariff/****************************************************************************
4525162922Sariff * int hdac_detach(device_t)
4526162922Sariff *
4527162922Sariff * Detach and free up resources utilized by the hdac device.
4528162922Sariff ****************************************************************************/
4529162922Sariffstatic int
4530162922Sariffhdac_detach(device_t dev)
4531162922Sariff{
4532162922Sariff	struct hdac_softc *sc = NULL;
4533162965Sariff	device_t *devlist = NULL;
4534162922Sariff	int devcount;
4535162922Sariff	struct hdac_devinfo *devinfo = NULL;
4536162965Sariff	struct hdac_codec *codec;
4537162922Sariff	int i;
4538162922Sariff
4539162922Sariff	devinfo = (struct hdac_devinfo *)pcm_getdevinfo(dev);
4540162922Sariff	if (devinfo != NULL && devinfo->codec != NULL)
4541162922Sariff		sc = devinfo->codec->sc;
4542162922Sariff	if (sc == NULL)
4543162922Sariff		return (EINVAL);
4544162922Sariff
4545162922Sariff	if (sc->registered > 0) {
4546162922Sariff		i = pcm_unregister(dev);
4547162922Sariff		if (i)
4548162922Sariff			return (i);
4549162922Sariff	}
4550162922Sariff
4551162922Sariff	sc->registered = 0;
4552162922Sariff
4553162922Sariff	/* Lock the mutex before messing with the dma engines */
4554162922Sariff	hdac_lock(sc);
4555162922Sariff	hdac_reset(sc);
4556162922Sariff	hdac_unlock(sc);
4557162922Sariff	snd_mtxfree(sc->lock);
4558162922Sariff	sc->lock = NULL;
4559162922Sariff
4560162922Sariff	device_get_children(sc->dev, &devlist, &devcount);
4561162965Sariff	for (i = 0; devlist != NULL && i < devcount; i++) {
4562162965Sariff		devinfo = (struct hdac_devinfo *)device_get_ivars(devlist[i]);
4563162965Sariff		if (devinfo == NULL)
4564162965Sariff			continue;
4565162965Sariff		if (devinfo->widget != NULL)
4566162965Sariff			free(devinfo->widget, M_HDAC);
4567162965Sariff		if (devinfo->node_type ==
4568162965Sariff		    HDA_PARAM_FCT_GRP_TYPE_NODE_TYPE_AUDIO &&
4569162965Sariff		    devinfo->function.audio.ctl != NULL)
4570162965Sariff			free(devinfo->function.audio.ctl, M_HDAC);
4571162965Sariff		free(devinfo, M_HDAC);
4572162965Sariff		device_delete_child(sc->dev, devlist[i]);
4573162965Sariff	}
4574162965Sariff	if (devlist != NULL)
4575162922Sariff		free(devlist, M_TEMP);
4576162922Sariff
4577162965Sariff	while (!SLIST_EMPTY(&sc->codec_list)) {
4578162965Sariff		codec = SLIST_FIRST(&sc->codec_list);
4579162965Sariff		SLIST_REMOVE_HEAD(&sc->codec_list, next_codec);
4580162965Sariff		free(codec, M_HDAC);
4581162922Sariff	}
4582162922Sariff
4583162922Sariff	hdac_dma_free(&sc->rirb_dma);
4584162922Sariff	hdac_dma_free(&sc->corb_dma);
4585162922Sariff	if (sc->play.blkcnt)
4586162922Sariff		hdac_dma_free(&sc->play.bdl_dma);
4587162922Sariff	if (sc->rec.blkcnt)
4588162922Sariff		hdac_dma_free(&sc->rec.bdl_dma);
4589162922Sariff	hdac_irq_free(sc);
4590162922Sariff	hdac_mem_free(sc);
4591162922Sariff	free(sc, M_DEVBUF);
4592162922Sariff
4593162922Sariff	return (0);
4594162922Sariff}
4595162922Sariff
4596162922Sariffstatic device_method_t hdac_methods[] = {
4597162922Sariff	/* device interface */
4598162922Sariff	DEVMETHOD(device_probe,		hdac_probe),
4599162922Sariff	DEVMETHOD(device_attach,	hdac_attach),
4600162922Sariff	DEVMETHOD(device_detach,	hdac_detach),
4601162922Sariff	{ 0, 0 }
4602162922Sariff};
4603162922Sariff
4604162922Sariffstatic driver_t hdac_driver = {
4605162922Sariff	"pcm",
4606162922Sariff	hdac_methods,
4607162922Sariff	PCM_SOFTC_SIZE,
4608162922Sariff};
4609162922Sariff
4610162922SariffDRIVER_MODULE(snd_hda, pci, hdac_driver, pcm_devclass, 0, 0);
4611162922SariffMODULE_DEPEND(snd_hda, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
4612162922SariffMODULE_VERSION(snd_hda, 1);
4613