VirtualBox

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

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

Audio: Moving some of the DrvAudio.h stuff into PDM - VBox/vmm/pdmaudioinline.h. bugref:9890

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

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