VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp@ 60756

Last change on this file since 60756 was 60643, checked in by vboxsync, 9 years ago

HDA: Presence must be inited for each node separately.

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