VirtualBox

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

Last change on this file was 104529, checked in by vboxsync, 4 months ago

Audio/HDA: Fixed recording on newer Windows versions (Windows 10): Those control the recording volume and muted state using a different codec node ID (see comments in patch) for the STAC9220 codec. When rebooting the guest, Windows mutes recording and re-enables it on a not-

yet-handled ADC (analog to digital converter). bugref:10682

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

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use