VirtualBox

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

Last change on this file since 87805 was 87805, 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.7 KB
Line 
1/* $Id: HDACodec.cpp 87805 2021-02-19 11:57:57Z 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
748#ifdef IN_RING3
749
750static int stac9220Construct(PHDACODEC pThis)
751{
752 pThis->u16VendorId = 0x8384; /* SigmaTel */
753 /*
754 * Note: The Linux kernel uses "patch_stac922x" for the fixups,
755 * which in turn uses "ref922x_pin_configs" for the configuration
756 * defaults tweaking in sound/pci/hda/patch_sigmatel.c.
757 */
758 pThis->u16DeviceId = 0x7680; /* STAC9221 A1 */
759 pThis->u8BSKU = 0x76;
760 pThis->u8AssemblyId = 0x80;
761
762 pThis->fInReset = false;
763
764#define STAC9220WIDGET(type) memcpy(&pThis->au8##type##s, &g_abStac9220##type##s, sizeof(uint8_t) * RT_ELEMENTS(g_abStac9220##type##s));
765 STAC9220WIDGET(Port);
766 STAC9220WIDGET(Dac);
767 STAC9220WIDGET(Adc);
768 STAC9220WIDGET(AdcVol);
769 STAC9220WIDGET(AdcMux);
770 STAC9220WIDGET(Pcbeep);
771 STAC9220WIDGET(SpdifIn);
772 STAC9220WIDGET(SpdifOut);
773 STAC9220WIDGET(DigInPin);
774 STAC9220WIDGET(DigOutPin);
775 STAC9220WIDGET(Cd);
776 STAC9220WIDGET(VolKnob);
777 STAC9220WIDGET(Reserved);
778#undef STAC9220WIDGET
779
780 pThis->cTotalNodes = STAC9221_NUM_NODES;
781 Assert(pThis->cTotalNodes <= CODEC_NODES_MAX);
782
783 pThis->u8AdcVolsLineIn = STAC9220_NID_AMP_ADC0;
784 pThis->u8DacLineOut = STAC9220_NID_DAC1;
785
786 /*
787 * Initialize all codec nodes.
788 * This is specific to the codec, so do this here.
789 *
790 * Note: Do *not* call stac9220Reset() here, as this would not
791 * initialize the node default configuration values then!
792 */
793 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
794 stac9220NodeReset(pThis, i, &pThis->aNodes[i]);
795
796 /* Common root node initializers. */
797 pThis->aNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
798 pThis->aNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
799
800 /* Common AFG node initializers. */
801 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
802 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
803 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
804 pThis->aNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
805
806 return VINF_SUCCESS;
807}
808
809#endif /* IN_RING3 */
810
811/*
812 * Some generic predicate functions.
813 */
814
815#define DECLISNODEOFTYPE(type) \
816 DECLINLINE(bool) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
817 { \
818 Assert(pThis->au8##type##s); \
819 for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
820 if (pThis->au8##type##s[i] == cNode) \
821 return true; \
822 return false; \
823 }
824/* hdaCodecIsPortNode */
825DECLISNODEOFTYPE(Port)
826/* hdaCodecIsDacNode */
827DECLISNODEOFTYPE(Dac)
828/* hdaCodecIsAdcVolNode */
829DECLISNODEOFTYPE(AdcVol)
830/* hdaCodecIsAdcNode */
831DECLISNODEOFTYPE(Adc)
832/* hdaCodecIsAdcMuxNode */
833DECLISNODEOFTYPE(AdcMux)
834/* hdaCodecIsPcbeepNode */
835DECLISNODEOFTYPE(Pcbeep)
836/* hdaCodecIsSpdifOutNode */
837DECLISNODEOFTYPE(SpdifOut)
838/* hdaCodecIsSpdifInNode */
839DECLISNODEOFTYPE(SpdifIn)
840/* hdaCodecIsDigInPinNode */
841DECLISNODEOFTYPE(DigInPin)
842/* hdaCodecIsDigOutPinNode */
843DECLISNODEOFTYPE(DigOutPin)
844/* hdaCodecIsCdNode */
845DECLISNODEOFTYPE(Cd)
846/* hdaCodecIsVolKnobNode */
847DECLISNODEOFTYPE(VolKnob)
848/* hdaCodecIsReservedNode */
849DECLISNODEOFTYPE(Reserved)
850
851#ifdef IN_RING3
852
853/*
854 * Misc helpers.
855 */
856static int hdaR3CodecToAudVolume(PHDACODECR3 pThisCC, PCODECNODE pNode, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
857{
858 RT_NOREF(pNode);
859
860 uint8_t iDir;
861 switch (enmMixerCtl)
862 {
863 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
864 case PDMAUDIOMIXERCTL_FRONT:
865 iDir = AMPLIFIER_OUT;
866 break;
867 case PDMAUDIOMIXERCTL_LINE_IN:
868 case PDMAUDIOMIXERCTL_MIC_IN:
869 iDir = AMPLIFIER_IN;
870 break;
871 default:
872 AssertMsgFailedReturn(("Invalid mixer control %RU32\n", enmMixerCtl), VERR_INVALID_PARAMETER);
873 break;
874 }
875
876 int iMute;
877 iMute = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
878 iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
879 iMute >>=7;
880 iMute &= 0x1;
881
882 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & 0x7f;
883 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
884
885 /*
886 * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
887 * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
888 * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
889 * to 1 (rather than zero) internally.
890 */
891 lVol = (lVol + 1) * (2 * 255) / 256;
892 rVol = (rVol + 1) * (2 * 255) / 256;
893
894 PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
895
896 LogFunc(("[NID0x%02x] %RU8/%RU8 (%s)\n",
897 pNode->node.uID, lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
898
899 LogRel2(("HDA: Setting volume for mixer control '%s' to %RU8/%RU8 (%s)\n",
900 DrvAudioHlpAudMixerCtlToStr(enmMixerCtl), lVol, rVol, RT_BOOL(iMute) ? "Muted" : "Unmuted"));
901
902 return pThisCC->pfnCbMixerSetVolume(pThisCC->pDevIns, enmMixerCtl, &Vol);
903}
904
905#endif /* IN_RING3 */
906
907DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
908{
909 Assert((pu32Reg && u8Offset < 32));
910 *pu32Reg &= ~(mask << u8Offset);
911 *pu32Reg |= (u32Cmd & mask) << u8Offset;
912}
913
914DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
915{
916 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
917}
918
919DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
920{
921 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
922}
923
924
925/*
926 * Verb processor functions.
927 */
928#if 0 /* unused */
929
930static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
931{
932 RT_NOREF(pThis, cmd);
933 LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
934 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
935 *pResp = 0;
936 return VINF_SUCCESS;
937}
938
939static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
940{
941 int rc;
942 rc = vrbProcUnimplemented(pThis, cmd, pResp);
943 *pResp |= CODEC_RESPONSE_UNSOLICITED;
944 return rc;
945}
946
947#endif /* unused */
948
949#ifdef IN_RING0
950
951/* B-- */
952static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
953{
954 *pResp = 0;
955
956 /* HDA spec 7.3.3.7 Note A */
957 /** @todo If index out of range response should be 0. */
958 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(cmd);
959
960 PCODECNODE pNode = &pThis->aNodes[CODEC_NID(cmd)];
961 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
962 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
963 CODEC_GET_AMP_DIRECTION(cmd),
964 CODEC_GET_AMP_SIDE(cmd),
965 u8Index);
966 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
967 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
968 CODEC_GET_AMP_DIRECTION(cmd),
969 CODEC_GET_AMP_SIDE(cmd),
970 u8Index);
971 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
972 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
973 CODEC_GET_AMP_DIRECTION(cmd),
974 CODEC_GET_AMP_SIDE(cmd),
975 u8Index);
976 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
977 *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
978 CODEC_GET_AMP_DIRECTION(cmd),
979 CODEC_GET_AMP_SIDE(cmd),
980 u8Index);
981 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
982 *pResp = AMPLIFIER_REGISTER(pNode->port.B_params,
983 CODEC_GET_AMP_DIRECTION(cmd),
984 CODEC_GET_AMP_SIDE(cmd),
985 u8Index);
986 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
987 *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
988 CODEC_GET_AMP_DIRECTION(cmd),
989 CODEC_GET_AMP_SIDE(cmd),
990 u8Index);
991 else
992 LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd), CODEC_NID(cmd)));
993
994 return VINF_SUCCESS;
995}
996
997static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
998{
999 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
1000 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
1001 {
1002 *pResp = 0;
1003
1004 LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1005 return VINF_SUCCESS;
1006 }
1007
1008 *pResp = pThis->aNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
1009 return VINF_SUCCESS;
1010}
1011
1012/* F01 */
1013static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1014{
1015 *pResp = 0;
1016
1017 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1018 *pResp = pThis->aNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1019 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1020 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F01_param;
1021 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1022 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F01_param;
1023 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1024 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F01_param;
1025 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1026 *pResp = pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1027 else
1028 LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1029
1030 return VINF_SUCCESS;
1031}
1032
1033/* 701 */
1034static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1035{
1036 *pResp = 0;
1037
1038 uint32_t *pu32Reg = NULL;
1039 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1040 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1041 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1042 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F01_param;
1043 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1044 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F01_param;
1045 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1046 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F01_param;
1047 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1048 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1049 else
1050 LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1051
1052 if (pu32Reg)
1053 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1054
1055 return VINF_SUCCESS;
1056}
1057
1058/* F07 */
1059static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1060{
1061 *pResp = 0;
1062
1063 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1064 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F07_param;
1065 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1066 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F07_param;
1067 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1068 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F07_param;
1069 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1070 *pResp = pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1071 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1072 *pResp = pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1073 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1074 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1075 else
1076 LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1077
1078 return VINF_SUCCESS;
1079}
1080
1081/* 707 */
1082static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1083{
1084 *pResp = 0;
1085
1086 uint32_t *pu32Reg = NULL;
1087 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1088 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F07_param;
1089 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1090 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F07_param;
1091 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1092 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F07_param;
1093 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1094 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1095 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1096 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1097 else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))
1098 && CODEC_NID(cmd) == 0x1b)
1099 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1100 else
1101 LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1102
1103 if (pu32Reg)
1104 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1105
1106 return VINF_SUCCESS;
1107}
1108
1109/* F08 */
1110static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1111{
1112 *pResp = 0;
1113
1114 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1115 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F08_param;
1116 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1117 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1118 else if ((cmd) == STAC9220_NID_AFG)
1119 *pResp = pThis->aNodes[CODEC_NID(cmd)].afg.u32F08_param;
1120 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1121 *pResp = pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1122 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1123 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F08_param;
1124 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1125 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1126 else
1127 LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1128
1129 return VINF_SUCCESS;
1130}
1131
1132/* 708 */
1133static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1134{
1135 *pResp = 0;
1136
1137 uint32_t *pu32Reg = NULL;
1138 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1139 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F08_param;
1140 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1141 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1142 else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1143 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F08_param;
1144 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1145 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1146 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1147 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F08_param;
1148 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1149 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F08_param;
1150 else
1151 LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1152
1153 if (pu32Reg)
1154 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1155
1156 return VINF_SUCCESS;
1157}
1158
1159/* F09 */
1160static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1161{
1162 *pResp = 0;
1163
1164 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1165 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F09_param;
1166 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1167 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F09_param;
1168 else
1169 {
1170 AssertFailed();
1171 LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1172 }
1173
1174 return VINF_SUCCESS;
1175}
1176
1177/* 709 */
1178static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1179{
1180 *pResp = 0;
1181
1182 uint32_t *pu32Reg = NULL;
1183 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1184 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F09_param;
1185 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1186 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F09_param;
1187 else
1188 LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1189
1190 if (pu32Reg)
1191 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1192
1193 return VINF_SUCCESS;
1194}
1195
1196static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1197{
1198 *pResp = 0;
1199
1200 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
1201 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
1202 {
1203 LogFlowFunc(("access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1204 return VINF_SUCCESS;
1205 }
1206 *pResp = pThis->aNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA];
1207 return VINF_SUCCESS;
1208}
1209
1210/* F03 */
1211static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1212{
1213 *pResp = 0;
1214
1215 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1216 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F03_param;
1217
1218 return VINF_SUCCESS;
1219}
1220
1221/* 703 */
1222static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1223{
1224 *pResp = 0;
1225
1226 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1227 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
1228 return VINF_SUCCESS;
1229}
1230
1231/* F0D */
1232static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1233{
1234 *pResp = 0;
1235
1236 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1237 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
1238 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1239 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
1240
1241 return VINF_SUCCESS;
1242}
1243
1244static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
1245{
1246 *pResp = 0;
1247
1248 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1249 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
1250 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1251 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
1252 return VINF_SUCCESS;
1253}
1254
1255/* 70D */
1256static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1257{
1258 return codecSetDigitalConverter(pThis, cmd, 0, pResp);
1259}
1260
1261/* 70E */
1262static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1263{
1264 return codecSetDigitalConverter(pThis, cmd, 8, pResp);
1265}
1266
1267/* F20 */
1268static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1269{
1270 Assert(CODEC_CAD(cmd) == pThis->id);
1271 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1272 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1273 {
1274 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1275 return VINF_SUCCESS;
1276 }
1277 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1278 *pResp = pThis->aNodes[CODEC_NID(cmd)].afg.u32F20_param;
1279 else
1280 *pResp = 0;
1281 return VINF_SUCCESS;
1282}
1283
1284static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
1285{
1286 Assert(CODEC_CAD(cmd) == pThis->id);
1287 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1288 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1289 {
1290 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1291 return VINF_SUCCESS;
1292 }
1293 uint32_t *pu32Reg;
1294 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1295 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F20_param;
1296 else
1297 AssertFailedReturn(VINF_SUCCESS);
1298 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
1299 return VINF_SUCCESS;
1300}
1301
1302/* 720 */
1303static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1304{
1305 *pResp = 0;
1306 return codecSetSubIdX(pThis, cmd, 0);
1307}
1308
1309/* 721 */
1310static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1311{
1312 *pResp = 0;
1313 return codecSetSubIdX(pThis, cmd, 8);
1314}
1315
1316/* 722 */
1317static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1318{
1319 *pResp = 0;
1320 return codecSetSubIdX(pThis, cmd, 16);
1321}
1322
1323/* 723 */
1324static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1325{
1326 *pResp = 0;
1327 return codecSetSubIdX(pThis, cmd, 24);
1328}
1329
1330static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1331{
1332 Assert(CODEC_CAD(cmd) == pThis->id);
1333
1334 if (pThis->enmType == CODEC_TYPE_STAC9220)
1335 {
1336 Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
1337
1338 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1339 stac9220Reset(pThis);
1340 }
1341 else
1342 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
1343
1344 *pResp = 0;
1345 return VINF_SUCCESS;
1346}
1347
1348/* F05 */
1349static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1350{
1351 *pResp = 0;
1352
1353 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1354 *pResp = pThis->aNodes[CODEC_NID(cmd)].afg.u32F05_param;
1355 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1356 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F05_param;
1357 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1358 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F05_param;
1359 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1360 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F05_param;
1361 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1362 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F05_param;
1363 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1364 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1365 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1366 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1367 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1368 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1369 else
1370 LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1371
1372 LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
1373 CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_ACT(*pResp), CODEC_F05_SET(*pResp)));
1374 return VINF_SUCCESS;
1375}
1376
1377/* 705 */
1378#if 1
1379static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1380{
1381 *pResp = 0;
1382
1383 uint32_t *pu32Reg = NULL;
1384 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1385 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F05_param;
1386 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1387 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F05_param;
1388 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1389 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F05_param;
1390 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1391 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F05_param;
1392 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1393 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F05_param;
1394 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1395 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1396 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1397 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1398 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1399 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1400 else
1401 {
1402 LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1403 }
1404
1405 if (!pu32Reg)
1406 return VINF_SUCCESS;
1407
1408 uint8_t uPwrCmd = CODEC_F05_SET (cmd);
1409 bool fReset = CODEC_F05_IS_RESET (*pu32Reg);
1410 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
1411#ifdef LOG_ENABLED
1412 bool fError = CODEC_F05_IS_ERROR (*pu32Reg);
1413 uint8_t uPwrAct = CODEC_F05_ACT (*pu32Reg);
1414 uint8_t uPwrSet = CODEC_F05_SET (*pu32Reg);
1415 LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
1416 CODEC_NID(cmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
1417 LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
1418 CODEC_F05_ACT(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param),
1419 CODEC_F05_SET(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param)));
1420#endif
1421
1422 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1423 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
1424
1425 const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param);
1426 if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
1427 {
1428 /* Propagate to all other nodes under this AFG. */
1429 LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
1430
1431#define PROPAGATE_PWR_STATE(_aList, _aMember) \
1432 { \
1433 const uint8_t *pu8NodeIndex = &_aList[0]; \
1434 while (*(++pu8NodeIndex)) \
1435 { \
1436 pThis->aNodes[*pu8NodeIndex]._aMember.u32F05_param = \
1437 CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
1438 LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", *pu8NodeIndex, \
1439 CODEC_F05_ACT(pThis->aNodes[*pu8NodeIndex]._aMember.u32F05_param), \
1440 CODEC_F05_SET(pThis->aNodes[*pu8NodeIndex]._aMember.u32F05_param))); \
1441 } \
1442 }
1443
1444 PROPAGATE_PWR_STATE(pThis->au8Dacs, dac);
1445 PROPAGATE_PWR_STATE(pThis->au8Adcs, adc);
1446 PROPAGATE_PWR_STATE(pThis->au8DigInPins, digin);
1447 PROPAGATE_PWR_STATE(pThis->au8DigOutPins, digout);
1448 PROPAGATE_PWR_STATE(pThis->au8SpdifIns, spdifin);
1449 PROPAGATE_PWR_STATE(pThis->au8SpdifOuts, spdifout);
1450 PROPAGATE_PWR_STATE(pThis->au8Reserveds, reserved);
1451
1452#undef PROPAGATE_PWR_STATE
1453 }
1454 /*
1455 * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
1456 * as PS-Set of this node. PS-Act always is one level under PS-Set here.
1457 */
1458 else
1459 {
1460 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
1461 }
1462
1463 LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
1464 CODEC_NID(cmd),
1465 CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
1466
1467 return VINF_SUCCESS;
1468}
1469#else
1470DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
1471{
1472 Assert(pu32F05_param);
1473 if (!pu32F05_param)
1474 return;
1475 bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
1476 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
1477 uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
1478 *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
1479}
1480
1481static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1482{
1483 Assert(CODEC_CAD(cmd) == pThis->id);
1484 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1485 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1486 {
1487 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1488 return VINF_SUCCESS;
1489 }
1490 *pResp = 0;
1491 uint32_t *pu32Reg;
1492 if (CODEC_NID(cmd) == 1 /* AFG */)
1493 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].afg.u32F05_param;
1494 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1495 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F05_param;
1496 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1497 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F05_param;
1498 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1499 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F05_param;
1500 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1501 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1502 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1503 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1504 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1505 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1506 else
1507 AssertFailedReturn(VINF_SUCCESS);
1508
1509 bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
1510 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
1511
1512 if (CODEC_NID(cmd) != 1 /* AFG */)
1513 {
1514 /*
1515 * We shouldn't propogate actual power state, which actual for AFG
1516 */
1517 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
1518 CODEC_F05_ACT(pThis->aNodes[1].afg.u32F05_param),
1519 CODEC_F05_SET(cmd));
1520 }
1521
1522 /* Propagate next power state only if AFG is on or verb modifies AFG power state */
1523 if ( CODEC_NID(cmd) == 1 /* AFG */
1524 || !CODEC_F05_ACT(pThis->aNodes[1].afg.u32F05_param))
1525 {
1526 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
1527 if ( CODEC_NID(cmd) == 1 /* AFG */
1528 && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
1529 {
1530 /* now we're powered on AFG and may propogate power states on nodes */
1531 const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
1532 while (*(++pu8NodeIndex))
1533 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].dac.u32F05_param);
1534
1535 pu8NodeIndex = &pThis->au8Adcs[0];
1536 while (*(++pu8NodeIndex))
1537 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].adc.u32F05_param);
1538
1539 pu8NodeIndex = &pThis->au8DigInPins[0];
1540 while (*(++pu8NodeIndex))
1541 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].digin.u32F05_param);
1542 }
1543 }
1544 return VINF_SUCCESS;
1545}
1546#endif
1547
1548/* F06 */
1549static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1550{
1551 *pResp = 0;
1552
1553 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1554 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F06_param;
1555 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1556 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32F06_param;
1557 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1558 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
1559 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1560 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
1561 else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
1562 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F06_param;
1563 else
1564 LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1565
1566 LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
1567 CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd), CODEC_F00_06_GET_CHANNEL_ID(cmd)));
1568
1569 return VINF_SUCCESS;
1570}
1571
1572/* A0 */
1573static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1574{
1575 *pResp = 0;
1576
1577 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1578 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32A_param;
1579 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1580 *pResp = pThis->aNodes[CODEC_NID(cmd)].adc.u32A_param;
1581 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1582 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifout.u32A_param;
1583 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1584 *pResp = pThis->aNodes[CODEC_NID(cmd)].spdifin.u32A_param;
1585 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1586 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32A_param;
1587 else
1588 LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1589
1590 return VINF_SUCCESS;
1591}
1592
1593/* Also see section 3.7.1. */
1594static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1595{
1596 *pResp = 0;
1597
1598 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1599 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
1600 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1601 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
1602 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1603 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
1604 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1605 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
1606 else
1607 LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1608
1609 return VINF_SUCCESS;
1610}
1611
1612/* F0C */
1613static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1614{
1615 *pResp = 0;
1616
1617 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1618 *pResp = pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
1619 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1620 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F0c_param;
1621 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1622 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F0c_param;
1623 else
1624 LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1625
1626 return VINF_SUCCESS;
1627}
1628
1629/* 70C */
1630static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1631{
1632 *pResp = 0;
1633
1634 uint32_t *pu32Reg = NULL;
1635 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1636 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
1637 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1638 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F0c_param;
1639 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1640 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F0c_param;
1641 else
1642 LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1643
1644 if (pu32Reg)
1645 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1646
1647 return VINF_SUCCESS;
1648}
1649
1650/* F0F */
1651static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1652{
1653 *pResp = 0;
1654
1655 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1656 *pResp = pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
1657 else
1658 LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1659
1660 return VINF_SUCCESS;
1661}
1662
1663/* 70F */
1664static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1665{
1666 *pResp = 0;
1667
1668 uint32_t *pu32Reg = NULL;
1669 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1670 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
1671 else
1672 LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1673
1674 if (pu32Reg)
1675 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1676
1677 return VINF_SUCCESS;
1678}
1679
1680/* F15 */
1681static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1682{
1683 RT_NOREF(pThis, cmd);
1684 *pResp = 0;
1685 return VINF_SUCCESS;
1686}
1687
1688/* 715 */
1689static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1690{
1691 RT_NOREF(pThis, cmd);
1692 *pResp = 0;
1693 return VINF_SUCCESS;
1694}
1695
1696/* F16 */
1697static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1698{
1699 RT_NOREF(pThis, cmd);
1700 *pResp = 0;
1701 return VINF_SUCCESS;
1702}
1703
1704/* 716 */
1705static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1706{
1707 RT_NOREF(pThis, cmd);
1708 *pResp = 0;
1709 return VINF_SUCCESS;
1710}
1711
1712/* F17 */
1713static DECLCALLBACK(int) vrbProcGetGPIODirection(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1714{
1715 *pResp = 0;
1716
1717 /* Note: this is true for ALC885. */
1718 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1719 *pResp = pThis->aNodes[1].afg.u32F17_param;
1720 else
1721 LogRel2(("HDA: Warning: Unhandled get GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1722
1723 return VINF_SUCCESS;
1724}
1725
1726/* 717 */
1727static DECLCALLBACK(int) vrbProcSetGPIODirection(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1728{
1729 *pResp = 0;
1730
1731 uint32_t *pu32Reg = NULL;
1732 if (CODEC_NID(cmd) == STAC9220_NID_AFG)
1733 pu32Reg = &pThis->aNodes[1].afg.u32F17_param;
1734 else
1735 LogRel2(("HDA: Warning: Unhandled set GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1736
1737 if (pu32Reg)
1738 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1739
1740 return VINF_SUCCESS;
1741}
1742
1743/* F1C */
1744static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1745{
1746 *pResp = 0;
1747
1748 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1749 *pResp = pThis->aNodes[CODEC_NID(cmd)].port.u32F1c_param;
1750 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1751 *pResp = pThis->aNodes[CODEC_NID(cmd)].digout.u32F1c_param;
1752 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1753 *pResp = pThis->aNodes[CODEC_NID(cmd)].digin.u32F1c_param;
1754 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1755 *pResp = pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
1756 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1757 *pResp = pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
1758 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1759 *pResp = pThis->aNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
1760 else
1761 LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1762
1763 return VINF_SUCCESS;
1764}
1765
1766static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
1767{
1768 uint32_t *pu32Reg = NULL;
1769 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1770 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].port.u32F1c_param;
1771 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1772 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digin.u32F1c_param;
1773 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1774 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].digout.u32F1c_param;
1775 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1776 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
1777 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1778 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
1779 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1780 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
1781 else
1782 LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
1783
1784 if (pu32Reg)
1785 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
1786
1787 return VINF_SUCCESS;
1788}
1789
1790/* 71C */
1791static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1792{
1793 *pResp = 0;
1794 return codecSetConfigX(pThis, cmd, 0);
1795}
1796
1797/* 71D */
1798static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1799{
1800 *pResp = 0;
1801 return codecSetConfigX(pThis, cmd, 8);
1802}
1803
1804/* 71E */
1805static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1806{
1807 *pResp = 0;
1808 return codecSetConfigX(pThis, cmd, 16);
1809}
1810
1811/* 71E */
1812static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1813{
1814 *pResp = 0;
1815 return codecSetConfigX(pThis, cmd, 24);
1816}
1817
1818/* F04 */
1819static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1820{
1821 *pResp = 0;
1822
1823 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1824 *pResp = pThis->aNodes[CODEC_NID(cmd)].dac.u32F04_param;
1825 else
1826 LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1827
1828 return VINF_SUCCESS;
1829}
1830
1831/* 704 */
1832static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1833{
1834 *pResp = 0;
1835
1836 uint32_t *pu32Reg = NULL;
1837 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1838 pu32Reg = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F04_param;
1839 else
1840 LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1841
1842 if (pu32Reg)
1843 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1844
1845 return VINF_SUCCESS;
1846}
1847
1848#else /* IN_RING3 */
1849
1850/* 3-- */
1851static DECLCALLBACK(int) vrbProcR3SetAmplifier(PHDACODEC pThis, PHDACODECR3 pThisCC, uint32_t cmd, uint64_t *pResp)
1852{
1853 *pResp = 0;
1854
1855 PCODECNODE pNode = &pThis->aNodes[CODEC_NID(cmd)];
1856 AMPLIFIER *pAmplifier = NULL;
1857 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1858 pAmplifier = &pNode->dac.B_params;
1859 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1860 pAmplifier = &pNode->adcvol.B_params;
1861 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1862 pAmplifier = &pNode->adcmux.B_params;
1863 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1864 pAmplifier = &pNode->pcbeep.B_params;
1865 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1866 pAmplifier = &pNode->port.B_params;
1867 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1868 pAmplifier = &pNode->adc.B_params;
1869 else
1870 LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
1871 cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd), CODEC_NID(cmd)));
1872
1873 if (!pAmplifier)
1874 return VINF_SUCCESS;
1875
1876 bool fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
1877 bool fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
1878 bool fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
1879 bool fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
1880 uint8_t u8Index = CODEC_SET_AMP_INDEX(cmd);
1881
1882 if ( (!fIsLeft && !fIsRight)
1883 || (!fIsOut && !fIsIn))
1884 return VINF_SUCCESS;
1885
1886 LogFunc(("[NID0x%02x] fIsOut=%RTbool, fIsIn=%RTbool, fIsLeft=%RTbool, fIsRight=%RTbool, Idx=%RU8\n",
1887 CODEC_NID(cmd), fIsOut, fIsIn, fIsLeft, fIsRight, u8Index));
1888
1889 if (fIsIn)
1890 {
1891 if (fIsLeft)
1892 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
1893 if (fIsRight)
1894 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1895
1896 // if (CODEC_NID(cmd) == pThis->u8AdcVolsLineIn)
1897 // {
1898 hdaR3CodecToAudVolume(pThisCC, pNode, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
1899 // }
1900 }
1901 if (fIsOut)
1902 {
1903 if (fIsLeft)
1904 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
1905 if (fIsRight)
1906 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1907
1908 if (CODEC_NID(cmd) == pThis->u8DacLineOut)
1909 hdaR3CodecToAudVolume(pThisCC, pNode, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
1910 }
1911
1912 return VINF_SUCCESS;
1913}
1914
1915/* 706 */
1916static DECLCALLBACK(int) vrbProcR3SetStreamId(PHDACODEC pThis, PHDACODECR3 pThisCC, uint32_t cmd, uint64_t *pResp)
1917{
1918 *pResp = 0;
1919
1920 uint8_t uSD = CODEC_F00_06_GET_STREAM_ID(cmd);
1921 uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(cmd);
1922
1923 LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8\n",
1924 CODEC_NID(cmd), uSD, uChannel));
1925
1926 ASSERT_GUEST_LOGREL_MSG_RETURN(uSD < HDA_MAX_STREAMS,
1927 ("Setting stream ID #%RU8 is invalid\n", uSD), VERR_INVALID_PARAMETER);
1928
1929 PDMAUDIODIR enmDir;
1930 uint32_t *pu32Addr = NULL;
1931 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1932 {
1933 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].dac.u32F06_param;
1934 enmDir = PDMAUDIODIR_OUT;
1935 }
1936 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1937 {
1938 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].adc.u32F06_param;
1939 enmDir = PDMAUDIODIR_IN;
1940 }
1941 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1942 {
1943 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
1944 enmDir = PDMAUDIODIR_OUT;
1945 }
1946 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1947 {
1948 pu32Addr = &pThis->aNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
1949 enmDir = PDMAUDIODIR_IN;
1950 }
1951 else
1952 {
1953 enmDir = PDMAUDIODIR_UNKNOWN;
1954 LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
1955 }
1956
1957 /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
1958 if (enmDir != PDMAUDIODIR_UNKNOWN)
1959 {
1960 pThis->aNodes[CODEC_NID(cmd)].node.uSD = uSD;
1961 pThis->aNodes[CODEC_NID(cmd)].node.uChannel = uChannel;
1962
1963 if (enmDir == PDMAUDIODIR_OUT)
1964 {
1965 /** @todo Check if non-interleaved streams need a different channel / SDn? */
1966
1967 /* Propagate to the controller. */
1968 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
1969#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
1970 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
1971 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
1972#endif
1973 }
1974 else if (enmDir == PDMAUDIODIR_IN)
1975 {
1976 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
1977#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
1978 pThisCC->pfnCbMixerControl(pThisCC->pDevIns, PDMAUDIOMIXERCTL_MIC_IN, uSD, uChannel);
1979#endif
1980 }
1981 }
1982
1983 if (pu32Addr)
1984 hdaCodecSetRegisterU8(pu32Addr, cmd, 0);
1985
1986 return VINF_SUCCESS;
1987}
1988
1989#endif /* IN_RING0 */
1990
1991#ifdef IN_RING0
1992
1993/**
1994 * HDA codec verb map for ring-0.
1995 * @todo Any reason not to use binary search here?
1996 * bird: because you'd need to sort the entries first...
1997 */
1998static const CODECVERBR0 g_aCodecVerbsR0[] =
1999{
2000 /* Verb Verb mask Callback Name
2001 * ---------- --------------------- ----------------------------------------------------------
2002 */
2003 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
2004 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
2005 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
2006 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
2007 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
2008 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
2009 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
2010 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
2011 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
2012 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
2013 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
2014 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
2015 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
2016 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
2017 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
2018 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
2019 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
2020 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
2021 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
2022 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
2023 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
2024 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
2025 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
2026 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
2027 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
2028 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
2029 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
2030 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
2031 { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
2032 { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
2033 { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
2034 { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
2035 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIODirection , "GetGPIODirection " },
2036 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIODirection , "SetGPIODirection " },
2037 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
2038 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
2039 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
2040 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
2041 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
2042 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
2043 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
2044 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
2045 { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
2046 { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " }
2047 /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
2048};
2049
2050#else /* IN_RING3 */
2051
2052/**
2053 * HDA codec verb map for ring-3.
2054 */
2055static const CODECVERBR3 g_aCodecVerbsR3[] =
2056{
2057 /* Verb Verb mask Callback Name
2058 * ---------- --------------------- ----------------------------------------------------------
2059 */
2060 { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcR3SetStreamId , "SetStreamId " },
2061 { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcR3SetAmplifier , "SetAmplifier " }
2062};
2063
2064#endif /* IN_RING0 */
2065
2066#ifdef IN_RING3
2067
2068/**
2069 * CODEC debug info item printing state.
2070 */
2071typedef struct CODECDEBUG
2072{
2073 /** DBGF info helpers. */
2074 PCDBGFINFOHLP pHlp;
2075 /** Current recursion level. */
2076 uint8_t uLevel;
2077 /** Pointer to codec state. */
2078 PHDACODEC pThis;
2079} CODECDEBUG;
2080/** Pointer to the debug info item printing state for the codec. */
2081typedef CODECDEBUG *PCODECDEBUG;
2082
2083#define CODECDBG_INDENT pInfo->uLevel++;
2084#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
2085
2086#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2087#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
2088
2089/** Wrapper around DBGFINFOHLP::pfnPrintf that adds identation. */
2090static void codecDbgPrintf(PCODECDEBUG pInfo, const char *pszFormat, ...)
2091{
2092 va_list va;
2093 va_start(va, pszFormat);
2094 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%N", pInfo->uLevel * 4, "", pszFormat, &va);
2095 va_end(va);
2096}
2097
2098/** Power state */
2099static void codecDbgPrintNodeRegF05(PCODECDEBUG pInfo, uint32_t u32Reg)
2100{
2101 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2102 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2103}
2104
2105static void codecDbgPrintNodeRegA(PCODECDEBUG pInfo, uint32_t u32Reg)
2106{
2107 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2108}
2109
2110static void codecDbgPrintNodeRegF00(PCODECDEBUG pInfo, uint32_t *paReg00)
2111{
2112 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2113
2114 CODECDBG_INDENT
2115 codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
2116 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2117 uint32_t uReg = paReg00[0xD];
2118 CODECDBG_INDENT
2119 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2120 CODEC_F00_0D_NUM_STEPS(uReg),
2121 CODEC_F00_0D_STEP_SIZE(uReg),
2122 CODEC_F00_0D_OFFSET(uReg),
2123 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2124
2125 uReg = paReg00[0x12];
2126 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2127 CODEC_F00_12_NUM_STEPS(uReg),
2128 CODEC_F00_12_STEP_SIZE(uReg),
2129 CODEC_F00_12_OFFSET(uReg),
2130 RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
2131 CODECDBG_UNINDENT
2132 CODECDBG_UNINDENT
2133}
2134
2135static void codecDbgPrintNodeAmp(PCODECDEBUG pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
2136{
2137# define CODECDBG_AMP(reg, chan) \
2138 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2139 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2140 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2141 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2142 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg))
2143
2144 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2145 CODECDBG_AMP(regAmp, "Left");
2146 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2147 CODECDBG_AMP(regAmp, "Right");
2148
2149# undef CODECDBG_AMP
2150}
2151
2152# if 0 /* unused */
2153static void codecDbgPrintNodeConnections(PCODECDEBUG pInfo, PCODECNODE pNode)
2154{
2155 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2156 {
2157 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2158 return;
2159 }
2160}
2161# endif
2162
2163static void codecDbgPrintNode(PCODECDEBUG pInfo, PCODECNODE pNode, bool fRecursive)
2164{
2165 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
2166
2167 if (pNode->node.uID == STAC9220_NID_ROOT)
2168 {
2169 CODECDBG_PRINT("ROOT\n");
2170 }
2171 else if (pNode->node.uID == STAC9220_NID_AFG)
2172 {
2173 CODECDBG_PRINT("AFG\n");
2174 CODECDBG_INDENT
2175 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2176 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2177 CODECDBG_UNINDENT
2178 }
2179 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
2180 {
2181 CODECDBG_PRINT("PORT\n");
2182 }
2183 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
2184 {
2185 CODECDBG_PRINT("DAC\n");
2186 CODECDBG_INDENT
2187 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2188 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2189 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2190 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2191 CODECDBG_UNINDENT
2192 }
2193 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
2194 {
2195 CODECDBG_PRINT("ADC VOLUME\n");
2196 CODECDBG_INDENT
2197 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2198 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2199 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2200 CODECDBG_UNINDENT
2201 }
2202 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
2203 {
2204 CODECDBG_PRINT("ADC\n");
2205 CODECDBG_INDENT
2206 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2207 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2208 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2209 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2210 CODECDBG_UNINDENT
2211 }
2212 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
2213 {
2214 CODECDBG_PRINT("ADC MUX\n");
2215 CODECDBG_INDENT
2216 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2217 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2218 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2219 CODECDBG_UNINDENT
2220 }
2221 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
2222 CODECDBG_PRINT("PC BEEP\n");
2223 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
2224 CODECDBG_PRINT("SPDIF OUT\n");
2225 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
2226 CODECDBG_PRINT("SPDIF IN\n");
2227 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
2228 CODECDBG_PRINT("DIGITAL IN PIN\n");
2229 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
2230 CODECDBG_PRINT("DIGITAL OUT PIN\n");
2231 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
2232 CODECDBG_PRINT("CD\n");
2233 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
2234 CODECDBG_PRINT("VOLUME KNOB\n");
2235 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
2236 CODECDBG_PRINT("RESERVED\n");
2237 else
2238 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
2239
2240 if (fRecursive)
2241 {
2242# define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
2243 if (cCnt >= _aEntry) \
2244 { \
2245 const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
2246 if (pNode->node.uID == uID) \
2247 codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
2248 }
2249
2250 /* Slow recursion, but this is debug stuff anyway. */
2251 for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
2252 {
2253 const PCODECNODE pSubNode = &pInfo->pThis->aNodes[i];
2254 if (pSubNode->node.uID == pNode->node.uID)
2255 continue;
2256
2257 const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
2258 if (cCnt == 0) /* No connections present? Skip. */
2259 continue;
2260
2261 CODECDBG_INDENT
2262 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
2263 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
2264 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
2265 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
2266 CODECDBG_UNINDENT
2267 }
2268
2269# undef CODECDBG_PRINT_CONLIST_ENTRY
2270 }
2271}
2272
2273static DECLCALLBACK(void) codecR3DbgListNodes(PHDACODEC pThis, PHDACODECR3 pThisCC, PCDBGFINFOHLP pHlp, const char *pszArgs)
2274{
2275 RT_NOREF(pThisCC, pszArgs);
2276
2277 pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
2278
2279 CODECDEBUG dbgInfo;
2280 dbgInfo.pHlp = pHlp;
2281 dbgInfo.pThis = pThis;
2282 dbgInfo.uLevel = 0;
2283
2284 PCODECDEBUG pInfo = &dbgInfo;
2285
2286 CODECDBG_INDENT
2287 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
2288 {
2289 PCODECNODE pNode = &pThis->aNodes[i];
2290
2291 /* Start with all nodes which have connection entries set. */
2292 if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
2293 codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
2294 }
2295 CODECDBG_UNINDENT
2296}
2297
2298static DECLCALLBACK(void) codecR3DbgSelector(PHDACODEC pThis, PHDACODECR3 pThisCC, PCDBGFINFOHLP pHlp, const char *pszArgs)
2299{
2300 RT_NOREF(pThis, pThisCC, pHlp, pszArgs);
2301}
2302
2303static DECLCALLBACK(int) codecR3Lookup(PHDACODEC pThis, PHDACODECR3 pThisCC, uint32_t cmd, uint64_t *puResp)
2304{
2305 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2306 AssertPtrReturn(puResp, VERR_INVALID_POINTER);
2307
2308 STAM_COUNTER_INC(&pThisCC->StatLookupsR3);
2309
2310 if (CODEC_CAD(cmd) != pThis->id)
2311 {
2312 *puResp = 0;
2313 AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
2314 return VERR_INVALID_PARAMETER;
2315 }
2316
2317 if ( CODEC_VERBDATA(cmd) == 0
2318 || CODEC_NID(cmd) >= pThis->cTotalNodes)
2319 {
2320 *puResp = 0;
2321 AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
2322 return VERR_INVALID_PARAMETER;
2323 }
2324
2325 /** @todo r=andy Implement a binary search here. */
2326 for (size_t i = 0; i < pThisCC->cVerbs; i++)
2327 {
2328 PCODECVERBR3 pVerb = &pThisCC->aVerbs[i];
2329
2330 if ((CODEC_VERBDATA(cmd) & pVerb->mask) == pThisCC->aVerbs[i].verb)
2331 {
2332 AssertPtrReturn(pVerb->pfn, VERR_NOT_IMPLEMENTED); /* Paranoia. */
2333
2334 int rc2 = pVerb->pfn(pThis, pThisCC, cmd, puResp);
2335 AssertRC(rc2);
2336 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
2337 CODEC_NID(cmd), pVerb->verb, pVerb->pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
2338 return rc2;
2339 }
2340 }
2341
2342 *puResp = 0;
2343 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
2344 return VERR_NOT_FOUND;
2345}
2346
2347#else /* IN_RING0 */
2348
2349static DECLCALLBACK(int) codecR0Lookup(PHDACODEC pThis, PHDACODECR0 pThisCC, uint32_t cmd, uint64_t *puResp)
2350{
2351 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2352 AssertPtrReturn(puResp, VERR_INVALID_POINTER);
2353
2354 STAM_COUNTER_INC(&pThisCC->StatLookupsR0);
2355
2356 if (CODEC_CAD(cmd) != pThis->id)
2357 {
2358 *puResp = 0;
2359 AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
2360 return VERR_INVALID_PARAMETER;
2361 }
2362
2363 if ( CODEC_VERBDATA(cmd) == 0
2364 || CODEC_NID(cmd) >= pThis->cTotalNodes)
2365 {
2366 *puResp = 0;
2367 AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
2368 return VERR_INVALID_PARAMETER;
2369 }
2370
2371 /** @todo r=andy Implement a binary search here. */
2372 for (size_t i = 0; i < pThisCC->cVerbs; i++)
2373 {
2374 PCODECVERBR0 pVerb = &pThisCC->aVerbs[i];
2375
2376 if ((CODEC_VERBDATA(cmd) & pVerb->mask) == pThisCC->aVerbs[i].verb)
2377 {
2378 AssertPtrReturn(pVerb->pfn, VERR_NOT_IMPLEMENTED); /* Paranoia. */
2379
2380 int rc2 = pVerb->pfn(pThis, cmd, puResp);
2381 AssertRC(rc2);
2382 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
2383 CODEC_NID(cmd), pVerb->verb, pVerb->pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
2384 return rc2;
2385 }
2386 }
2387
2388 *puResp = 0;
2389 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
2390 return VERR_NOT_FOUND;
2391}
2392
2393#endif /* IN_RING0 */
2394
2395/*
2396 * APIs exposed to DevHDA.
2397 */
2398
2399#ifdef IN_RING3
2400
2401int hdaR3CodecAddStream(PHDACODECR3 pThisCC, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
2402{
2403 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2404 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2405
2406 int rc = VINF_SUCCESS;
2407
2408 switch (enmMixerCtl)
2409 {
2410 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
2411 case PDMAUDIOMIXERCTL_FRONT:
2412#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2413 case PDMAUDIOMIXERCTL_CENTER_LFE:
2414 case PDMAUDIOMIXERCTL_REAR:
2415#endif
2416 break;
2417
2418 case PDMAUDIOMIXERCTL_LINE_IN:
2419#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2420 case PDMAUDIOMIXERCTL_MIC_IN:
2421#endif
2422 break;
2423
2424 default:
2425 AssertMsgFailed(("Mixer control %#x not implemented\n", enmMixerCtl));
2426 rc = VERR_NOT_IMPLEMENTED;
2427 break;
2428 }
2429
2430 if (RT_SUCCESS(rc))
2431 rc = pThisCC->pfnCbMixerAddStream(pThisCC->pDevIns, enmMixerCtl, pCfg);
2432
2433 LogFlowFuncLeaveRC(rc);
2434 return rc;
2435}
2436
2437int hdaR3CodecRemoveStream(PHDACODECR3 pThisCC, PDMAUDIOMIXERCTL enmMixerCtl)
2438{
2439 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2440
2441 int rc = pThisCC->pfnCbMixerRemoveStream(pThisCC->pDevIns, enmMixerCtl);
2442
2443 LogFlowFuncLeaveRC(rc);
2444 return rc;
2445}
2446
2447int hdaCodecSaveState(PPDMDEVINS pDevIns, PHDACODEC pThis, PSSMHANDLE pSSM)
2448{
2449 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
2450 AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
2451 VERR_INTERNAL_ERROR);
2452 pHlp->pfnSSMPutU32(pSSM, pThis->cTotalNodes);
2453 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
2454 pHlp->pfnSSMPutStructEx(pSSM, &pThis->aNodes[idxNode].SavedState, sizeof(pThis->aNodes[idxNode].SavedState),
2455 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
2456 return VINF_SUCCESS;
2457}
2458
2459int hdaR3CodecLoadState(PPDMDEVINS pDevIns, PHDACODEC pThis, PHDACODECR3 pThisCC, PSSMHANDLE pSSM, uint32_t uVersion)
2460{
2461 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
2462 PCSSMFIELD pFields = NULL;
2463 uint32_t fFlags = 0;
2464 if (uVersion >= HDA_SAVED_STATE_VERSION_4)
2465 {
2466 /* Since version 4 a flexible node count is supported. */
2467 uint32_t cNodes;
2468 int rc2 = pHlp->pfnSSMGetU32(pSSM, &cNodes);
2469 AssertRCReturn(rc2, rc2);
2470 AssertReturn(cNodes == 0x1c, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2471 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2472
2473 pFields = g_aCodecNodeFields;
2474 fFlags = 0;
2475 }
2476 else if (uVersion >= HDA_SAVED_STATE_VERSION_2)
2477 {
2478 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2479 pFields = g_aCodecNodeFields;
2480 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2481 }
2482 else if (uVersion >= HDA_SAVED_STATE_VERSION_1)
2483 {
2484 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2485 pFields = g_aCodecNodeFieldsV1;
2486 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2487 }
2488 else
2489 AssertFailedReturn(VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2490
2491 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
2492 {
2493 uint8_t idOld = pThis->aNodes[idxNode].SavedState.Core.uID;
2494 int rc = pHlp->pfnSSMGetStructEx(pSSM, &pThis->aNodes[idxNode].SavedState, sizeof(pThis->aNodes[idxNode].SavedState),
2495 fFlags, pFields, NULL);
2496 AssertRCReturn(rc, rc);
2497 AssertLogRelMsgReturn(idOld == pThis->aNodes[idxNode].SavedState.Core.uID,
2498 ("loaded %#x, expected %#x\n", pThis->aNodes[idxNode].SavedState.Core.uID, idOld),
2499 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2500 }
2501
2502 /*
2503 * Update stuff after changing the state.
2504 */
2505 PCODECNODE pNode;
2506 if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
2507 {
2508 pNode = &pThis->aNodes[pThis->u8DacLineOut];
2509 hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
2510 }
2511 else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
2512 {
2513 pNode = &pThis->aNodes[pThis->u8DacLineOut];
2514 hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
2515 }
2516
2517 pNode = &pThis->aNodes[pThis->u8AdcVolsLineIn];
2518 hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
2519
2520 LogFlowFuncLeaveRC(VINF_SUCCESS);
2521 return VINF_SUCCESS;
2522}
2523
2524/**
2525 * Powers off the codec (ring-3).
2526 *
2527 * @param pThisCC Context-specific codec data (ring-3) to power off.
2528 */
2529void hdaR3CodecPowerOff(PHDACODECR3 pThisCC)
2530{
2531 if (!pThisCC)
2532 return;
2533
2534 LogFlowFuncEnter();
2535
2536 LogRel2(("HDA: Powering off codec ...\n"));
2537
2538 int rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_FRONT);
2539 AssertRC(rc2);
2540#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
2541 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_CENTER_LFE);
2542 AssertRC(rc2);
2543 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_REAR);
2544 AssertRC(rc2);
2545#endif
2546
2547#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2548 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_MIC_IN);
2549 AssertRC(rc2);
2550#endif
2551 rc2 = hdaR3CodecRemoveStream(pThisCC, PDMAUDIOMIXERCTL_LINE_IN);
2552 AssertRC(rc2);
2553}
2554
2555/**
2556 * Constructs a codec (ring-3).
2557 *
2558 * @returns VBox status code.
2559 * @param pDevIns Associated device instance.
2560 * @param pThis Shared codec data beteen r0/r3.
2561 * @param pThisCC Context-specific codec data (ring-3).
2562 * @param uLUN Device LUN to assign.
2563 * @param pCfg CFGM node to use for configuration.
2564 */
2565int hdaR3CodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, PHDACODECR3 pThisCC,
2566 uint16_t uLUN, PCFGMNODE pCfg)
2567{
2568 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
2569 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2570 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2571 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2572
2573 pThis->id = uLUN;
2574 pThis->enmType = CODEC_TYPE_STAC9220; /** @todo Make this dynamic. */
2575
2576 int rc;
2577
2578 switch (pThis->enmType)
2579 {
2580 case CODEC_TYPE_STAC9220:
2581 {
2582 rc = stac9220Construct(pThis);
2583 AssertRCReturn(rc, rc);
2584 break;
2585 }
2586
2587 default:
2588 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
2589 break;
2590 }
2591
2592 memcpy(&pThisCC->aVerbs, &g_aCodecVerbsR3, sizeof(CODECVERBR3) * RT_ELEMENTS(g_aCodecVerbsR3));
2593 pThisCC->cVerbs = RT_ELEMENTS(g_aCodecVerbsR3);
2594
2595 pThisCC->pfnDbgSelector = codecR3DbgSelector;
2596 pThisCC->pfnDbgListNodes = codecR3DbgListNodes;
2597
2598 pThisCC->pfnLookup = codecR3Lookup;
2599
2600 /*
2601 * Set initial volume.
2602 */
2603 PCODECNODE pNode = &pThis->aNodes[pThis->u8DacLineOut];
2604 rc = hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
2605 AssertRCReturn(rc, rc);
2606
2607 pNode = &pThis->aNodes[pThis->u8AdcVolsLineIn];
2608 rc = hdaR3CodecToAudVolume(pThisCC, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
2609 AssertRCReturn(rc, rc);
2610
2611#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2612# error "Implement mic-in support!"
2613#endif
2614
2615 /*
2616 * Statistics
2617 */
2618#ifdef VBOX_WITH_STATISTICS
2619 PDMDevHlpSTAMRegister(pDevIns, &pThisCC->StatLookupsR3, STAMTYPE_COUNTER, "Codec/LookupsR3", STAMUNIT_OCCURENCES, "Number of R3 codecLookup calls");
2620#endif
2621
2622 return rc;
2623}
2624
2625#else /* IN_RING0 */
2626
2627/**
2628 * Constructs a codec (ring-0).
2629 *
2630 * @returns VBox status code.
2631 * @param pDevIns Associated device instance.
2632 * @param pThis Shared codec data beteen r0/r3.
2633 * @param pThisCC Context-specific codec data (ring-0).
2634 */
2635int hdaR0CodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, PHDACODECR0 pThisCC)
2636{
2637 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
2638 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2639 AssertPtrReturn(pThisCC, VERR_INVALID_POINTER);
2640
2641 memcpy(&pThisCC->aVerbs, &g_aCodecVerbsR0, sizeof(CODECVERBR0) * RT_ELEMENTS(g_aCodecVerbsR0));
2642 pThisCC->cVerbs = RT_ELEMENTS(g_aCodecVerbsR0);
2643
2644 pThisCC->pfnLookup = codecR0Lookup;
2645
2646 /* Note: Everything else is done in the R3 part. */
2647
2648 /*
2649 * Statistics
2650 */
2651#ifdef VBOX_WITH_STATISTICS
2652 /** @todo */
2653#endif
2654
2655 return VINF_SUCCESS;
2656}
2657
2658#endif /* IN_RING3 */
2659
2660/**
2661 * Destructs a codec.
2662 *
2663 * @param pThis Codec to destruct.
2664 */
2665void hdaCodecDestruct(PHDACODEC pThis)
2666{
2667 if (!pThis)
2668 return;
2669
2670 /* Nothing to do here atm. */
2671
2672 LogFlowFuncEnter();
2673}
2674
2675/**
2676 * Resets a codec.
2677 *
2678 * @param pThis Codec to reset.
2679 */
2680void hdaCodecReset(PHDACODEC pThis)
2681{
2682 switch (pThis->enmType)
2683 {
2684 case CODEC_TYPE_STAC9220:
2685 stac9220Reset(pThis);
2686 break;
2687
2688 default:
2689 AssertFailed();
2690 break;
2691 }
2692}
2693
Note: See TracBrowser for help on using the repository browser.

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