VirtualBox

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

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

Audio: File header adjustments. bugref:9890

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