VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 116.5 KB
RevLine 
[55364]1/* $Id: DevHdaCodec.cpp 98103 2023-01-17 14:15:46Z 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;
[90148]808 pCfg->idxAdcVolsLineIn = STAC9220_NID_AMP_ADC0;
809 pCfg->idxDacLineOut = STAC9220_NID_DAC1;
[60353]810
[90147]811 /* Copy over the node class lists and popuplate afNodeClassifications. */
[90141]812#define STAC9220WIDGET(a_Type) do { \
[90147]813 AssertCompile(RT_ELEMENTS(g_abStac9220##a_Type##s) <= RT_ELEMENTS(pCfg->ab##a_Type##s)); \
814 uint8_t *pbDst = (uint8_t *)&pCfg->ab##a_Type##s[0]; \
[90144]815 uintptr_t i; \
816 for (i = 0; i < RT_ELEMENTS(g_abStac9220##a_Type##s); i++) \
817 { \
818 uint8_t const idNode = g_abStac9220##a_Type##s[i]; \
[90147]819 if (idNode == 0) \
820 break; \
821 AssertReturn(idNode < RT_ELEMENTS(pThis->aNodes), VERR_INTERNAL_ERROR_3); \
822 pCfg->afNodeClassifications[idNode] |= RT_CONCAT(CODEC_NODE_CLS_,a_Type); \
[90144]823 pbDst[i] = idNode; \
824 } \
[90147]825 Assert(i + 1 == RT_ELEMENTS(g_abStac9220##a_Type##s)); \
826 for (; i < RT_ELEMENTS(pCfg->ab##a_Type##s); i++) \
[90144]827 pbDst[i] = 0; \
[90141]828 } while (0)
[44668]829 STAC9220WIDGET(Port);
830 STAC9220WIDGET(Dac);
831 STAC9220WIDGET(Adc);
832 STAC9220WIDGET(AdcVol);
833 STAC9220WIDGET(AdcMux);
834 STAC9220WIDGET(Pcbeep);
835 STAC9220WIDGET(SpdifIn);
836 STAC9220WIDGET(SpdifOut);
837 STAC9220WIDGET(DigInPin);
838 STAC9220WIDGET(DigOutPin);
839 STAC9220WIDGET(Cd);
840 STAC9220WIDGET(VolKnob);
841 STAC9220WIDGET(Reserved);
842#undef STAC9220WIDGET
843
[64403]844 /*
845 * Initialize all codec nodes.
846 * This is specific to the codec, so do this here.
847 *
848 * Note: Do *not* call stac9220Reset() here, as this would not
849 * initialize the node default configuration values then!
850 */
[88504]851 for (uint8_t i = 0; i < STAC9221_NUM_NODES; i++)
[90147]852 stac9220NodeReset(pThis, i, &pThis->aNodes[i], false /*fInReset*/);
[64403]853
[87799]854 /* Common root node initializers. */
[90147]855 pThis->aNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pCfg->idVendor, pCfg->idDevice);
[87799]856 pThis->aNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
857
858 /* Common AFG node initializers. */
[88504]859 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, STAC9221_NUM_NODES - 2);
[87799]860 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
861 pThis->aNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
[90147]862 pThis->aNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pCfg->idVendor, pCfg->bBSKU, pCfg->idAssembly);
[87799]863
[44668]864 return VINF_SUCCESS;
865}
866
867
[90119]868/*********************************************************************************************************************************
869* Common Helpers *
870*********************************************************************************************************************************/
871
[44668]872/*
[90142]873 * Some generic predicate functions.
[44668]874 */
[90119]875#define HDA_CODEC_IS_NODE_OF_TYPE_FUNC(a_Type) \
[90138]876 DECLINLINE(bool) hdaCodecIs##a_Type##Node(PHDACODECR3 pThis, uint8_t idNode) \
[90119]877 { \
[90147]878 Assert(idNode < RT_ELEMENTS(pThis->Cfg.afNodeClassifications)); \
879 Assert( (memchr(&pThis->Cfg.RT_CONCAT3(ab,a_Type,s)[0], idNode, sizeof(pThis->Cfg.RT_CONCAT3(ab,a_Type,s))) != NULL) \
880 == RT_BOOL(pThis->Cfg.afNodeClassifications[idNode] & RT_CONCAT(CODEC_NODE_CLS_,a_Type))); \
881 return RT_BOOL(pThis->Cfg.afNodeClassifications[idNode] & RT_CONCAT(CODEC_NODE_CLS_,a_Type)); \
[32803]882 }
[44667]883/* hdaCodecIsPortNode */
[90119]884HDA_CODEC_IS_NODE_OF_TYPE_FUNC(Port)
[44667]885/* hdaCodecIsDacNode */
[90119]886HDA_CODEC_IS_NODE_OF_TYPE_FUNC(Dac)
[44667]887/* hdaCodecIsAdcVolNode */
[90119]888HDA_CODEC_IS_NODE_OF_TYPE_FUNC(AdcVol)
[44667]889/* hdaCodecIsAdcNode */
[90119]890HDA_CODEC_IS_NODE_OF_TYPE_FUNC(Adc)
[44667]891/* hdaCodecIsAdcMuxNode */
[90119]892HDA_CODEC_IS_NODE_OF_TYPE_FUNC(AdcMux)
[44667]893/* hdaCodecIsPcbeepNode */
[90119]894HDA_CODEC_IS_NODE_OF_TYPE_FUNC(Pcbeep)
[44667]895/* hdaCodecIsSpdifOutNode */
[90119]896HDA_CODEC_IS_NODE_OF_TYPE_FUNC(SpdifOut)
[44667]897/* hdaCodecIsSpdifInNode */
[90119]898HDA_CODEC_IS_NODE_OF_TYPE_FUNC(SpdifIn)
[44667]899/* hdaCodecIsDigInPinNode */
[90119]900HDA_CODEC_IS_NODE_OF_TYPE_FUNC(DigInPin)
[44667]901/* hdaCodecIsDigOutPinNode */
[90119]902HDA_CODEC_IS_NODE_OF_TYPE_FUNC(DigOutPin)
[44667]903/* hdaCodecIsCdNode */
[90119]904HDA_CODEC_IS_NODE_OF_TYPE_FUNC(Cd)
[44667]905/* hdaCodecIsVolKnobNode */
[90119]906HDA_CODEC_IS_NODE_OF_TYPE_FUNC(VolKnob)
[44667]907/* hdaCodecIsReservedNode */
[90119]908HDA_CODEC_IS_NODE_OF_TYPE_FUNC(Reserved)
[32803]909
[31062]910
[44668]911/*
912 * Misc helpers.
913 */
[90138]914static int hdaR3CodecToAudVolume(PHDACODECR3 pThis, PCODECNODE pNode, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
[44668]915{
[65624]916 RT_NOREF(pNode);
917
[60353]918 uint8_t iDir;
919 switch (enmMixerCtl)
[44668]920 {
[61888]921 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
[60353]922 case PDMAUDIOMIXERCTL_FRONT:
923 iDir = AMPLIFIER_OUT;
[44668]924 break;
[53442]925 case PDMAUDIOMIXERCTL_LINE_IN:
[60353]926 case PDMAUDIOMIXERCTL_MIC_IN:
927 iDir = AMPLIFIER_IN;
[44668]928 break;
[53442]929 default:
[64991]930 AssertMsgFailedReturn(("Invalid mixer control %RU32\n", enmMixerCtl), VERR_INVALID_PARAMETER);
[53442]931 break;
[44668]932 }
[53442]933
[60353]934 int iMute;
935 iMute = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
936 iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
937 iMute >>=7;
938 iMute &= 0x1;
[53442]939
[89768]940 uint8_t bLeft = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & 0x7f;
941 uint8_t bRight = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
[60353]942
943 /*
944 * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
[55394]945 * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
946 * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
947 * to 1 (rather than zero) internally.
[55388]948 */
[89768]949 bLeft = (bLeft + 1) * (2 * 255) / 256;
950 bRight = (bRight + 1) * (2 * 255) / 256;
[55388]951
[89768]952 PDMAUDIOVOLUME Vol;
953 PDMAudioVolumeInitFromStereo(&Vol, RT_BOOL(iMute), bLeft, bRight);
[64991]954
[89768]955 LogFunc(("[NID0x%02x] %RU8/%RU8%s\n", pNode->node.uID, bLeft, bRight, Vol.fMuted ? "- Muted!" : ""));
956 LogRel2(("HDA: Setting volume for mixer control '%s' to %RU8/%RU8%s\n",
957 PDMAudioMixerCtlGetName(enmMixerCtl), bLeft, bRight, Vol.fMuted ? "- Muted!" : ""));
[65624]958
[90138]959 return hdaR3MixerSetVolume(pThis, enmMixerCtl, &Vol);
[44668]960}
961
[87799]962
[44667]963DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
[31459]964{
[44667]965 Assert((pu32Reg && u8Offset < 32));
966 *pu32Reg &= ~(mask << u8Offset);
967 *pu32Reg |= (u32Cmd & mask) << u8Offset;
[31459]968}
[44668]969
[44667]970DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
[31463]971{
[44667]972 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
[31463]973}
[31062]974
[44667]975DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
[31463]976{
[44667]977 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
[31463]978}
[31459]979
[31463]980
[90119]981/*********************************************************************************************************************************
982* Verb Processor Functions. *
983*********************************************************************************************************************************/
[63212]984#if 0 /* unused */
985
[90119]986/**
[90122]987 * @interface_method_impl{CODECVERB,pfn, Unimplemented}
[90119]988 */
[90138]989static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]990{
[90138]991 RT_NOREF(pThis, uCmd);
[90122]992 LogFlowFunc(("uCmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", uCmd,
993 CODEC_CAD(uCmd), CODEC_DIRECT(uCmd) ? 'N' : 'Y', CODEC_NID(uCmd), CODEC_VERBDATA(uCmd)));
994 *puResp = 0;
[30985]995 return VINF_SUCCESS;
996}
997
[90119]998
999/**
[90123]1000 * @interface_method_impl{CODECVERB,pfn, ??? }
[90119]1001 */
[90138]1002static DECLCALLBACK(int) vrbProcBreak(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1003{
1004 int rc;
[90138]1005 rc = vrbProcUnimplemented(pThis, uCmd, puResp);
[90122]1006 *puResp |= CODEC_RESPONSE_UNSOLICITED;
[30985]1007 return rc;
1008}
[44667]1009
[63212]1010#endif /* unused */
1011
[90119]1012/**
[90123]1013 * @interface_method_impl{CODECVERB,pfn, b-- }
[90119]1014 */
[90138]1015static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1016{
[90122]1017 *puResp = 0;
[59492]1018
[31459]1019 /* HDA spec 7.3.3.7 Note A */
[63562]1020 /** @todo If index out of range response should be 0. */
[90122]1021 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(uCmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(uCmd);
[31459]1022
[90122]1023 PCODECNODE pNode = &pThis->aNodes[CODEC_NID(uCmd)];
1024 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1025 *puResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
1026 CODEC_GET_AMP_DIRECTION(uCmd),
1027 CODEC_GET_AMP_SIDE(uCmd),
1028 u8Index);
1029 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(uCmd)))
1030 *puResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
1031 CODEC_GET_AMP_DIRECTION(uCmd),
1032 CODEC_GET_AMP_SIDE(uCmd),
1033 u8Index);
1034 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(uCmd)))
1035 *puResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
1036 CODEC_GET_AMP_DIRECTION(uCmd),
1037 CODEC_GET_AMP_SIDE(uCmd),
1038 u8Index);
1039 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(uCmd)))
1040 *puResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
1041 CODEC_GET_AMP_DIRECTION(uCmd),
1042 CODEC_GET_AMP_SIDE(uCmd),
1043 u8Index);
1044 else if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1045 *puResp = AMPLIFIER_REGISTER(pNode->port.B_params,
1046 CODEC_GET_AMP_DIRECTION(uCmd),
1047 CODEC_GET_AMP_SIDE(uCmd),
1048 u8Index);
1049 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1050 *puResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
1051 CODEC_GET_AMP_DIRECTION(uCmd),
1052 CODEC_GET_AMP_SIDE(uCmd),
1053 u8Index);
[44668]1054 else
[90122]1055 LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", uCmd, CODEC_NID(uCmd), CODEC_NID(uCmd)));
[59492]1056
[30985]1057 return VINF_SUCCESS;
1058}
[44667]1059
[90119]1060
1061/**
[90123]1062 * @interface_method_impl{CODECVERB,pfn, ??? }
[90119]1063 */
[90138]1064static DECLCALLBACK(int) vrbProcGetParameter(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1065{
[90122]1066 Assert((uCmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
1067 if ((uCmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
[31264]1068 {
[90122]1069 *puResp = 0;
[59492]1070
[90122]1071 LogFlowFunc(("invalid F00 parameter %d\n", (uCmd & CODEC_VERB_8BIT_DATA)));
[31264]1072 return VINF_SUCCESS;
1073 }
[59492]1074
[90122]1075 *puResp = pThis->aNodes[CODEC_NID(uCmd)].node.au32F00_param[uCmd & CODEC_VERB_8BIT_DATA];
[30985]1076 return VINF_SUCCESS;
1077}
[31190]1078
[90119]1079
1080/**
[90123]1081 * @interface_method_impl{CODECVERB,pfn, f01 }
[90119]1082 */
[90138]1083static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31190]1084{
[90122]1085 *puResp = 0;
[59492]1086
[90122]1087 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(uCmd)))
1088 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adcmux.u32F01_param;
1089 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1090 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digout.u32F01_param;
1091 else if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1092 *puResp = pThis->aNodes[CODEC_NID(uCmd)].port.u32F01_param;
1093 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1094 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adc.u32F01_param;
1095 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(uCmd)))
1096 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adcvol.u32F01_param;
[59492]1097 else
[90122]1098 LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1099
[31190]1100 return VINF_SUCCESS;
1101}
1102
[90119]1103
1104/**
[90123]1105 * @interface_method_impl{CODECVERB,pfn, 701 }
[90119]1106 */
[90138]1107static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31190]1108{
[90122]1109 *puResp = 0;
[59492]1110
1111 uint32_t *pu32Reg = NULL;
[90122]1112 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(uCmd)))
1113 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].adcmux.u32F01_param;
1114 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1115 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digout.u32F01_param;
1116 else if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1117 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].port.u32F01_param;
1118 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1119 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].adc.u32F01_param;
1120 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(uCmd)))
1121 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].adcvol.u32F01_param;
[44668]1122 else
[90122]1123 LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1124
1125 if (pu32Reg)
[90122]1126 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1127
[31190]1128 return VINF_SUCCESS;
1129}
1130
[90119]1131
1132/**
[90123]1133 * @interface_method_impl{CODECVERB,pfn, f07 }
[90119]1134 */
[90138]1135static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1136{
[90122]1137 *puResp = 0;
[59492]1138
[90122]1139 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1140 *puResp = pThis->aNodes[CODEC_NID(uCmd)].port.u32F07_param;
1141 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1142 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digout.u32F07_param;
1143 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1144 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F07_param;
1145 else if (hdaCodecIsCdNode(pThis, CODEC_NID(uCmd)))
1146 *puResp = pThis->aNodes[CODEC_NID(uCmd)].cdnode.u32F07_param;
1147 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(uCmd)))
1148 *puResp = pThis->aNodes[CODEC_NID(uCmd)].pcbeep.u32F07_param;
1149 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1150 *puResp = pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F07_param;
[30985]1151 else
[90122]1152 LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1153
[30985]1154 return VINF_SUCCESS;
1155}
1156
[90119]1157
1158/**
[90123]1159 * @interface_method_impl{CODECVERB,pfn, 707 }
[90119]1160 */
[90138]1161static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1162{
[90122]1163 *puResp = 0;
[59492]1164
1165 uint32_t *pu32Reg = NULL;
[90122]1166 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1167 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].port.u32F07_param;
1168 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1169 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F07_param;
1170 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1171 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digout.u32F07_param;
1172 else if (hdaCodecIsCdNode(pThis, CODEC_NID(uCmd)))
1173 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].cdnode.u32F07_param;
1174 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(uCmd)))
1175 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].pcbeep.u32F07_param;
1176 else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd))
1177 && CODEC_NID(uCmd) == 0x1b)
1178 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F07_param;
[44668]1179 else
[90122]1180 LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1181
1182 if (pu32Reg)
[90122]1183 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1184
[30985]1185 return VINF_SUCCESS;
1186}
[31156]1187
[90119]1188
1189/**
[90123]1190 * @interface_method_impl{CODECVERB,pfn, f08 }
[90119]1191 */
[90138]1192static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31156]1193{
[90122]1194 *puResp = 0;
[59492]1195
[90122]1196 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1197 *puResp = pThis->aNodes[CODEC_NID(uCmd)].port.u32F08_param;
1198 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1199 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F08_param;
1200 else if ((uCmd) == STAC9220_NID_AFG)
1201 *puResp = pThis->aNodes[CODEC_NID(uCmd)].afg.u32F08_param;
1202 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(uCmd)))
1203 *puResp = pThis->aNodes[CODEC_NID(uCmd)].volumeKnob.u32F08_param;
1204 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1205 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digout.u32F08_param;
1206 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1207 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F08_param;
[31156]1208 else
[90122]1209 LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1210
[31156]1211 return VINF_SUCCESS;
1212}
1213
[90119]1214
1215/**
[90123]1216 * @interface_method_impl{CODECVERB,pfn, 708 }
[90119]1217 */
[90138]1218static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31156]1219{
[90122]1220 *puResp = 0;
[59492]1221
1222 uint32_t *pu32Reg = NULL;
[90122]1223 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1224 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].port.u32F08_param;
1225 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1226 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F08_param;
1227 else if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
1228 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].afg.u32F08_param;
1229 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(uCmd)))
1230 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].volumeKnob.u32F08_param;
1231 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1232 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F08_param;
1233 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1234 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digout.u32F08_param;
[31156]1235 else
[90122]1236 LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1237
1238 if (pu32Reg)
[90122]1239 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1240
[31156]1241 return VINF_SUCCESS;
1242}
1243
[90119]1244
1245/**
[90123]1246 * @interface_method_impl{CODECVERB,pfn, f09 }
[90119]1247 */
[90138]1248static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31156]1249{
[90122]1250 *puResp = 0;
[59492]1251
[90122]1252 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1253 *puResp = pThis->aNodes[CODEC_NID(uCmd)].port.u32F09_param;
1254 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1255 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F09_param;
[31156]1256 else
[60925]1257 {
1258 AssertFailed();
[90122]1259 LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[60925]1260 }
[59492]1261
[31156]1262 return VINF_SUCCESS;
1263}
[31190]1264
[90119]1265
1266/**
[90123]1267 * @interface_method_impl{CODECVERB,pfn, 709 }
[90119]1268 */
[90138]1269static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31156]1270{
[90122]1271 *puResp = 0;
[59492]1272
1273 uint32_t *pu32Reg = NULL;
[90122]1274 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1275 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].port.u32F09_param;
1276 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1277 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F09_param;
[44668]1278 else
[90122]1279 LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1280
1281 if (pu32Reg)
[90122]1282 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1283
[31156]1284 return VINF_SUCCESS;
1285}
1286
[90119]1287
1288/**
[90123]1289 * @interface_method_impl{CODECVERB,pfn, ??? }
[90119]1290 */
[90138]1291static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1292{
[90122]1293 *puResp = 0;
[59492]1294
[90122]1295 Assert((uCmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
1296 if ((uCmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
[31264]1297 {
[90122]1298 LogFlowFunc(("access to invalid F02 index %d\n", (uCmd & CODEC_VERB_8BIT_DATA)));
[32933]1299 return VINF_SUCCESS;
[31264]1300 }
[90122]1301 *puResp = pThis->aNodes[CODEC_NID(uCmd)].node.au32F02_param[uCmd & CODEC_VERB_8BIT_DATA];
[30985]1302 return VINF_SUCCESS;
1303}
[44667]1304
[90119]1305
1306/**
[90123]1307 * @interface_method_impl{CODECVERB,pfn, f03 }
[90119]1308 */
[90138]1309static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31076]1310{
[90122]1311 *puResp = 0;
[59492]1312
[90122]1313 if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1314 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adc.u32F03_param;
[59492]1315
[31076]1316 return VINF_SUCCESS;
1317}
[31324]1318
[90119]1319
1320/**
[90123]1321 * @interface_method_impl{CODECVERB,pfn, 703 }
[90119]1322 */
[90138]1323static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31076]1324{
[90122]1325 *puResp = 0;
[59492]1326
[90122]1327 if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1328 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(uCmd)].adc.u32F03_param, uCmd, 0);
[31076]1329 return VINF_SUCCESS;
1330}
[31324]1331
[90119]1332
1333/**
[90123]1334 * @interface_method_impl{CODECVERB,pfn, f0d }
[90119]1335 */
[90138]1336static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31076]1337{
[90122]1338 *puResp = 0;
[59492]1339
[90122]1340 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1341 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F0d_param;
1342 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1343 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F0d_param;
[31076]1344 return VINF_SUCCESS;
1345}
[31324]1346
[90119]1347
[90138]1348static int codecSetDigitalConverter(PHDACODECR3 pThis, uint32_t uCmd, uint8_t u8Offset, uint64_t *puResp)
[31076]1349{
[90122]1350 *puResp = 0;
[59492]1351
[90122]1352 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1353 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F0d_param, uCmd, u8Offset);
1354 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1355 hdaCodecSetRegisterU8(&pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F0d_param, uCmd, u8Offset);
[31076]1356 return VINF_SUCCESS;
1357}
[31463]1358
[90119]1359
1360/**
[90123]1361 * @interface_method_impl{CODECVERB,pfn, 70d }
[90119]1362 */
[90138]1363static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31463]1364{
[90122]1365 return codecSetDigitalConverter(pThis, uCmd, 0, puResp);
[31463]1366}
1367
[90119]1368
1369/**
[90123]1370 * @interface_method_impl{CODECVERB,pfn, 70e }
[90119]1371 */
[90138]1372static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31076]1373{
[90122]1374 return codecSetDigitalConverter(pThis, uCmd, 8, puResp);
[31076]1375}
[31050]1376
[90119]1377
1378/**
[90123]1379 * @interface_method_impl{CODECVERB,pfn, f20 }
[90119]1380 */
[90138]1381static DECLCALLBACK(int) vrbProcGetSubId(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31050]1382{
[90147]1383 Assert(CODEC_CAD(uCmd) == pThis->Cfg.id);
1384 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->Cfg.cTotalNodes, RT_ELEMENTS(pThis->aNodes));
[90122]1385 Assert(CODEC_NID(uCmd) < cTotalNodes);
1386 if (CODEC_NID(uCmd) >= cTotalNodes)
[31264]1387 {
[90122]1388 LogFlowFunc(("invalid node address %d\n", CODEC_NID(uCmd)));
1389 *puResp = 0;
[31264]1390 return VINF_SUCCESS;
1391 }
[90122]1392 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
1393 *puResp = pThis->aNodes[CODEC_NID(uCmd)].afg.u32F20_param;
[44668]1394 else
[90122]1395 *puResp = 0;
[31050]1396 return VINF_SUCCESS;
1397}
1398
[90119]1399
[90138]1400static int codecSetSubIdX(PHDACODECR3 pThis, uint32_t uCmd, uint8_t u8Offset)
[33327]1401{
[90147]1402 Assert(CODEC_CAD(uCmd) == pThis->Cfg.id);
1403 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->Cfg.cTotalNodes, RT_ELEMENTS(pThis->aNodes));
[90122]1404 Assert(CODEC_NID(uCmd) < cTotalNodes);
1405 if (CODEC_NID(uCmd) >= cTotalNodes)
[33327]1406 {
[90122]1407 LogFlowFunc(("invalid node address %d\n", CODEC_NID(uCmd)));
[33327]1408 return VINF_SUCCESS;
1409 }
[44668]1410 uint32_t *pu32Reg;
[90122]1411 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
1412 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].afg.u32F20_param;
[44668]1413 else
1414 AssertFailedReturn(VINF_SUCCESS);
[90122]1415 hdaCodecSetRegisterU8(pu32Reg, uCmd, u8Offset);
[33327]1416 return VINF_SUCCESS;
1417}
[44667]1418
[90119]1419
1420/**
[90123]1421 * @interface_method_impl{CODECVERB,pfn, 720 }
[90119]1422 */
[90138]1423static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[33327]1424{
[90122]1425 *puResp = 0;
1426 return codecSetSubIdX(pThis, uCmd, 0);
[33327]1427}
1428
[90119]1429
1430/**
[90123]1431 * @interface_method_impl{CODECVERB,pfn, 721 }
[90119]1432 */
[90138]1433static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[33327]1434{
[90122]1435 *puResp = 0;
1436 return codecSetSubIdX(pThis, uCmd, 8);
[33327]1437}
[44667]1438
[90119]1439
1440/**
[90123]1441 * @interface_method_impl{CODECVERB,pfn, 722 }
[90119]1442 */
[90138]1443static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[33327]1444{
[90122]1445 *puResp = 0;
1446 return codecSetSubIdX(pThis, uCmd, 16);
[33327]1447}
[44667]1448
[90119]1449
1450/**
[90123]1451 * @interface_method_impl{CODECVERB,pfn, 723 }
[90119]1452 */
[90138]1453static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[33327]1454{
[90122]1455 *puResp = 0;
1456 return codecSetSubIdX(pThis, uCmd, 24);
[33327]1457}
1458
[90119]1459
1460/**
[90123]1461 * @interface_method_impl{CODECVERB,pfn, ??? }
[90119]1462 */
[90138]1463static DECLCALLBACK(int) vrbProcReset(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31062]1464{
[90147]1465 Assert(CODEC_CAD(uCmd) == pThis->Cfg.id);
[60925]1466
[90147]1467 if (pThis->Cfg.enmType == CODECTYPE_STAC9220)
[31062]1468 {
[90122]1469 Assert(CODEC_NID(uCmd) == STAC9220_NID_AFG);
[87799]1470
[90122]1471 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
[87799]1472 stac9220Reset(pThis);
[31062]1473 }
[87799]1474 else
1475 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
[60925]1476
[90122]1477 *puResp = 0;
[31062]1478 return VINF_SUCCESS;
1479}
1480
[90119]1481
1482/**
[90123]1483 * @interface_method_impl{CODECVERB,pfn, f05 }
[90119]1484 */
[90138]1485static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31050]1486{
[90122]1487 *puResp = 0;
[59492]1488
[90122]1489 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
1490 *puResp = pThis->aNodes[CODEC_NID(uCmd)].afg.u32F05_param;
1491 else if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1492 *puResp = pThis->aNodes[CODEC_NID(uCmd)].dac.u32F05_param;
1493 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1494 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adc.u32F05_param;
1495 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1496 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F05_param;
1497 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1498 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digout.u32F05_param;
1499 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1500 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F05_param;
1501 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1502 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F05_param;
1503 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1504 *puResp = pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F05_param;
[59492]1505 else
[90122]1506 LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1507
[60925]1508 LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
[90122]1509 CODEC_NID(uCmd), CODEC_F05_IS_RESET(*puResp), CODEC_F05_IS_STOPOK(*puResp), CODEC_F05_ACT(*puResp), CODEC_F05_SET(*puResp)));
[31050]1510 return VINF_SUCCESS;
1511}
[31156]1512
[60925]1513#if 1
[90119]1514
1515/**
[90123]1516 * @interface_method_impl{CODECVERB,pfn, 705 }
[90119]1517 */
[90138]1518static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31156]1519{
[90122]1520 *puResp = 0;
[59492]1521
1522 uint32_t *pu32Reg = NULL;
[90122]1523 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
1524 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].afg.u32F05_param;
1525 else if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1526 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].dac.u32F05_param;
1527 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1528 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F05_param;
1529 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1530 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digout.u32F05_param;
1531 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1532 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].adc.u32F05_param;
1533 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1534 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F05_param;
1535 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1536 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F05_param;
1537 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1538 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F05_param;
[44668]1539 else
[60925]1540 {
[90122]1541 LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[60925]1542 }
[34005]1543
[59492]1544 if (!pu32Reg)
1545 return VINF_SUCCESS;
1546
[90122]1547 uint8_t uPwrCmd = CODEC_F05_SET (uCmd);
[60353]1548 bool fReset = CODEC_F05_IS_RESET (*pu32Reg);
1549 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
[62991]1550#ifdef LOG_ENABLED
[60925]1551 bool fError = CODEC_F05_IS_ERROR (*pu32Reg);
[60353]1552 uint8_t uPwrAct = CODEC_F05_ACT (*pu32Reg);
1553 uint8_t uPwrSet = CODEC_F05_SET (*pu32Reg);
[60925]1554 LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
[90122]1555 CODEC_NID(uCmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
[60925]1556 LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
[87799]1557 CODEC_F05_ACT(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param),
1558 CODEC_F05_SET(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param)));
[62991]1559#endif
[60353]1560
[90122]1561 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
[60353]1562 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
1563
[87799]1564 const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->aNodes[STAC9220_NID_AFG].afg.u32F05_param);
[60925]1565 if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
1566 {
[60353]1567 /* Propagate to all other nodes under this AFG. */
[60925]1568 LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
[60353]1569
[90119]1570#define PROPAGATE_PWR_STATE(a_abList, a_Member) \
1571 do { \
1572 for (uintptr_t idxList = 0; idxList < RT_ELEMENTS(a_abList); idxList++) \
[60353]1573 { \
[90119]1574 uint8_t const idxNode = a_abList[idxList]; \
1575 if (idxNode) \
1576 { \
1577 pThis->aNodes[idxNode].a_Member.u32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
1578 LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", idxNode, \
1579 CODEC_F05_ACT(pThis->aNodes[idxNode].a_Member.u32F05_param), \
1580 CODEC_F05_SET(pThis->aNodes[idxNode].a_Member.u32F05_param))); \
1581 } \
1582 else \
1583 break; \
[60353]1584 } \
[90119]1585 } while (0)
[60353]1586
[90147]1587 PROPAGATE_PWR_STATE(pThis->Cfg.abDacs, dac);
1588 PROPAGATE_PWR_STATE(pThis->Cfg.abAdcs, adc);
1589 PROPAGATE_PWR_STATE(pThis->Cfg.abDigInPins, digin);
1590 PROPAGATE_PWR_STATE(pThis->Cfg.abDigOutPins, digout);
1591 PROPAGATE_PWR_STATE(pThis->Cfg.abSpdifIns, spdifin);
1592 PROPAGATE_PWR_STATE(pThis->Cfg.abSpdifOuts, spdifout);
1593 PROPAGATE_PWR_STATE(pThis->Cfg.abReserveds, reserved);
[60353]1594
1595#undef PROPAGATE_PWR_STATE
1596 }
1597 /*
[60925]1598 * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
[60353]1599 * as PS-Set of this node. PS-Act always is one level under PS-Set here.
1600 */
1601 else
1602 {
[60925]1603 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
1604 }
1605
1606 LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
[90122]1607 CODEC_NID(uCmd),
[60925]1608 CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
1609
1610 return VINF_SUCCESS;
1611}
[90119]1612
[60925]1613#else
[90119]1614
[60925]1615DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
1616{
1617 Assert(pu32F05_param);
1618 if (!pu32F05_param)
1619 return;
1620 bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
1621 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
1622 uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
1623 *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
1624}
1625
[90119]1626
1627/**
[90123]1628 * @interface_method_impl{CODECVERB,pfn, 705 }
[90119]1629 */
[90138]1630static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60925]1631{
[90147]1632 Assert(CODEC_CAD(uCmd) == pThis->Cfg.id);
1633 uint8_t const cTotalNodes = (uint8_t)RT_MIN(pThis->Cfg.cTotalNodes, RT_ELEMENTS(pThis->aNodes));
[90122]1634 Assert(CODEC_NID(uCmd) < cTotalNodes);
1635 if (CODEC_NID(uCmd) >= cTotalNodes)
[60925]1636 {
[90122]1637 *puResp = 0;
1638 LogFlowFunc(("invalid node address %d\n", CODEC_NID(uCmd)));
[60925]1639 return VINF_SUCCESS;
1640 }
[90122]1641 *puResp = 0;
[60925]1642 uint32_t *pu32Reg;
[90122]1643 if (CODEC_NID(uCmd) == 1 /* AFG */)
1644 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].afg.u32F05_param;
1645 else if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1646 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].dac.u32F05_param;
1647 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1648 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F05_param;
1649 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1650 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].adc.u32F05_param;
1651 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1652 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F05_param;
1653 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1654 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F05_param;
1655 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1656 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F05_param;
[60925]1657 else
1658 AssertFailedReturn(VINF_SUCCESS);
1659
1660 bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
1661 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
1662
[90122]1663 if (CODEC_NID(uCmd) != 1 /* AFG */)
[60925]1664 {
1665 /*
1666 * We shouldn't propogate actual power state, which actual for AFG
1667 */
[33803]1668 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
[87799]1669 CODEC_F05_ACT(pThis->aNodes[1].afg.u32F05_param),
[90122]1670 CODEC_F05_SET(uCmd));
[31984]1671 }
1672
[60925]1673 /* Propagate next power state only if AFG is on or verb modifies AFG power state */
[90122]1674 if ( CODEC_NID(uCmd) == 1 /* AFG */
[87799]1675 || !CODEC_F05_ACT(pThis->aNodes[1].afg.u32F05_param))
[60925]1676 {
[90122]1677 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(uCmd), CODEC_F05_SET(uCmd));
1678 if ( CODEC_NID(uCmd) == 1 /* AFG */
1679 && (CODEC_F05_SET(uCmd)) == CODEC_F05_D0)
[60925]1680 {
1681 /* now we're powered on AFG and may propogate power states on nodes */
[90141]1682 const uint8_t *pu8NodeIndex = &pThis->abDacs[0];
[60925]1683 while (*(++pu8NodeIndex))
[87799]1684 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].dac.u32F05_param);
[33803]1685
[90141]1686 pu8NodeIndex = &pThis->abAdcs[0];
[60925]1687 while (*(++pu8NodeIndex))
[87799]1688 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].adc.u32F05_param);
[33803]1689
[90141]1690 pu8NodeIndex = &pThis->abDigInPins[0];
[60925]1691 while (*(++pu8NodeIndex))
[87799]1692 codecPropogatePowerState(&pThis->aNodes[*pu8NodeIndex].digin.u32F05_param);
[60925]1693 }
1694 }
[31156]1695 return VINF_SUCCESS;
1696}
[90119]1697
[60925]1698#endif
[31156]1699
[90119]1700/**
[90123]1701 * @interface_method_impl{CODECVERB,pfn, f06 }
[90119]1702 */
[90138]1703static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1704{
[90122]1705 *puResp = 0;
[59492]1706
[90122]1707 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1708 *puResp = pThis->aNodes[CODEC_NID(uCmd)].dac.u32F06_param;
1709 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1710 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adc.u32F06_param;
1711 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1712 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F06_param;
1713 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1714 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F06_param;
1715 else if (CODEC_NID(uCmd) == STAC9221_NID_I2S_OUT)
1716 *puResp = pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F06_param;
[59492]1717 else
[90122]1718 LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1719
[60941]1720 LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
[90122]1721 CODEC_NID(uCmd), CODEC_F00_06_GET_STREAM_ID(uCmd), CODEC_F00_06_GET_CHANNEL_ID(uCmd)));
[60353]1722
[31075]1723 return VINF_SUCCESS;
1724}
[44667]1725
[90119]1726
1727/**
[90123]1728 * @interface_method_impl{CODECVERB,pfn, a0 }
[90119]1729 */
[90138]1730static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31075]1731{
[90122]1732 *puResp = 0;
[59492]1733
[90122]1734 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1735 *puResp = pThis->aNodes[CODEC_NID(uCmd)].dac.u32A_param;
1736 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1737 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adc.u32A_param;
1738 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1739 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32A_param;
1740 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1741 *puResp = pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32A_param;
1742 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1743 *puResp = pThis->aNodes[CODEC_NID(uCmd)].reserved.u32A_param;
[59492]1744 else
[90122]1745 LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1746
[31075]1747 return VINF_SUCCESS;
1748}
[31076]1749
[90119]1750
1751/**
[90123]1752 * @interface_method_impl{CODECVERB,pfn, ??? - Also see section 3.7.1. }
[90119]1753 */
[90138]1754static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[30985]1755{
[90122]1756 *puResp = 0;
[59492]1757
[90122]1758 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1759 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(uCmd)].dac.u32A_param, uCmd, 0);
1760 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
1761 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(uCmd)].adc.u32A_param, uCmd, 0);
1762 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
1763 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32A_param, uCmd, 0);
1764 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
1765 hdaCodecSetRegisterU16(&pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32A_param, uCmd, 0);
[59492]1766 else
[90122]1767 LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1768
[30985]1769 return VINF_SUCCESS;
1770}
[31188]1771
[90119]1772
1773/**
[90123]1774 * @interface_method_impl{CODECVERB,pfn, f0c }
[90119]1775 */
[90138]1776static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1777{
[90122]1778 *puResp = 0;
[59492]1779
[90122]1780 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(uCmd)))
1781 *puResp = pThis->aNodes[CODEC_NID(uCmd)].adcvol.u32F0c_param;
1782 else if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1783 *puResp = pThis->aNodes[CODEC_NID(uCmd)].dac.u32F0c_param;
1784 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1785 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F0c_param;
[59492]1786 else
[90122]1787 LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1788
[31188]1789 return VINF_SUCCESS;
1790}
1791
[90119]1792
1793/**
[90123]1794 * @interface_method_impl{CODECVERB,pfn, 70c }
[90119]1795 */
[90138]1796static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1797{
[90122]1798 *puResp = 0;
[59492]1799
1800 uint32_t *pu32Reg = NULL;
[90122]1801 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(uCmd)))
1802 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].adcvol.u32F0c_param;
1803 else if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
1804 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].dac.u32F0c_param;
1805 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1806 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F0c_param;
[44668]1807 else
[90122]1808 LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[44668]1809
[59492]1810 if (pu32Reg)
[90122]1811 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1812
[31188]1813 return VINF_SUCCESS;
1814}
1815
[90119]1816
1817/**
[90123]1818 * @interface_method_impl{CODECVERB,pfn, f0f }
[90119]1819 */
[90138]1820static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1821{
[90122]1822 *puResp = 0;
[59492]1823
[90122]1824 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(uCmd)))
1825 *puResp = pThis->aNodes[CODEC_NID(uCmd)].volumeKnob.u32F0f_param;
[59492]1826 else
[90122]1827 LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1828
[31188]1829 return VINF_SUCCESS;
1830}
1831
[90119]1832
1833/**
[90123]1834 * @interface_method_impl{CODECVERB,pfn, 70f }
[90119]1835 */
[90138]1836static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1837{
[90122]1838 *puResp = 0;
[59492]1839
[31188]1840 uint32_t *pu32Reg = NULL;
[90122]1841 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(uCmd)))
1842 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].volumeKnob.u32F0f_param;
[59492]1843 else
[90122]1844 LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1845
[31188]1846 if (pu32Reg)
[90122]1847 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1848
[31188]1849 return VINF_SUCCESS;
1850}
1851
[90119]1852
1853/**
[90123]1854 * @interface_method_impl{CODECVERB,pfn, f15 }
[90119]1855 */
[90138]1856static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60353]1857{
[90138]1858 RT_NOREF(pThis, uCmd);
[90122]1859 *puResp = 0;
[60353]1860 return VINF_SUCCESS;
1861}
1862
[90119]1863
1864/**
[90123]1865 * @interface_method_impl{CODECVERB,pfn, 715 }
[90119]1866 */
[90138]1867static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60353]1868{
[90138]1869 RT_NOREF(pThis, uCmd);
[90122]1870 *puResp = 0;
[60353]1871 return VINF_SUCCESS;
1872}
1873
[90119]1874
1875/**
[90123]1876 * @interface_method_impl{CODECVERB,pfn, f16 }
[90119]1877 */
[90138]1878static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60353]1879{
[90138]1880 RT_NOREF(pThis, uCmd);
[90122]1881 *puResp = 0;
[60353]1882 return VINF_SUCCESS;
1883}
1884
[90119]1885
1886/**
[90123]1887 * @interface_method_impl{CODECVERB,pfn, 716 }
[90119]1888 */
[90138]1889static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60353]1890{
[90138]1891 RT_NOREF(pThis, uCmd);
[90122]1892 *puResp = 0;
[60353]1893 return VINF_SUCCESS;
1894}
1895
[90119]1896
1897/**
[90123]1898 * @interface_method_impl{CODECVERB,pfn, f17 }
[90119]1899 */
[90138]1900static DECLCALLBACK(int) vrbProcGetGPIODirection(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[33327]1901{
[90122]1902 *puResp = 0;
[59492]1903
1904 /* Note: this is true for ALC885. */
[90122]1905 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
1906 *puResp = pThis->aNodes[1].afg.u32F17_param;
[59492]1907 else
[90122]1908 LogRel2(("HDA: Warning: Unhandled get GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1909
[33327]1910 return VINF_SUCCESS;
1911}
1912
[90119]1913
1914/**
[90123]1915 * @interface_method_impl{CODECVERB,pfn, 717 }
[90119]1916 */
[90138]1917static DECLCALLBACK(int) vrbProcSetGPIODirection(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[33327]1918{
[90122]1919 *puResp = 0;
[59492]1920
[33327]1921 uint32_t *pu32Reg = NULL;
[90122]1922 if (CODEC_NID(uCmd) == STAC9220_NID_AFG)
[87799]1923 pu32Reg = &pThis->aNodes[1].afg.u32F17_param;
[59492]1924 else
[90122]1925 LogRel2(("HDA: Warning: Unhandled set GPIO direction command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1926
[33327]1927 if (pu32Reg)
[90122]1928 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[59492]1929
[33327]1930 return VINF_SUCCESS;
1931}
1932
[90119]1933
1934/**
[90123]1935 * @interface_method_impl{CODECVERB,pfn, f1c }
[90119]1936 */
[90138]1937static DECLCALLBACK(int) vrbProcGetConfig(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1938{
[90122]1939 *puResp = 0;
[59492]1940
[90122]1941 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1942 *puResp = pThis->aNodes[CODEC_NID(uCmd)].port.u32F1c_param;
1943 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1944 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digout.u32F1c_param;
1945 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1946 *puResp = pThis->aNodes[CODEC_NID(uCmd)].digin.u32F1c_param;
1947 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(uCmd)))
1948 *puResp = pThis->aNodes[CODEC_NID(uCmd)].pcbeep.u32F1c_param;
1949 else if (hdaCodecIsCdNode(pThis, CODEC_NID(uCmd)))
1950 *puResp = pThis->aNodes[CODEC_NID(uCmd)].cdnode.u32F1c_param;
1951 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1952 *puResp = pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F1c_param;
[59492]1953 else
[90122]1954 LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[59492]1955
[31188]1956 return VINF_SUCCESS;
1957}
[44667]1958
[90138]1959static int codecSetConfigX(PHDACODECR3 pThis, uint32_t uCmd, uint8_t u8Offset)
[31188]1960{
1961 uint32_t *pu32Reg = NULL;
[90122]1962 if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
1963 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].port.u32F1c_param;
1964 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(uCmd)))
1965 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digin.u32F1c_param;
1966 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(uCmd)))
1967 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].digout.u32F1c_param;
1968 else if (hdaCodecIsCdNode(pThis, CODEC_NID(uCmd)))
1969 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].cdnode.u32F1c_param;
1970 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(uCmd)))
1971 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].pcbeep.u32F1c_param;
1972 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(uCmd)))
1973 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].reserved.u32F1c_param;
[59492]1974 else
[90122]1975 LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(uCmd), uCmd));
[59492]1976
[31188]1977 if (pu32Reg)
[90122]1978 hdaCodecSetRegisterU8(pu32Reg, uCmd, u8Offset);
[59492]1979
[31188]1980 return VINF_SUCCESS;
1981}
[44667]1982
[90119]1983
1984/**
[90123]1985 * @interface_method_impl{CODECVERB,pfn, 71c }
[90119]1986 */
[90138]1987static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1988{
[90122]1989 *puResp = 0;
1990 return codecSetConfigX(pThis, uCmd, 0);
[31188]1991}
[44667]1992
[90119]1993
1994/**
[90123]1995 * @interface_method_impl{CODECVERB,pfn, 71d }
[90119]1996 */
[90138]1997static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]1998{
[90122]1999 *puResp = 0;
2000 return codecSetConfigX(pThis, uCmd, 8);
[31188]2001}
[44667]2002
[90119]2003
2004/**
[90123]2005 * @interface_method_impl{CODECVERB,pfn, 71e }
[90119]2006 */
[90138]2007static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]2008{
[90122]2009 *puResp = 0;
2010 return codecSetConfigX(pThis, uCmd, 16);
[31188]2011}
[44667]2012
[90119]2013
2014/**
[90123]2015 * @interface_method_impl{CODECVERB,pfn, 71e }
[90119]2016 */
[90138]2017static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[31188]2018{
[90122]2019 *puResp = 0;
2020 return codecSetConfigX(pThis, uCmd, 24);
[31188]2021}
2022
[90119]2023
2024/**
[90123]2025 * @interface_method_impl{CODECVERB,pfn, f04 }
[90119]2026 */
[90138]2027static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60925]2028{
[90122]2029 *puResp = 0;
[30985]2030
[90122]2031 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
2032 *puResp = pThis->aNodes[CODEC_NID(uCmd)].dac.u32F04_param;
[60925]2033 else
[90122]2034 LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[60925]2035
2036 return VINF_SUCCESS;
2037}
2038
[90119]2039
2040/**
[90123]2041 * @interface_method_impl{CODECVERB,pfn, 704 }
[90119]2042 */
[90138]2043static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[60925]2044{
[90122]2045 *puResp = 0;
[60925]2046
2047 uint32_t *pu32Reg = NULL;
[90122]2048 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
2049 pu32Reg = &pThis->aNodes[CODEC_NID(uCmd)].dac.u32F04_param;
[60925]2050 else
[90122]2051 LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[60925]2052
2053 if (pu32Reg)
[90122]2054 hdaCodecSetRegisterU8(pu32Reg, uCmd, 0);
[60925]2055
2056 return VINF_SUCCESS;
2057}
2058
[87799]2059
[90119]2060/**
[90123]2061 * @interface_method_impl{CODECVERB,pfn, 3-- }
[90119]2062 */
[90138]2063static DECLCALLBACK(int) vrbProcR3SetAmplifier(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[87799]2064{
[90122]2065 *puResp = 0;
[87799]2066
[90122]2067 PCODECNODE pNode = &pThis->aNodes[CODEC_NID(uCmd)];
[87802]2068 AMPLIFIER *pAmplifier = NULL;
[90122]2069 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
[87802]2070 pAmplifier = &pNode->dac.B_params;
[90122]2071 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(uCmd)))
[87802]2072 pAmplifier = &pNode->adcvol.B_params;
[90122]2073 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(uCmd)))
[87802]2074 pAmplifier = &pNode->adcmux.B_params;
[90122]2075 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(uCmd)))
[87802]2076 pAmplifier = &pNode->pcbeep.B_params;
[90122]2077 else if (hdaCodecIsPortNode(pThis, CODEC_NID(uCmd)))
[87802]2078 pAmplifier = &pNode->port.B_params;
[90122]2079 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
[87802]2080 pAmplifier = &pNode->adc.B_params;
2081 else
2082 LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
[90122]2083 uCmd, CODEC_VERB_PAYLOAD16(uCmd), CODEC_NID(uCmd), CODEC_NID(uCmd)));
[87799]2084
[87802]2085 if (!pAmplifier)
2086 return VINF_SUCCESS;
2087
[90122]2088 bool fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(uCmd);
2089 bool fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(uCmd);
2090 bool fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(uCmd);
2091 bool fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(uCmd);
2092 uint8_t u8Index = CODEC_SET_AMP_INDEX(uCmd);
[87802]2093
2094 if ( (!fIsLeft && !fIsRight)
2095 || (!fIsOut && !fIsIn))
2096 return VINF_SUCCESS;
2097
2098 LogFunc(("[NID0x%02x] fIsOut=%RTbool, fIsIn=%RTbool, fIsLeft=%RTbool, fIsRight=%RTbool, Idx=%RU8\n",
[90122]2099 CODEC_NID(uCmd), fIsOut, fIsIn, fIsLeft, fIsRight, u8Index));
[87802]2100
2101 if (fIsIn)
2102 {
2103 if (fIsLeft)
[90122]2104 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), uCmd, 0);
[87802]2105 if (fIsRight)
[90122]2106 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), uCmd, 0);
[87802]2107
[91734]2108 /*
2109 * Check if the node ID is the one we use for controlling the line-in volume;
2110 * with STAC9220 this is connected to STAC9220_NID_AMP_ADC0 (ID 0x17).
2111 *
2112 * If we don't do this check here, some guests like newer Ubuntus mute mic-in
2113 * afterwards (connected to STAC9220_NID_AMP_ADC1 (ID 0x18)). This then would
2114 * also mute line-in, which breaks audio recording.
2115 *
2116 * See STAC9220 V1.0 01/08, p. 30 + oem2ticketref:53.
2117 */
2118 if (CODEC_NID(uCmd) == pThis->Cfg.idxAdcVolsLineIn)
[90138]2119 hdaR3CodecToAudVolume(pThis, pNode, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
[91734]2120
2121#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2122# error "Implement mic-in volume / mute setting."
2123 else if (CODEC_NID(uCmd) == pThis->Cfg.idxAdcVolsMicIn)
2124 hdaR3CodecToAudVolume(pThis, pNode, pAmplifier, PDMAUDIOMIXERCTL_MIC_IN);
2125#endif
2126
[87802]2127 }
2128 if (fIsOut)
2129 {
2130 if (fIsLeft)
[90122]2131 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), uCmd, 0);
[87802]2132 if (fIsRight)
[90122]2133 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), uCmd, 0);
[87802]2134
[90148]2135 if (CODEC_NID(uCmd) == pThis->Cfg.idxDacLineOut)
[90138]2136 hdaR3CodecToAudVolume(pThis, pNode, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
[87802]2137 }
2138
2139 return VINF_SUCCESS;
2140}
2141
[90119]2142
2143/**
[90123]2144 * @interface_method_impl{CODECVERB,pfn, 706 }
[90119]2145 */
[90138]2146static DECLCALLBACK(int) vrbProcR3SetStreamId(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[87802]2147{
[90122]2148 *puResp = 0;
[87802]2149
[90122]2150 uint8_t uSD = CODEC_F00_06_GET_STREAM_ID(uCmd);
2151 uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(uCmd);
[87802]2152
2153 LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8\n",
[90122]2154 CODEC_NID(uCmd), uSD, uChannel));
[87802]2155
2156 ASSERT_GUEST_LOGREL_MSG_RETURN(uSD < HDA_MAX_STREAMS,
2157 ("Setting stream ID #%RU8 is invalid\n", uSD), VERR_INVALID_PARAMETER);
2158
2159 PDMAUDIODIR enmDir;
[88502]2160 uint32_t *pu32Addr;
[90122]2161 if (hdaCodecIsDacNode(pThis, CODEC_NID(uCmd)))
[87802]2162 {
[90122]2163 pu32Addr = &pThis->aNodes[CODEC_NID(uCmd)].dac.u32F06_param;
[87802]2164 enmDir = PDMAUDIODIR_OUT;
2165 }
[90122]2166 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(uCmd)))
[87802]2167 {
[90122]2168 pu32Addr = &pThis->aNodes[CODEC_NID(uCmd)].adc.u32F06_param;
[87802]2169 enmDir = PDMAUDIODIR_IN;
2170 }
[90122]2171 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(uCmd)))
[87802]2172 {
[90122]2173 pu32Addr = &pThis->aNodes[CODEC_NID(uCmd)].spdifout.u32F06_param;
[87802]2174 enmDir = PDMAUDIODIR_OUT;
2175 }
[90122]2176 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(uCmd)))
[87802]2177 {
[90122]2178 pu32Addr = &pThis->aNodes[CODEC_NID(uCmd)].spdifin.u32F06_param;
[87802]2179 enmDir = PDMAUDIODIR_IN;
2180 }
2181 else
2182 {
2183 enmDir = PDMAUDIODIR_UNKNOWN;
[90122]2184 LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(uCmd), uCmd));
[88502]2185 return VINF_SUCCESS;
[87802]2186 }
2187
2188 /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
[90122]2189 pThis->aNodes[CODEC_NID(uCmd)].node.uSD = uSD;
2190 pThis->aNodes[CODEC_NID(uCmd)].node.uChannel = uChannel;
[88502]2191
2192 if (enmDir == PDMAUDIODIR_OUT)
[87802]2193 {
[88502]2194 /** @todo Check if non-interleaved streams need a different channel / SDn? */
[87802]2195
[88502]2196 /* Propagate to the controller. */
[90138]2197 hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
[88502]2198# ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
[90138]2199 hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
2200 hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
[88502]2201# endif
[87802]2202 }
[88502]2203 else if (enmDir == PDMAUDIODIR_IN)
2204 {
[90138]2205 hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
[88502]2206# ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
[90138]2207 hdaR3MixerControl(pThis, PDMAUDIOMIXERCTL_MIC_IN, uSD, uChannel);
[88502]2208# endif
2209 }
[87802]2210
[90122]2211 hdaCodecSetRegisterU8(pu32Addr, uCmd, 0);
[87802]2212
2213 return VINF_SUCCESS;
2214}
2215
2216
2217
[87799]2218/**
[88502]2219 * HDA codec verb descriptors.
2220 *
[88504]2221 * @note This must be ordered by uVerb so we can do a binary lookup.
[44667]2222 */
[88502]2223static const CODECVERB g_aCodecVerbs[] =
[30985]2224{
[88502]2225 /* Verb Verb mask Callback Name
2226 ---------- --------------------- ------------------------------------------------------------------- */
[88504]2227 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
[90131]2228 { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcR3SetAmplifier , "SetAmplifier " },
[88502]2229 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
[88504]2230 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
2231 { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " },
2232 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
[90131]2233 { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcR3SetStreamId , "SetStreamId " },
[88502]2234 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
2235 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
2236 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
[88504]2237 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
[88502]2238 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
2239 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
[88504]2240 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
2241 { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
2242 { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
2243 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIODirection , "SetGPIODirection " },
2244 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
2245 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
2246 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
2247 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
[88502]2248 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
2249 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
2250 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
2251 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
2252 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
[88504]2253 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
2254 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
2255 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
2256 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
2257 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
2258 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
2259 { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
[88502]2260 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
[88504]2261 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
2262 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
2263 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
2264 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
[88502]2265 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
[88504]2266 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
[88502]2267 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
2268 { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
2269 { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
2270 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIODirection , "GetGPIODirection " },
2271 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
[88504]2272 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
[60353]2273 /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
[30985]2274};
2275
[87801]2276
[90119]2277/**
[90122]2278 * Implements codec lookup and will call the handler on the verb it finds,
2279 * returning the handler response.
2280 *
2281 * @returns VBox status code (not strict).
[90119]2282 */
[90138]2283DECLHIDDEN(int) hdaR3CodecLookup(PHDACODECR3 pThis, uint32_t uCmd, uint64_t *puResp)
[90119]2284{
2285 /*
2286 * Clear the return value and assert some sanity.
2287 */
2288 AssertPtr(puResp);
2289 *puResp = 0;
[90138]2290 AssertPtr(pThis);
[90147]2291 AssertMsgReturn(CODEC_CAD(uCmd) == pThis->Cfg.id,
[90119]2292 ("Unknown codec address 0x%x\n", CODEC_CAD(uCmd)),
2293 VERR_INVALID_PARAMETER);
2294 uint32_t const uCmdData = CODEC_VERBDATA(uCmd);
2295 AssertMsgReturn( uCmdData != 0
[90147]2296 && CODEC_NID(uCmd) < RT_MIN(pThis->Cfg.cTotalNodes, RT_ELEMENTS(pThis->aNodes)),
[90119]2297 ("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(uCmd), uCmdData),
2298 VERR_INVALID_PARAMETER);
2299 STAM_COUNTER_INC(&pThis->CTX_SUFF(StatLookups));
2300
2301 /*
2302 * Do a binary lookup of the verb.
2303 * Note! if we want other verb tables, add a table selector before the loop.
2304 */
2305 size_t iFirst = 0;
2306 size_t iEnd = RT_ELEMENTS(g_aCodecVerbs);
2307 for (;;)
2308 {
2309 size_t const iCur = iFirst + (iEnd - iFirst) / 2;
2310 uint32_t const uVerb = g_aCodecVerbs[iCur].uVerb;
2311 if (uCmdData < uVerb)
2312 {
2313 if (iCur > iFirst)
2314 iEnd = iCur;
2315 else
2316 break;
2317 }
2318 else if ((uCmdData & g_aCodecVerbs[iCur].fMask) != uVerb)
2319 {
2320 if (iCur + 1 < iEnd)
2321 iFirst = iCur + 1;
2322 else
2323 break;
2324 }
2325 else
2326 {
2327 /*
2328 * Found it! Run the callback and return.
2329 */
2330 AssertPtrReturn(g_aCodecVerbs[iCur].pfn, VERR_INTERNAL_ERROR_5); /* Paranoia^2. */
2331
[90138]2332 int rc = g_aCodecVerbs[iCur].pfn(pThis, uCmd, puResp);
[90119]2333 AssertRC(rc);
2334 Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
2335 CODEC_NID(uCmd), g_aCodecVerbs[iCur].uVerb, g_aCodecVerbs[iCur].pszName, CODEC_VERB_PAYLOAD8(uCmd), *puResp));
2336 return rc;
2337 }
2338 }
2339
2340#ifdef VBOX_STRICT
2341 for (size_t i = 0; i < RT_ELEMENTS(g_aCodecVerbs); i++)
2342 {
2343 AssertMsg(i == 0 || g_aCodecVerbs[i - 1].uVerb < g_aCodecVerbs[i].uVerb,
2344 ("i=%#x uVerb[-1]=%#x uVerb=%#x - buggy table!\n", i, g_aCodecVerbs[i - 1].uVerb, g_aCodecVerbs[i].uVerb));
2345 AssertMsg((uCmdData & g_aCodecVerbs[i].fMask) != g_aCodecVerbs[i].uVerb,
2346 ("i=%#x uVerb=%#x uCmd=%#x - buggy binary search or table!\n", i, g_aCodecVerbs[i].uVerb, uCmd));
2347 }
2348#endif
2349 LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(uCmd), CODEC_VERBDATA(uCmd)));
2350 return VERR_NOT_FOUND;
2351}
2352
2353
2354/*********************************************************************************************************************************
2355* Debug *
2356*********************************************************************************************************************************/
[82421]2357/**
2358 * CODEC debug info item printing state.
2359 */
2360typedef struct CODECDEBUG
[56727]2361{
2362 /** DBGF info helpers. */
[90134]2363 PCDBGFINFOHLP pHlp;
[56727]2364 /** Current recursion level. */
[90134]2365 uint8_t uLevel;
[56727]2366 /** Pointer to codec state. */
[90141]2367 PHDACODECR3 pThis;
[82421]2368} CODECDEBUG;
2369/** Pointer to the debug info item printing state for the codec. */
2370typedef CODECDEBUG *PCODECDEBUG;
[56727]2371
[90131]2372#define CODECDBG_INDENT pInfo->uLevel++;
2373#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
[56727]2374
[90131]2375#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2376#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
[56727]2377
[90119]2378
[82421]2379/** Wrapper around DBGFINFOHLP::pfnPrintf that adds identation. */
2380static void codecDbgPrintf(PCODECDEBUG pInfo, const char *pszFormat, ...)
[56727]2381{
2382 va_list va;
2383 va_start(va, pszFormat);
[82421]2384 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%N", pInfo->uLevel * 4, "", pszFormat, &va);
[56727]2385 va_end(va);
2386}
2387
[90119]2388
[82421]2389/** Power state */
2390static void codecDbgPrintNodeRegF05(PCODECDEBUG pInfo, uint32_t u32Reg)
[56727]2391{
2392 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2393 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2394}
2395
[90119]2396
[82421]2397static void codecDbgPrintNodeRegA(PCODECDEBUG pInfo, uint32_t u32Reg)
[56727]2398{
2399 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2400}
2401
[90119]2402
[82421]2403static void codecDbgPrintNodeRegF00(PCODECDEBUG pInfo, uint32_t *paReg00)
[56727]2404{
2405 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2406
2407 CODECDBG_INDENT
[60925]2408 codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
[56727]2409 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2410 uint32_t uReg = paReg00[0xD];
2411 CODECDBG_INDENT
2412 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2413 CODEC_F00_0D_NUM_STEPS(uReg),
2414 CODEC_F00_0D_STEP_SIZE(uReg),
2415 CODEC_F00_0D_OFFSET(uReg),
2416 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2417
2418 uReg = paReg00[0x12];
2419 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2420 CODEC_F00_12_NUM_STEPS(uReg),
2421 CODEC_F00_12_STEP_SIZE(uReg),
2422 CODEC_F00_12_OFFSET(uReg),
[60925]2423 RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
[56727]2424 CODECDBG_UNINDENT
2425 CODECDBG_UNINDENT
2426}
2427
[90119]2428
[82421]2429static void codecDbgPrintNodeAmp(PCODECDEBUG pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
[56727]2430{
[90131]2431#define CODECDBG_AMP(reg, chan) \
[82421]2432 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2433 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2434 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2435 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2436 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg))
[56727]2437
2438 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2439 CODECDBG_AMP(regAmp, "Left");
2440 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2441 CODECDBG_AMP(regAmp, "Right");
2442
[90131]2443#undef CODECDBG_AMP
[56727]2444}
2445
[90119]2446
[90131]2447#if 0 /* unused */
[82421]2448static void codecDbgPrintNodeConnections(PCODECDEBUG pInfo, PCODECNODE pNode)
[56727]2449{
2450 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2451 {
2452 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2453 return;
2454 }
2455}
[90131]2456#endif
[56727]2457
[90119]2458
[82421]2459static void codecDbgPrintNode(PCODECDEBUG pInfo, PCODECNODE pNode, bool fRecursive)
[56727]2460{
[60941]2461 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
[56727]2462
[60941]2463 if (pNode->node.uID == STAC9220_NID_ROOT)
[56992]2464 CODECDBG_PRINT("ROOT\n");
[60941]2465 else if (pNode->node.uID == STAC9220_NID_AFG)
[56727]2466 {
[56992]2467 CODECDBG_PRINT("AFG\n");
[56727]2468 CODECDBG_INDENT
2469 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2470 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2471 CODECDBG_UNINDENT
2472 }
[60941]2473 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
[56992]2474 CODECDBG_PRINT("PORT\n");
[60941]2475 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
[56727]2476 {
[56992]2477 CODECDBG_PRINT("DAC\n");
[56727]2478 CODECDBG_INDENT
2479 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2480 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2481 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2482 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2483 CODECDBG_UNINDENT
2484 }
[60941]2485 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
[56727]2486 {
[56992]2487 CODECDBG_PRINT("ADC VOLUME\n");
[56727]2488 CODECDBG_INDENT
2489 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2490 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2491 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2492 CODECDBG_UNINDENT
2493 }
[60941]2494 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
[56727]2495 {
[56992]2496 CODECDBG_PRINT("ADC\n");
[56727]2497 CODECDBG_INDENT
2498 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2499 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2500 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2501 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2502 CODECDBG_UNINDENT
2503 }
[60941]2504 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
[56727]2505 {
[56992]2506 CODECDBG_PRINT("ADC MUX\n");
[56727]2507 CODECDBG_INDENT
2508 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2509 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2510 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2511 CODECDBG_UNINDENT
2512 }
[60941]2513 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
[56992]2514 CODECDBG_PRINT("PC BEEP\n");
[60941]2515 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
[56992]2516 CODECDBG_PRINT("SPDIF OUT\n");
[60941]2517 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
[56992]2518 CODECDBG_PRINT("SPDIF IN\n");
[60941]2519 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
[56992]2520 CODECDBG_PRINT("DIGITAL IN PIN\n");
[60941]2521 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
[56992]2522 CODECDBG_PRINT("DIGITAL OUT PIN\n");
[60941]2523 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
[56992]2524 CODECDBG_PRINT("CD\n");
[60941]2525 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
[56992]2526 CODECDBG_PRINT("VOLUME KNOB\n");
[60941]2527 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
[56992]2528 CODECDBG_PRINT("RESERVED\n");
[56727]2529 else
[60941]2530 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
[60925]2531
2532 if (fRecursive)
2533 {
[90131]2534#define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
[82421]2535 if (cCnt >= _aEntry) \
2536 { \
2537 const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
2538 if (pNode->node.uID == uID) \
2539 codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
2540 }
[60925]2541
2542 /* Slow recursion, but this is debug stuff anyway. */
[90147]2543 for (uint8_t i = 0; i < pInfo->pThis->Cfg.cTotalNodes; i++)
[60925]2544 {
[87799]2545 const PCODECNODE pSubNode = &pInfo->pThis->aNodes[i];
[60941]2546 if (pSubNode->node.uID == pNode->node.uID)
[60925]2547 continue;
2548
2549 const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
2550 if (cCnt == 0) /* No connections present? Skip. */
2551 continue;
2552
2553 CODECDBG_INDENT
2554 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
2555 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
2556 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
2557 CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
2558 CODECDBG_UNINDENT
2559 }
2560
[90131]2561#undef CODECDBG_PRINT_CONLIST_ENTRY
[60925]2562 }
[56727]2563}
2564
[90119]2565
[90135]2566/**
2567 * Worker for hdaR3DbgInfoCodecNodes implementing the 'hdcnodes' info item.
2568 */
[90138]2569DECLHIDDEN(void) hdaR3CodecDbgListNodes(PHDACODECR3 pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
[56727]2570{
[90138]2571 RT_NOREF(pszArgs);
[87799]2572
[60925]2573 pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
[56727]2574
[90119]2575 CODECDEBUG DbgInfo;
[90134]2576 DbgInfo.pHlp = pHlp;
[90138]2577 DbgInfo.pThis = pThis;
[90134]2578 DbgInfo.uLevel = 0;
[56727]2579
[90119]2580 PCODECDEBUG pInfo = &DbgInfo;
[56727]2581
2582 CODECDBG_INDENT
[90147]2583 for (uint8_t i = 0; i < pThis->Cfg.cTotalNodes; i++)
[56727]2584 {
[90138]2585 PCODECNODE pNode = &pThis->aNodes[i];
[60925]2586
2587 /* Start with all nodes which have connection entries set. */
2588 if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
[90119]2589 codecDbgPrintNode(&DbgInfo, pNode, true /* fRecursive */);
[56727]2590 }
2591 CODECDBG_UNINDENT
2592}
2593
[90119]2594
[90135]2595/**
2596 * Worker for hdaR3DbgInfoCodecSelector implementing the 'hdcselector' info item.
2597 */
[90138]2598DECLHIDDEN(void) hdaR3CodecDbgSelector(PHDACODECR3 pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
[56727]2599{
[90138]2600 RT_NOREF(pThis, pHlp, pszArgs);
[56727]2601}
2602
[88502]2603
[90131]2604#if 0 /* unused */
[90138]2605static DECLCALLBACK(void) stac9220DbgNodes(PHDACODECR3 pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
[30985]2606{
[90119]2607 RT_NOREF(pszArgs);
[90147]2608 uint8_t const cTotalNodes = RT_MIN(pThis->Cfg.cTotalNodes, RT_ELEMENTS(pThis->aNodes));
[90119]2609 for (uint8_t i = 1; i < cTotalNodes; i++)
[60925]2610 {
[90119]2611 PCODECNODE pNode = &pThis->aNodes[i];
2612 AMPLIFIER *pAmp = &pNode->dac.B_params;
[87799]2613
[90119]2614 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) & 0x7f;
2615 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) & 0x7f;
[44667]2616
[90119]2617 pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
[88504]2618 }
[30985]2619}
[90131]2620#endif
[31357]2621
[87800]2622
[90119]2623/*********************************************************************************************************************************
[90137]2624* Stream and State Management *
[90119]2625*********************************************************************************************************************************/
2626
[90138]2627int hdaR3CodecAddStream(PHDACODECR3 pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
[35515]2628{
[90138]2629 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
[60353]2630 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
[53442]2631
[60353]2632 int rc = VINF_SUCCESS;
2633
2634 switch (enmMixerCtl)
[35515]2635 {
[61888]2636 case PDMAUDIOMIXERCTL_VOLUME_MASTER:
[60925]2637 case PDMAUDIOMIXERCTL_FRONT:
[64333]2638#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
[60925]2639 case PDMAUDIOMIXERCTL_CENTER_LFE:
2640 case PDMAUDIOMIXERCTL_REAR:
2641#endif
2642 break;
[82450]2643
[60353]2644 case PDMAUDIOMIXERCTL_LINE_IN:
[64333]2645#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
[60353]2646 case PDMAUDIOMIXERCTL_MIC_IN:
[59275]2647#endif
[35515]2648 break;
[82450]2649
[35515]2650 default:
[87799]2651 AssertMsgFailed(("Mixer control %#x not implemented\n", enmMixerCtl));
[53442]2652 rc = VERR_NOT_IMPLEMENTED;
[60353]2653 break;
[35515]2654 }
[53442]2655
[60353]2656 if (RT_SUCCESS(rc))
[90138]2657 rc = hdaR3MixerAddStream(pThis, enmMixerCtl, pCfg);
[60353]2658
[53442]2659 LogFlowFuncLeaveRC(rc);
[35515]2660 return rc;
2661}
2662
[90119]2663
[90138]2664int hdaR3CodecRemoveStream(PHDACODECR3 pThis, PDMAUDIOMIXERCTL enmMixerCtl, bool fImmediate)
[60353]2665{
[90138]2666 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
[60925]2667
[90138]2668 int rc = hdaR3MixerRemoveStream(pThis, enmMixerCtl, fImmediate);
[60925]2669
2670 LogFlowFuncLeaveRC(rc);
2671 return rc;
[60353]2672}
2673
[90119]2674
[90134]2675/**
2676 * Saved the codec state.
2677 *
2678 * @returns VBox status code.
2679 * @param pDevIns The device instance of the HDA device.
[90138]2680 * @param pThis The codec instance data.
[90134]2681 * @param pSSM The saved state handle.
2682 */
[90138]2683int hdaCodecSaveState(PPDMDEVINS pDevIns, PHDACODECR3 pThis, PSSMHANDLE pSSM)
[30985]2684{
[90138]2685 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
[90147]2686 AssertLogRelMsgReturn(pThis->Cfg.cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->Cfg.cTotalNodes),
[44667]2687 VERR_INTERNAL_ERROR);
[90147]2688 pHlp->pfnSSMPutU32(pSSM, pThis->Cfg.cTotalNodes);
2689 for (unsigned idxNode = 0; idxNode < pThis->Cfg.cTotalNodes; ++idxNode)
[87799]2690 pHlp->pfnSSMPutStructEx(pSSM, &pThis->aNodes[idxNode].SavedState, sizeof(pThis->aNodes[idxNode].SavedState),
[82309]2691 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
[44667]2692 return VINF_SUCCESS;
2693}
2694
[90119]2695
[90134]2696/**
2697 * Loads the codec state.
2698 *
2699 * @returns VBox status code.
2700 * @param pDevIns The device instance of the HDA device.
[90138]2701 * @param pThis The codec instance data.
[90134]2702 * @param pSSM The saved state handle.
2703 * @param uVersion The state version.
2704 */
[90138]2705int hdaR3CodecLoadState(PPDMDEVINS pDevIns, PHDACODECR3 pThis, PSSMHANDLE pSSM, uint32_t uVersion)
[44667]2706{
[90134]2707 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
2708 PCSSMFIELD pFields = NULL;
2709 uint32_t fFlags = 0;
[82308]2710 if (uVersion >= HDA_SAVED_STATE_VERSION_4)
[44667]2711 {
[58900]2712 /* Since version 4 a flexible node count is supported. */
[82308]2713 uint32_t cNodes;
[82309]2714 int rc2 = pHlp->pfnSSMGetU32(pSSM, &cNodes);
[82308]2715 AssertRCReturn(rc2, rc2);
2716 AssertReturn(cNodes == 0x1c, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
[90147]2717 AssertReturn(pThis->Cfg.cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
[44667]2718
[82308]2719 pFields = g_aCodecNodeFields;
2720 fFlags = 0;
[44667]2721 }
[82308]2722 else if (uVersion >= HDA_SAVED_STATE_VERSION_2)
2723 {
[90147]2724 AssertReturn(pThis->Cfg.cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
[82308]2725 pFields = g_aCodecNodeFields;
2726 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2727 }
2728 else if (uVersion >= HDA_SAVED_STATE_VERSION_1)
2729 {
[90147]2730 AssertReturn(pThis->Cfg.cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
[82308]2731 pFields = g_aCodecNodeFieldsV1;
2732 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2733 }
2734 else
2735 AssertFailedReturn(VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
[44667]2736
[90147]2737 for (unsigned idxNode = 0; idxNode < pThis->Cfg.cTotalNodes; ++idxNode)
[44667]2738 {
[87799]2739 uint8_t idOld = pThis->aNodes[idxNode].SavedState.Core.uID;
2740 int rc = pHlp->pfnSSMGetStructEx(pSSM, &pThis->aNodes[idxNode].SavedState, sizeof(pThis->aNodes[idxNode].SavedState),
[82309]2741 fFlags, pFields, NULL);
[82252]2742 AssertRCReturn(rc, rc);
[87799]2743 AssertLogRelMsgReturn(idOld == pThis->aNodes[idxNode].SavedState.Core.uID,
2744 ("loaded %#x, expected %#x\n", pThis->aNodes[idxNode].SavedState.Core.uID, idOld),
[82252]2745 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2746 }
[65624]2747
[82252]2748 /*
2749 * Update stuff after changing the state.
2750 */
2751 PCODECNODE pNode;
[90148]2752 if (hdaCodecIsDacNode(pThis, pThis->Cfg.idxDacLineOut))
[82252]2753 {
[90148]2754 pNode = &pThis->aNodes[pThis->Cfg.idxDacLineOut];
[90138]2755 hdaR3CodecToAudVolume(pThis, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
[82252]2756 }
[90148]2757 else if (hdaCodecIsSpdifOutNode(pThis, pThis->Cfg.idxDacLineOut))
[82252]2758 {
[90148]2759 pNode = &pThis->aNodes[pThis->Cfg.idxDacLineOut];
[90138]2760 hdaR3CodecToAudVolume(pThis, pNode, &pNode->spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
[82252]2761 }
[65624]2762
[90148]2763 pNode = &pThis->aNodes[pThis->Cfg.idxAdcVolsLineIn];
[90138]2764 hdaR3CodecToAudVolume(pThis, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
[65624]2765
[82252]2766 LogFlowFuncLeaveRC(VINF_SUCCESS);
2767 return VINF_SUCCESS;
[44667]2768}
2769
[90119]2770
[60925]2771/**
[87799]2772 * Powers off the codec (ring-3).
[60925]2773 *
[90138]2774 * @param pThis The codec data.
[60925]2775 */
[90138]2776void hdaR3CodecPowerOff(PHDACODECR3 pThis)
[44667]2777{
[60925]2778 LogFlowFuncEnter();
2779 LogRel2(("HDA: Powering off codec ...\n"));
2780
[90138]2781 int rc2 = hdaR3CodecRemoveStream(pThis, PDMAUDIOMIXERCTL_FRONT, true /*fImmediate*/);
[60925]2782 AssertRC(rc2);
[64333]2783#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
[90138]2784 rc2 = hdaR3CodecRemoveStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, true /*fImmediate*/);
[60925]2785 AssertRC(rc2);
[90138]2786 rc2 = hdaR3CodecRemoveStream(pThis, PDMAUDIOMIXERCTL_REAR, true /*fImmediate*/);
[60925]2787 AssertRC(rc2);
2788#endif
2789
[64333]2790#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
[90138]2791 rc2 = hdaR3CodecRemoveStream(pThis, PDMAUDIOMIXERCTL_MIC_IN, true /*fImmediate*/);
[60925]2792 AssertRC(rc2);
2793#endif
[90138]2794 rc2 = hdaR3CodecRemoveStream(pThis, PDMAUDIOMIXERCTL_LINE_IN, true /*fImmediate*/);
[60925]2795 AssertRC(rc2);
2796}
2797
[90119]2798
[87799]2799/**
2800 * Constructs a codec (ring-3).
2801 *
2802 * @returns VBox status code.
[90134]2803 * @param pDevIns The associated device instance.
[90138]2804 * @param pThis The codec data.
[90134]2805 * @param uLUN Device LUN to assign.
2806 * @param pCfg CFGM node to use for configuration.
[87799]2807 */
[90138]2808int hdaR3CodecConstruct(PPDMDEVINS pDevIns, PHDACODECR3 pThis, uint16_t uLUN, PCFGMNODE pCfg)
[60925]2809{
[53442]2810 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
[90138]2811 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
[60353]2812 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
[90147]2813 HDACODECCFG *pCodecCfg = (HDACODECCFG *)&pThis->Cfg;
[44667]2814
[90147]2815 pCodecCfg->id = uLUN;
2816 pCodecCfg->enmType = CODECTYPE_STAC9220; /** @todo Make this dynamic. */
[59275]2817
[87799]2818 int rc;
[60353]2819
[90147]2820 switch (pCodecCfg->enmType)
[87799]2821 {
[90134]2822 case CODECTYPE_STAC9220:
[87799]2823 {
[90147]2824 rc = stac9220Construct(pThis, pCodecCfg);
[87799]2825 AssertRCReturn(rc, rc);
2826 break;
2827 }
[44667]2828
[87799]2829 default:
2830 AssertFailedReturn(VERR_NOT_IMPLEMENTED);
2831 break;
2832 }
[33716]2833
[60353]2834 /*
2835 * Set initial volume.
2836 */
[90148]2837 PCODECNODE pNode = &pThis->aNodes[pCodecCfg->idxDacLineOut];
[90138]2838 rc = hdaR3CodecToAudVolume(pThis, pNode, &pNode->dac.B_params, PDMAUDIOMIXERCTL_FRONT);
[87799]2839 AssertRCReturn(rc, rc);
[65624]2840
[90148]2841 pNode = &pThis->aNodes[pCodecCfg->idxAdcVolsLineIn];
[90138]2842 rc = hdaR3CodecToAudVolume(pThis, pNode, &pNode->adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
[87799]2843 AssertRCReturn(rc, rc);
2844
[90131]2845#ifdef VBOX_WITH_AUDIO_HDA_MIC_IN
2846# error "Implement mic-in support!"
2847#endif
[53567]2848
[82399]2849 /*
2850 * Statistics
2851 */
[88502]2852 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatLookupsR3, STAMTYPE_COUNTER, "Codec/LookupsR0", STAMUNIT_OCCURENCES, "Number of R0 codecLookup calls");
[90131]2853#if 0 /* Codec is not yet kosher enough for ring-0. @bugref{9890c64} */
[88502]2854 PDMDevHlpSTAMRegister(pDevIns, &pThis->StatLookupsR0, STAMTYPE_COUNTER, "Codec/LookupsR3", STAMUNIT_OCCURENCES, "Number of R3 codecLookup calls");
[90131]2855#endif
[82399]2856
[61001]2857 return rc;
[30985]2858}
[39368]2859
[87799]2860
2861/**
2862 * Destructs a codec.
2863 *
[90138]2864 * @param pThis Codec to destruct.
[87799]2865 */
[90138]2866void hdaCodecDestruct(PHDACODECR3 pThis)
[87799]2867{
[90134]2868 LogFlowFuncEnter();
[87799]2869
2870 /* Nothing to do here atm. */
[90138]2871 RT_NOREF(pThis);
[87799]2872}
2873
[90131]2874
[87799]2875/**
2876 * Resets a codec.
2877 *
[90138]2878 * @param pThis Codec to reset.
[87799]2879 */
[90138]2880void hdaCodecReset(PHDACODECR3 pThis)
[87799]2881{
[90147]2882 switch (pThis->Cfg.enmType)
[87799]2883 {
[90134]2884 case CODECTYPE_STAC9220:
[90138]2885 stac9220Reset(pThis);
[87799]2886 break;
2887
2888 default:
2889 AssertFailed();
2890 break;
2891 }
2892}
2893
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use