VirtualBox

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

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

DevHDA: Fixed bug in hdaCodecLoadState showcasing why switch aren't the best way of handling saved state versions. If the switch has current-version case, it's either already broken or just waiting for it to happen. (Current version shouldn't be used anywhere but in the registration statement.) This one broke when the state version was last bumped. bugref:9218

  • 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 82308 2019-12-01 01:20:59Z 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-2019 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->pHDAState, 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->pHDAState, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
2415#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2416 pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
2417 pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
2418#endif
2419 }
2420 else if (enmDir == PDMAUDIODIR_IN)
2421 {
2422 pThis->pfnCbMixerControl(pThis->pHDAState, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
2423#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2424 pThis->pfnCbMixerControl(pThis->pHDAState, 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 */
2715static const CODECVERB g_aCodecVerbs[] =
2716{
2717 /* Verb Verb mask Callback Name
2718 * ---------- --------------------- ----------------------------------------------------------
2719 */
2720 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
2721 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
2722 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
2723 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
2724 { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId , "SetStreamId " },
2725 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
2726 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
2727 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
2728 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
2729 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
2730 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
2731 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
2732 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
2733 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
2734 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
2735 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
2736 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
2737 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
2738 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
2739 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
2740 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
2741 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
2742 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
2743 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
2744 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
2745 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
2746 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
2747 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
2748 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
2749 { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
2750 { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
2751 { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
2752 { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
2753 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIODirection , "GetGPIODirection " },
2754 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIODirection , "SetGPIODirection " },
2755 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
2756 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
2757 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
2758 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
2759 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
2760 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
2761 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
2762 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
2763 { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier , "SetAmplifier " },
2764 { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
2765 { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " }
2766 /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
2767};
2768
2769#ifdef DEBUG
2770typedef struct CODECDBGINFO
2771{
2772 /** DBGF info helpers. */
2773 PCDBGFINFOHLP pHlp;
2774 /** Current recursion level. */
2775 uint8_t uLevel;
2776 /** Pointer to codec state. */
2777 PHDACODEC pThis;
2778
2779} CODECDBGINFO, *PCODECDBGINFO;
2780
2781#define CODECDBG_INDENT pInfo->uLevel++;
2782#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
2783
2784#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2785#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
2786
2787static void codecDbgPrintfIndentV(PCODECDBGINFO pInfo, uint16_t uIndent, const char *pszFormat, va_list va)
2788{
2789 char *pszValueFormat;
2790 if (RTStrAPrintfV(&pszValueFormat, pszFormat, va))
2791 {
2792 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%s", uIndent, "", pszValueFormat);
2793 RTStrFree(pszValueFormat);
2794 }
2795}
2796
2797static void codecDbgPrintf(PCODECDBGINFO pInfo, const char *pszFormat, ...)
2798{
2799 va_list va;
2800 va_start(va, pszFormat);
2801 codecDbgPrintfIndentV(pInfo, pInfo->uLevel * 4, pszFormat, va);
2802 va_end(va);
2803}
2804
2805/* Power state */
2806static void codecDbgPrintNodeRegF05(PCODECDBGINFO pInfo, uint32_t u32Reg)
2807{
2808 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2809 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2810}
2811
2812static void codecDbgPrintNodeRegA(PCODECDBGINFO pInfo, uint32_t u32Reg)
2813{
2814 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2815}
2816
2817static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
2818{
2819 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2820
2821 CODECDBG_INDENT
2822 codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
2823 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2824 uint32_t uReg = paReg00[0xD];
2825 CODECDBG_INDENT
2826 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2827 CODEC_F00_0D_NUM_STEPS(uReg),
2828 CODEC_F00_0D_STEP_SIZE(uReg),
2829 CODEC_F00_0D_OFFSET(uReg),
2830 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2831
2832 uReg = paReg00[0x12];
2833 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2834 CODEC_F00_12_NUM_STEPS(uReg),
2835 CODEC_F00_12_STEP_SIZE(uReg),
2836 CODEC_F00_12_OFFSET(uReg),
2837 RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
2838 CODECDBG_UNINDENT
2839 CODECDBG_UNINDENT
2840}
2841
2842static void codecDbgPrintNodeAmp(PCODECDBGINFO pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
2843{
2844#define CODECDBG_AMP(reg, chan) \
2845 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2846 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2847 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2848 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2849 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg));
2850
2851 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2852 CODECDBG_AMP(regAmp, "Left");
2853 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2854 CODECDBG_AMP(regAmp, "Right");
2855
2856#undef CODECDBG_AMP
2857}
2858
2859#if 0 /* unused */
2860static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
2861{
2862 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2863 {
2864 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2865 return;
2866 }
2867}
2868#endif
2869
2870static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecursive)
2871{
2872 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
2873
2874 if (pNode->node.uID == STAC9220_NID_ROOT)
2875 {
2876 CODECDBG_PRINT("ROOT\n");
2877 }
2878 else if (pNode->node.uID == STAC9220_NID_AFG)
2879 {
2880 CODECDBG_PRINT("AFG\n");
2881 CODECDBG_INDENT
2882 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2883 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2884 CODECDBG_UNINDENT
2885 }
2886 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
2887 {
2888 CODECDBG_PRINT("PORT\n");
2889 }
2890 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
2891 {
2892 CODECDBG_PRINT("DAC\n");
2893 CODECDBG_INDENT
2894 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2895 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2896 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2897 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2898 CODECDBG_UNINDENT
2899 }
2900 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
2901 {
2902 CODECDBG_PRINT("ADC VOLUME\n");
2903 CODECDBG_INDENT
2904 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2905 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2906 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2907 CODECDBG_UNINDENT
2908 }
2909 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
2910 {
2911 CODECDBG_PRINT("ADC\n");
2912 CODECDBG_INDENT
2913 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2914 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2915 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2916 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2917 CODECDBG_UNINDENT
2918 }
2919 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
2920 {
2921 CODECDBG_PRINT("ADC MUX\n");
2922 CODECDBG_INDENT
2923 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2924 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2925 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2926 CODECDBG_UNINDENT
2927 }
2928 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
2929 {
2930 CODECDBG_PRINT("PC BEEP\n");
2931 }
2932 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
2933 {
2934 CODECDBG_PRINT("SPDIF OUT\n");
2935 }
2936 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
2937 {
2938 CODECDBG_PRINT("SPDIF IN\n");
2939 }
2940 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
2941 {
2942 CODECDBG_PRINT("DIGITAL IN PIN\n");
2943 }
2944 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
2945 {
2946 CODECDBG_PRINT("DIGITAL OUT PIN\n");
2947 }
2948 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
2949 {
2950 CODECDBG_PRINT("CD\n");
2951 }
2952 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
2953 {
2954 CODECDBG_PRINT("VOLUME KNOB\n");
2955 }
2956 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
2957 {
2958 CODECDBG_PRINT("RESERVED\n");
2959 }
2960 else
2961 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
2962
2963 if (fRecursive)
2964 {
2965#define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
2966 if (cCnt >= _aEntry) \
2967 { \
2968 const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
2969 if (pNode->node.uID == uID) \
2970 codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
2971 }
2972
2973 /* Slow recursion, but this is debug stuff anyway. */
2974 for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
2975 {
2976 const PCODECNODE pSubNode = &pInfo->pThis->paNodes[i];
2977 if (pSubNode->node.uID == pNode->node.uID)
2978 continue;
2979
2980 const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
2981 if (cCnt == 0) /* No connections present? Skip. */
2982 continue;
2983
2984 CODECDBG_INDENT
2985 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
2986 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
2987 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
2988 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
2989 CODECDBG_UNINDENT
2990 }
2991
2992#undef CODECDBG_PRINT_CONLIST_ENTRY
2993 }
2994}
2995
2996static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
2997{
2998 RT_NOREF(pszArgs);
2999 pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
3000
3001 CODECDBGINFO dbgInfo;
3002 dbgInfo.pHlp = pHlp;
3003 dbgInfo.pThis = pThis;
3004 dbgInfo.uLevel = 0;
3005
3006 PCODECDBGINFO pInfo = &dbgInfo;
3007
3008 CODECDBG_INDENT
3009 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
3010 {
3011 PCODECNODE pNode = &pThis->paNodes[i];
3012
3013 /* Start with all nodes which have connection entries set. */
3014 if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
3015 codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
3016 }
3017 CODECDBG_UNINDENT
3018}
3019
3020static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
3021{
3022 RT_NOREF(pThis, pHlp, pszArgs);
3023}
3024#endif
3025
3026static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, uint64_t *puResp)
3027{
3028 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3029 AssertPtrReturn(puResp, VERR_INVALID_POINTER);
3030
3031 if (CODEC_CAD(cmd) != pThis->id)
3032 {
3033 *puResp = 0;
3034 AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
3035 return VERR_INVALID_PARAMETER;
3036 }
3037
3038 if ( CODEC_VERBDATA(cmd) == 0
3039 || CODEC_NID(cmd) >= pThis->cTotalNodes)
3040 {
3041 *puResp = 0;
3042 AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
3043 return VERR_INVALID_PARAMETER;
3044 }
3045
3046 /** @todo r=andy Implement a binary search here. */
3047 for (size_t i = 0; i < pThis->cVerbs; i++)
3048 {
3049 if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
3050 {
3051 int rc2 = pThis->paVerbs[i].pfn(pThis, cmd, puResp);
3052 AssertRC(rc2);
3053 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
3054 CODEC_NID(cmd), pThis->paVerbs[i].verb, pThis->paVerbs[i].pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
3055 return rc2;
3056 }
3057 }
3058
3059 *puResp = 0;
3060 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
3061 return VERR_NOT_FOUND;
3062}
3063
3064/*
3065 * APIs exposed to DevHDA.
3066 */
3067
3068int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
3069{
3070 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3071 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
3072
3073 int rc = VINF_SUCCESS;
3074
3075 switch (enmMixerCtl)
3076 {
3077 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
3078 case PDMAUDIOMIXERCTL_FRONT:
3079#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
3080 case PDMAUDIOMIXERCTL_CENTER_LFE:
3081 case PDMAUDIOMIXERCTL_REAR:
3082#endif
3083 {
3084 break;
3085 }
3086 case PDMAUDIOMIXERCTL_LINE_IN:
3087#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
3088 case PDMAUDIOMIXERCTL_MIC_IN:
3089#endif
3090 {
3091 break;
3092 }
3093 default:
3094 AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
3095 rc = VERR_NOT_IMPLEMENTED;
3096 break;
3097 }
3098
3099 if (RT_SUCCESS(rc))
3100 rc = pThis->pfnCbMixerAddStream(pThis->pHDAState, enmMixerCtl, pCfg);
3101
3102 LogFlowFuncLeaveRC(rc);
3103 return rc;
3104}
3105
3106int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl)
3107{
3108 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3109
3110 int rc = pThis->pfnCbMixerRemoveStream(pThis->pHDAState, enmMixerCtl);
3111
3112 LogFlowFuncLeaveRC(rc);
3113 return rc;
3114}
3115
3116int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
3117{
3118 AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
3119 VERR_INTERNAL_ERROR);
3120 SSMR3PutU32(pSSM, pThis->cTotalNodes);
3121 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
3122 SSMR3PutStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState),
3123 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
3124 return VINF_SUCCESS;
3125}
3126
3127int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
3128{
3129 PCSSMFIELD pFields = NULL;
3130 uint32_t fFlags = 0;
3131 if (uVersion >= HDA_SAVED_STATE_VERSION_4)
3132 {
3133 /* Since version 4 a flexible node count is supported. */
3134 uint32_t cNodes;
3135 int rc2 = SSMR3GetU32(pSSM, &cNodes);
3136 AssertRCReturn(rc2, rc2);
3137 AssertReturn(cNodes == 0x1c, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3138 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3139
3140 pFields = g_aCodecNodeFields;
3141 fFlags = 0;
3142 }
3143 else if (uVersion >= HDA_SAVED_STATE_VERSION_2)
3144 {
3145 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3146 pFields = g_aCodecNodeFields;
3147 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
3148 }
3149 else if (uVersion >= HDA_SAVED_STATE_VERSION_1)
3150 {
3151 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3152 pFields = g_aCodecNodeFieldsV1;
3153 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
3154 }
3155 else
3156 AssertFailedReturn(VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
3157
3158 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
3159 {
3160 uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.uID;
3161 int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState,
3162 sizeof(pThis->paNodes[idxNode].SavedState),
3163 fFlags, pFields, NULL);
3164 AssertRCReturn(rc, rc);
3165 AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.uID,
3166 ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.uID, idOld),
3167 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3168 }
3169
3170 /*
3171 * Update stuff after changing the state.
3172 */
3173 PCODECNODE pNode;
3174 if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
3175 {
3176 pNode = &pThis->paNodes[pThis->u8DacLineOut];
3177 hdaCodecToAudVolume(pThis, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
3178 }
3179 else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
3180 {
3181 pNode = &pThis->paNodes[pThis->u8DacLineOut];
3182 hdaCodecToAudVolume(pThis, pNode, &pNode->spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
3183 }
3184
3185 pNode = &pThis->paNodes[pThis->u8AdcVolsLineIn];
3186 hdaCodecToAudVolume(pThis, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
3187
3188 LogFlowFuncLeaveRC(VINF_SUCCESS);
3189 return VINF_SUCCESS;
3190}
3191
3192/**
3193 * Powers off the codec.
3194 *
3195 * @param pThis Codec to power off.
3196 */
3197void hdaCodecPowerOff(PHDACODEC pThis)
3198{
3199 if (!pThis)
3200 return;
3201
3202 LogFlowFuncEnter();
3203
3204 LogRel2(("HDA: Powering off codec ...\n"));
3205
3206 int rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_FRONT);
3207 AssertRC(rc2);
3208#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
3209 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE);
3210 AssertRC(rc2);
3211 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_REAR);
3212 AssertRC(rc2);
3213#endif
3214
3215#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
3216 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_MIC_IN);
3217 AssertRC(rc2);
3218#endif
3219 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_LINE_IN);
3220 AssertRC(rc2);
3221}
3222
3223void hdaCodecDestruct(PHDACODEC pThis)
3224{
3225 if (!pThis)
3226 return;
3227
3228 LogFlowFuncEnter();
3229
3230 if (pThis->paNodes)
3231 {
3232 RTMemFree(pThis->paNodes);
3233 pThis->paNodes = NULL;
3234 }
3235}
3236
3237int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
3238 uint16_t uLUN, PCFGMNODE pCfg)
3239{
3240 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
3241 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3242 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
3243
3244 pThis->id = uLUN;
3245 pThis->paVerbs = &g_aCodecVerbs[0];
3246 pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
3247
3248#ifdef DEBUG
3249 pThis->pfnDbgSelector = codecDbgSelector;
3250 pThis->pfnDbgListNodes = codecDbgListNodes;
3251#endif
3252 pThis->pfnLookup = codecLookup;
3253
3254 int rc = stac9220Construct(pThis);
3255 AssertRCReturn(rc, rc);
3256
3257 /* Common root node initializers. */
3258 pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
3259 pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
3260
3261 /* Common AFG node initializers. */
3262 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
3263 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
3264 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
3265 pThis->paNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
3266
3267 /*
3268 * Set initial volume.
3269 */
3270 PCODECNODE pNode = &pThis->paNodes[pThis->u8DacLineOut];
3271 hdaCodecToAudVolume(pThis, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
3272
3273 pNode = &pThis->paNodes[pThis->u8AdcVolsLineIn];
3274 hdaCodecToAudVolume(pThis, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
3275#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
3276# error "Implement mic-in support!"
3277#endif
3278
3279 LogFlowFuncLeaveRC(rc);
3280 return rc;
3281}
3282
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