VirtualBox

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

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

Audio/HDA:

  • Lowered timer to 100Hz and start/stop it only if needed. Should improve overall performance.
  • More work on dynamic stream assignments (SDI/SDO select) by the guest -- should make more Linux guests compatible with HDA.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 137.3 KB
Line 
1/* $Id: DevIchHdaCodec.cpp 60941 2016-05-12 13:12:20Z 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 /** The node's ID. */
553 uint8_t uID;
554 /** The node's name. */
555 char const *pszName;
556 /** The SDn ID this node is assigned to.
557 * 0 means not assigned, 1 is SDn0. */
558 uint8_t uSD;
559 /** The SDn's channel to use.
560 * Only valid if a valid SDn ID is set. */
561 uint8_t uChannel;
562 /* PRM 5.3.6 */
563 uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH];
564 uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH];
565} CODECCOMMONNODE;
566typedef CODECCOMMONNODE *PCODECCOMMONNODE;
567AssertCompile(CODECNODE_F00_PARAM_LENGTH == 20); /* saved state */
568AssertCompile(CODECNODE_F02_PARAM_LENGTH == 16); /* saved state */
569
570/**
571 * Compile time assertion on the expected node size.
572 */
573#define AssertNodeSize(a_Node, a_cParams) \
574 AssertCompile((a_cParams) <= (60 + 6)); /* the max size - saved state */ \
575 AssertCompile( sizeof(a_Node) - sizeof(CODECCOMMONNODE) \
576 == (((a_cParams) * sizeof(uint32_t) + sizeof(void *) - 1) & ~(sizeof(void *) - 1)) )
577
578typedef struct ROOTCODECNODE
579{
580 CODECCOMMONNODE node;
581} ROOTCODECNODE, *PROOTCODECNODE;
582AssertNodeSize(ROOTCODECNODE, 0);
583
584#define AMPLIFIER_SIZE 60
585typedef uint32_t AMPLIFIER[AMPLIFIER_SIZE];
586#define AMPLIFIER_IN 0
587#define AMPLIFIER_OUT 1
588#define AMPLIFIER_LEFT 1
589#define AMPLIFIER_RIGHT 0
590#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)])
591typedef struct DACNODE
592{
593 CODECCOMMONNODE node;
594 uint32_t u32F0d_param;
595 uint32_t u32F04_param;
596 uint32_t u32F05_param;
597 uint32_t u32F06_param;
598 uint32_t u32F0c_param;
599
600 uint32_t u32A_param;
601 AMPLIFIER B_params;
602
603} DACNODE, *PDACNODE;
604AssertNodeSize(DACNODE, 6 + 60);
605
606typedef struct ADCNODE
607{
608 CODECCOMMONNODE node;
609 uint32_t u32F01_param;
610 uint32_t u32F03_param;
611 uint32_t u32F05_param;
612 uint32_t u32F06_param;
613 uint32_t u32F09_param;
614
615 uint32_t u32A_param;
616 AMPLIFIER B_params;
617} ADCNODE, *PADCNODE;
618AssertNodeSize(DACNODE, 6 + 60);
619
620typedef struct SPDIFOUTNODE
621{
622 CODECCOMMONNODE node;
623 uint32_t u32F05_param;
624 uint32_t u32F06_param;
625 uint32_t u32F09_param;
626 uint32_t u32F0d_param;
627
628 uint32_t u32A_param;
629 AMPLIFIER B_params;
630} SPDIFOUTNODE, *PSPDIFOUTNODE;
631AssertNodeSize(SPDIFOUTNODE, 5 + 60);
632
633typedef struct SPDIFINNODE
634{
635 CODECCOMMONNODE node;
636 uint32_t u32F05_param;
637 uint32_t u32F06_param;
638 uint32_t u32F09_param;
639 uint32_t u32F0d_param;
640
641 uint32_t u32A_param;
642 AMPLIFIER B_params;
643} SPDIFINNODE, *PSPDIFINNODE;
644AssertNodeSize(SPDIFINNODE, 5 + 60);
645
646typedef struct AFGCODECNODE
647{
648 CODECCOMMONNODE node;
649 uint32_t u32F05_param;
650 uint32_t u32F08_param;
651 uint32_t u32F17_param;
652 uint32_t u32F20_param;
653} AFGCODECNODE, *PAFGCODECNODE;
654AssertNodeSize(AFGCODECNODE, 4);
655
656typedef struct PORTNODE
657{
658 CODECCOMMONNODE node;
659 uint32_t u32F01_param;
660 uint32_t u32F07_param;
661 uint32_t u32F08_param;
662 uint32_t u32F09_param;
663 uint32_t u32F1c_param;
664 AMPLIFIER B_params;
665} PORTNODE, *PPORTNODE;
666AssertNodeSize(PORTNODE, 5 + 60);
667
668typedef struct DIGOUTNODE
669{
670 CODECCOMMONNODE node;
671 uint32_t u32F01_param;
672 uint32_t u32F05_param;
673 uint32_t u32F07_param;
674 uint32_t u32F08_param;
675 uint32_t u32F09_param;
676 uint32_t u32F1c_param;
677} DIGOUTNODE, *PDIGOUTNODE;
678AssertNodeSize(DIGOUTNODE, 6);
679
680typedef struct DIGINNODE
681{
682 CODECCOMMONNODE node;
683 uint32_t u32F05_param;
684 uint32_t u32F07_param;
685 uint32_t u32F08_param;
686 uint32_t u32F09_param;
687 uint32_t u32F0c_param;
688 uint32_t u32F1c_param;
689 uint32_t u32F1e_param;
690} DIGINNODE, *PDIGINNODE;
691AssertNodeSize(DIGINNODE, 7);
692
693typedef struct ADCMUXNODE
694{
695 CODECCOMMONNODE node;
696 uint32_t u32F01_param;
697
698 uint32_t u32A_param;
699 AMPLIFIER B_params;
700} ADCMUXNODE, *PADCMUXNODE;
701AssertNodeSize(ADCMUXNODE, 2 + 60);
702
703typedef struct PCBEEPNODE
704{
705 CODECCOMMONNODE node;
706 uint32_t u32F07_param;
707 uint32_t u32F0a_param;
708
709 uint32_t u32A_param;
710 AMPLIFIER B_params;
711 uint32_t u32F1c_param;
712} PCBEEPNODE, *PPCBEEPNODE;
713AssertNodeSize(PCBEEPNODE, 3 + 60 + 1);
714
715typedef struct CDNODE
716{
717 CODECCOMMONNODE node;
718 uint32_t u32F07_param;
719 uint32_t u32F1c_param;
720} CDNODE, *PCDNODE;
721AssertNodeSize(CDNODE, 2);
722
723typedef struct VOLUMEKNOBNODE
724{
725 CODECCOMMONNODE node;
726 uint32_t u32F08_param;
727 uint32_t u32F0f_param;
728} VOLUMEKNOBNODE, *PVOLUMEKNOBNODE;
729AssertNodeSize(VOLUMEKNOBNODE, 2);
730
731typedef struct ADCVOLNODE
732{
733 CODECCOMMONNODE node;
734 uint32_t u32F0c_param;
735 uint32_t u32F01_param;
736 uint32_t u32A_params;
737 AMPLIFIER B_params;
738} ADCVOLNODE, *PADCVOLNODE;
739AssertNodeSize(ADCVOLNODE, 3 + 60);
740
741typedef struct RESNODE
742{
743 CODECCOMMONNODE node;
744 uint32_t u32F05_param;
745 uint32_t u32F06_param;
746 uint32_t u32F07_param;
747 uint32_t u32F1c_param;
748
749 uint32_t u32A_param;
750} RESNODE, *PRESNODE;
751AssertNodeSize(RESNODE, 5);
752
753/**
754 * Used for the saved state.
755 */
756typedef struct CODECSAVEDSTATENODE
757{
758 CODECCOMMONNODE Core;
759 uint32_t au32Params[60 + 6];
760} CODECSAVEDSTATENODE;
761AssertNodeSize(CODECSAVEDSTATENODE, 60 + 6);
762
763typedef union CODECNODE
764{
765 CODECCOMMONNODE node;
766 ROOTCODECNODE root;
767 AFGCODECNODE afg;
768 DACNODE dac;
769 ADCNODE adc;
770 SPDIFOUTNODE spdifout;
771 SPDIFINNODE spdifin;
772 PORTNODE port;
773 DIGOUTNODE digout;
774 DIGINNODE digin;
775 ADCMUXNODE adcmux;
776 PCBEEPNODE pcbeep;
777 CDNODE cdnode;
778 VOLUMEKNOBNODE volumeKnob;
779 ADCVOLNODE adcvol;
780 RESNODE reserved;
781 CODECSAVEDSTATENODE SavedState;
782} CODECNODE, *PCODECNODE;
783AssertNodeSize(CODECNODE, 60 + 6);
784
785
786/*********************************************************************************************************************************
787* Global Variables *
788*********************************************************************************************************************************/
789/* STAC9220 - Nodes IDs / names. */
790#define STAC9220_NID_ROOT 0x0 /* Root node */
791#define STAC9220_NID_AFG 0x1 /* Audio Configuration Group */
792#define STAC9220_NID_DAC0 0x2 /* Out */
793#define STAC9220_NID_DAC1 0x3 /* Out */
794#define STAC9220_NID_DAC2 0x4 /* Out */
795#define STAC9220_NID_DAC3 0x5 /* Out */
796#define STAC9220_NID_ADC0 0x6 /* In */
797#define STAC9220_NID_ADC1 0x7 /* In */
798#define STAC9220_NID_SPDIF_OUT 0x8 /* Out */
799#define STAC9220_NID_SPDIF_IN 0x9 /* In */
800/** Also known as PIN_A. */
801#define STAC9220_NID_PIN_HEADPHONE0 0xA /* In, Out */
802#define STAC9220_NID_PIN_B 0xB /* In, Out */
803#define STAC9220_NID_PIN_C 0xC /* In, Out */
804/** Also known as PIN D. */
805#define STAC9220_NID_PIN_HEADPHONE1 0xD /* In, Out */
806#define STAC9220_NID_PIN_E 0xE /* In */
807#define STAC9220_NID_PIN_F 0xF /* In, Out */
808/** Also known as DIGOUT0. */
809#define STAC9220_NID_PIN_SPDIF_OUT 0x10 /* Out */
810/** Also known as DIGIN. */
811#define STAC9220_NID_PIN_SPDIF_IN 0x11 /* In */
812#define STAC9220_NID_ADC0_MUX 0x12 /* In */
813#define STAC9220_NID_ADC1_MUX 0x13 /* In */
814#define STAC9220_NID_PCBEEP 0x14 /* Out */
815#define STAC9220_NID_PIN_CD 0x15 /* In */
816#define STAC9220_NID_VOL_KNOB 0x16
817#define STAC9220_NID_AMP_ADC0 0x17 /* In */
818#define STAC9220_NID_AMP_ADC1 0x18 /* In */
819/* Only for STAC9221. */
820#define STAC9221_NID_ADAT_OUT 0x19 /* Out */
821#define STAC9221_NID_I2S_OUT 0x1A /* Out */
822#define STAC9221_NID_PIN_I2S_OUT 0x1B /* Out */
823
824/** Number of total nodes emulated. */
825#define STAC9221_NUM_NODES 0x1C
826
827/* STAC9220 - Referenced through STAC9220WIDGET in the constructor below. */
828static 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 };
829static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0 };
830static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0 };
831static uint8_t const g_abStac9220SpdifOuts[] = { STAC9220_NID_SPDIF_OUT, 0 };
832static uint8_t const g_abStac9220SpdifIns[] = { STAC9220_NID_SPDIF_IN, 0 };
833static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
834static uint8_t const g_abStac9220DigInPins[] = { STAC9220_NID_PIN_SPDIF_IN, 0 };
835static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0 };
836static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0 };
837static uint8_t const g_abStac9220Pcbeeps[] = { STAC9220_NID_PCBEEP, 0 };
838static uint8_t const g_abStac9220Cds[] = { STAC9220_NID_PIN_CD, 0 };
839static uint8_t const g_abStac9220VolKnobs[] = { STAC9220_NID_VOL_KNOB, 0 };
840/* STAC 9221. */
841/** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
842static uint8_t const g_abStac9220Reserveds[] = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
843
844/** SSM description of a CODECNODE. */
845static SSMFIELD const g_aCodecNodeFields[] =
846{
847 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
848 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
849 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
850 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
851 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
852 SSMFIELD_ENTRY_TERM()
853};
854
855/** Backward compatibility with v1 of the CODECNODE. */
856static SSMFIELD const g_aCodecNodeFieldsV1[] =
857{
858 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
859 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
860 SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
861 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
862 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
863 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
864 SSMFIELD_ENTRY_TERM()
865};
866
867
868
869
870static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
871{
872 for (int i = 1; i < pThis->cTotalNodes; i++)
873 {
874 PCODECNODE pNode = &pThis->paNodes[i];
875 AMPLIFIER *pAmp = &pNode->dac.B_params;
876
877 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) & 0x7f;
878 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) & 0x7f;
879
880 pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
881 }
882}
883
884
885static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t uNID, PCODECNODE pNode)
886{
887 LogFlowFunc(("NID=0x%x (%RU8)\n", uNID, uNID));
888
889 if ( !pThis->fInReset
890 && ( uNID != STAC9220_NID_ROOT
891 && uNID != STAC9220_NID_AFG)
892 )
893 {
894 RT_ZERO(pNode->node);
895 }
896
897 /* Set common parameters across all nodes. */
898 pNode->node.uID = uNID;
899 pNode->node.uSD = 0;
900
901 switch (uNID)
902 {
903 /* Root node. */
904 case STAC9220_NID_ROOT:
905 {
906 /* Set the revision ID. */
907 pNode->root.node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x3, 0x4, 0x0, 0x1);
908 break;
909 }
910
911 /*
912 * AFG (Audio Function Group).
913 */
914 case STAC9220_NID_AFG:
915 {
916 pNode->afg.node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
917 /* We set the AFG's PCM capabitilies fixed to 44.1kHz, 16-bit signed. */
918 pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
919 pNode->afg.node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
920 pNode->afg.node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
921 | CODEC_F00_0C_CAP_BALANCED_IO
922 | CODEC_F00_0C_CAP_INPUT
923 | CODEC_F00_0C_CAP_OUTPUT
924 | CODEC_F00_0C_CAP_PRESENCE_DETECT
925 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
926 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;
927
928 /* Default input amplifier capabilities. */
929 pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
930 0 /* Step size */,
931 CODEC_AMP_NUM_STEPS,
932 0 /* Initial offset */);
933 /* Default output amplifier capabilities. */
934 pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
935 CODEC_AMP_STEP_SIZE,
936 CODEC_AMP_NUM_STEPS,
937 CODEC_AMP_OFF_INITIAL);
938
939 pNode->afg.node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);
940 pNode->afg.node.au32F00_param[0x0F] = CODEC_F00_0F_D3
941 | CODEC_F00_0F_D2
942 | CODEC_F00_0F_D1
943 | CODEC_F00_0F_D0;
944
945 pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2); /* PS-Act: D2, PS->Set D2. */
946 pNode->afg.u32F08_param = 0;
947 pNode->afg.u32F17_param = 0;
948 break;
949 }
950
951 /*
952 * DACs.
953 */
954 case STAC9220_NID_DAC0: /* DAC0: Headphones 0 + 1 */
955 case STAC9220_NID_DAC1: /* DAC1: PIN C */
956 case STAC9220_NID_DAC2: /* DAC2: PIN B */
957 case STAC9220_NID_DAC3: /* DAC3: PIN F */
958 {
959 pNode->dac.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
960 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
961 HDA_SDFMT_CHAN_STEREO);
962
963 /* 7.3.4.6: Audio widget capabilities. */
964 pNode->dac.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 13, 0)
965 | CODEC_F00_09_CAP_L_R_SWAP
966 | CODEC_F00_09_CAP_POWER_CTRL
967 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
968 | CODEC_F00_09_CAP_STEREO;
969
970 /* Connection list; must be 0 if the only connection for the widget is
971 * to the High Definition Audio Link. */
972 pNode->dac.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 0 /* Entries */);
973
974 pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);
975
976 RT_ZERO(pNode->dac.B_params);
977 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
978 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
979 break;
980 }
981
982 /*
983 * ADCs.
984 */
985 case STAC9220_NID_ADC0: /* Analog input. */
986 {
987 pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC0;
988 goto adc_init;
989 }
990
991 case STAC9220_NID_ADC1: /* Analog input (CD). */
992 {
993 pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC1;
994
995 /* Fall through is intentional. */
996 adc_init:
997
998 pNode->adc.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
999 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
1000 HDA_SDFMT_CHAN_STEREO);
1001
1002 pNode->adc.u32F03_param = RT_BIT(0);
1003 pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
1004
1005 pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 13, 0)
1006 | CODEC_F00_09_CAP_POWER_CTRL
1007 | CODEC_F00_09_CAP_CONNECTION_LIST
1008 | CODEC_F00_09_CAP_PROC_WIDGET
1009 | CODEC_F00_09_CAP_STEREO;
1010 /* Connection list entries. */
1011 pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1012 break;
1013 }
1014
1015 /*
1016 * SP/DIF In/Out.
1017 */
1018 case STAC9220_NID_SPDIF_OUT:
1019 {
1020 pNode->spdifout.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
1021 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
1022 HDA_SDFMT_CHAN_STEREO);
1023 pNode->spdifout.u32F06_param = 0;
1024 pNode->spdifout.u32F0d_param = 0;
1025
1026 pNode->spdifout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 4, 0)
1027 | CODEC_F00_09_CAP_DIGITAL
1028 | CODEC_F00_09_CAP_FMT_OVERRIDE
1029 | CODEC_F00_09_CAP_STEREO;
1030
1031 /* Use a fixed format from AFG. */
1032 pNode->spdifout.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
1033 pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
1034 break;
1035 }
1036
1037 case STAC9220_NID_SPDIF_IN:
1038 {
1039 pNode->spdifin.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
1040 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
1041 HDA_SDFMT_CHAN_STEREO);
1042
1043 pNode->spdifin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 4, 0)
1044 | CODEC_F00_09_CAP_DIGITAL
1045 | CODEC_F00_09_CAP_CONNECTION_LIST
1046 | CODEC_F00_09_CAP_FMT_OVERRIDE
1047 | CODEC_F00_09_CAP_STEREO;
1048
1049 /* Use a fixed format from AFG. */
1050 pNode->spdifin.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
1051 pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
1052
1053 /* Connection list entries. */
1054 pNode->spdifin.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1055 pNode->spdifin.node.au32F02_param[0] = 0x11;
1056 break;
1057 }
1058
1059 /*
1060 * PINs / Ports.
1061 */
1062 case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
1063 {
1064 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(false /*fPresent*/, CODEC_F09_ANALOG_NA);
1065
1066 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1067 | CODEC_F00_0C_CAP_INPUT
1068 | CODEC_F00_0C_CAP_OUTPUT
1069 | CODEC_F00_0C_CAP_HEADPHONE_AMP
1070 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1071 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1072
1073 /* Connection list entry 0: Goes to DAC0. */
1074 pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC0;
1075
1076 if (!pThis->fInReset)
1077 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1078 CODEC_F1C_LOCATION_FRONT,
1079 CODEC_F1C_DEVICE_HP,
1080 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1081 CODEC_F1C_COLOR_GREEN,
1082 CODEC_F1C_MISC_NONE,
1083 CODEC_F1C_ASSOCIATION_GROUP_1, 0x0 /* Seq */);
1084 goto port_init;
1085 }
1086
1087 case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
1088 {
1089 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /*fPresent*/, CODEC_F09_ANALOG_NA);
1090
1091 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1092 | CODEC_F00_0C_CAP_INPUT
1093 | CODEC_F00_0C_CAP_OUTPUT
1094 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1095 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1096
1097 /* Connection list entry 0: Goes to DAC2. */
1098 pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC2;
1099
1100 if (!pThis->fInReset)
1101 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1102 CODEC_F1C_LOCATION_REAR,
1103 CODEC_F1C_DEVICE_SPEAKER,
1104 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1105 CODEC_F1C_COLOR_BLACK,
1106 CODEC_F1C_MISC_NONE,
1107 CODEC_F1C_ASSOCIATION_GROUP_0, 0x1 /* Seq */);
1108 goto port_init;
1109 }
1110
1111 case STAC9220_NID_PIN_C: /* Rear Speaker. */
1112 {
1113 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /*fPresent*/, CODEC_F09_ANALOG_NA);
1114
1115 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1116 | CODEC_F00_0C_CAP_INPUT
1117 | CODEC_F00_0C_CAP_OUTPUT
1118 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1119 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1120
1121 /* Connection list entry 0: Goes to DAC1. */
1122 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC1;
1123
1124 if (!pThis->fInReset)
1125 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1126 CODEC_F1C_LOCATION_REAR,
1127 CODEC_F1C_DEVICE_SPEAKER,
1128 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1129 CODEC_F1C_COLOR_GREEN,
1130 CODEC_F1C_MISC_NONE,
1131 CODEC_F1C_ASSOCIATION_GROUP_0, 0x0 /* Seq */);
1132 goto port_init;
1133 }
1134
1135 case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
1136 {
1137 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(false /*fPresent*/, CODEC_F09_ANALOG_NA);
1138
1139 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1140 | CODEC_F00_0C_CAP_INPUT
1141 | CODEC_F00_0C_CAP_OUTPUT
1142 | CODEC_F00_0C_CAP_HEADPHONE_AMP
1143 | CODEC_F00_0C_CAP_PRESENCE_DETECT
1144 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
1145
1146 /* Connection list entry 0: Goes to DAC1. */
1147 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC0;
1148
1149 if (!pThis->fInReset)
1150 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1151 CODEC_F1C_LOCATION_FRONT,
1152 CODEC_F1C_DEVICE_MIC,
1153 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1154 CODEC_F1C_COLOR_PINK,
1155 CODEC_F1C_MISC_NONE,
1156 CODEC_F1C_ASSOCIATION_GROUP_4, 0x0 /* Seq */);
1157 /* Fall through is intentional. */
1158
1159 port_init:
1160
1161 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
1162 | CODEC_F07_OUT_ENABLE;
1163 pNode->port.u32F08_param = 0;
1164
1165 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1166 | CODEC_F00_09_CAP_CONNECTION_LIST
1167 | CODEC_F00_09_CAP_UNSOL
1168 | CODEC_F00_09_CAP_STEREO;
1169 /* Connection list entries. */
1170 pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1171 break;
1172 }
1173
1174 case STAC9220_NID_PIN_E:
1175 {
1176 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
1177 pNode->port.u32F08_param = 0;
1178 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /* fPresent */, CODEC_F09_ANALOG_NA);
1179
1180 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1181 | CODEC_F00_09_CAP_UNSOL
1182 | CODEC_F00_09_CAP_STEREO;
1183
1184 pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
1185 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
1186
1187 if (!pThis->fInReset)
1188 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1189 CODEC_F1C_LOCATION_REAR,
1190 CODEC_F1C_DEVICE_LINE_IN,
1191 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1192 CODEC_F1C_COLOR_BLUE,
1193 CODEC_F1C_MISC_NONE,
1194 CODEC_F1C_ASSOCIATION_GROUP_4, 0x1 /* Seq */);
1195 break;
1196 }
1197
1198 case STAC9220_NID_PIN_F:
1199 {
1200 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE | CODEC_F07_OUT_ENABLE;
1201 pNode->port.u32F08_param = 0;
1202 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /* fPresent */, CODEC_F09_ANALOG_NA);
1203
1204 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1205 | CODEC_F00_09_CAP_CONNECTION_LIST
1206 | CODEC_F00_09_CAP_UNSOL
1207 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1208 | CODEC_F00_09_CAP_STEREO;
1209
1210 pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
1211 | CODEC_F00_0C_CAP_OUTPUT;
1212
1213 /* Connection list entry 0: Goes to DAC3. */
1214 pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1215 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC3;
1216
1217 if (!pThis->fInReset)
1218 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1219 CODEC_F1C_LOCATION_INTERNAL,
1220 CODEC_F1C_DEVICE_SPEAKER,
1221 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1222 CODEC_F1C_COLOR_ORANGE,
1223 CODEC_F1C_MISC_NONE,
1224 CODEC_F1C_ASSOCIATION_GROUP_0, 0x2 /* Seq */);
1225 break;
1226 }
1227
1228 case STAC9220_NID_PIN_SPDIF_OUT: /* Rear SPDIF Out. */
1229 {
1230 pNode->digout.u32F07_param = CODEC_F07_OUT_ENABLE;
1231 pNode->digout.u32F09_param = 0;
1232
1233 pNode->digout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1234 | CODEC_F00_09_CAP_DIGITAL
1235 | CODEC_F00_09_CAP_CONNECTION_LIST
1236 | CODEC_F00_09_CAP_STEREO;
1237 pNode->digout.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT
1238 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
1239
1240 /* Connection list entries. */
1241 pNode->digout.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 3 /* Entries */);
1242 pNode->digout.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_SPDIF_OUT,
1243 STAC9220_NID_AMP_ADC0, STAC9221_NID_ADAT_OUT, 0);
1244 if (!pThis->fInReset)
1245 pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1246 CODEC_F1C_LOCATION_REAR,
1247 CODEC_F1C_DEVICE_SPDIF_OUT,
1248 CODEC_F1C_CONNECTION_TYPE_DIN,
1249 CODEC_F1C_COLOR_BLACK,
1250 CODEC_F1C_MISC_NONE,
1251 CODEC_F1C_ASSOCIATION_GROUP_2, 0x0 /* Seq */);
1252 break;
1253 }
1254
1255 case STAC9220_NID_PIN_SPDIF_IN:
1256 {
1257 pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 -> D3 */
1258 pNode->digin.u32F07_param = CODEC_F07_IN_ENABLE;
1259 pNode->digin.u32F08_param = 0;
1260 pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
1261 pNode->digin.u32F0c_param = 0;
1262
1263 pNode->digin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 3, 0)
1264 | CODEC_F00_09_CAP_POWER_CTRL
1265 | CODEC_F00_09_CAP_DIGITAL
1266 | CODEC_F00_09_CAP_UNSOL
1267 | CODEC_F00_09_CAP_STEREO;
1268
1269 pNode->digin.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
1270 | CODEC_F00_0C_CAP_INPUT
1271 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
1272 if (!pThis->fInReset)
1273 pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1274 CODEC_F1C_LOCATION_REAR,
1275 CODEC_F1C_DEVICE_SPDIF_IN,
1276 CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
1277 CODEC_F1C_COLOR_BLACK,
1278 CODEC_F1C_MISC_NONE,
1279 CODEC_F1C_ASSOCIATION_GROUP_5, 0x0 /* Seq */);
1280 break;
1281 }
1282
1283 case STAC9220_NID_ADC0_MUX:
1284 {
1285 pNode->adcmux.u32F01_param = 0; /* Connection select control index (STAC9220_NID_PIN_E). */
1286 goto adcmux_init;
1287 }
1288
1289 case STAC9220_NID_ADC1_MUX:
1290 {
1291 pNode->adcmux.u32F01_param = 1; /* Connection select control index (STAC9220_NID_PIN_CD). */
1292 /* Fall through is intentional. */
1293
1294 adcmux_init:
1295
1296 pNode->adcmux.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
1297 | CODEC_F00_09_CAP_CONNECTION_LIST
1298 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
1299 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1300 | CODEC_F00_09_CAP_STEREO;
1301
1302 pNode->adcmux.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 27, 4, 0);
1303
1304 /* Connection list entries. */
1305 pNode->adcmux.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 7 /* Entries */);
1306 pNode->adcmux.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_E,
1307 STAC9220_NID_PIN_CD,
1308 STAC9220_NID_PIN_F,
1309 STAC9220_NID_PIN_B);
1310 pNode->adcmux.node.au32F02_param[0x4] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_C,
1311 STAC9220_NID_PIN_HEADPHONE1,
1312 STAC9220_NID_PIN_HEADPHONE0,
1313 0x0 /* Unused */);
1314
1315 /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplifiers initialized with 0. */
1316 RT_ZERO(pNode->adcmux.B_params);
1317 break;
1318 }
1319
1320 case STAC9220_NID_PCBEEP:
1321 {
1322 pNode->pcbeep.u32F0a_param = 0;
1323
1324 pNode->pcbeep.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
1325 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
1326 | CODEC_F00_09_CAP_OUT_AMP_PRESENT;
1327 pNode->pcbeep.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 17, 3, 3);
1328
1329 RT_ZERO(pNode->pcbeep.B_params);
1330 break;
1331 }
1332
1333 case STAC9220_NID_PIN_CD:
1334 {
1335 pNode->cdnode.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1336 | CODEC_F00_09_CAP_STEREO;
1337 pNode->cdnode.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT;
1338
1339 if (!pThis->fInReset)
1340 pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
1341 CODEC_F1C_LOCATION_INTERNAL,
1342 CODEC_F1C_DEVICE_CD,
1343 CODEC_F1C_CONNECTION_TYPE_ATAPI,
1344 CODEC_F1C_COLOR_UNKNOWN,
1345 CODEC_F1C_MISC_NONE,
1346 CODEC_F1C_ASSOCIATION_GROUP_4, 0x2 /* Seq */);
1347 break;
1348 }
1349
1350 case STAC9220_NID_VOL_KNOB:
1351 {
1352 pNode->volumeKnob.u32F08_param = 0;
1353 pNode->volumeKnob.u32F0f_param = 0x7f;
1354
1355 pNode->volumeKnob.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0, 0);
1356 pNode->volumeKnob.node.au32F00_param[0xD] = RT_BIT(7) | 0x7F;
1357
1358 /* Connection list entries. */
1359 pNode->volumeKnob.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 4 /* Entries */);
1360 pNode->volumeKnob.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_DAC0,
1361 STAC9220_NID_DAC1,
1362 STAC9220_NID_DAC2,
1363 STAC9220_NID_DAC3);
1364 break;
1365 }
1366
1367 case STAC9220_NID_AMP_ADC0: /* ADC0Vol */
1368 {
1369 pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC0_MUX;
1370 goto adcvol_init;
1371 }
1372
1373 case STAC9220_NID_AMP_ADC1: /* ADC1Vol */
1374 {
1375 pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC1_MUX;
1376 /* Fall through is intentional. */
1377
1378 adcvol_init:
1379
1380 pNode->adcvol.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
1381 | CODEC_F00_09_CAP_L_R_SWAP
1382 | CODEC_F00_09_CAP_CONNECTION_LIST
1383 | CODEC_F00_09_CAP_IN_AMP_PRESENT
1384 | CODEC_F00_09_CAP_STEREO;
1385
1386
1387 pNode->adcvol.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1388
1389 RT_ZERO(pNode->adcvol.B_params);
1390 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
1391 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
1392 break;
1393 }
1394
1395 /*
1396 * STAC9221 nodes.
1397 */
1398
1399 case STAC9221_NID_ADAT_OUT:
1400 {
1401 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 3, 0)
1402 | CODEC_F00_09_CAP_DIGITAL
1403 | CODEC_F00_09_CAP_STEREO;
1404 break;
1405 }
1406
1407 case STAC9221_NID_I2S_OUT:
1408 {
1409 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 3, 0)
1410 | CODEC_F00_09_CAP_DIGITAL
1411 | CODEC_F00_09_CAP_STEREO;
1412 break;
1413 }
1414
1415 case STAC9221_NID_PIN_I2S_OUT:
1416 {
1417 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1418 | CODEC_F00_09_CAP_DIGITAL
1419 | CODEC_F00_09_CAP_CONNECTION_LIST
1420 | CODEC_F00_09_CAP_STEREO;
1421
1422 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
1423
1424 /* Connection list entries. */
1425 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
1426 pNode->node.au32F02_param[0] = STAC9221_NID_I2S_OUT;
1427
1428 if (!pThis->fInReset)
1429 pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
1430 CODEC_F1C_LOCATION_NA,
1431 CODEC_F1C_DEVICE_LINE_OUT,
1432 CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
1433 CODEC_F1C_COLOR_UNKNOWN,
1434 CODEC_F1C_MISC_NONE,
1435 CODEC_F1C_ASSOCIATION_GROUP_15, 0xB /* Seq */);
1436 break;
1437 }
1438
1439 default:
1440 AssertMsgFailed(("Node %RU8 not implemented\n", uNID));
1441 break;
1442 }
1443
1444 return VINF_SUCCESS;
1445}
1446
1447static int stac9220Construct(PHDACODEC pThis)
1448{
1449 unconst(pThis->cTotalNodes) = STAC9221_NUM_NODES;
1450
1451 pThis->pfnCodecNodeReset = stac9220ResetNode;
1452
1453 pThis->u16VendorId = 0x8384; /* SigmaTel */
1454 /*
1455 * Note: The Linux kernel uses "patch_stac922x" for the fixups,
1456 * which in turn uses "ref922x_pin_configs" for the configuration
1457 * defaults tweaking in sound/pci/hda/patch_sigmatel.c.
1458 */
1459 pThis->u16DeviceId = 0x7680; /* STAC9221 A1 */
1460 pThis->u8BSKU = 0x76;
1461 pThis->u8AssemblyId = 0x80;
1462
1463 pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes);
1464 if (!pThis->paNodes)
1465 return VERR_NO_MEMORY;
1466
1467 pThis->fInReset = false;
1468
1469#define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s
1470 STAC9220WIDGET(Port);
1471 STAC9220WIDGET(Dac);
1472 STAC9220WIDGET(Adc);
1473 STAC9220WIDGET(AdcVol);
1474 STAC9220WIDGET(AdcMux);
1475 STAC9220WIDGET(Pcbeep);
1476 STAC9220WIDGET(SpdifIn);
1477 STAC9220WIDGET(SpdifOut);
1478 STAC9220WIDGET(DigInPin);
1479 STAC9220WIDGET(DigOutPin);
1480 STAC9220WIDGET(Cd);
1481 STAC9220WIDGET(VolKnob);
1482 STAC9220WIDGET(Reserved);
1483#undef STAC9220WIDGET
1484
1485 unconst(pThis->u8AdcVolsLineIn) = STAC9220_NID_AMP_ADC0;
1486 unconst(pThis->u8DacLineOut) = STAC9220_NID_DAC1;
1487
1488 return VINF_SUCCESS;
1489}
1490
1491
1492/*
1493 * Some generic predicate functions.
1494 */
1495
1496#define DECLISNODEOFTYPE(type) \
1497 DECLINLINE(bool) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
1498 { \
1499 Assert(pThis->au8##type##s); \
1500 for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
1501 if (pThis->au8##type##s[i] == cNode) \
1502 return true; \
1503 return false; \
1504 }
1505/* hdaCodecIsPortNode */
1506DECLISNODEOFTYPE(Port)
1507/* hdaCodecIsDacNode */
1508DECLISNODEOFTYPE(Dac)
1509/* hdaCodecIsAdcVolNode */
1510DECLISNODEOFTYPE(AdcVol)
1511/* hdaCodecIsAdcNode */
1512DECLISNODEOFTYPE(Adc)
1513/* hdaCodecIsAdcMuxNode */
1514DECLISNODEOFTYPE(AdcMux)
1515/* hdaCodecIsPcbeepNode */
1516DECLISNODEOFTYPE(Pcbeep)
1517/* hdaCodecIsSpdifOutNode */
1518DECLISNODEOFTYPE(SpdifOut)
1519/* hdaCodecIsSpdifInNode */
1520DECLISNODEOFTYPE(SpdifIn)
1521/* hdaCodecIsDigInPinNode */
1522DECLISNODEOFTYPE(DigInPin)
1523/* hdaCodecIsDigOutPinNode */
1524DECLISNODEOFTYPE(DigOutPin)
1525/* hdaCodecIsCdNode */
1526DECLISNODEOFTYPE(Cd)
1527/* hdaCodecIsVolKnobNode */
1528DECLISNODEOFTYPE(VolKnob)
1529/* hdaCodecIsReservedNode */
1530DECLISNODEOFTYPE(Reserved)
1531
1532
1533/*
1534 * Misc helpers.
1535 */
1536static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
1537{
1538 uint8_t iDir;
1539 switch (enmMixerCtl)
1540 {
1541 case PDMAUDIOMIXERCTL_VOLUME:
1542 case PDMAUDIOMIXERCTL_FRONT:
1543 iDir = AMPLIFIER_OUT;
1544 break;
1545 case PDMAUDIOMIXERCTL_LINE_IN:
1546 case PDMAUDIOMIXERCTL_MIC_IN:
1547 iDir = AMPLIFIER_IN;
1548 break;
1549 default:
1550 AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), VERR_INVALID_PARAMETER);
1551 break;
1552 }
1553
1554 int iMute;
1555 iMute = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
1556 iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
1557 iMute >>=7;
1558 iMute &= 0x1;
1559
1560 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & 0x7f;
1561 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
1562
1563 /*
1564 * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
1565 * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
1566 * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
1567 * to 1 (rather than zero) internally.
1568 */
1569 lVol = (lVol + 1) * (2 * 255) / 256;
1570 rVol = (rVol + 1) * (2 * 255) / 256;
1571
1572 PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
1573 return pThis->pfnMixerSetVolume(pThis->pHDAState, enmMixerCtl, &Vol);
1574}
1575
1576DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
1577{
1578 Assert((pu32Reg && u8Offset < 32));
1579 *pu32Reg &= ~(mask << u8Offset);
1580 *pu32Reg |= (u32Cmd & mask) << u8Offset;
1581}
1582
1583DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
1584{
1585 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
1586}
1587
1588DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
1589{
1590 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
1591}
1592
1593
1594/*
1595 * Verb processor functions.
1596 */
1597static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1598{
1599 LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
1600 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
1601 *pResp = 0;
1602 return VINF_SUCCESS;
1603}
1604
1605static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1606{
1607 int rc;
1608 rc = vrbProcUnimplemented(pThis, cmd, pResp);
1609 *pResp |= CODEC_RESPONSE_UNSOLICITED;
1610 return rc;
1611}
1612
1613/* B-- */
1614static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1615{
1616 *pResp = 0;
1617
1618 /* HDA spec 7.3.3.7 Note A */
1619 /** @todo: If index out of range response should be 0. */
1620 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(cmd);
1621
1622 PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
1623 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1624 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
1625 CODEC_GET_AMP_DIRECTION(cmd),
1626 CODEC_GET_AMP_SIDE(cmd),
1627 u8Index);
1628 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1629 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
1630 CODEC_GET_AMP_DIRECTION(cmd),
1631 CODEC_GET_AMP_SIDE(cmd),
1632 u8Index);
1633 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1634 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
1635 CODEC_GET_AMP_DIRECTION(cmd),
1636 CODEC_GET_AMP_SIDE(cmd),
1637 u8Index);
1638 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1639 *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
1640 CODEC_GET_AMP_DIRECTION(cmd),
1641 CODEC_GET_AMP_SIDE(cmd),
1642 u8Index);
1643 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1644 *pResp = AMPLIFIER_REGISTER(pNode->port.B_params,
1645 CODEC_GET_AMP_DIRECTION(cmd),
1646 CODEC_GET_AMP_SIDE(cmd),
1647 u8Index);
1648 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1649 *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
1650 CODEC_GET_AMP_DIRECTION(cmd),
1651 CODEC_GET_AMP_SIDE(cmd),
1652 u8Index);
1653 else
1654 LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd)));
1655
1656 return VINF_SUCCESS;
1657}
1658
1659/* 3-- */
1660static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1661{
1662 *pResp = 0;
1663
1664 PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
1665 AMPLIFIER *pAmplifier = NULL;
1666 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1667 pAmplifier = &pNode->dac.B_params;
1668 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1669 pAmplifier = &pNode->adcvol.B_params;
1670 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1671 pAmplifier = &pNode->adcmux.B_params;
1672 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1673 pAmplifier = &pNode->pcbeep.B_params;
1674 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1675 pAmplifier = &pNode->port.B_params;
1676 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1677 pAmplifier = &pNode->adc.B_params;
1678 else
1679 LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
1680 cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd)));
1681
1682 if (!pAmplifier)
1683 return VINF_SUCCESS;
1684
1685 bool fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
1686 bool fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
1687 bool fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
1688 bool fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
1689 uint8_t u8Index = CODEC_SET_AMP_INDEX(cmd);
1690
1691 if ( (!fIsLeft && !fIsRight)
1692 || (!fIsOut && !fIsIn))
1693 return VINF_SUCCESS;
1694
1695 if (fIsIn)
1696 {
1697 if (fIsLeft)
1698 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
1699 if (fIsRight)
1700 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1701
1702 /** @todo Fix ID of u8AdcVolsLineIn! */
1703 hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
1704 }
1705 if (fIsOut)
1706 {
1707 if (fIsLeft)
1708 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
1709 if (fIsRight)
1710 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1711
1712 if (CODEC_NID(cmd) == pThis->u8DacLineOut)
1713 hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
1714 }
1715
1716 return VINF_SUCCESS;
1717}
1718
1719static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1720{
1721 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
1722 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
1723 {
1724 *pResp = 0;
1725
1726 LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1727 return VINF_SUCCESS;
1728 }
1729
1730 *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
1731 return VINF_SUCCESS;
1732}
1733
1734/* F01 */
1735static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1736{
1737 *pResp = 0;
1738
1739 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1740 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1741 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1742 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
1743 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1744 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
1745 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1746 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
1747 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1748 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1749 else
1750 LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1751
1752 return VINF_SUCCESS;
1753}
1754
1755/* 701 */
1756static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1757{
1758 *pResp = 0;
1759
1760 uint32_t *pu32Reg = NULL;
1761 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1762 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1763 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1764 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
1765 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1766 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
1767 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1768 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
1769 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1770 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1771 else
1772 LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1773
1774 if (pu32Reg)
1775 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1776
1777 return VINF_SUCCESS;
1778}
1779
1780/* F07 */
1781static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1782{
1783 *pResp = 0;
1784
1785 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1786 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
1787 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1788 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
1789 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1790 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
1791 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1792 *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1793 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1794 *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1795 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1796 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1797 else
1798 LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1799
1800 return VINF_SUCCESS;
1801}
1802
1803/* 707 */
1804static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1805{
1806 *pResp = 0;
1807
1808 uint32_t *pu32Reg = NULL;
1809 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1810 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
1811 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1812 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
1813 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1814 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
1815 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1816 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1817 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1818 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1819 else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))
1820 && CODEC_NID(cmd) == 0x1b)
1821 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1822 else
1823 LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1824
1825 if (pu32Reg)
1826 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1827
1828 return VINF_SUCCESS;
1829}
1830
1831/* F08 */
1832static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1833{
1834 *pResp = 0;
1835
1836 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1837 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
1838 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1839 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1840 else if ((cmd) == STAC9220_NID_AFG)
1841 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
1842 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1843 *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1844 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1845 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
1846 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1847 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1848 else
1849 LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1850
1851 return VINF_SUCCESS;
1852}
1853
1854/* 708 */
1855static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1856{
1857 *pResp = 0;
1858
1859 uint32_t *pu32Reg = NULL;
1860 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1861 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
1862 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1863 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1864 else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1865 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
1866 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1867 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1868 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1869 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1870 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1871 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
1872 else
1873 LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1874
1875 if (pu32Reg)
1876 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1877
1878 return VINF_SUCCESS;
1879}
1880
1881/* F09 */
1882static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1883{
1884 *pResp = 0;
1885
1886 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1887 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
1888 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1889 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
1890 else
1891 {
1892 AssertFailed();
1893 LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1894 }
1895
1896 return VINF_SUCCESS;
1897}
1898
1899/* 709 */
1900static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1901{
1902 *pResp = 0;
1903
1904 uint32_t *pu32Reg = NULL;
1905 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1906 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
1907 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1908 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
1909 else
1910 LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1911
1912 if (pu32Reg)
1913 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1914
1915 return VINF_SUCCESS;
1916}
1917
1918static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1919{
1920 *pResp = 0;
1921
1922 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
1923 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
1924 {
1925 LogFlowFunc(("access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1926 return VINF_SUCCESS;
1927 }
1928 *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA];
1929 return VINF_SUCCESS;
1930}
1931
1932/* F03 */
1933static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1934{
1935 *pResp = 0;
1936
1937 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1938 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param;
1939
1940 return VINF_SUCCESS;
1941}
1942
1943/* 703 */
1944static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1945{
1946 *pResp = 0;
1947
1948 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1949 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
1950 return VINF_SUCCESS;
1951}
1952
1953/* F0D */
1954static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1955{
1956 *pResp = 0;
1957
1958 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1959 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
1960 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1961 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
1962
1963 return VINF_SUCCESS;
1964}
1965
1966static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
1967{
1968 *pResp = 0;
1969
1970 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1971 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
1972 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1973 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
1974 return VINF_SUCCESS;
1975}
1976
1977/* 70D */
1978static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1979{
1980 return codecSetDigitalConverter(pThis, cmd, 0, pResp);
1981}
1982
1983/* 70E */
1984static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1985{
1986 return codecSetDigitalConverter(pThis, cmd, 8, pResp);
1987}
1988
1989/* F20 */
1990static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1991{
1992 Assert(CODEC_CAD(cmd) == pThis->id);
1993 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1994 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1995 {
1996 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1997 return VINF_SUCCESS;
1998 }
1999 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2000 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
2001 else
2002 *pResp = 0;
2003 return VINF_SUCCESS;
2004}
2005
2006static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
2007{
2008 Assert(CODEC_CAD(cmd) == pThis->id);
2009 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2010 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2011 {
2012 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2013 return VINF_SUCCESS;
2014 }
2015 uint32_t *pu32Reg;
2016 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2017 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
2018 else
2019 AssertFailedReturn(VINF_SUCCESS);
2020 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
2021 return VINF_SUCCESS;
2022}
2023
2024/* 720 */
2025static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2026{
2027 *pResp = 0;
2028 return codecSetSubIdX(pThis, cmd, 0);
2029}
2030
2031/* 721 */
2032static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2033{
2034 *pResp = 0;
2035 return codecSetSubIdX(pThis, cmd, 8);
2036}
2037
2038/* 722 */
2039static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2040{
2041 *pResp = 0;
2042 return codecSetSubIdX(pThis, cmd, 16);
2043}
2044
2045/* 723 */
2046static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2047{
2048 *pResp = 0;
2049 return codecSetSubIdX(pThis, cmd, 24);
2050}
2051
2052static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2053{
2054 Assert(CODEC_CAD(cmd) == pThis->id);
2055 Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
2056
2057 if ( CODEC_NID(cmd) == STAC9220_NID_AFG
2058 && pThis->pfnCodecNodeReset)
2059 {
2060 LogFunc(("Entering reset ...\n"));
2061
2062 pThis->fInReset = true;
2063
2064 for (uint8_t i = 0; i < pThis->cTotalNodes; ++i)
2065 pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
2066
2067 pThis->fInReset = false;
2068
2069 LogFunc(("Exited reset\n"));
2070 }
2071
2072 *pResp = 0;
2073 return VINF_SUCCESS;
2074}
2075
2076/* F05 */
2077static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2078{
2079 *pResp = 0;
2080
2081 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2082 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
2083 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2084 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
2085 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2086 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
2087 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2088 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
2089 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2090 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
2091 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2092 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
2093 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2094 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
2095 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2096 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
2097 else
2098 LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2099
2100 LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
2101 CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_ACT(*pResp), CODEC_F05_SET(*pResp)));
2102 return VINF_SUCCESS;
2103}
2104
2105/* 705 */
2106#if 1
2107static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2108{
2109 *pResp = 0;
2110
2111 uint32_t *pu32Reg = NULL;
2112 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2113 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
2114 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2115 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
2116 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2117 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
2118 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2119 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
2120 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2121 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
2122 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2123 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
2124 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2125 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
2126 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2127 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
2128 else
2129 {
2130 AssertFailed();
2131 LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2132 }
2133
2134 if (!pu32Reg)
2135 return VINF_SUCCESS;
2136
2137 bool fReset = CODEC_F05_IS_RESET (*pu32Reg);
2138 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
2139 bool fError = CODEC_F05_IS_ERROR (*pu32Reg);
2140 uint8_t uPwrAct = CODEC_F05_ACT (*pu32Reg);
2141 uint8_t uPwrSet = CODEC_F05_SET (*pu32Reg);
2142
2143 uint8_t uPwrCmd = CODEC_F05_SET (cmd);
2144
2145 LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
2146 CODEC_NID(cmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
2147
2148 LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
2149 CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param),
2150 CODEC_F05_SET(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param)));
2151
2152 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2153 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
2154
2155 const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param);
2156 if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
2157 {
2158 /* Propagate to all other nodes under this AFG. */
2159 LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
2160
2161#define PROPAGATE_PWR_STATE(_aList, _aMember) \
2162 { \
2163 const uint8_t *pu8NodeIndex = &_aList[0]; \
2164 while (*(++pu8NodeIndex)) \
2165 { \
2166 pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param = \
2167 CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
2168 LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", *pu8NodeIndex, \
2169 CODEC_F05_ACT(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param), \
2170 CODEC_F05_SET(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param))); \
2171 } \
2172 }
2173
2174 PROPAGATE_PWR_STATE(pThis->au8Dacs, dac);
2175 PROPAGATE_PWR_STATE(pThis->au8Adcs, adc);
2176 PROPAGATE_PWR_STATE(pThis->au8DigInPins, digin);
2177 PROPAGATE_PWR_STATE(pThis->au8DigOutPins, digout);
2178 PROPAGATE_PWR_STATE(pThis->au8SpdifIns, spdifin);
2179 PROPAGATE_PWR_STATE(pThis->au8SpdifOuts, spdifout);
2180 PROPAGATE_PWR_STATE(pThis->au8Reserveds, reserved);
2181
2182#undef PROPAGATE_PWR_STATE
2183 }
2184 /*
2185 * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
2186 * as PS-Set of this node. PS-Act always is one level under PS-Set here.
2187 */
2188 else
2189 {
2190 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
2191 }
2192
2193 LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
2194 CODEC_NID(cmd),
2195 CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
2196
2197 return VINF_SUCCESS;
2198}
2199#else
2200DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
2201{
2202 Assert(pu32F05_param);
2203 if (!pu32F05_param)
2204 return;
2205 bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
2206 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
2207 uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
2208 *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
2209}
2210
2211static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2212{
2213 Assert(CODEC_CAD(cmd) == pThis->id);
2214 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2215 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2216 {
2217 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2218 return VINF_SUCCESS;
2219 }
2220 *pResp = 0;
2221 uint32_t *pu32Reg;
2222 if (CODEC_NID(cmd) == 1 /* AFG */)
2223 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
2224 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2225 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
2226 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2227 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
2228 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2229 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
2230 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2231 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
2232 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2233 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
2234 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2235 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
2236 else
2237 AssertFailedReturn(VINF_SUCCESS);
2238
2239 bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
2240 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
2241
2242 if (CODEC_NID(cmd) != 1 /* AFG */)
2243 {
2244 /*
2245 * We shouldn't propogate actual power state, which actual for AFG
2246 */
2247 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
2248 CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param),
2249 CODEC_F05_SET(cmd));
2250 }
2251
2252 /* Propagate next power state only if AFG is on or verb modifies AFG power state */
2253 if ( CODEC_NID(cmd) == 1 /* AFG */
2254 || !CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param))
2255 {
2256 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
2257 if ( CODEC_NID(cmd) == 1 /* AFG */
2258 && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
2259 {
2260 /* now we're powered on AFG and may propogate power states on nodes */
2261 const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
2262 while (*(++pu8NodeIndex))
2263 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].dac.u32F05_param);
2264
2265 pu8NodeIndex = &pThis->au8Adcs[0];
2266 while (*(++pu8NodeIndex))
2267 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].adc.u32F05_param);
2268
2269 pu8NodeIndex = &pThis->au8DigInPins[0];
2270 while (*(++pu8NodeIndex))
2271 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].digin.u32F05_param);
2272 }
2273 }
2274 return VINF_SUCCESS;
2275}
2276#endif
2277
2278static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2279{
2280 *pResp = 0;
2281
2282 bool fIsOut;
2283
2284 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2285 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
2286 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2287 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
2288 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2289 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2290 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2291 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2292 else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
2293 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
2294 else
2295 LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2296
2297 LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
2298 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd), CODEC_F00_06_GET_CHANNEL_ID(cmd)));
2299
2300 return VINF_SUCCESS;
2301}
2302
2303/* F06 */
2304static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2305{
2306 *pResp = 0;
2307
2308 PDMAUDIODIR enmDir;
2309
2310 uint32_t *pu32Addr = NULL;
2311 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2312 {
2313 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
2314 enmDir = PDMAUDIODIR_OUT;
2315 }
2316 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2317 {
2318 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
2319 enmDir = PDMAUDIODIR_IN;
2320 }
2321 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2322 {
2323 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2324 enmDir = PDMAUDIODIR_OUT;
2325 }
2326 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2327 {
2328 pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2329 enmDir = PDMAUDIODIR_IN;
2330 }
2331 else
2332 {
2333 enmDir = PDMAUDIODIR_UNKNOWN;
2334 LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2335 }
2336
2337 /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
2338 if (enmDir != PDMAUDIODIR_UNKNOWN)
2339 {
2340 uint8_t uSD = CODEC_F00_06_GET_STREAM_ID(cmd);
2341 uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(cmd);
2342
2343 LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8, enmDir=%RU32\n",
2344 CODEC_NID(cmd), uSD, uChannel, enmDir));
2345
2346 pThis->paNodes[CODEC_NID(cmd)].node.uSD = uSD;
2347 pThis->paNodes[CODEC_NID(cmd)].node.uChannel = uChannel;
2348
2349 if (enmDir == PDMAUDIODIR_OUT)
2350 {
2351 /** @todo Check if non-interleaved streams need a different channel / SDn? */
2352
2353 /* Propagate to the controller. */
2354 pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
2355#ifdef VBOX_WITH_HDA_51_SURROUND
2356 pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
2357 pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
2358#endif
2359 }
2360 else if (enmDir == PDMAUDIODIR_IN)
2361 {
2362 pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
2363#ifdef VBOX_WITH_HDA_MIC_IN
2364 pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_MIC_IN, uSD, uChannel);
2365#endif
2366 }
2367 }
2368
2369 if (pu32Addr)
2370 hdaCodecSetRegisterU8(pu32Addr, cmd, 0);
2371
2372 return VINF_SUCCESS;
2373}
2374
2375/* A0 */
2376static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2377{
2378 *pResp = 0;
2379
2380 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2381 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param;
2382 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2383 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param;
2384 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2385 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param;
2386 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2387 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param;
2388 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2389 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32A_param;
2390 else
2391 LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2392
2393 return VINF_SUCCESS;
2394}
2395
2396/* Also see section 3.7.1. */
2397static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2398{
2399 *pResp = 0;
2400
2401 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2402 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
2403 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2404 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
2405 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2406 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
2407 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2408 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
2409 else
2410 LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2411
2412 return VINF_SUCCESS;
2413}
2414
2415/* F0C */
2416static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2417{
2418 *pResp = 0;
2419
2420 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
2421 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
2422 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2423 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
2424 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2425 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
2426 else
2427 LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2428
2429 return VINF_SUCCESS;
2430}
2431
2432/* 70C */
2433static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2434{
2435 *pResp = 0;
2436
2437 uint32_t *pu32Reg = NULL;
2438 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
2439 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
2440 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2441 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
2442 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2443 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
2444 else
2445 LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2446
2447 if (pu32Reg)
2448 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2449
2450 return VINF_SUCCESS;
2451}
2452
2453/* F0F */
2454static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2455{
2456 *pResp = 0;
2457
2458 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
2459 *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
2460 else
2461 LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2462
2463 return VINF_SUCCESS;
2464}
2465
2466/* 70F */
2467static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2468{
2469 *pResp = 0;
2470
2471 uint32_t *pu32Reg = NULL;
2472 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
2473 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
2474 else
2475 LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2476
2477 if (pu32Reg)
2478 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2479
2480 return VINF_SUCCESS;
2481}
2482
2483/* F15 */
2484static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2485{
2486 *pResp = 0;
2487
2488 return VINF_SUCCESS;
2489}
2490
2491/* 715 */
2492static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2493{
2494 *pResp = 0;
2495
2496 return VINF_SUCCESS;
2497}
2498
2499/* F16 */
2500static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2501{
2502 *pResp = 0;
2503
2504 return VINF_SUCCESS;
2505}
2506
2507/* 716 */
2508static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2509{
2510 *pResp = 0;
2511
2512 return VINF_SUCCESS;
2513}
2514
2515/* F17 */
2516static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2517{
2518 *pResp = 0;
2519
2520 /* Note: this is true for ALC885. */
2521 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2522 *pResp = pThis->paNodes[1].afg.u32F17_param;
2523 else
2524 LogRel2(("HDA: Warning: Unhandled get GPIO unsolisted command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2525
2526 return VINF_SUCCESS;
2527}
2528
2529/* 717 */
2530static DECLCALLBACK(int) vrbProcSetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2531{
2532 *pResp = 0;
2533
2534 uint32_t *pu32Reg = NULL;
2535 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
2536 pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
2537 else
2538 LogRel2(("HDA: Warning: Unhandled set GPIO unsolisted command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2539
2540 if (pu32Reg)
2541 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2542
2543 return VINF_SUCCESS;
2544}
2545
2546/* F1C */
2547static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2548{
2549 *pResp = 0;
2550
2551 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
2552 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
2553 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2554 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
2555 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2556 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
2557 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
2558 *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
2559 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
2560 *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
2561 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2562 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
2563 else
2564 LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2565
2566 return VINF_SUCCESS;
2567}
2568
2569static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
2570{
2571 uint32_t *pu32Reg = NULL;
2572 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
2573 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
2574 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2575 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
2576 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2577 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
2578 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
2579 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
2580 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
2581 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
2582 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2583 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
2584 else
2585 LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
2586
2587 if (pu32Reg)
2588 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
2589
2590 return VINF_SUCCESS;
2591}
2592
2593/* 71C */
2594static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2595{
2596 *pResp = 0;
2597 return codecSetConfigX(pThis, cmd, 0);
2598}
2599
2600/* 71D */
2601static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2602{
2603 *pResp = 0;
2604 return codecSetConfigX(pThis, cmd, 8);
2605}
2606
2607/* 71E */
2608static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2609{
2610 *pResp = 0;
2611 return codecSetConfigX(pThis, cmd, 16);
2612}
2613
2614/* 71E */
2615static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2616{
2617 *pResp = 0;
2618 return codecSetConfigX(pThis, cmd, 24);
2619}
2620
2621/* F04 */
2622static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2623{
2624 *pResp = 0;
2625
2626 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2627 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
2628 else
2629 LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2630
2631 return VINF_SUCCESS;
2632}
2633
2634/* 704 */
2635static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2636{
2637 *pResp = 0;
2638
2639 uint32_t *pu32Reg = NULL;
2640 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2641 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
2642 else
2643 LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2644
2645 if (pu32Reg)
2646 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2647
2648 return VINF_SUCCESS;
2649}
2650
2651/**
2652 * HDA codec verb map.
2653 * @todo Any reason not to use binary search here?
2654 */
2655static const CODECVERB g_aCodecVerbs[] =
2656{
2657 /* Verb Verb mask Callback Name
2658 * ---------- --------------------- ----------------------------------------------------------
2659 */
2660 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
2661 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
2662 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
2663 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
2664 { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId , "SetStreamId " },
2665 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
2666 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
2667 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
2668 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
2669 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
2670 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
2671 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
2672 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
2673 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
2674 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
2675 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
2676 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
2677 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
2678 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
2679 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
2680 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
2681 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
2682 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
2683 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
2684 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
2685 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
2686 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
2687 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
2688 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
2689 { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
2690 { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
2691 { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
2692 { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
2693 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted , "GetGPIOUnsolisted " },
2694 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted , "SetGPIOUnsolisted " },
2695 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
2696 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
2697 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
2698 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
2699 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
2700 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
2701 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
2702 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
2703 { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier , "SetAmplifier " },
2704 { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
2705 { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " }
2706 /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
2707};
2708
2709#ifdef DEBUG
2710typedef struct CODECDBGINFO
2711{
2712 /** DBGF info helpers. */
2713 PCDBGFINFOHLP pHlp;
2714 /** Current recursion level. */
2715 uint8_t uLevel;
2716 /** Pointer to codec state. */
2717 PHDACODEC pThis;
2718
2719} CODECDBGINFO, *PCODECDBGINFO;
2720
2721#define CODECDBG_INDENT pInfo->uLevel++;
2722#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
2723
2724#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2725#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
2726
2727static void codecDbgPrintfIndentV(PCODECDBGINFO pInfo, uint16_t uIndent, const char *pszFormat, va_list va)
2728{
2729 char *pszValueFormat;
2730 if (RTStrAPrintfV(&pszValueFormat, pszFormat, va))
2731 {
2732 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%s", uIndent, "", pszValueFormat);
2733 RTStrFree(pszValueFormat);
2734 }
2735}
2736
2737static void codecDbgPrintf(PCODECDBGINFO pInfo, const char *pszFormat, ...)
2738{
2739 va_list va;
2740 va_start(va, pszFormat);
2741 codecDbgPrintfIndentV(pInfo, pInfo->uLevel * 4, pszFormat, va);
2742 va_end(va);
2743}
2744
2745/* Power state */
2746static void codecDbgPrintNodeRegF05(PCODECDBGINFO pInfo, uint32_t u32Reg)
2747{
2748 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2749 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2750}
2751
2752static void codecDbgPrintNodeRegA(PCODECDBGINFO pInfo, uint32_t u32Reg)
2753{
2754 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2755}
2756
2757static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
2758{
2759 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2760
2761 CODECDBG_INDENT
2762 codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
2763 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2764 uint32_t uReg = paReg00[0xD];
2765 CODECDBG_INDENT
2766 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2767 CODEC_F00_0D_NUM_STEPS(uReg),
2768 CODEC_F00_0D_STEP_SIZE(uReg),
2769 CODEC_F00_0D_OFFSET(uReg),
2770 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2771
2772 uReg = paReg00[0x12];
2773 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2774 CODEC_F00_12_NUM_STEPS(uReg),
2775 CODEC_F00_12_STEP_SIZE(uReg),
2776 CODEC_F00_12_OFFSET(uReg),
2777 RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
2778 CODECDBG_UNINDENT
2779 CODECDBG_UNINDENT
2780}
2781
2782static void codecDbgPrintNodeAmp(PCODECDBGINFO pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
2783{
2784#define CODECDBG_AMP(reg, chan) \
2785 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2786 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2787 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2788 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2789 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg));
2790
2791 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2792 CODECDBG_AMP(regAmp, "Left");
2793 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2794 CODECDBG_AMP(regAmp, "Right");
2795
2796#undef CODECDBG_AMP
2797}
2798
2799static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
2800{
2801 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2802 {
2803 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2804 return;
2805 }
2806}
2807
2808static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecursive)
2809{
2810 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
2811
2812 if (pNode->node.uID == STAC9220_NID_ROOT)
2813 {
2814 CODECDBG_PRINT("ROOT\n");
2815 }
2816 else if (pNode->node.uID == STAC9220_NID_AFG)
2817 {
2818 CODECDBG_PRINT("AFG\n");
2819 CODECDBG_INDENT
2820 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2821 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2822 CODECDBG_UNINDENT
2823 }
2824 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
2825 {
2826 CODECDBG_PRINT("PORT\n");
2827 }
2828 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
2829 {
2830 CODECDBG_PRINT("DAC\n");
2831 CODECDBG_INDENT
2832 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2833 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2834 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2835 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2836 CODECDBG_UNINDENT
2837 }
2838 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
2839 {
2840 CODECDBG_PRINT("ADC VOLUME\n");
2841 CODECDBG_INDENT
2842 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2843 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2844 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2845 CODECDBG_UNINDENT
2846 }
2847 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
2848 {
2849 CODECDBG_PRINT("ADC\n");
2850 CODECDBG_INDENT
2851 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2852 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2853 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2854 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2855 CODECDBG_UNINDENT
2856 }
2857 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
2858 {
2859 CODECDBG_PRINT("ADC MUX\n");
2860 CODECDBG_INDENT
2861 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2862 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2863 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2864 CODECDBG_UNINDENT
2865 }
2866 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
2867 {
2868 CODECDBG_PRINT("PC BEEP\n");
2869 }
2870 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
2871 {
2872 CODECDBG_PRINT("SPDIF OUT\n");
2873 }
2874 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
2875 {
2876 CODECDBG_PRINT("SPDIF IN\n");
2877 }
2878 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
2879 {
2880 CODECDBG_PRINT("DIGITAL IN PIN\n");
2881 }
2882 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
2883 {
2884 CODECDBG_PRINT("DIGITAL OUT PIN\n");
2885 }
2886 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
2887 {
2888 CODECDBG_PRINT("CD\n");
2889 }
2890 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
2891 {
2892 CODECDBG_PRINT("VOLUME KNOB\n");
2893 }
2894 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
2895 {
2896 CODECDBG_PRINT("RESERVED\n");
2897 }
2898 else
2899 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
2900
2901 if (fRecursive)
2902 {
2903#define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
2904 if (cCnt >= _aEntry) \
2905 { \
2906 const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
2907 if (pNode->node.uID == uID) \
2908 codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
2909 }
2910
2911 /* Slow recursion, but this is debug stuff anyway. */
2912 for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
2913 {
2914 const PCODECNODE pSubNode = &pInfo->pThis->paNodes[i];
2915 if (pSubNode->node.uID == pNode->node.uID)
2916 continue;
2917
2918 const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
2919 if (cCnt == 0) /* No connections present? Skip. */
2920 continue;
2921
2922 CODECDBG_INDENT
2923 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
2924 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
2925 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
2926 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
2927 CODECDBG_UNINDENT
2928 }
2929
2930#undef CODECDBG_PRINT_CONLIST_ENTRY
2931 }
2932}
2933
2934static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
2935{
2936 pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
2937
2938 CODECDBGINFO dbgInfo;
2939 dbgInfo.pHlp = pHlp;
2940 dbgInfo.pThis = pThis;
2941 dbgInfo.uLevel = 0;
2942
2943 PCODECDBGINFO pInfo = &dbgInfo;
2944
2945 CODECDBG_INDENT
2946 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
2947 {
2948 PCODECNODE pNode = &pThis->paNodes[i];
2949
2950 /* Start with all nodes which have connection entries set. */
2951 if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
2952 codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
2953 }
2954 CODECDBG_UNINDENT
2955}
2956
2957static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
2958{
2959
2960}
2961#endif
2962
2963static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, uint64_t *puResp)
2964{
2965 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2966 AssertPtrReturn(puResp, VERR_INVALID_POINTER);
2967
2968 if (CODEC_CAD(cmd) != pThis->id)
2969 {
2970 *puResp = 0;
2971 AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
2972 return VERR_INVALID_PARAMETER;
2973 }
2974
2975 if ( CODEC_VERBDATA(cmd) == 0
2976 || CODEC_NID(cmd) >= pThis->cTotalNodes)
2977 {
2978 *puResp = 0;
2979 AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
2980 return VERR_INVALID_PARAMETER;
2981 }
2982
2983 /** @todo r=andy Implement a binary search here. */
2984 for (size_t i = 0; i < pThis->cVerbs; i++)
2985 {
2986 if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
2987 {
2988 int rc2 = pThis->paVerbs[i].pfn(pThis, cmd, puResp);
2989 AssertRC(rc2);
2990 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
2991 CODEC_NID(cmd), pThis->paVerbs[i].verb, pThis->paVerbs[i].pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
2992 return rc2;
2993 }
2994 }
2995
2996 *puResp = 0;
2997 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
2998 return VERR_NOT_FOUND;
2999}
3000
3001/*
3002 * APIs exposed to DevHDA.
3003 */
3004
3005int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
3006{
3007 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3008 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
3009
3010 int rc = VINF_SUCCESS;
3011
3012 switch (enmMixerCtl)
3013 {
3014 case PDMAUDIOMIXERCTL_VOLUME:
3015 case PDMAUDIOMIXERCTL_FRONT:
3016#ifdef VBOX_WITH_HDA_51_SURROUND
3017 case PDMAUDIOMIXERCTL_CENTER_LFE:
3018 case PDMAUDIOMIXERCTL_REAR:
3019#endif
3020 {
3021 break;
3022 }
3023 case PDMAUDIOMIXERCTL_LINE_IN:
3024#ifdef VBOX_WITH_HDA_MIC_IN
3025 case PDMAUDIOMIXERCTL_MIC_IN:
3026#endif
3027 {
3028 break;
3029 }
3030 default:
3031 AssertMsgFailed(("Mixer control %ld not implemented\n", enmMixerCtl));
3032 rc = VERR_NOT_IMPLEMENTED;
3033 break;
3034 }
3035
3036 if (RT_SUCCESS(rc))
3037 rc = pThis->pfnMixerAddStream(pThis->pHDAState, enmMixerCtl, pCfg);
3038
3039 LogFlowFuncLeaveRC(rc);
3040 return rc;
3041}
3042
3043int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl)
3044{
3045 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3046
3047 int rc = pThis->pfnMixerRemoveStream(pThis->pHDAState, enmMixerCtl);
3048
3049 LogFlowFuncLeaveRC(rc);
3050 return rc;
3051}
3052
3053int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
3054{
3055 AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
3056 VERR_INTERNAL_ERROR);
3057 SSMR3PutU32(pSSM, pThis->cTotalNodes);
3058 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
3059 SSMR3PutStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState),
3060 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
3061 return VINF_SUCCESS;
3062}
3063
3064int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
3065{
3066 PCSSMFIELD pFields;
3067 uint32_t fFlags;
3068 switch (uVersion)
3069 {
3070 case HDA_SSM_VERSION_1:
3071 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3072 pFields = g_aCodecNodeFieldsV1;
3073 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
3074 break;
3075
3076 case HDA_SSM_VERSION_2:
3077 case HDA_SSM_VERSION_3:
3078 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3079 pFields = g_aCodecNodeFields;
3080 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
3081 break;
3082
3083 /* Since version 4 a flexible node count is supported. */
3084 case HDA_SSM_VERSION_4:
3085 case HDA_SSM_VERSION_5:
3086 case HDA_SSM_VERSION:
3087 {
3088 uint32_t cNodes;
3089 int rc2 = SSMR3GetU32(pSSM, &cNodes);
3090 AssertRCReturn(rc2, rc2);
3091 if (cNodes != 0x1c)
3092 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
3093 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
3094
3095 pFields = g_aCodecNodeFields;
3096 fFlags = 0;
3097 break;
3098 }
3099
3100 default:
3101 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
3102 }
3103
3104 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
3105 {
3106 uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.uID;
3107 int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState,
3108 sizeof(pThis->paNodes[idxNode].SavedState),
3109 fFlags, pFields, NULL);
3110 if (RT_FAILURE(rc))
3111 return rc;
3112 AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.uID,
3113 ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.uID, idOld),
3114 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
3115 }
3116
3117 /*
3118 * Update stuff after changing the state.
3119 */
3120 if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
3121 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_FRONT);
3122 else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
3123 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
3124 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
3125
3126 return VINF_SUCCESS;
3127}
3128
3129/**
3130 * Powers off the codec.
3131 *
3132 * @param pThis Codec to power off.
3133 */
3134void hdaCodecPowerOff(PHDACODEC pThis)
3135{
3136 if (!pThis)
3137 return;
3138
3139 LogFlowFuncEnter();
3140
3141 LogRel2(("HDA: Powering off codec ...\n"));
3142
3143 int rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_FRONT);
3144 AssertRC(rc2);
3145#ifdef VBOX_WITH_HDA_51_SURROUND
3146 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE);
3147 AssertRC(rc2);
3148 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_REAR);
3149 AssertRC(rc2);
3150#endif
3151
3152#ifdef VBOX_WITH_HDA_MIC_IN
3153 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_MIC_IN);
3154 AssertRC(rc2);
3155#endif
3156 rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_LINE_IN);
3157 AssertRC(rc2);
3158}
3159
3160void hdaCodecDestruct(PHDACODEC pThis)
3161{
3162 if (!pThis)
3163 return;
3164
3165 LogFlowFuncEnter();
3166
3167 if (pThis->paNodes)
3168 {
3169 RTMemFree(pThis->paNodes);
3170 pThis->paNodes = NULL;
3171 }
3172}
3173
3174int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
3175 uint16_t uLUN, PCFGMNODE pCfg)
3176{
3177 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
3178 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
3179 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
3180
3181 pThis->id = uLUN;
3182 pThis->paVerbs = &g_aCodecVerbs[0];
3183 pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
3184
3185#ifdef DEBUG
3186 pThis->pfnDbgSelector = codecDbgSelector;
3187 pThis->pfnDbgListNodes = codecDbgListNodes;
3188#endif
3189 pThis->pfnLookup = codecLookup;
3190
3191 int rc = stac9220Construct(pThis);
3192 AssertRCReturn(rc, rc);
3193
3194 /* Common root node initializers. */
3195 pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
3196 pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
3197
3198 /* Common AFG node initializers. */
3199 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
3200 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
3201 pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
3202 pThis->paNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
3203
3204 do
3205 {
3206 /* Initialize the streams to some default values (44.1 kHz, 16-bit signed, 2 channels).
3207 * The codec's (fixed) delivery rate is 48kHz, so a frame will be delivered every 20.83us. */
3208 PDMAUDIOSTREAMCFG strmCfg;
3209 RT_ZERO(strmCfg);
3210 strmCfg.uHz = 44100;
3211 strmCfg.cChannels = 2;
3212 strmCfg.enmFormat = PDMAUDIOFMT_S16;
3213 strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
3214
3215 /*
3216 * Output streams.
3217 */
3218 strmCfg.enmDir = PDMAUDIODIR_OUT;
3219
3220 /* Front. */
3221 RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Front");
3222 strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
3223 rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_FRONT, &strmCfg);
3224 AssertRCBreak(rc);
3225
3226#ifdef VBOX_WITH_HDA_51_SURROUND
3227 /* Center / LFE. */
3228 RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Center / LFE");
3229 strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
3230 /** @todo Handle mono channel if only center *or* LFE is available? */
3231 rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, &strmCfg);
3232 AssertRCBreak(rc);
3233
3234 /* Rear. */
3235 RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Rear");
3236 strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
3237 rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_REAR, &strmCfg);
3238 AssertRCBreak(rc);
3239#endif
3240
3241 /*
3242 * Input streams.
3243 */
3244 strmCfg.enmDir = PDMAUDIODIR_IN;
3245
3246#ifdef VBOX_WITH_HDA_MIC_IN
3247 RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Microphone In");
3248 strmCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
3249 rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_MIC_IN, &strmCfg);
3250 AssertRCBreak(rc);
3251#endif
3252 RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Line In");
3253 strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
3254 rc = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_LINE_IN, &strmCfg);
3255 AssertRCBreak(rc);
3256
3257 } while (0);
3258
3259 /** @todo Handle rc here? */
3260
3261 /*
3262 * Reset nodes.
3263 */
3264 AssertPtr(pThis->paNodes);
3265 AssertPtr(pThis->pfnCodecNodeReset);
3266
3267 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
3268 pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
3269
3270 /*
3271 * Set initial volume.
3272 */
3273 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_FRONT);
3274 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
3275#ifdef VBOX_WITH_HDA_MIC_IN
3276 #error "Implement mic-in support!"
3277#endif
3278
3279 return VINF_SUCCESS;
3280}
3281
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