VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevCodec.cpp@ 31817

Last change on this file since 31817 was 31771, checked in by vboxsync, 15 years ago

Audio/HDA: introduces saved states.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.8 KB
Line 
1/* $Id: DevCodec.cpp 31771 2010-08-19 09:15:42Z vboxsync $ */
2/** @file
3 * DevCodec - VBox ICH Intel HD Audio Codec.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#define LOG_GROUP LOG_GROUP_DEV_AUDIO
18#include <VBox/pdmdev.h>
19#include <iprt/assert.h>
20#include <iprt/uuid.h>
21#include <iprt/string.h>
22#include <iprt/mem.h>
23#include <iprt/asm.h>
24
25#include "../Builtins.h"
26extern "C" {
27#include "audio.h"
28}
29#include "DevCodec.h"
30
31#define CODEC_CAD_MASK 0xF0000000
32#define CODEC_CAD_SHIFT 28
33#define CODEC_DIRECT_MASK RT_BIT(27)
34#define CODEC_NID_MASK 0x07F00000
35#define CODEC_NID_SHIFT 20
36#define CODEC_VERBDATA_MASK 0x000FFFFF
37#define CODEC_VERB_4BIT_CMD 0x000FFFF0
38#define CODEC_VERB_4BIT_DATA 0x0000000F
39#define CODEC_VERB_8BIT_CMD 0x000FFF00
40#define CODEC_VERB_8BIT_DATA 0x000000FF
41#define CODEC_VERB_16BIT_CMD 0x000F0000
42#define CODEC_VERB_16BIT_DATA 0x0000FFFF
43
44#define CODEC_CAD(cmd) ((cmd) & CODEC_CAD_MASK)
45#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK)
46#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT)
47#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK)
48#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x))
49#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4))
50#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8))
51#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16))
52
53#define CODEC_VERB_GET_AMP_DIRECTION RT_BIT(15)
54#define CODEC_VERB_GET_AMP_SIDE RT_BIT(13)
55#define CODEC_VERB_GET_AMP_INDEX 0x7
56
57/* HDA spec 7.3.3.7 NoteA */
58#define CODEC_GET_AMP_DIRECTION(cmd) (((cmd) & CODEC_VERB_GET_AMP_DIRECTION) >> 15)
59#define CODEC_GET_AMP_SIDE(cmd) (((cmd) & CODEC_VERB_GET_AMP_SIDE) >> 13)
60#define CODEC_GET_AMP_INDEX(cmd) (CODEC_GET_AMP_DIRECTION(cmd) ? 0 : ((cmd) & CODEC_VERB_GET_AMP_INDEX))
61
62/* HDA spec 7.3.3.7 NoteC */
63#define CODEC_VERB_SET_AMP_OUT_DIRECTION RT_BIT(15)
64#define CODEC_VERB_SET_AMP_IN_DIRECTION RT_BIT(14)
65#define CODEC_VERB_SET_AMP_LEFT_SIDE RT_BIT(13)
66#define CODEC_VERB_SET_AMP_RIGHT_SIDE RT_BIT(12)
67#define CODEC_VERB_SET_AMP_INDEX (0x7 << 8)
68
69#define CODEC_SET_AMP_IS_OUT_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_OUT_DIRECTION) != 0)
70#define CODEC_SET_AMP_IS_IN_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_IN_DIRECTION) != 0)
71#define CODEC_SET_AMP_IS_LEFT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_LEFT_SIDE) != 0)
72#define CODEC_SET_AMP_IS_RIGHT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_RIGHT_SIDE) != 0)
73#define CODEC_SET_AMP_INDEX(cmd) (((cmd) & CODEC_VERB_SET_AMP_INDEX) >> 7)
74
75
76#define STAC9220_NODE_COUNT 0x1C
77
78#define STAC9220_IS_AFG_CMD(cmd) ( \
79 CODEC_NID(cmd) == 0x1)
80
81#define STAC9220_IS_PORT_CMD(cmd) ( \
82 CODEC_NID(cmd) == 0xA \
83 || CODEC_NID(cmd) == 0xB \
84 || CODEC_NID(cmd) == 0xC \
85 || CODEC_NID(cmd) == 0xD \
86 || CODEC_NID(cmd) == 0xE \
87 || CODEC_NID(cmd) == 0xF)
88
89#define STAC9220_IS_DAC_CMD(cmd) ( \
90 CODEC_NID(cmd) == 0x2 \
91 || CODEC_NID(cmd) == 0x3 \
92 || CODEC_NID(cmd) == 0x4 \
93 || CODEC_NID(cmd) == 0x5)
94
95#define STAC9220_IS_ADCVOL_CMD(cmd) ( \
96 CODEC_NID(cmd) == 0x17 \
97 || CODEC_NID(cmd) == 0x18)
98
99#define STAC9220_IS_ADC_CMD(cmd) ( \
100 CODEC_NID(cmd) == 0x6 \
101 || CODEC_NID(cmd) == 0x7)
102
103#define STAC9220_IS_ADCMUX_CMD(cmd) ( \
104 CODEC_NID(cmd) == 0x12 \
105 || CODEC_NID(cmd) == 0x13)
106
107#define STAC9220_IS_PCBEEP_CMD(cmd) (CODEC_NID((cmd)) == 0x14)
108#define STAC9220_IS_SPDIFOUT_CMD(cmd) (CODEC_NID((cmd)) == 0x8)
109#define STAC9220_IS_SPDIFIN_CMD(cmd) (CODEC_NID((cmd)) == 0x9)
110
111#define STAC9220_IS_DIGINPIN_CMD(cmd) (CODEC_NID((cmd)) == 0x11)
112#define STAC9220_IS_DIGOUTPIN_CMD(cmd) (CODEC_NID((cmd)) == 0x10)
113
114#define STAC9220_IS_CD_CMD(cmd) (CODEC_NID((cmd)) == 0x15)
115
116#define STAC9220_IS_VOLKNOB_CMD(cmd) (CODEC_NID((cmd)) == 0x16)
117
118/* STAC9220 6.2 & 6.12 */
119#define STAC9220_IS_RESERVED_CMD(cmd) ( \
120 CODEC_NID((cmd)) == 0x19 \
121 || CODEC_NID((cmd)) == 0x1A \
122 || CODEC_NID((cmd)) == 0x1B)
123
124static int stac9220ResetNode(struct CODECState *pState, uint8_t nodenum, PCODECNODE pNode);
125static int codecToAudVolume(AMPLIFIER *pAmp, audmixerctl_t mt);
126
127static inline void codecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
128{
129 Assert((pu32Reg && u8Offset < 32));
130 *pu32Reg &= ~(mask << u8Offset);
131 *pu32Reg |= (u32Cmd & mask) << u8Offset;
132}
133static inline void codecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
134{
135 codecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
136}
137
138static inline void codecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
139{
140 codecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
141}
142
143
144static int codecUnimplemented(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
145{
146 Log(("codecUnimplemented: cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
147 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
148 *pResp = 0;
149 return VINF_SUCCESS;
150}
151
152static int codecBreak(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
153{
154 int rc;
155 rc = codecUnimplemented(pState, cmd, pResp);
156 *pResp |= CODEC_RESPONSE_UNSOLICITED;
157 return rc;
158}
159/* B-- */
160static int codecGetAmplifier(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
161{
162 Assert((CODEC_CAD(cmd) == pState->id));
163 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
164 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
165 {
166 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
167 return VINF_SUCCESS;
168 }
169 *pResp = 0;
170 /* HDA spec 7.3.3.7 Note A */
171 /* @todo: if index out of range response should be 0 */
172 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd);
173
174 PCODECNODE pNode = &pState->pNodes[CODEC_NID(cmd)];
175 if (STAC9220_IS_DAC_CMD(cmd))
176 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
177 CODEC_GET_AMP_DIRECTION(cmd),
178 CODEC_GET_AMP_SIDE(cmd),
179 u8Index);
180 else if (STAC9220_IS_ADCVOL_CMD(cmd))
181 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
182 CODEC_GET_AMP_DIRECTION(cmd),
183 CODEC_GET_AMP_SIDE(cmd),
184 u8Index);
185 else if (STAC9220_IS_ADCMUX_CMD(cmd))
186 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
187 CODEC_GET_AMP_DIRECTION(cmd),
188 CODEC_GET_AMP_SIDE(cmd),
189 u8Index);
190 else if (STAC9220_IS_PCBEEP_CMD(cmd))
191 *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
192 CODEC_GET_AMP_DIRECTION(cmd),
193 CODEC_GET_AMP_SIDE(cmd),
194 u8Index);
195 else{
196 AssertMsgReturn(0, ("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS);
197 }
198 return VINF_SUCCESS;
199}
200/* 3-- */
201static int codecSetAmplifier(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
202{
203 AMPLIFIER *pAmplifier = NULL;
204 bool fIsLeft = false;
205 bool fIsRight = false;
206 bool fIsOut = false;
207 bool fIsIn = false;
208 uint8_t u8Index = 0;
209 Assert((CODEC_CAD(cmd) == pState->id));
210 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
211 {
212 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
213 return VINF_SUCCESS;
214 }
215 *pResp = 0;
216 PCODECNODE pNode = &pState->pNodes[CODEC_NID(cmd)];
217 if (STAC9220_IS_DAC_CMD(cmd))
218 pAmplifier = &pNode->dac.B_params;
219 else if (STAC9220_IS_ADCVOL_CMD(cmd))
220 pAmplifier = &pNode->adcvol.B_params;
221 else if (STAC9220_IS_ADCMUX_CMD(cmd))
222 pAmplifier = &pNode->adcmux.B_params;
223 else if (STAC9220_IS_PCBEEP_CMD(cmd))
224 pAmplifier = &pNode->pcbeep.B_params;
225 Assert(pAmplifier);
226 if (pAmplifier)
227 {
228 fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
229 fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
230 fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
231 fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
232 u8Index = CODEC_SET_AMP_INDEX(cmd);
233 if ( (!fIsLeft && !fIsRight)
234 || (!fIsOut && !fIsIn))
235 return VINF_SUCCESS;
236 if (fIsIn)
237 {
238 if (fIsLeft)
239 codecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
240 if (fIsRight)
241 codecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
242 }
243 if (fIsOut)
244 {
245 if (fIsLeft)
246 codecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
247 if (fIsRight)
248 codecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
249 }
250 if (CODEC_NID(cmd) == 2)
251 codecToAudVolume(pAmplifier, AUD_MIXER_VOLUME);
252 if (CODEC_NID(cmd) == 0x17) /* Microphone */
253 codecToAudVolume(pAmplifier, AUD_MIXER_PCM);
254 }
255 return VINF_SUCCESS;
256}
257
258static int codecGetParameter(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
259{
260 Assert((CODEC_CAD(cmd) == pState->id));
261 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
262 {
263 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
264 return VINF_SUCCESS;
265 }
266 Assert(((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F0_PARAM_LENGTH));
267 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F0_PARAM_LENGTH)
268 {
269 Log(("HDAcodec: invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
270 return VINF_SUCCESS;
271 }
272 *pResp = 0;
273 *pResp = pState->pNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
274 return VINF_SUCCESS;
275}
276
277/* F01 */
278static int codecGetConSelectCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
279{
280 Assert((CODEC_CAD(cmd) == pState->id));
281 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
282 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
283 {
284 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
285 return VINF_SUCCESS;
286 }
287 *pResp = 0;
288 if (STAC9220_IS_ADCMUX_CMD(cmd))
289 *pResp = pState->pNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
290 else if (STAC9220_IS_DIGOUTPIN_CMD(cmd))
291 *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F01_param;
292 return VINF_SUCCESS;
293}
294
295/* 701 */
296static int codecSetConSelectCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
297{
298 uint32_t *pu32Reg = NULL;
299 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
300 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
301 {
302 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
303 return VINF_SUCCESS;
304 }
305 *pResp = 0;
306 if (STAC9220_IS_ADCMUX_CMD(cmd))
307 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
308 else if (STAC9220_IS_DIGOUTPIN_CMD(cmd))
309 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F01_param;
310 Assert((pu32Reg));
311 if (pu32Reg)
312 codecSetRegisterU8(pu32Reg, cmd, 0);
313 return VINF_SUCCESS;
314}
315
316/* F07 */
317static int codecGetPinCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
318{
319 Assert((CODEC_CAD(cmd) == pState->id));
320 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
321 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
322 {
323 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
324 return VINF_SUCCESS;
325 }
326 *pResp = 0;
327 if (STAC9220_IS_PORT_CMD(cmd))
328 *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F07_param;
329 else if (STAC9220_IS_DIGOUTPIN_CMD(cmd))
330 *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F07_param;
331 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
332 *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F07_param;
333 else if (STAC9220_IS_CD_CMD(cmd))
334 *pResp = pState->pNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
335 else
336 AssertMsgFailed(("Unsupported"));
337 return VINF_SUCCESS;
338}
339
340/* 707 */
341static int codecSetPinCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
342{
343 Assert((CODEC_CAD(cmd) == pState->id));
344 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
345 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
346 {
347 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
348 return VINF_SUCCESS;
349 }
350 *pResp = 0;
351 uint32_t *pu32Reg = NULL;
352 if (STAC9220_IS_PORT_CMD(cmd))
353 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F07_param;
354 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
355 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F07_param;
356 else if (STAC9220_IS_DIGOUTPIN_CMD(cmd))
357 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F07_param;
358 else if (STAC9220_IS_CD_CMD(cmd))
359 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
360 Assert((pu32Reg));
361 if (pu32Reg)
362 codecSetRegisterU8(pu32Reg, cmd, 0);
363 return VINF_SUCCESS;
364}
365
366/* F08 */
367static int codecGetUnsolicitedEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
368{
369 Assert((CODEC_CAD(cmd) == pState->id));
370 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
371 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
372 {
373 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
374 return VINF_SUCCESS;
375 }
376 *pResp = 0;
377 if (STAC9220_IS_PORT_CMD(cmd))
378 *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F08_param;
379 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
380 *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param;
381 else if (STAC9220_IS_AFG_CMD(cmd))
382 *pResp = pState->pNodes[CODEC_NID(cmd)].afg.u32F08_param;
383 else if (STAC9220_IS_VOLKNOB_CMD(cmd))
384 *pResp = pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
385 else
386 AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
387 return VINF_SUCCESS;
388}
389
390/* 708 */
391static int codecSetUnsolicitedEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
392{
393 Assert((CODEC_CAD(cmd) == pState->id));
394 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
395 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
396 {
397 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
398 return VINF_SUCCESS;
399 }
400 *pResp = 0;
401 uint32_t *pu32Reg = NULL;
402 if (STAC9220_IS_PORT_CMD(cmd))
403 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F08_param;
404 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
405 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param;
406 else if (STAC9220_IS_AFG_CMD(cmd))
407 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].afg.u32F08_param;
408 else if (STAC9220_IS_VOLKNOB_CMD(cmd))
409 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
410 else
411 AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
412 Assert(pu32Reg);
413 if(pu32Reg)
414 codecSetRegisterU8(pu32Reg, cmd, 0);
415 return VINF_SUCCESS;
416}
417
418/* F09 */
419static int codecGetPinSense(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
420{
421 Assert((CODEC_CAD(cmd) == pState->id));
422 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
423 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
424 {
425 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
426 return VINF_SUCCESS;
427 }
428 *pResp = 0;
429 if (STAC9220_IS_PORT_CMD(cmd))
430 *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F09_param;
431 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
432 *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F09_param;
433 else
434 AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
435 return VINF_SUCCESS;
436}
437
438/* 709 */
439static int codecSetPinSense(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
440{
441 Assert((CODEC_CAD(cmd) == pState->id));
442 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
443 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
444 {
445 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
446 return VINF_SUCCESS;
447 }
448 *pResp = 0;
449 uint32_t *pu32Reg = NULL;
450 if (STAC9220_IS_PORT_CMD(cmd))
451 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F08_param;
452 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
453 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param;
454 Assert(pu32Reg);
455 if(pu32Reg)
456 codecSetRegisterU8(pu32Reg, cmd, 0);
457 return VINF_SUCCESS;
458}
459
460static int codecGetConnectionListEntry(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
461{
462 Assert((CODEC_CAD(cmd) == pState->id));
463 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
464 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
465 {
466 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
467 return VINF_SUCCESS;
468 }
469 Assert((cmd & CODEC_VERB_8BIT_DATA) < 16);
470 if ((cmd & CODEC_VERB_8BIT_DATA) >= 16)
471 {
472 Log(("HDAcodec: access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
473 }
474 *pResp = *(uint32_t *)&pState->pNodes[CODEC_NID(cmd)].node.au8F02_param[cmd & CODEC_VERB_8BIT_DATA];
475 return VINF_SUCCESS;
476}
477/* F03 */
478static int codecGetProcessingState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
479{
480 Assert((CODEC_CAD(cmd) == pState->id));
481 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
482 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
483 {
484 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
485 return VINF_SUCCESS;
486 }
487 *pResp = 0;
488 if (STAC9220_IS_ADC_CMD(cmd))
489 *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F03_param;
490 return VINF_SUCCESS;
491}
492
493/* 703 */
494static int codecSetProcessingState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
495{
496 Assert((CODEC_CAD(cmd) == pState->id));
497 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
498 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
499 {
500 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
501 return VINF_SUCCESS;
502 }
503 *pResp = 0;
504 if (STAC9220_IS_ADC_CMD(cmd))
505 {
506 codecSetRegisterU8(&pState->pNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
507 }
508 return VINF_SUCCESS;
509}
510
511/* F0D */
512static int codecGetDigitalConverter(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
513{
514 Assert((CODEC_CAD(cmd) == pState->id));
515 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
516 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
517 {
518 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
519 return VINF_SUCCESS;
520 }
521 *pResp = 0;
522 if (STAC9220_IS_SPDIFOUT_CMD(cmd))
523 *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
524 else if (STAC9220_IS_SPDIFIN_CMD(cmd))
525 *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
526 return VINF_SUCCESS;
527}
528
529static int codecSetDigitalConverter(struct CODECState *pState, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
530{
531 Assert((CODEC_CAD(cmd) == pState->id));
532 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
533 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
534 {
535 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
536 return VINF_SUCCESS;
537 }
538 *pResp = 0;
539 if (STAC9220_IS_SPDIFOUT_CMD(cmd))
540 codecSetRegisterU8(&pState->pNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
541 else if (STAC9220_IS_SPDIFIN_CMD(cmd))
542 codecSetRegisterU8(&pState->pNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
543 return VINF_SUCCESS;
544}
545
546/* 70D */
547static int codecSetDigitalConverter1(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
548{
549 return codecSetDigitalConverter(pState, cmd, 0, pResp);
550}
551
552/* 70E */
553static int codecSetDigitalConverter2(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
554{
555 return codecSetDigitalConverter(pState, cmd, 8, pResp);
556}
557
558static int codecGetSubId(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
559{
560 Assert((CODEC_CAD(cmd) == pState->id));
561 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
562 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
563 {
564 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
565 return VINF_SUCCESS;
566 }
567 *pResp = 0;
568 if (STAC9220_IS_AFG_CMD(cmd))
569 {
570 *pResp = pState->pNodes[CODEC_NID(cmd)].afg.u32F20_param;
571 }
572 return VINF_SUCCESS;
573}
574
575static int codecReset(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
576{
577 Assert((CODEC_CAD(cmd) == pState->id));
578 Assert(STAC9220_IS_AFG_CMD(cmd));
579 if(STAC9220_IS_AFG_CMD(cmd))
580 {
581 uint8_t i;
582 Log(("HDAcodec: enters reset\n"));
583 for (i = 0; i < STAC9220_NODE_COUNT; ++i)
584 {
585 stac9220ResetNode(pState, i, &pState->pNodes[i]);
586 }
587 pState->fInReset = false;
588 Log(("HDAcodec: exits reset\n"));
589 }
590 *pResp = 0;
591 return VINF_SUCCESS;
592}
593
594/* F05 */
595static int codecGetPowerState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
596{
597 Assert((CODEC_CAD(cmd) == pState->id));
598 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
599 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
600 {
601 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
602 return VINF_SUCCESS;
603 }
604 *pResp = 0;
605 if (STAC9220_IS_AFG_CMD(cmd))
606 *pResp = pState->pNodes[CODEC_NID(cmd)].afg.u32F05_param;
607 else if (STAC9220_IS_DAC_CMD(cmd))
608 *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32F05_param;
609 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
610 *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F05_param;
611 else if (STAC9220_IS_ADC_CMD(cmd))
612 *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F05_param;
613 return VINF_SUCCESS;
614}
615
616/* 705 */
617static int codecSetPowerState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
618{
619 Assert((CODEC_CAD(cmd) == pState->id));
620 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
621 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
622 {
623 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
624 return VINF_SUCCESS;
625 }
626 uint32_t *pu32Reg = NULL;
627 *pResp = 0;
628 if (STAC9220_IS_AFG_CMD(cmd))
629 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].afg.u32F05_param;
630 else if (STAC9220_IS_DAC_CMD(cmd))
631 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].dac.u32F05_param;
632 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
633 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F05_param;
634 else if (STAC9220_IS_ADC_CMD(cmd))
635 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adc.u32F05_param;
636 Assert((pu32Reg));
637 if (!pu32Reg)
638 return VINF_SUCCESS;
639 *pu32Reg &= ~CODEC_VERB_8BIT_DATA;
640 *pu32Reg |= cmd & CODEC_VERB_4BIT_DATA;
641 *pu32Reg |= (cmd & CODEC_VERB_4BIT_DATA) << 4;
642 return VINF_SUCCESS;
643}
644
645static int codecGetStreamId(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
646{
647 Assert((CODEC_CAD(cmd) == pState->id));
648 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
649 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
650 {
651 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
652 return VINF_SUCCESS;
653 }
654 *pResp = 0;
655 if (STAC9220_IS_DAC_CMD(cmd))
656 *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32F06_param;
657 else if (STAC9220_IS_ADC_CMD(cmd))
658 *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F06_param;
659 else if (STAC9220_IS_SPDIFIN_CMD(cmd))
660 *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
661 else if (STAC9220_IS_SPDIFOUT_CMD(cmd))
662 *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
663 return VINF_SUCCESS;
664}
665static int codecSetStreamId(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
666{
667 Assert((CODEC_CAD(cmd) == pState->id));
668 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
669 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
670 {
671 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
672 return VINF_SUCCESS;
673 }
674 *pResp = 0;
675 uint32_t *pu32addr = NULL;
676 *pResp = 0;
677 if (STAC9220_IS_DAC_CMD(cmd))
678 pu32addr = &pState->pNodes[CODEC_NID(cmd)].dac.u32F06_param;
679 else if (STAC9220_IS_ADC_CMD(cmd))
680 pu32addr = &pState->pNodes[CODEC_NID(cmd)].adc.u32F06_param;
681 else if (STAC9220_IS_SPDIFOUT_CMD(cmd))
682 pu32addr = &pState->pNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
683 else if (STAC9220_IS_SPDIFIN_CMD(cmd))
684 pu32addr = &pState->pNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
685 Assert((pu32addr));
686 if (pu32addr)
687 codecSetRegisterU8(pu32addr, cmd, 0);
688 return VINF_SUCCESS;
689}
690static int codecGetConverterFormat(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
691{
692 Assert((CODEC_CAD(cmd) == pState->id));
693 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
694 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
695 {
696 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
697 return VINF_SUCCESS;
698 }
699 *pResp = 0;
700 if (STAC9220_IS_DAC_CMD(cmd))
701 *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32A_param;
702 else if (STAC9220_IS_ADC_CMD(cmd))
703 *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32A_param;
704 else if (STAC9220_IS_SPDIFOUT_CMD(cmd))
705 *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32A_param;
706 else if (STAC9220_IS_SPDIFIN_CMD(cmd))
707 *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32A_param;
708 return VINF_SUCCESS;
709}
710
711static int codecSetConverterFormat(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
712{
713 Assert((CODEC_CAD(cmd) == pState->id));
714 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
715 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
716 {
717 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
718 return VINF_SUCCESS;
719 }
720 *pResp = 0;
721 if (STAC9220_IS_DAC_CMD(cmd))
722 codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
723 else if (STAC9220_IS_ADC_CMD(cmd))
724 codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
725 else if (STAC9220_IS_SPDIFOUT_CMD(cmd))
726 codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
727 else if (STAC9220_IS_SPDIFIN_CMD(cmd))
728 codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
729 return VINF_SUCCESS;
730}
731
732/* F0C */
733static int codecGetEAPD_BTLEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
734{
735 Assert((CODEC_CAD(cmd) == pState->id));
736 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
737 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
738 {
739 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
740 return VINF_SUCCESS;
741 }
742 *pResp = 0;
743 if (STAC9220_IS_ADCVOL_CMD(cmd))
744 *pResp = pState->pNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
745 else if (STAC9220_IS_DAC_CMD(cmd))
746 *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32F0c_param;
747 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
748 *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F0c_param;
749 return VINF_SUCCESS;
750}
751
752/* 70C */
753static int codecSetEAPD_BTLEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
754{
755 Assert((CODEC_CAD(cmd) == pState->id));
756 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
757 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
758 {
759 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
760 return VINF_SUCCESS;
761 }
762 *pResp = 0;
763 uint32_t *pu32Reg = NULL;
764 if (STAC9220_IS_ADCVOL_CMD(cmd))
765 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
766 else if (STAC9220_IS_DAC_CMD(cmd))
767 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].dac.u32F0c_param;
768 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
769 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F0c_param;
770 *pResp = 0;
771 Assert((pu32Reg));
772 if (pu32Reg)
773 codecSetRegisterU8(pu32Reg, cmd, 0);
774 return VINF_SUCCESS;
775}
776
777/* F0F */
778static int codecGetVolumeKnobCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
779{
780 Assert((CODEC_CAD(cmd) == pState->id));
781 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
782 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
783 {
784 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
785 return VINF_SUCCESS;
786 }
787 *pResp = 0;
788 if (STAC9220_IS_VOLKNOB_CMD(cmd))
789 *pResp = pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
790 return VINF_SUCCESS;
791}
792
793/* 70F */
794static int codecSetVolumeKnobCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
795{
796 Assert((CODEC_CAD(cmd) == pState->id));
797 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
798 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
799 {
800 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
801 return VINF_SUCCESS;
802 }
803 uint32_t *pu32Reg = NULL;
804 *pResp = 0;
805 if (STAC9220_IS_VOLKNOB_CMD(cmd))
806 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
807 Assert((pu32Reg));
808 if (pu32Reg)
809 codecSetRegisterU8(pu32Reg, cmd, 0);
810 return VINF_SUCCESS;
811}
812
813/* F1C */
814static int codecGetConfig (struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
815{
816 Assert((CODEC_CAD(cmd) == pState->id));
817 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
818 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
819 {
820 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
821 return VINF_SUCCESS;
822 }
823 *pResp = 0;
824 if (STAC9220_IS_PORT_CMD(cmd))
825 *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F1c_param;
826 else if (STAC9220_IS_DIGOUTPIN_CMD(cmd))
827 *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F1c_param;
828 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
829 *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F1c_param;
830 else if (STAC9220_IS_CD_CMD(cmd))
831 *pResp = pState->pNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
832 return VINF_SUCCESS;
833}
834static int codecSetConfigX(struct CODECState *pState, uint32_t cmd, uint8_t u8Offset)
835{
836 Assert((CODEC_CAD(cmd) == pState->id));
837 Assert((CODEC_NID(cmd) < STAC9220_NODE_COUNT));
838 if (CODEC_NID(cmd) >= STAC9220_NODE_COUNT)
839 {
840 Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd)));
841 return VINF_SUCCESS;
842 }
843 uint32_t *pu32Reg = NULL;
844 if (STAC9220_IS_PORT_CMD(cmd))
845 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F1c_param;
846 else if (STAC9220_IS_DIGINPIN_CMD(cmd))
847 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F1c_param;
848 else if (STAC9220_IS_DIGOUTPIN_CMD(cmd))
849 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F1c_param;
850 else if (STAC9220_IS_CD_CMD(cmd))
851 pu32Reg = &pState->pNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
852 Assert((pu32Reg));
853 if (pu32Reg)
854 codecSetRegisterU8(pu32Reg, cmd, u8Offset);
855 return VINF_SUCCESS;
856}
857/* 71C */
858static int codecSetConfig0 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
859{
860 *pResp = 0;
861 return codecSetConfigX(pState, cmd, 0);
862}
863/* 71D */
864static int codecSetConfig1 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
865{
866 *pResp = 0;
867 return codecSetConfigX(pState, cmd, 8);
868}
869/* 71E */
870static int codecSetConfig2 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
871{
872 *pResp = 0;
873 return codecSetConfigX(pState, cmd, 16);
874}
875/* 71E */
876static int codecSetConfig3 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
877{
878 *pResp = 0;
879 return codecSetConfigX(pState, cmd, 24);
880}
881
882static int stac9220ResetNode(struct CODECState *pState, uint8_t nodenum, PCODECNODE pNode)
883{
884 pNode->node.id = nodenum;
885 pNode->node.au32F00_param[0xF] = RT_BIT(3)|RT_BIT(0); /* Power statest Supported: D0-yes, D1, D2, D3-no*/
886 switch (nodenum)
887 {
888 /* Root Node*/
889 case 0:
890 pNode->root.node.name = "Root";
891 //** @todo r=michaln: I fear the use of RT_MAKE_U32_FROM_U8() here makes the
892 // code much harder to read, not easier.
893 pNode->node.au32F00_param[0] = RT_MAKE_U32_FROM_U8(0x80, 0x76, 0x84, 0x83); /* VendorID = STAC9220/ DevId = 0x7680 */
894 pNode->node.au32F00_param[2] = RT_MAKE_U32_FROM_U8(0x1, 0x34, 0x10, 0x00); /* rev id */
895 pNode->node.au32F00_param[4] = RT_MAKE_U32_FROM_U8(0x1, 0x00, 0x01, 0x00); /* node info (start node: 1, start id = 1) */
896 break;
897 case 1:
898 pNode->afg.node.name = "AFG";
899 pNode->node.au32F00_param[4] = 2 << 16 | 0x17; /* starting node - 2; total numbers of nodes 0x17 */
900 pNode->node.au32F00_param[5] = RT_BIT(8)|RT_BIT(0);
901 pNode->node.au32F00_param[8] = RT_MAKE_U32_FROM_U8(0x0d, 0x0d, 0x01, 0x0); /* Capabilities */
902 //pNode->node.au32F00_param[0xa] = RT_BIT(19)|RT_BIT(18)|RT_BIT(17)|RT_BIT(10)|RT_BIT(9)|RT_BIT(8)|RT_BIT(7)|RT_BIT(6)|RT_BIT(5);
903 pNode->node.au32F00_param[0xa] = RT_BIT(17)|RT_BIT(5);
904 pNode->node.au32F00_param[0xc] = (17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0);
905 pNode->node.au32F00_param[0xb] = RT_BIT(0);
906 pNode->node.au32F00_param[0xd] = RT_BIT(31)|(0x5 << 16)|(0xE)<<8;
907 pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f;
908 pNode->node.au32F00_param[0x11] = 0;
909 pNode->node.au32F00_param[0xF] = RT_BIT(30)|RT_BIT(3)|RT_BIT(0); /* Power statest Supported: D0-yes, D1, D2, D3-no*/
910 pNode->afg.u32F05_param = 0x3 << 4| 0x3; /* PS-Act: D3, PS->Set D3 */
911 pNode->afg.u32F20_param = 0x83847882;
912 pNode->afg.u32F08_param = 0;
913 break;
914 case 2:
915 pNode->dac.node.name = "DAC0";
916 goto dac_init;
917 case 3:
918 pNode->dac.node.name = "DAC1";
919 goto dac_init;
920 case 4:
921 pNode->dac.node.name = "DAC2";
922 goto dac_init;
923 case 5:
924 pNode->dac.node.name = "DAC3";
925 dac_init:
926 memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE);
927 pNode->dac.u32A_param = RT_BIT(14)|(0x1 << 4)|0x1; /* 441000Hz/16bit/2ch */
928
929 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
930 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
931
932 pNode->dac.node.au32F00_param[9] = (0xf << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0);
933 pNode->dac.u32F0c_param = 0;
934 pNode->dac.u32F05_param = 0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3 */
935 break;
936 case 6:
937 pNode->adc.node.name = "ADC0";
938 pNode->node.au8F02_param[0] = 0x17;
939 goto adc_init;
940 case 7:
941 pNode->adc.node.name = "ADC1";
942 pNode->node.au8F02_param[0] = 0x18;
943 adc_init:
944 pNode->adc.u32A_param = RT_BIT(14)|(0x1 << 3)|0x1; /* 441000Hz/16bit/2ch */
945 pNode->adc.node.au32F00_param[0xE] = RT_BIT(0);
946 pNode->adc.u32F03_param = RT_BIT(0);
947 pNode->adc.u32F05_param = 0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */
948 pNode->adc.u32F06_param = 0;
949 pNode->adc.node.au32F00_param[9] = RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0);
950 break;
951 case 8:
952 pNode->spdifout.node.name = "SPDIFOut";
953 pNode->spdifout.u32A_param = (1<<14)|(0x1<<4) | 0x1;
954 pNode->spdifout.node.au32F00_param[9] = (4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
955 pNode->node.au32F00_param[0xa] = RT_BIT(17)|RT_BIT(5);
956 pNode->spdifout.node.au32F00_param[0xB] = RT_BIT(2)|RT_BIT(0);
957 pNode->spdifout.u32F06_param = 0;
958 pNode->spdifout.u32F0d_param = 0;
959 //pNode->spdifout.node.au32F00_param[0xA] = RT_BIT(19)|RT_BIT(18)|RT_BIT(17)|RT_BIT(10)|RT_BIT(9)|RT_BIT(8)|RT_BIT(7)|RT_BIT(6);
960 break;
961 case 9:
962 pNode->node.name = "Reserved_0";
963 pNode->spdifin.u32A_param = (0x1<<4) | 0x1;
964 pNode->spdifin.node.au32F00_param[9] = (0x1 << 20)|(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
965 pNode->node.au32F00_param[0xa] = RT_BIT(17)|RT_BIT(5);
966 pNode->spdifin.node.au32F00_param[0xB] = RT_BIT(2)|RT_BIT(0);
967 pNode->spdifin.u32F06_param = 0;
968 pNode->spdifin.u32F0d_param = 0;
969 break;
970 case 0xA:
971 pNode->node.name = "PortA";
972 pNode->node.au32F00_param[0xC] = 0x173f;
973 *(uint32_t *)pNode->node.au8F02_param = 0x2;
974 pNode->port.u32F07_param = RT_BIT(6);
975 pNode->port.u32F08_param = 0;
976 pNode->port.u32F09_param = RT_BIT(31)|0x9920; /* 39.2 kOm */
977 if (!pState->fInReset)
978 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02);
979 goto port_init;
980 case 0xB:
981 pNode->node.name = "PortB";
982 pNode->node.au32F00_param[0xC] = 0x1737;
983 *(uint32_t *)pNode->node.au8F02_param = 0x4;
984 pNode->port.u32F09_param = 0;
985 pNode->port.u32F07_param = RT_BIT(5);
986 if (!pState->fInReset)
987 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01);
988 goto port_init;
989 case 0xC:
990 pNode->node.name = "PortC";
991 *(uint32_t *)pNode->node.au8F02_param = 0x3;
992 pNode->node.au32F00_param[0xC] = 0x1737;
993 pNode->port.u32F09_param = 0;
994 pNode->port.u32F07_param = RT_BIT(5);
995 if (!pState->fInReset)
996 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01);
997 goto port_init;
998 case 0xD:
999 pNode->node.name = "PortD";
1000 pNode->port.u32F09_param = 0;
1001 pNode->node.au32F00_param[0xC] = 0x173f;
1002 *(uint32_t *)pNode->node.au8F02_param = 0x2;
1003 port_init:
1004 pNode->port.u32F08_param = 0;
1005 pNode->node.au32F00_param[9] = (4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
1006 pNode->node.au32F00_param[0xE] = 0x1;
1007 break;
1008 case 0xE:
1009 pNode->node.name = "PortE";
1010 pNode->node.au32F00_param[9] = (4 << 20)|RT_BIT(7)|RT_BIT(0);
1011 pNode->port.u32F08_param = 0;
1012 pNode->node.au32F00_param[0xC] = RT_BIT(5)|RT_BIT(2);
1013 pNode->port.u32F07_param = RT_BIT(5);
1014 pNode->port.u32F09_param = RT_BIT(31);
1015 if (!pState->fInReset)
1016 pNode->port.u32F1c_param = (0x2 << 30) /* built-in */ | (0xA << 20) /* mic. */
1017 | (0x1 << 16) | (0x30 << 8) | 0x51;
1018 break;
1019 case 0xF:
1020 pNode->node.name = "PortF";
1021 pNode->node.au32F00_param[9] = (4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
1022 pNode->node.au32F00_param[0xC] = 0x37;
1023 pNode->node.au32F00_param[0xE] = 0x1;
1024 pNode->port.u32F08_param = 0;
1025 pNode->port.u32F07_param = 0;
1026 if (!pState->fInReset)
1027 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01);
1028 pNode->node.au8F02_param[0] = 0x5;
1029 pNode->port.u32F09_param = 0;
1030 break;
1031 case 0x10:
1032 pNode->node.name = "DigOut_0";
1033 pNode->node.au32F00_param[9] = (4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
1034 pNode->node.au32F00_param[0xC] = RT_BIT(4);
1035 pNode->node.au32F00_param[0xE] = 0x2;
1036 pNode->digout.u32F01_param = 0;
1037 /* STAC9220 spec defines default connection list containing reserved nodes, that confuses some drivers. */
1038 *(uint32_t *)pNode->node.au8F02_param = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x0, 0);
1039 pNode->digout.u32F07_param = 0;
1040 if (!pState->fInReset)
1041 pNode->digout.u32F1c_param = RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
1042 break;
1043 case 0x11:
1044 pNode->node.name = "DigIn_0";
1045 pNode->node.au32F00_param[9] = (4 << 20)|(3<<16)|RT_BIT(10)|RT_BIT(9)|RT_BIT(7)|RT_BIT(0);
1046 pNode->node.au32F00_param[0xC] = /* RT_BIT(16)|*/ RT_BIT(5)|RT_BIT(2);
1047 pNode->digin.u32F05_param = 0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */
1048 pNode->digin.u32F07_param = 0;
1049 pNode->digin.u32F08_param = 0;
1050 pNode->digin.u32F09_param = 0;
1051 pNode->digin.u32F0c_param = 0;
1052 if (!pState->fInReset)
1053 pNode->digin.u32F1c_param = (0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60;
1054 break;
1055 case 0x12:
1056 pNode->node.name = "ADCMux_0";
1057 pNode->adcmux.u32F01_param = 0;
1058 goto adcmux_init;
1059 case 0x13:
1060 pNode->node.name = "ADCMux_1";
1061 pNode->adcmux.u32F01_param = 1;
1062 adcmux_init:
1063 pNode->node.au32F00_param[9] = (3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0);
1064 pNode->node.au32F00_param[0xe] = 0x7;
1065 pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8);
1066 /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/
1067 memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE);
1068 *(uint32_t *)&pNode->node.au8F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb);
1069 *(uint32_t *)&pNode->node.au8F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0);
1070 break;
1071 case 0x14:
1072 pNode->node.name = "PCBEEP";
1073 pNode->node.au32F00_param[9] = (7 << 20) | RT_BIT(3) | RT_BIT(2);
1074 pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3;
1075 pNode->pcbeep.u32F0a_param = 0;
1076 memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
1077 break;
1078 case 0x15:
1079 pNode->node.name = "CD";
1080 pNode->node.au32F00_param[0x9] = (4 << 20)|RT_BIT(0);
1081 pNode->node.au32F00_param[0xc] = RT_BIT(5);
1082 pNode->cdnode.u32F07_param = 0;
1083 if (!pState->fInReset)
1084 pNode->cdnode.u32F1c_param = RT_MAKE_U32_FROM_U8(0x52, 0x0, 0x33, 0x90);
1085 break;
1086 case 0x16:
1087 pNode->node.name = "VolumeKnob";
1088 pNode->node.au32F00_param[0x9] = (0x6 << 20);
1089 pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F;
1090 pNode->node.au32F00_param[0xe] = 0x4;
1091 *(uint32_t *)pNode->node.au8F02_param = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5);
1092 pNode->volumeKnob.u32F08_param = 0;
1093 pNode->volumeKnob.u32F0f_param = 0x7f;
1094 break;
1095 case 0x17:
1096 pNode->node.name = "ADC0Vol";
1097 *(uint32_t *)pNode->node.au8F02_param = 0x12;
1098 goto adcvol_init;
1099 case 0x18:
1100 pNode->node.name = "ADC1Vol";
1101 *(uint32_t *)pNode->node.au8F02_param = 0x13;
1102 adcvol_init:
1103 memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
1104
1105 pNode->node.au32F00_param[0x9] = (0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0);
1106 pNode->node.au32F00_param[0xe] = 0x1;
1107 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
1108 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
1109 pNode->adcvol.u32F0c_param = 0;
1110 default:
1111 break;
1112 }
1113 return VINF_SUCCESS;
1114}
1115
1116static int codecToAudVolume(AMPLIFIER *pAmp, audmixerctl_t mt)
1117{
1118 uint32_t dir = AMPLIFIER_OUT;
1119 switch (mt)
1120 {
1121 case AUD_MIXER_VOLUME:
1122 dir = AMPLIFIER_OUT;
1123 break;
1124 case AUD_MIXER_PCM:
1125 case AUD_MIXER_LINE_IN:
1126 dir = AMPLIFIER_IN;
1127 break;
1128 }
1129 int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
1130 mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
1131 mute >>=7;
1132 mute &= 0x1;
1133 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f;
1134 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f;
1135 AUD_set_volume(mt, &mute, &lVol, &rVol);
1136 return VINF_SUCCESS;
1137}
1138
1139static CODECVERB STAC9220VERB[] =
1140{
1141/* verb | verb mask | callback */
1142/* ----------- -------------------- ----------------------- */
1143 {0x000F0000, CODEC_VERB_8BIT_CMD , codecGetParameter },
1144 {0x000F0100, CODEC_VERB_8BIT_CMD , codecGetConSelectCtrl },
1145 {0x00070100, CODEC_VERB_8BIT_CMD , codecSetConSelectCtrl },
1146 {0x000F0600, CODEC_VERB_8BIT_CMD , codecGetStreamId },
1147 {0x00070600, CODEC_VERB_8BIT_CMD , codecSetStreamId },
1148 {0x000F0700, CODEC_VERB_8BIT_CMD , codecGetPinCtrl },
1149 {0x00070700, CODEC_VERB_8BIT_CMD , codecSetPinCtrl },
1150 {0x000F0800, CODEC_VERB_8BIT_CMD , codecGetUnsolicitedEnabled },
1151 {0x00070800, CODEC_VERB_8BIT_CMD , codecSetUnsolicitedEnabled },
1152 {0x000F0900, CODEC_VERB_8BIT_CMD , codecGetPinSense },
1153 {0x00070900, CODEC_VERB_8BIT_CMD , codecSetPinSense },
1154 {0x000F0200, CODEC_VERB_8BIT_CMD , codecGetConnectionListEntry },
1155 {0x000F0300, CODEC_VERB_8BIT_CMD , codecGetProcessingState },
1156 {0x00070300, CODEC_VERB_8BIT_CMD , codecSetProcessingState },
1157 {0x000F0D00, CODEC_VERB_8BIT_CMD , codecGetDigitalConverter },
1158 {0x00070D00, CODEC_VERB_8BIT_CMD , codecSetDigitalConverter1 },
1159 {0x00070E00, CODEC_VERB_8BIT_CMD , codecSetDigitalConverter2 },
1160 {0x000F2000, CODEC_VERB_8BIT_CMD , codecGetSubId },
1161 {0x0007FF00, CODEC_VERB_8BIT_CMD , codecReset },
1162 {0x000F0500, CODEC_VERB_8BIT_CMD , codecGetPowerState },
1163 {0x00070500, CODEC_VERB_8BIT_CMD , codecSetPowerState },
1164 {0x000F0C00, CODEC_VERB_8BIT_CMD , codecGetEAPD_BTLEnabled },
1165 {0x00070C00, CODEC_VERB_8BIT_CMD , codecSetEAPD_BTLEnabled },
1166 {0x000F0F00, CODEC_VERB_8BIT_CMD , codecGetVolumeKnobCtrl },
1167 {0x00070F00, CODEC_VERB_8BIT_CMD , codecSetVolumeKnobCtrl },
1168 {0x000F1C00, CODEC_VERB_8BIT_CMD , codecGetConfig },
1169 {0x00071C00, CODEC_VERB_8BIT_CMD , codecSetConfig0 },
1170 {0x00071D00, CODEC_VERB_8BIT_CMD , codecSetConfig1 },
1171 {0x00071E00, CODEC_VERB_8BIT_CMD , codecSetConfig2 },
1172 {0x00071F00, CODEC_VERB_8BIT_CMD , codecSetConfig3 },
1173 {0x000A0000, CODEC_VERB_16BIT_CMD, codecGetConverterFormat },
1174 {0x00020000, CODEC_VERB_16BIT_CMD, codecSetConverterFormat },
1175 {0x000B0000, CODEC_VERB_16BIT_CMD, codecGetAmplifier },
1176 {0x00030000, CODEC_VERB_16BIT_CMD, codecSetAmplifier },
1177};
1178
1179static int codecLookup(CODECState *pState, uint32_t cmd, PPFNCODECVERBPROCESSOR pfn)
1180{
1181 int rc = VINF_SUCCESS;
1182 Assert(CODEC_CAD(cmd) == pState->id);
1183 if ( CODEC_VERBDATA(cmd) == 0
1184 || CODEC_NID(cmd) >= STAC9220_NODE_COUNT
1185 || STAC9220_IS_RESERVED_CMD(cmd))
1186 {
1187 *pfn = codecUnimplemented;
1188 //** @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp)
1189 LogRel(("HDAcodec: cmd %x was ignored\n", cmd));
1190 return VINF_SUCCESS;
1191 }
1192 for (int i = 0; i < pState->cVerbs; ++i)
1193 {
1194 if ((CODEC_VERBDATA(cmd) & pState->pVerbs[i].mask) == pState->pVerbs[i].verb)
1195 {
1196 *pfn = pState->pVerbs[i].pfn;
1197 return VINF_SUCCESS;
1198 }
1199 }
1200 *pfn = codecUnimplemented;
1201 LogRel(("HDAcodec: callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
1202 return rc;
1203}
1204
1205static int codec_dac_to_aud(CODECState *pState, int dacnum, audsettings_t *paud)
1206{
1207 paud->freq = 44100;
1208 paud->nchannels = 2;
1209 paud->fmt = AUD_FMT_S16;
1210
1211 paud->endianness = 0;
1212 return VINF_SUCCESS;
1213}
1214
1215static void pi_callback (void *opaque, int avail)
1216{
1217 CODECState *pState = (CODECState *)opaque;
1218 pState->pfnTransfer(pState, PI_INDEX, avail);
1219}
1220
1221static void po_callback (void *opaque, int avail)
1222{
1223 CODECState *pState = (CODECState *)opaque;
1224 pState->pfnTransfer(pState, PO_INDEX, avail);
1225}
1226
1227static void mc_callback (void *opaque, int avail)
1228{
1229 CODECState *pState = (CODECState *)opaque;
1230 pState->pfnTransfer(pState, MC_INDEX, avail);
1231}
1232#define STAC9220_DAC_PI (0x2)
1233#define STAC9220_DAC_MC (0x3)
1234#define STAC9220_DAC_PO (0x4)
1235int stac9220Construct(CODECState *pState)
1236{
1237 audsettings_t as;
1238 pState->pVerbs = (CODECVERB *)&STAC9220VERB;
1239 pState->cVerbs = sizeof(STAC9220VERB)/sizeof(CODECVERB);
1240 pState->pfnLookup = codecLookup;
1241 pState->pNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * STAC9220_NODE_COUNT);
1242 pState->fInReset = false;
1243 uint8_t i;
1244 for (i = 0; i < STAC9220_NODE_COUNT; ++i)
1245 {
1246 stac9220ResetNode(pState, i, &pState->pNodes[i]);
1247 }
1248 //** @todo r=michaln: Was this meant to be 'HDA' or something like that? (AC'97 was on ICH0)
1249 AUD_register_card ("ICH0", &pState->card);
1250
1251
1252 codec_dac_to_aud(pState, STAC9220_DAC_PI, &as);
1253 pState->voice_pi = AUD_open_in(&pState->card, pState->voice_pi, "hda.in", pState, pi_callback, &as);
1254 codec_dac_to_aud(pState, STAC9220_DAC_PO, &as);
1255 pState->voice_po = AUD_open_out(&pState->card, pState->voice_po, "hda.out", pState, po_callback, &as);
1256 codec_dac_to_aud(pState, STAC9220_DAC_MC, &as);
1257 pState->voice_mc = AUD_open_in(&pState->card, pState->voice_mc, "hda.mc", pState, mc_callback, &as);
1258 if (!pState->voice_pi)
1259 LogRel (("HDAcodec: WARNING: Unable to open PCM IN!\n"));
1260 if (!pState->voice_mc)
1261 LogRel (("HDAcodec: WARNING: Unable to open PCM MC!\n"));
1262 if (!pState->voice_po)
1263 LogRel (("HDAcodec: WARNING: Unable to open PCM OUT!\n"));
1264 codecToAudVolume(&pState->pNodes[2].dac.B_params, AUD_MIXER_VOLUME);
1265 codecToAudVolume(&pState->pNodes[0x17].adcvol.B_params, AUD_MIXER_PCM);
1266 return VINF_SUCCESS;
1267}
1268int stac9220Destruct(CODECState *pCodecState)
1269{
1270 RTMemFree(pCodecState->pNodes);
1271 return VINF_SUCCESS;
1272}
1273
1274int stac9220SaveState(CODECState *pCodecState, PSSMHANDLE pSSMHandle)
1275{
1276 SSMR3PutMem (pSSMHandle, pCodecState->pNodes, sizeof(CODECNODE) * STAC9220_NODE_COUNT);
1277 return VINF_SUCCESS;
1278}
1279int stac9220LoadState(CODECState *pCodecState, PSSMHANDLE pSSMHandle)
1280{
1281 SSMR3GetMem (pSSMHandle, pCodecState->pNodes, sizeof(CODECNODE) * STAC9220_NODE_COUNT);
1282 codecToAudVolume(&pCodecState->pNodes[2].dac.B_params, AUD_MIXER_VOLUME);
1283 codecToAudVolume(&pCodecState->pNodes[0x17].adcvol.B_params, AUD_MIXER_PCM);
1284 return VINF_SUCCESS;
1285}
Note: See TracBrowser for help on using the repository browser.

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