VirtualBox

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

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

HDA/Codec: Codec now also can run in R0 to speed up interrupt handling and therefore lowering DPC latency on Windows guests [build fix]. ticketoem2ref:36

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette