VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/HDACodec.cpp@ 85546

Last change on this file since 85546 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 137.1 KB
Line 
1/* $Id: HDACodec.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * HDACodec - VBox HD Audio Codec.
4 *
5 * Implemented based on the Intel HD Audio specification and the
6 * Sigmatel/IDT STAC9220 datasheet.
7 */
8
9/*
10 * Copyright (C) 2006-2020 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEV_HDA_CODEC
26#include <VBox/AssertGuest.h>
27#include <VBox/vmm/pdmdev.h>
28#include <VBox/vmm/pdmaudioifs.h>
29#include <iprt/assert.h>
30#include <iprt/uuid.h>
31#include <iprt/string.h>
32#include <iprt/mem.h>
33#include <iprt/asm.h>
34#include <iprt/cpp/utils.h>
35
36#include "VBoxDD.h"
37#include "DrvAudio.h"
38#include "HDACodec.h"
39#include "DevHDACommon.h"
40#include "AudioMixer.h"
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46/* PRM 5.3.1 */
47/** Codec address mask. */
48#define CODEC_CAD_MASK 0xF0000000
49/** Codec address shift. */
50#define CODEC_CAD_SHIFT 28
51#define CODEC_DIRECT_MASK RT_BIT(27)
52/** Node ID mask. */
53#define CODEC_NID_MASK 0x07F00000
54/** Node ID shift. */
55#define CODEC_NID_SHIFT 20
56#define CODEC_VERBDATA_MASK 0x000FFFFF
57#define CODEC_VERB_4BIT_CMD 0x000FFFF0
58#define CODEC_VERB_4BIT_DATA 0x0000000F
59#define CODEC_VERB_8BIT_CMD 0x000FFF00
60#define CODEC_VERB_8BIT_DATA 0x000000FF
61#define CODEC_VERB_16BIT_CMD 0x000F0000
62#define CODEC_VERB_16BIT_DATA 0x0000FFFF
63
64#define CODEC_CAD(cmd) (((cmd) & CODEC_CAD_MASK) >> CODEC_CAD_SHIFT)
65#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK)
66#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT)
67#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK)
68#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x))
69#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4))
70#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8))
71#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16))
72#define CODEC_VERB_PAYLOAD4(cmd) ((cmd) & CODEC_VERB_4BIT_DATA)
73#define CODEC_VERB_PAYLOAD8(cmd) ((cmd) & CODEC_VERB_8BIT_DATA)
74#define CODEC_VERB_PAYLOAD16(cmd) ((cmd) & CODEC_VERB_16BIT_DATA)
75
76#define CODEC_VERB_GET_AMP_DIRECTION RT_BIT(15)
77#define CODEC_VERB_GET_AMP_SIDE RT_BIT(13)
78#define CODEC_VERB_GET_AMP_INDEX 0x7
79
80/* HDA spec 7.3.3.7 NoteA */
81#define CODEC_GET_AMP_DIRECTION(cmd) (((cmd) & CODEC_VERB_GET_AMP_DIRECTION) >> 15)
82#define CODEC_GET_AMP_SIDE(cmd) (((cmd) & CODEC_VERB_GET_AMP_SIDE) >> 13)
83#define CODEC_GET_AMP_INDEX(cmd) (CODEC_GET_AMP_DIRECTION(cmd) ? 0 : ((cmd) & CODEC_VERB_GET_AMP_INDEX))
84
85/* HDA spec 7.3.3.7 NoteC */
86#define CODEC_VERB_SET_AMP_OUT_DIRECTION RT_BIT(15)
87#define CODEC_VERB_SET_AMP_IN_DIRECTION RT_BIT(14)
88#define CODEC_VERB_SET_AMP_LEFT_SIDE RT_BIT(13)
89#define CODEC_VERB_SET_AMP_RIGHT_SIDE RT_BIT(12)
90#define CODEC_VERB_SET_AMP_INDEX (0x7 << 8)
91#define CODEC_VERB_SET_AMP_MUTE RT_BIT(7)
92/** Note: 7-bit value [6:0]. */
93#define CODEC_VERB_SET_AMP_GAIN 0x7F
94
95#define CODEC_SET_AMP_IS_OUT_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_OUT_DIRECTION) != 0)
96#define CODEC_SET_AMP_IS_IN_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_IN_DIRECTION) != 0)
97#define CODEC_SET_AMP_IS_LEFT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_LEFT_SIDE) != 0)
98#define CODEC_SET_AMP_IS_RIGHT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_RIGHT_SIDE) != 0)
99#define CODEC_SET_AMP_INDEX(cmd) (((cmd) & CODEC_VERB_SET_AMP_INDEX) >> 7)
100#define CODEC_SET_AMP_MUTE(cmd) ((cmd) & CODEC_VERB_SET_AMP_MUTE)
101#define CODEC_SET_AMP_GAIN(cmd) ((cmd) & CODEC_VERB_SET_AMP_GAIN)
102
103/* HDA spec 7.3.3.1 defines layout of configuration registers/verbs (0xF00) */
104/* VendorID (7.3.4.1) */
105#define CODEC_MAKE_F00_00(vendorID, deviceID) (((vendorID) << 16) | (deviceID))
106#define CODEC_F00_00_VENDORID(f00_00) (((f00_00) >> 16) & 0xFFFF)
107#define CODEC_F00_00_DEVICEID(f00_00) ((f00_00) & 0xFFFF)
108
109/** RevisionID (7.3.4.2). */
110#define CODEC_MAKE_F00_02(majRev, minRev, venFix, venProg, stepFix, stepProg) \
111 ( (((majRev) & 0xF) << 20) \
112 | (((minRev) & 0xF) << 16) \
113 | (((venFix) & 0xF) << 12) \
114 | (((venProg) & 0xF) << 8) \
115 | (((stepFix) & 0xF) << 4) \
116 | ((stepProg) & 0xF))
117
118/** Subordinate node count (7.3.4.3). */
119#define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF))
120#define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04) (((f00_04) >> 16) & 0xFF)
121#define CODEC_F00_04_TO_NODE_COUNT(f00_04) ((f00_04) & 0xFF)
122/*
123 * Function Group Type (7.3.4.4)
124 * 0 & [0x3-0x7f] are reserved types
125 * [0x80 - 0xff] are vendor defined function groups
126 */
127#define CODEC_MAKE_F00_05(UnSol, NodeType) (((UnSol) << 8)|(NodeType))
128#define CODEC_F00_05_UNSOL RT_BIT(8)
129#define CODEC_F00_05_AFG (0x1)
130#define CODEC_F00_05_MFG (0x2)
131#define CODEC_F00_05_IS_UNSOL(f00_05) RT_BOOL((f00_05) & RT_BIT(8))
132#define CODEC_F00_05_GROUP(f00_05) ((f00_05) & 0xff)
133/* Audio Function Group capabilities (7.3.4.5). */
134#define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF))
135#define CODEC_F00_08_BEEP_GEN(f00_08) ((f00_08) & RT_BIT(16)
136
137/* Converter Stream, Channel (7.3.3.11). */
138#define CODEC_F00_06_GET_STREAM_ID(cmd) (((cmd) >> 4) & 0x0F)
139#define CODEC_F00_06_GET_CHANNEL_ID(cmd) (((cmd) & 0x0F))
140
141/* Widget Capabilities (7.3.4.6). */
142#define CODEC_MAKE_F00_09(type, delay, chan_ext) \
143 ( (((type) & 0xF) << 20) \
144 | (((delay) & 0xF) << 16) \
145 | (((chan_ext) & 0xF) << 13))
146/* note: types 0x8-0xe are reserved */
147#define CODEC_F00_09_TYPE_AUDIO_OUTPUT (0x0)
148#define CODEC_F00_09_TYPE_AUDIO_INPUT (0x1)
149#define CODEC_F00_09_TYPE_AUDIO_MIXER (0x2)
150#define CODEC_F00_09_TYPE_AUDIO_SELECTOR (0x3)
151#define CODEC_F00_09_TYPE_PIN_COMPLEX (0x4)
152#define CODEC_F00_09_TYPE_POWER_WIDGET (0x5)
153#define CODEC_F00_09_TYPE_VOLUME_KNOB (0x6)
154#define CODEC_F00_09_TYPE_BEEP_GEN (0x7)
155#define CODEC_F00_09_TYPE_VENDOR_DEFINED (0xF)
156
157#define CODEC_F00_09_CAP_CP RT_BIT(12)
158#define CODEC_F00_09_CAP_L_R_SWAP RT_BIT(11)
159#define CODEC_F00_09_CAP_POWER_CTRL RT_BIT(10)
160#define CODEC_F00_09_CAP_DIGITAL RT_BIT(9)
161#define CODEC_F00_09_CAP_CONNECTION_LIST RT_BIT(8)
162#define CODEC_F00_09_CAP_UNSOL RT_BIT(7)
163#define CODEC_F00_09_CAP_PROC_WIDGET RT_BIT(6)
164#define CODEC_F00_09_CAP_STRIPE RT_BIT(5)
165#define CODEC_F00_09_CAP_FMT_OVERRIDE RT_BIT(4)
166#define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE RT_BIT(3)
167#define CODEC_F00_09_CAP_OUT_AMP_PRESENT RT_BIT(2)
168#define CODEC_F00_09_CAP_IN_AMP_PRESENT RT_BIT(1)
169#define CODEC_F00_09_CAP_STEREO RT_BIT(0)
170
171#define CODEC_F00_09_TYPE(f00_09) (((f00_09) >> 20) & 0xF)
172
173#define CODEC_F00_09_IS_CAP_CP(f00_09) RT_BOOL((f00_09) & RT_BIT(12))
174#define CODEC_F00_09_IS_CAP_L_R_SWAP(f00_09) RT_BOOL((f00_09) & RT_BIT(11))
175#define CODEC_F00_09_IS_CAP_POWER_CTRL(f00_09) RT_BOOL((f00_09) & RT_BIT(10))
176#define CODEC_F00_09_IS_CAP_DIGITAL(f00_09) RT_BOOL((f00_09) & RT_BIT(9))
177#define CODEC_F00_09_IS_CAP_CONNECTION_LIST(f00_09) RT_BOOL((f00_09) & RT_BIT(8))
178#define CODEC_F00_09_IS_CAP_UNSOL(f00_09) RT_BOOL((f00_09) & RT_BIT(7))
179#define CODEC_F00_09_IS_CAP_PROC_WIDGET(f00_09) RT_BOOL((f00_09) & RT_BIT(6))
180#define CODEC_F00_09_IS_CAP_STRIPE(f00_09) RT_BOOL((f00_09) & RT_BIT(5))
181#define CODEC_F00_09_IS_CAP_FMT_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(4))
182#define CODEC_F00_09_IS_CAP_AMP_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(3))
183#define CODEC_F00_09_IS_CAP_OUT_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(2))
184#define CODEC_F00_09_IS_CAP_IN_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(1))
185#define CODEC_F00_09_IS_CAP_LSB(f00_09) RT_BOOL((f00_09) & RT_BIT(0))
186
187/* Supported PCM size, rates (7.3.4.7) */
188#define CODEC_F00_0A_32_BIT RT_BIT(19)
189#define CODEC_F00_0A_24_BIT RT_BIT(18)
190#define CODEC_F00_0A_16_BIT RT_BIT(17)
191#define CODEC_F00_0A_8_BIT RT_BIT(16)
192
193#define CODEC_F00_0A_48KHZ_MULT_8X RT_BIT(11)
194#define CODEC_F00_0A_48KHZ_MULT_4X RT_BIT(10)
195#define CODEC_F00_0A_44_1KHZ_MULT_4X RT_BIT(9)
196#define CODEC_F00_0A_48KHZ_MULT_2X RT_BIT(8)
197#define CODEC_F00_0A_44_1KHZ_MULT_2X RT_BIT(7)
198#define CODEC_F00_0A_48KHZ RT_BIT(6)
199#define CODEC_F00_0A_44_1KHZ RT_BIT(5)
200/* 2/3 * 48kHz */
201#define CODEC_F00_0A_48KHZ_2_3X RT_BIT(4)
202/* 1/2 * 44.1kHz */
203#define CODEC_F00_0A_44_1KHZ_1_2X RT_BIT(3)
204/* 1/3 * 48kHz */
205#define CODEC_F00_0A_48KHZ_1_3X RT_BIT(2)
206/* 1/4 * 44.1kHz */
207#define CODEC_F00_0A_44_1KHZ_1_4X RT_BIT(1)
208/* 1/6 * 48kHz */
209#define CODEC_F00_0A_48KHZ_1_6X RT_BIT(0)
210
211/* Supported streams formats (7.3.4.8) */
212#define CODEC_F00_0B_AC3 RT_BIT(2)
213#define CODEC_F00_0B_FLOAT32 RT_BIT(1)
214#define CODEC_F00_0B_PCM RT_BIT(0)
215
216/* Pin Capabilities (7.3.4.9)*/
217#define CODEC_MAKE_F00_0C(vref_ctrl) (((vref_ctrl) & 0xFF) << 8)
218#define CODEC_F00_0C_CAP_HBR RT_BIT(27)
219#define CODEC_F00_0C_CAP_DP RT_BIT(24)
220#define CODEC_F00_0C_CAP_EAPD RT_BIT(16)
221#define CODEC_F00_0C_CAP_HDMI RT_BIT(7)
222#define CODEC_F00_0C_CAP_BALANCED_IO RT_BIT(6)
223#define CODEC_F00_0C_CAP_INPUT RT_BIT(5)
224#define CODEC_F00_0C_CAP_OUTPUT RT_BIT(4)
225#define CODEC_F00_0C_CAP_HEADPHONE_AMP RT_BIT(3)
226#define CODEC_F00_0C_CAP_PRESENCE_DETECT RT_BIT(2)
227#define CODEC_F00_0C_CAP_TRIGGER_REQUIRED RT_BIT(1)
228#define CODEC_F00_0C_CAP_IMPENDANCE_SENSE RT_BIT(0)
229
230#define CODEC_F00_0C_IS_CAP_HBR(f00_0c) ((f00_0c) & RT_BIT(27))
231#define CODEC_F00_0C_IS_CAP_DP(f00_0c) ((f00_0c) & RT_BIT(24))
232#define CODEC_F00_0C_IS_CAP_EAPD(f00_0c) ((f00_0c) & RT_BIT(16))
233#define CODEC_F00_0C_IS_CAP_HDMI(f00_0c) ((f00_0c) & RT_BIT(7))
234#define CODEC_F00_0C_IS_CAP_BALANCED_IO(f00_0c) ((f00_0c) & RT_BIT(6))
235#define CODEC_F00_0C_IS_CAP_INPUT(f00_0c) ((f00_0c) & RT_BIT(5))
236#define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c) ((f00_0c) & RT_BIT(4))
237#define CODEC_F00_0C_IS_CAP_HP(f00_0c) ((f00_0c) & RT_BIT(3))
238#define CODEC_F00_0C_IS_CAP_PRESENCE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2))
239#define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c) ((f00_0c) & RT_BIT(1))
240#define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c) ((f00_0c) & RT_BIT(0))
241
242/* Input Amplifier capabilities (7.3.4.10). */
243#define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \
244 ( (((mute_cap) & UINT32_C(0x1)) << 31) \
245 | (((step_size) & UINT32_C(0xFF)) << 16) \
246 | (((num_steps) & UINT32_C(0xFF)) << 8) \
247 | ((offset) & UINT32_C(0xFF)))
248
249#define CODEC_F00_0D_CAP_MUTE RT_BIT(7)
250
251#define CODEC_F00_0D_IS_CAP_MUTE(f00_0d) ( ( f00_0d) & RT_BIT(31))
252#define CODEC_F00_0D_STEP_SIZE(f00_0d) ((( f00_0d) & (0x7F << 16)) >> 16)
253#define CODEC_F00_0D_NUM_STEPS(f00_0d) ((((f00_0d) & (0x7F << 8)) >> 8) + 1)
254#define CODEC_F00_0D_OFFSET(f00_0d) ( (f00_0d) & 0x7F)
255
256/** Indicates that the amplifier can be muted. */
257#define CODEC_AMP_CAP_MUTE 0x1
258/** The amplifier's maximum number of steps. We want
259 * a ~90dB dynamic range, so 64 steps with 1.25dB each
260 * should do the trick.
261 *
262 * As we want to map our range to [0..128] values we can avoid
263 * multiplication and simply doing a shift later.
264 *
265 * Produces -96dB to +0dB.
266 * "0" indicates a step of 0.25dB, "127" indicates a step of 32dB.
267 */
268#define CODEC_AMP_NUM_STEPS 0x7F
269/** The initial gain offset (and when doing a node reset). */
270#define CODEC_AMP_OFF_INITIAL 0x7F
271/** The amplifier's gain step size. */
272#define CODEC_AMP_STEP_SIZE 0x2
273
274/* Output Amplifier capabilities (7.3.4.10) */
275#define CODEC_MAKE_F00_12 CODEC_MAKE_F00_0D
276
277#define CODEC_F00_12_IS_CAP_MUTE(f00_12) CODEC_F00_0D_IS_CAP_MUTE(f00_12)
278#define CODEC_F00_12_STEP_SIZE(f00_12) CODEC_F00_0D_STEP_SIZE(f00_12)
279#define CODEC_F00_12_NUM_STEPS(f00_12) CODEC_F00_0D_NUM_STEPS(f00_12)
280#define CODEC_F00_12_OFFSET(f00_12) CODEC_F00_0D_OFFSET(f00_12)
281
282/* Connection list lenght (7.3.4.11). */
283#define CODEC_MAKE_F00_0E(long_form, length) \
284 ( (((long_form) & 0x1) << 7) \
285 | ((length) & 0x7F))
286/* Indicates short-form NIDs. */
287#define CODEC_F00_0E_LIST_NID_SHORT 0
288/* Indicates long-form NIDs. */
289#define CODEC_F00_0E_LIST_NID_LONG 1
290#define CODEC_F00_0E_IS_LONG(f00_0e) RT_BOOL((f00_0e) & RT_BIT(7))
291#define CODEC_F00_0E_COUNT(f00_0e) ((f00_0e) & 0x7F)
292/* Supported Power States (7.3.4.12) */
293#define CODEC_F00_0F_EPSS RT_BIT(31)
294#define CODEC_F00_0F_CLKSTOP RT_BIT(30)
295#define CODEC_F00_0F_S3D3 RT_BIT(29)
296#define CODEC_F00_0F_D3COLD RT_BIT(4)
297#define CODEC_F00_0F_D3 RT_BIT(3)
298#define CODEC_F00_0F_D2 RT_BIT(2)
299#define CODEC_F00_0F_D1 RT_BIT(1)
300#define CODEC_F00_0F_D0 RT_BIT(0)
301
302/* Processing capabilities 7.3.4.13 */
303#define CODEC_MAKE_F00_10(num, benign) ((((num) & 0xFF) << 8) | ((benign) & 0x1))
304#define CODEC_F00_10_NUM(f00_10) (((f00_10) & (0xFF << 8)) >> 8)
305#define CODEC_F00_10_BENING(f00_10) ((f00_10) & 0x1)
306
307/* GPIO count (7.3.4.14). */
308#define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \
309 ( (((wake) & UINT32_C(0x1)) << 31) \
310 | (((unsol) & UINT32_C(0x1)) << 30) \
311 | (((numgpi) & UINT32_C(0xFF)) << 16) \
312 | (((numgpo) & UINT32_C(0xFF)) << 8) \
313 | ((numgpio) & UINT32_C(0xFF)))
314
315/* Processing States (7.3.3.4). */
316#define CODEC_F03_OFF (0)
317#define CODEC_F03_ON RT_BIT(0)
318#define CODEC_F03_BENING RT_BIT(1)
319/* Power States (7.3.3.10). */
320#define CODEC_MAKE_F05(reset, stopok, error, act, set) \
321 ( (((reset) & 0x1) << 10) \
322 | (((stopok) & 0x1) << 9) \
323 | (((error) & 0x1) << 8) \
324 | (((act) & 0xF) << 4) \
325 | ((set) & 0xF))
326#define CODEC_F05_D3COLD (4)
327#define CODEC_F05_D3 (3)
328#define CODEC_F05_D2 (2)
329#define CODEC_F05_D1 (1)
330#define CODEC_F05_D0 (0)
331
332#define CODEC_F05_IS_RESET(value) (((value) & RT_BIT(10)) != 0)
333#define CODEC_F05_IS_STOPOK(value) (((value) & RT_BIT(9)) != 0)
334#define CODEC_F05_IS_ERROR(value) (((value) & RT_BIT(8)) != 0)
335#define CODEC_F05_ACT(value) (((value) & 0xF0) >> 4)
336#define CODEC_F05_SET(value) (((value) & 0xF))
337
338#define CODEC_F05_GE(p0, p1) ((p0) <= (p1))
339#define CODEC_F05_LE(p0, p1) ((p0) >= (p1))
340
341/* Converter Stream, Channel (7.3.3.11). */
342#define CODEC_MAKE_F06(stream, channel) \
343 ( (((stream) & 0xF) << 4) \
344 | ((channel) & 0xF))
345#define CODEC_F06_STREAM(value) ((value) & 0xF0)
346#define CODEC_F06_CHANNEL(value) ((value) & 0xF)
347
348/* Pin Widged Control (7.3.3.13). */
349#define CODEC_F07_VREF_HIZ (0)
350#define CODEC_F07_VREF_50 (0x1)
351#define CODEC_F07_VREF_GROUND (0x2)
352#define CODEC_F07_VREF_80 (0x4)
353#define CODEC_F07_VREF_100 (0x5)
354#define CODEC_F07_IN_ENABLE RT_BIT(5)
355#define CODEC_F07_OUT_ENABLE RT_BIT(6)
356#define CODEC_F07_OUT_H_ENABLE RT_BIT(7)
357
358/* Volume Knob Control (7.3.3.29). */
359#define CODEC_F0F_IS_DIRECT RT_BIT(7)
360#define CODEC_F0F_VOLUME (0x7F)
361
362/* Unsolicited enabled (7.3.3.14). */
363#define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F))
364
365/* Converter formats (7.3.3.8) and (3.7.1). */
366/* This is the same format as SDnFMT. */
367#define CODEC_MAKE_A HDA_SDFMT_MAKE
368
369#define CODEC_A_TYPE HDA_SDFMT_TYPE
370#define CODEC_A_TYPE_PCM HDA_SDFMT_TYPE_PCM
371#define CODEC_A_TYPE_NON_PCM HDA_SDFMT_TYPE_NON_PCM
372
373#define CODEC_A_BASE HDA_SDFMT_BASE
374#define CODEC_A_BASE_48KHZ HDA_SDFMT_BASE_48KHZ
375#define CODEC_A_BASE_44KHZ HDA_SDFMT_BASE_44KHZ
376
377/* Pin Sense (7.3.3.15). */
378#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \
379( (((fPresent) & 0x1) << 31) \
380 | (((impedance) & UINT32_C(0x7FFFFFFF))))
381#define CODEC_F09_ANALOG_NA UINT32_C(0x7FFFFFFF)
382#define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \
383( (((fPresent) & UINT32_C(0x1)) << 31) \
384 | (((fELDValid) & UINT32_C(0x1)) << 30))
385
386#define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1))
387#define CODEC_FOC_IS_LRSWAP(f0c) RT_BOOL((f0c) & RT_BIT(2))
388#define CODEC_FOC_IS_EAPD(f0c) RT_BOOL((f0c) & RT_BIT(1))
389#define CODEC_FOC_IS_BTL(f0c) RT_BOOL((f0c) & RT_BIT(0))
390/* HDA spec 7.3.3.31 defines layout of configuration registers/verbs (0xF1C) */
391/* Configuration's port connection */
392#define CODEC_F1C_PORT_MASK (0x3)
393#define CODEC_F1C_PORT_SHIFT (30)
394
395#define CODEC_F1C_PORT_COMPLEX (0x0)
396#define CODEC_F1C_PORT_NO_PHYS (0x1)
397#define CODEC_F1C_PORT_FIXED (0x2)
398#define CODEC_F1C_BOTH (0x3)
399
400/* Configuration default: connection */
401#define CODEC_F1C_PORT_MASK (0x3)
402#define CODEC_F1C_PORT_SHIFT (30)
403
404/* Connected to a jack (1/8", ATAPI, ...). */
405#define CODEC_F1C_PORT_COMPLEX (0x0)
406/* No physical connection. */
407#define CODEC_F1C_PORT_NO_PHYS (0x1)
408/* Fixed function device (integrated speaker, integrated mic, ...). */
409#define CODEC_F1C_PORT_FIXED (0x2)
410/* Both, a jack and an internal device are attached. */
411#define CODEC_F1C_BOTH (0x3)
412
413/* Configuration default: Location */
414#define CODEC_F1C_LOCATION_MASK (0x3F)
415#define CODEC_F1C_LOCATION_SHIFT (24)
416
417/* [4:5] bits of location region means chassis attachment */
418#define CODEC_F1C_LOCATION_PRIMARY_CHASSIS (0)
419#define CODEC_F1C_LOCATION_INTERNAL RT_BIT(4)
420#define CODEC_F1C_LOCATION_SECONDRARY_CHASSIS RT_BIT(5)
421#define CODEC_F1C_LOCATION_OTHER RT_BIT(5)
422
423/* [0:3] bits of location region means geometry location attachment */
424#define CODEC_F1C_LOCATION_NA (0)
425#define CODEC_F1C_LOCATION_REAR (0x1)
426#define CODEC_F1C_LOCATION_FRONT (0x2)
427#define CODEC_F1C_LOCATION_LEFT (0x3)
428#define CODEC_F1C_LOCATION_RIGTH (0x4)
429#define CODEC_F1C_LOCATION_TOP (0x5)
430#define CODEC_F1C_LOCATION_BOTTOM (0x6)
431#define CODEC_F1C_LOCATION_SPECIAL_0 (0x7)
432#define CODEC_F1C_LOCATION_SPECIAL_1 (0x8)
433#define CODEC_F1C_LOCATION_SPECIAL_2 (0x9)
434
435/* Configuration default: Device type */
436#define CODEC_F1C_DEVICE_MASK (0xF)
437#define CODEC_F1C_DEVICE_SHIFT (20)
438#define CODEC_F1C_DEVICE_LINE_OUT (0)
439#define CODEC_F1C_DEVICE_SPEAKER (0x1)
440#define CODEC_F1C_DEVICE_HP (0x2)
441#define CODEC_F1C_DEVICE_CD (0x3)
442#define CODEC_F1C_DEVICE_SPDIF_OUT (0x4)
443#define CODEC_F1C_DEVICE_DIGITAL_OTHER_OUT (0x5)
444#define CODEC_F1C_DEVICE_MODEM_LINE_SIDE (0x6)
445#define CODEC_F1C_DEVICE_MODEM_HANDSET_SIDE (0x7)
446#define CODEC_F1C_DEVICE_LINE_IN (0x8)
447#define CODEC_F1C_DEVICE_AUX (0x9)
448#define CODEC_F1C_DEVICE_MIC (0xA)
449#define CODEC_F1C_DEVICE_PHONE (0xB)
450#define CODEC_F1C_DEVICE_SPDIF_IN (0xC)
451#define CODEC_F1C_DEVICE_RESERVED (0xE)
452#define CODEC_F1C_DEVICE_OTHER (0xF)
453
454/* Configuration default: Connection type */
455#define CODEC_F1C_CONNECTION_TYPE_MASK (0xF)
456#define CODEC_F1C_CONNECTION_TYPE_SHIFT (16)
457
458#define CODEC_F1C_CONNECTION_TYPE_UNKNOWN (0)
459#define CODEC_F1C_CONNECTION_TYPE_1_8INCHES (0x1)
460#define CODEC_F1C_CONNECTION_TYPE_1_4INCHES (0x2)
461#define CODEC_F1C_CONNECTION_TYPE_ATAPI (0x3)
462#define CODEC_F1C_CONNECTION_TYPE_RCA (0x4)
463#define CODEC_F1C_CONNECTION_TYPE_OPTICAL (0x5)
464#define CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL (0x6)
465#define CODEC_F1C_CONNECTION_TYPE_ANALOG (0x7)
466#define CODEC_F1C_CONNECTION_TYPE_DIN (0x8)
467#define CODEC_F1C_CONNECTION_TYPE_XLR (0x9)
468#define CODEC_F1C_CONNECTION_TYPE_RJ_11 (0xA)
469#define CODEC_F1C_CONNECTION_TYPE_COMBO (0xB)
470#define CODEC_F1C_CONNECTION_TYPE_OTHER (0xF)
471
472/* Configuration's color */
473#define CODEC_F1C_COLOR_MASK (0xF)
474#define CODEC_F1C_COLOR_SHIFT (12)
475#define CODEC_F1C_COLOR_UNKNOWN (0)
476#define CODEC_F1C_COLOR_BLACK (0x1)
477#define CODEC_F1C_COLOR_GREY (0x2)
478#define CODEC_F1C_COLOR_BLUE (0x3)
479#define CODEC_F1C_COLOR_GREEN (0x4)
480#define CODEC_F1C_COLOR_RED (0x5)
481#define CODEC_F1C_COLOR_ORANGE (0x6)
482#define CODEC_F1C_COLOR_YELLOW (0x7)
483#define CODEC_F1C_COLOR_PURPLE (0x8)
484#define CODEC_F1C_COLOR_PINK (0x9)
485#define CODEC_F1C_COLOR_RESERVED_0 (0xA)
486#define CODEC_F1C_COLOR_RESERVED_1 (0xB)
487#define CODEC_F1C_COLOR_RESERVED_2 (0xC)
488#define CODEC_F1C_COLOR_RESERVED_3 (0xD)
489#define CODEC_F1C_COLOR_WHITE (0xE)
490#define CODEC_F1C_COLOR_OTHER (0xF)
491
492/* Configuration's misc */
493#define CODEC_F1C_MISC_MASK (0xF)
494#define CODEC_F1C_MISC_SHIFT (8)
495#define CODEC_F1C_MISC_NONE 0
496#define CODEC_F1C_MISC_JACK_NO_PRESENCE_DETECT RT_BIT(0)
497#define CODEC_F1C_MISC_RESERVED_0 RT_BIT(1)
498#define CODEC_F1C_MISC_RESERVED_1 RT_BIT(2)
499#define CODEC_F1C_MISC_RESERVED_2 RT_BIT(3)
500
501/* Configuration default: Association */
502#define CODEC_F1C_ASSOCIATION_MASK (0xF)
503#define CODEC_F1C_ASSOCIATION_SHIFT (4)
504
505/** Reserved; don't use. */
506#define CODEC_F1C_ASSOCIATION_INVALID 0x0
507#define CODEC_F1C_ASSOCIATION_GROUP_0 0x1
508#define CODEC_F1C_ASSOCIATION_GROUP_1 0x2
509#define CODEC_F1C_ASSOCIATION_GROUP_2 0x3
510#define CODEC_F1C_ASSOCIATION_GROUP_3 0x4
511#define CODEC_F1C_ASSOCIATION_GROUP_4 0x5
512#define CODEC_F1C_ASSOCIATION_GROUP_5 0x6
513#define CODEC_F1C_ASSOCIATION_GROUP_6 0x7
514#define CODEC_F1C_ASSOCIATION_GROUP_7 0x8
515/* Note: Windows OSes will treat group 15 (0xF) as single PIN devices.
516 * The sequence number associated with that group then will be ignored. */
517#define CODEC_F1C_ASSOCIATION_GROUP_15 0xF
518
519/* Configuration default: Association Sequence. */
520#define CODEC_F1C_SEQ_MASK (0xF)
521#define CODEC_F1C_SEQ_SHIFT (0)
522
523/* Implementation identification (7.3.3.30). */
524#define CODEC_MAKE_F20(bmid, bsku, aid) \
525 ( (((bmid) & 0xFFFF) << 16) \
526 | (((bsku) & 0xFF) << 8) \
527 | (((aid) & 0xFF)) \
528 )
529
530/* Macro definition helping in filling the configuration registers. */
531#define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence) \
532 ( (((port_connectivity) & 0xF) << CODEC_F1C_PORT_SHIFT) \
533 | (((location) & 0xF) << CODEC_F1C_LOCATION_SHIFT) \
534 | (((device) & 0xF) << CODEC_F1C_DEVICE_SHIFT) \
535 | (((connection_type) & 0xF) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
536 | (((color) & 0xF) << CODEC_F1C_COLOR_SHIFT) \
537 | (((misc) & 0xF) << CODEC_F1C_MISC_SHIFT) \
538 | (((association) & 0xF) << CODEC_F1C_ASSOCIATION_SHIFT) \
539 | (((sequence) & 0xF)))
540
541
542/*********************************************************************************************************************************
543* Structures and Typedefs *
544*********************************************************************************************************************************/
545/** The F00 parameter length (in dwords). */
546#define CODECNODE_F00_PARAM_LENGTH 20
547/** The F02 parameter length (in dwords). */
548#define CODECNODE_F02_PARAM_LENGTH 16
549
550/**
551 * Common (or core) codec node structure.
552 */
553typedef struct CODECCOMMONNODE
554{
555 /** The node's ID. */
556 uint8_t uID;
557 /** The node's name. */
558 char const *pszName;
559 /** The SDn ID this node is assigned to.
560 * 0 means not assigned, 1 is SDn0. */
561 uint8_t uSD;
562 /** The SDn's channel to use.
563 * Only valid if a valid SDn ID is set. */
564 uint8_t uChannel;
565 /* PRM 5.3.6 */
566 uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH];
567 uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH];
568} CODECCOMMONNODE;
569typedef CODECCOMMONNODE *PCODECCOMMONNODE;
570AssertCompile(CODECNODE_F00_PARAM_LENGTH == 20); /* saved state */
571AssertCompile(CODECNODE_F02_PARAM_LENGTH == 16); /* saved state */
572
573/**
574 * Compile time assertion on the expected node size.
575 */
576#define AssertNodeSize(a_Node, a_cParams) \
577 AssertCompile((a_cParams) <= (60 + 6)); /* the max size - saved state */ \
578 AssertCompile( sizeof(a_Node) - sizeof(CODECCOMMONNODE) \
579 == (((a_cParams) * sizeof(uint32_t) + sizeof(void *) - 1) & ~(sizeof(void *) - 1)) )
580
581typedef struct ROOTCODECNODE
582{
583 CODECCOMMONNODE node;
584} ROOTCODECNODE, *PROOTCODECNODE;
585AssertNodeSize(ROOTCODECNODE, 0);
586
587#define AMPLIFIER_SIZE 60
588typedef uint32_t AMPLIFIER[AMPLIFIER_SIZE];
589#define AMPLIFIER_IN 0
590#define AMPLIFIER_OUT 1
591#define AMPLIFIER_LEFT 1
592#define AMPLIFIER_RIGHT 0
593#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)])
594typedef struct DACNODE
595{
596 CODECCOMMONNODE node;
597 uint32_t u32F0d_param;
598 uint32_t u32F04_param;
599 uint32_t u32F05_param;
600 uint32_t u32F06_param;
601 uint32_t u32F0c_param;
602
603 uint32_t u32A_param;
604 AMPLIFIER B_params;
605
606} DACNODE, *PDACNODE;
607AssertNodeSize(DACNODE, 6 + 60);
608
609typedef struct ADCNODE
610{
611 CODECCOMMONNODE node;
612 uint32_t u32F01_param;
613 uint32_t u32F03_param;
614 uint32_t u32F05_param;
615 uint32_t u32F06_param;
616 uint32_t u32F09_param;
617
618 uint32_t u32A_param;
619 AMPLIFIER B_params;
620} ADCNODE, *PADCNODE;
621AssertNodeSize(DACNODE, 6 + 60);
622
623typedef struct SPDIFOUTNODE
624{
625 CODECCOMMONNODE node;
626 uint32_t u32F05_param;
627 uint32_t u32F06_param;
628 uint32_t u32F09_param;
629 uint32_t u32F0d_param;
630
631 uint32_t u32A_param;
632 AMPLIFIER B_params;
633} SPDIFOUTNODE, *PSPDIFOUTNODE;
634AssertNodeSize(SPDIFOUTNODE, 5 + 60);
635
636typedef struct SPDIFINNODE
637{
638 CODECCOMMONNODE node;
639 uint32_t u32F05_param;
640 uint32_t u32F06_param;
641 uint32_t u32F09_param;
642 uint32_t u32F0d_param;
643
644 uint32_t u32A_param;
645 AMPLIFIER B_params;
646} SPDIFINNODE, *PSPDIFINNODE;
647AssertNodeSize(SPDIFINNODE, 5 + 60);
648
649typedef struct AFGCODECNODE
650{
651 CODECCOMMONNODE node;
652 uint32_t u32F05_param;
653 uint32_t u32F08_param;
654 uint32_t u32F17_param;
655 uint32_t u32F20_param;
656} AFGCODECNODE, *PAFGCODECNODE;
657AssertNodeSize(AFGCODECNODE, 4);
658
659typedef struct PORTNODE
660{
661 CODECCOMMONNODE node;
662 uint32_t u32F01_param;
663 uint32_t u32F07_param;
664 uint32_t u32F08_param;
665 uint32_t u32F09_param;
666 uint32_t u32F1c_param;
667 AMPLIFIER B_params;
668} PORTNODE, *PPORTNODE;
669AssertNodeSize(PORTNODE, 5 + 60);
670
671typedef struct DIGOUTNODE
672{
673 CODECCOMMONNODE node;
674 uint32_t u32F01_param;
675 uint32_t u32F05_param;
676 uint32_t u32F07_param;
677 uint32_t u32F08_param;
678 uint32_t u32F09_param;
679 uint32_t u32F1c_param;
680} DIGOUTNODE, *PDIGOUTNODE;
681AssertNodeSize(DIGOUTNODE, 6);
682
683typedef struct DIGINNODE
684{
685 CODECCOMMONNODE node;
686 uint32_t u32F05_param;
687 uint32_t u32F07_param;
688 uint32_t u32F08_param;
689 uint32_t u32F09_param;
690 uint32_t u32F0c_param;
691 uint32_t u32F1c_param;
692 uint32_t u32F1e_param;
693} DIGINNODE, *PDIGINNODE;
694AssertNodeSize(DIGINNODE, 7);
695
696typedef struct ADCMUXNODE
697{
698 CODECCOMMONNODE node;
699 uint32_t u32F01_param;
700
701 uint32_t u32A_param;
702 AMPLIFIER B_params;
703} ADCMUXNODE, *PADCMUXNODE;
704AssertNodeSize(ADCMUXNODE, 2 + 60);
705
706typedef struct PCBEEPNODE
707{
708 CODECCOMMONNODE node;
709 uint32_t u32F07_param;
710 uint32_t u32F0a_param;
711
712 uint32_t u32A_param;
713 AMPLIFIER B_params;
714 uint32_t u32F1c_param;
715} PCBEEPNODE, *PPCBEEPNODE;
716AssertNodeSize(PCBEEPNODE, 3 + 60 + 1);
717
718typedef struct CDNODE
719{
720 CODECCOMMONNODE node;
721 uint32_t u32F07_param;
722 uint32_t u32F1c_param;
723} CDNODE, *PCDNODE;
724AssertNodeSize(CDNODE, 2);
725
726typedef struct VOLUMEKNOBNODE
727{
728 CODECCOMMONNODE node;
729 uint32_t u32F08_param;
730 uint32_t u32F0f_param;
731} VOLUMEKNOBNODE, *PVOLUMEKNOBNODE;
732AssertNodeSize(VOLUMEKNOBNODE, 2);
733
734typedef struct ADCVOLNODE
735{
736 CODECCOMMONNODE node;
737 uint32_t u32F0c_param;
738 uint32_t u32F01_param;
739 uint32_t u32A_params;
740 AMPLIFIER B_params;
741} ADCVOLNODE, *PADCVOLNODE;
742AssertNodeSize(ADCVOLNODE, 3 + 60);
743
744typedef struct RESNODE
745{
746 CODECCOMMONNODE node;
747 uint32_t u32F05_param;
748 uint32_t u32F06_param;
749 uint32_t u32F07_param;
750 uint32_t u32F1c_param;
751
752 uint32_t u32A_param;
753} RESNODE, *PRESNODE;
754AssertNodeSize(RESNODE, 5);
755
756/**
757 * Used for the saved state.
758 */
759typedef struct CODECSAVEDSTATENODE
760{
761 CODECCOMMONNODE Core;
762 uint32_t au32Params[60 + 6];
763} CODECSAVEDSTATENODE;
764AssertNodeSize(CODECSAVEDSTATENODE, 60 + 6);
765
766typedef union CODECNODE
767{
768 CODECCOMMONNODE node;
769 ROOTCODECNODE root;
770 AFGCODECNODE afg;
771 DACNODE dac;
772 ADCNODE adc;
773 SPDIFOUTNODE spdifout;
774 SPDIFINNODE spdifin;
775 PORTNODE port;
776 DIGOUTNODE digout;
777 DIGINNODE digin;
778 ADCMUXNODE adcmux;
779 PCBEEPNODE pcbeep;
780 CDNODE cdnode;
781 VOLUMEKNOBNODE volumeKnob;
782 ADCVOLNODE adcvol;
783 RESNODE reserved;
784 CODECSAVEDSTATENODE SavedState;
785} CODECNODE, *PCODECNODE;
786AssertNodeSize(CODECNODE, 60 + 6);
787
788
789/*********************************************************************************************************************************
790* Global Variables *
791*********************************************************************************************************************************/
792/* STAC9220 - Nodes IDs / names. */
793#define STAC9220_NID_ROOT 0x0 /* Root node */
794#define STAC9220_NID_AFG 0x1 /* Audio Configuration Group */
795#define STAC9220_NID_DAC0 0x2 /* Out */
796#define STAC9220_NID_DAC1 0x3 /* Out */
797#define STAC9220_NID_DAC2 0x4 /* Out */
798#define STAC9220_NID_DAC3 0x5 /* Out */
799#define STAC9220_NID_ADC0 0x6 /* In */
800#define STAC9220_NID_ADC1 0x7 /* In */
801#define STAC9220_NID_SPDIF_OUT 0x8 /* Out */
802#define STAC9220_NID_SPDIF_IN 0x9 /* In */
803/** Also known as PIN_A. */
804#define STAC9220_NID_PIN_HEADPHONE0 0xA /* In, Out */
805#define STAC9220_NID_PIN_B 0xB /* In, Out */
806#define STAC9220_NID_PIN_C 0xC /* In, Out */
807/** Also known as PIN D. */
808#define STAC9220_NID_PIN_HEADPHONE1 0xD /* In, Out */
809#define STAC9220_NID_PIN_E 0xE /* In */
810#define STAC9220_NID_PIN_F 0xF /* In, Out */
811/** Also known as DIGOUT0. */
812#define STAC9220_NID_PIN_SPDIF_OUT 0x10 /* Out */
813/** Also known as DIGIN. */
814#define STAC9220_NID_PIN_SPDIF_IN 0x11 /* In */
815#define STAC9220_NID_ADC0_MUX 0x12 /* In */
816#define STAC9220_NID_ADC1_MUX 0x13 /* In */
817#define STAC9220_NID_PCBEEP 0x14 /* Out */
818#define STAC9220_NID_PIN_CD 0x15 /* In */
819#define STAC9220_NID_VOL_KNOB 0x16
820#define STAC9220_NID_AMP_ADC0 0x17 /* In */
821#define STAC9220_NID_AMP_ADC1 0x18 /* In */
822/* Only for STAC9221. */
823#define STAC9221_NID_ADAT_OUT 0x19 /* Out */
824#define STAC9221_NID_I2S_OUT 0x1A /* Out */
825#define STAC9221_NID_PIN_I2S_OUT 0x1B /* Out */
826
827/** Number of total nodes emulated. */
828#define STAC9221_NUM_NODES 0x1C
829
830/* STAC9220 - Referenced through STAC9220WIDGET in the constructor below. */
831static uint8_t const g_abStac9220Ports[] = { STAC9220_NID_PIN_HEADPHONE0, STAC9220_NID_PIN_B, STAC9220_NID_PIN_C, STAC9220_NID_PIN_HEADPHONE1, STAC9220_NID_PIN_E, STAC9220_NID_PIN_F, 0 };
832static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0 };
833static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0 };
834static uint8_t const g_abStac9220SpdifOuts[] = { STAC9220_NID_SPDIF_OUT, 0 };
835static uint8_t const g_abStac9220SpdifIns[] = { STAC9220_NID_SPDIF_IN, 0 };
836static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
837static uint8_t const g_abStac9220DigInPins[] = { STAC9220_NID_PIN_SPDIF_IN, 0 };
838static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0 };
839static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0 };
840static uint8_t const g_abStac9220Pcbeeps[] = { STAC9220_NID_PCBEEP, 0 };
841static uint8_t const g_abStac9220Cds[] = { STAC9220_NID_PIN_CD, 0 };
842static uint8_t const g_abStac9220VolKnobs[] = { STAC9220_NID_VOL_KNOB, 0 };
843/* STAC 9221. */
844/** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
845static uint8_t const g_abStac9220Reserveds[] = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
846
847/** SSM description of a CODECNODE. */
848static SSMFIELD const g_aCodecNodeFields[] =
849{
850 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
851 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
852 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
853 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
854 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
855 SSMFIELD_ENTRY_TERM()
856};
857
858/** Backward compatibility with v1 of the CODECNODE. */
859static SSMFIELD const g_aCodecNodeFieldsV1[] =
860{
861 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
862 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
863 SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
864 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
865 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
866 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
867 SSMFIELD_ENTRY_TERM()
868};
869
870
871
872#if 0 /* unused */
873static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
874{
875 RT_NOREF(pszArgs);
876 for (uint8_t i = 1; i < pThis->cTotalNodes; i++)
877 {
878 PCODECNODE pNode = &pThis->paNodes[i];
879 AMPLIFIER *pAmp = &pNode->dac.B_params;
880
881 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) & 0x7f;
882 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) & 0x7f;
883
884 pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
885 }
886}
887#endif
888
889/**
890 * Resets the codec with all its connected nodes.
891 *
892 * @param pThis HDA codec to reset.
893 */
894static DECLCALLBACK(void) stac9220Reset(PHDACODEC pThis)
895{
896 AssertPtrReturnVoid(pThis->paNodes);
897 AssertPtrReturnVoid(pThis->pfnNodeReset);
898
899 LogRel(("HDA: Codec reset\n"));
900
901 pThis->fInReset = true;
902
903 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
904 pThis->pfnNodeReset(pThis, i, &pThis->paNodes[i]);
905
906 pThis->fInReset = false;
907}
908
909/**
910 * Resets a single node of the codec.
911 *
912 * @returns IPRT status code.
913 * @param pThis HDA codec of node to reset.
914 * @param uNID Node ID to set node to.
915 * @param pNode Node to reset.
916 */
917static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t uNID, PCODECNODE pNode)
918{
919 LogFlowFunc(("NID=0x%x (%RU8)\n", uNID, uNID));
920
921 if ( !pThis->fInReset
922 && ( uNID != STAC9220_NID_ROOT
923 && uNID != STAC9220_NID_AFG)
924 )
925 {
926 RT_ZERO(pNode->node);
927 }
928
929 /* Set common parameters across all nodes. */
930 pNode->node.uID = uNID;
931 pNode->node.uSD = 0;
932
933 switch (uNID)
934 {
935 /* Root node. */
936 case STAC9220_NID_ROOT:
937 {
938 /* Set the revision ID. */
939 pNode->root.node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x3, 0x4, 0x0, 0x1);
940 break;
941 }
942
943 /*
944 * AFG (Audio Function Group).
945 */
946 case STAC9220_NID_AFG:
947 {
948 pNode->afg.node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
949 /* We set the AFG's PCM capabitilies fixed to 44.1kHz, 16-bit signed. */
950 pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
951 pNode->afg.node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
952 pNode->afg.node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
953 | CODEC_F00_0C_CAP_BALANCED_IO
954 | CODEC_F00_0C_CAP_INPUT
955 | CODEC_F00_0C_CAP_OUTPUT
956 | CODEC_F00_0C_CAP_PRESENCE_DETECT
957 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
958 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;
959
960 /* Default input amplifier capabilities. */
961 pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
962 CODEC_AMP_STEP_SIZE,
963 CODEC_AMP_NUM_STEPS,
964 CODEC_AMP_OFF_INITIAL);
965 /* Default output amplifier capabilities. */
966 pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
967 CODEC_AMP_STEP_SIZE,
968 CODEC_AMP_NUM_STEPS,
969 CODEC_AMP_OFF_INITIAL);
970
971 pNode->afg.node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);
972 pNode->afg.node.au32F00_param[0x0F] = CODEC_F00_0F_D3
973 | CODEC_F00_0F_D2
974 | CODEC_F00_0F_D1
975 | CODEC_F00_0F_D0;
976
977 pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2); /* PS-Act: D2, PS->Set D2. */
978 pNode->afg.u32F08_param = 0;
979 pNode->afg.u32F17_param = 0;
980 break;
981 }
982
983 /*
984 * DACs.
985 */
986 case STAC9220_NID_DAC0: /* DAC0: Headphones 0 + 1 */
987 case STAC9220_NID_DAC1: /* DAC1: PIN C */
988 case STAC9220_NID_DAC2: /* DAC2: PIN B */
989 case STAC9220_NID_DAC3: /* DAC3: PIN F */
990 {
991 pNode->dac.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
992 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
993 HDA_SDFMT_CHAN_STEREO);
994
995 /* 7.3.4.6: Audio widget capabilities. */
996 pNode->dac.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 13, 0)
997 | CODEC_F00_09_CAP_L_R_SWAP
998 | CODEC_F00_09_CAP_POWER_CTRL
999 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1000 | CODEC_F00_09_CAP_STEREO;
1001
1002 /* Connection list; must be 0 if the only connection for the widget is
1003 * to the High Definition Audio Link. */
1004 pNode->dac.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 0 /* Entries */);
1005
1006 pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);
1007
1008 RT_ZERO(pNode->dac.B_params);
1009 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
1010 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
1011 break;
1012 }
1013
1014 /*
1015 * ADCs.
1016 */
1017 case STAC9220_NID_ADC0: /* Analog input. */
1018 {
1019 pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC0;
1020 goto adc_init;
1021 }
1022
1023 case STAC9220_NID_ADC1: /* Analog input (CD). */
1024 {
1025 pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC1;
1026
1027 /* Fall through is intentional. */
1028 adc_init:
1029
1030 pNode->adc.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
1031 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
1032 HDA_SDFMT_CHAN_STEREO);
1033
1034 pNode->adc.u32F03_param = RT_BIT(0);
1035 pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
1036
1037 pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
1038 | CODEC_F00_09_CAP_POWER_CTRL
1039 | CODEC_F00_09_CAP_CONNECTION_LIST
1040 | CODEC_F00_09_CAP_PROC_WIDGET
1041 | CODEC_F00_09_CAP_STEREO;
1042 /* Connection list entries. */
1043 pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1044 break;
1045 }
1046
1047 /*
1048 * SP/DIF In/Out.
1049 */
1050 case STAC9220_NID_SPDIF_OUT:
1051 {
1052 pNode->spdifout.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
1053 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
1054 HDA_SDFMT_CHAN_STEREO);
1055 pNode->spdifout.u32F06_param = 0;
1056 pNode->spdifout.u32F0d_param = 0;
1057
1058 pNode->spdifout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 4, 0)
1059 | CODEC_F00_09_CAP_DIGITAL
1060 | CODEC_F00_09_CAP_FMT_OVERRIDE
1061 | CODEC_F00_09_CAP_STEREO;
1062
1063 /* Use a fixed format from AFG. */
1064 pNode->spdifout.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
1065 pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
1066 break;
1067 }
1068
1069 case STAC9220_NID_SPDIF_IN:
1070 {
1071 pNode->spdifin.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
1072 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
1073 HDA_SDFMT_CHAN_STEREO);
1074
1075 pNode->spdifin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 4, 0)
1076 | CODEC_F00_09_CAP_DIGITAL
1077 | CODEC_F00_09_CAP_CONNECTION_LIST
1078 | CODEC_F00_09_CAP_FMT_OVERRIDE
1079 | CODEC_F00_09_CAP_STEREO;
1080
1081 /* Use a fixed format from AFG. */
1082 pNode->spdifin.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
1083 pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
1084
1085 /* Connection list entries. */
1086 pNode->spdifin.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1087 pNode->spdifin.node.au32F02_param[0] = 0x11;
1088 break;
1089 }
1090
1091 /*
1092 * PINs / Ports.
1093 */
1094 case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
1095 {
1096 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA);
1097
1098 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1099 | CODEC_F00_0C_CAP_INPUT
1100 | CODEC_F00_0C_CAP_OUTPUT
1101 | CODEC_F00_0C_CAP_HEADPHONE_AMP
1102 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1103 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1104
1105 /* Connection list entry 0: Goes to DAC0. */
1106 pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC0;
1107
1108 if (!pThis->fInReset)
1109 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1110 CODEC_F1C_LOCATION_FRONT,
1111 CODEC_F1C_DEVICE_HP,
1112 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1113 CODEC_F1C_COLOR_GREEN,
1114 CODEC_F1C_MISC_NONE,
1115 CODEC_F1C_ASSOCIATION_GROUP_1, 0x0 /* Seq */);
1116 goto port_init;
1117 }
1118
1119 case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
1120 {
1121 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
1122
1123 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1124 | CODEC_F00_0C_CAP_INPUT
1125 | CODEC_F00_0C_CAP_OUTPUT
1126 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1127 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1128
1129 /* Connection list entry 0: Goes to DAC2. */
1130 pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC2;
1131
1132 if (!pThis->fInReset)
1133 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1134 CODEC_F1C_LOCATION_REAR,
1135 CODEC_F1C_DEVICE_SPEAKER,
1136 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1137 CODEC_F1C_COLOR_BLACK,
1138 CODEC_F1C_MISC_NONE,
1139 CODEC_F1C_ASSOCIATION_GROUP_0, 0x1 /* Seq */);
1140 goto port_init;
1141 }
1142
1143 case STAC9220_NID_PIN_C: /* Rear Speaker. */
1144 {
1145 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
1146
1147 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1148 | CODEC_F00_0C_CAP_INPUT
1149 | CODEC_F00_0C_CAP_OUTPUT
1150 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1151 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1152
1153 /* Connection list entry 0: Goes to DAC1. */
1154 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC1;
1155
1156 if (!pThis->fInReset)
1157 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1158 CODEC_F1C_LOCATION_REAR,
1159 CODEC_F1C_DEVICE_SPEAKER,
1160 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1161 CODEC_F1C_COLOR_GREEN,
1162 CODEC_F1C_MISC_NONE,
1163 CODEC_F1C_ASSOCIATION_GROUP_0, 0x0 /* Seq */);
1164 goto port_init;
1165 }
1166
1167 case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
1168 {
1169 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
1170
1171 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1172 | CODEC_F00_0C_CAP_INPUT
1173 | CODEC_F00_0C_CAP_OUTPUT
1174 | CODEC_F00_0C_CAP_HEADPHONE_AMP
1175 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1176 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1177
1178 /* Connection list entry 0: Goes to DAC1. */
1179 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC0;
1180
1181 if (!pThis->fInReset)
1182 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1183 CODEC_F1C_LOCATION_FRONT,
1184 CODEC_F1C_DEVICE_MIC,
1185 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1186 CODEC_F1C_COLOR_PINK,
1187 CODEC_F1C_MISC_NONE,
1188 CODEC_F1C_ASSOCIATION_GROUP_15, 0x0 /* Ignored */);
1189 /* Fall through is intentional. */
1190
1191 port_init:
1192
1193 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
1194 | CODEC_F07_OUT_ENABLE;
1195 pNode->port.u32F08_param = 0;
1196
1197 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1198 | CODEC_F00_09_CAP_CONNECTION_LIST
1199 | CODEC_F00_09_CAP_UNSOL
1200 | CODEC_F00_09_CAP_STEREO;
1201 /* Connection list entries. */
1202 pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1203 break;
1204 }
1205
1206 case STAC9220_NID_PIN_E:
1207 {
1208 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
1209 pNode->port.u32F08_param = 0;
1210 /* If Line in is reported as enabled, OS X sees no speakers! Windows does
1211 * not care either way, although Linux does.
1212 */
1213 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /* fPresent */, 0);
1214
1215 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1216 | CODEC_F00_09_CAP_UNSOL
1217 | CODEC_F00_09_CAP_STEREO;
1218
1219 pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
1220 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
1221
1222 if (!pThis->fInReset)
1223 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1224 CODEC_F1C_LOCATION_REAR,
1225 CODEC_F1C_DEVICE_LINE_IN,
1226 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1227 CODEC_F1C_COLOR_BLUE,
1228 CODEC_F1C_MISC_NONE,
1229 CODEC_F1C_ASSOCIATION_GROUP_4, 0x1 /* Seq */);
1230 break;
1231 }
1232
1233 case STAC9220_NID_PIN_F:
1234 {
1235 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE | CODEC_F07_OUT_ENABLE;
1236 pNode->port.u32F08_param = 0;
1237 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /* fPresent */, CODEC_F09_ANALOG_NA);
1238
1239 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1240 | CODEC_F00_09_CAP_CONNECTION_LIST
1241 | CODEC_F00_09_CAP_UNSOL
1242 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1243 | CODEC_F00_09_CAP_STEREO;
1244
1245 pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
1246 | CODEC_F00_0C_CAP_OUTPUT;
1247
1248 /* Connection list entry 0: Goes to DAC3. */
1249 pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1250 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC3;
1251
1252 if (!pThis->fInReset)
1253 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1254 CODEC_F1C_LOCATION_INTERNAL,
1255 CODEC_F1C_DEVICE_SPEAKER,
1256 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1257 CODEC_F1C_COLOR_ORANGE,
1258 CODEC_F1C_MISC_NONE,
1259 CODEC_F1C_ASSOCIATION_GROUP_0, 0x2 /* Seq */);
1260 break;
1261 }
1262
1263 case STAC9220_NID_PIN_SPDIF_OUT: /* Rear SPDIF Out. */
1264 {
1265 pNode->digout.u32F07_param = CODEC_F07_OUT_ENABLE;
1266 pNode->digout.u32F09_param = 0;
1267
1268 pNode->digout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1269 | CODEC_F00_09_CAP_DIGITAL
1270 | CODEC_F00_09_CAP_CONNECTION_LIST
1271 | CODEC_F00_09_CAP_STEREO;
1272 pNode->digout.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
1273
1274 /* Connection list entries. */
1275 pNode->digout.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 3 /* Entries */);
1276 pNode->digout.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_SPDIF_OUT,
1277 STAC9220_NID_AMP_ADC0, STAC9221_NID_ADAT_OUT, 0);
1278 if (!pThis->fInReset)
1279 pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1280 CODEC_F1C_LOCATION_REAR,
1281 CODEC_F1C_DEVICE_SPDIF_OUT,
1282 CODEC_F1C_CONNECTION_TYPE_DIN,
1283 CODEC_F1C_COLOR_BLACK,
1284 CODEC_F1C_MISC_NONE,
1285 CODEC_F1C_ASSOCIATION_GROUP_2, 0x0 /* Seq */);
1286 break;
1287 }
1288
1289 case STAC9220_NID_PIN_SPDIF_IN:
1290 {
1291 pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 -> D3 */
1292 pNode->digin.u32F07_param = CODEC_F07_IN_ENABLE;
1293 pNode->digin.u32F08_param = 0;
1294 pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
1295 pNode->digin.u32F0c_param = 0;
1296
1297 pNode->digin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 3, 0)
1298 | CODEC_F00_09_CAP_POWER_CTRL
1299 | CODEC_F00_09_CAP_DIGITAL
1300 | CODEC_F00_09_CAP_UNSOL
1301 | CODEC_F00_09_CAP_STEREO;
1302
1303 pNode->digin.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
1304 | CODEC_F00_0C_CAP_INPUT
1305 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
1306 if (!pThis->fInReset)
1307 pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1308 CODEC_F1C_LOCATION_REAR,
1309 CODEC_F1C_DEVICE_SPDIF_IN,
1310 CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
1311 CODEC_F1C_COLOR_BLACK,
1312 CODEC_F1C_MISC_NONE,
1313 CODEC_F1C_ASSOCIATION_GROUP_5, 0x0 /* Seq */);
1314 break;
1315 }
1316
1317 case STAC9220_NID_ADC0_MUX:
1318 {
1319 pNode->adcmux.u32F01_param = 0; /* Connection select control index (STAC9220_NID_PIN_E). */
1320 goto adcmux_init;
1321 }
1322
1323 case STAC9220_NID_ADC1_MUX:
1324 {
1325 pNode->adcmux.u32F01_param = 1; /* Connection select control index (STAC9220_NID_PIN_CD). */
1326 /* Fall through is intentional. */
1327
1328 adcmux_init:
1329
1330 pNode->adcmux.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
1331 | CODEC_F00_09_CAP_CONNECTION_LIST
1332 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
1333 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1334 | CODEC_F00_09_CAP_STEREO;
1335
1336 pNode->adcmux.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 27, 4, 0);
1337
1338 /* Connection list entries. */
1339 pNode->adcmux.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 7 /* Entries */);
1340 pNode->adcmux.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_E,
1341 STAC9220_NID_PIN_CD,
1342 STAC9220_NID_PIN_F,
1343 STAC9220_NID_PIN_B);
1344 pNode->adcmux.node.au32F02_param[0x4] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_C,
1345 STAC9220_NID_PIN_HEADPHONE1,
1346 STAC9220_NID_PIN_HEADPHONE0,
1347 0x0 /* Unused */);
1348
1349 /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplifiers initialized with 0. */
1350 RT_ZERO(pNode->adcmux.B_params);
1351 break;
1352 }
1353
1354 case STAC9220_NID_PCBEEP:
1355 {
1356 pNode->pcbeep.u32F0a_param = 0;
1357
1358 pNode->pcbeep.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
1359 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
1360 | CODEC_F00_09_CAP_OUT_AMP_PRESENT;
1361 pNode->pcbeep.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 17, 3, 3);
1362
1363 RT_ZERO(pNode->pcbeep.B_params);
1364 break;
1365 }
1366
1367 case STAC9220_NID_PIN_CD:
1368 {
1369 pNode->cdnode.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1370 | CODEC_F00_09_CAP_STEREO;
1371 pNode->cdnode.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT;
1372
1373 if (!pThis->fInReset)
1374 pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
1375 CODEC_F1C_LOCATION_INTERNAL,
1376 CODEC_F1C_DEVICE_CD,
1377 CODEC_F1C_CONNECTION_TYPE_ATAPI,
1378 CODEC_F1C_COLOR_UNKNOWN,
1379 CODEC_F1C_MISC_NONE,
1380 CODEC_F1C_ASSOCIATION_GROUP_4, 0x2 /* Seq */);
1381 break;
1382 }
1383
1384 case STAC9220_NID_VOL_KNOB:
1385 {
1386 pNode->volumeKnob.u32F08_param = 0;
1387 pNode->volumeKnob.u32F0f_param = 0x7f;
1388
1389 pNode->volumeKnob.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0, 0);
1390 pNode->volumeKnob.node.au32F00_param[0xD] = RT_BIT(7) | 0x7F;
1391
1392 /* Connection list entries. */
1393 pNode->volumeKnob.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 4 /* Entries */);
1394 pNode->volumeKnob.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_DAC0,
1395 STAC9220_NID_DAC1,
1396 STAC9220_NID_DAC2,
1397 STAC9220_NID_DAC3);
1398 break;
1399 }
1400
1401 case STAC9220_NID_AMP_ADC0: /* ADC0Vol */
1402 {
1403 pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC0_MUX;
1404 goto adcvol_init;
1405 }
1406
1407 case STAC9220_NID_AMP_ADC1: /* ADC1Vol */
1408 {
1409 pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC1_MUX;
1410 /* Fall through is intentional. */
1411
1412 adcvol_init:
1413
1414 pNode->adcvol.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
1415 | CODEC_F00_09_CAP_L_R_SWAP
1416 | CODEC_F00_09_CAP_CONNECTION_LIST
1417 | CODEC_F00_09_CAP_IN_AMP_PRESENT
1418 | CODEC_F00_09_CAP_STEREO;
1419
1420
1421 pNode->adcvol.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1422
1423 RT_ZERO(pNode->adcvol.B_params);
1424 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
1425 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
1426 break;
1427 }
1428
1429 /*
1430 * STAC9221 nodes.
1431 */
1432
1433 case STAC9221_NID_ADAT_OUT:
1434 {
1435 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 3, 0)
1436 | CODEC_F00_09_CAP_DIGITAL
1437 | CODEC_F00_09_CAP_STEREO;
1438 break;
1439 }
1440
1441 case STAC9221_NID_I2S_OUT:
1442 {
1443 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 3, 0)
1444 | CODEC_F00_09_CAP_DIGITAL
1445 | CODEC_F00_09_CAP_STEREO;
1446 break;
1447 }
1448
1449 case STAC9221_NID_PIN_I2S_OUT:
1450 {
1451 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1452 | CODEC_F00_09_CAP_DIGITAL
1453 | CODEC_F00_09_CAP_CONNECTION_LIST
1454 | CODEC_F00_09_CAP_STEREO;
1455
1456 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
1457
1458 /* Connection list entries. */
1459 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1460 pNode->node.au32F02_param[0] = STAC9221_NID_I2S_OUT;
1461
1462 if (!pThis->fInReset)
1463 pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
1464 CODEC_F1C_LOCATION_NA,
1465 CODEC_F1C_DEVICE_LINE_OUT,
1466 CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
1467 CODEC_F1C_COLOR_UNKNOWN,
1468 CODEC_F1C_MISC_NONE,
1469 CODEC_F1C_ASSOCIATION_GROUP_15, 0x0 /* Ignored */);
1470 break;
1471 }
1472
1473 default:
1474 AssertMsgFailed(("Node %RU8 not implemented\n", uNID));
1475 break;
1476 }
1477
1478 return VINF_SUCCESS;
1479}
1480
1481static int stac9220Construct(PHDACODEC pThis)
1482{
1483 unconst(pThis->cTotalNodes) = STAC9221_NUM_NODES;
1484
1485 pThis->pfnReset = stac9220Reset;
1486 pThis->pfnNodeReset = stac9220ResetNode;
1487
1488 pThis->u16VendorId = 0x8384; /* SigmaTel */
1489 /*
1490 * Note: The Linux kernel uses "patch_stac922x" for the fixups,
1491 * which in turn uses "ref922x_pin_configs" for the configuration
1492 * defaults tweaking in sound/pci/hda/patch_sigmatel.c.
1493 */
1494 pThis->u16DeviceId = 0x7680; /* STAC9221 A1 */
1495 pThis->u8BSKU = 0x76;
1496 pThis->u8AssemblyId = 0x80;
1497
1498 pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes);
1499 if (!pThis->paNodes)
1500 return VERR_NO_MEMORY;
1501
1502 pThis->fInReset = false;
1503
1504#define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s
1505 STAC9220WIDGET(Port);
1506 STAC9220WIDGET(Dac);
1507 STAC9220WIDGET(Adc);
1508 STAC9220WIDGET(AdcVol);
1509 STAC9220WIDGET(AdcMux);
1510 STAC9220WIDGET(Pcbeep);
1511 STAC9220WIDGET(SpdifIn);
1512 STAC9220WIDGET(SpdifOut);
1513 STAC9220WIDGET(DigInPin);
1514 STAC9220WIDGET(DigOutPin);
1515 STAC9220WIDGET(Cd);
1516 STAC9220WIDGET(VolKnob);
1517 STAC9220WIDGET(Reserved);
1518#undef STAC9220WIDGET
1519
1520 unconst(pThis->u8AdcVolsLineIn) = STAC9220_NID_AMP_ADC0;
1521 unconst(pThis->u8DacLineOut) = STAC9220_NID_DAC1;
1522
1523 /*
1524 * Initialize all codec nodes.
1525 * This is specific to the codec, so do this here.
1526 *
1527 * Note: Do *not* call stac9220Reset() here, as this would not
1528 * initialize the node default configuration values then!
1529 */
1530 AssertPtr(pThis->paNodes);
1531 AssertPtr(pThis->pfnNodeReset);
1532
1533 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
1534 {
1535 int rc2 = stac9220ResetNode(pThis, i, &pThis->paNodes[i]);
1536 AssertRC(rc2);
1537 }
1538
1539 return VINF_SUCCESS;
1540}
1541
1542
1543/*
1544 * Some generic predicate functions.
1545 */
1546
1547#define DECLISNODEOFTYPE(type) \
1548 DECLINLINE(bool) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
1549 { \
1550 Assert(pThis->au8##type##s); \
1551 for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
1552 if (pThis->au8##type##s[i] == cNode) \
1553 return true; \
1554 return false; \
1555 }
1556/* hdaCodecIsPortNode */
1557DECLISNODEOFTYPE(Port)
1558/* hdaCodecIsDacNode */
1559DECLISNODEOFTYPE(Dac)
1560/* hdaCodecIsAdcVolNode */
1561DECLISNODEOFTYPE(AdcVol)
1562/* hdaCodecIsAdcNode */
1563DECLISNODEOFTYPE(Adc)
1564/* hdaCodecIsAdcMuxNode */
1565DECLISNODEOFTYPE(AdcMux)
1566/* hdaCodecIsPcbeepNode */
1567DECLISNODEOFTYPE(Pcbeep)
1568/* hdaCodecIsSpdifOutNode */
1569DECLISNODEOFTYPE(SpdifOut)
1570/* hdaCodecIsSpdifInNode */
1571DECLISNODEOFTYPE(SpdifIn)
1572/* hdaCodecIsDigInPinNode */
1573DECLISNODEOFTYPE(DigInPin)
1574/* hdaCodecIsDigOutPinNode */
1575DECLISNODEOFTYPE(DigOutPin)
1576/* hdaCodecIsCdNode */
1577DECLISNODEOFTYPE(Cd)
1578/* hdaCodecIsVolKnobNode */
1579DECLISNODEOFTYPE(VolKnob)
1580/* hdaCodecIsReservedNode */
1581DECLISNODEOFTYPE(Reserved)
1582
1583
1584/*
1585 * Misc helpers.
1586 */
1587static int hdaCodecToAudVolume(PHDACODEC pThis, PCODECNODE pNode, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
1588{
1589 RT_NOREF(pNode);
1590
1591 uint8_t iDir;
1592 switch (enmMixerCtl)
1593 {
1594 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
1595 case PDMAUDIOMIXERCTL_FRONT:
1596 iDir = AMPLIFIER_OUT;
1597 break;
1598 case PDMAUDIOMIXERCTL_LINE_IN:
1599 case PDMAUDIOMIXERCTL_MIC_IN:
1600 iDir = AMPLIFIER_IN;
1601 break;
1602 default:
1603 AssertMsgFailedReturn(("Invalid mixer control %RU32\n", enmMixerCtl), VERR_INVALID_PARAMETER);
1604 break;
1605 }
1606
1607 int iMute;
1608 iMute = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
1609 iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
1610 iMute >>=7;
1611 iMute &= 0x1;
1612
1613 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & 0x7f;
1614 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
1615
1616 /*
1617 * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
1618 * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
1619 * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
1620 * to 1 (rather than zero) internally.
1621 */
1622 lVol = (lVol + 1) * (2 * 255) / 256;
1623 rVol = (rVol + 1) * (2 * 255) / 256;
1624
1625 PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
1626
1627 LogFunc(("[NID0x%02x] %RU8/%RU8 (%s)\n",
1628 pNode->node.uID, lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
1629
1630 LogRel2(("HDA: Setting volume for mixer control '%s' to %RU8/%RU8 (%s)\n",
1631 DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
1632
1633 return pThis->pfnCbMixerSetVolume(pThis->pDevIns, enmMixerCtl, &Vol);
1634}
1635
1636DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
1637{
1638 Assert((pu32Reg && u8Offset < 32));
1639 *pu32Reg &= ~(mask << u8Offset);
1640 *pu32Reg |= (u32Cmd & mask) << u8Offset;
1641}
1642
1643DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
1644{
1645 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
1646}
1647
1648DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
1649{
1650 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
1651}
1652
1653
1654/*
1655 * Verb processor functions.
1656 */
1657#if 0 /* unused */
1658
1659static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1660{
1661 RT_NOREF(pThis, cmd);
1662 LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
1663 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
1664 *pResp = 0;
1665 return VINF_SUCCESS;
1666}
1667
1668static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1669{
1670 int rc;
1671 rc = vrbProcUnimplemented(pThis, cmd, pResp);
1672 *pResp |= CODEC_RESPONSE_UNSOLICITED;
1673 return rc;
1674}
1675
1676#endif /* unused */
1677
1678/* B-- */
1679static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1680{
1681 *pResp = 0;
1682
1683 /* HDA spec 7.3.3.7 Note A */
1684 /** @todo If index out of range response should be 0. */
1685 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(cmd);
1686
1687 PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
1688 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1689 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
1690 CODEC_GET_AMP_DIRECTION(cmd),
1691 CODEC_GET_AMP_SIDE(cmd),
1692 u8Index);
1693 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1694 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
1695 CODEC_GET_AMP_DIRECTION(cmd),
1696 CODEC_GET_AMP_SIDE(cmd),
1697 u8Index);
1698 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1699 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
1700 CODEC_GET_AMP_DIRECTION(cmd),
1701 CODEC_GET_AMP_SIDE(cmd),
1702 u8Index);
1703 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1704 *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
1705 CODEC_GET_AMP_DIRECTION(cmd),
1706 CODEC_GET_AMP_SIDE(cmd),
1707 u8Index);
1708 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1709 *pResp = AMPLIFIER_REGISTER(pNode->port.B_params,
1710 CODEC_GET_AMP_DIRECTION(cmd),
1711 CODEC_GET_AMP_SIDE(cmd),
1712 u8Index);
1713 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1714 *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
1715 CODEC_GET_AMP_DIRECTION(cmd),
1716 CODEC_GET_AMP_SIDE(cmd),
1717 u8Index);
1718 else
1719 LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd), CODEC_NID(cmd)));
1720
1721 return VINF_SUCCESS;
1722}
1723
1724/* 3-- */
1725static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1726{
1727 *pResp = 0;
1728
1729 PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
1730 AMPLIFIER *pAmplifier = NULL;
1731 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1732 pAmplifier = &pNode->dac.B_params;
1733 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1734 pAmplifier = &pNode->adcvol.B_params;
1735 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1736 pAmplifier = &pNode->adcmux.B_params;
1737 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1738 pAmplifier = &pNode->pcbeep.B_params;
1739 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1740 pAmplifier = &pNode->port.B_params;
1741 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1742 pAmplifier = &pNode->adc.B_params;
1743 else
1744 LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
1745 cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd), CODEC_NID(cmd)));
1746
1747 if (!pAmplifier)
1748 return VINF_SUCCESS;
1749
1750 bool fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
1751 bool fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
1752 bool fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
1753 bool fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
1754 uint8_t u8Index = CODEC_SET_AMP_INDEX(cmd);
1755
1756 if ( (!fIsLeft && !fIsRight)
1757 || (!fIsOut && !fIsIn))
1758 return VINF_SUCCESS;
1759
1760 LogFunc(("[NID0x%02x] fIsOut=%RTbool, fIsIn=%RTbool, fIsLeft=%RTbool, fIsRight=%RTbool, Idx=%RU8\n",
1761 CODEC_NID(cmd), fIsOut, fIsIn, fIsLeft, fIsRight, u8Index));
1762
1763 if (fIsIn)
1764 {
1765 if (fIsLeft)
1766 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
1767 if (fIsRight)
1768 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1769
1770 // if (CODEC_NID(cmd) == pThis->u8AdcVolsLineIn)
1771 // {
1772 hdaCodecToAudVolume(pThis, pNode, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
1773 // }
1774 }
1775 if (fIsOut)
1776 {
1777 if (fIsLeft)
1778 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
1779 if (fIsRight)
1780 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1781
1782 if (CODEC_NID(cmd) == pThis->u8DacLineOut)
1783 hdaCodecToAudVolume(pThis, pNode, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
1784 }
1785
1786 return VINF_SUCCESS;
1787}
1788
1789static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1790{
1791 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
1792 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
1793 {
1794 *pResp = 0;
1795
1796 LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1797 return VINF_SUCCESS;
1798 }
1799
1800 *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
1801 return VINF_SUCCESS;
1802}
1803
1804/* F01 */
1805static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1806{
1807 *pResp = 0;
1808
1809 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1810 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1811 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1812 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
1813 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1814 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
1815 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1816 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
1817 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1818 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1819 else
1820 LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1821
1822 return VINF_SUCCESS;
1823}
1824
1825/* 701 */
1826static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1827{
1828 *pResp = 0;
1829
1830 uint32_t *pu32Reg = NULL;
1831 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1832 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1833 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1834 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
1835 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1836 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
1837 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1838 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
1839 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1840 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1841 else
1842 LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1843
1844 if (pu32Reg)
1845 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1846
1847 return VINF_SUCCESS;
1848}
1849
1850/* F07 */
1851static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1852{
1853 *pResp = 0;
1854
1855 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1856 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
1857 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1858 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
1859 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1860 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
1861 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1862 *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1863 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1864 *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1865 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1866 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1867 else
1868 LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1869
1870 return VINF_SUCCESS;
1871}
1872
1873/* 707 */
1874static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1875{
1876 *pResp = 0;
1877
1878 uint32_t *pu32Reg = NULL;
1879 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1880 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
1881 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1882 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
1883 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1884 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
1885 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1886 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1887 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1888 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1889 else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))
1890 && CODEC_NID(cmd) == 0x1b)
1891 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1892 else
1893 LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1894
1895 if (pu32Reg)
1896 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1897
1898 return VINF_SUCCESS;
1899}
1900
1901/* F08 */
1902static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1903{
1904 *pResp = 0;
1905
1906 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1907 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
1908 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1909 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1910 else if ((cmd) == STAC9220_NID_AFG)
1911 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
1912 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1913 *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1914 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1915 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
1916 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1917 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1918 else
1919 LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1920
1921 return VINF_SUCCESS;
1922}
1923
1924/* 708 */
1925static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1926{
1927 *pResp = 0;
1928
1929 uint32_t *pu32Reg = NULL;
1930 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1931 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
1932 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1933 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1934 else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1935 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
1936 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1937 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1938 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1939 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1940 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1941 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
1942 else
1943 LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1944
1945 if (pu32Reg)
1946 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1947
1948 return VINF_SUCCESS;
1949}
1950
1951/* F09 */
1952static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1953{
1954 *pResp = 0;
1955
1956 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1957 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
1958 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1959 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
1960 else
1961 {
1962 AssertFailed();
1963 LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1964 }
1965
1966 return VINF_SUCCESS;
1967}
1968
1969/* 709 */
1970static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1971{
1972 *pResp = 0;
1973
1974 uint32_t *pu32Reg = NULL;
1975 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1976 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
1977 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1978 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
1979 else
1980 LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1981
1982 if (pu32Reg)
1983 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1984
1985 return VINF_SUCCESS;
1986}
1987
1988static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1989{
1990 *pResp = 0;
1991
1992 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
1993 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
1994 {
1995 LogFlowFunc(("access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1996 return VINF_SUCCESS;
1997 }
1998 *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA];
1999 return VINF_SUCCESS;
2000}
2001
2002/* F03 */
2003static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2004{
2005 *pResp = 0;
2006
2007 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2008 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param;
2009
2010 return VINF_SUCCESS;
2011}
2012
2013/* 703 */
2014static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2015{
2016 *pResp = 0;
2017
2018 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2019 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
2020 return VINF_SUCCESS;
2021}
2022
2023/* F0D */
2024static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2025{
2026 *pResp = 0;
2027
2028 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2029 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
2030 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2031 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
2032
2033 return VINF_SUCCESS;
2034}
2035
2036static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
2037{
2038 *pResp = 0;
2039
2040 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2041 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
2042 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2043 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
2044 return VINF_SUCCESS;
2045}
2046
2047/* 70D */
2048static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2049{
2050 return codecSetDigitalConverter(pThis, cmd, 0, pResp);
2051}
2052
2053/* 70E */
2054static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2055{
2056 return codecSetDigitalConverter(pThis, cmd, 8, pResp);
2057}
2058
2059/* F20 */
2060static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2061{
2062 Assert(CODEC_CAD(cmd) == pThis->id);
2063 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2064 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2065 {
2066 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2067 return VINF_SUCCESS;
2068 }
2069 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2070 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
2071 else
2072 *pResp = 0;
2073 return VINF_SUCCESS;
2074}
2075
2076static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
2077{
2078 Assert(CODEC_CAD(cmd) == pThis->id);
2079 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2080 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2081 {
2082 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2083 return VINF_SUCCESS;
2084 }
2085 uint32_t *pu32Reg;
2086 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2087 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
2088 else
2089 AssertFailedReturn(VINF_SUCCESS);
2090 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
2091 return VINF_SUCCESS;
2092}
2093
2094/* 720 */
2095static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2096{
2097 *pResp = 0;
2098 return codecSetSubIdX(pThis, cmd, 0);
2099}
2100
2101/* 721 */
2102static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2103{
2104 *pResp = 0;
2105 return codecSetSubIdX(pThis, cmd, 8);
2106}
2107
2108/* 722 */
2109static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2110{
2111 *pResp = 0;
2112 return codecSetSubIdX(pThis, cmd, 16);
2113}
2114
2115/* 723 */
2116static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2117{
2118 *pResp = 0;
2119 return codecSetSubIdX(pThis, cmd, 24);
2120}
2121
2122static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2123{
2124 Assert(CODEC_CAD(cmd) == pThis->id);
2125 Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
2126
2127 if ( CODEC_NID(cmd) == STAC9220_NID_AFG
2128 && pThis->pfnReset)
2129 {
2130 pThis->pfnReset(pThis);
2131 }
2132
2133 *pResp = 0;
2134 return VINF_SUCCESS;
2135}
2136
2137/* F05 */
2138static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2139{
2140 *pResp = 0;
2141
2142 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2143 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
2144 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2145 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
2146 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2147 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
2148 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2149 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
2150 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2151 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
2152 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2153 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
2154 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2155 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
2156 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2157 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
2158 else
2159 LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2160
2161 LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
2162 CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_ACT(*pResp), CODEC_F05_SET(*pResp)));
2163 return VINF_SUCCESS;
2164}
2165
2166/* 705 */
2167#if 1
2168static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2169{
2170 *pResp = 0;
2171
2172 uint32_t *pu32Reg = NULL;
2173 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2174 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
2175 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2176 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
2177 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2178 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
2179 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2180 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
2181 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2182 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
2183 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2184 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
2185 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2186 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
2187 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2188 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
2189 else
2190 {
2191 LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2192 }
2193
2194 if (!pu32Reg)
2195 return VINF_SUCCESS;
2196
2197 uint8_t uPwrCmd = CODEC_F05_SET (cmd);
2198 bool fReset = CODEC_F05_IS_RESET (*pu32Reg);
2199 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
2200#ifdef LOG_ENABLED
2201 bool fError = CODEC_F05_IS_ERROR (*pu32Reg);
2202 uint8_t uPwrAct = CODEC_F05_ACT (*pu32Reg);
2203 uint8_t uPwrSet = CODEC_F05_SET (*pu32Reg);
2204 LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
2205 CODEC_NID(cmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
2206 LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
2207 CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param),
2208 CODEC_F05_SET(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param)));
2209#endif
2210
2211 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2212 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
2213
2214 const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param);
2215 if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
2216 {
2217 /* Propagate to all other nodes under this AFG. */
2218 LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
2219
2220#define PROPAGATE_PWR_STATE(_aList, _aMember) \
2221 { \
2222 const uint8_t *pu8NodeIndex = &_aList[0]; \
2223 while (*(++pu8NodeIndex)) \
2224 { \
2225 pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param = \
2226 CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
2227 LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", *pu8NodeIndex, \
2228 CODEC_F05_ACT(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param), \
2229 CODEC_F05_SET(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param))); \
2230 } \
2231 }
2232
2233 PROPAGATE_PWR_STATE(pThis->au8Dacs, dac);
2234 PROPAGATE_PWR_STATE(pThis->au8Adcs, adc);
2235 PROPAGATE_PWR_STATE(pThis->au8DigInPins, digin);
2236 PROPAGATE_PWR_STATE(pThis->au8DigOutPins, digout);
2237 PROPAGATE_PWR_STATE(pThis->au8SpdifIns, spdifin);
2238 PROPAGATE_PWR_STATE(pThis->au8SpdifOuts, spdifout);
2239 PROPAGATE_PWR_STATE(pThis->au8Reserveds, reserved);
2240
2241#undef PROPAGATE_PWR_STATE
2242 }
2243 /*
2244 * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
2245 * as PS-Set of this node. PS-Act always is one level under PS-Set here.
2246 */
2247 else
2248 {
2249 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
2250 }
2251
2252 LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
2253 CODEC_NID(cmd),
2254 CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
2255
2256 return VINF_SUCCESS;
2257}
2258#else
2259DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
2260{
2261 Assert(pu32F05_param);
2262 if (!pu32F05_param)
2263 return;
2264 bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
2265 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
2266 uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
2267 *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
2268}
2269
2270static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2271{
2272 Assert(CODEC_CAD(cmd) == pThis->id);
2273 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2274 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2275 {
2276 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2277 return VINF_SUCCESS;
2278 }
2279 *pResp = 0;
2280 uint32_t *pu32Reg;
2281 if (CODEC_NID(cmd) == 1 /* AFG */)
2282 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
2283 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2284 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
2285 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2286 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
2287 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2288 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
2289 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2290 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
2291 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2292 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
2293 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2294 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
2295 else
2296 AssertFailedReturn(VINF_SUCCESS);
2297
2298 bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
2299 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
2300
2301 if (CODEC_NID(cmd) != 1 /* AFG */)
2302 {
2303 /*
2304 * We shouldn't propogate actual power state, which actual for AFG
2305 */
2306 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
2307 CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param),
2308 CODEC_F05_SET(cmd));
2309 }
2310
2311 /* Propagate next power state only if AFG is on or verb modifies AFG power state */
2312 if ( CODEC_NID(cmd) == 1 /* AFG */
2313 || !CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param))
2314 {
2315 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
2316 if ( CODEC_NID(cmd) == 1 /* AFG */
2317 && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
2318 {
2319 /* now we're powered on AFG and may propogate power states on nodes */
2320 const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
2321 while (*(++pu8NodeIndex))
2322 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].dac.u32F05_param);
2323
2324 pu8NodeIndex = &pThis->au8Adcs[0];
2325 while (*(++pu8NodeIndex))
2326 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].adc.u32F05_param);
2327
2328 pu8NodeIndex = &pThis->au8DigInPins[0];
2329 while (*(++pu8NodeIndex))
2330 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].digin.u32F05_param);
2331 }
2332 }
2333 return VINF_SUCCESS;
2334}
2335#endif
2336
2337/* F06 */
2338static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2339{
2340 *pResp = 0;
2341
2342 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2343 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
2344 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2345 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
2346 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2347 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2348 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2349 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2350 else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
2351 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
2352 else
2353 LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2354
2355 LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
2356 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd), CODEC_F00_06_GET_CHANNEL_ID(cmd)));
2357
2358 return VINF_SUCCESS;
2359}
2360
2361/* 706 */
2362static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2363{
2364 *pResp = 0;
2365
2366 uint8_t uSD = CODEC_F00_06_GET_STREAM_ID(cmd);
2367 uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(cmd);
2368
2369 LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8\n",
2370 CODEC_NID(cmd), uSD, uChannel));
2371
2372 ASSERT_GUEST_LOGREL_MSG_RETURN(uSD < HDA_MAX_STREAMS,
2373 ("Setting stream ID #%RU8 is invalid\n", uSD), VERR_INVALID_PARAMETER);
2374
2375 PDMAUDIODIR enmDir;
2376 uint32_t *pu32Addr = NULL;
2377 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2378 {
2379 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
2380 enmDir = PDMAUDIODIR_OUT;
2381 }
2382 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2383 {
2384 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
2385 enmDir = PDMAUDIODIR_IN;
2386 }
2387 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2388 {
2389 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2390 enmDir = PDMAUDIODIR_OUT;
2391 }
2392 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2393 {
2394 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2395 enmDir = PDMAUDIODIR_IN;
2396 }
2397 else
2398 {
2399 enmDir = PDMAUDIODIR_UNKNOWN;
2400 LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2401 }
2402
2403 /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
2404 if (enmDir != PDMAUDIODIR_UNKNOWN)
2405 {
2406 pThis->paNodes[CODEC_NID(cmd)].node.uSD = uSD;
2407 pThis->paNodes[CODEC_NID(cmd)].node.uChannel = uChannel;
2408
2409 if (enmDir == PDMAUDIODIR_OUT)
2410 {
2411 /** @todo Check if non-interleaved streams need a different channel / SDn? */
2412
2413 /* Propagate to the controller. */
2414 pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
2415#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2416 pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
2417 pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
2418#endif
2419 }
2420 else if (enmDir == PDMAUDIODIR_IN)
2421 {
2422 pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
2423#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2424 pThis->pfnCbMixerControl(pThis->pDevIns, PDMAUDIOMIXERCTL_MIC_IN, uSD, uChannel);
2425#endif
2426 }
2427 }
2428
2429 if (pu32Addr)
2430 hdaCodecSetRegisterU8(pu32Addr, cmd, 0);
2431
2432 return VINF_SUCCESS;
2433}
2434
2435/* A0 */
2436static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2437{
2438 *pResp = 0;
2439
2440 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2441 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param;
2442 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2443 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param;
2444 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2445 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param;
2446 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2447 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param;
2448 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2449 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32A_param;
2450 else
2451 LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2452
2453 return VINF_SUCCESS;
2454}
2455
2456/* Also see section 3.7.1. */
2457static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2458{
2459 *pResp = 0;
2460
2461 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2462 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
2463 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2464 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
2465 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2466 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
2467 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2468 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
2469 else
2470 LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2471
2472 return VINF_SUCCESS;
2473}
2474
2475/* F0C */
2476static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2477{
2478 *pResp = 0;
2479
2480 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
2481 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
2482 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2483 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
2484 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2485 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
2486 else
2487 LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2488
2489 return VINF_SUCCESS;
2490}
2491
2492/* 70C */
2493static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2494{
2495 *pResp = 0;
2496
2497 uint32_t *pu32Reg = NULL;
2498 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
2499 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
2500 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2501 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
2502 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2503 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
2504 else
2505 LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2506
2507 if (pu32Reg)
2508 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2509
2510 return VINF_SUCCESS;
2511}
2512
2513/* F0F */
2514static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2515{
2516 *pResp = 0;
2517
2518 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
2519 *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
2520 else
2521 LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2522
2523 return VINF_SUCCESS;
2524}
2525
2526/* 70F */
2527static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2528{
2529 *pResp = 0;
2530
2531 uint32_t *pu32Reg = NULL;
2532 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
2533 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
2534 else
2535 LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2536
2537 if (pu32Reg)
2538 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2539
2540 return VINF_SUCCESS;
2541}
2542
2543/* F15 */
2544static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2545{
2546 RT_NOREF(pThis, cmd);
2547 *pResp = 0;
2548 return VINF_SUCCESS;
2549}
2550
2551/* 715 */
2552static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2553{
2554 RT_NOREF(pThis, cmd);
2555 *pResp = 0;
2556 return VINF_SUCCESS;
2557}
2558
2559/* F16 */
2560static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2561{
2562 RT_NOREF(pThis, cmd);
2563 *pResp = 0;
2564 return VINF_SUCCESS;
2565}
2566
2567/* 716 */
2568static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2569{
2570 RT_NOREF(pThis, cmd);
2571 *pResp = 0;
2572 return VINF_SUCCESS;
2573}
2574
2575/* F17 */
2576static DECLCALLBACK(int) vrbProcGetGPIODirection(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2577{
2578 *pResp = 0;
2579
2580 /* Note: this is true for ALC885. */
2581 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2582 *pResp = pThis->paNodes[1].afg.u32F17_param;
2583 else
2584 LogRel2(("HDA: Warning: Unhandled get GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2585
2586 return VINF_SUCCESS;
2587}
2588
2589/* 717 */
2590static DECLCALLBACK(int) vrbProcSetGPIODirection(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2591{
2592 *pResp = 0;
2593
2594 uint32_t *pu32Reg = NULL;
2595 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2596 pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
2597 else
2598 LogRel2(("HDA: Warning: Unhandled set GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2599
2600 if (pu32Reg)
2601 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2602
2603 return VINF_SUCCESS;
2604}
2605
2606/* F1C */
2607static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2608{
2609 *pResp = 0;
2610
2611 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
2612 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
2613 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2614 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
2615 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2616 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
2617 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
2618 *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
2619 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
2620 *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
2621 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2622 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
2623 else
2624 LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2625
2626 return VINF_SUCCESS;
2627}
2628
2629static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
2630{
2631 uint32_t *pu32Reg = NULL;
2632 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
2633 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
2634 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2635 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
2636 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2637 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
2638 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
2639 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
2640 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
2641 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
2642 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2643 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
2644 else
2645 LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
2646
2647 if (pu32Reg)
2648 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
2649
2650 return VINF_SUCCESS;
2651}
2652
2653/* 71C */
2654static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2655{
2656 *pResp = 0;
2657 return codecSetConfigX(pThis, cmd, 0);
2658}
2659
2660/* 71D */
2661static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2662{
2663 *pResp = 0;
2664 return codecSetConfigX(pThis, cmd, 8);
2665}
2666
2667/* 71E */
2668static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2669{
2670 *pResp = 0;
2671 return codecSetConfigX(pThis, cmd, 16);
2672}
2673
2674/* 71E */
2675static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2676{
2677 *pResp = 0;
2678 return codecSetConfigX(pThis, cmd, 24);
2679}
2680
2681/* F04 */
2682static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2683{
2684 *pResp = 0;
2685
2686 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2687 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
2688 else
2689 LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2690
2691 return VINF_SUCCESS;
2692}
2693
2694/* 704 */
2695static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2696{
2697 *pResp = 0;
2698
2699 uint32_t *pu32Reg = NULL;
2700 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2701 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
2702 else
2703 LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2704
2705 if (pu32Reg)
2706 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2707
2708 return VINF_SUCCESS;
2709}
2710
2711/**
2712 * HDA codec verb map.
2713 * @todo Any reason not to use binary search here?
2714 * bird: because you'd need to sort the entries first...
2715 */
2716static const CODECVERB g_aCodecVerbs[] =
2717{
2718 /* Verb Verb mask Callback Name
2719 * ---------- --------------------- ----------------------------------------------------------
2720 */
2721 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
2722 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
2723 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
2724 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
2725 { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId , "SetStreamId " },
2726 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
2727 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
2728 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
2729 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
2730 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
2731 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
2732 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
2733 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
2734 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
2735 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
2736 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
2737 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
2738 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
2739 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
2740 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
2741 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
2742 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
2743 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
2744 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
2745 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
2746 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
2747 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
2748 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
2749 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
2750 { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
2751 { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
2752 { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
2753 { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
2754 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIODirection , "GetGPIODirection " },
2755 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIODirection , "SetGPIODirection " },
2756 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
2757 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
2758 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
2759 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
2760 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
2761 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
2762 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
2763 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
2764 { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier , "SetAmplifier " },
2765 { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
2766 { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " }
2767 /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
2768};
2769
2770
2771/**
2772 * CODEC debug info item printing state.
2773 */
2774typedef struct CODECDEBUG
2775{
2776 /** DBGF info helpers. */
2777 PCDBGFINFOHLP pHlp;
2778 /** Current recursion level. */
2779 uint8_t uLevel;
2780 /** Pointer to codec state. */
2781 PHDACODEC pThis;
2782} CODECDEBUG;
2783/** Pointer to the debug info item printing state for the codec. */
2784typedef CODECDEBUG *PCODECDEBUG;
2785
2786#define CODECDBG_INDENT pInfo->uLevel++;
2787#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
2788
2789#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2790#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
2791
2792/** Wrapper around DBGFINFOHLP::pfnPrintf that adds identation. */
2793static void codecDbgPrintf(PCODECDEBUG pInfo, const char *pszFormat, ...)
2794{
2795 va_list va;
2796 va_start(va, pszFormat);
2797 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%N", pInfo->uLevel * 4, "", pszFormat, &va);
2798 va_end(va);
2799}
2800
2801/** Power state */
2802static void codecDbgPrintNodeRegF05(PCODECDEBUG pInfo, uint32_t u32Reg)
2803{
2804 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2805 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2806}
2807
2808static void codecDbgPrintNodeRegA(PCODECDEBUG pInfo, uint32_t u32Reg)
2809{
2810 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2811}
2812
2813static void codecDbgPrintNodeRegF00(PCODECDEBUG pInfo, uint32_t *paReg00)
2814{
2815 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2816
2817 CODECDBG_INDENT
2818 codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
2819 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2820 uint32_t uReg = paReg00[0xD];
2821 CODECDBG_INDENT
2822 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2823 CODEC_F00_0D_NUM_STEPS(uReg),
2824 CODEC_F00_0D_STEP_SIZE(uReg),
2825 CODEC_F00_0D_OFFSET(uReg),
2826 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2827
2828 uReg = paReg00[0x12];
2829 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2830 CODEC_F00_12_NUM_STEPS(uReg),
2831 CODEC_F00_12_STEP_SIZE(uReg),
2832 CODEC_F00_12_OFFSET(uReg),
2833 RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
2834 CODECDBG_UNINDENT
2835 CODECDBG_UNINDENT
2836}
2837
2838static void codecDbgPrintNodeAmp(PCODECDEBUG pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
2839{
2840# define CODECDBG_AMP(reg, chan) \
2841 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2842 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2843 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2844 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2845 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg))
2846
2847 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2848 CODECDBG_AMP(regAmp, "Left");
2849 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2850 CODECDBG_AMP(regAmp, "Right");
2851
2852# undef CODECDBG_AMP
2853}
2854
2855# if 0 /* unused */
2856static void codecDbgPrintNodeConnections(PCODECDEBUG pInfo, PCODECNODE pNode)
2857{
2858 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2859 {
2860 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2861 return;
2862 }
2863}
2864# endif
2865
2866static void codecDbgPrintNode(PCODECDEBUG pInfo, PCODECNODE pNode, bool fRecursive)
2867{
2868 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
2869
2870 if (pNode->node.uID == STAC9220_NID_ROOT)
2871 {
2872 CODECDBG_PRINT("ROOT\n");
2873 }
2874 else if (pNode->node.uID == STAC9220_NID_AFG)
2875 {
2876 CODECDBG_PRINT("AFG\n");
2877 CODECDBG_INDENT
2878 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2879 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2880 CODECDBG_UNINDENT
2881 }
2882 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
2883 {
2884 CODECDBG_PRINT("PORT\n");
2885 }
2886 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
2887 {
2888 CODECDBG_PRINT("DAC\n");
2889 CODECDBG_INDENT
2890 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2891 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2892 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2893 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2894 CODECDBG_UNINDENT
2895 }
2896 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
2897 {
2898 CODECDBG_PRINT("ADC VOLUME\n");
2899 CODECDBG_INDENT
2900 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2901 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2902 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2903 CODECDBG_UNINDENT
2904 }
2905 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
2906 {
2907 CODECDBG_PRINT("ADC\n");
2908 CODECDBG_INDENT
2909 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2910 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2911 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2912 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2913 CODECDBG_UNINDENT
2914 }
2915 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
2916 {
2917 CODECDBG_PRINT("ADC MUX\n");
2918 CODECDBG_INDENT
2919 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2920 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2921 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2922 CODECDBG_UNINDENT
2923 }
2924 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
2925 CODECDBG_PRINT("PC BEEP\n");
2926 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
2927 CODECDBG_PRINT("SPDIF OUT\n");
2928 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
2929 CODECDBG_PRINT("SPDIF IN\n");
2930 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
2931 CODECDBG_PRINT("DIGITAL IN PIN\n");
2932 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
2933 CODECDBG_PRINT("DIGITAL OUT PIN\n");
2934 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
2935 CODECDBG_PRINT("CD\n");
2936 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
2937 CODECDBG_PRINT("VOLUME KNOB\n");
2938 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
2939 CODECDBG_PRINT("RESERVED\n");
2940 else
2941 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
2942
2943 if (fRecursive)
2944 {
2945# define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
2946 if (cCnt >= _aEntry) \
2947 { \
2948 const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
2949 if (pNode->node.uID == uID) \
2950 codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
2951 }
2952
2953 /* Slow recursion, but this is debug stuff anyway. */
2954 for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
2955 {
2956 const PCODECNODE pSubNode = &pInfo->pThis->paNodes[i];
2957 if (pSubNode->node.uID == pNode->node.uID)
2958 continue;
2959
2960 const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
2961 if (cCnt == 0) /* No connections present? Skip. */
2962 continue;
2963
2964 CODECDBG_INDENT
2965 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
2966 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
2967 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
2968 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
2969 CODECDBG_UNINDENT
2970 }
2971
2972# undef CODECDBG_PRINT_CONLIST_ENTRY
2973 }
2974}
2975
2976static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
2977{
2978 RT_NOREF(pszArgs);
2979 pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
2980
2981 CODECDEBUG dbgInfo;
2982 dbgInfo.pHlp = pHlp;
2983 dbgInfo.pThis = pThis;
2984 dbgInfo.uLevel = 0;
2985
2986 PCODECDEBUG pInfo = &dbgInfo;
2987
2988 CODECDBG_INDENT
2989 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
2990 {
2991 PCODECNODE pNode = &pThis->paNodes[i];
2992
2993 /* Start with all nodes which have connection entries set. */
2994 if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
2995 codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
2996 }
2997 CODECDBG_UNINDENT
2998}
2999
3000#ifdef DEBUG
3001
3002static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
3003{
3004 RT_NOREF(pThis, pHlp, pszArgs);
3005}
3006
3007#endif /* DEBUG */
3008
3009static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, uint64_t *puResp)
3010{
3011 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3012 AssertPtrReturn(puResp, VERR_INVALID_POINTER);
3013 STAM_COUNTER_INC(&pThis->StatLookups);
3014
3015 if (CODEC_CAD(cmd) != pThis->id)
3016 {
3017 *puResp = 0;
3018 AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
3019 return VERR_INVALID_PARAMETER;
3020 }
3021
3022 if ( CODEC_VERBDATA(cmd) == 0
3023 || CODEC_NID(cmd) >= pThis->cTotalNodes)
3024 {
3025 *puResp = 0;
3026 AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
3027 return VERR_INVALID_PARAMETER;
3028 }
3029
3030 /** @todo r=andy Implement a binary search here. */
3031 for (size_t i = 0; i < pThis->cVerbs; i++)
3032 {
3033 if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
3034 {
3035 int rc2 = pThis->paVerbs[i].pfn(pThis, cmd, puResp);
3036 AssertRC(rc2);
3037 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
3038 CODEC_NID(cmd), pThis->paVerbs[i].verb, pThis->paVerbs[i].pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
3039 return rc2;
3040 }
3041 }
3042
3043 *puResp = 0;
3044 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
3045 return VERR_NOT_FOUND;
3046}
3047
3048/*
3049 * APIs exposed to DevHDA.
3050 */
3051
3052int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
3053{
3054 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3055 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
3056
3057 int rc = VINF_SUCCESS;
3058
3059 switch (enmMixerCtl)
3060 {
3061 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
3062 case PDMAUDIOMIXERCTL_FRONT:
3063#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
3064 case PDMAUDIOMIXERCTL_CENTER_LFE:
3065 case PDMAUDIOMIXERCTL_REAR:
3066#endif
3067 break;
3068
3069 case PDMAUDIOMIXERCTL_LINE_IN:
3070#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
3071 case PDMAUDIOMIXERCTL_MIC_IN:
3072#endif
3073 break;
3074
3075 default:
3076 AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
3077 rc = VERR_NOT_IMPLEMENTED;
3078 break;
3079 }
3080
3081 if (RT_SUCCESS(rc))
3082 rc = pThis->pfnCbMixerAddStream(pThis->pDevIns, enmMixerCtl, pCfg);
3083
3084 LogFlowFuncLeaveRC(rc);
3085 return rc;
3086}
3087
3088int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl)
3089{
3090 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3091
3092 int rc = pThis->pfnCbMixerRemoveStream(pThis->pDevIns, enmMixerCtl);
3093
3094 LogFlowFuncLeaveRC(rc);
3095 return rc;
3096}
3097
3098int hdaCodecSaveState(PPDMDEVINS pDevIns, PHDACODEC pThis, PSSMHANDLE pSSM)
3099{
3100 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3101 AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
3102 VERR_INTERNAL_ERROR);
3103 pHlp->pfnSSMPutU32(pSSM, pThis->cTotalNodes);
3104 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
3105 pHlp->pfnSSMPutStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState),
3106 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
3107 return VINF_SUCCESS;
3108}
3109
3110int hdaCodecLoadState(PPDMDEVINS pDevIns, PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
3111{
3112 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
3113 PCSSMFIELD pFields = NULL;
3114 uint32_t fFlags = 0;
3115 if (uVersion >= HDA_SAVED_STATE_VERSION_4)
3116 {
3117 /* Since version 4 a flexible node count is supported. */
3118 uint32_t cNodes;
3119 int rc2 = pHlp->pfnSSMGetU32(pSSM, &cNodes);
3120 AssertRCReturn(rc2, rc2);
3121 AssertReturn(cNodes == 0x1c, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3122 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3123
3124 pFields = g_aCodecNodeFields;
3125 fFlags = 0;
3126 }
3127 else if (uVersion >= HDA_SAVED_STATE_VERSION_2)
3128 {
3129 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3130 pFields = g_aCodecNodeFields;
3131 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
3132 }
3133 else if (uVersion >= HDA_SAVED_STATE_VERSION_1)
3134 {
3135 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3136 pFields = g_aCodecNodeFieldsV1;
3137 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
3138 }
3139 else
3140 AssertFailedReturn(VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
3141
3142 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
3143 {
3144 uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.uID;
3145 int rc = pHlp->pfnSSMGetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState),
3146 fFlags, pFields, NULL);
3147 AssertRCReturn(rc, rc);
3148 AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.uID,
3149 ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.uID, idOld),
3150 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3151 }
3152
3153 /*
3154 * Update stuff after changing the state.
3155 */
3156 PCODECNODE pNode;
3157 if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
3158 {
3159 pNode = &pThis->paNodes[pThis->u8DacLineOut];
3160 hdaCodecToAudVolume(pThis, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
3161 }
3162 else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
3163 {
3164 pNode = &pThis->paNodes[pThis->u8DacLineOut];
3165 hdaCodecToAudVolume(pThis, pNode, &pNode->spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
3166 }
3167
3168 pNode = &pThis->paNodes[pThis->u8AdcVolsLineIn];
3169 hdaCodecToAudVolume(pThis, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
3170
3171 LogFlowFuncLeaveRC(VINF_SUCCESS);
3172 return VINF_SUCCESS;
3173}
3174
3175/**
3176 * Powers off the codec.
3177 *
3178 * @param pThis Codec to power off.
3179 */
3180void hdaCodecPowerOff(PHDACODEC pThis)
3181{
3182 if (!pThis)
3183 return;
3184
3185 LogFlowFuncEnter();
3186
3187 LogRel2(("HDA: Powering off codec ...\n"));
3188
3189 int rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_FRONT);
3190 AssertRC(rc2);
3191#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
3192 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE);
3193 AssertRC(rc2);
3194 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_REAR);
3195 AssertRC(rc2);
3196#endif
3197
3198#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
3199 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_MIC_IN);
3200 AssertRC(rc2);
3201#endif
3202 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_LINE_IN);
3203 AssertRC(rc2);
3204}
3205
3206void hdaCodecDestruct(PHDACODEC pThis)
3207{
3208 if (!pThis)
3209 return;
3210
3211 LogFlowFuncEnter();
3212
3213 if (pThis->paNodes)
3214 {
3215 RTMemFree(pThis->paNodes);
3216 pThis->paNodes = NULL;
3217 }
3218}
3219
3220int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
3221 uint16_t uLUN, PCFGMNODE pCfg)
3222{
3223 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
3224 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3225 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
3226
3227 pThis->id = uLUN;
3228 pThis->paVerbs = &g_aCodecVerbs[0];
3229 pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
3230
3231#ifdef DEBUG
3232 pThis->pfnDbgSelector = codecDbgSelector;
3233#endif
3234 pThis->pfnDbgListNodes = codecDbgListNodes;
3235 pThis->pfnLookup = codecLookup;
3236
3237 int rc = stac9220Construct(pThis);
3238 AssertRCReturn(rc, rc);
3239
3240 /* Common root node initializers. */
3241 pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
3242 pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
3243
3244 /* Common AFG node initializers. */
3245 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
3246 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
3247 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
3248 pThis->paNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
3249
3250 /*
3251 * Set initial volume.
3252 */
3253 PCODECNODE pNode = &pThis->paNodes[pThis->u8DacLineOut];
3254 hdaCodecToAudVolume(pThis, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
3255
3256 pNode = &pThis->paNodes[pThis->u8AdcVolsLineIn];
3257 hdaCodecToAudVolume(pThis, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
3258#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
3259# error "Implement mic-in support!"
3260#endif
3261
3262 /*
3263 * Statistics
3264 */
3265#ifdef VBOX_WITH_STATISTICS
3266 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatLookups, STAMTYPE_COUNTER, "Codec/Lookups", STAMUNIT_OCCURENCES, "Number of codecLookup calls");
3267#endif
3268
3269 LogFlowFuncLeaveRC(rc);
3270 return rc;
3271}
3272
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette