VirtualBox

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

Last change on this file since 67711 was 67711, checked in by vboxsync, 7 years ago

HDA Codec: Fixed Get/Set GPIO Direction command name, fixed Snow Leopard sound assertion (missing CAP_UNSOL).

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