VirtualBox

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

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

DevHda: Consolidating codec state into one structure and removing the unnecessary R3 codec state allocating. bugref:9890

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