VirtualBox

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

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