VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp@ 57541

Last change on this file since 57541 was 57393, checked in by vboxsync, 9 years ago

DECLCALLBACK

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 121.7 KB
Line 
1/* $Id: DevIchHdaCodec.cpp 57393 2015-08-17 15:02:05Z vboxsync $ */
2/** @file
3 * DevIchHdaCodec - VBox ICH Intel HD Audio Codec.
4 *
5 * Implemented against "Intel I/O Controller Hub 6 (ICH6) High Definition
6 * Audio / AC '97 - Programmer's Reference Manual (PRM)", document number
7 * 302349-003.
8 */
9
10/*
11 * Copyright (C) 2006-2015 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_DEV_HDA_CODEC
27#include <VBox/vmm/pdmdev.h>
28#include <VBox/vmm/pdmaudioifs.h>
29#include <iprt/assert.h>
30#include <iprt/uuid.h>
31#include <iprt/string.h>
32#include <iprt/mem.h>
33#include <iprt/asm.h>
34#include <iprt/cpp/utils.h>
35
36#include "VBoxDD.h"
37#include "DevIchHdaCodec.h"
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43/* PRM 5.3.1 */
44/** Codec address mask. */
45#define CODEC_CAD_MASK 0xF0000000
46/** Codec address shift. */
47#define CODEC_CAD_SHIFT 28
48#define CODEC_DIRECT_MASK RT_BIT(27)
49/** Node ID mask. */
50#define CODEC_NID_MASK 0x07F00000
51/** Node ID shift. */
52#define CODEC_NID_SHIFT 20
53#define CODEC_VERBDATA_MASK 0x000FFFFF
54#define CODEC_VERB_4BIT_CMD 0x000FFFF0
55#define CODEC_VERB_4BIT_DATA 0x0000000F
56#define CODEC_VERB_8BIT_CMD 0x000FFF00
57#define CODEC_VERB_8BIT_DATA 0x000000FF
58#define CODEC_VERB_16BIT_CMD 0x000F0000
59#define CODEC_VERB_16BIT_DATA 0x0000FFFF
60
61#define CODEC_CAD(cmd) (((cmd) & CODEC_CAD_MASK) >> CODEC_CAD_SHIFT)
62#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK)
63#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT)
64#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK)
65#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x))
66#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4))
67#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8))
68#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16))
69#define CODEC_VERB_PAYLOAD4(cmd) ((cmd) & CODEC_VERB_4BIT_DATA)
70#define CODEC_VERB_PAYLOAD8(cmd) ((cmd) & CODEC_VERB_8BIT_DATA)
71#define CODEC_VERB_PAYLOAD16(cmd) ((cmd) & CODEC_VERB_16BIT_DATA)
72
73#define CODEC_VERB_GET_AMP_DIRECTION RT_BIT(15)
74#define CODEC_VERB_GET_AMP_SIDE RT_BIT(13)
75#define CODEC_VERB_GET_AMP_INDEX 0x7
76
77/* HDA spec 7.3.3.7 NoteA */
78#define CODEC_GET_AMP_DIRECTION(cmd) (((cmd) & CODEC_VERB_GET_AMP_DIRECTION) >> 15)
79#define CODEC_GET_AMP_SIDE(cmd) (((cmd) & CODEC_VERB_GET_AMP_SIDE) >> 13)
80#define CODEC_GET_AMP_INDEX(cmd) (CODEC_GET_AMP_DIRECTION(cmd) ? 0 : ((cmd) & CODEC_VERB_GET_AMP_INDEX))
81
82/* HDA spec 7.3.3.7 NoteC */
83#define CODEC_VERB_SET_AMP_OUT_DIRECTION RT_BIT(15)
84#define CODEC_VERB_SET_AMP_IN_DIRECTION RT_BIT(14)
85#define CODEC_VERB_SET_AMP_LEFT_SIDE RT_BIT(13)
86#define CODEC_VERB_SET_AMP_RIGHT_SIDE RT_BIT(12)
87#define CODEC_VERB_SET_AMP_INDEX (0x7 << 8)
88#define CODEC_VERB_SET_AMP_MUTE RT_BIT(7)
89/** Note: 7-bit value [6:0]. */
90#define CODEC_VERB_SET_AMP_GAIN 0x7F
91
92#define CODEC_SET_AMP_IS_OUT_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_OUT_DIRECTION) != 0)
93#define CODEC_SET_AMP_IS_IN_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_IN_DIRECTION) != 0)
94#define CODEC_SET_AMP_IS_LEFT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_LEFT_SIDE) != 0)
95#define CODEC_SET_AMP_IS_RIGHT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_RIGHT_SIDE) != 0)
96#define CODEC_SET_AMP_INDEX(cmd) (((cmd) & CODEC_VERB_SET_AMP_INDEX) >> 7)
97#define CODEC_SET_AMP_MUTE(cmd) ((cmd) & CODEC_VERB_SET_AMP_MUTE)
98#define CODEC_SET_AMP_GAIN(cmd) ((cmd) & CODEC_VERB_SET_AMP_GAIN)
99
100/* HDA spec 7.3.3.1 defines layout of configuration registers/verbs (0xF00) */
101/* VendorID (7.3.4.1) */
102#define CODEC_MAKE_F00_00(vendorID, deviceID) (((vendorID) << 16) | (deviceID))
103#define CODEC_F00_00_VENDORID(f00_00) (((f00_00) >> 16) & 0xFFFF)
104#define CODEC_F00_00_DEVICEID(f00_00) ((f00_00) & 0xFFFF)
105/* RevisionID (7.3.4.2)*/
106#define CODEC_MAKE_F00_02(MajRev, MinRev, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID))
107/* Subordinate node count (7.3.4.3)*/
108#define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF))
109#define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04) (((f00_04) >> 16) & 0xFF)
110#define CODEC_F00_04_TO_NODE_COUNT(f00_04) ((f00_04) & 0xFF)
111/*
112 * Function Group Type (7.3.4.4)
113 * 0 & [0x3-0x7f] are reserved types
114 * [0x80 - 0xff] are vendor defined function groups
115 */
116#define CODEC_MAKE_F00_05(UnSol, NodeType) (((UnSol) << 8)|(NodeType))
117#define CODEC_F00_05_UNSOL RT_BIT(8)
118#define CODEC_F00_05_AFG (0x1)
119#define CODEC_F00_05_MFG (0x2)
120#define CODEC_F00_05_IS_UNSOL(f00_05) RT_BOOL((f00_05) & RT_BIT(8))
121#define CODEC_F00_05_GROUP(f00_05) ((f00_05) & 0xff)
122/* Audio Function Group capabilities (7.3.4.5) */
123#define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF))
124#define CODEC_F00_08_BEEP_GEN(f00_08) ((f00_08) & RT_BIT(16)
125
126/* Widget Capabilities (7.3.4.6) */
127#define CODEC_MAKE_F00_09(type, delay, chanel_count) \
128 ( (((type) & 0xF) << 20) \
129 | (((delay) & 0xF) << 16) \
130 | (((chanel_count) & 0xF) << 13))
131/* note: types 0x8-0xe are reserved */
132#define CODEC_F00_09_TYPE_AUDIO_OUTPUT (0x0)
133#define CODEC_F00_09_TYPE_AUDIO_INPUT (0x1)
134#define CODEC_F00_09_TYPE_AUDIO_MIXER (0x2)
135#define CODEC_F00_09_TYPE_AUDIO_SELECTOR (0x3)
136#define CODEC_F00_09_TYPE_PIN_COMPLEX (0x4)
137#define CODEC_F00_09_TYPE_POWER_WIDGET (0x5)
138#define CODEC_F00_09_TYPE_VOLUME_KNOB (0x6)
139#define CODEC_F00_09_TYPE_BEEP_GEN (0x7)
140#define CODEC_F00_09_TYPE_VENDOR_DEFINED (0xF)
141
142#define CODEC_F00_09_CAP_CP RT_BIT(12)
143#define CODEC_F00_09_CAP_L_R_SWAP RT_BIT(11)
144#define CODEC_F00_09_CAP_POWER_CTRL RT_BIT(10)
145#define CODEC_F00_09_CAP_DIGITAL RT_BIT(9)
146#define CODEC_F00_09_CAP_CONNECTION_LIST RT_BIT(8)
147#define CODEC_F00_09_CAP_UNSOL RT_BIT(7)
148#define CODEC_F00_09_CAP_PROC_WIDGET RT_BIT(6)
149#define CODEC_F00_09_CAP_STRIPE RT_BIT(5)
150#define CODEC_F00_09_CAP_FMT_OVERRIDE RT_BIT(4)
151#define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE RT_BIT(3)
152#define CODEC_F00_09_CAP_OUT_AMP_PRESENT RT_BIT(2)
153#define CODEC_F00_09_CAP_IN_AMP_PRESENT RT_BIT(1)
154#define CODEC_F00_09_CAP_LSB RT_BIT(0)
155
156#define CODEC_F00_09_TYPE(f00_09) (((f00_09) >> 20) & 0xF)
157
158#define CODEC_F00_09_IS_CAP_CP(f00_09) RT_BOOL((f00_09) & RT_BIT(12))
159#define CODEC_F00_09_IS_CAP_L_R_SWAP(f00_09) RT_BOOL((f00_09) & RT_BIT(11))
160#define CODEC_F00_09_IS_CAP_POWER_CTRL(f00_09) RT_BOOL((f00_09) & RT_BIT(10))
161#define CODEC_F00_09_IS_CAP_DIGITAL(f00_09) RT_BOOL((f00_09) & RT_BIT(9))
162#define CODEC_F00_09_IS_CAP_CONNECTION_LIST(f00_09) RT_BOOL((f00_09) & RT_BIT(8))
163#define CODEC_F00_09_IS_CAP_UNSOL(f00_09) RT_BOOL((f00_09) & RT_BIT(7))
164#define CODEC_F00_09_IS_CAP_PROC_WIDGET(f00_09) RT_BOOL((f00_09) & RT_BIT(6))
165#define CODEC_F00_09_IS_CAP_STRIPE(f00_09) RT_BOOL((f00_09) & RT_BIT(5))
166#define CODEC_F00_09_IS_CAP_FMT_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(4))
167#define CODEC_F00_09_IS_CAP_AMP_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(3))
168#define CODEC_F00_09_IS_CAP_OUT_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(2))
169#define CODEC_F00_09_IS_CAP_IN_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(1))
170#define CODEC_F00_09_IS_CAP_LSB(f00_09) RT_BOOL((f00_09) & RT_BIT(0))
171
172/* Supported PCM size, rates (7.3.4.7) */
173#define CODEC_F00_0A_32_BIT RT_BIT(19)
174#define CODEC_F00_0A_24_BIT RT_BIT(18)
175#define CODEC_F00_0A_16_BIT RT_BIT(17)
176#define CODEC_F00_0A_8_BIT RT_BIT(16)
177
178#define CODEC_F00_0A_48KHZ_MULT_8X RT_BIT(11)
179#define CODEC_F00_0A_48KHZ_MULT_4X RT_BIT(10)
180#define CODEC_F00_0A_44_1KHZ_MULT_4X RT_BIT(9)
181#define CODEC_F00_0A_48KHZ_MULT_2X RT_BIT(8)
182#define CODEC_F00_0A_44_1KHZ_MULT_2X RT_BIT(7)
183#define CODEC_F00_0A_48KHZ RT_BIT(6)
184#define CODEC_F00_0A_44_1KHZ RT_BIT(5)
185/* 2/3 * 48kHz */
186#define CODEC_F00_0A_48KHZ_2_3X RT_BIT(4)
187/* 1/2 * 44.1kHz */
188#define CODEC_F00_0A_44_1KHZ_1_2X RT_BIT(3)
189/* 1/3 * 48kHz */
190#define CODEC_F00_0A_48KHZ_1_3X RT_BIT(2)
191/* 1/4 * 44.1kHz */
192#define CODEC_F00_0A_44_1KHZ_1_4X RT_BIT(1)
193/* 1/6 * 48kHz */
194#define CODEC_F00_0A_48KHZ_1_6X RT_BIT(0)
195
196/* Supported streams formats (7.3.4.8) */
197#define CODEC_F00_0B_AC3 RT_BIT(2)
198#define CODEC_F00_0B_FLOAT32 RT_BIT(1)
199#define CODEC_F00_0B_PCM RT_BIT(0)
200
201/* Pin Capabilities (7.3.4.9)*/
202#define CODEC_MAKE_F00_0C(vref_ctrl) (((vref_ctrl) & 0xFF) << 8)
203#define CODEC_F00_0C_CAP_HBR RT_BIT(27)
204#define CODEC_F00_0C_CAP_DP RT_BIT(24)
205#define CODEC_F00_0C_CAP_EAPD RT_BIT(16)
206#define CODEC_F00_0C_CAP_HDMI RT_BIT(7)
207#define CODEC_F00_0C_CAP_BALANCED_IO RT_BIT(6)
208#define CODEC_F00_0C_CAP_INPUT RT_BIT(5)
209#define CODEC_F00_0C_CAP_OUTPUT RT_BIT(4)
210#define CODEC_F00_0C_CAP_HP RT_BIT(3)
211#define CODEC_F00_0C_CAP_PRESENSE_DETECT RT_BIT(2)
212#define CODEC_F00_0C_CAP_TRIGGER_REQUIRED RT_BIT(1)
213#define CODEC_F00_0C_CAP_IMPENDANCE_SENSE RT_BIT(0)
214
215#define CODEC_F00_0C_IS_CAP_HBR(f00_0c) ((f00_0c) & RT_BIT(27))
216#define CODEC_F00_0C_IS_CAP_DP(f00_0c) ((f00_0c) & RT_BIT(24))
217#define CODEC_F00_0C_IS_CAP_EAPD(f00_0c) ((f00_0c) & RT_BIT(16))
218#define CODEC_F00_0C_IS_CAP_HDMI(f00_0c) ((f00_0c) & RT_BIT(7))
219#define CODEC_F00_0C_IS_CAP_BALANCED_IO(f00_0c) ((f00_0c) & RT_BIT(6))
220#define CODEC_F00_0C_IS_CAP_INPUT(f00_0c) ((f00_0c) & RT_BIT(5))
221#define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c) ((f00_0c) & RT_BIT(4))
222#define CODEC_F00_0C_IS_CAP_HP(f00_0c) ((f00_0c) & RT_BIT(3))
223#define CODEC_F00_0C_IS_CAP_PRESENSE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2))
224#define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c) ((f00_0c) & RT_BIT(1))
225#define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c) ((f00_0c) & RT_BIT(0))
226
227/* Input Amplifier capabilities (7.3.4.10) */
228#define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \
229 ( (((mute_cap) & 0x1) << 31) \
230 | (((step_size) & 0xFF) << 16) \
231 | (((num_steps) & 0xFF) << 8) \
232 | ((offset) & 0xFF))
233
234#define CODEC_F00_0D_CAP_MUTE RT_BIT(7)
235
236#define CODEC_F00_0D_IS_CAP_MUTE(f00_0d) ( ( f00_0d) & RT_BIT(31))
237#define CODEC_F00_0D_STEP_SIZE(f00_0d) ((( f00_0d) & (0x7F << 16)) >> 16)
238#define CODEC_F00_0D_NUM_STEPS(f00_0d) ((((f00_0d) & (0x7F << 8)) >> 8) + 1)
239#define CODEC_F00_0D_OFFSET(f00_0d) ( (f00_0d) & 0x7F)
240
241/* Output Amplifier capabilities (7.3.4.10) */
242#define CODEC_MAKE_F00_12 CODEC_MAKE_F00_0D
243
244#define CODEC_F00_12_IS_CAP_MUTE(f00_12) CODEC_F00_0D_IS_CAP_MUTE(f00_12)
245#define CODEC_F00_12_STEP_SIZE(f00_12) CODEC_F00_0D_STEP_SIZE(f00_12)
246#define CODEC_F00_12_NUM_STEPS(f00_12) CODEC_F00_0D_NUM_STEPS(f00_12)
247#define CODEC_F00_12_OFFSET(f00_12) CODEC_F00_0D_OFFSET(f00_12)
248
249/* Connection list lenght (7.3.4.11) */
250#define CODEC_MAKE_F00_0E(long_form, length) \
251 ( (((long_form) & 0x1) << 7) \
252 | ((length) & 0x7F))
253/* Indicates short-form NIDs. */
254#define CODEC_F00_0E_LIST_NID_SHORT 0
255/* Indicates long-form NIDs. */
256#define CODEC_F00_0E_LIST_NID_LONG 1
257#define CODEC_F00_0E_IS_LONG(f00_0e) RT_BOOL((f00_0e) & RT_BIT(7))
258#define CODEC_F00_0E_COUNT(f00_0e) ((f00_0e) & 0x7F)
259/* Supported Power States (7.3.4.12) */
260#define CODEC_F00_0F_EPSS RT_BIT(31)
261#define CODEC_F00_0F_CLKSTOP RT_BIT(30)
262#define CODEC_F00_0F_S3D3 RT_BIT(29)
263#define CODEC_F00_0F_D3COLD RT_BIT(4)
264#define CODEC_F00_0F_D3 RT_BIT(3)
265#define CODEC_F00_0F_D2 RT_BIT(2)
266#define CODEC_F00_0F_D1 RT_BIT(1)
267#define CODEC_F00_0F_D0 RT_BIT(0)
268
269/* Processing capabilities 7.3.4.13 */
270#define CODEC_MAKE_F00_10(num, benign) ((((num) & 0xFF) << 8) | ((benign) & 0x1))
271#define CODEC_F00_10_NUM(f00_10) (((f00_10) & (0xFF << 8)) >> 8)
272#define CODEC_F00_10_BENING(f00_10) ((f00_10) & 0x1)
273
274/* CP/IO Count (7.3.4.14) */
275#define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \
276 ( (((wake) & 0x1) << 31) \
277 | (((unsol) & 0x1) << 30) \
278 | (((numgpi) & 0xFF) << 16) \
279 | (((numgpo) & 0xFF) << 8) \
280 | ((numgpio) & 0xFF))
281
282/* Processing States (7.3.3.4) */
283#define CODEC_F03_OFF (0)
284#define CODEC_F03_ON RT_BIT(0)
285#define CODEC_F03_BENING RT_BIT(1)
286/* Power States (7.3.3.10) */
287#define CODEC_MAKE_F05(reset, stopok, error, act, set) \
288 ( (((reset) & 0x1) << 10) \
289 | (((stopok) & 0x1) << 9) \
290 | (((error) & 0x1) << 8) \
291 | (((act) & 0x7) << 4) \
292 | ((set) & 0x7))
293#define CODEC_F05_D3COLD (4)
294#define CODEC_F05_D3 (3)
295#define CODEC_F05_D2 (2)
296#define CODEC_F05_D1 (1)
297#define CODEC_F05_D0 (0)
298
299#define CODEC_F05_IS_RESET(value) (((value) & RT_BIT(10)) != 0)
300#define CODEC_F05_IS_STOPOK(value) (((value) & RT_BIT(9)) != 0)
301#define CODEC_F05_IS_ERROR(value) (((value) & RT_BIT(8)) != 0)
302#define CODEC_F05_ACT(value) (((value) & 0x7) >> 4)
303#define CODEC_F05_SET(value) (((value) & 0x7))
304
305#define CODEC_F05_GE(p0, p1) ((p0) <= (p1))
306#define CODEC_F05_LE(p0, p1) ((p0) >= (p1))
307
308/* Pin Widged Control (7.3.3.13) */
309#define CODEC_F07_VREF_HIZ (0)
310#define CODEC_F07_VREF_50 (0x1)
311#define CODEC_F07_VREF_GROUND (0x2)
312#define CODEC_F07_VREF_80 (0x4)
313#define CODEC_F07_VREF_100 (0x5)
314#define CODEC_F07_IN_ENABLE RT_BIT(5)
315#define CODEC_F07_OUT_ENABLE RT_BIT(6)
316#define CODEC_F07_OUT_H_ENABLE RT_BIT(7)
317
318/* Unsolicited enabled (7.3.3.14) */
319#define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F))
320
321/* Converter formats (7.3.3.8) and (3.7.1) */
322#define CODEC_MAKE_A(fNonPCM, f44_1BaseRate, mult, div, bits, chan) \
323 ( (((fNonPCM) & 0x1) << 15) \
324 | (((f44_1BaseRate) & 0x1) << 14) \
325 | (((mult) & 0x7) << 11) \
326 | (((div) & 0x7) << 8) \
327 | (((bits) & 0x7) << 4) \
328 | ((chan) & 0xF))
329
330#define CODEC_A_TYPE RT_BIT(15)
331#define CODEC_A_TYPE_PCM (0)
332#define CODEC_A_TYPE_NON_PCM (1)
333
334#define CODEC_A_BASE RT_BIT(14)
335#define CODEC_A_BASE_48KHZ (0)
336#define CODEC_A_BASE_44KHZ (1)
337
338#define CODEC_A_MULT_1X (0)
339#define CODEC_A_MULT_2X (1)
340#define CODEC_A_MULT_3X (2)
341#define CODEC_A_MULT_4X (3)
342
343#define CODEC_A_DIV_1X (0)
344#define CODEC_A_DIV_2X (1)
345#define CODEC_A_DIV_3X (2)
346#define CODEC_A_DIV_4X (3)
347#define CODEC_A_DIV_5X (4)
348#define CODEC_A_DIV_6X (5)
349#define CODEC_A_DIV_7X (6)
350#define CODEC_A_DIV_8X (7)
351
352#define CODEC_A_8_BIT (0)
353#define CODEC_A_16_BIT (1)
354#define CODEC_A_20_BIT (2)
355#define CODEC_A_24_BIT (3)
356#define CODEC_A_32_BIT (4)
357
358#define CODEC_A_CHAN_MONO (0)
359#define CODEC_A_CHAN_STEREO (1)
360
361/* Pin Sense (7.3.3.15) */
362#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \
363( (((fPresent) & 0x1) << 31) \
364 | (((impedance) & 0x7FFFFFFF)))
365#define CODEC_F09_ANALOG_NA 0x7FFFFFFF
366#define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \
367( (((fPresent) & 0x1) << 31) \
368 | (((fELDValid) & 0x1) << 30))
369
370#define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1))
371#define CODEC_FOC_IS_LRSWAP(f0c) RT_BOOL((f0c) & RT_BIT(2))
372#define CODEC_FOC_IS_EAPD(f0c) RT_BOOL((f0c) & RT_BIT(1))
373#define CODEC_FOC_IS_BTL(f0c) RT_BOOL((f0c) & RT_BIT(0))
374/* HDA spec 7.3.3.31 defines layout of configuration registers/verbs (0xF1C) */
375/* Configuration's port connection */
376#define CODEC_F1C_PORT_MASK (0x3)
377#define CODEC_F1C_PORT_SHIFT (30)
378
379#define CODEC_F1C_PORT_COMPLEX (0x0)
380#define CODEC_F1C_PORT_NO_PHYS (0x1)
381#define CODEC_F1C_PORT_FIXED (0x2)
382#define CODEC_F1C_BOTH (0x3)
383
384/* Configuration default: connection */
385#define CODEC_F1C_PORT_MASK (0x3)
386#define CODEC_F1C_PORT_SHIFT (30)
387
388/* Connected to a jack (1/8", ATAPI, ...). */
389#define CODEC_F1C_PORT_COMPLEX (0x0)
390/* No physical connection. */
391#define CODEC_F1C_PORT_NO_PHYS (0x1)
392/* Fixed function device (integrated speaker, integrated mic, ...). */
393#define CODEC_F1C_PORT_FIXED (0x2)
394/* Both, a jack and an internal device are attached. */
395#define CODEC_F1C_BOTH (0x3)
396
397/* Configuration default: Location */
398#define CODEC_F1C_LOCATION_MASK (0x3F)
399#define CODEC_F1C_LOCATION_SHIFT (24)
400
401/* [4:5] bits of location region means chassis attachment */
402#define CODEC_F1C_LOCATION_PRIMARY_CHASSIS (0)
403#define CODEC_F1C_LOCATION_INTERNAL RT_BIT(4)
404#define CODEC_F1C_LOCATION_SECONDRARY_CHASSIS RT_BIT(5)
405#define CODEC_F1C_LOCATION_OTHER RT_BIT(5)
406
407/* [0:3] bits of location region means geometry location attachment */
408#define CODEC_F1C_LOCATION_NA (0)
409#define CODEC_F1C_LOCATION_REAR (0x1)
410#define CODEC_F1C_LOCATION_FRONT (0x2)
411#define CODEC_F1C_LOCATION_LEFT (0x3)
412#define CODEC_F1C_LOCATION_RIGTH (0x4)
413#define CODEC_F1C_LOCATION_TOP (0x5)
414#define CODEC_F1C_LOCATION_BOTTOM (0x6)
415#define CODEC_F1C_LOCATION_SPECIAL_0 (0x7)
416#define CODEC_F1C_LOCATION_SPECIAL_1 (0x8)
417#define CODEC_F1C_LOCATION_SPECIAL_2 (0x9)
418
419/* Configuration default: Device type */
420#define CODEC_F1C_DEVICE_MASK (0xF)
421#define CODEC_F1C_DEVICE_SHIFT (20)
422#define CODEC_F1C_DEVICE_LINE_OUT (0)
423#define CODEC_F1C_DEVICE_SPEAKER (0x1)
424#define CODEC_F1C_DEVICE_HP (0x2)
425#define CODEC_F1C_DEVICE_CD (0x3)
426#define CODEC_F1C_DEVICE_SPDIF_OUT (0x4)
427#define CODEC_F1C_DEVICE_DIGITAL_OTHER_OUT (0x5)
428#define CODEC_F1C_DEVICE_MODEM_LINE_SIDE (0x6)
429#define CODEC_F1C_DEVICE_MODEM_HANDSET_SIDE (0x7)
430#define CODEC_F1C_DEVICE_LINE_IN (0x8)
431#define CODEC_F1C_DEVICE_AUX (0x9)
432#define CODEC_F1C_DEVICE_MIC (0xA)
433#define CODEC_F1C_DEVICE_PHONE (0xB)
434#define CODEC_F1C_DEVICE_SPDIF_IN (0xC)
435#define CODEC_F1C_DEVICE_RESERVED (0xE)
436#define CODEC_F1C_DEVICE_OTHER (0xF)
437
438/* Configuration default: Connection type */
439#define CODEC_F1C_CONNECTION_TYPE_MASK (0xF)
440#define CODEC_F1C_CONNECTION_TYPE_SHIFT (16)
441
442#define CODEC_F1C_CONNECTION_TYPE_UNKNOWN (0)
443#define CODEC_F1C_CONNECTION_TYPE_1_8INCHES (0x1)
444#define CODEC_F1C_CONNECTION_TYPE_1_4INCHES (0x2)
445#define CODEC_F1C_CONNECTION_TYPE_ATAPI (0x3)
446#define CODEC_F1C_CONNECTION_TYPE_RCA (0x4)
447#define CODEC_F1C_CONNECTION_TYPE_OPTICAL (0x5)
448#define CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL (0x6)
449#define CODEC_F1C_CONNECTION_TYPE_ANALOG (0x7)
450#define CODEC_F1C_CONNECTION_TYPE_DIN (0x8)
451#define CODEC_F1C_CONNECTION_TYPE_XLR (0x9)
452#define CODEC_F1C_CONNECTION_TYPE_RJ_11 (0xA)
453#define CODEC_F1C_CONNECTION_TYPE_COMBO (0xB)
454#define CODEC_F1C_CONNECTION_TYPE_OTHER (0xF)
455
456/* Configuration's color */
457#define CODEC_F1C_COLOR_MASK (0xF)
458#define CODEC_F1C_COLOR_SHIFT (12)
459#define CODEC_F1C_COLOR_UNKNOWN (0)
460#define CODEC_F1C_COLOR_BLACK (0x1)
461#define CODEC_F1C_COLOR_GREY (0x2)
462#define CODEC_F1C_COLOR_BLUE (0x3)
463#define CODEC_F1C_COLOR_GREEN (0x4)
464#define CODEC_F1C_COLOR_RED (0x5)
465#define CODEC_F1C_COLOR_ORANGE (0x6)
466#define CODEC_F1C_COLOR_YELLOW (0x7)
467#define CODEC_F1C_COLOR_PURPLE (0x8)
468#define CODEC_F1C_COLOR_PINK (0x9)
469#define CODEC_F1C_COLOR_RESERVED_0 (0xA)
470#define CODEC_F1C_COLOR_RESERVED_1 (0xB)
471#define CODEC_F1C_COLOR_RESERVED_2 (0xC)
472#define CODEC_F1C_COLOR_RESERVED_3 (0xD)
473#define CODEC_F1C_COLOR_WHITE (0xE)
474#define CODEC_F1C_COLOR_OTHER (0xF)
475
476/* Configuration's misc */
477#define CODEC_F1C_MISC_MASK (0xF)
478#define CODEC_F1C_MISC_SHIFT (8)
479#define CODEC_F1C_MISC_JACK_DETECT (0)
480#define CODEC_F1C_MISC_RESERVED_0 (1)
481#define CODEC_F1C_MISC_RESERVED_1 (2)
482#define CODEC_F1C_MISC_RESERVED_2 (3)
483
484/* Configuration default: Association */
485#define CODEC_F1C_ASSOCIATION_MASK (0xF)
486#define CODEC_F1C_ASSOCIATION_SHIFT (4)
487
488/* Reserved; don't use. */
489#define CODEC_F1C_ASSOCIATION_INVALID 0x0
490#define CODEC_F1C_ASSOCIATION_GROUP_0 0x1
491#define CODEC_F1C_ASSOCIATION_GROUP_1 0x2
492#define CODEC_F1C_ASSOCIATION_GROUP_2 0x3
493#define CODEC_F1C_ASSOCIATION_GROUP_3 0x4
494#define CODEC_F1C_ASSOCIATION_GROUP_4 0x5
495#define CODEC_F1C_ASSOCIATION_GROUP_5 0x6
496#define CODEC_F1C_ASSOCIATION_GROUP_6 0x7
497#define CODEC_F1C_ASSOCIATION_GROUP_7 0x8
498#define CODEC_F1C_ASSOCIATION_GROUP_15 0xF
499
500/* Configuration default: Association Sequence */
501#define CODEC_F1C_SEQ_MASK (0xF)
502#define CODEC_F1C_SEQ_SHIFT (0)
503
504/* Implementation identification (7.3.3.30) */
505#define CODEC_MAKE_F20(bmid, bsku, aid) \
506 ( (((bmid) & 0xFFFF) << 16) \
507 | (((bsku) & 0xFF) << 8) \
508 | (((aid) & 0xFF)) \
509 )
510
511/* macro definition helping in filling the configuration registers. */
512#define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence) \
513 ( ((port_connectivity) << CODEC_F1C_PORT_SHIFT) \
514 | ((location) << CODEC_F1C_LOCATION_SHIFT) \
515 | ((device) << CODEC_F1C_DEVICE_SHIFT) \
516 | ((connection_type) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
517 | ((color) << CODEC_F1C_COLOR_SHIFT) \
518 | ((misc) << CODEC_F1C_MISC_SHIFT) \
519 | ((association) << CODEC_F1C_ASSOCIATION_SHIFT) \
520 | ((sequence)))
521
522
523/*********************************************************************************************************************************
524* Structures and Typedefs *
525*********************************************************************************************************************************/
526/** The F00 parameter length (in dwords). */
527#define CODECNODE_F00_PARAM_LENGTH 20
528/** The F02 parameter length (in dwords). */
529#define CODECNODE_F02_PARAM_LENGTH 16
530
531/**
532 * Common (or core) codec node structure.
533 */
534typedef struct CODECCOMMONNODE
535{
536 /** Node id - 7 bit format */
537 uint8_t id;
538 /** The node name. */
539 char const *pszName;
540 /* PRM 5.3.6 */
541 uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH];
542 uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH];
543} CODECCOMMONNODE;
544typedef CODECCOMMONNODE *PCODECCOMMONNODE;
545AssertCompile(CODECNODE_F00_PARAM_LENGTH == 20); /* saved state */
546AssertCompile(CODECNODE_F02_PARAM_LENGTH == 16); /* saved state */
547
548/**
549 * Compile time assertion on the expected node size.
550 */
551#define AssertNodeSize(a_Node, a_cParams) \
552 AssertCompile((a_cParams) <= (60 + 6)); /* the max size - saved state */ \
553 AssertCompile( sizeof(a_Node) - sizeof(CODECCOMMONNODE) \
554 == (((a_cParams) * sizeof(uint32_t) + sizeof(void *) - 1) & ~(sizeof(void *) - 1)) )
555
556typedef struct ROOTCODECNODE
557{
558 CODECCOMMONNODE node;
559} ROOTCODECNODE, *PROOTCODECNODE;
560AssertNodeSize(ROOTCODECNODE, 0);
561
562#define AMPLIFIER_SIZE 60
563typedef uint32_t AMPLIFIER[AMPLIFIER_SIZE];
564#define AMPLIFIER_IN 0
565#define AMPLIFIER_OUT 1
566#define AMPLIFIER_LEFT 1
567#define AMPLIFIER_RIGHT 0
568#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)])
569typedef struct DACNODE
570{
571 CODECCOMMONNODE node;
572 uint32_t u32F0d_param;
573 uint32_t u32F04_param;
574 uint32_t u32F05_param;
575 uint32_t u32F06_param;
576 uint32_t u32F0c_param;
577
578 uint32_t u32A_param;
579 AMPLIFIER B_params;
580
581} DACNODE, *PDACNODE;
582AssertNodeSize(DACNODE, 6 + 60);
583
584typedef struct ADCNODE
585{
586 CODECCOMMONNODE node;
587 uint32_t u32F03_param;
588 uint32_t u32F05_param;
589 uint32_t u32F06_param;
590 uint32_t u32F09_param;
591
592 uint32_t u32A_param;
593 uint32_t u32F01_param;
594 AMPLIFIER B_params;
595} ADCNODE, *PADCNODE;
596AssertNodeSize(DACNODE, 6 + 60);
597
598typedef struct SPDIFOUTNODE
599{
600 CODECCOMMONNODE node;
601 uint32_t u32F05_param;
602 uint32_t u32F06_param;
603 uint32_t u32F09_param;
604 uint32_t u32F0d_param;
605
606 uint32_t u32A_param;
607 AMPLIFIER B_params;
608} SPDIFOUTNODE, *PSPDIFOUTNODE;
609AssertNodeSize(SPDIFOUTNODE, 5 + 60);
610
611typedef struct SPDIFINNODE
612{
613 CODECCOMMONNODE node;
614 uint32_t u32F05_param;
615 uint32_t u32F06_param;
616 uint32_t u32F09_param;
617 uint32_t u32F0d_param;
618
619 uint32_t u32A_param;
620 AMPLIFIER B_params;
621} SPDIFINNODE, *PSPDIFINNODE;
622AssertNodeSize(SPDIFINNODE, 5 + 60);
623
624typedef struct AFGCODECNODE
625{
626 CODECCOMMONNODE node;
627 uint32_t u32F05_param;
628 uint32_t u32F08_param;
629 uint32_t u32F20_param;
630 uint32_t u32F17_param;
631} AFGCODECNODE, *PAFGCODECNODE;
632AssertNodeSize(AFGCODECNODE, 4);
633
634typedef struct PORTNODE
635{
636 CODECCOMMONNODE node;
637 uint32_t u32F07_param;
638 uint32_t u32F08_param;
639 uint32_t u32F09_param;
640 uint32_t u32F01_param;
641 uint32_t u32F1c_param;
642 AMPLIFIER B_params;
643} PORTNODE, *PPORTNODE;
644AssertNodeSize(PORTNODE, 5 + 60);
645
646typedef struct DIGOUTNODE
647{
648 CODECCOMMONNODE node;
649 uint32_t u32F01_param;
650 uint32_t u32F08_param;
651 uint32_t u32F07_param;
652 uint32_t u32F09_param;
653 uint32_t u32F1c_param;
654} DIGOUTNODE, *PDIGOUTNODE;
655AssertNodeSize(DIGOUTNODE, 5);
656
657typedef struct DIGINNODE
658{
659 CODECCOMMONNODE node;
660 uint32_t u32F05_param;
661 uint32_t u32F07_param;
662 uint32_t u32F08_param;
663 uint32_t u32F09_param;
664 uint32_t u32F0c_param;
665 uint32_t u32F1c_param;
666 uint32_t u32F1e_param;
667} DIGINNODE, *PDIGINNODE;
668AssertNodeSize(DIGINNODE, 7);
669
670typedef struct ADCMUXNODE
671{
672 CODECCOMMONNODE node;
673 uint32_t u32F01_param;
674
675 uint32_t u32A_param;
676 AMPLIFIER B_params;
677} ADCMUXNODE, *PADCMUXNODE;
678AssertNodeSize(ADCMUXNODE, 2 + 60);
679
680typedef struct PCBEEPNODE
681{
682 CODECCOMMONNODE node;
683 uint32_t u32F07_param;
684 uint32_t u32F0a_param;
685
686 uint32_t u32A_param;
687 AMPLIFIER B_params;
688 uint32_t u32F1c_param;
689} PCBEEPNODE, *PPCBEEPNODE;
690AssertNodeSize(PCBEEPNODE, 3 + 60 + 1);
691
692typedef struct CDNODE
693{
694 CODECCOMMONNODE node;
695 uint32_t u32F07_param;
696 uint32_t u32F1c_param;
697} CDNODE, *PCDNODE;
698AssertNodeSize(CDNODE, 2);
699
700typedef struct VOLUMEKNOBNODE
701{
702 CODECCOMMONNODE node;
703 uint32_t u32F08_param;
704 uint32_t u32F0f_param;
705} VOLUMEKNOBNODE, *PVOLUMEKNOBNODE;
706AssertNodeSize(VOLUMEKNOBNODE, 2);
707
708typedef struct ADCVOLNODE
709{
710 CODECCOMMONNODE node;
711 uint32_t u32F0c_param;
712 uint32_t u32F01_param;
713 uint32_t u32A_params;
714 AMPLIFIER B_params;
715} ADCVOLNODE, *PADCVOLNODE;
716AssertNodeSize(ADCVOLNODE, 3 + 60);
717
718typedef struct RESNODE
719{
720 CODECCOMMONNODE node;
721 uint32_t u32F05_param;
722 uint32_t u32F06_param;
723 uint32_t u32F07_param;
724 uint32_t u32F1c_param;
725} RESNODE, *PRESNODE;
726AssertNodeSize(RESNODE, 4);
727
728/**
729 * Used for the saved state.
730 */
731typedef struct CODECSAVEDSTATENODE
732{
733 CODECCOMMONNODE Core;
734 uint32_t au32Params[60 + 6];
735} CODECSAVEDSTATENODE;
736AssertNodeSize(CODECSAVEDSTATENODE, 60 + 6);
737
738typedef union CODECNODE
739{
740 CODECCOMMONNODE node;
741 ROOTCODECNODE root;
742 AFGCODECNODE afg;
743 DACNODE dac;
744 ADCNODE adc;
745 SPDIFOUTNODE spdifout;
746 SPDIFINNODE spdifin;
747 PORTNODE port;
748 DIGOUTNODE digout;
749 DIGINNODE digin;
750 ADCMUXNODE adcmux;
751 PCBEEPNODE pcbeep;
752 CDNODE cdnode;
753 VOLUMEKNOBNODE volumeKnob;
754 ADCVOLNODE adcvol;
755 RESNODE reserved;
756 CODECSAVEDSTATENODE SavedState;
757} CODECNODE, *PCODECNODE;
758AssertNodeSize(CODECNODE, 60 + 6);
759
760
761/*********************************************************************************************************************************
762* Global Variables *
763*********************************************************************************************************************************/
764/* STAC9220 - Nodes IDs / names. */
765#define STAC9220_NID_ROOT 0x0 /* Root node */
766#define STAC9220_NID_AFG 0x1 /* Audio Configuration Group */
767#define STAC9220_NID_DAC0 0x2 /* Out */
768#define STAC9220_NID_DAC1 0x3 /* Out */
769#define STAC9220_NID_DAC2 0x4 /* Out */
770#define STAC9220_NID_DAC3 0x5 /* Out */
771#define STAC9220_NID_ADC0 0x6 /* In */
772#define STAC9220_NID_ADC1 0x7 /* In */
773#define STAC9220_NID_SPDIF_OUT 0x8 /* Out */
774#define STAC9220_NID_SPDIF_IN 0x9 /* In */
775#define STAC9220_NID_PIN_HEADPHONE0 0xA /* In, Out */
776#define STAC9220_NID_PIN_B 0xB /* In, Out */
777#define STAC9220_NID_PIN_C 0xC /* In, Out */
778#define STAC9220_NID_PIN_HEADPHONE1 0xD /* In, Out */
779#define STAC9220_NID_PIN_E 0xE /* In */
780#define STAC9220_NID_PIN_F 0xF /* In, Out */
781#define STAC9220_NID_PIN_SPDIF_OUT 0x10 /* Out */
782#define STAC9220_NID_PIN_SPDIF_IN 0x11 /* In */
783#define STAC9220_NID_ADC0_MUX 0x12 /* In */
784#define STAC9220_NID_ADC1_MUX 0x13 /* In */
785#define STAC9220_NID_PCBEEP 0x14 /* Out */
786#define STAC9220_NID_PIN_CD 0x15 /* In */
787#define STAC9220_NID_VOL_KNOB 0x16
788#define STAC9220_NID_AMP_ADC0 0x17 /* In */
789#define STAC9220_NID_AMP_ADC1 0x18 /* In */
790/* STAC9221. */
791#define STAC9221_NID_ADAT_OUT 0x19 /* Out */
792#define STAC9221_NID_I2S_OUT 0x1A /* Out */
793#define STAC9221_NID_PIN_I2S_OUT 0x1B /* Out */
794
795#if 1
796/* STAC9220 - Referenced thru STAC9220WIDGET in the constructor below. */
797static uint8_t const g_abStac9220Ports[] = { 0x0A, 0xB, 0xC, 0xD, 0xE, 0xF, 0};
798static uint8_t const g_abStac9220Dacs[] = { 0x02, 0x3, 0x4, 0x5, 0};
799static uint8_t const g_abStac9220Adcs[] = { 0x06, 0x7, 0};
800static uint8_t const g_abStac9220SpdifOuts[] = { 0x08, 0 };
801static uint8_t const g_abStac9220SpdifIns[] = { 0x09, 0 };
802static uint8_t const g_abStac9220DigOutPins[] = { 0x10, 0 };
803static uint8_t const g_abStac9220DigInPins[] = { 0x11, 0 };
804static uint8_t const g_abStac9220AdcVols[] = { 0x17, 0x18, 0};
805static uint8_t const g_abStac9220AdcMuxs[] = { 0x12, 0x13, 0};
806static uint8_t const g_abStac9220Pcbeeps[] = { 0x14, 0 };
807static uint8_t const g_abStac9220Cds[] = { 0x15, 0 };
808static uint8_t const g_abStac9220VolKnobs[] = { 0x16, 0 };
809static uint8_t const g_abStac9220Reserveds[] = { 0x09, 0x19, 0x1a, 0x1b, 0 };
810#else /** @todo Enable this after 5.0 -- needs more testing first. */
811static 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};
812static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0};
813static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0};
814static uint8_t const g_abStac9220SpdifOuts[] = { STAC9220_NID_SPDIF_OUT, 0 };
815static uint8_t const g_abStac9220SpdifIns[] = { STAC9220_NID_SPDIF_IN, 0 };
816static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
817static uint8_t const g_abStac9220DigInPins[] = { STAC9220_NID_PIN_SPDIF_IN, 0 };
818static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0};
819static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0};
820static uint8_t const g_abStac9220Pcbeeps[] = { STAC9220_NID_PCBEEP, 0 };
821static uint8_t const g_abStac9220Cds[] = { STAC9220_NID_PIN_CD, 0 };
822static uint8_t const g_abStac9220VolKnobs[] = { STAC9220_NID_VOL_KNOB, 0 };
823/* STAC 9221. */
824/** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
825static uint8_t const g_abStac9220Reserveds[] = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
826#endif
827
828/** SSM description of a CODECNODE. */
829static SSMFIELD const g_aCodecNodeFields[] =
830{
831 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id),
832 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
833 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
834 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
835 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
836 SSMFIELD_ENTRY_TERM()
837};
838
839/** Backward compatibility with v1 of the CODECNODE. */
840static SSMFIELD const g_aCodecNodeFieldsV1[] =
841{
842 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id),
843 SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
844 SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
845 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
846 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
847 SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
848 SSMFIELD_ENTRY_TERM()
849};
850
851
852
853
854static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
855{
856 for (int i = 1; i < 12; i++)
857 {
858 PCODECNODE pNode = &pThis->paNodes[i];
859 AMPLIFIER *pAmp = &pNode->dac.B_params;
860
861 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) & 0x7f;
862 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) & 0x7f;
863
864 pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
865 }
866}
867
868
869static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t nodenum, PCODECNODE pNode)
870{
871 pNode->node.id = nodenum;
872 pNode->node.au32F00_param[0xF] = 0; /* Power statest Supported: are the same as AFG reports */
873 switch (nodenum)
874 {
875 /* Root Node*/
876 case 0:
877 pNode->node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */
878 break;
879 case 1:
880 pNode->node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
881 pNode->node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
882 | CODEC_F00_0C_CAP_BALANCED_IO
883 | CODEC_F00_0C_CAP_INPUT
884 | CODEC_F00_0C_CAP_PRESENSE_DETECT
885 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
886 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//(17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0);
887 pNode->node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
888 pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(1, 0x5, 0xE, 0);//RT_BIT(31)|(0x5 << 16)|(0xE)<<8;
889 pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f;
890 pNode->node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);//0xc0000004;
891 pNode->node.au32F00_param[0x0F] = CODEC_F00_0F_D3|CODEC_F00_0F_D2|CODEC_F00_0F_D1|CODEC_F00_0F_D0;
892 pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2);//0x2 << 4| 0x2; /* PS-Act: D3, PS->Set D3 */
893 pNode->afg.u32F08_param = 0;
894 pNode->afg.u32F17_param = 0;
895 break;
896 case 2:
897 case 3:
898 case 4:
899 case 5:
900 memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE);
901 pNode->dac.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 4)|0x1; /* 44100Hz/16bit/2ch */
902
903 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
904 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
905
906 pNode->dac.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0xD, 0)
907 | CODEC_F00_09_CAP_L_R_SWAP
908 | CODEC_F00_09_CAP_POWER_CTRL
909 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
910 | CODEC_F00_09_CAP_LSB;//(0xD << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0);
911 pNode->dac.u32F0c_param = 0;
912 pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3 */
913 break;
914 case 6:
915 pNode->node.au32F02_param[0] = 0x17;
916 goto adc_init;
917 case 7:
918 pNode->node.au32F02_param[0] = 0x18;
919 adc_init:
920 pNode->adc.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 3)|0x1; /* 44100Hz/16bit/2ch */
921 pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
922 pNode->adc.u32F03_param = RT_BIT(0);
923 pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */
924 pNode->adc.u32F06_param = 0;
925 pNode->adc.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
926 | CODEC_F00_09_CAP_POWER_CTRL
927 | CODEC_F00_09_CAP_CONNECTION_LIST
928 | CODEC_F00_09_CAP_PROC_WIDGET
929 | CODEC_F00_09_CAP_LSB;//RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0);
930 break;
931 case 8:
932 pNode->spdifout.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(1<<14)|(0x1<<4) | 0x1;
933 pNode->spdifout.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x4, 0)
934 | CODEC_F00_09_CAP_DIGITAL
935 | CODEC_F00_09_CAP_FMT_OVERRIDE
936 | CODEC_F00_09_CAP_LSB;//(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
937 pNode->node.au32F00_param[0xa] = pThis->paNodes[1].node.au32F00_param[0xA];
938 pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
939 pNode->spdifout.u32F06_param = 0;
940 pNode->spdifout.u32F0d_param = 0;
941 break;
942 case 9:
943 pNode->spdifin.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(0x1<<4) | 0x1;
944 pNode->spdifin.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0x4, 0)
945 | CODEC_F00_09_CAP_DIGITAL
946 | CODEC_F00_09_CAP_CONNECTION_LIST
947 | CODEC_F00_09_CAP_FMT_OVERRIDE
948 | CODEC_F00_09_CAP_LSB;//(0x1 << 20)|(4 << 16) | RT_BIT(9)| RT_BIT(8)|RT_BIT(4)|0x1;
949 pNode->node.au32F00_param[0xA] = pThis->paNodes[1].node.au32F00_param[0xA];
950 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
951 pNode->node.au32F02_param[0] = 0x11;
952 pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
953 pNode->spdifin.u32F06_param = 0;
954 pNode->spdifin.u32F0d_param = 0;
955 break;
956 case 0xA:
957 pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
958 | CODEC_F00_0C_CAP_INPUT
959 | CODEC_F00_0C_CAP_OUTPUT
960 | CODEC_F00_0C_CAP_HP
961 | CODEC_F00_0C_CAP_PRESENSE_DETECT
962 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
963 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x173f;
964 pNode->node.au32F02_param[0] = 0x2;
965 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
966 | CODEC_F07_OUT_ENABLE;
967 pNode->port.u32F08_param = 0;
968 if (!pThis->fInReset)
969 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
970 CODEC_F1C_LOCATION_FRONT,
971 CODEC_F1C_DEVICE_HP,
972 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
973 CODEC_F1C_COLOR_GREEN,
974 CODEC_F1C_MISC_JACK_DETECT,
975 0x2, 0);//RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02);
976 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
977 goto port_init;
978 case 0xB:
979 pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
980 | CODEC_F00_0C_CAP_INPUT
981 | CODEC_F00_0C_CAP_OUTPUT
982 | CODEC_F00_0C_CAP_PRESENSE_DETECT
983 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
984 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
985 pNode->node.au32F02_param[0] = 0x4;
986 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
987 if (!pThis->fInReset)
988 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
989 CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR,
990 CODEC_F1C_DEVICE_SPEAKER,
991 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
992 CODEC_F1C_COLOR_BLACK,
993 CODEC_F1C_MISC_JACK_DETECT,
994 0x1, 0x1);//RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01);
995 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
996 goto port_init;
997 case 0xC:
998 pNode->node.au32F02_param[0] = 0x3;
999 pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1000 | CODEC_F00_0C_CAP_INPUT
1001 | CODEC_F00_0C_CAP_OUTPUT
1002 | CODEC_F00_0C_CAP_PRESENSE_DETECT
1003 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
1004 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
1005 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
1006 if (!pThis->fInReset)
1007 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1008 CODEC_F1C_LOCATION_REAR,
1009 CODEC_F1C_DEVICE_SPEAKER,
1010 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1011 CODEC_F1C_COLOR_GREEN,
1012 0x0, 0x1, 0x0);//RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01);
1013 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
1014 goto port_init;
1015 case 0xD:
1016 pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
1017 | CODEC_F00_0C_CAP_INPUT
1018 | CODEC_F00_0C_CAP_OUTPUT
1019 | CODEC_F00_0C_CAP_PRESENSE_DETECT
1020 | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
1021 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
1022 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
1023 pNode->node.au32F02_param[0] = 0x2;
1024 if (!pThis->fInReset)
1025 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1026 CODEC_F1C_LOCATION_FRONT,
1027 CODEC_F1C_DEVICE_MIC,
1028 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1029 CODEC_F1C_COLOR_PINK,
1030 0x0, 0x5, 0x0);//RT_MAKE_U32_FROM_U8(0x50, 0x90, 0xA1, 0x02); /* Microphone */
1031 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
1032 port_init:
1033 pNode->port.u32F08_param = 0;
1034 pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
1035 | CODEC_F00_09_CAP_CONNECTION_LIST
1036 | CODEC_F00_09_CAP_UNSOL
1037 | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
1038 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
1039 break;
1040 case 0xE:
1041 pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
1042 | CODEC_F00_09_CAP_UNSOL
1043 | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(7)|RT_BIT(0);
1044 pNode->port.u32F08_param = 0;
1045 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
1046 | CODEC_F00_0C_CAP_OUTPUT
1047 | CODEC_F00_0C_CAP_PRESENSE_DETECT;//0x34;
1048 pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
1049 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
1050 if (!pThis->fInReset)
1051 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1052 CODEC_F1C_LOCATION_REAR,
1053 CODEC_F1C_DEVICE_LINE_OUT,
1054 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1055 CODEC_F1C_COLOR_BLUE,
1056 0x0, 0x4, 0x0);//0x01013040; /* Line Out */
1057 break;
1058 case 0xF:
1059 pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
1060 | CODEC_F00_09_CAP_CONNECTION_LIST
1061 | CODEC_F00_09_CAP_UNSOL
1062 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1063 | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(2)|RT_BIT(0);
1064 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
1065 | CODEC_F00_0C_CAP_OUTPUT
1066 | CODEC_F00_0C_CAP_PRESENSE_DETECT
1067 /* | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
1068 | CODEC_F00_0C_CAP_IMPENDANCE_SENSE */;//0x37;
1069 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
1070 pNode->port.u32F08_param = 0;
1071 pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE
1072 | CODEC_F07_IN_ENABLE;
1073 if (!pThis->fInReset)
1074 pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1075 CODEC_F1C_LOCATION_INTERNAL,
1076 CODEC_F1C_DEVICE_SPEAKER,
1077 CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
1078 CODEC_F1C_COLOR_ORANGE,
1079 0x0, 0x1, 0x2);//RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01);
1080 pNode->node.au32F02_param[0] = 0x5;
1081 pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
1082 break;
1083 case 0x10:
1084 pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
1085 | CODEC_F00_09_CAP_DIGITAL
1086 | CODEC_F00_09_CAP_CONNECTION_LIST
1087 | CODEC_F00_09_CAP_LSB;//(4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
1088 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//RT_BIT(4);
1089 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x3);
1090 pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0);
1091 if (!pThis->fInReset)
1092 pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1093 CODEC_F1C_LOCATION_REAR,
1094 CODEC_F1C_DEVICE_SPDIF_OUT,
1095 CODEC_F1C_CONNECTION_TYPE_DIN,
1096 CODEC_F1C_COLOR_BLACK,
1097 0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
1098 break;
1099 case 0x11:
1100 pNode->node.au32F00_param[9] = (4 << 20) | (3 << 16) | RT_BIT(10) | RT_BIT(9) | RT_BIT(7) | RT_BIT(0);
1101 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
1102 | CODEC_F00_0C_CAP_INPUT
1103 | CODEC_F00_0C_CAP_PRESENSE_DETECT;//RT_BIT(16)| RT_BIT(5)|RT_BIT(2);
1104 pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */
1105 pNode->digin.u32F07_param = 0;
1106 pNode->digin.u32F08_param = 0;
1107 pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
1108 pNode->digin.u32F0c_param = 0;
1109 if (!pThis->fInReset)
1110 pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
1111 CODEC_F1C_LOCATION_REAR,
1112 CODEC_F1C_DEVICE_SPDIF_IN,
1113 CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
1114 CODEC_F1C_COLOR_BLACK,
1115 0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60;
1116 break;
1117 case 0x12:
1118 pNode->adcmux.u32F01_param = 0;
1119 goto adcmux_init;
1120 case 0x13:
1121 pNode->adcmux.u32F01_param = 1;
1122 adcmux_init:
1123 pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0x0, 0)
1124 | CODEC_F00_09_CAP_CONNECTION_LIST
1125 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
1126 | CODEC_F00_09_CAP_OUT_AMP_PRESENT
1127 | CODEC_F00_09_CAP_LSB;//(3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0);
1128 pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x7);
1129 pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8);
1130 /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/
1131 memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE);
1132 pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb);
1133 pNode->node.au32F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0);
1134 break;
1135 case 0x14:
1136 pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
1137 | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
1138 | CODEC_F00_09_CAP_OUT_AMP_PRESENT;//(7 << 20) | RT_BIT(3) | RT_BIT(2);
1139 pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3;
1140 pNode->pcbeep.u32F0a_param = 0;
1141 memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
1142 break;
1143 case 0x15:
1144 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1145 | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(0);
1146 pNode->node.au32F00_param[0xc] = CODEC_F00_0C_CAP_INPUT;//RT_BIT(5);
1147 if (!pThis->fInReset)
1148 pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
1149 CODEC_F1C_LOCATION_INTERNAL,
1150 CODEC_F1C_DEVICE_CD,
1151 CODEC_F1C_CONNECTION_TYPE_ATAPI,
1152 CODEC_F1C_COLOR_UNKNOWN,
1153 0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90);
1154 break;
1155 case 0x16:
1156 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0x0, 0x0);//(0x6 << 20);
1157 pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F;
1158 pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x4);
1159 pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5);
1160 pNode->volumeKnob.u32F08_param = 0;
1161 pNode->volumeKnob.u32F0f_param = 0x7f;
1162 break;
1163 case 0x17:
1164 pNode->node.au32F02_param[0] = 0x12;
1165 goto adcvol_init;
1166 case 0x18:
1167 pNode->node.au32F02_param[0] = 0x13;
1168 adcvol_init:
1169 memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
1170
1171 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
1172 | CODEC_F00_09_CAP_L_R_SWAP
1173 | CODEC_F00_09_CAP_CONNECTION_LIST
1174 | CODEC_F00_09_CAP_IN_AMP_PRESENT
1175 | CODEC_F00_09_CAP_LSB;//(0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0);
1176 pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x1);
1177 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
1178 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
1179 pNode->adcvol.u32F0c_param = 0;
1180 break;
1181 case 0x19:
1182 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0)
1183 | CODEC_F00_09_CAP_DIGITAL
1184 | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
1185 break;
1186 case 0x1A:
1187 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0)
1188 | CODEC_F00_09_CAP_DIGITAL
1189 | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
1190 break;
1191 case 0x1B:
1192 pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
1193 | CODEC_F00_09_CAP_DIGITAL
1194 | CODEC_F00_09_CAP_CONNECTION_LIST
1195 | CODEC_F00_09_CAP_LSB;//(0x4 << 20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
1196 pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x1);
1197 pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//0x10;
1198 pNode->node.au32F02_param[0] = 0x1a;
1199 pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
1200 CODEC_F1C_LOCATION_NA,
1201 CODEC_F1C_DEVICE_LINE_OUT,
1202 CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
1203 CODEC_F1C_COLOR_UNKNOWN,
1204 0x0, 0x0, 0xf);//0x4000000f;
1205 break;
1206 default:
1207 break;
1208 }
1209 return VINF_SUCCESS;
1210}
1211
1212
1213static int stac9220Construct(PHDACODEC pThis)
1214{
1215 unconst(pThis->cTotalNodes) = 0x1C;
1216 pThis->pfnCodecNodeReset = stac9220ResetNode;
1217 pThis->pfnDbgListNodes = stac9220DbgNodes;
1218 pThis->u16VendorId = 0x8384;
1219 pThis->u16DeviceId = 0x7680;
1220 pThis->u8BSKU = 0x76;
1221 pThis->u8AssemblyId = 0x80;
1222 pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes);
1223 if (!pThis->paNodes)
1224 return VERR_NO_MEMORY;
1225 pThis->fInReset = false;
1226#define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s
1227 STAC9220WIDGET(Port);
1228 STAC9220WIDGET(Dac);
1229 STAC9220WIDGET(Adc);
1230 STAC9220WIDGET(AdcVol);
1231 STAC9220WIDGET(AdcMux);
1232 STAC9220WIDGET(Pcbeep);
1233 STAC9220WIDGET(SpdifIn);
1234 STAC9220WIDGET(SpdifOut);
1235 STAC9220WIDGET(DigInPin);
1236 STAC9220WIDGET(DigOutPin);
1237 STAC9220WIDGET(Cd);
1238 STAC9220WIDGET(VolKnob);
1239 STAC9220WIDGET(Reserved);
1240#undef STAC9220WIDGET
1241 unconst(pThis->u8AdcVolsLineIn) = 0x17;
1242 unconst(pThis->u8DacLineOut) = 0x3;
1243
1244 return VINF_SUCCESS;
1245}
1246
1247
1248/*
1249 * Some generic predicate functions.
1250 */
1251
1252#define DECLISNODEOFTYPE(type) \
1253 DECLINLINE(int) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
1254 { \
1255 Assert(pThis->au8##type##s); \
1256 for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
1257 if (pThis->au8##type##s[i] == cNode) \
1258 return 1; \
1259 return 0; \
1260 }
1261/* hdaCodecIsPortNode */
1262DECLISNODEOFTYPE(Port)
1263/* hdaCodecIsDacNode */
1264DECLISNODEOFTYPE(Dac)
1265/* hdaCodecIsAdcVolNode */
1266DECLISNODEOFTYPE(AdcVol)
1267/* hdaCodecIsAdcNode */
1268DECLISNODEOFTYPE(Adc)
1269/* hdaCodecIsAdcMuxNode */
1270DECLISNODEOFTYPE(AdcMux)
1271/* hdaCodecIsPcbeepNode */
1272DECLISNODEOFTYPE(Pcbeep)
1273/* hdaCodecIsSpdifOutNode */
1274DECLISNODEOFTYPE(SpdifOut)
1275/* hdaCodecIsSpdifInNode */
1276DECLISNODEOFTYPE(SpdifIn)
1277/* hdaCodecIsDigInPinNode */
1278DECLISNODEOFTYPE(DigInPin)
1279/* hdaCodecIsDigOutPinNode */
1280DECLISNODEOFTYPE(DigOutPin)
1281/* hdaCodecIsCdNode */
1282DECLISNODEOFTYPE(Cd)
1283/* hdaCodecIsVolKnobNode */
1284DECLISNODEOFTYPE(VolKnob)
1285/* hdaCodecIsReservedNode */
1286DECLISNODEOFTYPE(Reserved)
1287
1288
1289/*
1290 * Misc helpers.
1291 */
1292static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL mt)
1293{
1294 uint32_t dir = AMPLIFIER_OUT;
1295 ENMSOUNDSOURCE enmSrc;
1296 switch (mt)
1297 {
1298 case PDMAUDIOMIXERCTL_PCM:
1299 enmSrc = PO_INDEX;
1300 dir = AMPLIFIER_OUT;
1301 break;
1302 case PDMAUDIOMIXERCTL_LINE_IN:
1303 enmSrc = PI_INDEX;
1304 dir = AMPLIFIER_IN;
1305 break;
1306 default:
1307 AssertMsgFailedReturn(("Invalid mixer control %ld\n", mt), VERR_INVALID_PARAMETER);
1308 break;
1309 }
1310
1311 int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
1312 mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
1313 mute >>=7;
1314 mute &= 0x1;
1315 uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f;
1316 uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f;
1317
1318 /* The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
1319 * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
1320 * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
1321 * to 1 (rather than zero) internally.
1322 */
1323 lVol = (lVol + 1) * (2 * 255) / 256;
1324 rVol = (rVol + 1) * (2 * 255) / 256;
1325
1326 return pThis->pfnSetVolume(pThis->pHDAState, enmSrc, RT_BOOL(mute), lVol, rVol);
1327}
1328
1329DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
1330{
1331 Assert((pu32Reg && u8Offset < 32));
1332 *pu32Reg &= ~(mask << u8Offset);
1333 *pu32Reg |= (u32Cmd & mask) << u8Offset;
1334}
1335
1336DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
1337{
1338 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
1339}
1340
1341DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
1342{
1343 hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
1344}
1345
1346
1347/*
1348 * Verb processor functions.
1349 */
1350
1351static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1352{
1353 LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
1354 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
1355 *pResp = 0;
1356 return VINF_SUCCESS;
1357}
1358
1359static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1360{
1361 int rc;
1362 rc = vrbProcUnimplemented(pThis, cmd, pResp);
1363 *pResp |= CODEC_RESPONSE_UNSOLICITED;
1364 return rc;
1365}
1366
1367/* B-- */
1368static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1369{
1370 Assert(CODEC_CAD(cmd) == pThis->id);
1371 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1372 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1373 {
1374 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1375 return VINF_SUCCESS;
1376 }
1377 *pResp = 0;
1378 /* HDA spec 7.3.3.7 Note A */
1379 /** @todo: if index out of range response should be 0 */
1380 uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd);
1381
1382 PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
1383 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1384 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
1385 CODEC_GET_AMP_DIRECTION(cmd),
1386 CODEC_GET_AMP_SIDE(cmd),
1387 u8Index);
1388 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1389 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
1390 CODEC_GET_AMP_DIRECTION(cmd),
1391 CODEC_GET_AMP_SIDE(cmd),
1392 u8Index);
1393 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1394 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
1395 CODEC_GET_AMP_DIRECTION(cmd),
1396 CODEC_GET_AMP_SIDE(cmd),
1397 u8Index);
1398 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1399 *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
1400 CODEC_GET_AMP_DIRECTION(cmd),
1401 CODEC_GET_AMP_SIDE(cmd),
1402 u8Index);
1403 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1404 *pResp = AMPLIFIER_REGISTER(pNode->port.B_params,
1405 CODEC_GET_AMP_DIRECTION(cmd),
1406 CODEC_GET_AMP_SIDE(cmd),
1407 u8Index);
1408 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1409 *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
1410 CODEC_GET_AMP_DIRECTION(cmd),
1411 CODEC_GET_AMP_SIDE(cmd),
1412 u8Index);
1413 else
1414 AssertMsgFailedReturn(("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS);
1415 return VINF_SUCCESS;
1416}
1417
1418/* 3-- */
1419static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1420{
1421 bool fIsLeft = false;
1422 bool fIsRight = false;
1423 bool fIsOut = false;
1424 bool fIsIn = false;
1425 uint8_t u8Index = 0;
1426 Assert(CODEC_CAD(cmd) == pThis->id);
1427 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1428 {
1429 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1430 return VINF_SUCCESS;
1431 }
1432 *pResp = 0;
1433 PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
1434 AMPLIFIER *pAmplifier;
1435 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1436 pAmplifier = &pNode->dac.B_params;
1437 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1438 pAmplifier = &pNode->adcvol.B_params;
1439 else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1440 pAmplifier = &pNode->adcmux.B_params;
1441 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1442 pAmplifier = &pNode->pcbeep.B_params;
1443 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1444 pAmplifier = &pNode->port.B_params;
1445 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1446 pAmplifier = &pNode->adc.B_params;
1447 else
1448 AssertFailedReturn(VINF_SUCCESS);
1449
1450 fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
1451 fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
1452 fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
1453 fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
1454 u8Index = CODEC_SET_AMP_INDEX(cmd);
1455 if ( (!fIsLeft && !fIsRight)
1456 || (!fIsOut && !fIsIn))
1457 return VINF_SUCCESS;
1458 if (fIsIn)
1459 {
1460 if (fIsLeft)
1461 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
1462 if (fIsRight)
1463 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1464
1465 /** @todo Fix ID of u8AdcVolsLineIn! */
1466 hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
1467 }
1468 if (fIsOut)
1469 {
1470 if (fIsLeft)
1471 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
1472 if (fIsRight)
1473 hdaCodecSetRegisterU8(&AMPLIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
1474
1475 if (CODEC_NID(cmd) == pThis->u8DacLineOut)
1476 hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_PCM);
1477 }
1478
1479 return VINF_SUCCESS;
1480}
1481
1482static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1483{
1484 Assert(CODEC_CAD(cmd) == pThis->id);
1485 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1486 {
1487 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1488 return VINF_SUCCESS;
1489 }
1490 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
1491 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
1492 {
1493 LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1494 return VINF_SUCCESS;
1495 }
1496 *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
1497 return VINF_SUCCESS;
1498}
1499
1500/* F01 */
1501static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1502{
1503 Assert(CODEC_CAD(cmd) == pThis->id);
1504 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1505 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1506 {
1507 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1508 return VINF_SUCCESS;
1509 }
1510 *pResp = 0;
1511 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1512 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1513 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1514 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
1515 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1516 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
1517 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1518 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
1519 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1520 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1521 return VINF_SUCCESS;
1522}
1523
1524/* 701 */
1525static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1526{
1527 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1528 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1529 {
1530 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1531 return VINF_SUCCESS;
1532 }
1533 *pResp = 0;
1534 uint32_t *pu32Reg;
1535 if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
1536 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
1537 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1538 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
1539 else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1540 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
1541 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1542 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
1543 else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
1544 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
1545 else
1546 AssertFailedReturn(VINF_SUCCESS);
1547 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1548 return VINF_SUCCESS;
1549}
1550
1551/* F07 */
1552static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1553{
1554 Assert(CODEC_CAD(cmd) == pThis->id);
1555 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1556 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1557 {
1558 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1559 return VINF_SUCCESS;
1560 }
1561 *pResp = 0;
1562 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1563 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
1564 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1565 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
1566 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1567 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
1568 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1569 *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1570 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1571 *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1572 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1573 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1574 else
1575 AssertMsgFailed(("Unsupported"));
1576 return VINF_SUCCESS;
1577}
1578
1579/* 707 */
1580static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1581{
1582 Assert(CODEC_CAD(cmd) == pThis->id);
1583 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1584 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1585 {
1586 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1587 return VINF_SUCCESS;
1588 }
1589 *pResp = 0;
1590 uint32_t *pu32Reg;
1591 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1592 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
1593 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1594 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
1595 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1596 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
1597 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
1598 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
1599 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
1600 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
1601 else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))
1602 && CODEC_NID(cmd) == 0x1b)
1603 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
1604 else
1605 AssertFailedReturn(VINF_SUCCESS);
1606 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1607 return VINF_SUCCESS;
1608}
1609
1610/* F08 */
1611static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1612{
1613 Assert(CODEC_CAD(cmd) == pThis->id);
1614 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1615 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1616 {
1617 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1618 return VINF_SUCCESS;
1619 }
1620 *pResp = 0;
1621 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1622 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
1623 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1624 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1625 else if ((cmd) == 1 /* AFG */)
1626 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
1627 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1628 *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1629 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1630 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
1631 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1632 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1633 else
1634 AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
1635 return VINF_SUCCESS;
1636}
1637
1638/* 708 */
1639static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1640{
1641 Assert(CODEC_CAD(cmd) == pThis->id);
1642 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1643 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1644 {
1645 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1646 return VINF_SUCCESS;
1647 }
1648 *pResp = 0;
1649 uint32_t *pu32Reg;
1650 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1651 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
1652 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1653 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1654 else if (CODEC_NID(cmd) == 1 /* AFG */)
1655 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
1656 else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
1657 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
1658 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1659 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
1660 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
1661 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
1662 else
1663 AssertMsgFailedReturn(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)), VINF_SUCCESS);
1664 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1665 return VINF_SUCCESS;
1666}
1667
1668/* F09 */
1669static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1670{
1671 Assert(CODEC_CAD(cmd) == pThis->id);
1672 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1673 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1674 {
1675 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1676 return VINF_SUCCESS;
1677 }
1678 *pResp = 0;
1679 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1680 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
1681 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1682 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
1683 else
1684 AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
1685 return VINF_SUCCESS;
1686}
1687
1688/* 709 */
1689static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1690{
1691 Assert(CODEC_CAD(cmd) == pThis->id);
1692 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1693 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1694 {
1695 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1696 return VINF_SUCCESS;
1697 }
1698 *pResp = 0;
1699 uint32_t *pu32Reg;
1700 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
1701 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
1702 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1703 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
1704 else
1705 AssertFailedReturn(VINF_SUCCESS);
1706 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
1707 return VINF_SUCCESS;
1708}
1709
1710static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1711{
1712 Assert(CODEC_CAD(cmd) == pThis->id);
1713 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1714 *pResp = 0;
1715 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1716 {
1717 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1718 return VINF_SUCCESS;
1719 }
1720 Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
1721 if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
1722 {
1723 LogFlowFunc(("access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
1724 return VINF_SUCCESS;
1725 }
1726 *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA];
1727 return VINF_SUCCESS;
1728}
1729
1730/* F03 */
1731static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1732{
1733 Assert(CODEC_CAD(cmd) == pThis->id);
1734 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1735 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1736 {
1737 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1738 return VINF_SUCCESS;
1739 }
1740 *pResp = 0;
1741 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1742 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param;
1743 return VINF_SUCCESS;
1744}
1745
1746/* 703 */
1747static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1748{
1749 Assert(CODEC_CAD(cmd) == pThis->id);
1750 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1751 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1752 {
1753 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1754 return VINF_SUCCESS;
1755 }
1756 *pResp = 0;
1757 if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1758 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
1759 return VINF_SUCCESS;
1760}
1761
1762/* F0D */
1763static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1764{
1765 Assert(CODEC_CAD(cmd) == pThis->id);
1766 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1767 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1768 {
1769 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1770 return VINF_SUCCESS;
1771 }
1772 *pResp = 0;
1773 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1774 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
1775 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1776 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
1777 return VINF_SUCCESS;
1778}
1779
1780static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
1781{
1782 Assert(CODEC_CAD(cmd) == pThis->id);
1783 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1784 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1785 {
1786 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1787 return VINF_SUCCESS;
1788 }
1789 *pResp = 0;
1790 if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1791 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
1792 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1793 hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
1794 return VINF_SUCCESS;
1795}
1796
1797/* 70D */
1798static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1799{
1800 return codecSetDigitalConverter(pThis, cmd, 0, pResp);
1801}
1802
1803/* 70E */
1804static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1805{
1806 return codecSetDigitalConverter(pThis, cmd, 8, pResp);
1807}
1808
1809/* F20 */
1810static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1811{
1812 Assert(CODEC_CAD(cmd) == pThis->id);
1813 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1814 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1815 {
1816 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1817 return VINF_SUCCESS;
1818 }
1819 if (CODEC_NID(cmd) == 1 /* AFG */)
1820 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
1821 else
1822 *pResp = 0;
1823 return VINF_SUCCESS;
1824}
1825
1826static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
1827{
1828 Assert(CODEC_CAD(cmd) == pThis->id);
1829 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1830 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1831 {
1832 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1833 return VINF_SUCCESS;
1834 }
1835 uint32_t *pu32Reg;
1836 if (CODEC_NID(cmd) == 0x1 /* AFG */)
1837 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
1838 else
1839 AssertFailedReturn(VINF_SUCCESS);
1840 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
1841 return VINF_SUCCESS;
1842}
1843
1844/* 720 */
1845static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1846{
1847 *pResp = 0;
1848 return codecSetSubIdX(pThis, cmd, 0);
1849}
1850
1851/* 721 */
1852static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1853{
1854 *pResp = 0;
1855 return codecSetSubIdX(pThis, cmd, 8);
1856}
1857
1858/* 722 */
1859static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1860{
1861 *pResp = 0;
1862 return codecSetSubIdX(pThis, cmd, 16);
1863}
1864
1865/* 723 */
1866static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1867{
1868 *pResp = 0;
1869 return codecSetSubIdX(pThis, cmd, 24);
1870}
1871
1872static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1873{
1874 Assert(CODEC_CAD(cmd) == pThis->id);
1875 Assert(CODEC_NID(cmd) == 1 /* AFG */);
1876 if ( CODEC_NID(cmd) == 1 /* AFG */
1877 && pThis->pfnCodecNodeReset)
1878 {
1879 uint8_t i;
1880 LogFlowFunc(("enters reset\n"));
1881 Assert(pThis->pfnCodecNodeReset);
1882 for (i = 0; i < pThis->cTotalNodes; ++i)
1883 {
1884 pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
1885 }
1886 pThis->fInReset = false;
1887 LogFlowFunc(("exits reset\n"));
1888 }
1889 *pResp = 0;
1890 return VINF_SUCCESS;
1891}
1892
1893/* F05 */
1894static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1895{
1896 Assert(CODEC_CAD(cmd) == pThis->id);
1897 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1898 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1899 {
1900 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1901 return VINF_SUCCESS;
1902 }
1903 *pResp = 0;
1904 if (CODEC_NID(cmd) == 1 /* AFG */)
1905 *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
1906 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1907 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
1908 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1909 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
1910 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1911 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
1912 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1913 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1914 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1915 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1916 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1917 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1918 return VINF_SUCCESS;
1919}
1920
1921/* 705 */
1922
1923DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
1924{
1925 Assert(pu32F05_param);
1926 if (!pu32F05_param)
1927 return;
1928 bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
1929 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
1930 uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
1931 *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
1932}
1933
1934static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
1935{
1936 Assert(CODEC_CAD(cmd) == pThis->id);
1937 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
1938 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
1939 {
1940 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
1941 return VINF_SUCCESS;
1942 }
1943 *pResp = 0;
1944 uint32_t *pu32Reg;
1945 if (CODEC_NID(cmd) == 1 /* AFG */)
1946 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
1947 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
1948 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
1949 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
1950 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
1951 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
1952 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
1953 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
1954 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
1955 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
1956 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
1957 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
1958 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
1959 else
1960 AssertFailedReturn(VINF_SUCCESS);
1961
1962 bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
1963 bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
1964
1965 if (CODEC_NID(cmd) != 1 /* AFG */)
1966 {
1967 /*
1968 * We shouldn't propogate actual power state, which actual for AFG
1969 */
1970 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
1971 CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param),
1972 CODEC_F05_SET(cmd));
1973 }
1974
1975 /* Propagate next power state only if AFG is on or verb modifies AFG power state */
1976 if ( CODEC_NID(cmd) == 1 /* AFG */
1977 || !CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param))
1978 {
1979 *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
1980 if ( CODEC_NID(cmd) == 1 /* AFG */
1981 && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
1982 {
1983 /* now we're powered on AFG and may propogate power states on nodes */
1984 const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
1985 while (*(++pu8NodeIndex))
1986 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].dac.u32F05_param);
1987
1988 pu8NodeIndex = &pThis->au8Adcs[0];
1989 while (*(++pu8NodeIndex))
1990 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].adc.u32F05_param);
1991
1992 pu8NodeIndex = &pThis->au8DigInPins[0];
1993 while (*(++pu8NodeIndex))
1994 codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].digin.u32F05_param);
1995 }
1996 }
1997 return VINF_SUCCESS;
1998}
1999
2000static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2001{
2002 Assert(CODEC_CAD(cmd) == pThis->id);
2003 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2004 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2005 {
2006 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2007 return VINF_SUCCESS;
2008 }
2009 *pResp = 0;
2010 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2011 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
2012 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2013 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
2014 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2015 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2016 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2017 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2018 else if (CODEC_NID(cmd) == 0x1A)
2019 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
2020 return VINF_SUCCESS;
2021}
2022
2023static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2024{
2025 Assert(CODEC_CAD(cmd) == pThis->id);
2026 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2027 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2028 {
2029 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2030 return VINF_SUCCESS;
2031 }
2032 *pResp = 0;
2033 uint32_t *pu32addr;
2034 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2035 pu32addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
2036 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2037 pu32addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
2038 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2039 pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
2040 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2041 pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
2042 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2043 pu32addr = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
2044 else
2045 AssertFailedReturn(VINF_SUCCESS);
2046 hdaCodecSetRegisterU8(pu32addr, cmd, 0);
2047 return VINF_SUCCESS;
2048}
2049
2050static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2051{
2052 Assert(CODEC_CAD(cmd) == pThis->id);
2053 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2054 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2055 {
2056 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2057 return VINF_SUCCESS;
2058 }
2059 *pResp = 0;
2060 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2061 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param;
2062 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2063 *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param;
2064 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2065 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param;
2066 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2067 *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param;
2068 return VINF_SUCCESS;
2069}
2070
2071static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2072{
2073 Assert(CODEC_CAD(cmd) == pThis->id);
2074 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2075 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2076 {
2077 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2078 return VINF_SUCCESS;
2079 }
2080 *pResp = 0;
2081 if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2082 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
2083 else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
2084 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
2085 else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
2086 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
2087 else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
2088 hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
2089 return VINF_SUCCESS;
2090}
2091
2092/* F0C */
2093static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2094{
2095 Assert(CODEC_CAD(cmd) == pThis->id);
2096 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2097 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2098 {
2099 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2100 return VINF_SUCCESS;
2101 }
2102 *pResp = 0;
2103 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
2104 *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
2105 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2106 *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
2107 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2108 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
2109 return VINF_SUCCESS;
2110}
2111
2112/* 70C */
2113static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2114{
2115 Assert(CODEC_CAD(cmd) == pThis->id);
2116 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2117 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2118 {
2119 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2120 return VINF_SUCCESS;
2121 }
2122
2123 *pResp = 0;
2124 uint32_t *pu32Reg;
2125 if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
2126 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
2127 else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
2128 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
2129 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2130 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
2131 else
2132 AssertFailedReturn(VINF_SUCCESS);
2133 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2134
2135 return VINF_SUCCESS;
2136}
2137
2138/* F0F */
2139static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2140{
2141 Assert(CODEC_CAD(cmd) == pThis->id);
2142 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2143 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2144 {
2145 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2146 return VINF_SUCCESS;
2147 }
2148 *pResp = 0;
2149 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
2150 *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
2151 return VINF_SUCCESS;
2152}
2153
2154/* 70F */
2155static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2156{
2157 Assert(CODEC_CAD(cmd) == pThis->id);
2158 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2159 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2160 {
2161 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2162 return VINF_SUCCESS;
2163 }
2164 uint32_t *pu32Reg = NULL;
2165 *pResp = 0;
2166 if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
2167 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
2168 Assert(pu32Reg);
2169 if (pu32Reg)
2170 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2171 return VINF_SUCCESS;
2172}
2173
2174/* F17 */
2175static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2176{
2177 Assert(CODEC_CAD(cmd) == pThis->id);
2178 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2179 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2180 {
2181 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2182 return VINF_SUCCESS;
2183 }
2184 *pResp = 0;
2185 /* note: this is true for ALC885 */
2186 if (CODEC_NID(cmd) == 0x1 /* AFG */)
2187 *pResp = pThis->paNodes[1].afg.u32F17_param;
2188 return VINF_SUCCESS;
2189}
2190
2191/* 717 */
2192static DECLCALLBACK(int) vrbProcSetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2193{
2194 Assert(CODEC_CAD(cmd) == pThis->id);
2195 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2196 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2197 {
2198 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2199 return VINF_SUCCESS;
2200 }
2201 uint32_t *pu32Reg = NULL;
2202 *pResp = 0;
2203 if (CODEC_NID(cmd) == 1 /* AFG */)
2204 pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
2205 Assert(pu32Reg);
2206 if (pu32Reg)
2207 hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
2208 return VINF_SUCCESS;
2209}
2210
2211/* F1C */
2212static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2213{
2214 Assert(CODEC_CAD(cmd) == pThis->id);
2215 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2216 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2217 {
2218 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2219 return VINF_SUCCESS;
2220 }
2221 *pResp = 0;
2222 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
2223 *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
2224 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2225 *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
2226 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2227 *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
2228 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
2229 *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
2230 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
2231 *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
2232 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2233 *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
2234 return VINF_SUCCESS;
2235}
2236
2237static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
2238{
2239 Assert(CODEC_CAD(cmd) == pThis->id);
2240 Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
2241 if (CODEC_NID(cmd) >= pThis->cTotalNodes)
2242 {
2243 LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
2244 return VINF_SUCCESS;
2245 }
2246 uint32_t *pu32Reg = NULL;
2247 if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
2248 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
2249 else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
2250 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
2251 else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
2252 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
2253 else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
2254 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
2255 else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
2256 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
2257 else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2258 pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
2259 Assert(pu32Reg);
2260 if (pu32Reg)
2261 hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
2262 return VINF_SUCCESS;
2263}
2264
2265/* 71C */
2266static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2267{
2268 *pResp = 0;
2269 return codecSetConfigX(pThis, cmd, 0);
2270}
2271
2272/* 71D */
2273static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2274{
2275 *pResp = 0;
2276 return codecSetConfigX(pThis, cmd, 8);
2277}
2278
2279/* 71E */
2280static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2281{
2282 *pResp = 0;
2283 return codecSetConfigX(pThis, cmd, 16);
2284}
2285
2286/* 71E */
2287static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
2288{
2289 *pResp = 0;
2290 return codecSetConfigX(pThis, cmd, 24);
2291}
2292
2293
2294/**
2295 * HDA codec verb map.
2296 * @todo Any reason not to use binary search here?
2297 */
2298static const CODECVERB g_aCodecVerbs[] =
2299{
2300/* verb | verb mask | callback */
2301/* ----------- -------------------- ----------------------- */
2302 { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter },
2303 { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl },
2304 { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl },
2305 { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId },
2306 { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId },
2307 { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl },
2308 { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl },
2309 { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled },
2310 { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled },
2311 { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense },
2312 { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense },
2313 { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry },
2314 { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState },
2315 { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState },
2316 { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter },
2317 { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 },
2318 { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 },
2319 { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId },
2320 { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 },
2321 { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 },
2322 { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 },
2323 { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 },
2324 { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset },
2325 { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState },
2326 { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState },
2327 { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled },
2328 { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled },
2329 { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl },
2330 { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl },
2331 { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted },
2332 { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted },
2333 { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig },
2334 { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 },
2335 { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 },
2336 { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 },
2337 { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 },
2338 { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat },
2339 { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat },
2340 { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier },
2341 { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier },
2342};
2343
2344#ifdef DEBUG
2345typedef struct CODECDBGINFO
2346{
2347 /** DBGF info helpers. */
2348 PCDBGFINFOHLP pHlp;
2349 /** Current recursion level. */
2350 uint8_t uLevel;
2351 /** Pointer to codec state. */
2352 PHDACODEC pThis;
2353
2354} CODECDBGINFO, *PCODECDBGINFO;
2355
2356#define CODECDBG_INDENT pInfo->uLevel++;
2357#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
2358
2359#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
2360#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
2361
2362static void codecDbgPrintfIndentV(PCODECDBGINFO pInfo, uint16_t uIndent, const char *pszFormat, va_list va)
2363{
2364 char *pszValueFormat;
2365 if (RTStrAPrintfV(&pszValueFormat, pszFormat, va))
2366 {
2367 pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%s", uIndent, "", pszValueFormat);
2368 RTStrFree(pszValueFormat);
2369 }
2370}
2371
2372static void codecDbgPrintf(PCODECDBGINFO pInfo, const char *pszFormat, ...)
2373{
2374 va_list va;
2375 va_start(va, pszFormat);
2376 codecDbgPrintfIndentV(pInfo, pInfo->uLevel * 4, pszFormat, va);
2377 va_end(va);
2378}
2379
2380/* Power state */
2381static void codecDbgPrintNodeRegF05(PCODECDBGINFO pInfo, uint32_t u32Reg)
2382{
2383 codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
2384 CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
2385}
2386
2387static void codecDbgPrintNodeRegA(PCODECDBGINFO pInfo, uint32_t u32Reg)
2388{
2389 codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
2390}
2391
2392static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
2393{
2394 codecDbgPrintf(pInfo, "Parameters (F00):\n");
2395
2396 CODECDBG_INDENT
2397 codecDbgPrintf(pInfo, "Amplifier Caps:\n");
2398 uint32_t uReg = paReg00[0xD];
2399 CODECDBG_INDENT
2400 codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2401 CODEC_F00_0D_NUM_STEPS(uReg),
2402 CODEC_F00_0D_STEP_SIZE(uReg),
2403 CODEC_F00_0D_OFFSET(uReg),
2404 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2405
2406 uReg = paReg00[0x12];
2407 codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
2408 CODEC_F00_12_NUM_STEPS(uReg),
2409 CODEC_F00_12_STEP_SIZE(uReg),
2410 CODEC_F00_12_OFFSET(uReg),
2411 RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
2412 CODECDBG_UNINDENT
2413 CODECDBG_UNINDENT
2414}
2415
2416static void codecDbgPrintNodeAmp(PCODECDBGINFO pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
2417{
2418#define CODECDBG_AMP(reg, chan) \
2419 codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
2420 uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
2421 RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
2422 RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
2423 CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg));
2424
2425 uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
2426 CODECDBG_AMP(regAmp, "Left");
2427 regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
2428 CODECDBG_AMP(regAmp, "Right");
2429
2430#undef CODECDBG_AMP
2431}
2432
2433static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
2434{
2435 if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
2436 {
2437 codecDbgPrintf(pInfo, "[HDA LINK]\n");
2438 return;
2439 }
2440}
2441
2442static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode)
2443{
2444 codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.id, pNode->node.id);
2445
2446 if (pNode->node.id == STAC9220_NID_ROOT)
2447 {
2448 CODECDBG_PRINT("ROOT\n");
2449 }
2450 else if (pNode->node.id == STAC9220_NID_AFG)
2451 {
2452 CODECDBG_PRINT("AFG\n");
2453 CODECDBG_INDENT
2454 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2455 codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
2456 CODECDBG_UNINDENT
2457 }
2458 else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.id))
2459 {
2460 CODECDBG_PRINT("PORT\n");
2461 }
2462 else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.id))
2463 {
2464 CODECDBG_PRINT("DAC\n");
2465 CODECDBG_INDENT
2466 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2467 codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
2468 codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
2469 codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
2470 CODECDBG_UNINDENT
2471 }
2472 else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.id))
2473 {
2474 CODECDBG_PRINT("ADC VOLUME\n");
2475 CODECDBG_INDENT
2476 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2477 codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
2478 codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
2479 CODECDBG_UNINDENT
2480 }
2481 else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.id))
2482 {
2483 CODECDBG_PRINT("ADC\n");
2484 CODECDBG_INDENT
2485 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2486 codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
2487 codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
2488 codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
2489 CODECDBG_UNINDENT
2490 }
2491 else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.id))
2492 {
2493 CODECDBG_PRINT("ADC MUX\n");
2494 CODECDBG_INDENT
2495 codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
2496 codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
2497 codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
2498 CODECDBG_UNINDENT
2499 }
2500 else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.id))
2501 {
2502 CODECDBG_PRINT("PC BEEP\n");
2503 }
2504 else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.id))
2505 {
2506 CODECDBG_PRINT("SPDIF OUT\n");
2507 }
2508 else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.id))
2509 {
2510 CODECDBG_PRINT("SPDIF IN\n");
2511 }
2512 else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.id))
2513 {
2514 CODECDBG_PRINT("DIGITAL IN PIN\n");
2515 }
2516 else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.id))
2517 {
2518 CODECDBG_PRINT("DIGITAL OUT PIN\n");
2519 }
2520 else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.id))
2521 {
2522 CODECDBG_PRINT("CD\n");
2523 }
2524 else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.id))
2525 {
2526 CODECDBG_PRINT("VOLUME KNOB\n");
2527 }
2528 else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.id))
2529 {
2530 CODECDBG_PRINT("RESERVED\n");
2531 }
2532 else
2533 CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.id);
2534}
2535
2536static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
2537{
2538 pHlp->pfnPrintf(pHlp, "HDA LINK\n");
2539
2540 CODECDBGINFO dbgInfo;
2541 dbgInfo.pHlp = pHlp;
2542 dbgInfo.pThis = pThis;
2543 dbgInfo.uLevel = 0;
2544
2545 PCODECDBGINFO pInfo = &dbgInfo;
2546
2547 CODECDBG_INDENT
2548 for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
2549 {
2550 PCODECNODE pNode = &pThis->paNodes[i];
2551 if (pNode->node.au32F00_param[0xE] == 0) /* Start with all nodes connected directly to the HDA (Azalia) link. */
2552 codecDbgPrintNode(&dbgInfo, pNode);
2553 }
2554 CODECDBG_UNINDENT
2555}
2556
2557static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
2558{
2559
2560}
2561#endif
2562
2563static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, PPFNHDACODECVERBPROCESSOR pfn)
2564{
2565 Assert(CODEC_CAD(cmd) == pThis->id);
2566 if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
2567 LogFlowFunc(("cmd %x was addressed to reserved node\n", cmd));
2568
2569 if ( CODEC_VERBDATA(cmd) == 0
2570 || CODEC_NID(cmd) >= pThis->cTotalNodes)
2571 {
2572 *pfn = vrbProcUnimplemented;
2573 /// @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp)
2574 LogFlowFunc(("cmd %x was ignored\n", cmd));
2575 return VINF_SUCCESS;
2576 }
2577
2578 for (int i = 0; i < pThis->cVerbs; ++i)
2579 {
2580 if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
2581 {
2582 *pfn = pThis->paVerbs[i].pfn;
2583 return VINF_SUCCESS;
2584 }
2585 }
2586
2587 *pfn = vrbProcUnimplemented;
2588 LogFlowFunc(("callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
2589 return VINF_SUCCESS;
2590}
2591
2592/*
2593 * APIs exposed to DevHDA.
2594 */
2595
2596/**
2597 *
2598 * routines open one of the voices (IN, OUT) with corresponding parameters.
2599 * this routine could be called from HDA on setting/resseting sound format.
2600 *
2601 * @todo Probably passed settings should be verified (if AFG's declared proposed
2602 * format) before enabling.
2603 */
2604int hdaCodecOpenStream(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, PPDMAUDIOSTREAMCFG pCfg)
2605{
2606 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2607
2608 int rc;
2609
2610 switch (enmSoundSource)
2611 {
2612 case PI_INDEX:
2613 rc = pThis->pfnOpenIn(pThis->pHDAState, "hda.in", PDMAUDIORECSOURCE_LINE_IN, pCfg);
2614 break;
2615
2616 case PO_INDEX:
2617 rc = pThis->pfnOpenOut(pThis->pHDAState, "hda.out", pCfg);
2618 break;
2619
2620#ifdef VBOX_WITH_HDA_MIC_IN
2621 case MC_INDEX:
2622 rc = pThis->pfnOpenIn(pThis->pHDAState, "hda.mc", PDMAUDIORECSOURCE_MIC, pCfg);
2623 break;
2624#endif
2625 default:
2626 AssertMsgFailed(("Index %ld not implemented\n", enmSoundSource));
2627 rc = VERR_NOT_IMPLEMENTED;
2628 }
2629
2630 LogFlowFuncLeaveRC(rc);
2631 return rc;
2632}
2633
2634int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
2635{
2636 AssertLogRelMsgReturn(pThis->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
2637 VERR_INTERNAL_ERROR);
2638 SSMR3PutU32(pSSM, pThis->cTotalNodes);
2639 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
2640 SSMR3PutStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState),
2641 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
2642 return VINF_SUCCESS;
2643}
2644
2645int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
2646{
2647 PCSSMFIELD pFields;
2648 uint32_t fFlags;
2649 switch (uVersion)
2650 {
2651 case HDA_SSM_VERSION_1:
2652 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2653 pFields = g_aCodecNodeFieldsV1;
2654 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2655 break;
2656
2657 case HDA_SSM_VERSION_2:
2658 case HDA_SSM_VERSION_3:
2659 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2660 pFields = g_aCodecNodeFields;
2661 fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
2662 break;
2663
2664 case HDA_SSM_VERSION:
2665 {
2666 uint32_t cNodes;
2667 int rc2 = SSMR3GetU32(pSSM, &cNodes);
2668 AssertRCReturn(rc2, rc2);
2669 if (cNodes != 0x1c)
2670 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
2671 AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
2672
2673 pFields = g_aCodecNodeFields;
2674 fFlags = 0;
2675 break;
2676 }
2677
2678 default:
2679 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2680 }
2681
2682 for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
2683 {
2684 uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.id;
2685 int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState,
2686 sizeof(pThis->paNodes[idxNode].SavedState),
2687 fFlags, pFields, NULL);
2688 if (RT_FAILURE(rc))
2689 return rc;
2690 AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.id,
2691 ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.id, idOld),
2692 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
2693 }
2694
2695 /*
2696 * Update stuff after changing the state.
2697 */
2698 if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
2699 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
2700 else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
2701 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_PCM);
2702 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
2703
2704 return VINF_SUCCESS;
2705}
2706
2707int hdaCodecDestruct(PHDACODEC pThis)
2708{
2709 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2710
2711 if (pThis->paNodes)
2712 {
2713 RTMemFree(pThis->paNodes);
2714 pThis->paNodes = NULL;
2715 }
2716
2717 return VINF_SUCCESS;
2718}
2719
2720int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
2721 uint16_t uLUN, PCFGMNODE pCfg)
2722{
2723 AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
2724 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2725 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2726
2727 pThis->id = uLUN;
2728 pThis->paVerbs = &g_aCodecVerbs[0];
2729 pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
2730 pThis->pfnLookup = codecLookup;
2731#ifdef DEBUG
2732 pThis->pfnDbgSelector = codecDbgSelector;
2733 pThis->pfnDbgListNodes = codecDbgListNodes;
2734#endif
2735 int rc = stac9220Construct(pThis);
2736 AssertRC(rc);
2737
2738 /* common root node initializers */
2739 pThis->paNodes[0].node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
2740 pThis->paNodes[0].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
2741 /* common AFG node initializers */
2742 pThis->paNodes[1].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
2743 pThis->paNodes[1].node.au32F00_param[5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
2744 pThis->paNodes[1].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
2745
2746 /* 44.1 kHz. */
2747 PDMAUDIOSTREAMCFG as;
2748 as.uHz = 44100;
2749 as.cChannels = 2;
2750 as.enmFormat = AUD_FMT_S16;
2751 as.enmEndianness = PDMAUDIOHOSTENDIANNESS;
2752
2753 pThis->paNodes[1].node.au32F00_param[0xA] = CODEC_F00_0A_16_BIT;
2754
2755 hdaCodecOpenStream(pThis, PI_INDEX, &as);
2756 hdaCodecOpenStream(pThis, PO_INDEX, &as);
2757#ifdef VBOX_WITH_HDA_MIC_IN
2758 hdaCodecOpenStream(pThis, MC_INDEX, &as);
2759#endif
2760
2761 pThis->paNodes[1].node.au32F00_param[0xA] |= CODEC_F00_0A_44_1KHZ;
2762
2763 uint8_t i;
2764 Assert(pThis->paNodes);
2765 Assert(pThis->pfnCodecNodeReset);
2766
2767 for (i = 0; i < pThis->cTotalNodes; ++i)
2768 pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
2769
2770 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
2771 hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
2772
2773 return VINF_SUCCESS;
2774}
2775
Note: See TracBrowser for help on using the repository browser.

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