VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevHdaCodec.cpp@ 89467

Last change on this file since 89467 was 89213, checked in by vboxsync, 4 years ago

Audio: Added an fImmediate indicator to the pfnStreamDestroy methods so the backend knows whether it's okay to continue draining the stream or if it must be destroyed without delay. The latter is typically only for shutdown and driver plumbing. This helps quite a bit for HDA/CoreAudio/knoppix. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 111.1 KB
Line 
1/* $Id: DevHdaCodec.cpp 89213 2021-05-21 10:00:12Z vboxsync $ */
2/** @file
3 * Intel HD Audio Controller Emulation - Codec, Sigmatel/IDT STAC9220.
4 *
5 * Implemented based on the Intel HD Audio specification and the
6 * Sigmatel/IDT STAC9220 datasheet.
7 */
8
9/*
10 * Copyright (C) 2006-2020 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#define LOG_GROUP LOG_GROUP_DEV_HDA_CODEC
26#include <VBox/log.h>
27
28#include <VBox/AssertGuest.h>
29#include <VBox/vmm/pdmdev.h>
30#include <VBox/vmm/pdmaudioifs.h>
31#include <VBox/vmm/pdmaudioinline.h>
32
33#include <iprt/assert.h>
34#include <iprt/uuid.h>
35#include <iprt/string.h>
36#include <iprt/mem.h>
37#include <iprt/asm.h>
38#include <iprt/cpp/utils.h>
39
40#include "VBoxDD.h"
41#include "AudioMixer.h"
42#include "DevHdaCodec.h"
43#include "DevHdaCommon.h"
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49
50
51#define AMPLIFIER_IN 0
52#define AMPLIFIER_OUT 1
53#define AMPLIFIER_LEFT 1
54#define AMPLIFIER_RIGHT 0
55#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)])
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61/* STAC9220 - Nodes IDs / names. */
62#define STAC9220_NID_ROOT 0x0 /* Root node */
63#define STAC9220_NID_AFG 0x1 /* Audio Configuration Group */
64#define STAC9220_NID_DAC0 0x2 /* Out */
65#define STAC9220_NID_DAC1 0x3 /* Out */
66#define STAC9220_NID_DAC2 0x4 /* Out */
67#define STAC9220_NID_DAC3 0x5 /* Out */
68#define STAC9220_NID_ADC0 0x6 /* In */
69#define STAC9220_NID_ADC1 0x7 /* In */
70#define STAC9220_NID_SPDIF_OUT 0x8 /* Out */
71#define STAC9220_NID_SPDIF_IN 0x9 /* In */
72/** Also known as PIN_A. */
73#define STAC9220_NID_PIN_HEADPHONE0 0xA /* In, Out */
74#define STAC9220_NID_PIN_B 0xB /* In, Out */
75#define STAC9220_NID_PIN_C 0xC /* In, Out */
76/** Also known as PIN D. */
77#define STAC9220_NID_PIN_HEADPHONE1 0xD /* In, Out */
78#define STAC9220_NID_PIN_E 0xE /* In */
79#define STAC9220_NID_PIN_F 0xF /* In, Out */
80/** Also known as DIGOUT0. */
81#define STAC9220_NID_PIN_SPDIF_OUT 0x10 /* Out */
82/** Also known as DIGIN. */
83#define STAC9220_NID_PIN_SPDIF_IN 0x11 /* In */
84#define STAC9220_NID_ADC0_MUX 0x12 /* In */
85#define STAC9220_NID_ADC1_MUX 0x13 /* In */
86#define STAC9220_NID_PCBEEP 0x14 /* Out */
87#define STAC9220_NID_PIN_CD 0x15 /* In */
88#define STAC9220_NID_VOL_KNOB 0x16
89#define STAC9220_NID_AMP_ADC0 0x17 /* In */
90#define STAC9220_NID_AMP_ADC1 0x18 /* In */
91/* Only for STAC9221. */
92#define STAC9221_NID_ADAT_OUT 0x19 /* Out */
93#define STAC9221_NID_I2S_OUT 0x1A /* Out */
94#define STAC9221_NID_PIN_I2S_OUT 0x1B /* Out */
95
96/** Number of total nodes emulated. */
97#define STAC9221_NUM_NODES 0x1C
98
99
100/*********************************************************************************************************************************
101* Global Variables *
102*********************************************************************************************************************************/
103#ifdef IN_RING3
104
105/* STAC9220 - Referenced through STAC9220WIDGET in the constructor below. */
106static 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 };
107static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0 };
108static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0 };
109static uint8_t const g_abStac9220SpdifOuts[] = { STAC9220_NID_SPDIF_OUT, 0 };
110static uint8_t const g_abStac9220SpdifIns[] = { STAC9220_NID_SPDIF_IN, 0 };
111static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
112static uint8_t const g_abStac9220DigInPins[] = { STAC9220_NID_PIN_SPDIF_IN, 0 };
113static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0 };
114static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0 };
115static uint8_t const g_abStac9220Pcbeeps[] = { STAC9220_NID_PCBEEP, 0 };
116static uint8_t const g_abStac9220Cds[] = { STAC9220_NID_PIN_CD, 0 };
117static uint8_t const g_abStac9220VolKnobs[] = { STAC9220_NID_VOL_KNOB, 0 };
118/* STAC 9221. */
119/** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
120static uint8_t const g_abStac9220Reserveds[] = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
121
122/** SSM description of CODECCOMMONNODE. */
123static SSMFIELD const g_aCodecNodeFields[] =
124{
125 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
126 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
127 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
128 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
129 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
130 SSMFIELD_ENTRY_TERM()
131};
132
133/** Backward compatibility with v1 of CODECCOMMONNODE. */
134static SSMFIELD const g_aCodecNodeFieldsV1[] =
135{
136 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
137 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
138 SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
139 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
140 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
141 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
142 SSMFIELD_ENTRY_TERM()
143};
144
145#endif /* IN_RING3 */
146
147
148
149#if 0 /* unused */
150static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
151{
152 RT_NOREF(pszArgs);
153 uint8_t const cTotalNodes = RT_MIN(pThis->cTotalNodes, RT_ELEMENTS(pThis->aNodes));
154 for (uint8_t i = 1; i < cTotalNodes; i++)
155 {
156 PCODECNODE pNode = &pThis->aNodes[i];
157 AMPLIFIER *pAmp = &pNode->dac.B_params;
158
159 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) & 0x7f;
160 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) & 0x7f;
161
162 pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
163 }
164}
165#endif
166
167
168/**
169 * Resets a single node of the codec.
170 *
171 * @param pThis HDA codec of node to reset.
172 * @param uNID Node ID to set node to.
173 * @param pNode Node to reset.
174 */
175static void stac9220NodeReset(PHDACODEC pThis, uint8_t uNID, PCODECNODE pNode)
176{
177 LogFlowFunc(("NID=0x%x (%RU8)\n", uNID, uNID));
178
179 if ( !pThis->fInReset
180 && ( uNID != STAC9220_NID_ROOT
181 && uNID != STAC9220_NID_AFG)
182 )
183 {
184 RT_ZERO(pNode->node);
185 }
186
187 /* Set common parameters across all nodes. */
188 pNode->node.uID = uNID;
189 pNode->node.uSD = 0;
190
191 switch (uNID)
192 {
193 /* Root node. */
194 case STAC9220_NID_ROOT:
195 {
196 /* Set the revision ID. */
197 pNode->root.node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x3, 0x4, 0x0, 0x1);
198 break;
199 }
200
201 /*
202 * AFG (Audio Function Group).
203 */
204 case STAC9220_NID_AFG:
205 {
206 pNode->afg.node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
207 /* We set the AFG's PCM capabitilies fixed to 16kHz, 22.5kHz + 44.1kHz, 16-bit signed. */
208 pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ /* 44.1 kHz */
209 | CODEC_F00_0A_44_1KHZ_1_2X /* Messed up way of saying 22.05 kHz */
210 | CODEC_F00_0A_48KHZ_1_3X /* Messed up way of saying 16 kHz. */
211 | CODEC_F00_0A_16_BIT; /* 16-bit signed */
212 /* Note! We do not set CODEC_F00_0A_48KHZ here because we end up with
213 S/PDIF output showing up in windows and it trying to configure
214 streams other than 0 and 4 and stuff going sideways in the
215 stream setup/removal area. */
216 pNode->afg.node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
217 pNode->afg.node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
218 | CODEC_F00_0C_CAP_BALANCED_IO
219 | CODEC_F00_0C_CAP_INPUT
220 | CODEC_F00_0C_CAP_OUTPUT
221 | CODEC_F00_0C_CAP_PRESENCE_DETECT
222 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
223 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;
224
225 /* Default input amplifier capabilities. */
226 pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
227 CODEC_AMP_STEP_SIZE,
228 CODEC_AMP_NUM_STEPS,
229 CODEC_AMP_OFF_INITIAL);
230 /* Default output amplifier capabilities. */
231 pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
232 CODEC_AMP_STEP_SIZE,
233 CODEC_AMP_NUM_STEPS,
234 CODEC_AMP_OFF_INITIAL);
235
236 pNode->afg.node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);
237 pNode->afg.node.au32F00_param[0x0F] = CODEC_F00_0F_D3
238 | CODEC_F00_0F_D2
239 | CODEC_F00_0F_D1
240 | CODEC_F00_0F_D0;
241
242 pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2); /* PS-Act: D2, PS->Set D2. */
243 pNode->afg.u32F08_param = 0;
244 pNode->afg.u32F17_param = 0;
245 break;
246 }
247
248 /*
249 * DACs.
250 */
251 case STAC9220_NID_DAC0: /* DAC0: Headphones 0 + 1 */
252 case STAC9220_NID_DAC1: /* DAC1: PIN C */
253 case STAC9220_NID_DAC2: /* DAC2: PIN B */
254 case STAC9220_NID_DAC3: /* DAC3: PIN F */
255 {
256 pNode->dac.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
257 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT,
258 HDA_SDFMT_CHAN_STEREO);
259
260 /* 7.3.4.6: Audio widget capabilities. */
261 pNode->dac.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 13, 0)
262 | CODEC_F00_09_CAP_L_R_SWAP
263 | CODEC_F00_09_CAP_POWER_CTRL
264 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
265 | CODEC_F00_09_CAP_STEREO;
266
267 /* Connection list; must be 0 if the only connection for the widget is
268 * to the High Definition Audio Link. */
269 pNode->dac.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 0 /* Entries */);
270
271 pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);
272
273 RT_ZERO(pNode->dac.B_params);
274 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
275 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
276 break;
277 }
278
279 /*
280 * ADCs.
281 */
282 case STAC9220_NID_ADC0: /* Analog input. */
283 {
284 pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC0;
285 goto adc_init;
286 }
287
288 case STAC9220_NID_ADC1: /* Analog input (CD). */
289 {
290 pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC1;
291
292 /* Fall through is intentional. */
293 adc_init:
294
295 pNode->adc.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
296 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT,
297 HDA_SDFMT_CHAN_STEREO);
298
299 pNode->adc.u32F03_param = RT_BIT(0);
300 pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
301
302 pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
303 | CODEC_F00_09_CAP_POWER_CTRL
304 | CODEC_F00_09_CAP_CONNECTION_LIST
305 | CODEC_F00_09_CAP_PROC_WIDGET
306 | CODEC_F00_09_CAP_STEREO;
307 /* Connection list entries. */
308 pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
309 break;
310 }
311
312 /*
313 * SP/DIF In/Out.
314 */
315 case STAC9220_NID_SPDIF_OUT:
316 {
317 pNode->spdifout.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
318 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT,
319 HDA_SDFMT_CHAN_STEREO);
320 pNode->spdifout.u32F06_param = 0;
321 pNode->spdifout.u32F0d_param = 0;
322
323 pNode->spdifout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 4, 0)
324 | CODEC_F00_09_CAP_DIGITAL
325 | CODEC_F00_09_CAP_FMT_OVERRIDE
326 | CODEC_F00_09_CAP_STEREO;
327
328 /* Use a fixed format from AFG. */
329 pNode->spdifout.node.au32F00_param[0xA] = pThis->aNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
330 pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
331 break;
332 }
333
334 case STAC9220_NID_SPDIF_IN:
335 {
336 pNode->spdifin.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
337 HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_2X, HDA_SDFMT_16_BIT,
338 HDA_SDFMT_CHAN_STEREO);
339
340 pNode->spdifin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 4, 0)
341 | CODEC_F00_09_CAP_DIGITAL
342 | CODEC_F00_09_CAP_CONNECTION_LIST
343 | CODEC_F00_09_CAP_FMT_OVERRIDE
344 | CODEC_F00_09_CAP_STEREO;
345
346 /* Use a fixed format from AFG. */
347 pNode->spdifin.node.au32F00_param[0xA] = pThis->aNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
348 pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
349
350 /* Connection list entries. */
351 pNode->spdifin.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
352 pNode->spdifin.node.au32F02_param[0] = 0x11;
353 break;
354 }
355
356 /*
357 * PINs / Ports.
358 */
359 case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
360 {
361 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA);
362
363 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
364 | CODEC_F00_0C_CAP_INPUT
365 | CODEC_F00_0C_CAP_OUTPUT
366 | CODEC_F00_0C_CAP_HEADPHONE_AMP
367 | CODEC_F00_0C_CAP_PRESENCE_DETECT
368 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
369
370 /* Connection list entry 0: Goes to DAC0. */
371 pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC0;
372
373 if (!pThis->fInReset)
374 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
375 CODEC_F1C_LOCATION_FRONT,
376 CODEC_F1C_DEVICE_HP,
377 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
378 CODEC_F1C_COLOR_GREEN,
379 CODEC_F1C_MISC_NONE,
380 CODEC_F1C_ASSOCIATION_GROUP_1, 0x0 /* Seq */);
381 goto port_init;
382 }
383
384 case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
385 {
386 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
387
388 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
389 | CODEC_F00_0C_CAP_INPUT
390 | CODEC_F00_0C_CAP_OUTPUT
391 | CODEC_F00_0C_CAP_PRESENCE_DETECT
392 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
393
394 /* Connection list entry 0: Goes to DAC2. */
395 pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC2;
396
397 if (!pThis->fInReset)
398 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
399 CODEC_F1C_LOCATION_REAR,
400 CODEC_F1C_DEVICE_SPEAKER,
401 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
402 CODEC_F1C_COLOR_BLACK,
403 CODEC_F1C_MISC_NONE,
404 CODEC_F1C_ASSOCIATION_GROUP_0, 0x1 /* Seq */);
405 goto port_init;
406 }
407
408 case STAC9220_NID_PIN_C: /* Rear Speaker. */
409 {
410 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
411
412 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
413 | CODEC_F00_0C_CAP_INPUT
414 | CODEC_F00_0C_CAP_OUTPUT
415 | CODEC_F00_0C_CAP_PRESENCE_DETECT
416 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
417
418 /* Connection list entry 0: Goes to DAC1. */
419 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC1;
420
421 if (!pThis->fInReset)
422 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
423 CODEC_F1C_LOCATION_REAR,
424 CODEC_F1C_DEVICE_SPEAKER,
425 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
426 CODEC_F1C_COLOR_GREEN,
427 CODEC_F1C_MISC_NONE,
428 CODEC_F1C_ASSOCIATION_GROUP_0, 0x0 /* Seq */);
429 goto port_init;
430 }
431
432 case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
433 {
434 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
435
436 pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
437 | CODEC_F00_0C_CAP_INPUT
438 | CODEC_F00_0C_CAP_OUTPUT
439 | CODEC_F00_0C_CAP_HEADPHONE_AMP
440 | CODEC_F00_0C_CAP_PRESENCE_DETECT
441 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
442
443 /* Connection list entry 0: Goes to DAC1. */
444 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC0;
445
446 if (!pThis->fInReset)
447 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
448 CODEC_F1C_LOCATION_FRONT,
449 CODEC_F1C_DEVICE_MIC,
450 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
451 CODEC_F1C_COLOR_PINK,
452 CODEC_F1C_MISC_NONE,
453 CODEC_F1C_ASSOCIATION_GROUP_15, 0x0 /* Ignored */);
454 /* Fall through is intentional. */
455
456 port_init:
457
458 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
459 | CODEC_F07_OUT_ENABLE;
460 pNode->port.u32F08_param = 0;
461
462 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
463 | CODEC_F00_09_CAP_CONNECTION_LIST
464 | CODEC_F00_09_CAP_UNSOL
465 | CODEC_F00_09_CAP_STEREO;
466 /* Connection list entries. */
467 pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
468 break;
469 }
470
471 case STAC9220_NID_PIN_E:
472 {
473 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
474 pNode->port.u32F08_param = 0;
475 /* If Line in is reported as enabled, OS X sees no speakers! Windows does
476 * not care either way, although Linux does.
477 */
478 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /* fPresent */, 0);
479
480 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
481 | CODEC_F00_09_CAP_UNSOL
482 | CODEC_F00_09_CAP_STEREO;
483
484 pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
485 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
486
487 if (!pThis->fInReset)
488 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
489 CODEC_F1C_LOCATION_REAR,
490 CODEC_F1C_DEVICE_LINE_IN,
491 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
492 CODEC_F1C_COLOR_BLUE,
493 CODEC_F1C_MISC_NONE,
494 CODEC_F1C_ASSOCIATION_GROUP_4, 0x1 /* Seq */);
495 break;
496 }
497
498 case STAC9220_NID_PIN_F:
499 {
500 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE | CODEC_F07_OUT_ENABLE;
501 pNode->port.u32F08_param = 0;
502 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /* fPresent */, CODEC_F09_ANALOG_NA);
503
504 pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
505 | CODEC_F00_09_CAP_CONNECTION_LIST
506 | CODEC_F00_09_CAP_UNSOL
507 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
508 | CODEC_F00_09_CAP_STEREO;
509
510 pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
511 | CODEC_F00_0C_CAP_OUTPUT;
512
513 /* Connection list entry 0: Goes to DAC3. */
514 pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
515 pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC3;
516
517 if (!pThis->fInReset)
518 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
519 CODEC_F1C_LOCATION_INTERNAL,
520 CODEC_F1C_DEVICE_SPEAKER,
521 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
522 CODEC_F1C_COLOR_ORANGE,
523 CODEC_F1C_MISC_NONE,
524 CODEC_F1C_ASSOCIATION_GROUP_0, 0x2 /* Seq */);
525 break;
526 }
527
528 case STAC9220_NID_PIN_SPDIF_OUT: /* Rear SPDIF Out. */
529 {
530 pNode->digout.u32F07_param = CODEC_F07_OUT_ENABLE;
531 pNode->digout.u32F09_param = 0;
532
533 pNode->digout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
534 | CODEC_F00_09_CAP_DIGITAL
535 | CODEC_F00_09_CAP_CONNECTION_LIST
536 | CODEC_F00_09_CAP_STEREO;
537 pNode->digout.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
538
539 /* Connection list entries. */
540 pNode->digout.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 3 /* Entries */);
541 pNode->digout.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_SPDIF_OUT,
542 STAC9220_NID_AMP_ADC0, STAC9221_NID_ADAT_OUT, 0);
543 if (!pThis->fInReset)
544 pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
545 CODEC_F1C_LOCATION_REAR,
546 CODEC_F1C_DEVICE_SPDIF_OUT,
547 CODEC_F1C_CONNECTION_TYPE_DIN,
548 CODEC_F1C_COLOR_BLACK,
549 CODEC_F1C_MISC_NONE,
550 CODEC_F1C_ASSOCIATION_GROUP_2, 0x0 /* Seq */);
551 break;
552 }
553
554 case STAC9220_NID_PIN_SPDIF_IN:
555 {
556 pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 -> D3 */
557 pNode->digin.u32F07_param = CODEC_F07_IN_ENABLE;
558 pNode->digin.u32F08_param = 0;
559 pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
560 pNode->digin.u32F0c_param = 0;
561
562 pNode->digin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 3, 0)
563 | CODEC_F00_09_CAP_POWER_CTRL
564 | CODEC_F00_09_CAP_DIGITAL
565 | CODEC_F00_09_CAP_UNSOL
566 | CODEC_F00_09_CAP_STEREO;
567
568 pNode->digin.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
569 | CODEC_F00_0C_CAP_INPUT
570 | CODEC_F00_0C_CAP_PRESENCE_DETECT;
571 if (!pThis->fInReset)
572 pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
573 CODEC_F1C_LOCATION_REAR,
574 CODEC_F1C_DEVICE_SPDIF_IN,
575 CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
576 CODEC_F1C_COLOR_BLACK,
577 CODEC_F1C_MISC_NONE,
578 CODEC_F1C_ASSOCIATION_GROUP_5, 0x0 /* Seq */);
579 break;
580 }
581
582 case STAC9220_NID_ADC0_MUX:
583 {
584 pNode->adcmux.u32F01_param = 0; /* Connection select control index (STAC9220_NID_PIN_E). */
585 goto adcmux_init;
586 }
587
588 case STAC9220_NID_ADC1_MUX:
589 {
590 pNode->adcmux.u32F01_param = 1; /* Connection select control index (STAC9220_NID_PIN_CD). */
591 /* Fall through is intentional. */
592
593 adcmux_init:
594
595 pNode->adcmux.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
596 | CODEC_F00_09_CAP_CONNECTION_LIST
597 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
598 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
599 | CODEC_F00_09_CAP_STEREO;
600
601 pNode->adcmux.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 27, 4, 0);
602
603 /* Connection list entries. */
604 pNode->adcmux.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 7 /* Entries */);
605 pNode->adcmux.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_E,
606 STAC9220_NID_PIN_CD,
607 STAC9220_NID_PIN_F,
608 STAC9220_NID_PIN_B);
609 pNode->adcmux.node.au32F02_param[0x4] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_C,
610 STAC9220_NID_PIN_HEADPHONE1,
611 STAC9220_NID_PIN_HEADPHONE0,
612 0x0 /* Unused */);
613
614 /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplifiers initialized with 0. */
615 RT_ZERO(pNode->adcmux.B_params);
616 break;
617 }
618
619 case STAC9220_NID_PCBEEP:
620 {
621 pNode->pcbeep.u32F0a_param = 0;
622
623 pNode->pcbeep.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
624 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
625 | CODEC_F00_09_CAP_OUT_AMP_PRESENT;
626 pNode->pcbeep.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 17, 3, 3);
627
628 RT_ZERO(pNode->pcbeep.B_params);
629 break;
630 }
631
632 case STAC9220_NID_PIN_CD:
633 {
634 pNode->cdnode.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
635 | CODEC_F00_09_CAP_STEREO;
636 pNode->cdnode.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT;
637
638 if (!pThis->fInReset)
639 pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
640 CODEC_F1C_LOCATION_INTERNAL,
641 CODEC_F1C_DEVICE_CD,
642 CODEC_F1C_CONNECTION_TYPE_ATAPI,
643 CODEC_F1C_COLOR_UNKNOWN,
644 CODEC_F1C_MISC_NONE,
645 CODEC_F1C_ASSOCIATION_GROUP_4, 0x2 /* Seq */);
646 break;
647 }
648
649 case STAC9220_NID_VOL_KNOB:
650 {
651 pNode->volumeKnob.u32F08_param = 0;
652 pNode->volumeKnob.u32F0f_param = 0x7f;
653
654 pNode->volumeKnob.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0, 0);
655 pNode->volumeKnob.node.au32F00_param[0xD] = RT_BIT(7) | 0x7F;
656
657 /* Connection list entries. */
658 pNode->volumeKnob.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 4 /* Entries */);
659 pNode->volumeKnob.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_DAC0,
660 STAC9220_NID_DAC1,
661 STAC9220_NID_DAC2,
662 STAC9220_NID_DAC3);
663 break;
664 }
665
666 case STAC9220_NID_AMP_ADC0: /* ADC0Vol */
667 {
668 pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC0_MUX;
669 goto adcvol_init;
670 }
671
672 case STAC9220_NID_AMP_ADC1: /* ADC1Vol */
673 {
674 pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC1_MUX;
675 /* Fall through is intentional. */
676
677 adcvol_init:
678
679 pNode->adcvol.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
680 | CODEC_F00_09_CAP_L_R_SWAP
681 | CODEC_F00_09_CAP_CONNECTION_LIST
682 | CODEC_F00_09_CAP_IN_AMP_PRESENT
683 | CODEC_F00_09_CAP_STEREO;
684
685
686 pNode->adcvol.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
687
688 RT_ZERO(pNode->adcvol.B_params);
689 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
690 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
691 break;
692 }
693
694 /*
695 * STAC9221 nodes.
696 */
697
698 case STAC9221_NID_ADAT_OUT:
699 {
700 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 3, 0)
701 | CODEC_F00_09_CAP_DIGITAL
702 | CODEC_F00_09_CAP_STEREO;
703 break;
704 }
705
706 case STAC9221_NID_I2S_OUT:
707 {
708 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 3, 0)
709 | CODEC_F00_09_CAP_DIGITAL
710 | CODEC_F00_09_CAP_STEREO;
711 break;
712 }
713
714 case STAC9221_NID_PIN_I2S_OUT:
715 {
716 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
717 | CODEC_F00_09_CAP_DIGITAL
718 | CODEC_F00_09_CAP_CONNECTION_LIST
719 | CODEC_F00_09_CAP_STEREO;
720
721 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
722
723 /* Connection list entries. */
724 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
725 pNode->node.au32F02_param[0] = STAC9221_NID_I2S_OUT;
726
727 if (!pThis->fInReset)
728 pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
729 CODEC_F1C_LOCATION_NA,
730 CODEC_F1C_DEVICE_LINE_OUT,
731 CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
732 CODEC_F1C_COLOR_UNKNOWN,
733 CODEC_F1C_MISC_NONE,
734 CODEC_F1C_ASSOCIATION_GROUP_15, 0x0 /* Ignored */);
735 break;
736 }
737
738 default:
739 AssertMsgFailed(("Node %RU8 not implemented\n", uNID));
740 break;
741 }
742}
743
744/**
745 * Resets the codec with all its connected nodes.
746 *
747 * @param pThis HDA codec to reset.
748 */
749static DECLCALLBACK(void) stac9220Reset(PHDACODEC pThis)
750{
751 AssertPtrReturnVoid(pThis->aNodes);
752
753 LogRel(("HDA: Codec reset\n"));
754
755 pThis->fInReset = true;
756
757 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->cTotalNodes, RT_ELEMENTS(pThis->aNodes));
758 for (uint8_t i = 0; i < cTotalNodes; i++)
759 stac9220NodeReset(pThis, i, &pThis->aNodes[i]);
760
761 pThis->fInReset = false;
762}
763
764#ifdef IN_RING3
765
766static int stac9220Construct(PHDACODEC pThis)
767{
768 pThis->u16VendorId = 0x8384; /* SigmaTel */
769 /*
770 * Note: The Linux kernel uses "patch_stac922x" for the fixups,
771 * which in turn uses "ref922x_pin_configs" for the configuration
772 * defaults tweaking in sound/pci/hda/patch_sigmatel.c.
773 */
774 pThis->u16DeviceId = 0x7680; /* STAC9221 A1 */
775 pThis->u8BSKU = 0x76;
776 pThis->u8AssemblyId = 0x80;
777
778 pThis->fInReset = false;
779
780#define STAC9220WIDGET(type) memcpy(&pThis->au8##type##s, &g_abStac9220##type##s, sizeof(uint8_t) * RT_ELEMENTS(g_abStac9220##type##s));
781 STAC9220WIDGET(Port);
782 STAC9220WIDGET(Dac);
783 STAC9220WIDGET(Adc);
784 STAC9220WIDGET(AdcVol);
785 STAC9220WIDGET(AdcMux);
786 STAC9220WIDGET(Pcbeep);
787 STAC9220WIDGET(SpdifIn);
788 STAC9220WIDGET(SpdifOut);
789 STAC9220WIDGET(DigInPin);
790 STAC9220WIDGET(DigOutPin);
791 STAC9220WIDGET(Cd);
792 STAC9220WIDGET(VolKnob);
793 STAC9220WIDGET(Reserved);
794#undef STAC9220WIDGET
795
796 AssertCompile(STAC9221_NUM_NODES <= RT_ELEMENTS(pThis->aNodes));
797 pThis->cTotalNodes = STAC9221_NUM_NODES;
798
799 pThis->u8AdcVolsLineIn = STAC9220_NID_AMP_ADC0;
800 pThis->u8DacLineOut = STAC9220_NID_DAC1;
801
802 /*
803 * Initialize all codec nodes.
804 * This is specific to the codec, so do this here.
805 *
806 * Note: Do *not* call stac9220Reset() here, as this would not
807 * initialize the node default configuration values then!
808 */
809 for (uint8_t i = 0; i < STAC9221_NUM_NODES; i++)
810 stac9220NodeReset(pThis, i, &pThis->aNodes[i]);
811
812 /* Common root node initializers. */
813 pThis->aNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
814 pThis->aNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
815
816 /* Common AFG node initializers. */
817 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, STAC9221_NUM_NODES - 2);
818 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
819 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
820 pThis->aNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
821
822 return VINF_SUCCESS;
823}
824
825#endif /* IN_RING3 */
826
827/*
828 * Some generic predicate functions.
829 */
830
831#define DECLISNODEOFTYPE(type) \
832 DECLINLINE(bool) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
833 { \
834 Assert(pThis->au8##type##s); \
835 for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
836 if (pThis->au8##type##s[i] == cNode) \
837 return true; \
838 return false; \
839 }
840/* hdaCodecIsPortNode */
841DECLISNODEOFTYPE(Port)
842/* hdaCodecIsDacNode */
843DECLISNODEOFTYPE(Dac)
844/* hdaCodecIsAdcVolNode */
845DECLISNODEOFTYPE(AdcVol)
846/* hdaCodecIsAdcNode */
847DECLISNODEOFTYPE(Adc)
848/* hdaCodecIsAdcMuxNode */
849DECLISNODEOFTYPE(AdcMux)
850/* hdaCodecIsPcbeepNode */
851DECLISNODEOFTYPE(Pcbeep)
852/* hdaCodecIsSpdifOutNode */
853DECLISNODEOFTYPE(SpdifOut)
854/* hdaCodecIsSpdifInNode */
855DECLISNODEOFTYPE(SpdifIn)
856/* hdaCodecIsDigInPinNode */
857DECLISNODEOFTYPE(DigInPin)
858/* hdaCodecIsDigOutPinNode */
859DECLISNODEOFTYPE(DigOutPin)
860/* hdaCodecIsCdNode */
861DECLISNODEOFTYPE(Cd)
862/* hdaCodecIsVolKnobNode */
863DECLISNODEOFTYPE(VolKnob)
864/* hdaCodecIsReservedNode */
865DECLISNODEOFTYPE(Reserved)
866
867#ifdef IN_RING3
868
869/*
870 * Misc helpers.
871 */
872static int hdaR3CodecToAudVolume(PHDACODECR3 pThisCC, PCODECNODE pNode, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
873{
874 RT_NOREF(pNode);
875
876 uint8_t iDir;
877 switch (enmMixerCtl)
878 {
879 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
880 case PDMAUDIOMIXERCTL_FRONT:
881 iDir = AMPLIFIER_OUT;
882 break;
883 case PDMAUDIOMIXERCTL_LINE_IN:
884 case PDMAUDIOMIXERCTL_MIC_IN:
885 iDir = AMPLIFIER_IN;
886 break;
887 default:
888 AssertMsgFailedReturn(("Invalid mixer control %RU32\n", enmMixerCtl), VERR_INVALID_PARAMETER);
889 break;
890 }
891
892 int iMute;
893 iMute = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
894 iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
895 iMute >>=7;
896 iMute &= 0x1;
897
898 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & 0x7f;
899 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
900
901 /*
902 * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
903 * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
904 * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
905 * to 1 (rather than zero) internally.
906 */
907 lVol = (lVol + 1) * (2 * 255) / 256;
908 rVol = (rVol + 1) * (2 * 255) / 256;
909
910 PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
911
912 LogFunc(("[NID0x%02x] %RU8/%RU8 (%s)\n",
913 pNode->node.uID, lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
914
915 LogRel2(("HDA: Setting volume for mixer control '%s' to %RU8/%RU8 (%s)\n",
916 PDMAudioMixerCtlGetName(enmMixerCtl), lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
917
918 return pThisCC->pfnCbMixerSetVolume(pThisCC->pDevIns, enmMixerCtl, &Vol);
919}
920
921#endif /* IN_RING3 */
922
923DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
924{
925 Assert((pu32Reg && u8Offset < 32));
926 *pu32Reg &= ~(mask << u8Offset);
927 *pu32Reg |= (u32Cmd & mask) << u8Offset;
928}
929
930DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
931{
932 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
933}
934
935DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
936{
937 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
938}
939
940
941/*
942 * Verb processor functions.
943 */
944#if 0 /* unused */
945
946static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
947{
948 RT_NOREF(pThis, pThisCC, cmd);
949 LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
950 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
951 *pResp = 0;
952 return VINF_SUCCESS;
953}
954
955static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
956{
957 int rc;
958 rc = vrbProcUnimplemented(pThis, pThisCC, cmd, pResp);
959 *pResp |= CODEC_RESPONSE_UNSOLICITED;
960 return rc;
961}
962
963#endif /* unused */
964
965
966/* B-- */
967static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
968{
969 RT_NOREF(pThisCC);
970 *pResp = 0;
971
972 /* HDA spec 7.3.3.7 Note A */
973 /** @todo If index out of range response should be 0. */
974 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(cmd);
975
976 PCODECNODE pNode = &pThis->aNodes[CODEC_NID(cmd)];
977 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
978 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
979 CODEC_GET_AMP_DIRECTION(cmd),
980 CODEC_GET_AMP_SIDE(cmd),
981 u8Index);
982 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
983 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
984 CODEC_GET_AMP_DIRECTION(cmd),
985 CODEC_GET_AMP_SIDE(cmd),
986 u8Index);
987 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
988 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
989 CODEC_GET_AMP_DIRECTION(cmd),
990 CODEC_GET_AMP_SIDE(cmd),
991 u8Index);
992 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
993 *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
994 CODEC_GET_AMP_DIRECTION(cmd),
995 CODEC_GET_AMP_SIDE(cmd),
996 u8Index);
997 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
998 *pResp = AMPLIFIER_REGISTER(pNode->port.B_params,
999 CODEC_GET_AMP_DIRECTION(cmd),
1000 CODEC_GET_AMP_SIDE(cmd),
1001 u8Index);
1002 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1003 *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
1004 CODEC_GET_AMP_DIRECTION(cmd),
1005 CODEC_GET_AMP_SIDE(cmd),
1006 u8Index);
1007 else
1008 LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd), CODEC_NID(cmd)));
1009
1010 return VINF_SUCCESS;
1011}
1012
1013static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1014{
1015 RT_NOREF(pThisCC);
1016 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
1017 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
1018 {
1019 *pResp = 0;
1020
1021 LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1022 return VINF_SUCCESS;
1023 }
1024
1025 *pResp = pThis->aNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
1026 return VINF_SUCCESS;
1027}
1028
1029/* F01 */
1030static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1031{
1032 RT_NOREF(pThisCC);
1033 *pResp = 0;
1034
1035 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1036 *pResp = pThis->aNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1037 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1038 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F01_param;
1039 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1040 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F01_param;
1041 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1042 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F01_param;
1043 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1044 *pResp = pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1045 else
1046 LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1047
1048 return VINF_SUCCESS;
1049}
1050
1051/* 701 */
1052static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1053{
1054 RT_NOREF(pThisCC);
1055 *pResp = 0;
1056
1057 uint32_t *pu32Reg = NULL;
1058 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1059 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1060 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1061 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F01_param;
1062 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1063 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F01_param;
1064 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1065 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F01_param;
1066 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1067 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1068 else
1069 LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1070
1071 if (pu32Reg)
1072 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1073
1074 return VINF_SUCCESS;
1075}
1076
1077/* F07 */
1078static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1079{
1080 RT_NOREF(pThisCC);
1081 *pResp = 0;
1082
1083 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1084 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F07_param;
1085 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1086 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F07_param;
1087 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1088 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F07_param;
1089 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1090 *pResp = pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1091 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1092 *pResp = pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1093 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1094 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1095 else
1096 LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1097
1098 return VINF_SUCCESS;
1099}
1100
1101/* 707 */
1102static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1103{
1104 RT_NOREF(pThisCC);
1105 *pResp = 0;
1106
1107 uint32_t *pu32Reg = NULL;
1108 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1109 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F07_param;
1110 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1111 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F07_param;
1112 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1113 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F07_param;
1114 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1115 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1116 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1117 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1118 else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))
1119 && CODEC_NID(cmd) == 0x1b)
1120 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1121 else
1122 LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1123
1124 if (pu32Reg)
1125 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1126
1127 return VINF_SUCCESS;
1128}
1129
1130/* F08 */
1131static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1132{
1133 RT_NOREF(pThisCC);
1134 *pResp = 0;
1135
1136 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1137 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F08_param;
1138 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1139 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1140 else if ((cmd) == STAC9220_NID_AFG)
1141 *pResp = pThis->aNodes[CODEC_NID(cmd)].afg.u32F08_param;
1142 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1143 *pResp = pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1144 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1145 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F08_param;
1146 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1147 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1148 else
1149 LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1150
1151 return VINF_SUCCESS;
1152}
1153
1154/* 708 */
1155static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1156{
1157 RT_NOREF(pThisCC);
1158 *pResp = 0;
1159
1160 uint32_t *pu32Reg = NULL;
1161 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1162 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F08_param;
1163 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1164 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1165 else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1166 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F08_param;
1167 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1168 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1169 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1170 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1171 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1172 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F08_param;
1173 else
1174 LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1175
1176 if (pu32Reg)
1177 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1178
1179 return VINF_SUCCESS;
1180}
1181
1182/* F09 */
1183static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1184{
1185 RT_NOREF(pThisCC);
1186 *pResp = 0;
1187
1188 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1189 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F09_param;
1190 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1191 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F09_param;
1192 else
1193 {
1194 AssertFailed();
1195 LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1196 }
1197
1198 return VINF_SUCCESS;
1199}
1200
1201/* 709 */
1202static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1203{
1204 RT_NOREF(pThisCC);
1205 *pResp = 0;
1206
1207 uint32_t *pu32Reg = NULL;
1208 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1209 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F09_param;
1210 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1211 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F09_param;
1212 else
1213 LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1214
1215 if (pu32Reg)
1216 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1217
1218 return VINF_SUCCESS;
1219}
1220
1221static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1222{
1223 RT_NOREF(pThisCC);
1224 *pResp = 0;
1225
1226 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
1227 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
1228 {
1229 LogFlowFunc(("access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1230 return VINF_SUCCESS;
1231 }
1232 *pResp = pThis->aNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA];
1233 return VINF_SUCCESS;
1234}
1235
1236/* F03 */
1237static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1238{
1239 RT_NOREF(pThisCC);
1240 *pResp = 0;
1241
1242 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1243 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F03_param;
1244
1245 return VINF_SUCCESS;
1246}
1247
1248/* 703 */
1249static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1250{
1251 RT_NOREF(pThisCC);
1252 *pResp = 0;
1253
1254 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1255 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
1256 return VINF_SUCCESS;
1257}
1258
1259/* F0D */
1260static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1261{
1262 RT_NOREF(pThisCC);
1263 *pResp = 0;
1264
1265 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1266 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
1267 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1268 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
1269
1270 return VINF_SUCCESS;
1271}
1272
1273static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
1274{
1275 *pResp = 0;
1276
1277 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1278 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
1279 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1280 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
1281 return VINF_SUCCESS;
1282}
1283
1284/* 70D */
1285static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1286{
1287 RT_NOREF(pThisCC);
1288 return codecSetDigitalConverter(pThis, cmd, 0, pResp);
1289}
1290
1291/* 70E */
1292static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1293{
1294 RT_NOREF(pThisCC);
1295 return codecSetDigitalConverter(pThis, cmd, 8, pResp);
1296}
1297
1298/* F20 */
1299static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1300{
1301 RT_NOREF(pThisCC);
1302 Assert(CODEC_CAD(cmd) == pThis->id);
1303 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->cTotalNodes, RT_ELEMENTS(pThis->aNodes));
1304 Assert(CODEC_NID(cmd) < cTotalNodes);
1305 if (CODEC_NID(cmd) >= cTotalNodes)
1306 {
1307 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1308 *pResp = 0;
1309 return VINF_SUCCESS;
1310 }
1311 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1312 *pResp = pThis->aNodes[CODEC_NID(cmd)].afg.u32F20_param;
1313 else
1314 *pResp = 0;
1315 return VINF_SUCCESS;
1316}
1317
1318static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
1319{
1320 Assert(CODEC_CAD(cmd) == pThis->id);
1321 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->cTotalNodes, RT_ELEMENTS(pThis->aNodes));
1322 Assert(CODEC_NID(cmd) < cTotalNodes);
1323 if (CODEC_NID(cmd) >= cTotalNodes)
1324 {
1325 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1326 return VINF_SUCCESS;
1327 }
1328 uint32_t *pu32Reg;
1329 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1330 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F20_param;
1331 else
1332 AssertFailedReturn(VINF_SUCCESS);
1333 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
1334 return VINF_SUCCESS;
1335}
1336
1337/* 720 */
1338static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1339{
1340 RT_NOREF(pThisCC);
1341 *pResp = 0;
1342 return codecSetSubIdX(pThis, cmd, 0);
1343}
1344
1345/* 721 */
1346static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1347{
1348 RT_NOREF(pThisCC);
1349 *pResp = 0;
1350 return codecSetSubIdX(pThis, cmd, 8);
1351}
1352
1353/* 722 */
1354static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1355{
1356 RT_NOREF(pThisCC);
1357 *pResp = 0;
1358 return codecSetSubIdX(pThis, cmd, 16);
1359}
1360
1361/* 723 */
1362static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1363{
1364 RT_NOREF(pThisCC);
1365 *pResp = 0;
1366 return codecSetSubIdX(pThis, cmd, 24);
1367}
1368
1369static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1370{
1371 RT_NOREF(pThisCC);
1372 Assert(CODEC_CAD(cmd) == pThis->id);
1373
1374 if (pThis->enmType == CODEC_TYPE_STAC9220)
1375 {
1376 Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
1377
1378 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1379 stac9220Reset(pThis);
1380 }
1381 else
1382 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
1383
1384 *pResp = 0;
1385 return VINF_SUCCESS;
1386}
1387
1388/* F05 */
1389static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1390{
1391 RT_NOREF(pThisCC);
1392 *pResp = 0;
1393
1394 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1395 *pResp = pThis->aNodes[CODEC_NID(cmd)].afg.u32F05_param;
1396 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1397 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F05_param;
1398 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1399 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F05_param;
1400 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1401 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F05_param;
1402 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1403 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F05_param;
1404 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1405 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1406 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1407 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1408 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1409 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1410 else
1411 LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1412
1413 LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
1414 CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_ACT(*pResp), CODEC_F05_SET(*pResp)));
1415 return VINF_SUCCESS;
1416}
1417
1418/* 705 */
1419#if 1
1420static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1421{
1422 RT_NOREF(pThisCC);
1423 *pResp = 0;
1424
1425 uint32_t *pu32Reg = NULL;
1426 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1427 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F05_param;
1428 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1429 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F05_param;
1430 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1431 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F05_param;
1432 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1433 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F05_param;
1434 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1435 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F05_param;
1436 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1437 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1438 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1439 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1440 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1441 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1442 else
1443 {
1444 LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1445 }
1446
1447 if (!pu32Reg)
1448 return VINF_SUCCESS;
1449
1450 uint8_t uPwrCmd = CODEC_F05_SET (cmd);
1451 bool fReset = CODEC_F05_IS_RESET (*pu32Reg);
1452 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
1453#ifdef LOG_ENABLED
1454 bool fError = CODEC_F05_IS_ERROR (*pu32Reg);
1455 uint8_t uPwrAct = CODEC_F05_ACT (*pu32Reg);
1456 uint8_t uPwrSet = CODEC_F05_SET (*pu32Reg);
1457 LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
1458 CODEC_NID(cmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
1459 LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
1460 CODEC_F05_ACT(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param),
1461 CODEC_F05_SET(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param)));
1462#endif
1463
1464 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1465 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
1466
1467 const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param);
1468 if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
1469 {
1470 /* Propagate to all other nodes under this AFG. */
1471 LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
1472
1473#define PROPAGATE_PWR_STATE(_aList, _aMember) \
1474 { \
1475 const uint8_t *pu8NodeIndex = &_aList[0]; \
1476 while (*(++pu8NodeIndex)) \
1477 { \
1478 pThis->aNodes[*pu8NodeIndex]._aMember.u32F05_param = \
1479 CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
1480 LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", *pu8NodeIndex, \
1481 CODEC_F05_ACT(pThis->aNodes[*pu8NodeIndex]._aMember.u32F05_param), \
1482 CODEC_F05_SET(pThis->aNodes[*pu8NodeIndex]._aMember.u32F05_param))); \
1483 } \
1484 }
1485
1486 PROPAGATE_PWR_STATE(pThis->au8Dacs, dac);
1487 PROPAGATE_PWR_STATE(pThis->au8Adcs, adc);
1488 PROPAGATE_PWR_STATE(pThis->au8DigInPins, digin);
1489 PROPAGATE_PWR_STATE(pThis->au8DigOutPins, digout);
1490 PROPAGATE_PWR_STATE(pThis->au8SpdifIns, spdifin);
1491 PROPAGATE_PWR_STATE(pThis->au8SpdifOuts, spdifout);
1492 PROPAGATE_PWR_STATE(pThis->au8Reserveds, reserved);
1493
1494#undef PROPAGATE_PWR_STATE
1495 }
1496 /*
1497 * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
1498 * as PS-Set of this node. PS-Act always is one level under PS-Set here.
1499 */
1500 else
1501 {
1502 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
1503 }
1504
1505 LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
1506 CODEC_NID(cmd),
1507 CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
1508
1509 return VINF_SUCCESS;
1510}
1511#else
1512DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
1513{
1514 Assert(pu32F05_param);
1515 if (!pu32F05_param)
1516 return;
1517 bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
1518 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
1519 uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
1520 *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
1521}
1522
1523static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1524{
1525 RT_NOREF(pThisCC);
1526 Assert(CODEC_CAD(cmd) == pThis->id);
1527 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->cTotalNodes, RT_ELEMENTS(pThis->aNodes));
1528 Assert(CODEC_NID(cmd) < cTotalNodes);
1529 if (CODEC_NID(cmd) >= cTotalNodes)
1530 {
1531 *pResp = 0;
1532 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1533 return VINF_SUCCESS;
1534 }
1535 *pResp = 0;
1536 uint32_t *pu32Reg;
1537 if (CODEC_NID(cmd) == 1 /* AFG */)
1538 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F05_param;
1539 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1540 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F05_param;
1541 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1542 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F05_param;
1543 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1544 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F05_param;
1545 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1546 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1547 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1548 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1549 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1550 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1551 else
1552 AssertFailedReturn(VINF_SUCCESS);
1553
1554 bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
1555 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
1556
1557 if (CODEC_NID(cmd) != 1 /* AFG */)
1558 {
1559 /*
1560 * We shouldn't propogate actual power state, which actual for AFG
1561 */
1562 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
1563 CODEC_F05_ACT(pThis->aNodes[1].afg.u32F05_param),
1564 CODEC_F05_SET(cmd));
1565 }
1566
1567 /* Propagate next power state only if AFG is on or verb modifies AFG power state */
1568 if ( CODEC_NID(cmd) == 1 /* AFG */
1569 || !CODEC_F05_ACT(pThis->aNodes[1].afg.u32F05_param))
1570 {
1571 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
1572 if ( CODEC_NID(cmd) == 1 /* AFG */
1573 && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
1574 {
1575 /* now we're powered on AFG and may propogate power states on nodes */
1576 const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
1577 while (*(++pu8NodeIndex))
1578 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].dac.u32F05_param);
1579
1580 pu8NodeIndex = &pThis->au8Adcs[0];
1581 while (*(++pu8NodeIndex))
1582 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].adc.u32F05_param);
1583
1584 pu8NodeIndex = &pThis->au8DigInPins[0];
1585 while (*(++pu8NodeIndex))
1586 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].digin.u32F05_param);
1587 }
1588 }
1589 return VINF_SUCCESS;
1590}
1591#endif
1592
1593/* F06 */
1594static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1595{
1596 RT_NOREF(pThisCC);
1597 *pResp = 0;
1598
1599 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1600 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F06_param;
1601 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1602 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F06_param;
1603 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1604 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
1605 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1606 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
1607 else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
1608 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F06_param;
1609 else
1610 LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1611
1612 LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
1613 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd), CODEC_F00_06_GET_CHANNEL_ID(cmd)));
1614
1615 return VINF_SUCCESS;
1616}
1617
1618/* A0 */
1619static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1620{
1621 RT_NOREF(pThisCC);
1622 *pResp = 0;
1623
1624 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1625 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32A_param;
1626 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1627 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32A_param;
1628 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1629 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32A_param;
1630 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1631 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32A_param;
1632 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1633 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32A_param;
1634 else
1635 LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1636
1637 return VINF_SUCCESS;
1638}
1639
1640/* Also see section 3.7.1. */
1641static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1642{
1643 RT_NOREF(pThisCC);
1644 *pResp = 0;
1645
1646 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1647 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
1648 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1649 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
1650 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1651 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
1652 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1653 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
1654 else
1655 LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1656
1657 return VINF_SUCCESS;
1658}
1659
1660/* F0C */
1661static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1662{
1663 RT_NOREF(pThisCC);
1664 *pResp = 0;
1665
1666 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1667 *pResp = pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
1668 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1669 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F0c_param;
1670 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1671 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F0c_param;
1672 else
1673 LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1674
1675 return VINF_SUCCESS;
1676}
1677
1678/* 70C */
1679static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1680{
1681 RT_NOREF(pThisCC);
1682 *pResp = 0;
1683
1684 uint32_t *pu32Reg = NULL;
1685 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1686 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
1687 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1688 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F0c_param;
1689 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1690 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F0c_param;
1691 else
1692 LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1693
1694 if (pu32Reg)
1695 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1696
1697 return VINF_SUCCESS;
1698}
1699
1700/* F0F */
1701static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1702{
1703 RT_NOREF(pThisCC);
1704 *pResp = 0;
1705
1706 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1707 *pResp = pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
1708 else
1709 LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1710
1711 return VINF_SUCCESS;
1712}
1713
1714/* 70F */
1715static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1716{
1717 RT_NOREF(pThisCC);
1718 *pResp = 0;
1719
1720 uint32_t *pu32Reg = NULL;
1721 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1722 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
1723 else
1724 LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1725
1726 if (pu32Reg)
1727 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1728
1729 return VINF_SUCCESS;
1730}
1731
1732/* F15 */
1733static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1734{
1735 RT_NOREF(pThis, pThisCC, cmd);
1736 *pResp = 0;
1737 return VINF_SUCCESS;
1738}
1739
1740/* 715 */
1741static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1742{
1743 RT_NOREF(pThis, pThisCC, cmd);
1744 *pResp = 0;
1745 return VINF_SUCCESS;
1746}
1747
1748/* F16 */
1749static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1750{
1751 RT_NOREF(pThis, pThisCC, cmd);
1752 *pResp = 0;
1753 return VINF_SUCCESS;
1754}
1755
1756/* 716 */
1757static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1758{
1759 RT_NOREF(pThis, pThisCC, cmd);
1760 *pResp = 0;
1761 return VINF_SUCCESS;
1762}
1763
1764/* F17 */
1765static DECLCALLBACK(int) vrbProcGetGPIODirection(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1766{
1767 RT_NOREF(pThisCC);
1768 *pResp = 0;
1769
1770 /* Note: this is true for ALC885. */
1771 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1772 *pResp = pThis->aNodes[1].afg.u32F17_param;
1773 else
1774 LogRel2(("HDA: Warning: Unhandled get GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1775
1776 return VINF_SUCCESS;
1777}
1778
1779/* 717 */
1780static DECLCALLBACK(int) vrbProcSetGPIODirection(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1781{
1782 RT_NOREF(pThisCC);
1783 *pResp = 0;
1784
1785 uint32_t *pu32Reg = NULL;
1786 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1787 pu32Reg = &pThis->aNodes[1].afg.u32F17_param;
1788 else
1789 LogRel2(("HDA: Warning: Unhandled set GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1790
1791 if (pu32Reg)
1792 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1793
1794 return VINF_SUCCESS;
1795}
1796
1797/* F1C */
1798static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1799{
1800 RT_NOREF(pThisCC);
1801 *pResp = 0;
1802
1803 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1804 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F1c_param;
1805 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1806 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F1c_param;
1807 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1808 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F1c_param;
1809 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1810 *pResp = pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
1811 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1812 *pResp = pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
1813 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1814 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
1815 else
1816 LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1817
1818 return VINF_SUCCESS;
1819}
1820
1821static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
1822{
1823 uint32_t *pu32Reg = NULL;
1824 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1825 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F1c_param;
1826 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1827 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F1c_param;
1828 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1829 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F1c_param;
1830 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1831 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
1832 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1833 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
1834 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1835 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
1836 else
1837 LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
1838
1839 if (pu32Reg)
1840 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
1841
1842 return VINF_SUCCESS;
1843}
1844
1845/* 71C */
1846static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1847{
1848 RT_NOREF(pThisCC);
1849 *pResp = 0;
1850 return codecSetConfigX(pThis, cmd, 0);
1851}
1852
1853/* 71D */
1854static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1855{
1856 RT_NOREF(pThisCC);
1857 *pResp = 0;
1858 return codecSetConfigX(pThis, cmd, 8);
1859}
1860
1861/* 71E */
1862static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1863{
1864 RT_NOREF(pThisCC);
1865 *pResp = 0;
1866 return codecSetConfigX(pThis, cmd, 16);
1867}
1868
1869/* 71E */
1870static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1871{
1872 RT_NOREF(pThisCC);
1873 *pResp = 0;
1874 return codecSetConfigX(pThis, cmd, 24);
1875}
1876
1877/* F04 */
1878static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1879{
1880 RT_NOREF(pThisCC);
1881 *pResp = 0;
1882
1883 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1884 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F04_param;
1885 else
1886 LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1887
1888 return VINF_SUCCESS;
1889}
1890
1891/* 704 */
1892static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1893{
1894 RT_NOREF(pThisCC);
1895 *pResp = 0;
1896
1897 uint32_t *pu32Reg = NULL;
1898 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1899 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F04_param;
1900 else
1901 LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1902
1903 if (pu32Reg)
1904 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1905
1906 return VINF_SUCCESS;
1907}
1908
1909#ifdef IN_RING3
1910
1911/* 3-- */
1912static DECLCALLBACK(int) vrbProcR3SetAmplifier(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1913{
1914 *pResp = 0;
1915
1916 PCODECNODE pNode = &pThis->aNodes[CODEC_NID(cmd)];
1917 AMPLIFIER *pAmplifier = NULL;
1918 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1919 pAmplifier = &pNode->dac.B_params;
1920 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1921 pAmplifier = &pNode->adcvol.B_params;
1922 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1923 pAmplifier = &pNode->adcmux.B_params;
1924 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1925 pAmplifier = &pNode->pcbeep.B_params;
1926 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1927 pAmplifier = &pNode->port.B_params;
1928 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1929 pAmplifier = &pNode->adc.B_params;
1930 else
1931 LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
1932 cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd), CODEC_NID(cmd)));
1933
1934 if (!pAmplifier)
1935 return VINF_SUCCESS;
1936
1937 bool fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
1938 bool fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
1939 bool fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
1940 bool fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
1941 uint8_t u8Index = CODEC_SET_AMP_INDEX(cmd);
1942
1943 if ( (!fIsLeft && !fIsRight)
1944 || (!fIsOut && !fIsIn))
1945 return VINF_SUCCESS;
1946
1947 LogFunc(("[NID0x%02x] fIsOut=%RTbool, fIsIn=%RTbool, fIsLeft=%RTbool, fIsRight=%RTbool, Idx=%RU8\n",
1948 CODEC_NID(cmd), fIsOut, fIsIn, fIsLeft, fIsRight, u8Index));
1949
1950 if (fIsIn)
1951 {
1952 if (fIsLeft)
1953 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
1954 if (fIsRight)
1955 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1956
1957 // if (CODEC_NID(cmd) == pThis->u8AdcVolsLineIn)
1958 // {
1959 hdaR3CodecToAudVolume(pThisCC, pNode, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
1960 // }
1961 }
1962 if (fIsOut)
1963 {
1964 if (fIsLeft)
1965 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
1966 if (fIsRight)
1967 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1968
1969 if (CODEC_NID(cmd) == pThis->u8DacLineOut)
1970 hdaR3CodecToAudVolume(pThisCC, pNode, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
1971 }
1972
1973 return VINF_SUCCESS;
1974}
1975
1976/* 706 */
1977static DECLCALLBACK(int) vrbProcR3SetStreamId(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t cmd, uint64_t *pResp)
1978{
1979 *pResp = 0;
1980
1981 uint8_t uSD = CODEC_F00_06_GET_STREAM_ID(cmd);
1982 uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(cmd);
1983
1984 LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8\n",
1985 CODEC_NID(cmd), uSD, uChannel));
1986
1987 ASSERT_GUEST_LOGREL_MSG_RETURN(uSD < HDA_MAX_STREAMS,
1988 ("Setting stream ID #%RU8 is invalid\n", uSD), VERR_INVALID_PARAMETER);
1989
1990 PDMAUDIODIR enmDir;
1991 uint32_t *pu32Addr;
1992 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1993 {
1994 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F06_param;
1995 enmDir = PDMAUDIODIR_OUT;
1996 }
1997 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1998 {
1999 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F06_param;
2000 enmDir = PDMAUDIODIR_IN;
2001 }
2002 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2003 {
2004 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2005 enmDir = PDMAUDIODIR_OUT;
2006 }
2007 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2008 {
2009 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2010 enmDir = PDMAUDIODIR_IN;
2011 }
2012 else
2013 {
2014 enmDir = PDMAUDIODIR_UNKNOWN;
2015 LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
2016 return VINF_SUCCESS;
2017 }
2018
2019 /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
2020 pThis->aNodes[CODEC_NID(cmd)].node.uSD = uSD;
2021 pThis->aNodes[CODEC_NID(cmd)].node.uChannel = uChannel;
2022
2023 if (enmDir == PDMAUDIODIR_OUT)
2024 {
2025 /** @todo Check if non-interleaved streams need a different channel / SDn? */
2026
2027 /* Propagate to the controller. */
2028 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
2029# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2030 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
2031 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
2032# endif
2033 }
2034 else if (enmDir == PDMAUDIODIR_IN)
2035 {
2036 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
2037# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2038 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_MIC_IN, uSD, uChannel);
2039# endif
2040 }
2041
2042 hdaCodecSetRegisterU8(pu32Addr, cmd, 0);
2043
2044 return VINF_SUCCESS;
2045}
2046
2047#endif /* IN_RING3 */
2048
2049
2050/**
2051 * HDA codec verb descriptors.
2052 *
2053 * @note This must be ordered by uVerb so we can do a binary lookup.
2054 */
2055static const CODECVERB g_aCodecVerbs[] =
2056{
2057 /* Verb Verb mask Callback Name
2058 ---------- --------------------- ------------------------------------------------------------------- */
2059 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
2060 { 0x00030000, CODEC_VERB_16BIT_CMD, CTX_EXPR(vrbProcR3SetAmplifier,NULL,NULL), "SetAmplifier " },
2061 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
2062 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
2063 { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " },
2064 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
2065 { 0x00070600, CODEC_VERB_8BIT_CMD , CTX_EXPR(vrbProcR3SetStreamId,NULL,NULL) , "SetStreamId " },
2066 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
2067 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
2068 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
2069 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
2070 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
2071 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
2072 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
2073 { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
2074 { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
2075 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIODirection , "SetGPIODirection " },
2076 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
2077 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
2078 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
2079 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
2080 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
2081 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
2082 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
2083 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
2084 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
2085 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
2086 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
2087 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
2088 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
2089 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
2090 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
2091 { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
2092 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
2093 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
2094 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
2095 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
2096 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
2097 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
2098 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
2099 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
2100 { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
2101 { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
2102 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIODirection , "GetGPIODirection " },
2103 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
2104 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
2105 /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
2106};
2107
2108
2109#ifdef IN_RING3
2110
2111/**
2112 * CODEC debug info item printing state.
2113 */
2114typedef struct CODECDEBUG
2115{
2116 /** DBGF info helpers. */
2117 PCDBGFINFOHLP pHlp;
2118 /** Current recursion level. */
2119 uint8_t uLevel;
2120 /** Pointer to codec state. */
2121 PHDACODEC pThis;
2122} CODECDEBUG;
2123/** Pointer to the debug info item printing state for the codec. */
2124typedef CODECDEBUG *PCODECDEBUG;
2125
2126#define CODECDBG_INDENT pInfo->uLevel++;
2127#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
2128
2129#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2130#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
2131
2132/** Wrapper around DBGFINFOHLP::pfnPrintf that adds identation. */
2133static void codecDbgPrintf(PCODECDEBUG pInfo, const char *pszFormat, ...)
2134{
2135 va_list va;
2136 va_start(va, pszFormat);
2137 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%N", pInfo->uLevel * 4, "", pszFormat, &va);
2138 va_end(va);
2139}
2140
2141/** Power state */
2142static void codecDbgPrintNodeRegF05(PCODECDEBUG pInfo, uint32_t u32Reg)
2143{
2144 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2145 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2146}
2147
2148static void codecDbgPrintNodeRegA(PCODECDEBUG pInfo, uint32_t u32Reg)
2149{
2150 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2151}
2152
2153static void codecDbgPrintNodeRegF00(PCODECDEBUG pInfo, uint32_t *paReg00)
2154{
2155 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2156
2157 CODECDBG_INDENT
2158 codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
2159 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2160 uint32_t uReg = paReg00[0xD];
2161 CODECDBG_INDENT
2162 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2163 CODEC_F00_0D_NUM_STEPS(uReg),
2164 CODEC_F00_0D_STEP_SIZE(uReg),
2165 CODEC_F00_0D_OFFSET(uReg),
2166 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2167
2168 uReg = paReg00[0x12];
2169 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2170 CODEC_F00_12_NUM_STEPS(uReg),
2171 CODEC_F00_12_STEP_SIZE(uReg),
2172 CODEC_F00_12_OFFSET(uReg),
2173 RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
2174 CODECDBG_UNINDENT
2175 CODECDBG_UNINDENT
2176}
2177
2178static void codecDbgPrintNodeAmp(PCODECDEBUG pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
2179{
2180# define CODECDBG_AMP(reg, chan) \
2181 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2182 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2183 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2184 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2185 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg))
2186
2187 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2188 CODECDBG_AMP(regAmp, "Left");
2189 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2190 CODECDBG_AMP(regAmp, "Right");
2191
2192# undef CODECDBG_AMP
2193}
2194
2195# if 0 /* unused */
2196static void codecDbgPrintNodeConnections(PCODECDEBUG pInfo, PCODECNODE pNode)
2197{
2198 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2199 {
2200 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2201 return;
2202 }
2203}
2204# endif
2205
2206static void codecDbgPrintNode(PCODECDEBUG pInfo, PCODECNODE pNode, bool fRecursive)
2207{
2208 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
2209
2210 if (pNode->node.uID == STAC9220_NID_ROOT)
2211 {
2212 CODECDBG_PRINT("ROOT\n");
2213 }
2214 else if (pNode->node.uID == STAC9220_NID_AFG)
2215 {
2216 CODECDBG_PRINT("AFG\n");
2217 CODECDBG_INDENT
2218 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2219 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2220 CODECDBG_UNINDENT
2221 }
2222 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
2223 {
2224 CODECDBG_PRINT("PORT\n");
2225 }
2226 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
2227 {
2228 CODECDBG_PRINT("DAC\n");
2229 CODECDBG_INDENT
2230 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2231 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2232 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2233 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2234 CODECDBG_UNINDENT
2235 }
2236 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
2237 {
2238 CODECDBG_PRINT("ADC VOLUME\n");
2239 CODECDBG_INDENT
2240 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2241 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2242 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2243 CODECDBG_UNINDENT
2244 }
2245 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
2246 {
2247 CODECDBG_PRINT("ADC\n");
2248 CODECDBG_INDENT
2249 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2250 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2251 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2252 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2253 CODECDBG_UNINDENT
2254 }
2255 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
2256 {
2257 CODECDBG_PRINT("ADC MUX\n");
2258 CODECDBG_INDENT
2259 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2260 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2261 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2262 CODECDBG_UNINDENT
2263 }
2264 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
2265 CODECDBG_PRINT("PC BEEP\n");
2266 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
2267 CODECDBG_PRINT("SPDIF OUT\n");
2268 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
2269 CODECDBG_PRINT("SPDIF IN\n");
2270 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
2271 CODECDBG_PRINT("DIGITAL IN PIN\n");
2272 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
2273 CODECDBG_PRINT("DIGITAL OUT PIN\n");
2274 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
2275 CODECDBG_PRINT("CD\n");
2276 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
2277 CODECDBG_PRINT("VOLUME KNOB\n");
2278 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
2279 CODECDBG_PRINT("RESERVED\n");
2280 else
2281 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
2282
2283 if (fRecursive)
2284 {
2285# define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
2286 if (cCnt >= _aEntry) \
2287 { \
2288 const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
2289 if (pNode->node.uID == uID) \
2290 codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
2291 }
2292
2293 /* Slow recursion, but this is debug stuff anyway. */
2294 for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
2295 {
2296 const PCODECNODE pSubNode = &pInfo->pThis->aNodes[i];
2297 if (pSubNode->node.uID == pNode->node.uID)
2298 continue;
2299
2300 const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
2301 if (cCnt == 0) /* No connections present? Skip. */
2302 continue;
2303
2304 CODECDBG_INDENT
2305 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
2306 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
2307 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
2308 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
2309 CODECDBG_UNINDENT
2310 }
2311
2312# undef CODECDBG_PRINT_CONLIST_ENTRY
2313 }
2314}
2315
2316static DECLCALLBACK(void) codecR3DbgListNodes(PHDACODEC pThis, PHDACODECR3 pThisCC, PCDBGFINFOHLP pHlp, const char *pszArgs)
2317{
2318 RT_NOREF(pThisCC, pszArgs);
2319
2320 pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
2321
2322 CODECDEBUG dbgInfo;
2323 dbgInfo.pHlp = pHlp;
2324 dbgInfo.pThis = pThis;
2325 dbgInfo.uLevel = 0;
2326
2327 PCODECDEBUG pInfo = &dbgInfo;
2328
2329 CODECDBG_INDENT
2330 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
2331 {
2332 PCODECNODE pNode = &pThis->aNodes[i];
2333
2334 /* Start with all nodes which have connection entries set. */
2335 if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
2336 codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
2337 }
2338 CODECDBG_UNINDENT
2339}
2340
2341static DECLCALLBACK(void) codecR3DbgSelector(PHDACODEC pThis, PHDACODECR3 pThisCC, PCDBGFINFOHLP pHlp, const char *pszArgs)
2342{
2343 RT_NOREF(pThis, pThisCC, pHlp, pszArgs);
2344}
2345
2346#endif /* IN_RING3 */
2347
2348/**
2349 * Implements
2350 */
2351static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, PHDACODECCC pThisCC, uint32_t uCmd, uint64_t *puResp)
2352{
2353 /*
2354 * Clear the return value and assert some sanity.
2355 */
2356 AssertPtr(puResp);
2357 *puResp = 0;
2358 AssertPtr(pThis);
2359 AssertPtr(pThisCC);
2360 AssertMsgReturn(CODEC_CAD(uCmd) == pThis->id,
2361 ("Unknown codec address 0x%x\n", CODEC_CAD(uCmd)),
2362 VERR_INVALID_PARAMETER);
2363 uint32_t const uCmdData = CODEC_VERBDATA(uCmd);
2364 AssertMsgReturn( uCmdData != 0
2365 && CODEC_NID(uCmd) < RT_MIN(pThis->cTotalNodes, RT_ELEMENTS(pThis->aNodes)),
2366 ("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(uCmd), uCmdData),
2367 VERR_INVALID_PARAMETER);
2368 STAM_COUNTER_INC(&pThis->CTX_SUFF(StatLookups));
2369
2370 /*
2371 * Do a binary lookup of the verb.
2372 * Note! if we want other verb tables, add a table selector before the loop.
2373 */
2374 size_t iFirst = 0;
2375 size_t iEnd = RT_ELEMENTS(g_aCodecVerbs);
2376 for (;;)
2377 {
2378 size_t const iCur = iFirst + (iEnd - iFirst) / 2;
2379 uint32_t const uVerb = g_aCodecVerbs[iCur].uVerb;
2380 if (uCmdData < uVerb)
2381 {
2382 if (iCur > iFirst)
2383 iEnd = iCur;
2384 else
2385 break;
2386 }
2387 else if ((uCmdData & g_aCodecVerbs[iCur].fMask) != uVerb)
2388 {
2389 if (iCur + 1 < iEnd)
2390 iFirst = iCur + 1;
2391 else
2392 break;
2393 }
2394 else
2395 {
2396 /*
2397 * Found it! Run the callback and return.
2398 */
2399#ifndef IN_RING3
2400 if (!g_aCodecVerbs[iCur].pfn)
2401 {
2402 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> VERR_INVALID_CONTEXT\n", /* -> ring-3 */
2403 CODEC_NID(uCmd), g_aCodecVerbs[iCur].uVerb, g_aCodecVerbs[iCur].pszName, CODEC_VERB_PAYLOAD8(uCmd)));
2404 return VERR_INVALID_CONTEXT;
2405 }
2406#endif
2407 AssertPtrReturn(g_aCodecVerbs[iCur].pfn, VERR_INTERNAL_ERROR_5); /* Paranoia^2. */
2408
2409 int rc = g_aCodecVerbs[iCur].pfn(pThis, pThisCC, uCmd, puResp);
2410 AssertRC(rc);
2411 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
2412 CODEC_NID(uCmd), g_aCodecVerbs[iCur].uVerb, g_aCodecVerbs[iCur].pszName, CODEC_VERB_PAYLOAD8(uCmd), *puResp));
2413 return rc;
2414 }
2415 }
2416
2417#ifdef VBOX_STRICT
2418 for (size_t i = 0; i < RT_ELEMENTS(g_aCodecVerbs); i++)
2419 {
2420 AssertMsg(i == 0 || g_aCodecVerbs[i - 1].uVerb < g_aCodecVerbs[i].uVerb,
2421 ("i=%#x uVerb[-1]=%#x uVerb=%#x - buggy table!\n", i, g_aCodecVerbs[i - 1].uVerb, g_aCodecVerbs[i].uVerb));
2422 AssertMsg((uCmdData & g_aCodecVerbs[i].fMask) != g_aCodecVerbs[i].uVerb,
2423 ("i=%#x uVerb=%#x uCmd=%#x - buggy binary search or table!\n", i, g_aCodecVerbs[i].uVerb, uCmd));
2424 }
2425#endif
2426 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(uCmd), CODEC_VERBDATA(uCmd)));
2427 return VERR_NOT_FOUND;
2428}
2429
2430
2431/*
2432 * APIs exposed to DevHDA.
2433 */
2434
2435#ifdef IN_RING3
2436
2437int hdaR3CodecAddStream(PHDACODECR3 pThisCC, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
2438{
2439 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2440 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2441
2442 int rc = VINF_SUCCESS;
2443
2444 switch (enmMixerCtl)
2445 {
2446 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
2447 case PDMAUDIOMIXERCTL_FRONT:
2448#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2449 case PDMAUDIOMIXERCTL_CENTER_LFE:
2450 case PDMAUDIOMIXERCTL_REAR:
2451#endif
2452 break;
2453
2454 case PDMAUDIOMIXERCTL_LINE_IN:
2455#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2456 case PDMAUDIOMIXERCTL_MIC_IN:
2457#endif
2458 break;
2459
2460 default:
2461 AssertMsgFailed(("Mixer control %#x not implemented\n", enmMixerCtl));
2462 rc = VERR_NOT_IMPLEMENTED;
2463 break;
2464 }
2465
2466 if (RT_SUCCESS(rc))
2467 rc = pThisCC->pfnCbMixerAddStream(pThisCC->pDevIns, enmMixerCtl, pCfg);
2468
2469 LogFlowFuncLeaveRC(rc);
2470 return rc;
2471}
2472
2473int hdaR3CodecRemoveStream(PHDACODECR3 pThisCC, PDMAUDIOMIXERCTL enmMixerCtl, bool fImmediate)
2474{
2475 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2476
2477 int rc = pThisCC->pfnCbMixerRemoveStream(pThisCC->pDevIns, enmMixerCtl, fImmediate);
2478
2479 LogFlowFuncLeaveRC(rc);
2480 return rc;
2481}
2482
2483int hdaCodecSaveState(PPDMDEVINS pDevIns, PHDACODEC pThis, PSSMHANDLE pSSM)
2484{
2485 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
2486 AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
2487 VERR_INTERNAL_ERROR);
2488 pHlp->pfnSSMPutU32(pSSM, pThis->cTotalNodes);
2489 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
2490 pHlp->pfnSSMPutStructEx(pSSM, &pThis->aNodes[idxNode].SavedState, sizeof(pThis->aNodes[idxNode].SavedState),
2491 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
2492 return VINF_SUCCESS;
2493}
2494
2495int hdaR3CodecLoadState(PPDMDEVINS pDevIns, PHDACODEC pThis, PHDACODECR3 pThisCC, PSSMHANDLE pSSM, uint32_t uVersion)
2496{
2497 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
2498 PCSSMFIELD pFields = NULL;
2499 uint32_t fFlags = 0;
2500 if (uVersion >= HDA_SAVED_STATE_VERSION_4)
2501 {
2502 /* Since version 4 a flexible node count is supported. */
2503 uint32_t cNodes;
2504 int rc2 = pHlp->pfnSSMGetU32(pSSM, &cNodes);
2505 AssertRCReturn(rc2, rc2);
2506 AssertReturn(cNodes == 0x1c, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2507 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2508
2509 pFields = g_aCodecNodeFields;
2510 fFlags = 0;
2511 }
2512 else if (uVersion >= HDA_SAVED_STATE_VERSION_2)
2513 {
2514 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2515 pFields = g_aCodecNodeFields;
2516 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2517 }
2518 else if (uVersion >= HDA_SAVED_STATE_VERSION_1)
2519 {
2520 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2521 pFields = g_aCodecNodeFieldsV1;
2522 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2523 }
2524 else
2525 AssertFailedReturn(VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2526
2527 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
2528 {
2529 uint8_t idOld = pThis->aNodes[idxNode].SavedState.Core.uID;
2530 int rc = pHlp->pfnSSMGetStructEx(pSSM, &pThis->aNodes[idxNode].SavedState, sizeof(pThis->aNodes[idxNode].SavedState),
2531 fFlags, pFields, NULL);
2532 AssertRCReturn(rc, rc);
2533 AssertLogRelMsgReturn(idOld == pThis->aNodes[idxNode].SavedState.Core.uID,
2534 ("loaded %#x, expected %#x\n", pThis->aNodes[idxNode].SavedState.Core.uID, idOld),
2535 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2536 }
2537
2538 /*
2539 * Update stuff after changing the state.
2540 */
2541 PCODECNODE pNode;
2542 if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
2543 {
2544 pNode = &pThis->aNodes[pThis->u8DacLineOut];
2545 hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
2546 }
2547 else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
2548 {
2549 pNode = &pThis->aNodes[pThis->u8DacLineOut];
2550 hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
2551 }
2552
2553 pNode = &pThis->aNodes[pThis->u8AdcVolsLineIn];
2554 hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
2555
2556 LogFlowFuncLeaveRC(VINF_SUCCESS);
2557 return VINF_SUCCESS;
2558}
2559
2560/**
2561 * Powers off the codec (ring-3).
2562 *
2563 * @param pThisCC Context-specific codec data (ring-3) to power off.
2564 */
2565void hdaR3CodecPowerOff(PHDACODECR3 pThisCC)
2566{
2567 if (!pThisCC)
2568 return;
2569
2570 LogFlowFuncEnter();
2571
2572 LogRel2(("HDA: Powering off codec ...\n"));
2573
2574 int rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_FRONT, true /*fImmediate*/);
2575 AssertRC(rc2);
2576#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2577 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_CENTER_LFE, true /*fImmediate*/);
2578 AssertRC(rc2);
2579 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_REAR, true /*fImmediate*/);
2580 AssertRC(rc2);
2581#endif
2582
2583#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2584 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_MIC_IN, true /*fImmediate*/);
2585 AssertRC(rc2);
2586#endif
2587 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_LINE_IN, true /*fImmediate*/);
2588 AssertRC(rc2);
2589}
2590
2591/**
2592 * Constructs a codec (ring-3).
2593 *
2594 * @returns VBox status code.
2595 * @param pDevIns Associated device instance.
2596 * @param pThis Shared codec data beteen r0/r3.
2597 * @param pThisCC Context-specific codec data (ring-3).
2598 * @param uLUN Device LUN to assign.
2599 * @param pCfg CFGM node to use for configuration.
2600 */
2601int hdaR3CodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, PHDACODECR3 pThisCC, uint16_t uLUN, PCFGMNODE pCfg)
2602{
2603 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
2604 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2605 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2606 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2607
2608 pThis->id = uLUN;
2609 pThis->enmType = CODEC_TYPE_STAC9220; /** @todo Make this dynamic. */
2610
2611 int rc;
2612
2613 switch (pThis->enmType)
2614 {
2615 case CODEC_TYPE_STAC9220:
2616 {
2617 rc = stac9220Construct(pThis);
2618 AssertRCReturn(rc, rc);
2619 break;
2620 }
2621
2622 default:
2623 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
2624 break;
2625 }
2626
2627 pThisCC->pfnDbgSelector = codecR3DbgSelector;
2628 pThisCC->pfnDbgListNodes = codecR3DbgListNodes;
2629 pThisCC->pfnLookup = codecLookup;
2630
2631 /*
2632 * Set initial volume.
2633 */
2634 PCODECNODE pNode = &pThis->aNodes[pThis->u8DacLineOut];
2635 rc = hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
2636 AssertRCReturn(rc, rc);
2637
2638 pNode = &pThis->aNodes[pThis->u8AdcVolsLineIn];
2639 rc = hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
2640 AssertRCReturn(rc, rc);
2641
2642# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2643# error "Implement mic-in support!"
2644# endif
2645
2646 /*
2647 * Statistics
2648 */
2649 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatLookupsR3, STAMTYPE_COUNTER, "Codec/LookupsR0", STAMUNIT_OCCURENCES, "Number of R0 codecLookup calls");
2650# if 0 /* Codec is not yet kosher enough for ring-0. @bugref{9890c64} */
2651 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatLookupsR0, STAMTYPE_COUNTER, "Codec/LookupsR3", STAMUNIT_OCCURENCES, "Number of R3 codecLookup calls");
2652# endif
2653
2654 return rc;
2655}
2656
2657#else /* IN_RING0 */
2658
2659/**
2660 * Constructs a codec (ring-0).
2661 *
2662 * @returns VBox status code.
2663 * @param pDevIns Associated device instance.
2664 * @param pThis Shared codec data beteen r0/r3.
2665 * @param pThisCC Context-specific codec data (ring-0).
2666 */
2667int hdaR0CodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, PHDACODECR0 pThisCC)
2668{
2669 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
2670 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2671 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2672
2673 pThisCC->pfnLookup = codecLookup;
2674
2675 /* Note: Everything else is done in the R3 part. */
2676
2677 return VINF_SUCCESS;
2678}
2679
2680#endif /* IN_RING0 */
2681
2682/**
2683 * Destructs a codec.
2684 *
2685 * @param pThis Codec to destruct.
2686 */
2687void hdaCodecDestruct(PHDACODEC pThis)
2688{
2689 if (!pThis)
2690 return;
2691
2692 /* Nothing to do here atm. */
2693
2694 LogFlowFuncEnter();
2695}
2696
2697/**
2698 * Resets a codec.
2699 *
2700 * @param pThis Codec to reset.
2701 */
2702void hdaCodecReset(PHDACODEC pThis)
2703{
2704 switch (pThis->enmType)
2705 {
2706 case CODEC_TYPE_STAC9220:
2707 stac9220Reset(pThis);
2708 break;
2709
2710 default:
2711 AssertFailed();
2712 break;
2713 }
2714}
2715
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