VirtualBox

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

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

DevHda: Only HDACODECR3, no HDACODEC structure any more. bugref:9890

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